1 /*
2 * parse.c: handles messages from the server. Believe it or not. I
3 * certainly wouldn't if I were you.
4 *
5 * Written By Michael Sandrof
6 *
7 * Copyright (c) 1990 Michael Sandrof.
8 * Copyright (c) 1991, 1992 Troy Rollo.
9 * Copyright (c) 1992-2021 Matthew R. Green.
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include "irc.h"
37 IRCII_RCSID("@(#)$eterna: parse.c,v 1.123 2021/02/27 08:00:42 mrg Exp $");
38
39 #include "server.h"
40 #include "names.h"
41 #include "vars.h"
42 #include "ctcp.h"
43 #include "hook.h"
44 #include "edit.h"
45 #include "ignore.h"
46 #include "whois.h"
47 #include "lastlog.h"
48 #include "ircaux.h"
49 #include "funny.h"
50 #include "irccrypt.h"
51 #include "ircterm.h"
52 #include "flood.h"
53 #include "window.h"
54 #include "screen.h"
55 #include "output.h"
56 #include "numbers.h"
57 #include "parse.h"
58 #include "notify.h"
59 #include "notice.h"
60 #include "alias.h"
61
62 #define STRING_CHANNEL '+'
63 #define MULTI_CHANNEL '#'
64 #define LOCAL_CHANNEL '&'
65 #define SAFE_CHANNEL '!'
66
67 #define MAXPARA 15 /* Taken from the ircd */
68
69 static void break_args(u_char *, u_char **, u_char **);
70 static void p_linreply(u_char *, u_char *, u_char **);
71 static void p_ping(u_char *, u_char *, u_char **);
72 static void p_topic(u_char *, u_char *, u_char **);
73 static void p_wall(u_char *, u_char *, u_char **);
74 static void p_wallops(u_char *, u_char **);
75 static void p_privmsg(u_char *, u_char *, u_char **);
76 static void p_quit(u_char *, u_char **);
77 static void p_pong(u_char *, u_char *, u_char **);
78 static void p_error(u_char *, u_char **);
79 static void p_channel(u_char *, u_char *, u_char **);
80 static void p_invite(u_char *, u_char **);
81 static void p_server_kill(u_char *, u_char **);
82 static void p_nick(u_char *, u_char *, u_char **);
83 static void p_mode(u_char *, u_char *, u_char **);
84 static void p_kick(u_char *, u_char *, u_char **);
85 static void p_part(u_char *, u_char *, u_char **);
86
87 /* User and host information from server 2.7 */
88 static u_char *FromUserHost = NULL;
89
90 /* doing a PRIVMSG */
91 static int doing_privmsg_active = 0;
92
93 /*
94 * joined_nick: the nickname of the last person who joined the current
95 * channel
96 */
97 static u_char *joined_nick = NULL;
98
99 /* public_nick: nick of the last person to send a message to your channel */
100 static u_char *public_nick = NULL;
101
102 /*
103 * is_channel: determines if the argument is a channel. If it's a number,
104 * begins with MULTI_CHANNEL and has no '*', or STRING_CHANNEL, then its a
105 * channel.
106 */
107 int
is_channel(u_char * to)108 is_channel(u_char *to)
109 {
110 int version;
111 const int from_server = get_from_server();
112
113 if (to == 0)
114 return (0);
115
116 version = server_get_version(from_server);
117 if (version == ServerICB)
118 return (my_stricmp(to, server_get_icbgroup(from_server)) == 0);
119 else
120 return ((version < Server2_7 && (isdigit(*to) || (*to == STRING_CHANNEL) || *to == '-'))
121 || (version > Server2_6 && *to == MULTI_CHANNEL)
122 || (version > Server2_7 && *to == LOCAL_CHANNEL)
123 || (version > Server2_8 && *to == STRING_CHANNEL)
124 || (version > Server2_9 && *to == SAFE_CHANNEL));
125 }
126
127
128 /*
129 * paste_args: re-connect a string broken up with break_args(), with a
130 * starting point. paste_args(ArgList, 2) will end up with 3 strings
131 * in ArgList[0], ArgList[1] the same as post-break_args(), and with
132 * all the remaining arguments in ArgList[2].
133 */
134 u_char *
paste_args(u_char ** Args,int StartPoint)135 paste_args(u_char **Args, int StartPoint)
136 {
137 int i;
138
139 for (; StartPoint; Args++, StartPoint--)
140 if (!*Args)
141 return NULL;
142 for (i = 0; Args[i] && Args[i+1]; i++)
143 Args[i][my_strlen(Args[i])] = ' ';
144 Args[1] = NULL;
145 return Args[0];
146 }
147
148 /*
149 * break_args: breaks up the line from the server, in to where its from,
150 * setting FromUserHost if it should be, and returns all the arguements
151 * that are there. Re-written by phone, dec 1992.
152 *
153 * using this function will leave you will a NULL terminated list, and
154 * any attempt to use any argument must ensure that all the previous
155 * entries are not NULL. eg, do not check or use for ArgList[1] without
156 * first making sure ArgList[0] is not NULL.
157 */
158 static void
break_args(u_char * Input,u_char ** Sender,u_char ** OutPut)159 break_args(u_char *Input, u_char **Sender, u_char **OutPut)
160 {
161 u_char *s = Input,
162 *t;
163 int ArgCount = 0;
164
165 /*
166 * Get sender from :sender and user@host if :nick!user@host
167 */
168 FromUserHost = NULL;
169
170 if (*Input == ':')
171 {
172 u_char *tmp;
173
174 *Input++ = '\0';
175 if ((s = (u_char *) my_index(Input, ' ')) != NULL)
176 *s++ = '\0';
177 *Sender = Input;
178 if ((tmp = (u_char *) my_index(*Sender, '!')) != NULL)
179 {
180 *tmp++ = '\0';
181 FromUserHost = tmp;
182 }
183 }
184 else
185 *Sender = empty_string();
186
187 if (s)
188 {
189 for (;;)
190 {
191 while (*s == ' ')
192 *s++ = '\0';
193
194 if (!*s)
195 break;
196
197 if (*s == ':')
198 {
199 for (t = s; *t; t++)
200 *t = *(t + 1);
201 OutPut[ArgCount++] = s;
202 break;
203 }
204 OutPut[ArgCount++] = s;
205 if (ArgCount >= MAXPARA)
206 break;
207
208 for (; *s != ' ' && *s; s++)
209 ;
210 }
211 }
212 while (ArgCount <= MAXPARA)
213 OutPut[ArgCount++] = NULL;
214 }
215
216 /* beep_em: Not hard to figure this one out */
217 void
beep_em(int beeps)218 beep_em(int beeps)
219 {
220 int cnt,
221 i;
222
223 for (cnt = beeps, i = 0; i < cnt; i++)
224 term_beep();
225 }
226
227 /* in response to a TOPIC message from the server */
228 static void
p_topic(u_char * comm,u_char * from,u_char ** ArgList)229 p_topic(u_char *comm, u_char *from, u_char **ArgList)
230 {
231 int flag;
232
233 if (check_params(comm, from, 1, ArgList, 1))
234 return;
235
236 flag = double_ignore(from, from_user_host(), IGNORE_CRAP);
237 if (flag == IGNORED)
238 return;
239
240 save_message_from();
241 if (!ArgList[1])
242 {
243 message_from(NULL, LOG_CRAP);
244 if (do_hook(TOPIC_LIST, "%s * %s", from, ArgList[0]))
245 say("%s has changed the topic to %s", from, ArgList[0]);
246 }
247 else
248 {
249 message_from(ArgList[0], LOG_CRAP);
250 if (do_hook(TOPIC_LIST, "%s %s %s", from, ArgList[0], ArgList[1]))
251 say("%s has changed the topic on channel %s to %s",
252 from, ArgList[0], ArgList[1]);
253 }
254 restore_message_from();
255 }
256
257 static void
p_linreply(u_char * comm,u_char * from,u_char ** ArgList)258 p_linreply(u_char *comm, u_char *from, u_char **ArgList)
259 {
260 if (check_params(comm, from, 0, ArgList, 1))
261 return;
262
263 paste_args(ArgList, 0);
264 say("%s", ArgList[0]);
265 }
266
267 static void
p_wall(u_char * comm,u_char * from,u_char ** ArgList)268 p_wall(u_char *comm, u_char *from, u_char **ArgList)
269 {
270 int flag,
271 level;
272 u_char *line;
273 u_char *high;
274
275 if (check_params(comm, from, 0, ArgList, 1))
276 return;
277
278 paste_args(ArgList, 0);
279 line = ArgList[0];
280 flag = double_ignore(from, from_user_host(), IGNORE_WALLS);
281 save_message_from();
282 message_from(from, LOG_WALL);
283 if (flag != IGNORED)
284 {
285 if (flag == HIGHLIGHTED)
286 high = highlight_str();
287 else
288 high = empty_string();
289 if ((flag != DONT_IGNORE) && (ignore_usernames() & IGNORE_WALLS)
290 && !from_user_host())
291 add_to_whois_queue(from, whois_ignore_walls, "%s",line);
292 else
293 {
294 level = set_lastlog_msg_level(LOG_WALL);
295 if (check_flooding(from,
296 server_get_nickname(parsing_server()),
297 WALL_FLOOD, line) && do_hook(WALL_LIST, "%s %s",
298 from, line))
299 put_it("%s#%s#%s %s", high, from, high, line);
300 if (do_beep_on_level(LOG_WALL))
301 beep_em(1);
302 set_lastlog_msg_level(level);
303 }
304 }
305 restore_message_from();
306 }
307
308 static void
p_wallops(u_char * from,u_char ** ArgList)309 p_wallops(u_char *from, u_char **ArgList)
310 {
311 int flag, level;
312 u_char *line;
313
314 if (!from)
315 return;
316 if (!(line = paste_args(ArgList, 0)))
317 return;
318 flag = double_ignore(from, from_user_host(), IGNORE_WALLOPS);
319 level = set_lastlog_msg_level(LOG_WALLOP);
320 save_message_from();
321 message_from(from, LOG_WALLOP);
322 if (my_index(from, '.'))
323 {
324 u_char *high;
325
326 if (flag != IGNORED)
327 {
328 if (flag == HIGHLIGHTED)
329 high = highlight_str();
330 else
331 high = empty_string();
332 if (do_hook(WALLOP_LIST, "%s S %s", from, line))
333 put_it("%s!%s!%s %s", high, from, high, line);
334 if (do_beep_on_level(LOG_WALLOP))
335 beep_em(1);
336 }
337 }
338 else
339 {
340 if (get_int_var(USER_WALLOPS_VAR))
341 {
342 if (flag != DONT_IGNORE &&
343 check_flooding(from,
344 server_get_nickname(parsing_server()),
345 WALLOP_FLOOD, line))
346 add_to_whois_queue(from, whois_new_wallops, "%s", line);
347 }
348 else if (my_strcmp(from, server_get_nickname(get_window_server(0))) != 0)
349 put_it("!%s! %s", from, line);
350 }
351 set_lastlog_msg_level(level);
352 restore_message_from();
353 }
354
355 void
whoreply(u_char * from,u_char ** ArgList)356 whoreply(u_char *from, u_char **ArgList)
357 {
358 static u_char format[40];
359 static int last_width = -1;
360 int ok;
361 u_char *channel,
362 *user,
363 *host,
364 *server,
365 *nick,
366 *status,
367 *name;
368 int i;
369
370 if (last_width != get_int_var(CHANNEL_NAME_WIDTH_VAR))
371 {
372 if ((last_width = get_int_var(CHANNEL_NAME_WIDTH_VAR)) != 0)
373 snprintf(CP(format), sizeof format, "%%-%u.%us %%-9s %%-3s %%s@%%s (%%s)",
374 (u_char) last_width,
375 (u_char) last_width);
376 else
377 my_strcpy(format, UP("%s\t%-9s %-3s %s@%s (%s)"));
378 }
379 i = 0;
380 channel = user = host = server = nick = status = name = empty_string();
381 if (ArgList[i])
382 channel = ArgList[i++];
383 if (ArgList[i])
384 user = ArgList[i++];
385 if (ArgList[i])
386 host = ArgList[i++];
387 if (ArgList[i])
388 server = ArgList[i++];
389 if (ArgList[i])
390 nick = ArgList[i++];
391 if (ArgList[i])
392 status = ArgList[i++];
393 paste_args(ArgList, i);
394
395 if (ArgList[i])
396 name = ArgList[i];
397
398 ok = whoreply_check(channel, user, host, server, nick, status, name, format);
399 if (ok)
400 {
401 if (do_hook(WHO_LIST, "%s %s %s %s %s %s", channel, nick,
402 status, user, host, name))
403 {
404 if (get_int_var(SHOW_WHO_HOPCOUNT_VAR))
405 put_it(CP(format), channel, nick, status, user, host,
406 name);
407 else
408 {
409 u_char *tmp;
410
411 if ((tmp = (u_char *) my_index(name, ' ')) !=
412 NULL)
413 tmp++;
414 else
415 tmp = name;
416 put_it(CP(format), channel, nick, status, user, host,
417 tmp);
418 }
419 }
420 }
421 }
422
423 static void
p_privmsg(u_char * comm,u_char * from,u_char ** ArgList)424 p_privmsg(u_char *comm, u_char *from, u_char **ArgList)
425 {
426 int level,
427 flag,
428 list_type,
429 flood_type,
430 log_type;
431 u_char ignore_type;
432 u_char *ptr,
433 *to;
434 u_char *high;
435 int no_flood;
436
437 if (check_params(comm, from, 0, ArgList, 2))
438 return;
439
440 paste_args(ArgList, 1);
441 to = ArgList[0];
442 ptr = ArgList[1];
443 save_message_from();
444 if (is_channel(to))
445 {
446 malloc_strcpy(&public_nick, from);
447 if (!is_on_channel(to, parsing_server(), from))
448 {
449 log_type = LOG_PUBLIC;
450 ignore_type = IGNORE_PUBLIC;
451 list_type = PUBLIC_MSG_LIST;
452 flood_type = PUBLIC_FLOOD;
453 }
454 else
455 {
456 log_type = LOG_PUBLIC;
457 ignore_type = IGNORE_PUBLIC;
458 if (is_current_channel(to, parsing_server(), 0))
459 list_type = PUBLIC_LIST;
460 else
461 list_type = PUBLIC_OTHER_LIST;
462 flood_type = PUBLIC_FLOOD;
463 }
464 message_from(to, log_type);
465 }
466 else
467 {
468 flood_type = MSG_FLOOD;
469 if (my_stricmp(to, server_get_nickname(parsing_server())))
470 {
471 log_type = LOG_WALL;
472 ignore_type = IGNORE_WALLS;
473 list_type = MSG_GROUP_LIST;
474 }
475 else
476 {
477 log_type = LOG_MSG;
478 ignore_type = IGNORE_MSGS;
479 list_type = MSG_LIST;
480 }
481 message_from(from, log_type);
482 }
483 flag = double_ignore(from, from_user_host(), ignore_type);
484 switch (flag)
485 {
486 case IGNORED:
487 if ((list_type == MSG_LIST) && get_int_var(SEND_IGNORE_MSG_VAR))
488 send_to_server("NOTICE %s :%s is ignoring you", from,
489 server_get_nickname(parsing_server()));
490 goto out;
491 case HIGHLIGHTED:
492 high = highlight_str();
493 break;
494 default:
495 high = empty_string();
496 break;
497 }
498 level = set_lastlog_msg_level(log_type);
499 ptr = do_ctcp(from, to, ptr);
500 if (!ptr || !*ptr)
501 goto out;
502 if ((flag != DONT_IGNORE) && (ignore_usernames() & ignore_type) && !from_user_host())
503 add_to_whois_queue(from, whois_ignore_msgs, "%s", ptr);
504 else
505 {
506 no_flood = check_flooding(from, to, flood_type, ptr);
507 if (ctcp_was_crypted() == 0 || do_hook(ENCRYPTED_PRIVMSG_LIST,"%s %s %s",from, to, ptr))
508 {
509 switch (list_type)
510 {
511 case PUBLIC_MSG_LIST:
512 if (no_flood && do_hook(list_type, "%s %s %s", from, to, ptr))
513 put_it("%s(%s/%s)%s %s", high, from, to, high, ptr);
514 break;
515 case MSG_GROUP_LIST:
516 if (no_flood && do_hook(list_type, "%s %s %s", from, to, ptr))
517 put_it("%s-%s:%s-%s %s", high, from, to, high, ptr);
518 break;
519 case MSG_LIST:
520 if (!no_flood)
521 break;
522 set_recv_nick(from);
523 if (is_away_set())
524 beep_em(get_int_var(BEEP_WHEN_AWAY_VAR));
525 if (do_hook(list_type, "%s %s", from, ptr))
526 {
527 if (is_away_set())
528 {
529 time_t t;
530 u_char *msg = NULL;
531 size_t len = my_strlen(ptr) + 20;
532
533 t = time(NULL);
534 msg = new_malloc(len);
535 snprintf(CP(msg), len, "%s <%.16s>", ptr, ctime(&t));
536 put_it("%s*%s*%s %s", high, from, high, msg);
537 new_free(&msg);
538 }
539 else
540 put_it("%s*%s*%s %s", high, from, high, ptr);
541 }
542 break;
543 case PUBLIC_LIST:
544 if (get_int_var(MAKE_NOTICE_MSG_VAR))
545 doing_privmsg_active = 1;
546 if (no_flood && do_hook(list_type, "%s %s %s", from,
547 to, ptr))
548 put_it("%s<%s>%s %s", high, from, high, ptr);
549 doing_privmsg_active = 0;
550 break;
551 case PUBLIC_OTHER_LIST:
552 if (get_int_var(MAKE_NOTICE_MSG_VAR))
553 doing_privmsg_active = 1;
554 if (no_flood && do_hook(list_type, "%s %s %s", from,
555 to, ptr))
556 put_it("%s<%s:%s>%s %s", high, from, to, high,
557 ptr);
558 doing_privmsg_active = 0;
559 break;
560 }
561 if (do_beep_on_level(log_type))
562 beep_em(1);
563 }
564 }
565 set_lastlog_msg_level(level);
566 out:
567 restore_message_from();
568 }
569
570 static void
p_quit(u_char * from,u_char ** ArgList)571 p_quit(u_char *from, u_char **ArgList)
572 {
573 int one_prints = 0;
574 u_char *chan;
575 u_char *Reason;
576 int flag;
577
578 flag = double_ignore(from, from_user_host(), IGNORE_CRAP);
579 save_message_from();
580 if (flag != IGNORED)
581 {
582 paste_args(ArgList, 0);
583 Reason = ArgList[0] ? ArgList[0] : (u_char *) "?";
584 for (chan = walk_channels(from, 1, parsing_server()); chan; chan = walk_channels(from, 0, -1))
585 {
586 message_from(chan, LOG_CRAP);
587 if (do_hook(CHANNEL_SIGNOFF_LIST, "%s %s %s", chan, from, Reason))
588 one_prints = 1;
589 }
590 if (one_prints)
591 {
592 message_from(what_channel(from, parsing_server()), LOG_CRAP);
593 if (do_hook(SIGNOFF_LIST, "%s %s", from, Reason))
594 say("Signoff: %s (%s)", from, Reason);
595 }
596 }
597 message_from(NULL, LOG_CURRENT);
598 remove_from_channel(NULL, from, parsing_server());
599 notify_mark(from, 0, 0);
600 restore_message_from();
601 }
602
603 static void
p_pong(u_char * comm,u_char * from,u_char ** ArgList)604 p_pong(u_char *comm, u_char *from, u_char **ArgList)
605 {
606 int flag;
607
608 if (check_params(comm, from, 0, ArgList, 1))
609 return;
610
611 flag = double_ignore(from, from_user_host(), IGNORE_CRAP);
612 if (flag == IGNORED)
613 return;
614
615 if (ArgList[0])
616 say("%s: PONG received from %s", ArgList[0], from);
617 }
618
619 static void
p_error(u_char * from,u_char ** ArgList)620 p_error(u_char *from, u_char **ArgList)
621 {
622 if (ArgList[0] == NULL)
623 return;
624 paste_args(ArgList, 0);
625 say("%s", ArgList[0]);
626 }
627
628 static void
p_channel(u_char * comm,u_char * from,u_char ** ArgList)629 p_channel(u_char *comm, u_char *from, u_char **ArgList)
630 {
631 int join;
632 u_char *channel;
633 int flag;
634 u_char *s, *ov = NULL;
635 int chan_oper = 0, chan_voice = 0;
636
637 if (check_params(comm, from, 0, ArgList, 1))
638 return;
639
640 flag = double_ignore(from, from_user_host(), IGNORE_CRAP);
641 if (my_strcmp(ArgList[0], zero()))
642 {
643 join = 1;
644 channel = ArgList[0];
645 /*
646 * this \007 should be \a but a lot of compilers are
647 * broken. *sigh* -mrg
648 */
649 if ((ov = s = my_index(channel, '\007')))
650 {
651 *s = '\0';
652 ov++;
653 while (*++s)
654 {
655 if (*s == 'o')
656 chan_oper = 1;
657 if (*s == 'v')
658 chan_voice = 1;
659
660 }
661 }
662 malloc_strcpy(&joined_nick, from);
663 }
664 else
665 {
666 channel = zero();
667 join = 0;
668 }
669 if (!my_stricmp(from, server_get_nickname(parsing_server())))
670 {
671 if (join)
672 {
673 add_channel(channel, 0, parsing_server(), CHAN_JOINED, NULL);
674 send_to_server("MODE %s", channel);
675 }
676 else
677 remove_channel(channel, parsing_server());
678 }
679 else
680 {
681 save_message_from();
682 message_from(channel, LOG_CRAP);
683 if (join)
684 add_to_channel(channel, from, parsing_server(), chan_oper, chan_voice);
685 else
686 remove_from_channel(channel, from, parsing_server());
687 restore_message_from();
688 }
689 if (join)
690 {
691 if (!get_channel_oper(channel, parsing_server()))
692 set_in_on_who(1);
693 save_message_from();
694 message_from(channel, LOG_CRAP);
695 if (flag != IGNORED && do_hook(JOIN_LIST, "%s %s %s", from,
696 channel, ov ? ov : (u_char *) ""))
697 {
698 if (from_user_host())
699 if (ov && *ov)
700 say("%s (%s) has joined channel %s +%s", from,
701 from_user_host(), channel, ov);
702 else
703 say("%s (%s) has joined channel %s", from,
704 from_user_host(), channel);
705 else
706 if (ov && *ov)
707 say("%s has joined channel %s +%s", from,
708 channel, ov);
709 else
710 say("%s has joined channel %s", from, channel);
711 }
712 restore_message_from();
713 set_in_on_who(0);
714 }
715 }
716
717 static void
p_invite(u_char * from,u_char ** ArgList)718 p_invite(u_char *from, u_char **ArgList)
719 {
720 u_char *high;
721 int flag;
722
723 if (!from)
724 return;
725 flag = double_ignore(from, from_user_host(), IGNORE_INVITES);
726 switch (flag)
727 {
728 case IGNORED:
729 if (get_int_var(SEND_IGNORE_MSG_VAR))
730 send_to_server("NOTICE %s :%s is ignoring you",
731 from, server_get_nickname(parsing_server()));
732 return;
733 case HIGHLIGHTED:
734 high = highlight_str();
735 break;
736 default:
737 high = empty_string();
738 break;
739 }
740 if (ArgList[0] && ArgList[1])
741 {
742 if ((flag != DONT_IGNORE) && (ignore_usernames() & IGNORE_INVITES)
743 && !from_user_host())
744 add_to_whois_queue(from, whois_ignore_invites,
745 "%s", ArgList[1]);
746 else
747 {
748 save_message_from();
749 message_from(from, LOG_CRAP);
750 if (do_hook(INVITE_LIST, "%s %s", from, ArgList[1]))
751 say("%s%s%s invites you to channel %s", high,
752 from, high, ArgList[1]);
753 restore_message_from();
754 set_invite_channel(ArgList[1]);
755 set_recv_nick(from);
756 }
757 }
758 }
759
760 static void
p_server_kill(u_char * from,u_char ** ArgList)761 p_server_kill(u_char *from, u_char **ArgList)
762 {
763 /*
764 * this is so bogus checking for a server name having a '.'
765 * in it - phone, april 1993.
766 */
767 if (my_index(from, '.'))
768 say("You have been rejected by server %s", from);
769 else
770 say("You have been killed by operator %s %s", from,
771 ArgList[0] && ArgList[1] ?
772 ArgList[1] : (u_char *) "(No Reason Given)");
773 close_server(parsing_server(), empty_string());
774 window_check_servers();
775 if (!connected_to_server())
776 say("Use /SERVER to reconnect to a server");
777 }
778
779 static void
p_ping(u_char * comm,u_char * from,u_char ** ArgList)780 p_ping(u_char *comm, u_char *from, u_char **ArgList)
781 {
782 if (check_params(comm, from, 0, ArgList, 1))
783 return;
784
785 send_to_server("PONG :%s", paste_args(ArgList, 0));
786 }
787
788 static void
p_nick(u_char * comm,u_char * from,u_char ** ArgList)789 p_nick(u_char *comm, u_char *from, u_char **ArgList)
790 {
791 int one_prints = 0,
792 its_me = 0;
793 u_char *chan;
794 u_char *line;
795 int flag;
796
797 if (check_params(comm, from, 0, ArgList, 1))
798 return;
799
800 flag = double_ignore(from, from_user_host(), IGNORE_CRAP);
801 line = ArgList[0];
802 if (my_stricmp(from, server_get_nickname(parsing_server())) == 0){
803 if (parsing_server() == get_primary_server())
804 set_nickname(line);
805 server_set_nickname(parsing_server(), line);
806 its_me = 1;
807 }
808 save_message_from();
809 if (flag != IGNORED)
810 {
811 for (chan = walk_channels(from, 1, parsing_server()); chan;
812 chan = walk_channels(from, 0, -1))
813 {
814 message_from(chan, LOG_CRAP);
815 if (do_hook(CHANNEL_NICK_LIST, "%s %s %s", chan, from, line))
816 one_prints = 1;
817 }
818 if (one_prints)
819 {
820 if (its_me)
821 message_from(NULL, LOG_CRAP);
822 else
823 message_from(what_channel(from, parsing_server()), LOG_CRAP);
824 if (do_hook(NICKNAME_LIST, "%s %s", from, line))
825 say("%s is now known as %s", from, line);
826 }
827 }
828 rename_nick(from, line, parsing_server());
829 if (my_stricmp(from, line))
830 {
831 message_from(NULL, LOG_CURRENT);
832 notify_mark(from, 0, 0);
833 notify_mark(line, 1, 0);
834 }
835 restore_message_from();
836 }
837
838 static void
p_mode(u_char * comm,u_char * from,u_char ** ArgList)839 p_mode(u_char *comm, u_char *from, u_char **ArgList)
840 {
841 u_char *channel;
842 u_char *line;
843 int flag;
844
845 if (check_params(comm, from, 0, ArgList, 2))
846 return;
847
848 paste_args(ArgList, 1);
849 channel = ArgList[0];
850 line = ArgList[1];
851
852 flag = double_ignore(from, from_user_host(), IGNORE_CRAP);
853 save_message_from();
854 message_from(channel, LOG_CRAP);
855 if (is_channel(channel))
856 {
857 if (flag != IGNORED && do_hook(MODE_LIST, "%s %s %s",
858 from, channel, line))
859 say("Mode change \"%s\" on channel %s by %s",
860 line, channel, from);
861 update_channel_mode(channel, parsing_server(), line);
862 }
863 else
864 {
865 if (flag != IGNORED && do_hook(MODE_LIST, "%s %s %s",
866 from, channel, line))
867 say("Mode change \"%s\" for user %s by %s",
868 line, channel, from);
869 update_user_mode(line);
870 }
871 update_all_status();
872 restore_message_from();
873 }
874
875 static void
p_kick(u_char * comm,u_char * from,u_char ** ArgList)876 p_kick(u_char *comm, u_char *from, u_char **ArgList)
877 {
878 u_char *channel,
879 *who,
880 *comment;
881
882 if (check_params(comm, from, 0, ArgList, 2))
883 return;
884
885 channel = ArgList[0];
886 who = ArgList[1];
887 comment = ArgList[2];
888
889 save_message_from();
890 message_from(channel, LOG_CRAP);
891 if (my_stricmp(who, server_get_nickname(parsing_server())) == 0)
892 {
893 if (comment && *comment)
894 {
895 if (do_hook(KICK_LIST, "%s %s %s %s", who,
896 from, channel, comment))
897 say("You have been kicked off channel %s by %s (%s)",
898 channel, from, comment);
899 }
900 else
901 {
902 if (do_hook(KICK_LIST, "%s %s %s", who, from,
903 channel))
904 say("You have been kicked off channel %s by %s",
905 channel, from);
906 }
907 remove_channel(channel, parsing_server());
908 update_all_status();
909 }
910 else
911 {
912 if (comment && *comment)
913 {
914 if (do_hook(KICK_LIST, "%s %s %s %s", who,
915 from, channel, comment))
916 say("%s has been kicked off channel %s by %s (%s)",
917 who, channel, from, comment);
918 }
919 else
920 {
921 if (do_hook(KICK_LIST, "%s %s %s", who, from,
922 channel))
923 say("%s has been kicked off channel %s by %s",
924 who, channel, from);
925 }
926 remove_from_channel(channel, who, parsing_server());
927 }
928 restore_message_from();
929 }
930
931 static void
p_part(u_char * comm,u_char * from,u_char ** ArgList)932 p_part(u_char *comm, u_char *from, u_char **ArgList)
933 {
934 u_char *channel;
935 u_char *comment;
936 int flag;
937
938 if (check_params(comm, from, 0, ArgList, 1))
939 return;
940
941 channel = ArgList[0];
942 flag = double_ignore(from, from_user_host(), IGNORE_CRAP);
943 if (!is_on_channel(channel, parsing_server(), from))
944 return;
945 comment = ArgList[1];
946 if (!comment)
947 comment = empty_string();
948 set_in_on_who(1);
949 if (flag != IGNORED)
950 {
951 save_message_from();
952 message_from(channel, LOG_CRAP);
953 if (do_hook(LEAVE_LIST, "%s %s %s", from, channel, comment))
954 {
955 if (comment && *comment != '\0')
956 say("%s has left channel %s (%s)", from, channel, comment);
957 else
958 say("%s has left channel %s", from, channel);
959 }
960 restore_message_from();
961 }
962 if (my_stricmp(from, server_get_nickname(parsing_server())) == 0)
963 remove_channel(channel, parsing_server());
964 else
965 remove_from_channel(channel, from, parsing_server());
966 set_in_on_who(0);
967 }
968
969 /*
970 * irc2_odd_server_stuff(): call this if you parse an IRC message and
971 * it doesn't make sense and perhaps should be warned about.
972 */
973 void
irc2_odd_server_stuff(u_char * comm,u_char * from,u_char ** ArgList)974 irc2_odd_server_stuff(u_char *comm, u_char *from, u_char **ArgList)
975 {
976 u_char *args;
977
978 paste_args(ArgList, 0);
979 args = ArgList[0];
980 if (!args)
981 args = empty_string();
982
983 if (from)
984 say("Odd server stuff: \"%s %s\" (%s)", comm, args, from);
985 else
986 say("Odd server stuff: \"%s %s\"", comm, args);
987 }
988
989 /*
990 * front end to irc2_odd_server_stuff() with argument checking.
991 * 'comm', 'from', and 'args' are passed to irc2_odd_server_stuff()
992 * if check_from is set and from is NULL, or, if any array index
993 * smaller than arg_count is NULL (ie, array must have arg_count
994 * or more entries.)
995 */
996 int
check_params(u_char * comm,u_char * from,int check_from,u_char ** args,unsigned arg_count)997 check_params(u_char *comm, u_char *from, int check_from,
998 u_char **args, unsigned arg_count)
999 {
1000 int fail = 0;
1001
1002 if (check_from && from == NULL)
1003 fail = 1;
1004 else
1005 {
1006 int i;
1007
1008 for (i = 0; i < arg_count; i++)
1009 if (args[i] == NULL)
1010 {
1011 fail = 1;
1012 break;
1013 }
1014 }
1015
1016 if (fail)
1017 {
1018 irc2_odd_server_stuff(comm, from, args);
1019 return 1;
1020 }
1021
1022 return 0;
1023 }
1024
1025 void
irc2_parse_server(u_char * line)1026 irc2_parse_server(u_char *line)
1027 {
1028 u_char *from,
1029 *comm,
1030 *end,
1031 *copy = NULL;
1032 int numeric;
1033 u_char **ArgList;
1034 u_char *TrueArgs[MAXPARA + 1];
1035
1036 if (NULL == line)
1037 return;
1038
1039 end = my_strlen(line) + line - 1;
1040 if (*end == '\n') {
1041 *end = '\0';
1042 if (end > line)
1043 end--;
1044 }
1045 if (*end == '\r')
1046 *end = '\0';
1047
1048 if (end < line)
1049 {
1050 yell("--- HEY BAD BOO");
1051 }
1052
1053 if (*line == ':')
1054 {
1055 if (!do_hook(RAW_IRC_LIST, "%s", line + 1))
1056 return;
1057 }
1058 else if (!do_hook(RAW_IRC_LIST, "%s %s", "*", line))
1059 return;
1060
1061 malloc_strcpy(©, line);
1062 ArgList = TrueArgs;
1063 break_args(copy, &from, ArgList);
1064
1065 if (!(comm = (*ArgList++)))
1066 goto out; /* Empty line from server - ByeBye */
1067
1068 /*
1069 * At this point, from and comm are both valid pointers, but the
1070 * ArgList may start with a NULL. Not all the functions called
1071 * from here require that the ArgList[0] be a valid string, so each
1072 * must check any consumed ArgList[] component is valid.
1073 */
1074
1075 /*
1076 * only allow numbers 1 .. 999.
1077 */
1078 if ((numeric = my_atoi(comm)) > 0 && numeric < 1000)
1079 numbered_command(comm, from, numeric, ArgList);
1080 else if (my_strcmp(comm, "NAMREPLY") == 0)
1081 funny_namreply(comm, from, ArgList);
1082 else if (my_strcmp(comm, "WHOREPLY") == 0)
1083 whoreply(from, ArgList);
1084 else if (my_strcmp(comm, "NOTICE") == 0)
1085 parse_notice(comm, from, ArgList);
1086 /* everything else is handled locally */
1087 else if (my_strcmp(comm, "PRIVMSG") == 0)
1088 p_privmsg(comm, from, ArgList);
1089 else if (my_strcmp(comm, "JOIN") == 0)
1090 p_channel(comm, from, ArgList);
1091 else if (my_strcmp(comm, "PART") == 0)
1092 p_part(comm, from, ArgList);
1093 else if (my_strcmp(comm, "CHANNEL") == 0)
1094 p_channel(comm, from, ArgList);
1095 else if (my_strcmp(comm, "QUIT") == 0)
1096 p_quit(from, ArgList);
1097 else if (my_strcmp(comm, "WALL") == 0)
1098 p_wall(comm, from, ArgList);
1099 else if (my_strcmp(comm, "WALLOPS") == 0)
1100 p_wallops(from, ArgList);
1101 else if (my_strcmp(comm, "LINREPLY") == 0)
1102 p_linreply(comm, from, ArgList);
1103 else if (my_strcmp(comm, "PING") == 0)
1104 p_ping(comm, from, ArgList);
1105 else if (my_strcmp(comm, "TOPIC") == 0)
1106 p_topic(comm, from, ArgList);
1107 else if (my_strcmp(comm, "PONG") == 0)
1108 p_pong(comm, from, ArgList);
1109 else if (my_strcmp(comm, "INVITE") == 0)
1110 p_invite(from, ArgList);
1111 else if (my_strcmp(comm, "NICK") == 0)
1112 p_nick(comm, from, ArgList);
1113 else if (my_strcmp(comm, "KILL") == 0)
1114 p_server_kill(from, ArgList);
1115 else if (my_strcmp(comm, "MODE") == 0)
1116 p_mode(comm, from, ArgList);
1117 else if (my_strcmp(comm, "KICK") == 0)
1118 p_kick(comm, from, ArgList);
1119 else if (my_strcmp(comm, "ERROR") == 0)
1120 p_error(from, ArgList);
1121 else if (my_strcmp(comm, "ERROR:") == 0) /* Server bug makes this a must */
1122 p_error(from, ArgList);
1123 else
1124 irc2_odd_server_stuff(comm, from, ArgList);
1125 out:
1126 new_free(©);
1127 }
1128
1129 int
doing_privmsg(void)1130 doing_privmsg(void)
1131 {
1132 return doing_privmsg_active;
1133 }
1134
1135 u_char *
from_user_host(void)1136 from_user_host(void)
1137 {
1138 return FromUserHost;
1139 }
1140
1141 void
set_from_user_host(u_char * fuh)1142 set_from_user_host(u_char *fuh)
1143 {
1144 FromUserHost = fuh;
1145 }
1146
1147 u_char *
get_joined_nick(void)1148 get_joined_nick(void)
1149 {
1150 return joined_nick;
1151 }
1152
1153 u_char *
get_public_nick(void)1154 get_public_nick(void)
1155 {
1156 return public_nick;
1157 }
1158