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