1 /*
2  * numbers.c: handles all those strange numeric response dished out by that
3  * wacky, nutty program we call ircd
4  *
5  * Written by Michael Sandrof
6  *
7  * Copyright (c) 1990 Michael Sandrof.
8  * Copyright (c) 1991, 1992 Troy Rollo.
9  * Copyright (c) 1992-2000 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("@(#)$Id: numbers.c,v 1.57 2000/07/18 17:12:21 mrg Exp $");
38 
39 #include "input.h"
40 #include "edit.h"
41 #include "ircaux.h"
42 #include "vars.h"
43 #include "lastlog.h"
44 #include "hook.h"
45 #include "server.h"
46 #include "whois.h"
47 #include "numbers.h"
48 #include "window.h"
49 #include "screen.h"
50 #include "output.h"
51 #include "whois.h"
52 #include "funny.h"
53 #include "parse.h"
54 
55 #include "dma.h"
56 #include "ckey.h"
57 #include "bans.h"
58 #include "ninja.h"
59 #include "channels.h"
60 #include "nicks.h"
61 
62 static	void	nickname_in_use _((u_char *, u_char **));
63 static	void	password_sendline _((u_char *, u_char *));
64 static	void	get_password _((void));
65 static	void	nickname_sendline _((u_char *, u_char *));
66 static	void	channel_topic _((u_char *, u_char **));
67 static	void	not_valid_channel _((u_char *, u_char **));
68 static	void	cannot_join_channel _((u_char *, u_char **));
69 static	void	version _((u_char *, u_char **));
70 static	void	invite _((u_char *, u_char **));
71 
72 /* ninja extensions */
73 static	void	channel_topic_time _((u_char *, u_char **));
74 static	void	show_ban_except_line _((u_char *, u_char **));
75 extern	u_char	*old_nick;
76 	u_char	*leader = UNULL;
77 
78 static	int	already_doing_reset_nickname = 0;
79 
80 /*
81  * numeric_banner: This returns in a static string of either "xxx" where
82  * xxx is the current numeric, or "***" if SHOW_NUMBERS is OFF
83  */
84 u_char	*
numeric_banner()85 numeric_banner()
86 {
87    static	u_char	thing[8];
88 
89    if (get_string_var(LEADER_VAR) && !get_int_var(SHOW_NUMERICS_VAR))
90      return leader;
91 
92    memset(thing, 0, sizeof(thing));
93    if (get_int_var(SHOW_NUMERICS_VAR))
94      snprintf(CP(thing), sizeof(thing)-1, "%3.3u ", -current_numeric);
95    else
96      my_strcpy(thing, "*** "); /* safe thing[8] */
97    return (thing);
98 }
99 
100 
101 /*
102  * display_msg: handles the displaying of messages from the variety of
103  * possible formats that the irc server spits out.  you'd think someone would
104  * simplify this
105  */
106 void
display_msg(from,ArgList)107 display_msg(from, ArgList)
108 	u_char	*from,
109 		**ArgList;
110 {
111 	u_char	*ptr;
112 	u_char	*rest;
113 
114 	rest = PasteArgs(ArgList, 0);
115 	if (from && (my_strnicmp(get_server_itsname(parsing_server_index), from,
116 			my_strlen(get_server_itsname(parsing_server_index))) == 0))
117 		from = (u_char *) 0;
118 	if ((ptr = (u_char *) my_index(rest, ':')) != NULL)
119 	{
120 		*(ptr++) = (u_char) 0;
121 		if (my_strlen(rest))
122 		{
123 			if (from)
124 				put_it("%s%s: %s (from %s)", numeric_banner(),
125 					rest, ptr, from);
126 			else
127 				put_it("%s%s: %s", numeric_banner(), rest,
128 					ptr);
129 		}
130 		else
131 		{
132 			if (from)
133 				put_it("%s%s (from %s)", numeric_banner(),
134 					ptr, from);
135 			else
136 				put_it("%s%s", numeric_banner(), ptr);
137 		}
138 	}
139 	else
140 	{
141 		if (from)
142 			put_it("%s%s (from %s)", numeric_banner(), rest, from);
143 		else
144 			put_it("%s%s", numeric_banner(), rest);
145 	}
146 }
147 
148 /*
149  * password_sendline: called by send_line() in get_password() to handle
150  * hitting of the return key, etc
151  */
152 static	void
password_sendline(data,line)153 password_sendline(data, line)
154 	u_char	*data;
155 	u_char	*line;
156 {
157 	int	new_server;
158 
159 	new_server = my_atoi(data);
160 	set_server_password(new_server, line);
161 	connect_to_server(get_server_name(new_server),
162 		get_server_port(new_server), get_server_nickname(new_server), -1);
163 }
164 
165 /*
166  * get_password: when a host responds that the user needs to supply a
167  * password, it gets handled here!  the user is prompted for a password and
168  * then reconnection is attempted with that password.  but, the reality of
169  * the situation is that no one really uses user passwords.  ah well
170  */
171 static	void
get_password()172 get_password()
173 {
174 	u_char	server_num[8];
175 
176 	say("password required for connection to server %s",
177 		get_server_name(parsing_server_index));
178 	close_server(parsing_server_index, empty_string);
179         if (!dumb)
180 	{
181 	   	memset(server_num, 0, sizeof(server_num));
182 		snprintf(CP(server_num), sizeof(server_num)-1, "%d", parsing_server_index);
183 		add_wait_prompt(UP("Server Password:"), password_sendline,
184 			server_num, WAIT_PROMPT_LINE);
185 	}
186 }
187 
188 /*ARGSUSED*/
189 static void
nickname_sendline(data,nick)190 nickname_sendline(data, nick)
191 	u_char	*data;
192 	u_char	*nick;
193 {
194 	int	new_server, server;
195 
196 	new_server = my_atoi(data);
197 	server = parsing_server_index;
198 	from_server = new_server;
199 	send_to_server("NICK %s", nick);
200 	if (new_server == primary_server)
201 		malloc_strcpy(&nickname, nick);
202 	set_server_nickname(new_server, nick);
203 	from_server = server;
204 	already_doing_reset_nickname = 0;
205 	update_all_status();
206 }
207 
208 /*
209  * reset_nickname: when the server reports that the selected nickname is not
210  * a good one, it gets reset here.
211  */
212 void
reset_nickname()213 reset_nickname()
214 {
215    u_char	server_num[10];
216 
217    if (already_doing_reset_nickname)
218      return;
219    say("You have specified an illegal nickname");
220    if (!dumb && !get_int_var(NO_ASK_NICKNAME_VAR))
221      {
222 	already_doing_reset_nickname = 1;
223 	say("Please enter your nickname");
224 	sprintf(CP(server_num), "%d", parsing_server_index); /* somewhat safe, assumes %d < 19 */
225 	add_wait_prompt(UP("Nickname: "), nickname_sendline, server_num,
226 			WAIT_PROMPT_LINE);
227      }
228    update_all_status();
229 }
230 
231 /*ARGSUSED*/
232 static	void
channel_topic(from,ArgList)233 channel_topic(from, ArgList)
234 	u_char	*from,
235 		**ArgList;
236 {
237    u_char	*topic, *channel;
238 
239    save_message_from();
240    if (ArgList[1] && is_channel(ArgList[0]))
241      {
242 	topic = ArgList[1];
243 	channel = ArgList[0];
244 	message_from(channel, LOG_CRAP);
245 	put_it("%sTopic for %s: %s", numeric_banner(), channel,
246 	       topic);
247      }
248    else
249      {
250 	message_from((u_char *) 0, LOG_CURRENT);	/* XXX should remove this */
251 	PasteArgs(ArgList, 0);
252 	put_it("%sTopic: %s", numeric_banner(), ArgList[0]);
253      }
254    restore_message_from();
255 }
256 
257 static	void
nickname_in_use(from,ArgList)258 nickname_in_use(from, ArgList)
259 	u_char	*from,
260 		**ArgList;
261 {
262    PasteArgs(ArgList, 0);
263    if (is_server_connected(parsing_server_index)) {
264       if (do_hook(current_numeric, "%s", *ArgList))
265 	display_msg(from, ArgList);
266    }
267    else
268      {
269 	u_char *unp = UNULL;
270 
271 	if (never_connected || parsing_server_index != primary_server ||
272 	    !attempting_to_connect)
273 	  {
274 	     if (do_hook(current_numeric, "%s", *ArgList))
275 	       display_msg(from, ArgList);
276 	     /* reset_nickname(); */
277 	  }
278 	else
279 	  {
280 	     send_to_server("USER %s %s ninja-%s :%s", username,
281 			    (send_umode && *send_umode) ? send_umode : (u_char *) ".",
282 			    irc_version,
283 			    realname);
284 	  }
285 
286 	unp = next_arg(*ArgList, ArgList);
287 	if (unp)
288 	  rotate_nick(unp);
289      }
290 }
291 
292 
293 static	void
not_valid_channel(from,ArgList)294 not_valid_channel(from, ArgList)
295 	u_char	*from,
296 		**ArgList;
297 {
298 	u_char	*channel;
299 	u_char	*s;
300 
301 	if (!(channel = ArgList[0]) || !ArgList[1])
302 		return;
303 	PasteArgs(ArgList, 1);
304 	s = get_server_name(parsing_server_index);
305 	if (0 == my_strnicmp(s, from, my_strlen(s)))
306 	{
307 	   /*
308 	    * lets not do this...
309 	    *
310 		remove_channel(channel, parsing_server_index);
311 	    */
312 		put_it("%s%s %s", numeric_banner(), channel, ArgList[1]);
313 	}
314 }
315 
316 /* from ircd .../include/numeric.h */
317 /*
318 #define ERR_CHANNELISFULL    471
319 #define ERR_INVITEONLYCHAN   473
320 #define ERR_BANNEDFROMCHAN   474
321 #define ERR_BADCHANNELKEY    475
322 #define ERR_BADCHANMASK      476
323 */
324 static	void
cannot_join_channel(from,ArgList)325 cannot_join_channel(from, ArgList)
326 	u_char	*from,
327 		**ArgList;
328 {
329    u_char	chan[512], *keyp;
330    u_char	buffer[BIG_BUFFER_SIZE];
331 
332    if (!ArgList[0])
333      return;
334    my_strncpy(chan, ArgList[0], sizeof(chan)-1);
335    chan[sizeof(chan)-1] = '\0';
336 
337    if (is_on_channel(chan, parsing_server_index, get_server_nickname(parsing_server_index)))
338      return;
339    remove_channel(chan, parsing_server_index);
340 
341    PasteArgs(ArgList, 0);
342    if (do_hook(current_numeric, "%s %s", from, *ArgList)) {
343       my_strncpy(buffer, ArgList[0], sizeof(buffer)-1);
344       buffer[sizeof(buffer)-1] = '\0';
345       switch(-current_numeric)
346 	{
347 	 case 471:
348 	   my_strmcat(buffer, " (Channel is full)", sizeof(buffer)-1);
349 	   break;
350 	 case 473:
351 	   my_strmcat(buffer, " (Invite only channel)", sizeof(buffer)-1);
352 	   break;
353 	 case 474:
354 	   my_strmcat(buffer, " (Banned from channel)", sizeof(buffer)-1);
355 	   break;
356 	 case 475:
357 	   my_strmcat(buffer, " (Bad channel key", sizeof(buffer)-1);
358 	   keyp = get_ckey(chan);
359 	   if (keyp && *keyp)
360 	     {
361 		if (!get_int_var(HIDE_CHANNEL_KEYS_VAR))
362 		  {
363 		     my_strmcat(buffer, ": ", sizeof(buffer)-1);
364 		     my_strmcat(buffer, keyp, sizeof(buffer)-1);
365 		  }
366 		else
367 		  my_strmcat(buffer, " (from key list)", sizeof(buffer)-1);
368 	     }
369 	   my_strmcat(buffer, ")", sizeof(buffer)-1);
370 	   break;
371 	 case 476:
372 	   my_strmcat(buffer, " (Bad channel mask)", sizeof(buffer)-1);
373 	   break;
374 	}
375       put_it("%s%s", numeric_banner(), buffer);
376    }
377 }
378 
379 
380 /*ARGSUSED*/
381 static	void
version(from,ArgList)382 version(from, ArgList)
383 	u_char	*from,
384 		**ArgList;
385 {
386 	if (ArgList[2])
387 	{
388 		PasteArgs(ArgList, 2);
389 		put_it("%sServer %s: %s %s", numeric_banner(), ArgList[1],
390 			ArgList[0], ArgList[2]);
391 	}
392 	else
393 	{
394 		PasteArgs(ArgList, 1);
395 		put_it("%sServer %s: %s", numeric_banner(), ArgList[1],
396 			ArgList[0]);
397 	}
398 }
399 
400 
401 /*ARGSUSED*/
402 static	void
invite(from,ArgList)403 invite(from, ArgList)
404 	u_char	*from,
405 		**ArgList;
406 {
407 	u_char	*who,
408 		*channel;
409 
410 	if ((who = ArgList[0]) && (channel = ArgList[1]))
411 	{
412 		save_message_from();
413 		message_from(channel, LOG_CRAP);
414 		if (do_hook(current_numeric, "%s %s %s", from, who, channel))
415 			put_it("%sInviting %s to %s",
416 					numeric_banner(), who, channel);
417 		restore_message_from();
418 	}
419 }
420 
421 
422 /*
423  * numbered_command: does (hopefully) the right thing with the numbered
424  * responses from the server.  I wasn't real careful to be sure I got them
425  * all, but the default case should handle any I missed (sorry)
426  */
427 void
numbered_command(from,comm,ArgList)428 numbered_command(from, comm, ArgList)
429 	u_char	*from;
430 	int	comm;
431 	u_char	**ArgList;
432 {
433 	u_char	*user;
434 	u_char	none_of_these = 0;
435 	u_char	blah[BIG_BUFFER_SIZE];
436 	int	flag,
437 		lastlog_level;
438 #if 0
439 	int	user_cnt,
440 		inv_cnt,
441 		server_cnt;
442 #endif /* 0 */
443 
444 	if (!from || !*from)
445 		return;
446 	if (!*ArgList[0])
447 		user = (u_char *) 0;
448 	else
449 		user = ArgList[0];
450 	if (!ArgList[1])
451 		return;
452 	lastlog_level = set_lastlog_msg_level(LOG_CRAP);
453 	save_message_from();
454 	message_from((u_char *) 0, LOG_CRAP);
455 	ArgList++;
456 	current_numeric = -comm;	/* must be negative of numeric! */
457 	switch (comm)
458 	{
459 	case 001:	/* #define RPL_WELCOME          001 */
460 	   /*
461 	    * always take the nick from this line!
462 	    */
463 	   if (user)
464 	     set_server_nickname(from_server, user);
465 	   else if (old_nick)
466 	     {
467 		set_server_nickname(from_server, old_nick);
468 		dma_Free(&old_nick);
469 	     }
470 	   /* lets also set the server's user mode here */
471 	   if (server_list[from_server].usermode)
472 	     send_to_server("MODE %s %s",
473 			    server_list[from_server].nickname,
474 			    server_list[from_server].usermode);
475 
476 		PasteArgs(ArgList, 0);
477 		if (do_hook(current_numeric, "%s %s", from, *ArgList))
478 			display_msg(from, ArgList);
479 		clean_whois_queue();
480 		break;
481 	case 002:	/* #define RPL_YOURHOST         002 */
482 		PasteArgs(ArgList, 0);
483 		sprintf(CP(blah), "*** %s", ArgList[0]);
484 		got_initial_version(blah);
485 		if (do_hook(current_numeric, "%s %s", from, *ArgList))
486 			display_msg(from, ArgList);
487 		break;
488 
489 /* should do something with this some day, 2.8 had channel/user mode switches
490  *
491  * this is now handled by nincache.c also (the channel/user modes)
492  */
493 	case 004:	/* #define RPL_MYINFO           004 */
494 		PasteArgs(ArgList, 0);
495 		if (do_hook(current_numeric, "%s %s", from, *ArgList))
496 			display_msg(from, ArgList);
497 		break;
498 
499 /*
500  * this part of ircii has been broken for most of ircd 2.7, so someday I'll
501  * make it work for ircd 2.8 ...  phone..
502  */
503 #if 0
504 	case 251:		/* #define RPL_LUSERCLIENT      251 */
505 		display_msg(from, ArgList);
506 		if (server_list[from_server].connected)
507 			break;
508 		if ((from_server == primary_server) && ((sscanf(ArgList[1],
509 		    "There are %d users and %d invisible on %d servers",
510 		    &user_cnt, &inv_cnt, &server_cnt) == 3)||(sscanf(ArgList[1],
511 		    "There are %d users and %d invisible on %d servers",
512 		    &user_cnt, &inv_cnt, &server_cnt) == 3)))
513 		{
514 			user_cnt += inv_cnt;
515 			if ((server_cnt < get_int_var(MINIMUM_SERVERS_VAR)) ||
516 			    (user_cnt < get_int_var(MINIMUM_USERS_VAR)))
517 			{
518 				say("Trying better populated server...");
519 				get_connected(from_server + 1);
520 			}
521 		}
522 		break;
523 #endif /* 0 */
524 	case 301:		/* #define RPL_AWAY             301 */
525 		user_is_away(from, ArgList);
526 		break;
527 
528 	case 302:		/* #define RPL_USERHOST         302 */
529 		userhost_returned(from, ArgList);
530 		break;
531 
532 	case 303:		/* #define RPL_ISON             303 */
533 		ison_returned(from, ArgList);
534 		break;
535 
536 	case 311:		/* #define RPL_WHOISUSER        311 */
537 		whois_name(from, ArgList);
538 		break;
539 
540 	case 312:		/* #define RPL_WHOISSERVER      312 */
541 		whois_server(from, ArgList);
542 		break;
543 
544 	case 313:		/* #define RPL_WHOISOPERATOR    313 */
545 		whois_oper(from, ArgList);
546 		break;
547 
548 	case 314:		/* #define RPL_WHOWASUSER       314 */
549 		whowas_name(from, ArgList);
550 		break;
551 
552 	case 316:		/* #define RPL_WHOISCHANOP      316 */
553 		whois_chop(from, ArgList);
554 		break;
555 
556 	case 317:		/* #define RPL_WHOISIDLE        317 */
557 		whois_lastcom(from, ArgList);
558 		break;
559 
560 	case 318:		/* #define RPL_ENDOFWHOIS       318 */
561 		end_of_whois(from, ArgList);
562 		break;
563 
564 	case 319:		/* #define RPL_WHOISCHANNELS    319 */
565 		whois_channels(from, ArgList);
566 		break;
567 
568 	case 321:		/* #define RPL_LISTSTART        321 */
569 		ArgList[0] = UP("Channel\0Users\0Topic");
570 		ArgList[1] = ArgList[0] + 8;
571 		ArgList[2] = ArgList[1] + 6;
572 		ArgList[3] = (u_char *) 0;
573 		funny_list(from, ArgList);
574 		break;
575 
576 	case 322:		/* #define RPL_LIST             322 */
577 		funny_list(from, ArgList);
578 		break;
579 
580 	 case 324:		/* #define RPL_CHANNELMODEIS    324 */
581 	     {
582 		Channel *tc;
583 		if (ArgList[0]
584 		    && (tc = lookup_channel(ArgList[0], from_server, CHAN_NOUNLINK))
585 		    && (tc->status & CHAN_MODE))
586 		  funny_mode(from, ArgList);
587 	     }
588 	   break;
589 
590 	 case 329:		/* #define RPL_CREATIONTIME	329 */
591 	     {
592 		if (ArgList[1])
593 		  {
594 		     time_t t;
595 
596 		     sscanf(ArgList[1], "%lu", &t); /* XXX: not a good idea.. str_to_time_t is needed or something */
597 		     save_message_from();
598 		     message_from(ArgList[0], LOG_CRAP);
599 		     if (do_hook(current_numeric, "%s %s %s", from, ArgList[0], ArgList[1]))
600 		       put_info("%s was created %s", ArgList[0],
601 				ninja_strftime(&t, "%a, %b %d at %I:%M%p"));
602 		     restore_message_from();
603 		  }
604 	     }
605 	   break;
606 
607 	case 341:		/* #define RPL_INVITING         341 */
608 		invite(from, ArgList);
609 		break;
610 
611 	 case 348:		/* #define RPL_EXCEPTLIST      	348 */
612 	   if (ArgList[0])
613 	     show_ban_except_line(from, ArgList);
614 	   break;
615 	 case 349:		/* #define RPL_ENDOFEXCEPTLIST 	349 */
616 	   if (ArgList[0])
617 	     {
618 		PasteArgs(ArgList, 0);
619 		flag = do_hook(current_numeric, "%s %s", from, ArgList[0]);
620 		if (get_int_var(SHOW_END_OF_MSGS_VAR) && flag)
621 		  display_msg(from, ArgList);
622 	     }
623 	   break;
624 
625 	case 352:		/* #define RPL_WHOREPLY         352 */
626 		whoreply((u_char *) 0, ArgList);
627 		break;
628 
629 	case 353:		/* #define RPL_NAMREPLY         353 */
630 		funny_namreply(from, ArgList);
631 		break;
632 
633 	case 366:		/* #define RPL_ENDOFNAMES       366 */
634 		{
635 			u_char	*tmp = (u_char *) 0,
636 				*chan;
637 
638 			malloc_strcpy(&tmp, ArgList[0]);
639 		   	chan = tmp;
640 			PasteArgs(ArgList, 0);
641 		   	/* chan = UP(strtok(CP(tmp), " ")); */
642 			flag = do_hook(current_numeric, "%s %s", from, ArgList[0]);
643 				if (get_int_var(SHOW_END_OF_MSGS_VAR) && flag)
644 					display_msg(from, ArgList);
645 
646 			new_free(&tmp);
647 		}
648 		break;
649 
650 	 case 367:		/* #define RPL_BANLIST		367 */
651 	   if (ArgList[0])
652 	     show_ban_except_line(from, ArgList);
653 	   break;
654 	 case 368:		/* #define RPL_ENDOFBANLIST    	368 */
655 	   if (ArgList[0])
656 	     {
657 		PasteArgs(ArgList, 0);
658 		flag = do_hook(current_numeric, "%s %s", from, ArgList[0]);
659 		if (get_int_var(SHOW_END_OF_MSGS_VAR) && flag)
660 		  display_msg(from, ArgList);
661 	     }
662 	   break;
663 
664 	case 381: 		/* #define RPL_YOUREOPER        381 */
665 		PasteArgs(ArgList, 0);
666 		if (do_hook(current_numeric, "%s %s", from, *ArgList))
667 			display_msg(from, ArgList);
668 		set_server_operator(parsing_server_index, 1);
669 		update_all_status();	/* fix the status line */
670 		break;
671 
672 	case 401:		/* #define ERR_NOSUCHNICK       401 */
673 		no_such_nickname(from, ArgList);
674 		break;
675 
676 	case 405:		/* #define ERR_TOOMANYCHANNELS  405 */
677 		remove_channel(ArgList[0], parsing_server_index);
678 		break;
679 
680 	case 421:		/* #define ERR_UNKNOWNCOMMAND   421 */
681 		if (check_screen_redirect(ArgList[0]))
682 			break;
683 		if (check_wait_command(ArgList[0]))
684 			break;
685 		PasteArgs(ArgList, 0);
686 		flag = do_hook(current_numeric, "%s %s", from, *ArgList);
687 		if (!my_strncmp("ISON", *ArgList, 4) || !my_strncmp("USERHOST",
688 		    *ArgList, 8))
689 		{
690 			set_server_2_6_2(parsing_server_index, 0);
691 			convert_to_whois();
692 		}
693 		else if (flag)
694 			display_msg(from, ArgList);
695 		break;
696 
697 	 case 432:		/* #define ERR_ERRONEUSNICKNAME 432 */
698 	   if (do_hook(current_numeric, "%s %s", from, *ArgList))
699 	     {
700 		u_char *enp;
701 
702 		display_msg(from, ArgList);
703 		enp = next_arg(*ArgList, ArgList);
704 		if (enp)
705 		  rotate_nick(enp);
706 	     }
707 	   break;
708 
709 	 case 433:		/* #define ERR_NICKNAMEINUSE    433 */
710 	   if (!attempting_to_connect
711 	       && get_int_var(AUTO_WHOIS_NICK_IN_USE_VAR))
712 	     send_to_server("WHOIS %s", ArgList[0]);
713 	   nickname_in_use(from, ArgList);
714 	   break;
715 
716 	case 437:		/* #define ERR_UNAVAILRESOURCE  437 */
717 		flag = do_hook(current_numeric, "%s %s", from, *ArgList);
718 		if (!is_channel(*ArgList))
719 		{
720 			nickname_in_use(from, ArgList);
721 			/* reset_nickname(); */
722 		} else if (flag)
723 			display_msg(from, ArgList);
724 		break;
725 
726 
727 
728 	case 463:		/* #define ERR_NOPERMFORHOST    463 */
729 		display_msg(from, ArgList);
730 		close_server(parsing_server_index, empty_string);
731 		window_check_servers();
732 		if (!connected_to_server
733 		    && get_int_var(AUTO_RECONNECT_VAR))
734 			get_connected(parsing_server_index + 1);
735 		break;
736 
737 	case 464:		/* #define ERR_PASSWDMISMATCH   464 */
738 		PasteArgs(ArgList, 0);
739 		flag = do_hook(current_numeric, "%s %s", from, ArgList[0]);
740 		if (oper_command)
741 		{
742 			if (flag)
743 				display_msg(from, ArgList);
744 		}
745 		else
746 			get_password();
747 		break;
748 
749 	case 465:		/* #define ERR_YOUREBANNEDCREEP 465 */
750 		{
751 			int	klined_server = parsing_server_index;
752 
753 			PasteArgs(ArgList, 0);
754 			if (do_hook(current_numeric, "%s %s", from, ArgList[0]))
755 				display_msg(from, ArgList);
756 			close_server(parsing_server_index, empty_string);
757 			window_check_servers();
758 			if (number_of_servers > 1)
759 			{
760 				remove_from_server_list(klined_server);
761 			}
762 			if (!connected_to_server
763 			    && get_int_var(AUTO_RECONNECT_VAR))
764 		     		get_connected(klined_server + 1);
765 				/* say("You are not connected to a server. Use /SERVER to connect."); */
766 			break;
767 		}
768 
769 	case 471:		/* #define ERR_CHANNELISFULL    471 */
770 	case 473:		/* #define ERR_INVITEONLYCHAN   473 */
771 	case 474:		/* #define ERR_BANNEDFROMCHAN   474 */
772 	case 475: 		/* #define ERR_BADCHANNELKEY    475 */
773 	case 476:		/* #define ERR_BADCHANMASK      476 */
774 		cannot_join_channel(from, ArgList);
775 		break;
776 
777 	case 484:		/* #define ERR_RESTRICTED       484 */
778 		if (do_hook(current_numeric, "%s %s", from, *ArgList))
779 			display_msg(from, ArgList);
780 		set_server_flag(parsing_server_index, USER_MODE_R, 1);
781 		break;
782 
783 		/*
784 		 * The following accumulates the remaining arguments
785 		 * in ArgSpace for hook detection.  We can't use
786 		 * PasteArgs here because we still need the arguments
787 		 * separated for use elsewhere.
788 		 */
789 	default:
790 		{
791 			u_char	*ArgSpace = (u_char *) 0;
792 			int	i,
793 				do_message_from = 0;
794 			size_t	len;
795 
796 			for (i = len = 0; ArgList[i]; len += my_strlen(ArgList[i++]))
797 				;
798 			len += (i - 1);
799 			ArgSpace = new_malloc(len + 1);
800 			ArgSpace[0] = '\0';
801 			/* this is cheating */
802 			if (ArgList[0] && is_channel(ArgList[0]))
803 				do_message_from = 1;
804 			for (i = 0; ArgList[i]; i++)
805 			{
806 				if (i)
807 					my_strcat(ArgSpace, " ");
808 				my_strcat(ArgSpace, ArgList[i]);
809 			}
810 			if (do_message_from)
811 				message_from(ArgList[0], LOG_CRAP);
812 			i = do_hook(current_numeric, "%s %s", from, ArgSpace);
813 			new_free(&ArgSpace);
814 			if (do_message_from)
815 				restore_message_from();
816 			if (i == 0)
817 				goto done;
818 			none_of_these = 1;
819 		}
820 	}
821 	/* the following do not hurt the ircII if intercepted by a hook */
822 	if (none_of_these)
823 	{
824 		switch (comm)
825 		{
826 		case 221: 		/* #define RPL_UMODEIS          221 */
827 			put_it("%sYour user mode is \"%s\"", numeric_banner(),
828 				ArgList[0]);
829 			break;
830 
831 		case 242:		/* #define RPL_STATSUPTIME      242 */
832 			PasteArgs(ArgList, 0);
833 			if (from && !my_strnicmp(get_server_itsname(parsing_server_index),
834 			    from, my_strlen(get_server_itsname(parsing_server_index))))
835 				from = NULL;
836 			if (from)
837 				put_it("%s%s from (%s)", numeric_banner(),
838 					*ArgList, from);
839 			else
840 				put_it("%s%s", numeric_banner(), *ArgList);
841 			break;
842 
843 		case 332:		/* #define RPL_TOPIC            332 */
844 			channel_topic(from, ArgList);
845 			break;
846 
847 		 case 333:		/* #define RPL_TOPICWHOTIME	333 */
848 		   channel_topic_time(from, ArgList);
849 		   break;
850 
851 		case 351:		/* #define RPL_VERSION          351 */
852 			version(from, ArgList);
853 			break;
854 
855 		case 364:		/* #define RPL_LINKS            364 */
856 			if (ArgList[2])
857 			{
858 				PasteArgs(ArgList, 2);
859 				put_it("%s%-20s %-20s %s", numeric_banner(),
860 					ArgList[0], ArgList[1], ArgList[2]);
861 			}
862 			else
863 			{
864 				PasteArgs(ArgList, 1);
865 				put_it("%s%-20s %s", numeric_banner(),
866 					ArgList[0], ArgList[1]);
867 			}
868 			break;
869 
870 		case 372:		/* #define RPL_MOTD             372 */
871 			if (!get_int_var(SUPPRESS_SERVER_MOTD_VAR) ||
872 			    !get_server_motd(parsing_server_index))
873 			{
874 				PasteArgs(ArgList, 0);
875 				put_it("%s%s", numeric_banner(), ArgList[0]);
876 			}
877 			break;
878 
879 		case 375:		/* #define RPL_MOTDSTART        375 */
880 			if (!get_int_var(SUPPRESS_SERVER_MOTD_VAR) ||
881 			    !get_server_motd(parsing_server_index))
882 			{
883 				PasteArgs(ArgList, 0);
884 				put_it("%s%s", numeric_banner(), ArgList[0]);
885 			}
886 			break;
887 
888 		case 376:		/* #define RPL_ENDOFMOTD        376 */
889 			if (attempting_to_connect)
890 				got_initial_version(UP("*** Your host is broken and not running any version"));
891 			if (get_int_var(SHOW_END_OF_MSGS_VAR) &&
892 			    (!get_int_var(SUPPRESS_SERVER_MOTD_VAR) ||
893 			    !get_server_motd(parsing_server_index)))
894 			{
895 				PasteArgs(ArgList, 0);
896 				put_it("%s%s", numeric_banner(), ArgList[0]);
897 			}
898 			set_server_motd(parsing_server_index, 0);
899 			break;
900 
901 		case 384:		/* #define RPL_MYPORTIS         384 */
902 			PasteArgs(ArgList, 0);
903 			put_it("%s%s %s", numeric_banner(), ArgList[0], user);
904 			break;
905 
906 		case 385:		/* #define RPL_NOTOPERANYMORE   385 */
907 			set_server_operator(parsing_server_index, 0);
908 			display_msg(from, ArgList);
909 			update_all_status();
910 			break;
911 
912 		case 403:		/* #define ERR_NOSUCHCHANNEL    403 */
913 			not_valid_channel(from, ArgList);
914 			break;
915 
916 		case 432:		/* #define ERR_ERRONEUSNICKNAME 432 */
917 			display_msg(from, ArgList);
918 		   /* reset_nickname(); 8*/
919 			break;
920 
921 		case 451:		/* #define ERR_NOTREGISTERED    451 */
922 	/*
923 	 * Sometimes the server doesn't catch the USER line, so
924 	 * here we send a simplified version again  -lynx
925 	 */
926 			send_to_server("USER %s %s ninja-%s :%s", username,
927 				(send_umode && *send_umode) ? send_umode : (u_char *) ".",
928 				       irc_version,
929 				realname);
930 			send_to_server("NICK %s",
931 				get_server_nickname(parsing_server_index));
932 			break;
933 
934 		case 462:		/* #define ERR_ALREADYREGISTRED 462 */
935 			display_msg(from, ArgList);
936 			break;
937 
938 #define RPL_CLOSEEND         363
939 #define RPL_SERVLISTEND      235
940 		case 315:		/* #define RPL_ENDOFWHO         315 */
941 			if (cannot_open != (u_char *) 0)
942 				yell("Cannot open: %s", cannot_open);
943 
944 		case 323:               /* #define RPL_LISTEND          323 */
945 			funny_print_widelist();
946 
947 		case 219:		/* #define RPL_ENDOFSTATS       219 */
948 		case 232:		/* #define RPL_ENDOFSERVICES    232 */
949 		case 365:		/* #define RPL_ENDOFLINKS       365 */
950 		case 369:		/* #define RPL_ENDOFWHOWAS      369 */
951 		case 374:		/* #define RPL_ENDOFINFO        374 */
952 #if 0	/* this case needs special handing - see above */
953 		case 376:		/* #define RPL_ENDOFMOTD        376 */
954 #endif /* 0 */
955 		case 394:		/* #define RPL_ENDOFUSERS       394 */
956 			if (!get_int_var(SHOW_END_OF_MSGS_VAR))
957 				break;
958 		default:
959 			display_msg(from, ArgList);
960 		}
961 	}
962 	set_lastlog_msg_level(lastlog_level);
963 done:
964 	restore_message_from();
965 }
966 
967 
968 /*
969  * show a ban/ban exception on a channel..
970  */
971 static void
show_ban_except_line(from,ArgList)972 show_ban_except_line(from, ArgList)
973    u_char *from, **ArgList;
974 {
975    if (is_channel(ArgList[0]) && ArgList[1])
976      {
977 	if (ArgList[2] && ArgList[3])
978 	  {
979 	     time_t t;
980 
981 	     sscanf(ArgList[3], "%lu", (unsigned long *) &t);
982 	     put_info("[%s] %s by %s at %s", ArgList[0], ArgList[1], ArgList[2], ninja_strftime(&t, "%I:%M%p on %a, %b %d"));
983 	  }
984 	else if (ArgList[2])
985 	  put_info("[%s] %s by %s", ArgList[0], ArgList[1], ArgList[2]);
986 	else
987 	  put_info("[%s] %s", ArgList[0], ArgList[1]);
988      }
989 }
990 
991 /*
992  * when the topic got set and who set it
993  */
994 static void
channel_topic_time(from,ArgList)995 channel_topic_time(from, ArgList)
996    u_char *from, **ArgList;
997 {
998    if (ArgList[1] && is_channel(ArgList[0]) && ArgList[2])
999      {
1000 	time_t t;
1001 
1002 	message_from(ArgList[0], LOG_CRAP);
1003 	sscanf(ArgList[2], "%lu", (unsigned long *) &t);
1004 	if (checkgrep(ArgList[0], NULL))
1005 	  put_raw("%sThe topic was set by %s on %s.", numeric_banner(),
1006 		  ArgList[1], ninja_strftime(&t, "%a, %b %d at %I:%M%p"));
1007 
1008      }
1009    else
1010      {
1011 	PasteArgs(ArgList, 0);
1012 	message_from((char *) 0, LOG_CURRENT);
1013 	put_raw("%sBroken RPL_TOPICWHOTIME: %s", numeric_banner(), *ArgList);
1014      }
1015 }
1016 
1017