1 #ifdef RCS
2 static char rcsid[]="$Id: server.c,v 1.2 2001/03/13 05:04:47 holsta Exp $";
3 #endif
4 /******************************************************************************
5 * Internetting Cooperating Programmers
6 * ----------------------------------------------------------------------------
7 *
8 * ____ PROJECT
9 * | _ \ __ _ _ __ ___ ___ _ __
10 * | | | |/ _` | '_ \ / __/ _ \ '__|
11 * | |_| | (_| | | | | (_| __/ |
12 * |____/ \__,_|_| |_|\___\___|_| the IRC bot
13 *
14 * All files in this archive are subject to the GNU General Public License.
15 *
16 * $Source: /cvsroot/dancer/dancer/src/server.c,v $
17 * $Revision: 1.2 $
18 * $Date: 2001/03/13 05:04:47 $
19 * $Author: holsta $
20 * $State: Exp $
21 * $Locker: $
22 *
23 * ---------------------------------------------------------------------------
24 *****************************************************************************/
25
26 #include "dancer.h"
27 #include "trio.h"
28 #include "strio.h"
29 #include "numeric.h" /* From the irc server source */
30 #include "list.h"
31 #include "function.h"
32 #include "user.h"
33 #include "command.h"
34 #include "ctcp.h"
35 #include "transfer.h"
36 #include "seen.h"
37 #include "server.h"
38 #include "bans.h"
39 #include "link.h"
40 #include "servfunc.h"
41 #include "fplrun.h"
42
43 /* --- Global ----------------------------------------------------- */
44
45 extern time_t now;
46
47 extern char cmodes[], chanmodes[], ckey[], chankey[];
48 extern char channel[], nickname[], servername[];
49 extern char botmatch[], myaddr[];
50 extern char askforops[];
51 extern char *errfrom;
52
53 extern bool nickflag, connected, restart, moderateflag;
54 extern bool lockmode, lockkey, locklimit;
55 extern bool netsplitmode;
56 extern bool deopprotect;
57 extern bool talkative;
58 extern bool warnmode;
59 extern bool multimode;
60 extern bool cleanup;
61 extern bool invitable;
62 extern bool autojoin;
63 extern bool autoop;
64 extern bool dispcomment;
65 extern bool autoop;
66 extern bool kickbans;
67 extern bool autounban;
68 extern bool strictopmode;
69 extern bool fakenamemode;
70 extern bool opprotect;
71 extern bool oplevel;
72 extern bool mute;
73 extern bool possiblyfresh;
74 extern bool bantimeouts;
75 extern bool chat;
76 extern bool public;
77
78 extern int possiblyfreshtime;
79 extern int pubbantime;
80 extern int retry;
81
82 extern long climit;
83 extern long levels[];
84
85 extern itemident *current;
86
87
88 time_t topictime = 0;
89 time_t lastservertime = 0;
90
91 char topic[BIGBUFFER]; /* Topic of the channel */
92 char topicwho[BIGBUFFER]; /* Who made the topic? */
93
94 bool botop = FALSE; /* TRUE if the bot has channel operator status */
95
96 long numofbotmodes;
97 long modecount[11] = { 0,0,0,0,0,0,0,0,0,0,0 };
98 long autoopswaiting = 0;
99 long limitc = 0;
100
101 #define MINMODEPARAMS 3
102 static int maxmodeparams;
103
104 /* ---------------------------------------------------------------- */
105
106 struct
107 {
108 char *name;
109 void (*function)(char *a, char *b);
110 } messages[] =
111 {
112 {"PRIVMSG", OnPrivmsg}, {"MODE", OnMode}, {"JOIN", OnJoin},
113 {"PART", OnPart}, {"QUIT", OnQuit}, {"NICK", OnNick},
114 {"KICK", OnKick}, {"PING", OnPing}, {"PONG", OnPong},
115 {"TOPIC", OnTopic}, {"NOTICE", OnNotice}, {"INVITE", OnInvite},
116 {"ERROR", OnError},
117 {"", (void(*)())(NULL)}
118 };
119
120 #ifndef HAVE_MEMMOVE
memmove(char * to,char * from,int len)121 void memmove(char *to, char *from, int len)
122 {
123 int i;
124
125 if (to > from) {
126 for (i = len - 1; i >= 0; i--)
127 to[i] = from[i];
128 }
129 else {
130 for (i=0; i > len; i++)
131 to[i] = from[i];
132 }
133 }
134 #endif
135
136 /* --- ParseServer ------------------------------------------------ */
137
138 #include "server_gperf.c"
139
ParseServer(char * line)140 void ParseServer(char *line)
141 {
142 char *from, *command, *rest, *end;
143
144 snapshot;
145 if (':' == line[0]) {
146 from = line + 1;
147 command = StrIndex(from, ' ');
148 if (NULL == command)
149 return;
150 *command++ = (char)0;
151 }
152 else {
153 from = servername;
154 command = line;
155 }
156
157 rest = StrIndex(command, ' ');
158 if (NULL == rest)
159 return;
160 *rest++ = (char)0;
161
162 end = StrIndex(rest, '\n');
163 if (end) {
164 if ('\r' == end[-1])
165 end--;
166 *end = (char)0;
167 }
168
169 if (isdigit(command[0])) {
170 OnNumeric(from, atoi(command), rest);
171 }
172 else {
173 struct Servercmds *p;
174
175 p = FindServerKey(command, StrLength(command));
176 if (p) {
177 lastservertime = now;
178 p->function(from, rest);
179 }
180 }
181 }
182
183 /* --- OnPrivmsg -------------------------------------------------- */
184
OnPrivmsg(char * from,char * line)185 void OnPrivmsg(char *from, char *line)
186 {
187 char nick[NICKLEN+1], userhost[MIDBUFFER];
188 char target[MIDBUFFER], buffer[BIGBUFFER];
189 char *xs;
190
191 snapshot;
192 if ('$' == line[0]) /* Ignore global messages */
193 return;
194
195 if ((2 == StrScan(from, "%"NICKLENTXT"[^!]!%"MIDBUFFERTXT"s",
196 nick, userhost)) &&
197 (2 == StrScan(line, "%"MIDBUFFERTXT"s :%"BIGBUFFERTXT"[^\n]",
198 target, buffer))) {
199
200 errfrom = nick;
201 public = IsChannel(target);
202 chat = FALSE;
203
204 xs = StrIndex(buffer, '\001');
205 if (xs) {
206 char ctcpfrom[MIDBUFFER];
207 char ctcpbuffer[BIGBUFFER];
208 char *ys;
209 int len;
210
211 do {
212 ys = StrIndex(xs + 1, '\001');
213 if (NULL == ys)
214 break; /* do - while */
215 len = ys - xs - 1;
216 if (len > 0) {
217 memmove(ctcpbuffer, xs + 1, len);
218 ctcpbuffer[len] = (char)0;
219 len = StrLength(ys + 1);
220 if (len > 0 ) {
221 memmove(xs, ys + 1, len);
222 xs[len] = (char)0;
223 }
224 else
225 *xs = (char)0;
226
227 StrCopyMax(ctcpfrom, sizeof(ctcpfrom), from);
228 if (public)
229 PubCTCP(ctcpfrom, ctcpbuffer);
230 else
231 CTCP(ctcpfrom, ctcpbuffer);
232 }
233 else
234 xs += 2; /* Empty ctcp */
235 } while (xs = StrIndex(xs, '\001'));
236 }
237
238 if (buffer[0]) {
239 if (public)
240 PubCommand(nick, userhost, buffer);
241 else
242 Command(nick, userhost, buffer);
243 }
244 }
245 else
246 Debug("Parse error in OnPrivmsg(from = \"%s\", line = \"%s\")", from, line);
247 }
248
249 /* --- OnNotice --------------------------------------------------- */
250
OnNotice(char * from,char * line)251 void OnNotice(char *from, char *line)
252 {
253 char target[MIDBUFFER], buffer[BIGBUFFER];
254
255 snapshot;
256 if (2 == StrScan(line, "%"MIDBUFFERTXT"s :%"BIGBUFFERTXT"[^\n]",
257 target, buffer)) {
258
259 if (IsServer(from)) { /* Server notices */
260 char bywho[MIDBUFFER];
261 char channelbuffer[MIDBUFFER];
262 char modebuffer[BIGBUFFER];
263
264 if (3 == StrScan(buffer, "Fake: %"MIDBUFFERTXT"s MODE %"MIDBUFFERTXT"s %"BIGBUFFERTXT"[^\n]",
265 bywho, channelbuffer, modebuffer)) {
266 StrFormatMax(buffer, sizeof(buffer), "Fake: \"%s\" on channel %s by %s [%s]",
267 modebuffer, channelbuffer, bywho, from);
268 Log(LOG, buffer);
269 Multicast(REPORTCAST, buffer);
270 }
271 }
272 #if 0
273 else {
274 char nick[NICKLEN+1];
275 char userhost[MIDBUFFER];
276 itemguest *g;
277
278 if (2 == StrScan(from, "%"NICKLENTXT"[^!]!%"MIDBUFFERTXT"s",
279 nick, userhost)) {
280 g = FindNick(nick);
281 if (g) {
282 floodcheck();
283 }
284 }
285 }
286 #endif
287 }
288 else
289 Debug("Parse error in OnNotice(from = \"%s\", line = \"%s\")", from, line);
290 }
291
292 /* --- OnTopic ---------------------------------------------------- */
293
OnTopic(char * from,char * line)294 void OnTopic(char *from, char *line)
295 {
296 char nick[NICKLEN+1], userhost[MIDBUFFER];
297 char target[MIDBUFFER], buffer[BIGBUFFER] = "";
298
299 snapshot;
300 if ((2 == StrScan(from, "%"NICKLENTXT"[^!]!%"MIDBUFFERTXT"s",
301 nick, userhost)) &&
302 (1 <= StrScan(line, "%"MIDBUFFERTXT"s :%"BIGBUFFERTXT"[^\n]",
303 target, buffer))) {
304
305 Logf(LOGTOPIC, "\"%s\" by %s (%s)", buffer, nick, userhost);
306
307 #ifdef HAVE_LIBFPL
308 if (runfpl(RUN_TOPIC, line, FPLRUN_PRE))
309 return;
310 #endif
311
312 StrCopyMax(topic, sizeof(topic), buffer);
313 StrCopyMax(topicwho, sizeof(topicwho), from);
314 topictime = now;
315
316 runfpl(RUN_TOPIC, line, FPLRUN_POST);
317 }
318 else
319 Debug("Parse error in OnTopic(from = \"%s\", line = \"%s\")", from, line);
320 }
321
322 /* --- OnInvite --------------------------------------------------- */
323
OnInvite(char * from,char * line)324 void OnInvite(char *from, char *line)
325 {
326 char nick[NICKLEN+1], userhost[MIDBUFFER];
327 char target[MIDBUFFER];
328 itemuser *u;
329
330 snapshot;
331 if ((2 == StrScan(from, "%"NICKLENTXT"[^!]!%"MIDBUFFERTXT"s",
332 nick, userhost)) &&
333 (1 == StrScan(line, "%*s :%"MIDBUFFERTXT"s", target))) {
334
335 Logf(LOG, "Invited to %s by %s", target, from);
336
337 #ifdef HAVE_LIBFPL
338 if (runfpl(RUN_INVITE, target, FPLRUN_PRE))
339 return;
340 #endif
341
342 u = FindUser(nick, userhost);
343 if (u && (u->level >= LEVELTRUST)) {
344 if (invitable) {
345 errfrom = nick;
346 CmdJoin(nick, target);
347 }
348 else
349 Send(nick, GetDefaultText(msg_no_invitation));
350 }
351 runfpl(RUN_INVITE, target, FPLRUN_POST);
352 }
353 else
354 Debug("Parse error in OnInvite(from = \"%s\", line = \"%s\")", from, line);
355 }
356
357 /* --- OnMode ----------------------------------------------------- */
358
359 #define MAXMODEPARAMS 6
360 #define MAXSOLOMODES 8
361
362 struct Modeparamlist {
363 char *param[MAXMODEPARAMS];
364 int index;
365 };
366
OnMode(char * from,char * line)367 void OnMode(char *from, char *line)
368 {
369 char flagbuffer[MINIBUFFER], parambuffer[BIGBUFFER];
370 char domode[MAXSOLOMODES+1], undomode[MAXSOLOMODES+1];
371 char *userhost, *modes, *param;
372 char c, cursign = '+';
373 bool servermode, botmode;
374 bool keymode = FALSE, limitmode = FALSE;
375 bool dirty_hack = FALSE;
376 int params = 0, i = 0, j = 0;
377 itemguest *pc, *who;
378 struct Modeparamlist chopon, chopoff, voiceon, voiceoff;
379 struct Modeparamlist banon, banoff;
380 struct Modeparamlist bxcepton, bxceptoff, ixcepton, ixceptoff;
381 struct Modeparamlist temp;
382
383 snapshot;
384 StrTokenize(from, "!");
385 userhost = StrTokenize(NULL, "");
386
387 Logf(LOGMODE, "\"%s\" by %s%s%s%s", line, from,
388 userhost ? " (" : "",
389 userhost ? userhost : "",
390 userhost ? ")" : "");
391
392 if (!IsChannel(NextWord(line)))
393 return; /* Ignore user mode changes */
394
395 servermode = IsServer(from);
396 if (servermode) {
397 botmode = FALSE;
398 who = NULL;
399 }
400 else {
401 botmode = StrEqualCase(from, nickname);
402 who = FindNick(from); /* Who did the mode change? */
403 }
404
405 modes = NextWord(line);
406 if (NULL == modes)
407 return; /* Parse error! */
408
409 chopon.index = chopoff.index = voiceon.index = voiceoff.index = \
410 banon.index = banoff.index = bxcepton.index = bxceptoff.index = \
411 ixcepton.index = ixceptoff.index = 0;
412
413 while (c = *modes++) {
414 switch (c) {
415
416 case '+':
417 case '-':
418 cursign = c;
419 break;
420
421 case 'o':
422 param = NextWord(line);
423 if (param) {
424 params++;
425
426 if ('+' == cursign) {
427 modecount[0]++;
428 if (MAXMODEPARAMS > chopon.index)
429 chopon.param[chopon.index++] = param;
430 }
431 else {
432 if (MAXMODEPARAMS > chopoff.index)
433 chopoff.param[chopoff.index++] = param;
434 }
435
436 if (StrEqualCase(param, nickname)) {
437 /* This is us! */
438 if (talkative && !mute) {
439 if ('+' == cursign) {
440 if (!botop)
441 Actionf(GetDefaultText(msg_thanks_for_ops), from);
442 }
443 else {
444 if (botop)
445 Actionf(GetDefaultText(msg_slaps_for_deop), from);
446 }
447 }
448
449 botop = ('+' == cursign);
450 }
451
452 if (botmode) {
453 pc = FindNick(param);
454 if (pc) {
455 pc->flags.chanop = ('+' == cursign);
456 pc->flags.splitop = FALSE;
457 }
458 }
459 }
460 break;
461
462 case 'b':
463 param = NextWord(line);
464 if (param) {
465 params++;
466
467 if ('+' == cursign) {
468 modecount[1]++;
469 if (MAXMODEPARAMS > banon.index)
470 banon.param[banon.index++] = param;
471 }
472 else {
473 if (MAXMODEPARAMS > banoff.index)
474 banoff.param[banoff.index++] = param;
475 }
476
477 if (servermode) {
478 if ('+' == cursign)
479 AddToBanList(BAN_ACTUAL, from, NULL, param, 0, NULL);
480 }
481 else {
482 if ('+' == cursign) {
483 char *nick = NULL;
484
485 if (who) {
486 who->bans++;
487 if (!botmode &&
488 (who->ident->level < LEVELBOT) &&
489 IllegalBan(param)) {
490 /*
491 * Not set by bot AND the banner has too little level AND
492 * matches the bot or a ban-proctected person (when
493 * banprotection is on).
494 */
495 Mode("%s-b%s%s %s",
496 dirty_hack ? "" : "-o",
497 dirty_hack ? "" : " ",
498 dirty_hack ? "" : from,
499 param);
500
501 /* Lets not deop the abuser again */
502 dirty_hack = TRUE;
503 }
504 }
505
506 /*
507 * We make an attempt to see if we can find a nick to attach
508 * with the specified ban pattern. This works [pretty good]
509 * in all cases when the ban is set before the kick...
510 */
511 pc = FindHost(param);
512 if (pc) {
513 nick = pc->ident->nick;
514 }
515 else {
516 /*
517 * Ok, no user matched the banpattern that was set. We're
518 * going for more casual guesses. Now, let's take a quick look
519 * and see if any of the recent kicks match the pattern.
520 *
521 * We don't try the SEEN functions since they could be very
522 * extensive and take quite some time (a few months in #Amiga
523 * gives a lot more than 10000 hosts and 20000 nicks).
524 */
525 itemkick *k;
526
527 k = KickMatch(param);
528 if (k)
529 nick = k->nick;
530 }
531
532 /* If we found the nick the 'guess-way', we set the GUESS bit */
533 AddToBanList(BAN_ACTUAL | (nick ? BAN_GUESSNICK : 0),
534 from, nick, param,
535 botmode ? -1 : pubbantime, NULL);
536 }
537 else
538 Unbanned(from, param, botmode);
539 }
540
541 if ('+' == cursign) {
542 int num;
543
544 num = CountBans(BAN_ACTUAL);
545 if (BANLIST_ALERTSIZE <= num) {
546 static time_t lastwarn = 0;
547
548 if (!autounban || !botop || !UnbanLoprio(from)) {
549 /*
550 * The bot can be told to automatically unban the least important
551 * ban when reaching this amount. If it isn't, or it isn't
552 * opped, or the unban failed for some reason, we procede
553 * (and make the ALERT output).
554 */
555
556 if ((now - lastwarn) > 10*SECINMIN) {
557 /* Max-rate is every 10th minute! */
558 if (!mute)
559 Actionf(GetDefaultText(msg_alert_banlist_full), num);
560
561 Logf(LOGWARN, "Banlist contains %d bans!", num);
562 lastwarn = now;
563 }
564 }
565 }
566 }
567 }
568 break;
569
570 case 'e':
571 param = NextWord(line);
572 if (param) {
573 params++;
574
575 if ('+' == cursign) {
576 if (MAXMODEPARAMS > bxcepton.index)
577 bxcepton.param[bxcepton.index++] = param;
578 }
579 else {
580 if (MAXMODEPARAMS > bxceptoff.index)
581 bxceptoff.param[bxceptoff.index++] = param;
582 }
583 }
584 break;
585
586 case 'I':
587 param = NextWord(line);
588 if (param) {
589 params++;
590
591 if ('+' == cursign) {
592 if (MAXMODEPARAMS > ixcepton.index)
593 ixcepton.param[ixcepton.index++] = param;
594 }
595 else {
596 if (MAXMODEPARAMS > ixceptoff.index)
597 ixceptoff.param[ixceptoff.index++] = param;
598 }
599 }
600 break;
601
602 case 'k':
603 param = NextWord(line);
604 if (param) {
605 params++;
606
607 if ('+' == cursign) {
608 modecount[2]++;
609 StrCopyMax(chankey, 32, param);
610 }
611 else {
612 chankey[0] = (char)0;
613 }
614 }
615
616 keymode = TRUE;
617 break;
618
619 case 'l':
620 if ('+' == cursign) {
621 modecount[3]++;
622
623 param = NextWord(line);
624 if (param) {
625 params++;
626 limitc = atoi(param);
627 }
628 }
629 else {
630 limitc = 0;
631 }
632
633 limitmode = TRUE;
634 break;
635
636 case 'v':
637 param = NextWord(line);
638 if (param) {
639 params++;
640
641 if ('+' == cursign)
642 modecount[4]++;
643
644 pc = FindNick(param);
645 if (pc)
646 pc->flags.voice = ('+' == cursign);
647 }
648 break;
649
650 case 'p':
651 case 's':
652 case 'i':
653 case 't':
654 case 'n':
655 case 'm': /* undo changes */
656 if (StrIndex(cmodes, c)) {
657 if ('-' == cursign) {
658 if (MAXSOLOMODES > i)
659 domode[i++] = c;
660 }
661 }
662 else {
663 if ('+' == cursign) {
664 if (MAXSOLOMODES > j)
665 undomode[j++] = c;
666 }
667 }
668
669 if ('+' == cursign) {
670 switch(c) {
671 case 'p': modecount[5]++; break;
672 case 's': modecount[6]++; break;
673 case 'i': modecount[7]++; break;
674 case 't': modecount[8]++; break;
675 case 'n': modecount[9]++; break;
676 case 'm': modecount[10]++; break;
677 }
678 }
679 break;
680 } /* switch */
681 } /* while */
682
683 domode[i] = undomode[j] = (char)0;
684
685 if (maxmodeparams < params) {
686 maxmodeparams = params;
687 }
688
689 /* Reacts to non-bot modes only */
690 if (botmode) {
691 numofbotmodes++; /* Bot changed a mode in the channel */
692 }
693 else {
694 flagbuffer[0] = parambuffer[0] = (char)0;
695 params = 0;
696
697 /* Handle netsplit hacks, strictop and opprotect */
698 for (i = temp.index = 0; i < chopon.index; i++) {
699 pc = FindNick(chopon.param[i]);
700 if (pc) {
701 if (!pc->flags.chanop &&
702 (pc->ident->level < MAX(LEVELRECOG, oplevel))) {
703 if (servermode) {
704 if (netsplitmode && !pc->flags.splitop) {
705 temp.param[temp.index++] = chopon.param[i];
706 }
707 }
708 else {
709 /* Not by server */
710 if (strictopmode) {
711 if (!StrEqualCase(chopon.param[i], nickname) &&
712 who && (who->ident->level < MAX(LEVELBOT, oplevel))) {
713 temp.param[temp.index++] = chopon.param[i];
714 }
715 }
716 }
717 }
718
719 /* The guest *IS* chanop right now */
720 pc->flags.chanop = TRUE;
721 }
722 }
723
724 if (botop && temp.index) {
725 /* We won't inform mass-oppers */
726 if (!servermode && (1 == temp.index) && !mute) {
727 SendNickf(from, GetDefaultText(msg_no_ops_allowed), temp.param[0]);
728 }
729
730 StrCopyMax(flagbuffer, sizeof(flagbuffer), "-");
731
732 if (who && (who->ident->level < MAX(LEVELCHANOP, oplevel)) &&
733 !dirty_hack) {
734 dirty_hack = TRUE;
735 StrAppendMax(flagbuffer, sizeof(flagbuffer), "o");
736 StrFormatAppendMax(parambuffer, sizeof(parambuffer), " %s", from);
737 params++;
738 }
739
740 for (i = 0; i < temp.index; i++) {
741 if (maxmodeparams <= params) {
742 Mode("%s%s", flagbuffer, parambuffer);
743 StrCopyMax(flagbuffer, sizeof(flagbuffer), "-");
744 parambuffer[0] = (char)0;
745 params = 0;
746 }
747
748 StrAppendMax(flagbuffer, sizeof(flagbuffer), "o");
749 StrFormatAppendMax(parambuffer, sizeof(parambuffer), " %s", temp.param[i]);
750 params++;
751 }
752 }
753
754 for (i = temp.index = 0; i < chopoff.index; i++) {
755 pc = FindNick(chopoff.param[i]);
756 if (pc) {
757 if (pc->flags.chanop &&
758 (pc->ident->level >= MAX(LEVELCHANOP, oplevel))) {
759 if (servermode) {
760 if (netsplitmode) {
761 temp.param[temp.index++] = chopoff.param[i];
762 }
763 }
764 else {
765 if (opprotect) {
766 if (who && (who->ident->level < MAX(LEVELCHANOP, oplevel))) {
767 temp.param[temp.index++] = chopoff.param[i];
768 }
769 }
770 }
771 }
772
773 /* Guest *IS NOT* a chanop anymore */
774 pc->flags.chanop = pc->flags.splitop = FALSE;
775 }
776 }
777
778 if (botop && temp.index) {
779 if (who && (who->ident->level < MAX(LEVELCHANOP, oplevel)) &&
780 !dirty_hack) {
781 dirty_hack = TRUE;
782
783 if (maxmodeparams <= params) {
784 Mode("%s%s", flagbuffer, parambuffer);
785 params = 0;
786 }
787
788 if (0 == params) {
789 StrCopyMax(flagbuffer, sizeof(flagbuffer), "-");
790 parambuffer[0] = (char)0;
791 }
792
793 StrAppendMax(flagbuffer, sizeof(flagbuffer), "o");
794 StrFormatAppendMax(parambuffer, sizeof(parambuffer), " %s", from);
795 params++;
796 }
797
798 if (maxmodeparams > params) {
799 StrAppendMax(flagbuffer, sizeof(flagbuffer), "+");
800 }
801
802 for (i = 0; i < temp.index; i++) {
803 if (maxmodeparams <= params) {
804 Mode("%s%s", flagbuffer, parambuffer);
805 StrCopyMax(flagbuffer, sizeof(flagbuffer), "+");
806 parambuffer[0] = (char)0;
807 params = 0;
808 }
809
810 StrAppendMax(flagbuffer, sizeof(flagbuffer), "o");
811 StrFormatAppendMax(parambuffer, sizeof(parambuffer), " %s", temp.param[i]);
812 params++;
813 }
814 }
815
816 if (botop) {
817 if (flagbuffer[0]) {
818 Mode("%s%s", flagbuffer, parambuffer);
819 }
820
821 /* Only LEVELBOT or higher users are allowed to set/remove exceptions */
822 if (who && (who->ident->level < MAX(LEVELBOT, oplevel))) {
823 flagbuffer[0] = parambuffer[0] = (char)0;
824
825 if (bxcepton.index || ixcepton.index) {
826 StrAppendMax(flagbuffer, sizeof(flagbuffer), "-");
827 }
828
829 /* Remove user +e's */
830 for (i = 0; i < bxcepton.index; i++) {
831 StrAppendMax(flagbuffer, sizeof(flagbuffer), "e");
832 StrFormatAppendMax(parambuffer, sizeof(parambuffer), " %s",
833 bxcepton.param[i]);
834 }
835
836 /* Remove user +I's */
837 for (i = 0; i < ixcepton.index; i++) {
838 StrAppendMax(flagbuffer, sizeof(flagbuffer), "I");
839 StrFormatAppendMax(parambuffer, sizeof(parambuffer), " %s",
840 ixcepton.param[i]);
841 }
842
843 #if 0
844 /* We need to keep a list of exceptions to compare with */
845 if (bxceptoff.index || ixceptoff.index) {
846 StrAppendMax(flagbuffer, sizeof(flagbuffer), "+");
847 }
848
849 /* Reset user -e's */
850 for (i = 0; i < bxceptoff.index; i++) {
851 StrAppendMax(flagbuffer, sizeof(flagbuffer), "e");
852 StrFormatAppendMax(parambuffer, sizeof(parambuffer), " %s",
853 bxceptoff.param[i]);
854 }
855
856 /* Reset user -I's */
857 for (i = 0; i < ixceptoff.index; i++) {
858 StrAppendMax(flagbuffer, sizeof(flagbuffer), "I");
859 StrFormatAppendMax(parambuffer, sizeof(parambuffer), " %s",
860 ixceptoff.param[i]);
861 }
862 #endif
863
864 if (flagbuffer[0]) {
865 if (who->ident->level < MAX(LEVELCHANOP, oplevel))
866 Mode("-o %s", from);
867 Mode("%s%s", flagbuffer, parambuffer);
868 }
869 }
870
871 /* React to channel key changes */
872 if (lockkey && keymode) {
873 if (servermode || (who && (who->ident->level < MAX(LEVELBOT, oplevel)))) {
874 if (!StrEqualCase(ckey, chankey)) {
875 if (chankey[0])
876 Mode("-k %s", chankey);
877 if (ckey[0])
878 Mode("+k %s", ckey);
879 }
880 }
881 }
882
883 /* React to channel mode changes */
884 if (lockmode && (domode[0] || undomode[0])) {
885 if (servermode || (who && (who->ident->level < MAX(LEVELCHANOP, oplevel)))) {
886 Mode("%s%s%s%s", domode[0] ? "+" : "", domode,
887 undomode[0] ? "-" : "", undomode);
888 }
889 }
890
891 /* React to channel limit changes */
892 if (locklimit && limitmode) {
893 if (servermode || (who && (who->ident->level < MAX(LEVELCHANOP, oplevel)))) {
894 if (climit != limitc) {
895 /* We got a limit we don't like */
896 if (0 == climit)
897 Mode("-l");
898 else
899 Mode("+l %d", climit);
900 }
901 }
902 }
903 }
904
905 if (servermode) {
906 /* Server actions are only here on net-heals! */
907 NetHeal();
908
909 /* Remove bans set by server */
910 if (possiblyfreshtime &&
911 ((now - possiblyfreshtime) < SERVERBANTIMEOUT)) {
912
913 for (i = 0; i < banon.index; i++) {
914 if (IsUnban(banon.param[i])) {
915 /* If one of them bans matched an unbanned one! It means that we
916 don't consider this a "fresh" split! */
917 possiblyfreshtime = 0;
918 break;
919 }
920 }
921
922 if (possiblyfreshtime) {
923 /* Don't unban serverbans */
924 banon.index = 0;
925 }
926 }
927
928 if (botop) {
929 flagbuffer[0] = parambuffer[0] = (char)0;
930
931 /* Remove +b server modes */
932 for (i = 0; i < banon.index; i++) {
933 StrAppendMax(flagbuffer, sizeof(flagbuffer), "b");
934 StrFormatAppendMax(parambuffer, sizeof(parambuffer), " %s",
935 banon.param[i]);
936 }
937
938 /* Remove all +e server modes for the moment */
939 for (i = 0; i < bxcepton.index; i++) {
940 StrAppendMax(flagbuffer, sizeof(flagbuffer), "e");
941 StrFormatAppendMax(parambuffer, sizeof(parambuffer), " %s",
942 bxcepton.param[i]);
943 }
944
945 /* Remove all +I server for the moment */
946 for (i = 0; i < ixcepton.index; i++) {
947 StrAppendMax(flagbuffer, sizeof(flagbuffer), "I");
948 StrFormatAppendMax(parambuffer, sizeof(parambuffer), " %s",
949 ixcepton.param[i]);
950 }
951
952 if (flagbuffer[0])
953 Mode("-%s%s", flagbuffer, parambuffer);
954 }
955 }
956 else {
957 /* Not server */
958 if (deopprotect && (temp.index > 1) && botop && who)
959 Warning(who, "deoppers", "Mass-deop detected");
960 }
961 }
962 }
963
964 /* --- OnJoin ----------------------------------------------------- */
965
OnJoin(char * from,char * line)966 void OnJoin(char *from, char *line)
967 {
968 char nick[NICKLEN+1], userhost[MIDBUFFER];
969 char target[MIDBUFFER];
970 char *servermodes, *pointer;
971 extern char unetserv[];
972
973 snapshot;
974 switch (line[0]) {
975
976 case ':':
977 pointer = &line[1];
978 break;
979
980 default:
981 pointer = line;
982 break;
983
984 }
985
986 if ((2 == StrScan(from, "%"NICKLENTXT"[^!]!%"MIDBUFFERTXT"s",
987 nick, userhost)) &&
988 (1 == StrScan(pointer, "%"MIDBUFFERTXT"s", target))) {
989
990 runfpl(RUN_JOIN, nick, FPLRUN_PRE);
991
992 /* ircd2.9 uses '\a' to append modes (server ops/voice) */
993 servermodes = StrIndex(target, '\a');
994 if (servermodes)
995 *servermodes++ = (char)0;
996
997 if (StrEqualCase(nick, nickname)) {
998 StrCopyMax(channel, 200, target);
999 #ifdef NICKSERV
1000 WriteServer("CHANSERV op %s %s", channel, nickname);
1001 #endif
1002
1003 #ifdef UNDERNET
1004 WriteServer("PRIVMSG %s :OP %s %s", unetserv, channel, nickname);
1005 #endif
1006 WriteServer("WHO %s", target); /* Who are on the channel */
1007 WriteServer("MODE %s", target); /* What are the channel modes */
1008 WriteServer("MODE %s b", target); /* What are the bans */
1009 }
1010 else {
1011 bool nethealjoin = FALSE;
1012 itemguest *g;
1013
1014 if (AddGuest(nick, userhost, FALSE, FALSE, FALSE, &g)) {
1015 if (moderateflag && botop)
1016 Mode("+v %s", nick);
1017 }
1018 else {
1019 /* Netjoin or error */
1020 nethealjoin = TRUE;
1021 }
1022
1023 if (g) {
1024 current = g->ident;
1025
1026 if (fakenamemode && g->ident->illegalname)
1027 StickyKick(g, GetDefaultText(msg_illegal_name));
1028
1029 if (kickbans) {
1030 /* Check done even if not opped for the purpose of being better aware
1031 of the situation when later opped */
1032 if (IsBan(from))
1033 StickyKick(g, "Go away, you're banned here!");
1034 }
1035
1036 if (servermodes) {
1037 /* Make a fake mode change */
1038 char xfrom[MIDBUFFER], xline[MIDBUFFER];
1039
1040 StrCopyMax(xfrom, sizeof(xfrom), servername);
1041 StrFormatMax(xline, sizeof(xline), "%s +%s %s %s",
1042 target, servermodes, nick,
1043 (servermodes[1] ? nick : ""));
1044 OnMode(xfrom, xline);
1045 }
1046
1047 if (autoop && IsAutoOp(g)) {
1048 /* DONT op anyone at this join, when several bots/people run services
1049 like this the channel simply gets flooded after long lasting netheals.
1050 Let's wait a (random) while before checking this user if it is op,
1051 and if it still isn't, op the poor thing. */
1052 g->op_this_person = now + Rnd()*10+10;
1053 autoopswaiting++;
1054 }
1055
1056 if (multimode && (g->ident->level < LEVELEXPERT) && !g->flags.bot) {
1057 /* Do this check even if not opped, the knowledge can be good if we
1058 are suddenly opped in the middle of an attack */
1059 MultiCheck(g->ident->userdomain);
1060 }
1061
1062 if (warnmode)
1063 WarnCheck(nick, userhost);
1064
1065 if (dispcomment && !nethealjoin)
1066 DispComment(g);
1067 }
1068 }
1069
1070 runfpl(RUN_JOIN, nick, FPLRUN_POST);
1071 }
1072 else
1073 Debug("Parse error in OnJoin(from = \"%s\", line = \"%s\")", from, line);
1074 }
1075
1076 /* --- OnPart ----------------------------------------------------- */
1077
OnPart(char * from,char * line)1078 void OnPart(char *from, char *line)
1079 {
1080 char nick[NICKLEN+1], userhost[MIDBUFFER];
1081 char target[MIDBUFFER], buffer[BIGBUFFER] = "";
1082
1083 snapshot;
1084 if ((2 == StrScan(from, "%"NICKLENTXT"[^!]!%"MIDBUFFERTXT"s",
1085 nick, userhost)) &&
1086 (1 <= StrScan(line, "%"MIDBUFFERTXT"s :%"BIGBUFFERTXT"[^\n]",
1087 target, buffer))) {
1088
1089 Logf(LOGPART, "%s%s%s%s", nick,
1090 buffer[0] ? " (" : "",
1091 buffer[0] ? buffer : "",
1092 buffer[0] ? ")" : "");
1093
1094 runfpl(RUN_LEAVE, nick, FPLRUN_PRE);
1095
1096 if (StrEqualCase(nick, nickname)) { /* I left */
1097 SeenInsertAll(SEENLEFT, NULL, NULL);
1098 DeleteGuests();
1099 BanDisable(); /* No valid bans anymore */
1100 }
1101 else {
1102 itemguest *g;
1103
1104 g = FindNick(nick);
1105 if (g) {
1106 SeenInsert(g, SEENLEAVE, NULL,
1107 (buffer[0] && !StrEqualCase(buffer, nick)) ? buffer : NULL);
1108 RemoveGuest(g);
1109 }
1110 else
1111 Debug("Internal confusion. Unknown user \"%s\" left.", from);
1112 }
1113
1114 runfpl(RUN_LEAVE, nick, FPLRUN_POST);
1115 }
1116 else
1117 Debug("Parse error in OnPart(from = \"%s\", line = \"%s\")", from, line);
1118 }
1119
1120 /* --- OnQuit ----------------------------------------------------- */
1121
OnQuit(char * from,char * line)1122 void OnQuit(char *from, char *line)
1123 {
1124 char nick[NICKLEN+1], userhost[MIDBUFFER];
1125 char buffer[BIGBUFFER] = "";
1126
1127 snapshot;
1128 /* There might be no reason at all, ie. only ":\000" */
1129 StrScan(line, ":%"BIGBUFFERTXT"[^\n]", buffer);
1130
1131 if (2 == StrScan(from, "%"NICKLENTXT"[^!]!%"MIDBUFFERTXT"s",
1132 nick, userhost)) {
1133
1134 Logf(LOGQUIT, "%s (%s)", nick, buffer);
1135
1136 runfpl(RUN_QUIT, nick, FPLRUN_PRE);
1137
1138 if (StrEqualCase(nick, nickname)) { /* I quitted */
1139 SeenInsertAll(SEENQUITED, NULL, NULL);
1140 DeleteGuests();
1141 BanDisable();
1142 }
1143 else {
1144 bool split = FALSE;
1145 itemguest *g;
1146
1147 g = FindNick(nick);
1148 if (g) {
1149 /* Enhanced split detection to trap even more faked ones */
1150 if (PatternExist(buffer, "^[-A-Z0-9a-z.*]+[.][A-Za-z]+ [-A-Z0-9a-z.*]+[.][A-Za-z]+")) {
1151 char name1[MIDBUFFER];
1152 char name2[MIDBUFFER];
1153 char *p;
1154
1155 if (2 == StrScan(buffer, "%"MIDBUFFERTXT"s %"MIDBUFFERTXT"s",
1156 name1, name2)) {
1157 p = StrIndexLast(name1, '.');
1158 if (p && FindByCode(&p[1])) {
1159 p = StrIndexLast(name2, '.');
1160 if (p && FindByCode(&p[1]))
1161 split = TRUE;
1162 }
1163 }
1164 }
1165
1166 SeenInsert(g, SEENQUIT, NULL, buffer);
1167 if (split)
1168 AddSplitter(g, buffer);
1169 else
1170 RemoveGuest(g);
1171 }
1172 else
1173 Debug("Internal confusion. Unknown user \"%s\" quit.", from);
1174 }
1175
1176 runfpl(RUN_QUIT, nick, FPLRUN_POST);
1177 }
1178 else
1179 Debug("Parse error in OnQuit(from = \"%s\", line = \"%s\")", from, line);
1180 }
1181
1182 /* --- OnKick ----------------------------------------------------- */
1183
OnKick(char * from,char * line)1184 void OnKick(char *from, char *line)
1185 {
1186 char nick[NICKLEN+1], userhost[MIDBUFFER];
1187 char target[MIDBUFFER], victim[NICKLEN+1], buffer[BIGBUFFER];
1188
1189 snapshot;
1190 if ((2 == StrScan(from, "%"NICKLENTXT"[^!]!%"MIDBUFFERTXT"s",
1191 nick, userhost)) &&
1192 (3 == StrScan(line, "%"MIDBUFFERTXT"s %"NICKLENTXT"s :%"BIGBUFFERTXT"[^\n]",
1193 target, victim, buffer))) {
1194
1195 Logf(LOGKICK, "(%s) by %s", line, from);
1196
1197 runfpl(RUN_KICK, line, FPLRUN_PRE);
1198
1199 if (StrEqualCase(victim, nickname)) { /* I was kicked */
1200 SeenInsertAll(SEENKICKED, from, NULL);
1201 DeleteGuests();
1202 BanDisable(); /* No valid bans anymore */
1203 if (autojoin)
1204 WriteServer("JOIN %s %s", channel, chankey);
1205 #ifdef HAVE_LIBFPL
1206 if (!runfpl(RUN_KICKBOT, from, FPLRUN_PRE))
1207 runfpl(RUN_KICKBOT, from, FPLRUN_POST);
1208 #endif
1209 }
1210 else {
1211 itemguest *g, *w;
1212
1213 w = FindNick(nick);
1214 if (w)
1215 w->kicks++;
1216
1217 g = FindNick(victim); /* This _CAN_ return NULL */
1218 if (g) {
1219 if (StrEqualCase(nick, nickname)) { /* Bot kick */
1220 AddKick(g->ident, from, buffer, KICK_COMMON);
1221 }
1222 else { /* Not a bot kick */
1223 AddKick(g->ident, from, buffer,
1224 (g->ident->level < LEVELTRUST) ? KICK_COMMON : KICK_TRUSTEDUSER);
1225
1226 if (opprotect) {
1227 if (botop && w &&
1228 (w->ident->level < MAX(LEVELCHANOP, oplevel)) &&
1229 (g->ident->level >= MAX(LEVELCHANOP, oplevel))) {
1230 Mode("-o %s", nick);
1231 }
1232 }
1233 }
1234 SeenInsert(g, SEENKICK, from, buffer);
1235 RemoveGuest(g);
1236 }
1237 else
1238 Debug("Internal confusion. Unknown user \"%s\" was kicked.", victim);
1239 }
1240
1241 runfpl(RUN_KICK, target, FPLRUN_POST);
1242 }
1243 else
1244 Debug("Parse error in OnKick(from = \"%s\", line = \"%s\")", from, line);
1245 }
1246
1247 /* --- OnNick ----------------------------------------------------- */
1248
OnNick(char * from,char * line)1249 void OnNick(char *from, char *line)
1250 {
1251 char nick[NICKLEN+1], userhost[MIDBUFFER];
1252 char newnick[NICKLEN+1];
1253
1254 snapshot;
1255 if ((2 == StrScan(from, "%"NICKLENTXT"[^!]!%"MIDBUFFERTXT"s",
1256 nick, userhost)) &&
1257 (1 == StrScan(line, ":%"NICKLENTXT"s", newnick))) {
1258
1259 Logf(LOGNICK, "%s is now known as %s (%s)", nick, newnick, userhost);
1260
1261 runfpl(RUN_NICK, nick, FPLRUN_PRE);
1262
1263 if (StrEqualCase(nick, nickname)) {
1264 StrCopy(nickname, newnick);
1265 StrFormatMax(botmatch, MIDBUFFER, "%s!%s", newnick, myaddr);
1266 SendLinkAll(IBCP_NICKNAME, "%s", newnick);
1267 }
1268 ChangeGuest(nick, newnick);
1269
1270 runfpl(RUN_NICK, newnick, FPLRUN_POST);
1271 }
1272 else
1273 Debug("Parse error in OnNick(from = \"%s\", line = \"%s\")", from, line);
1274 }
1275
1276 /* --- OnPing ----------------------------------------------------- */
1277
OnPing(char * from,char * line)1278 void OnPing(char *from, char *line)
1279 {
1280 char forward[MIDBUFFER];
1281
1282 snapshot;
1283 if (1 == StrScan(line, "%*s %"MIDBUFFERTXT"s", forward))
1284 WriteServer("PONG %s", forward);
1285 else
1286 WriteServer("PONG %s", (':' == line[0]) ? &line[1] : line);
1287 }
1288
1289 /* --- OnPong ----------------------------------------------------- */
1290
1291 int pendingpings = 0;
1292 struct timeval pingval;
1293 struct timeval pongval;
1294 struct timeval delayval;
1295
OnPong(char * from,char * line)1296 void OnPong(char *from, char *line)
1297 {
1298 snapshot;
1299 pendingpings--;
1300 gettimeofday(&pongval, NULL);
1301 delayval.tv_sec = pongval.tv_sec - pingval.tv_sec;
1302 delayval.tv_usec = pongval.tv_usec - pingval.tv_usec;
1303
1304 /* Normalize the time values */
1305 while (delayval.tv_usec > MILLION) {
1306 delayval.tv_usec -= MILLION;
1307 delayval.tv_sec++;
1308 }
1309 while (delayval.tv_usec < 0) {
1310 delayval.tv_usec += MILLION;
1311 delayval.tv_sec--;
1312 }
1313 }
1314
PingServer(void)1315 void PingServer(void)
1316 {
1317 snapshot;
1318 pendingpings++;
1319 gettimeofday(&pingval, NULL);
1320 WriteServer("PING :%s", servername);
1321 }
1322
1323 /* --- OnError ---------------------------------------------------- */
1324
OnError(char * from,char * line)1325 void OnError(char *from, char *line)
1326 {
1327 char buffer[BIGBUFFER];
1328
1329 snapshot;
1330 #ifdef HAVE_LIBFPL
1331 if (!runfpl(RUN_ERROR, line, FPLRUN_PRE))
1332 runfpl(RUN_ERROR, line, FPLRUN_POST);
1333 #endif
1334
1335 StrFormatMax(buffer, sizeof(buffer), "ERROR: (%s) from %s",
1336 (':' == line[0]) ? &line[1] : line, from);
1337 Log(LOG, buffer);
1338 DisconnectServ(buffer);
1339 connected = FALSE;
1340
1341 SeenInsertAll(SEENERROR, line, NULL);
1342 DeleteGuests();
1343 BanDisable();
1344
1345 restart = cleanup = TRUE;
1346 }
1347
1348 /* --- OnKill ----------------------------------------------------- */
1349
1350 #if 0
1351 void OnKill(char *from, char *line)
1352 {
1353 snapshot;
1354 Logf(LOGKILL, "(%s) by %s", line, from);
1355
1356 #ifdef HAVE_LIBFPL
1357 if (!runfpl(RUN_KILL, line, FPLRUN_PRE))
1358 runfpl(RUN_KILL, line, FPLRUN_POST);
1359 #endif
1360
1361 DisconnectServ(line);
1362 connected = FALSE;
1363
1364 SeenInsertAll(SEENKILL, from, line);
1365 DeleteGuests();
1366 BanDisable();
1367
1368 restart = cleanup = TRUE;
1369 }
1370 #endif
1371
1372 #ifdef NICKSERV
1373 extern char nickpasswd[];
1374 #endif
1375
1376 #ifdef UNDERNET
1377 extern char unetpasswd[];
1378 extern char unetnick[];
1379 extern char unetserv[];
1380 #endif
1381
1382 /* --- OnNumeric -------------------------------------------------- */
1383
OnNumeric(char * from,int num,char * line)1384 void OnNumeric(char *from, int num, char *line)
1385 {
1386 char buffer[BIGBUFFER];
1387 char number[22];
1388
1389 snapshot;
1390 StrFormatMax(number, sizeof(number), "%d", num);
1391 runfpl(RUN_NUMERIC, number, FPLRUN_PRE);
1392
1393 switch (num) {
1394
1395 case RPL_WELCOME: /* Welcomming message */
1396 connected = TRUE;
1397 StrCopyMax(servername, MIDBUFFER, from);
1398 StrScan(line, "%"NICKLENTXT"s", nickname);
1399 #ifndef DBUG
1400 WriteServer("MODE %s +is", nickname);
1401 #else
1402 WriteServer("MODE %s +i", nickname);
1403 #endif
1404 #ifdef NICKSERV
1405 WriteServer("NICKSERV identify %s", nickpasswd);
1406 #endif
1407 #ifdef UNDERNET
1408 WriteServer("PRIVMSG %s :LOGIN %s %s", unetserv, unetnick, unetpasswd);
1409 #endif
1410 WriteServer("JOIN %s %s", channel, chankey);
1411 gettimeofday(&pongval, NULL);
1412 retry = 0;
1413 maxmodeparams = MINMODEPARAMS;
1414 break;
1415
1416 case ERR_NICKNAMEINUSE: /* Nickname already in use */
1417 case ERR_ERRONEUSNICKNAME: /* or wrong nickname */
1418 case ERR_UNAVAILRESOURCE: /* Nick/channel is temporarily unavailable */
1419 if (!nickflag)
1420 nickflag = TRUE;
1421 else {
1422 NewNick();
1423 WriteServer("NICK %s", nickname);
1424 }
1425 break;
1426
1427 case ERR_NICKCOLLISION: /* Nickname collision */
1428 Log(LOG, "Nickname collision");
1429 restart = cleanup = TRUE;
1430 break;
1431
1432 case ERR_NOTREGISTERED: /* You have not registered */
1433 Hello(NULL);
1434 break;
1435
1436 case RPL_WHOREPLY: /* Users on channel at join time */
1437 NewGuest_Who(line);
1438 break;
1439
1440 case RPL_TOPIC: /* The topic on join */
1441 topictime = now;
1442 topic[0] = (char)0;
1443 StrScan(line, "%*s %*s :%"BIGBUFFERTXT"[^\n]", topic);
1444 StrCopyMax(topicwho, sizeof(topicwho), from);
1445 break;
1446
1447 case RPL_NOTOPIC:
1448 topictime = 0;
1449 break;
1450
1451 case RPL_CHANNELMODEIS:
1452 chanmodes[0] = (char)0;
1453 StrScan(line, "%*s %*s +%15s", chanmodes);
1454 break;
1455
1456 case RPL_BANLIST: /* get 3rd word */
1457 if (1 == StrScan(line, "%*s %*s %"BIGBUFFERTXT"s", buffer)) {
1458 /* fprintf(stderr, "BANLIST ENTRY: '%s'\n", buffer); */
1459 AddToBanList(BAN_ACTUAL, NULL, NULL, buffer, -1, NULL);
1460 }
1461 break;
1462
1463 case RPL_ENDOFBANLIST:
1464 /* we're at the end of banlist */
1465 bantimeouts = TRUE; /* enable timeouts now */
1466 if (!CountBans(BAN_ACTUAL)) {
1467 /* no actual bans in the channel */
1468 possiblyfresh = TRUE; /* restarted server? */
1469 /* fprintf(stderr, "### no bans in channel! ###\n"); */
1470 }
1471 break;
1472
1473 case ERR_NOSUCHNICK: /* Flush messages if target has disappeared */
1474 case ERR_NOSUCHCHANNEL:
1475 if (1 == StrScan(line, "%*s %"NICKLENTXT"s", buffer))
1476 MessageReaper(buffer);
1477 break;
1478
1479 case ERR_CANNOTSENDTOCHAN: /* Check for channel desync */
1480 case ERR_CHANOPRIVSNEEDED:
1481 if (!StrEqual(from, servername)) {
1482 StrFormatMax(buffer, sizeof(buffer), "Desync: Server %s rejected request", from);
1483 Log(LOG, buffer);
1484 Multicast(REPORTCAST, buffer);
1485 }
1486 break;
1487
1488 case RPL_ENDOFNAMES: /* End of /NAMES list */
1489 if (*askforops && !botop)
1490 Action(askforops);
1491 break;
1492
1493 case ERR_CHANNELISFULL:
1494 StrFormatMax(buffer, sizeof(buffer), "Channel %s is full", channel);
1495 Log(LOG, buffer);
1496 Multicast(REPORTCAST, buffer);
1497 break;
1498
1499 case ERR_INVITEONLYCHAN:
1500 StrFormatMax(buffer, sizeof(buffer), "Channel %s is invite-only", channel);
1501 Log(LOG, buffer);
1502 Multicast(REPORTCAST, buffer);
1503 break;
1504
1505 case ERR_BANNEDFROMCHAN:
1506 StrFormatMax(buffer, sizeof(buffer), "Banned from channel %s", channel);
1507 Log(LOG, buffer);
1508 Multicast(REPORTCAST, buffer);
1509 break;
1510
1511 case ERR_BADCHANNELKEY:
1512 StrFormatMax(buffer, sizeof(buffer), "Bad channel key for %s", channel);
1513 Log(LOG, buffer);
1514 Multicast(REPORTCAST, buffer);
1515 break;
1516
1517 case ERR_NOPERMFORHOST: /* Not I-lined */
1518 Logf(LOG, "No permission to connect to server %s", servername);
1519 break;
1520
1521 case ERR_YOUREBANNEDCREEP: /* K-lined */
1522 Logf(LOG, "Banned from server %s", servername);
1523 break;
1524
1525 #if 0
1526 /* Messages we definetely ignore: */
1527
1528 /* MOTD junk */
1529 case RPL_MOTDSTART:
1530 case RPL_MOTD:
1531 case RPL_ENDOFMOTD:
1532
1533 /* Inital crap info: */
1534 case RPL_YOURHOST: /* 'Darxide :Your host is irc.ludd.luth.se, running
1535 version 2.9.2+Cr8' */
1536 case RPL_CREATED: /* 'Darxide :This server was created Sun Jan 26
1537 1997 at 16:54:21 MET' */
1538 case RPL_MYINFO: /* 'Darxide irc.ludd.luth.se 2.9.2+Cr8 oirw abiklmnopqstv' */
1539
1540 /* Luser statistics: */
1541 case RPL_LUSERCLIENT: /* 'Darxide :There are 11523 users and 0 services
1542 on 61 servers' */
1543 case RPL_LUSEROP: /* 'Darxide 88 :operators online' */
1544 case RPL_LUSERUNKNOWN: /* 'Darxide 2 :unknown connections' */
1545 case RPL_LUSERCHANNELS: /* 'Darxide 4319 :channels formed' */
1546 case RPL_LUSERME: /* 'Darxide :I have 309 clients, 0 services and 3
1547 servers' */
1548
1549 case RPL_NAMREPLY: /* the name list we get automatically when we join a
1550 channel */
1551
1552 case RPL_ENDOFWHO: /* End of /WHO list */
1553
1554 #endif
1555
1556 default: /* Recommended ending of a switch() */
1557
1558 /* case ERR_RESTRICTED: we're restricted here, could try to change to a
1559 different server */
1560
1561 if (num >= ERR_NOSUCHNICK) {
1562 /* Log errors only */
1563 Logf(LOG, "Server message %d: '%s'", num, line);
1564 }
1565 break;
1566 }
1567 runfpl(RUN_NUMERIC, number, FPLRUN_POST);
1568 }
1569