]> jfr.im git - irc/quakenet/newserv.git/blob - serverlist/serverlist.c
CHANSERV: fix issue where chanserv_relay doesn't wait for db to be loaded before...
[irc/quakenet/newserv.git] / serverlist / serverlist.c
1 #include "../core/schedule.h"
2 #include "../irc/irc.h"
3 #include "../lib/irc_string.h"
4 #include "../localuser/localuserchannel.h"
5 #include "../control/control.h"
6 #include "../usercount/usercount.h"
7 #include "../lib/version.h"
8 #include "../serverlist/serverlist.h"
9 #include "../core/config.h"
10 #include "../lib/strlfunc.h"
11
12 MODULE_VERSION("")
13
14 #include <stdlib.h>
15 #include <string.h>
16 #include <stdarg.h>
17 #include <stdio.h>
18 #include <sys/time.h>
19 #include <pcre.h>
20
21 int cmd_serverlist(void *sender, int cargc, char **cargv);
22 void serverlist_hook_newserver(int hook, void *arg);
23 void serverlist_hook_lostserver(int hook, void *arg);
24 int serverlist_versionreply(void *source, int cargc, char **cargv);
25 void serverlist_pingservers(void *arg);
26 int serverlist_rpong(void *source, int cargc, char **cargv);
27
28 const flag servertypeflags[] = {
29 { 'c', SERVERTYPEFLAG_CLIENT_SERVER },
30 { 'h', SERVERTYPEFLAG_HUB },
31 { 's', SERVERTYPEFLAG_SERVICE },
32 { 'Q', SERVERTYPEFLAG_CHANSERV },
33 { 'S', SERVERTYPEFLAG_SPAMSCAN },
34 { 'X', SERVERTYPEFLAG_CRITICAL_SERVICE },
35 { '\0', 0 }
36 };
37
38 struct {
39 int used;
40 int lag;
41 sstring *version1;
42 sstring *version2;
43 flag_t type;
44 } serverinfo[MAXSERVERS];
45
46 void serverlist_doversion(void);
47
48 static sstring *s_server, *q_server;
49 static pcre *service_re, *hub_re, *not_client_re;
50
51 static pcre *compilefree(sstring *re) {
52 const char *err;
53 int erroffset;
54 pcre *r;
55
56 r = pcre_compile(re->content, 0, &err, &erroffset, NULL);
57 if(r == NULL) {
58 Error("serverlist", ERR_WARNING, "Unable to compile RE %s (offset: %d, reason: %s)", re->content, erroffset, err);
59 freesstring(re);
60 return NULL;
61 }
62
63 freesstring(re);
64 return r;
65 }
66
67 void _init(void) {
68 registercontrolhelpcmd("serverlist",NO_OPER,1,&cmd_serverlist,"Usage: serverlist [pattern]\nShows all currently connected servers");
69 /* hooks for serverlist */
70 registerhook(HOOK_SERVER_NEWSERVER, &serverlist_hook_newserver);
71 registerhook(HOOK_SERVER_LOSTSERVER, &serverlist_hook_lostserver);
72 int i;
73
74 q_server = getcopyconfigitem("serverlist", "q_server", "CServe.quakenet.org", HOSTLEN);
75 s_server = getcopyconfigitem("serverlist", "s_server", "services2.uk.quakenet.org", HOSTLEN);
76
77 service_re = compilefree(getcopyconfigitem("serverlist", "service_re", "^services\\d*\\..*$", 256));
78 hub_re = compilefree(getcopyconfigitem("serverlist", "hub_re", "^hub\\d*\\..*$", 256));
79 not_client_re = compilefree(getcopyconfigitem("serverlist", "not_client_re", "^(testserv\\d*\\.).*$", 256));
80
81 for (i = 0; i < MAXSERVERS; i++) {
82 if (serverlist[i].linkstate == LS_LINKED)
83 serverinfo[i].used = 1;
84 else
85 serverinfo[i].used = 0;
86
87 serverinfo[i].lag = -1;
88 serverinfo[i].version1 = NULL;
89 serverinfo[i].version2 = NULL;
90 serverinfo[i].type = getservertype(&serverlist[i]);
91 }
92 registernumerichandler(351, &serverlist_versionreply, 2);
93 registerserverhandler("RO", &serverlist_rpong, 4);
94
95 schedulerecurring(time(NULL)+1, 0, 60, &serverlist_pingservers, NULL);
96 }
97
98 void _fini(void) {
99 int i;
100 for (i = 0; i < MAXSERVERS; i++) {
101 if (serverinfo[i].used) {
102 freesstring(serverinfo[i].version1);
103 freesstring(serverinfo[i].version2);
104 }
105 }
106 deregisternumerichandler(351, &serverlist_versionreply);
107 deregisterserverhandler("RO", &serverlist_rpong);
108
109 deregisterhook(HOOK_SERVER_NEWSERVER, &serverlist_hook_newserver);
110 deregisterhook(HOOK_SERVER_LOSTSERVER, &serverlist_hook_lostserver);
111
112 deregistercontrolcmd("serverlist",cmd_serverlist);
113
114 deleteschedule(NULL, &serverlist_pingservers, NULL);
115
116 freesstring(q_server);
117 freesstring(s_server);
118 pcre_free(service_re);
119 pcre_free(hub_re);
120 pcre_free(not_client_re);
121 }
122
123 int cmd_serverlist(void *sender, int cargc, char **cargv) {
124 nick *np = (nick*)sender;
125 int a, i, ucount, acount, scount;
126 char lagstr[20];
127 char buf[512];
128
129 controlreply(np, "%-7s %-35s %5s/%5s/%-7s %-7s %-7s %-20s %-8s %-20s", "Numeric", "Hostname", "ECl", "Cl", "MaxCl", "Flags", "Type", "Connected for", "Lag", "Version");
130
131 scount = acount = 0;
132
133 for (i = 0; i < MAXSERVERS; i++) {
134 if (serverlist[i].linkstate == LS_LINKED && (cargc < 1 || match2strings(cargv[0], serverlist[i].name->content))) {
135 ucount = 0;
136
137 for (a = 0; a <= serverlist[i].maxusernum; a++)
138 if (servernicks[i][a] != NULL)
139 ucount++;
140
141 acount += ucount;
142 scount++;
143
144 if (serverinfo[i].lag == -1)
145 strcpy(lagstr, "-");
146 else
147 snprintf(lagstr, sizeof(lagstr), "%d", serverinfo[i].lag);
148
149 strlcpy(buf, printflags(serverinfo[i].type, servertypeflags), sizeof(buf));
150
151 controlreply(np, "%-7d %-35s %5d/%5d/%-7d %-7s %-7s %-20s %-8s %-20s - %s", i, serverlist[i].name->content,
152 servercount[i], ucount, serverlist[i].maxusernum,
153 printflags(serverlist[i].flags, smodeflags), buf,
154 longtoduration(getnettime() - serverlist[i].ts, 0),
155 lagstr,
156 serverinfo[i].version1 ? serverinfo[i].version1->content : "Unknown",
157 serverinfo[i].version2 ? serverinfo[i].version2->content : "Unknown");
158 }
159 }
160
161 controlreply(np, "--- End of list. %d users and %d servers on the net.", acount, scount);
162
163 /* update version info for next time */
164 serverlist_doversion();
165
166 return CMD_OK;
167 }
168
169 int serverlist_versionreply(void *source, int cargc, char **cargv) {
170 int num;
171
172 if (cargc < 6)
173 return CMD_OK;
174
175 num = numerictolong(cargv[0], 2);
176
177 if (serverinfo[num].used) {
178 freesstring(serverinfo[num].version1);
179 freesstring(serverinfo[num].version2);
180
181 serverinfo[num].version1 = getsstring(cargv[3], strlen(cargv[3]));
182 serverinfo[num].version2 = getsstring(cargv[5], strlen(cargv[5]));
183 }
184 return CMD_OK;
185 }
186
187 void serverlist_doversion(void) {
188 int i;
189 char *num1, *numeric;
190
191 if (mynick == NULL)
192 return;
193
194 for (i = 0; i < MAXSERVERS; i++) {
195 if (serverlist[i].linkstate == LS_LINKED && serverinfo[i].version1 == NULL) {
196 numeric = longtonumeric(mynick->numeric,5);
197 num1 = (char*)malloc(strlen(numeric) + 1); /* bleh.. longtonumeric() is using static variables */
198 strcpy(num1, numeric);
199
200 irc_send("%s V :%s", num1, longtonumeric(i,2));
201 free(num1);
202 }
203 }
204 }
205
206 void serverlist_hook_newserver(int hook, void *arg) {
207 char *num1, *numeric;
208 long num = (long)arg;
209
210 serverinfo[num].used = 1;
211 serverinfo[num].version1 = NULL;
212 serverinfo[num].version2 = NULL;
213 serverinfo[num].type = getservertype(&serverlist[num]);
214
215 if (mynick == NULL) /* bleh this is buggy... doesn't do it when mynick appears */
216 return;
217
218 numeric = longtonumeric(mynick->numeric,5);
219 num1 = (char*)malloc(strlen(numeric) + 1); /* bleh.. longtonumeric() is using static variables */
220 strcpy(num1, numeric);
221
222 irc_send("%s V :%s", num1, longtonumeric(num,2));
223
224 free(num1);
225 }
226
227 void serverlist_hook_lostserver(int hook, void *arg) {
228 long num = (long)arg;
229
230 serverinfo[num].used = 0;
231 freesstring(serverinfo[num].version1);
232 freesstring(serverinfo[num].version2);
233 }
234
235 flag_t getservertype(server *server) {
236 flag_t result = 0;
237 char *server_name;
238 int server_len;
239
240 if(server == NULL || server->name == NULL)
241 return 0;
242
243 server_name = server->name->content;
244 server_len = server->name->length;
245
246 if(server->flags & SMODE_SERVICE)
247 result|=SERVERTYPEFLAG_SERVICE;
248
249 if(!strcmp(server_name, q_server->content)) {
250 result|=SERVERTYPEFLAG_CHANSERV;
251 result|=SERVERTYPEFLAG_CRITICAL_SERVICE;
252 } else if(!strcmp(server_name, s_server->content)) {
253 result|=SERVERTYPEFLAG_SPAMSCAN;
254 result|=SERVERTYPEFLAG_CRITICAL_SERVICE;
255 } else {
256 if(service_re && (pcre_exec(service_re, NULL, server_name, server_len, 0, 0, NULL, 0) >= 0)) {
257 /* matches service re */
258 if((server->flags & SMODE_SERVICE) == 0) {
259 /* is not a service */
260 Error("serverlist", ERR_WARNING, "Non-service server (%s) matched service RE.", server_name);
261 }
262 } else {
263 /* does not match service re */
264 if((server->flags & SMODE_SERVICE) != 0) {
265 result|=SERVERTYPEFLAG_SERVICE;
266 Error("serverlist", ERR_WARNING, "Service server (%s) that does not match service RE.", server_name);
267 }
268 }
269 }
270
271 if(hub_re && (pcre_exec(hub_re, NULL, server_name, server_len, 0, 0, NULL, 0) >= 0)) {
272 if((server->flags & SMODE_HUB) != 0) {
273 result|=SERVERTYPEFLAG_HUB;
274 } else {
275 Error("serverlist", ERR_WARNING, "Server matched hub re but isn't a hub (%s).", server_name);
276 }
277 }
278
279 if(not_client_re && (pcre_exec(not_client_re, NULL, server_name, server_len, 0, 0, NULL, 0) >= 0)) {
280 /* noop */
281 } else if(result == 0) {
282 result|=SERVERTYPEFLAG_CLIENT_SERVER;
283 }
284
285 return result;
286 }
287
288 void serverlist_pingservers(void *arg) {
289 int i;
290 server *from, *to;
291 char fnum[10], tnum[10];
292 struct timeval tv;
293
294 if (!mynick)
295 return;
296
297 for(i=0;i<MAXSERVERS;i++) {
298 to = &serverlist[i];
299
300 if (to->parent == -1)
301 continue;
302
303 from = &serverlist[to->parent];
304
305 if (to->linkstate != LS_LINKED || from->linkstate != LS_LINKED)
306 continue;
307
308 strcpy(fnum, longtonumeric(to->parent,2));
309 strcpy(tnum, longtonumeric(i, 2));
310
311 if (from->parent == -1) { /* Are we the source? */
312 (void) gettimeofday(&tv, NULL);
313 irc_send("%s RI %s %s %jd %jd :RP", mynumeric->content, tnum, longtonumeric(mynick->numeric,5), (intmax_t)tv.tv_sec, (intmax_t)tv.tv_usec);
314 } else {
315 strcpy(fnum, longtonumeric(to->parent,2));
316 strcpy(tnum, longtonumeric(i, 2));
317 irc_send("%s RI %s %s :RP", longtonumeric(mynick->numeric,5), to->name->content, fnum);
318 }
319 }
320 }
321
322 int serverlist_rpong(void *source, int cargc, char **cargv) {
323 int to, lag;
324 struct timeval tv;
325
326 if (cargc < 4)
327 return CMD_ERROR;
328
329 if (cargc == 5) { /* From target to source server */
330 if (strcmp(cargv[4], "RP") != 0)
331 return CMD_OK;
332
333 to = numerictolong(source, 2);
334
335 (void) gettimeofday(&tv, NULL);
336 lag = (tv.tv_sec - strtoull(cargv[2], NULL, 10)) * 1000 + (tv.tv_usec - strtoull(cargv[3], NULL, 10)) / 1000;
337 } else { /* From source server to client */
338 if (strcmp(cargv[3], "RP") != 0)
339 return CMD_OK;
340
341 to = findserver(cargv[1]);
342
343 if (to == -1)
344 return CMD_ERROR;
345
346 lag = atoi(cargv[2]);
347 }
348
349 serverinfo[to].lag = lag;
350
351 return CMD_OK;
352 }