/[svn]/vendor/ircservices-5.1.24/messages.c
ViewVC logotype

Contents of /vendor/ircservices-5.1.24/messages.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1171 - (show annotations)
Fri Aug 12 20:00:46 2011 UTC (10 years, 3 months ago) by michael
File MIME type: text/x-chdr
File size: 19384 byte(s)
- Import ircservices-5.1.24. Don't ever think about modifying anything in this
  folder!
  Since Andrew Church has discontinued his services project in April 2011, the
  ircd-hybrid team has been given permissions to officially continue and
  maintain the already mentioned project.
  The name of this project will be changed for the reason being that the current
  name "IRC Services" is way too generic these days.

  Remember: Don't ever modify anything in here. This folder is kept for reference.

1 /* Definitions of IRC message functions and list of messages.
2 *
3 * IRC Services is copyright (c) 1996-2009 Andrew Church.
4 * E-mail: <achurch@achurch.org>
5 * Parts written by Andrew Kempe and others.
6 * This program is free but copyrighted software; see the file GPL.txt for
7 * details.
8 */
9
10 #include "services.h"
11 #include "messages.h"
12 #include "language.h"
13 #include "modules.h"
14 #include "version.h"
15 #include "modules/operserv/operserv.h"
16
17 /*************************************************************************/
18
19 /* Enable ignore code for PRIVMSGs? */
20 int allow_ignore = 1;
21
22 /* Callbacks for various messages */
23 static int cb_privmsg = -1;
24 static int cb_whois = -1;
25
26 /*************************************************************************/
27 /************************ Basic message handling *************************/
28 /*************************************************************************/
29
30 static void m_nickcoll(char *source, int ac, char **av)
31 {
32 if (ac < 1)
33 return;
34 if (!readonly)
35 introduce_user(av[0]);
36 }
37
38 /*************************************************************************/
39
40 static void m_ping(char *source, int ac, char **av)
41 {
42 if (ac < 1)
43 return;
44 send_cmd(ServerName, "PONG %s %s", ac>1 ? av[1] : ServerName, av[0]);
45 }
46
47 /*************************************************************************/
48
49 static void m_info(char *source, int ac, char **av)
50 {
51 int i;
52 struct tm *tm;
53 char timebuf[64];
54
55 if (!*source) {
56 log("Source missing from INFO message");
57 return;
58 }
59
60 tm = localtime(&start_time);
61 strftime(timebuf, sizeof(timebuf), "%a %b %d %H:%M:%S %Y %Z", tm);
62
63 for (i = 0; info_text[i]; i++)
64 send_cmd(ServerName, "371 %s :%s", source, info_text[i]);
65 send_cmd(ServerName, "371 %s :Version %s (%s)", source,
66 version_number, version_build);
67 send_cmd(ServerName, "371 %s :On-line since %s", source, timebuf);
68 send_cmd(ServerName, "374 %s :End of /INFO list.", source);
69 }
70
71 /*************************************************************************/
72
73 static void m_join(char *source, int ac, char **av)
74 {
75 if (!*source) {
76 log("Source missing from JOIN message");
77 return;
78 } else if (ac < 1) {
79 return;
80 }
81 do_join(source, ac, av);
82 }
83
84 /*************************************************************************/
85
86 static void m_kick(char *source, int ac, char **av)
87 {
88 if (!*source) {
89 log("Source missing from KICK message");
90 return;
91 } else if (ac != 3) {
92 return;
93 }
94 do_kick(source, ac, av);
95 }
96
97 /*************************************************************************/
98
99 static void m_kill(char *source, int ac, char **av)
100 {
101 if (!*source) {
102 log("Source missing from KILL message");
103 return;
104 } else if (ac != 2) {
105 return;
106 }
107 /* Recover if someone kills us. If introduce_user() returns 0, then
108 * the user in question isn't a pseudoclient, so pass it on to the
109 * user handling code. */
110 if (!introduce_user(av[0]))
111 do_kill(source, ac, av);
112 }
113
114 /*************************************************************************/
115
116 static void m_mode(char *source, int ac, char **av)
117 {
118 if (!*source) {
119 log("Source missing from MODE message");
120 return;
121 }
122
123 if (*av[0] == '#' || *av[0] == '&') {
124 if (ac < 2)
125 return;
126 do_cmode(source, ac, av);
127 } else {
128 if (ac != 2) {
129 return;
130 } else if (irc_stricmp(source,av[0])!=0 && strchr(source,'.')==NULL) {
131 log("user: MODE %s %s from different nick %s!", av[0], av[1],
132 source);
133 wallops(NULL, "%s attempted to change mode %s for %s",
134 source, av[1], av[0]);
135 return;
136 }
137 do_umode(source, ac, av);
138 }
139 }
140
141 /*************************************************************************/
142
143 static void m_motd(char *source, int ac, char **av)
144 {
145 FILE *f;
146 char buf[BUFSIZE];
147
148 if (!*source) {
149 log("Source missing from MOTD message");
150 return;
151 }
152
153 f = fopen(MOTDFilename, "r");
154 send_cmd(ServerName, "375 %s :- %s Message of the Day",
155 source, ServerName);
156 if (f) {
157 while (fgets(buf, sizeof(buf), f)) {
158 buf[strlen(buf)-1] = 0;
159 send_cmd(ServerName, "372 %s :- %s", source, buf);
160 }
161 fclose(f);
162 } else {
163 send_cmd(ServerName, "372 %s :- MOTD file not found! Please "
164 "contact your IRC administrator.", source);
165 }
166 }
167
168 /*************************************************************************/
169
170 static void m_part(char *source, int ac, char **av)
171 {
172 if (!*source) {
173 log("Source missing from PART message");
174 return;
175 } else if (ac < 1 || ac > 2) {
176 return;
177 }
178 do_part(source, ac, av);
179 }
180
181 /*************************************************************************/
182
183 static const char msg_up_inactive[] =
184 "Network buffer size exceeded inactive threshold (%d%%), not processing"
185 " PRIVMSGs";
186 static const char msg_up_ignore[] =
187 "Network buffer size exceeded ignore threshold (%d%%), ignoring PRIVMSGs";
188 static const char msg_down_inactive[] =
189 "Network buffer size dropped below ignore threshold (%d%%), not"
190 " processing PRIVMSGs";
191 static const char msg_down_normal[] =
192 "Network buffer size dropped below inactive threshold (%d%%),"
193 " processing PRIVMSGs normally";
194
195 static void m_privmsg(char *source, int ac, char **av)
196 {
197 /* PRIVMSG handling status based on NetBufferLimit settings */
198 static enum {NORMAL,INACTIVE,IGNORE} netbuf_status = NORMAL;
199
200 uint32 start, stop; /* When processing started and finished */
201 User *u = get_user(source);
202 char *s;
203
204
205 if (!*source) {
206 log("Source missing from PRIVMSG message");
207 return;
208 } else if (ac != 2) {
209 return;
210 }
211
212 /* If a server is specified (nick@server format), make sure it matches
213 * us, and strip it off. */
214 s = strchr(av[0], '@');
215 if (s) {
216 *s++ = 0;
217 if (stricmp(s, ServerName) != 0)
218 return;
219 }
220
221 /* Check network buffer status. */
222 if (NetBufferLimitInactive) {
223 int bufstat = sock_bufstat(servsock, NULL, NULL, NULL, NULL);
224 const char *message = NULL;
225 int value = 0;
226 switch (netbuf_status) {
227 case NORMAL:
228 if (NetBufferLimitIgnore && bufstat >= NetBufferLimitIgnore) {
229 message = msg_up_ignore;
230 value = NetBufferLimitIgnore;
231 netbuf_status = IGNORE;
232 } else if (bufstat >= NetBufferLimitInactive) {
233 message = msg_up_inactive;
234 value = NetBufferLimitInactive;
235 netbuf_status = INACTIVE;
236 }
237 break;
238 case INACTIVE:
239 if (NetBufferLimitIgnore && bufstat >= NetBufferLimitIgnore) {
240 message = msg_up_ignore;
241 value = NetBufferLimitIgnore;
242 netbuf_status = IGNORE;
243 } else if (bufstat < NetBufferLimitInactive) {
244 message = msg_down_normal;
245 value = NetBufferLimitInactive;
246 netbuf_status = NORMAL;
247 }
248 break;
249 case IGNORE:
250 if (bufstat < NetBufferLimitInactive) {
251 message = msg_down_normal;
252 value = NetBufferLimitInactive;
253 netbuf_status = NORMAL;
254 } else if (bufstat < NetBufferLimitIgnore) {
255 message = msg_down_inactive;
256 value = NetBufferLimitIgnore;
257 netbuf_status = INACTIVE;
258 }
259 break;
260 } /* switch (netbuf_status) */
261 if (message) {
262 log(message, value);
263 wallops(NULL, message, value);
264 }
265 }
266
267 /* Check if we should ignore. Operators always get through. */
268 if (u) {
269 ignore_update(u, 0);
270 if (!is_oper(u)) {
271 if (netbuf_status != NORMAL) {
272 if (netbuf_status == INACTIVE) {
273 if (u)
274 notice_lang(av[0], u, SERVICES_IS_BUSY);
275 else
276 notice(av[0], source,
277 getstring(NULL, SERVICES_IS_BUSY));
278 }
279 return;
280 } else if (allow_ignore && IgnoreDecay && IgnoreThreshold) {
281 if (u->ignore >= IgnoreThreshold) {
282 log("Ignored message from %s: \"%s\"", source, inbuf);
283 return;
284 }
285 }
286 }
287 }
288
289 /* Not ignored; actually execute the command, and update ignore data. */
290 start = time_msec();
291 call_callback_3(cb_privmsg, source, av[0], av[1]);
292 stop = time_msec();
293 if (stop > start && u && !is_oper(u))
294 ignore_update(u, stop-start);
295 }
296
297 /*************************************************************************/
298
299 static void m_quit(char *source, int ac, char **av)
300 {
301 if (!*source) {
302 log("Source missing from QUIT message");
303 return;
304 } else if (ac != 1) {
305 return;
306 }
307 do_quit(source, ac, av);
308 }
309
310 /*************************************************************************/
311
312 static void m_server(char *source, int ac, char **av)
313 {
314 do_server(source, ac, av);
315 }
316
317 /*************************************************************************/
318
319 static void m_squit(char *source, int ac, char **av)
320 {
321 do_squit(source, ac, av);
322 }
323
324 /*************************************************************************/
325
326 static void m_stats(char *source, int ac, char **av)
327 {
328 if (!*source) {
329 log("Source missing from STATS message");
330 return;
331 } else if (ac < 1) {
332 return;
333 }
334
335 switch (*av[0]) {
336 case 'u': {
337 int uptime = time(NULL) - start_time;
338 Module *module_operserv;
339 typeof(get_operserv_data) *p_get_operserv_data;
340 int32 maxusercnt;
341
342 send_cmd(NULL, "242 %s :Services up %d day%s, %02d:%02d:%02d",
343 source, uptime/86400, (uptime/86400 == 1) ? "" : "s",
344 (uptime/3600) % 24, (uptime/60) % 60, uptime % 60);
345 if ((module_operserv = find_module("operserv/main")) != NULL
346 && (p_get_operserv_data =
347 get_module_symbol(module_operserv, "get_operserv_data"))
348 && p_get_operserv_data(OSDATA_MAXUSERCNT, &maxusercnt)
349 ) {
350 send_cmd(NULL, "250 %s :Current users: %d (%d ops); maximum %d",
351 source, usercnt, opcnt, maxusercnt);
352 } else {
353 send_cmd(NULL, "250 %s :Current users: %d (%d ops)",
354 source, usercnt, opcnt);
355 }
356 send_cmd(NULL, "219 %s u :End of /STATS report.", source);
357 break;
358 } /* case 'u' */
359
360 case 'l': {
361 uint64 read, written;
362 sock_rwstat(servsock, &read, &written);
363 send_cmd(NULL, "211 %s Server SendBuf SentBytes SentMsgs RecvBuf "
364 "RecvBytes RecvMsgs ConnTime", source);
365 #if SIZEOF_LONG >= 8
366 send_cmd(NULL, "211 %s %s %u %lu %d %u %lu %d %ld",
367 source, RemoteServer,
368 read_buffer_len(servsock), (unsigned long)read, -1,
369 write_buffer_len(servsock), (unsigned long)written, -1,
370 (long)start_time);
371 #else // assume long long is available
372 send_cmd(NULL, "211 %s %s %u %llu %d %u %llu %d %ld",
373 source, RemoteServer,
374 read_buffer_len(servsock), (unsigned long long)read, -1,
375 write_buffer_len(servsock), (unsigned long long)written, -1,
376 (long)start_time);
377 #endif
378 send_cmd(NULL, "219 %s l :End of /STATS report.", source);
379 break;
380 }
381
382 case 'c':
383 case 'h':
384 case 'i':
385 case 'k':
386 case 'm':
387 case 'o':
388 case 'y':
389 send_cmd(NULL, "219 %s %c :/STATS %c not applicable or not supported.",
390 source, *av[0], *av[0]);
391 break;
392 }
393 }
394
395 /*************************************************************************/
396
397 static void m_time(char *source, int ac, char **av)
398 {
399 time_t t;
400 struct tm *tm;
401 char buf[64];
402
403 if (!*source) {
404 log("Source missing from TIME message");
405 return;
406 }
407
408 time(&t);
409 tm = localtime(&t);
410 strftime(buf, sizeof(buf), "%a %b %d %H:%M:%S %Y %Z", tm);
411 send_cmd(NULL, "391 %s %s :%s", source, ServerName, buf);
412 }
413
414 /*************************************************************************/
415
416 static void m_topic(char *source, int ac, char **av)
417 {
418 if (ac != 4)
419 return;
420 do_topic(source, ac, av);
421 }
422
423 /*************************************************************************/
424
425 static void m_version(char *source, int ac, char **av)
426 {
427 if (!*source) {
428 log("Source missing from VERSION message");
429 return;
430 }
431 send_cmd(ServerName, "351 %s %s-%s %s :%s", source,
432 program_name, version_number, ServerName, version_build);
433 }
434
435 /*************************************************************************/
436
437 static void m_whois(char *source, int ac, char **av)
438 {
439 if (!*source) {
440 log("Source missing from WHOIS message");
441 return;
442 } else if (ac < 1) {
443 return;
444 }
445
446 if (call_callback_3(cb_whois, source, av[0],
447 ac>1 ? av[1] : NULL) <= 0
448 ) {
449 send_cmd(ServerName, "401 %s %s :No such service.", source, av[0]);
450 }
451 }
452
453 /*************************************************************************/
454
455 /* Basic messages (defined above). Note that NICK and USER are left to the
456 * protocol modules, since their usage varies widely between protocols. */
457
458 static Message base_messages[] = {
459
460 { "401", NULL },
461 { "436", m_nickcoll },
462 { "AWAY", NULL },
463 { "INFO", m_info },
464 { "JOIN", m_join },
465 { "KICK", m_kick },
466 { "KILL", m_kill },
467 { "MODE", m_mode },
468 { "MOTD", m_motd },
469 { "NOTICE", NULL },
470 { "PART", m_part },
471 { "PASS", NULL },
472 { "PING", m_ping },
473 { "PONG", NULL },
474 { "PRIVMSG", m_privmsg },
475 { "QUIT", m_quit },
476 { "SERVER", m_server },
477 { "SQUIT", m_squit },
478 { "STATS", m_stats },
479 { "TIME", m_time },
480 { "TOPIC", m_topic },
481 { "VERSION", m_version },
482 { "WALLOPS", NULL },
483 { "WHOIS", m_whois },
484
485 { NULL }
486
487 };
488
489 /*************************************************************************/
490 /******************** Message registration and lookup ********************/
491 /*************************************************************************/
492
493 /* Structure to link tables together */
494 typedef struct messagetable_ MessageTable;
495 struct messagetable_ {
496 MessageTable *next, *prev;
497 Message *table;
498 };
499 static MessageTable *msgtable = NULL;
500
501 /* List of known messages (for speed-lookup list) */
502 typedef struct messagenode_ MessageNode;
503 struct messagenode_ {
504 MessageNode *next, *prev;
505 Message *msg;
506 };
507 static MessageNode *msglist = NULL;
508
509 /*************************************************************************/
510 /*************************************************************************/
511
512 /* (Re)generate the speed-lookup list. This list is used to reduce the
513 * time spent searching for messages; every time a message is seen, its
514 * entry in this list is moved one place closer to the head of the list,
515 * allowing frequently-seen messages to "percolate" to the top of the list
516 * so that they will be found more quickly by searches.
517 */
518
519 static void init_message_list(void)
520 {
521 MessageNode *mn, *mn2;
522 MessageTable *mt;
523 Message *m;
524
525 LIST_FOREACH_SAFE(mn, msglist, mn2)
526 free(mn);
527 msglist = NULL;
528
529 LIST_FOREACH (mt, msgtable) {
530 for (m = mt->table; m->name; m++) {
531 LIST_SEARCH(msglist, msg->name, m->name, stricmp, mn);
532 if (!mn) {
533 mn = smalloc(sizeof(*mn));
534 mn->msg = m;
535 LIST_INSERT(mn, msglist);
536 }
537 }
538 }
539 }
540
541 /*************************************************************************/
542
543 /* Register the given table of messages. Returns 1 on success, 0 on
544 * failure (`table' == NULL, `table' already registered, or out of memory).
545 */
546
547 int register_messages(Message *table)
548 {
549 MessageTable *mt;
550
551 if (!table)
552 return 0;
553 LIST_SEARCH_SCALAR(msgtable, table, table, mt);
554 if (mt) /* if it's already on the list, abort */
555 return 0;
556 mt = malloc(sizeof(*mt));
557 if (!mt) /* out of memory */
558 return 0;
559 mt->table = table;
560 LIST_INSERT(mt, msgtable);
561 init_message_list();
562 return 1;
563 }
564
565 /*************************************************************************/
566
567 /* Unregister the given table of messages. Returns 1 on success, 0 on
568 * failure (`table' not registered).
569 */
570
571 int unregister_messages(Message *table)
572 {
573 MessageTable *mt;
574
575 LIST_SEARCH_SCALAR(msgtable, table, table, mt);
576 if (!mt)
577 return 0;
578 LIST_REMOVE(mt, msgtable);
579 free(mt);
580 init_message_list();
581 return 1;
582 }
583
584 /*************************************************************************/
585
586 /* Return the Message structure for the given message name, or NULL if none
587 * exists. If there are multiple tables with entries for the message,
588 * returns the entry in the most recently registered table.
589 */
590
591 Message *find_message(const char *name)
592 {
593 MessageNode *mn;
594
595 LIST_SEARCH(msglist, msg->name, name, stricmp, mn);
596 if (mn) {
597 MessageNode *prev = mn->prev;
598 if (prev) {
599 MessageNode *pprev = prev->prev;
600 MessageNode *next = mn->next;
601 /* Current order: pprev -> prev -> mn -> next */
602 /* New order: pprev -> mn -> prev -> next */
603 if (pprev)
604 pprev->next = mn;
605 else
606 msglist = mn;
607 mn->prev = pprev;
608 mn->next = prev;
609 prev->prev = mn;
610 prev->next = next;
611 if (next)
612 next->prev = prev;
613 }
614 return mn->msg;
615 }
616 return NULL;
617 }
618
619 /*************************************************************************/
620 /************************ Initialization/cleanup *************************/
621 /*************************************************************************/
622
623 int messages_init(int ac, char **av)
624 {
625 if (!register_messages(base_messages)) {
626 log("messages_init: Unable to register base messages\n");
627 return 0;
628 }
629 cb_privmsg = register_callback("m_privmsg");
630 cb_whois = register_callback("m_whois");
631 if (cb_privmsg < 0 || cb_whois < 0) {
632 log("messages_init: register_callback() failed\n");
633 return 0;
634 }
635 return 1;
636 }
637
638 /*************************************************************************/
639
640 void messages_cleanup(void)
641 {
642 unregister_callback(cb_whois);
643 unregister_callback(cb_privmsg);
644 unregister_messages(base_messages);
645 }
646
647 /*************************************************************************/
648
649 /*
650 * Local variables:
651 * c-file-style: "stroustrup"
652 * c-file-offsets: ((case-label . *) (statement-case-intro . *))
653 * indent-tabs-mode: nil
654 * End:
655 *
656 * vim: expandtab shiftwidth=4:
657 */

svnadmin@ircd-hybrid.org
ViewVC Help
Powered by ViewVC 1.1.28