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-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: numbers.c,v 1.106 2021/02/24 10:38:03 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 "names.h"
52 #include "whois.h"
53 #include "funny.h"
54 #include "parse.h"
55 #include "notice.h"
56 
57 static	void	reset_nickname(u_char *);
58 static	void	password_sendline(u_char *, u_char *);
59 static	void	get_password(void);
60 static	void	nickname_sendline(u_char *, u_char *);
61 static	void	channel_topic(u_char *, u_char **);
62 static	void	not_valid_channel(u_char *, u_char **);
63 static	void	cannot_join_channel(u_char *, u_char **);
64 static	void	version(u_char *, u_char *, u_char **);
65 static	void	invite(u_char *, u_char *, u_char **);
66 
67 static	int	already_doing_reset_nickname = 0;
68 static	int	current_numeric_local;	/* this is negative of the
69 					 * current numeric! */
70 
71 /*
72  * numeric_banner: This returns in a static string of either "xxx" where
73  * xxx is the current numeric, or "***" if SHOW_NUMBERS is OFF
74  */
75 u_char	*
numeric_banner(void)76 numeric_banner(void)
77 {
78 	static	u_char	thing[4];
79 
80 	if (get_int_var(SHOW_NUMERICS_VAR))
81 		snprintf(CP(thing), sizeof thing, "%3.3u", -current_numeric());
82 	else
83 		my_strcpy(thing, UP("***"));
84 	return (thing);
85 }
86 
87 
88 /*
89  * display_msg: handles the displaying of messages from the variety of
90  * possible formats that the irc server spits out.
91  */
92 void
display_msg(u_char * from,u_char ** ArgList)93 display_msg(u_char *from, u_char **ArgList)
94 {
95 	u_char	*rest;
96 	u_char	*name = server_get_itsname(parsing_server());
97 
98 	if (my_strnicmp(name, from, my_strlen(name)) == 0)
99 		from = NULL;
100 
101 	rest = paste_args(ArgList, 0);
102 	if (rest == NULL)
103 		rest = empty_string();
104 
105 	if (from)
106 		put_it("%s %s (from %s)", numeric_banner(), rest, from);
107 	else
108 		put_it("%s %s", numeric_banner(), rest);
109 }
110 
111 /*
112  * password_sendline: called by send_line() in get_password() to handle
113  * hitting of the return key, etc
114  */
115 static	void
password_sendline(u_char * data,u_char * line)116 password_sendline(u_char *data, u_char *line)
117 {
118 	int	new_server;
119 
120 	new_server = my_atoi(data);
121 	server_set_password(new_server, line);
122 	connect_to_server(server_get_name(new_server),
123 		server_get_port(new_server), server_get_nickname(new_server), -1);
124 }
125 
126 /*
127  * get_password: when a host responds that the user needs to supply a
128  * password, it gets handled here!  the user is prompted for a password and
129  * then reconnection is attempted with that password.  but, the reality of
130  * the situation is that no one really uses user passwords.  ah well
131  */
132 static	void
get_password(void)133 get_password(void)
134 {
135 	u_char	server_num[8];
136 
137 	say("password required for connection to server %s",
138 		server_get_name(parsing_server()));
139 	close_server(parsing_server(), empty_string());
140 	if (!term_basic())
141 	{
142 		snprintf(CP(server_num), sizeof server_num, "%d", parsing_server());
143 		add_wait_prompt(UP("Server Password:"), password_sendline,
144 			server_num, WAIT_PROMPT_LINE);
145 	}
146 }
147 
148 static	void
nickname_sendline(u_char * data,u_char * nick)149 nickname_sendline(u_char *data, u_char *nick)
150 {
151 	int	new_server, server;
152 
153 	new_server = my_atoi(data);
154 	server = parsing_server();
155 	set_from_server(new_server);
156 	if (nick && *nick)
157 	{
158 		send_to_server("NICK %s", nick);
159 		if (new_server == get_primary_server())
160 			set_nickname(nick);
161 		server_set_nickname(new_server, nick);
162 	}
163 	set_from_server(server);
164 	already_doing_reset_nickname = 0;
165 	update_all_status();
166 }
167 
168 /*
169  * reset_nickname: when the server reports that the selected nickname is not
170  * a good one, it gets reset here.
171  */
172 static	void
reset_nickname(u_char * from)173 reset_nickname(u_char *from)
174 {
175 	u_char	server_num[10];
176 	const	int	from_server = get_from_server();
177 
178 	if (already_doing_reset_nickname ||
179 	    is_server_connected(from_server) ||
180 	    !server_get_attempting_to_connect(from_server))
181 		return;
182 
183 	say("You have specified an illegal nickname");
184 	if (!term_basic() && !get_int_var(NO_ASK_NICKNAME_VAR))
185 	{
186 		already_doing_reset_nickname = 1;
187 		say("Please enter your nickname");
188 		snprintf(CP(server_num), sizeof server_num, "%d", parsing_server());
189 		add_wait_prompt(UP("Nickname: "), nickname_sendline, server_num,
190 			WAIT_PROMPT_LINE);
191 	}
192 	update_all_status();
193 }
194 
195 static	void
channel_topic(u_char * from,u_char ** ArgList)196 channel_topic(u_char *from, u_char **ArgList)
197 {
198 	u_char	*topic, *channel;
199 
200 	save_message_from();
201 	if (ArgList[1] && is_channel(ArgList[0]))
202 	{
203 		topic = ArgList[1];
204 		channel = ArgList[0];
205 		message_from(channel, LOG_CRAP);
206 		put_it("%s Topic for %s: %s", numeric_banner(), channel,
207 			topic);
208 	}
209 	else
210 	{
211 		message_from(NULL, LOG_CURRENT);
212 		paste_args(ArgList, 0);
213 		put_it("%s Topic: %s", numeric_banner(), ArgList[0]);
214 	}
215 	restore_message_from();
216 }
217 
218 static	void
not_valid_channel(u_char * from,u_char ** ArgList)219 not_valid_channel(u_char *from, u_char **ArgList)
220 {
221 	u_char	*channel;
222 	u_char	*s;
223 
224 	if (ArgList[1] == NULL)
225 		return;
226 	channel = ArgList[0];
227 	paste_args(ArgList, 1);
228 	s = server_get_name(parsing_server());
229 	if (0 == my_strnicmp(s, from, my_strlen(s)))
230 	{
231 		remove_channel(channel, parsing_server());
232 		put_it("%s %s %s", numeric_banner(), channel, ArgList[1]);
233 	}
234 }
235 
236 static	void
cannot_join_channel(u_char * from,u_char ** ArgList)237 cannot_join_channel(u_char *from, u_char **ArgList)
238 {
239 	u_char	*chan, *extra;
240 
241 	chan = ArgList[0];
242 	if (!is_on_channel(chan, parsing_server(),
243 			server_get_nickname(parsing_server())))
244 		remove_channel(chan, parsing_server());
245 	else
246 		return;
247 
248 	paste_args(ArgList, 0);
249 	if (do_hook(current_numeric(), "%s %s", from, ArgList[0])) {
250 		switch(-current_numeric())
251 		{
252 		case 471:		/* #define ERR_CHANNELISFULL    471 */
253 			extra = UP(" (Channel is full)");
254 			break;
255 		case 473:		/* #define ERR_INVITEONLYCHAN   473 */
256 			extra = UP(" (Invite only channel)");
257 			break;
258 		case 474:		/* #define ERR_BANNEDFROMCHAN   474 */
259 			extra = UP(" (Banned from channel)");
260 			break;
261 		case 475: 		/* #define ERR_BADCHANNELKEY    475 */
262 			extra = UP(" (Bad channel key)");
263 			break;
264 		case 476:		/* #define ERR_BADCHANMASK      476 */
265 			extra = UP(" (Bad channel mask)");
266 			break;
267 		default:
268 			extra = empty_string();
269 		}
270 		put_it("%s %s%s", numeric_banner(), ArgList[0], extra);
271 	}
272 }
273 
274 
275 static	void
version(u_char * comm,u_char * from,u_char ** ArgList)276 version(u_char *comm, u_char *from, u_char **ArgList)
277 {
278 	if (check_params(comm, from, 0, ArgList, 2))
279 		return;
280 
281 	if (ArgList[2])
282 	{
283 		paste_args(ArgList, 2);
284 		put_it("%s Server %s: %s %s", numeric_banner(), ArgList[1],
285 			ArgList[0], ArgList[2]);
286 	}
287 	else
288 	{
289 		paste_args(ArgList, 1);
290 		put_it("%s Server %s: %s", numeric_banner(), ArgList[1],
291 			ArgList[0]);
292 	}
293 }
294 
295 
296 static	void
invite(u_char * comm,u_char * from,u_char ** ArgList)297 invite(u_char *comm, u_char *from, u_char **ArgList)
298 {
299 	u_char	*who,
300 		*channel;
301 
302 	if (check_params(comm, from, 0, ArgList, 2))
303 		return;
304 
305 	who = ArgList[0];
306 	channel = ArgList[1];
307 	if (channel)
308 	{
309 		save_message_from();
310 		message_from(channel, LOG_CRAP);
311 		if (do_hook(current_numeric(), "%s %s %s", from, who, channel))
312 			put_it("%s Inviting %s to channel %s",
313 					numeric_banner(), who, channel);
314 		restore_message_from();
315 	}
316 }
317 
318 
319 /*
320  * numbered_command: does (hopefully) the right thing with the numbered
321  * responses from the server.  I wasn't real careful to be sure I got them
322  * all, but the default case should handle any I missed (sorry)
323  */
324 void
numbered_command(u_char * commstr,u_char * from,int comm,u_char ** ArgList)325 numbered_command(u_char *commstr, u_char *from, int comm, u_char **ArgList)
326 {
327 	u_char	*user;
328 	u_char	none_of_these = 0;
329 	u_char	*blah = NULL;
330 	int	flag,
331 		lastlog_level;
332 	const	int	from_server = parsing_server();
333 #if 0
334 	int	user_cnt,
335 		inv_cnt,
336 		server_cnt;
337 #endif /* 0 */
338 
339 	if (!from || !*from || !*ArgList)
340 		return;
341 	if (!*ArgList[0])
342 		user = NULL;
343 	else
344 		user = ArgList[0];
345 	if (!ArgList[1])
346 		return;
347 	ArgList++;
348 	if (check_params(commstr, from, 0, ArgList, 1))
349 		return;
350 
351 	/*
352 	 * At this point, unlike in irc2_parse_server(), ArgList[0] is now
353 	 * always valid, making all of commstr, from, and ArgList[0] valid.
354 	 */
355 
356 	lastlog_level = set_lastlog_msg_level(LOG_CRAP);
357 	save_message_from();
358 	message_from(NULL, LOG_CRAP);
359 	current_numeric_local = -comm;	/* must be negative of numeric! */
360 	switch (comm)
361 	{
362 	case 001:	/* #define RPL_WELCOME          001 */
363 		paste_args(ArgList, 0);
364 		if (my_strcmp(user, server_get_nickname(from_server)) != 0)
365 		{
366 			yell("=== Setting this servers nickname to \"%s\" from \"%s\"", user, server_get_nickname(from_server));
367 			server_set_nickname(from_server, user);
368 		}
369 		if (do_hook(current_numeric(), "%s %s", from, ArgList[0]))
370 			display_msg(from, ArgList);
371 		clean_whois_queue();
372 		break;
373 	case 002:	/* #define RPL_YOURHOST         002 */
374 		paste_args(ArgList, 0);
375 		malloc_snprintf(&blah, "*** %s", ArgList[0]);
376 		got_initial_version(blah);
377 		new_free(&blah);
378 		if (do_hook(current_numeric(), "%s %s", from, ArgList[0]))
379 			display_msg(from, ArgList);
380 		break;
381 
382 /* should do something with this some day, 2.8 had channel/user mode switches */
383 	case 004:	/* #define RPL_MYINFO           004 */
384 		paste_args(ArgList, 0);
385 		if (do_hook(current_numeric(), "%s %s", from, ArgList[0]))
386 			display_msg(from, ArgList);
387 		break;
388 
389 /*
390  * this part of ircii has been broken for most of ircd 2.7, so someday I'll
391  * make it work for ircd 2.8 ...  phone..
392  */
393 #if 0
394 	case 251:		/* #define RPL_LUSERCLIENT      251 */
395 		display_msg(from, ArgList);
396 		if (is_server_connected(from_server))
397 			break;
398 		if (ArgList[1] != NULL && from_server == get_primary_server() &&
399 		    ((sscanf(ArgList[1],
400 			     "There are %d users and %d invisible on %d servers",
401 			     &user_cnt, &inv_cnt, &server_cnt) == 3)))
402 		{
403 			user_cnt =+ inv_cnt;
404 			if ((server_cnt < get_int_var(MINIMUM_SERVERS_VAR)) ||
405 			    (user_cnt < get_int_var(MINIMUM_USERS_VAR)))
406 			{
407 				say("Trying better populated server...");
408 				get_connected(from_server + 1);
409 			}
410 		}
411 		break;
412 #endif /* 0 */
413 	case 301:		/* #define RPL_AWAY             301 */
414 		user_is_away(commstr, from, ArgList);
415 		break;
416 
417 	case 302:		/* #define RPL_USERHOST         302 */
418 		userhost_returned(from, ArgList);
419 		break;
420 
421 	case 303:		/* #define RPL_ISON             303 */
422 		ison_returned(from, ArgList);
423 		break;
424 
425 	case 311:		/* #define RPL_WHOISUSER        311 */
426 		whois_name(commstr, from, ArgList);
427 		break;
428 
429 	case 312:		/* #define RPL_WHOISSERVER      312 */
430 		whois_server(from, ArgList);
431 		break;
432 
433 	case 313:		/* #define RPL_WHOISOPERATOR    313 */
434 		whois_oper(from, ArgList);
435 		break;
436 
437 	case 314:		/* #define RPL_WHOWASUSER       314 */
438 		whowas_name(commstr, from, ArgList);
439 		break;
440 
441 	case 316:		/* #define RPL_WHOISCHANOP      316 */
442 		whois_chop(from, ArgList);
443 		break;
444 
445 	case 317:		/* #define RPL_WHOISIDLE        317 */
446 		whois_lastcom(commstr, from, ArgList);
447 		break;
448 
449 	case 318:		/* #define RPL_ENDOFWHOIS       318 */
450 		end_of_whois(from, ArgList);
451 		break;
452 
453 	case 319:		/* #define RPL_WHOISCHANNELS    319 */
454 		whois_channels(commstr, from, ArgList);
455 		break;
456 
457 	case 321:		/* #define RPL_LISTSTART        321 */
458 		ArgList[0] = UP("Channel\0Users\0Topic");
459 		ArgList[1] = ArgList[0] + 8;
460 		ArgList[2] = ArgList[1] + 6;
461 		ArgList[3] = NULL;
462 		funny_list(commstr, from, ArgList);
463 		break;
464 
465 	case 322:		/* #define RPL_LIST             322 */
466 		funny_list(commstr, from, ArgList);
467 		break;
468 
469 	case 324:		/* #define RPL_CHANNELMODEIS    324 */
470 		funny_mode(from, ArgList);
471 		break;
472 
473 	case 341:		/* #define RPL_INVITING         341 */
474 		invite(commstr, from, ArgList);
475 		break;
476 
477 	case 352:		/* #define RPL_WHOREPLY         352 */
478 		whoreply(NULL, ArgList);
479 		break;
480 
481 	case 353:		/* #define RPL_NAMREPLY         353 */
482 		funny_namreply(commstr, from, ArgList);
483 		break;
484 
485 	case 366:		/* #define RPL_ENDOFNAMES       366 */
486 		{
487 			u_char	*tmp = NULL,
488 				*chan;
489 
490 			paste_args(ArgList, 0);
491 			malloc_strcpy(&tmp, ArgList[0]);
492 			chan = next_arg(tmp, 0);
493 			flag = do_hook(current_numeric(), "%s %s", from, ArgList[0]);
494 
495 			if (flag &&
496 			    channel_mode_lookup(chan, CHAN_NAMES | CHAN_MODE, 0) &&
497 			    get_int_var(SHOW_END_OF_MSGS_VAR) && flag)
498 				display_msg(from, ArgList);
499 
500 			new_free(&tmp);
501 		}
502 		break;
503 
504 	case 381: 		/* #define RPL_YOUREOPER        381 */
505 		paste_args(ArgList, 0);
506 		if (do_hook(current_numeric(), "%s %s", from, ArgList[0]))
507 			display_msg(from, ArgList);
508 		server_set_operator(parsing_server(), 1);
509 		update_all_status();	/* fix the status line */
510 		break;
511 
512 	case 401:		/* #define ERR_NOSUCHNICK       401 */
513 		no_such_nickname(commstr, from, ArgList);
514 		break;
515 
516 	case 405:		/* #define ERR_TOOMANYCHANNELS  405 */
517 		remove_channel(ArgList[0], parsing_server());
518 		break;
519 
520 	case 421:		/* #define ERR_UNKNOWNCOMMAND   421 */
521 		if (check_screen_redirect(ArgList[0]))
522 			break;
523 		if (check_wait_command(ArgList[0]))
524 			break;
525 		paste_args(ArgList, 0);
526 		flag = do_hook(current_numeric(), "%s %s", from, ArgList[0]);
527 		if (!my_strncmp("ISON", ArgList[0], 4) || !my_strncmp("USERHOST",
528 		    ArgList[0], 8))
529 		{
530 			server_set_2_6_2(parsing_server(), 0);
531 			convert_to_whois();
532 		}
533 		else if (flag)
534 			display_msg(from, ArgList);
535 		break;
536 
537 	case 432:		/* #define ERR_ERRONEUSNICKNAME 432 */
538 	case 433:		/* #define ERR_NICKNAMEINUSE    433 */
539 		paste_args(ArgList, 0);
540 		if (do_hook(current_numeric(), "%s %s", from, ArgList[0]))
541 			display_msg(from, ArgList);
542 		reset_nickname(from);
543 		break;
544 
545 	case 437:		/* #define ERR_UNAVAILRESOURCE  437 */
546 		paste_args(ArgList, 0);
547 		if (do_hook(current_numeric(), "%s %s", from, ArgList[0]))
548 			display_msg(from, ArgList);
549 		if (!is_channel(ArgList[0]))
550 			reset_nickname(from);
551 		break;
552 
553 	case 463:		/* #define ERR_NOPERMFORHOST    463 */
554 		display_msg(from, ArgList);
555 		close_server(parsing_server(), empty_string());
556 		window_check_servers();
557 		if (!connected_to_server())
558 			get_connected(parsing_server() + 1);
559 		break;
560 
561 	case 464:		/* #define ERR_PASSWDMISMATCH   464 */
562 		paste_args(ArgList, 0);
563 		flag = do_hook(current_numeric(), "%s %s", from, ArgList[0]);
564 		if (server_get_oper_command())
565 		{
566 			if (flag)
567 				display_msg(from, ArgList);
568 		}
569 		else
570 			get_password();
571 		break;
572 
573 	case 465:		/* #define ERR_YOUREBANNEDCREEP 465 */
574 		{
575 			int	klined_server = parsing_server();
576 
577 			paste_args(ArgList, 0);
578 			if (do_hook(current_numeric(), "%s %s", from, ArgList[0]))
579 				display_msg(from, ArgList);
580 			close_server(parsing_server(), empty_string());
581 			window_check_servers();
582 			if (number_of_servers() > 1)
583 				remove_from_server_list(klined_server);
584 			if (!connected_to_server())
585 				say("You are not connected to a server. Use /SERVER to connect.");
586 			break;
587 		}
588 
589 	case 471:		/* #define ERR_CHANNELISFULL    471 */
590 	case 473:		/* #define ERR_INVITEONLYCHAN   473 */
591 	case 474:		/* #define ERR_BANNEDFROMCHAN   474 */
592 	case 475: 		/* #define ERR_BADCHANNELKEY    475 */
593 	case 476:		/* #define ERR_BADCHANMASK      476 */
594 		cannot_join_channel(from, ArgList);
595 		break;
596 
597 	case 484:		/* #define ERR_RESTRICTED       484 */
598 		if (do_hook(current_numeric(), "%s %s", from, ArgList[0]))
599 			display_msg(from, ArgList);
600 		server_set_flag(parsing_server(), USER_MODE_R, 1);
601 		break;
602 
603 		/*
604 		 * The following accumulates the remaining arguments
605 		 * in ArgSpace for hook detection.  We can't use
606 		 * paste_args here because we still need the arguments
607 		 * separated for use elsewhere.
608 		 */
609 	default:
610 		{
611 			u_char	*ArgSpace = NULL;
612 			int	i,
613 				do_message_from = 0;
614 			size_t	len;
615 
616 			for (i = len = 0; ArgList[i];)
617 				len += 1 + my_strlen(ArgList[i++]);
618 			len += (i - 1);
619 			ArgSpace = new_malloc(len + 1);
620 			ArgSpace[0] = '\0';
621 			/* this is cheating */
622 			if (is_channel(ArgList[0]))
623 				do_message_from = 1;
624 			for (i = 0; ArgList[i]; i++)
625 			{
626 				if (i)
627 					my_strcat(ArgSpace, " ");
628 				my_strcat(ArgSpace, ArgList[i]);
629 			}
630 			if (do_message_from)
631 			{
632 				save_message_from();
633 				message_from(ArgList[0], LOG_CRAP);
634 			}
635 			i = do_hook(current_numeric(), "%s %s", from, ArgSpace);
636 			new_free(&ArgSpace);
637 			if (do_message_from)
638 				restore_message_from();
639 			if (i == 0)
640 				goto done;
641 			none_of_these = 1;
642 		}
643 	}
644 	/* the following do not hurt the ircII if intercepted by a hook */
645 	if (none_of_these)
646 	{
647 		switch (comm)
648 		{
649 		case 221: 		/* #define RPL_UMODEIS          221 */
650 			put_it("%s Your user mode is \"%s\"", numeric_banner(),
651 				ArgList[0]);
652 			break;
653 
654 		case 242:		/* #define RPL_STATSUPTIME      242 */
655 			paste_args(ArgList, 0);
656 			if (from && !my_strnicmp(server_get_itsname(parsing_server()),
657 			    from, my_strlen(server_get_itsname(parsing_server()))))
658 				from = NULL;
659 			if (from)
660 				put_it("%s %s from (%s)", numeric_banner(),
661 					ArgList[0], from);
662 			else
663 				put_it("%s %s", numeric_banner(), ArgList[0]);
664 			break;
665 
666 		case 332:		/* #define RPL_TOPIC            332 */
667 			channel_topic(from, ArgList);
668 			break;
669 
670 		case 351:		/* #define RPL_VERSION          351 */
671 			version(commstr, from, ArgList);
672 			break;
673 
674 		case 364:		/* #define RPL_LINKS            364 */
675 			if (check_params(commstr, from, 0, ArgList, 2))
676 				return;
677 			if (ArgList[2])
678 			{
679 				paste_args(ArgList, 2);
680 				put_it("%s %-20s %-20s %s", numeric_banner(),
681 					ArgList[0], ArgList[1], ArgList[2]);
682 			}
683 			else
684 			{
685 				paste_args(ArgList, 1);
686 				put_it("%s %-20s %s", numeric_banner(),
687 					ArgList[0], ArgList[1]);
688 			}
689 			break;
690 
691 		case 372:		/* #define RPL_MOTD             372 */
692 			if (!get_int_var(SUPPRESS_SERVER_MOTD_VAR) ||
693 			    !server_get_motd(parsing_server()))
694 			{
695 				paste_args(ArgList, 0);
696 				put_it("%s %s", numeric_banner(), ArgList[0]);
697 			}
698 			break;
699 
700 		case 375:		/* #define RPL_MOTDSTART        375 */
701 			if (!get_int_var(SUPPRESS_SERVER_MOTD_VAR) ||
702 			    !server_get_motd(parsing_server()))
703 			{
704 				paste_args(ArgList, 0);
705 				put_it("%s %s", numeric_banner(), ArgList[0]);
706 			}
707 			break;
708 
709 		case 376:		/* #define RPL_ENDOFMOTD        376 */
710 			if (server_get_attempting_to_connect(parsing_server()))
711 				got_initial_version(UP("*** Your host is broken and not running any version"));
712 			if (get_int_var(SHOW_END_OF_MSGS_VAR) &&
713 			    (!get_int_var(SUPPRESS_SERVER_MOTD_VAR) ||
714 			    !server_get_motd(parsing_server())))
715 			{
716 				paste_args(ArgList, 0);
717 				put_it("%s %s", numeric_banner(), ArgList[0]);
718 			}
719 			server_set_motd(parsing_server(), 0);
720 			break;
721 
722 		case 384:		/* #define RPL_MYPORTIS         384 */
723 			paste_args(ArgList, 0);
724 			put_it("%s %s %s", numeric_banner(), ArgList[0], user);
725 			break;
726 
727 		case 385:		/* #define RPL_NOTOPERANYMORE   385 */
728 			server_set_operator(parsing_server(), 0);
729 			display_msg(from, ArgList);
730 			update_all_status();
731 			break;
732 
733 		case 403:		/* #define ERR_NOSUCHCHANNEL    403 */
734 			not_valid_channel(from, ArgList);
735 			break;
736 
737 		case 451:		/* #define ERR_NOTREGISTERED    451 */
738 	/*
739 	 * Sometimes the server doesn't catch the USER line, so
740 	 * here we send a simplified version again  -lynx
741 	 */
742 			send_to_server("USER %s %s . :%s", my_username(),
743 				irc_umode(), my_realname());
744 			send_to_server("NICK %s",
745 				server_get_nickname(parsing_server()));
746 			break;
747 
748 		case 462:		/* #define ERR_ALREADYREGISTRED 462 */
749 			display_msg(from, ArgList);
750 			break;
751 
752 #define RPL_CLOSEEND         363
753 #define RPL_SERVLISTEND      235
754 		case 315:		/* #define RPL_ENDOFWHO         315 */
755 		case 323:               /* #define RPL_LISTEND          323 */
756 			funny_print_widelist();
757 
758 		case 219:		/* #define RPL_ENDOFSTATS       219 */
759 		case 232:		/* #define RPL_ENDOFSERVICES    232 */
760 		case 365:		/* #define RPL_ENDOFLINKS       365 */
761 		case 368:		/* #define RPL_ENDOFBANLIST     368 */
762 		case 369:		/* #define RPL_ENDOFWHOWAS      369 */
763 		case 374:		/* #define RPL_ENDOFINFO        374 */
764 #if 0	/* this case needs special handing - see above */
765 		case 376:		/* #define RPL_ENDOFMOTD        376 */
766 #endif /* 0 */
767 		case 394:		/* #define RPL_ENDOFUSERS       394 */
768 			if (!get_int_var(SHOW_END_OF_MSGS_VAR))
769 				break;
770 		default:
771 			display_msg(from, ArgList);
772 		}
773 	}
774 	set_lastlog_msg_level(lastlog_level);
775 done:
776 	restore_message_from();
777 }
778 
779 int
current_numeric(void)780 current_numeric(void)
781 {
782 	return current_numeric_local;
783 }
784