1 /*
2  * edit.c: This is really a mishmash of function and such that deal with IRCII
3  * commands (both normal and keybinding commands)
4  *
5  * Written By Michael Sandrof
6  *
7  * Copyright (c) 1990 Michael Sandrof.
8  * Copyright (c) 1991, 1992 Troy Rollo.
9  * Copyright (c) 1992-2001 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 #include "dma.h"
38 IRCII_RCSID("@(#)$eterna: edit.c,v 1.155 2001/09/06 17:12:45 mrg Exp $");
39 
40 #include <sys/stat.h>
41 
42 #ifdef ESIX
43 # include <lan/net_types.h>
44 #endif /* ESIX */
45 
46 #include "parse.h"
47 #include "ircterm.h"
48 #include "server.h"
49 #include "edit.h"
50 #include "irccrypt.h"
51 #include "vars.h"
52 #include "ircaux.h"
53 #include "lastlog.h"
54 #include "window.h"
55 #include "screen.h"
56 #include "whois.h"
57 #include "hook.h"
58 #include "input.h"
59 #include "ignore.h"
60 #include "keys.h"
61 #include "alias.h"
62 #include "history.h"
63 #include "funny.h"
64 #include "ctcp.h"
65 #include "dcc.h"
66 #include "translat.h"
67 #include "output.h"
68 #include "exec.h"
69 #include "notify.h"
70 #include "numbers.h"
71 #include "status.h"
72 #include "if.h"
73 #include "help.h"
74 #include "stack.h"
75 #include "queue.h"
76 #ifdef SUPPORT_ICB
77 # include "icb.h"
78 #endif
79 
80 #include "channels.h"
81 #include "irc_comm.h"
82 #include "ninjacmd.h"
83 #include "grep.h"
84 #include "friends.h"
85 #include "enemies.h"
86 #include "ndcc.h"
87 #include "orignick.h"
88 #include "ninja.h"
89 #include "info.h"
90 #include "tabkey.h"
91 #include "ckey.h"
92 #include "ninredir.h"
93 #include "mileston.h"
94 
95 /*
96  * current_exec_timer - used to make sure we don't remove a timer
97  * from within itself.
98  */
99 static	int	current_exec_timer = -1;
100 
101 static	int	save_which;
102 static	int	save_do_all;
103 
104 static	void	show_timer _((u_char *));
105 static	int	create_timer_ref _((int));
106 static	void	get_history _((int));
107 static	void	oper_password_received _((u_char *, u_char *));
108 /*
109  * moved to edit.h and made public
110  *
111 static	u_char	*do_channel _((u_char *, int));
112  */
113 	void	send_action _((u_char *, u_char *));
114 
115 TimerList *PendingTimers = (TimerList *) 0;
116 
117 /* used with input_move_cursor */
118 #define RIGHT 1
119 #define LEFT 0
120 
121 /* used with /save */
122 #define	SFLAG_ALIAS	0x0001
123 #define	SFLAG_BIND	0x0002
124 #define	SFLAG_ON	0x0004
125 #define	SFLAG_SET	0x0008
126 #define	SFLAG_NOTIFY	0x0010
127 #define	SFLAG_DIGRAPH	0x0020
128 
129 /* The maximum number of recursive LOAD levels allowed */
130 #define MAX_LOAD_DEPTH 10
131 
132 /* recv_nick: the nickname of the last person to send you a privmsg */
133 	u_char	*recv_nick = NULL;
134 
135 /* sent_nick: the nickname of the last person to whom you sent a privmsg */
136 	u_char	*sent_nick = NULL;
137 	u_char	*sent_body = NULL;
138 
139 /* Used to keep down the nesting of /LOADs and to determine if we
140  * should activate the warning for /ONs if the NOVICE variable is set.
141  */
142 	int	load_depth = 0;
143 
144 /* Used to prevent global messaging */
145 extern	int	in_on_who;
146 
147 typedef	struct	WaitCmdstru
148 {
149 	u_char	*stuff;
150 	struct	WaitCmdstru	*next;
151 }	WaitCmd;
152 
153 static	WaitCmd	*start_wait_list = NULL,
154 		*end_wait_list = NULL;
155 
156 	u_char	lame_wait_nick[] = "1#LAME";
157 
158 /* a few advance declarations */
159 static	void	sendlinecmd _((u_char *, u_char *, u_char *));
160 static	void	do_send_text _((u_char *, u_char *, u_char *));
161 static	void	funny_stuff _((u_char *, u_char *, u_char *));
162 static	void	catter _((u_char *, u_char *, u_char *));
163 static	void	cd _((u_char *, u_char *, u_char *));
164 static	void	e_wall _((u_char *, u_char *, u_char *));
165 static	void	send_squery _((u_char *, u_char *, u_char *));
166 static	void	send_brick _((u_char *, u_char *, u_char *));
167 static	void	send_2comm _((u_char *, u_char *, u_char *));
168 static	void	send_comm _((u_char *, u_char *, u_char *));
169 static	void	send_invite _((u_char *, u_char *, u_char *));
170 static	void	send_motd _((u_char *, u_char *, u_char *));
171 static	void	send_topic _((u_char *, u_char *, u_char *));
172 static	void	send_channel_nargs _((u_char *, u_char *, u_char *));
173 /*
174  * not used...
175 static	void	send_channel_2args _((u_char *, u_char *, u_char *));
176  */
177 static	void	send_channel_1arg _((u_char *, u_char *, u_char *));
178 static	void	my_clear _((u_char *, u_char *, u_char *));
179 static	void	quote _((u_char *, u_char *, u_char *));
180 static	void	e_privmsg _((u_char *, u_char *, u_char *));
181 static	void	flush _((u_char *, u_char *, u_char *));
182 /*
183  * ninja replaces this
184  *
185 static	void	away _((u_char *, u_char *, u_char *));
186  */
187 static	void	oper _((u_char *, u_char *, u_char *));
188 static	void	e_channel _((u_char *, u_char *, u_char *));
189 static	void	who _((u_char *, u_char *, u_char *));
190 static	void	whois _((u_char *, u_char *, u_char *));
191 static	void	ison _((u_char *, u_char *, u_char *));
192 static	void	userhost _((u_char *, u_char *, u_char *));
193 static	void	info _((u_char *, u_char *, u_char *));
194 static	void	e_nick _((u_char *, u_char *, u_char *));
195 static	void	commentcmd _((u_char *, u_char *, u_char *));
196 static	void	sleepcmd _((u_char *, u_char *, u_char *));
197 static	void	version _((u_char *, u_char *, u_char *));
198 static	void	ctcp _((u_char *, u_char *, u_char *));
199 static	void	dcc _((u_char *, u_char *, u_char *));
200 static	void	deop _((u_char *, u_char *, u_char *));
201 static	void	my_echo _((u_char *, u_char *, u_char *));
202 static	void	save_settings _((u_char *, u_char *, u_char *));
203 static	void	redirect _((u_char *, u_char *, u_char *));
204 static	void	waitcmd _((u_char *, u_char *, u_char *));
205 static	void	describe _((u_char *, u_char *, u_char *));
206 static	void	me _((u_char *, u_char *, u_char *));
207 static	void	mload _((u_char *, u_char *, u_char *));
208 static	void	mlist _((u_char *, u_char *, u_char *));
209 static	void	evalcmd _((u_char *, u_char *, u_char *));
210 static	void	hook _((u_char *, u_char *, u_char *));
211 	void	timercmd _((u_char *, u_char *, u_char *));
212 static	void	inputcmd _((u_char *, u_char *, u_char *));
213 static	void	pingcmd _((u_char *, u_char *, u_char *));
214 static	void	xtypecmd _((u_char *, u_char *, u_char *));
215 static	void	beepcmd _((u_char *, u_char *, u_char *));
216 static	void	abortcmd _((u_char *, u_char *, u_char *));
217 static	void	really_save _((u_char *, u_char *));
218 
219 /*
220  * moved to irc_comm.h
221  *
222  * IrcCommand: structure for each command in the command table * /
223 typedef	struct
224 {
225 	char	FAR *name;				/ * what the user types * /
226 	char	*server_func;				/ * what gets sent to the server
227 							 * (if anything) * /
228 	void	(*func) _((u_char *, u_char *, u_char *)); / * function that is the command * /
229 	unsigned	flags;
230 }	IrcCommand;
231 
232  *
233  */
234 
235 static	IrcCommand *find_command _((u_char *, int *));
236 
237 #define NONOVICEABBREV	0x0001
238 #define NOINTERACTIVE	0x0002
239 #define NOSIMPLESCRIPT	0x0004
240 #define NOCOMPLEXSCRIPT	0x0008
241 #define SERVERREQ	0x0010
242 
243 /*
244  * irc_command: all the available irc commands:  Note that the first entry has
245  * a zero length string name and a null server command... this little trick
246  * makes "/ blah blah blah" to always be sent to a channel, bypassing queries,
247  * etc.  Neato.  This list MUST be sorted.
248  */
249 static	IrcCommand FAR irc_command[] =
250 {
251 	{ "",		CP(empty_string), do_send_text,		NOSIMPLESCRIPT| NOCOMPLEXSCRIPT },
252 	/*
253 	 * I really want to remove #, but it will break a lot of scripts.  - mycroft
254 	 *
255 	 * I agree - it should be converted to a special character in parse_line.
256 	 *                                                            - Troy
257 	 */
258 	{ "#",		NULL,		commentcmd, 		0 },
259 	{ ":",		NULL,		commentcmd, 		0 },
260 	{ "ABORT",	NULL,		abortcmd,	       	0 },
261    /* ninja start */
262 	{ "ABOUT",	NULL,		ninja_about,		0 },
263 	{ "ADDE",	"ADDE",		add_enemy,		0 },
264 	{ "ADDEC",	"ADDEC",       	add_enemy_chan,		0 },
265 	{ "ADDS",	NULL,		addserver,		0 },
266    /* ninja stop */
267 	{ "ADMIN",	"ADMIN",	send_comm, 		SERVERREQ },
268 	{ "ALIAS",	"0",		alias,			0 },
269 #ifdef ALLOC_DEBUG
270 	{ "ALLOC",	NULL,		alloc_cmd,		0 },
271 #endif /* ALLOC_DEBUG */
272    /* ninja start */
273 	{ "AME",	"AME",		ame,			0 },
274    /* ninja stop */
275 	{ "ASSIGN",	"1",		alias,			0 },
276 	{ "AWAY",	"AWAY",		away,			SERVERREQ },
277    /* ninja start */
278 	{ "BACK",	"AWAY",		back,			SERVERREQ },
279 	{ "BAN",	"BAN",		do_ban_stuff,  		SERVERREQ },
280 	{ "BANKICK",   	"BK",		do_special_k,  		SERVERREQ },
281 	{ "BANS",	"BANS",		show_ban_cache,        	0 },
282    /* ninja stop */
283 	{ "BEEP",	0,		beepcmd,		0 },
284 	{ "BIND",	NULL,		bindcmd,		0 },
285    /* ninja start */
286 	{ "BK",		"BK",		do_special_k,  		SERVERREQ },
287    /* ninja stop */
288 	{ "BRICK",	"BRICK",	send_brick,		SERVERREQ },
289 	{ "BYE",	"QUIT",		e_quit,			NONOVICEABBREV },
290 	{ "CAT",	NULL,		catter,			0 },
291 	{ "CD",		NULL,		cd,			0 },
292 	{ "CHANNEL",	"JOIN",		e_channel,		SERVERREQ },
293    /* ninja start */
294 	{ "CHHOST",	"CHHOST",      	chhost,			0 },
295 	{ "CHKEY",	"CHKEY",	chkey,			SERVERREQ },
296 	{ "CHNAME",	"CHNAME",      	chuname,		0 },
297    /* ninja stop */
298 	{ "CLEAR",	NULL,		my_clear,		0 },
299 	{ "COMMENT",	NULL,		commentcmd,		0 },
300 	{ "CONNECT",	"CONNECT",	send_comm,		SERVERREQ },
301    /* ninja start */
302    	{ "CS",		"SCAN",		ninja_scan,		0 },
303    /* ninja stop */
304 	{ "CTCC",	NULL,		dcc,			SERVERREQ },
305 	{ "CTCP",	NULL,		ctcp,			SERVERREQ },
306    /* ninja start */
307    	{ "CYCLE",	"CYCLE",       	cycle,			SERVERREQ },
308    /* ninja stop */
309 	{ "DATE",	"TIME",		send_comm,		SERVERREQ },
310 	{ "DCC",	NULL,		dcc,			SERVERREQ },
311 	{ "DEOP",	NULL,		deop,			SERVERREQ },
312 	{ "DESCRIBE",	NULL,		describe,		SERVERREQ },
313 	{ "DIE",	"DIE",		send_comm,		SERVERREQ },
314 	{ "DIGRAPH",	NULL,		digraph,		0 },
315 	{ "DISCONNECT",	NULL,		disconnectcmd,		SERVERREQ },
316    /* ninja start */
317         { "DOP",       	"DOP",		give_or_take_ops,      	SERVERREQ },
318         { "DVOICE",    	"DVOICE",      	give_or_take_ops,      	SERVERREQ },
319    /* ninja stop */
320 	{ "ECHO",	NULL,		my_echo,		0 },
321 	{ "ENCRYPT",	NULL,		encrypt_cmd,		0 },
322 	{ "EVAL",	NULL,		evalcmd,		0 },
323 	{ "EXEC",	NULL,		execcmd,		0 },
324 	{ "EXIT",	"QUIT",		e_quit,			NONOVICEABBREV },
325    /* ninja start */
326 	{ "FBK",       	"FBK",		filter_kick,  		SERVERREQ },
327    /* ninja stop */
328 	{ "FE",		NULL,		foreach_handler,	0 },
329 	{ "FEC",	NULL,		fec,			0 },
330    /* ninja start */
331 	{ "FKICK",    	"FKICK",       	filter_kick,  		SERVERREQ },
332    /* ninja stop */
333 	{ "FLUSH",	NULL,		flush,			SERVERREQ },
334 	{ "FOR",	NULL,		foreach_handler,	0 },
335 	{ "FOREACH",	NULL,		foreach_handler,	0 },
336    /* ninja start */
337 	{ "FRIEND",	NULL,		friend_cmd,	0 },
338 	{ "GREP",    	"GREP",       	grep,			0 },
339    /* ninja stop */
340 	{ "HASH",	"HASH",		send_comm,		SERVERREQ },
341 	{ "HELP",	NULL,		help,			0 },
342 	{ "HISTORY",	NULL,		history,		0 },
343 	{ "HOOK",	NULL,		hook,			0 },
344 	{ "HOST",	"USERHOST",	userhost,		SERVERREQ },
345 #ifdef SUPPORT_ICB
346 	{ "ICB",	NULL,		icbcmd,			0 },
347 #endif
348 	{ "IF",		NULL,		ifcmd,			0 },
349 	{ "IGNORE",	NULL,		ignore,			0 },
350 	{ "INFO",	"INFO",		info,			SERVERREQ },
351 	{ "INPUT",	NULL,		inputcmd,		0 },
352 	{ "INVITE",	"INVITE",	send_invite,		SERVERREQ },
353    /* ninja start */
354 	{ "IRCIISAVE",	NULL,		save_settings,		0 },
355    /* ninja stop */
356 	{ "ISON",	"ISON",		ison,			SERVERREQ },
357 	{ "JOIN",	"JOIN",		e_channel,		SERVERREQ },
358    /* ninja start */
359 	{ "K",		"KICK",		do_special_k,		SERVERREQ },
360 	{ "KB",   	"BK",		do_special_k,  		SERVERREQ },
361 	{ "KEY",	"KEY",		chkey,			SERVERREQ },
362 	{ "KICK",	"KICK",		do_special_k,		SERVERREQ },
363 	{ "KICKBAN",   	"BK",		do_special_k,  		SERVERREQ },
364    /* ninja stop */
365 	{ "KILL",	"KILL",		send_2comm,		SERVERREQ },
366 	{ "LASTLOG",	NULL,		lastlog,		0 },
367 	{ "LEAVE",	"PART",		send_channel_1arg,	SERVERREQ },
368    /* ninja start */
369 	{ "LIMIT",   	"LIMIT",       	change_channel_limit,	SERVERREQ },
370    /* ninja stop */
371 	{ "LINKS",	"LINKS",	send_comm,		NONOVICEABBREV|SERVERREQ },
372 	{ "LIST",	"LIST",		funny_stuff,		SERVERREQ },
373    /* ninja start */
374 	{ "LISTENEMIES","LISTENEMIES",	show_enemies,		SERVERREQ },
375 	{ "LK",		"LK",  		lamer_kick,		SERVERREQ },
376    /* ninja stop */
377 	{ "LOAD",	"LOAD",		load,			0 },
378 	{ "LUSERS",	"LUSERS",	send_comm,		SERVERREQ },
379    /* ninja start */
380 	{ "MASS",	"MASS",  	mass,			SERVERREQ },
381 	{ "MDOP",	"MDOP",  	mdop,			SERVERREQ },
382 	{ "MDVOICE",   	"MDVOICE",     	mass_abbrev,		SERVERREQ },
383    /* ninja stop */
384 	{ "ME",		NULL,		me,			SERVERREQ },
385 	{ "MLIST",	NULL,		mlist,			0 },
386 	{ "MLOAD",	NULL,		mload,			0 },
387 	{ "MODE",	"MODE",		send_channel_nargs,	SERVERREQ },
388    /* ninja start */
389 	{ "MOP",   	"MOP",     	mass_abbrev,		SERVERREQ },
390    /* ninja stop */
391 	{ "MOTD",	"MOTD",		send_motd,		SERVERREQ },
392 	{ "MSG",	"PRIVMSG",	e_privmsg,		0 },
393    /* ninja start */
394 	{ "MVOICE",   	"MVOICE",     	mass_abbrev,		SERVERREQ },
395    /* ninja stop */
396 	{ "NAMES",	"NAMES",	funny_stuff,		SERVERREQ },
397    /* ninja start */
398 	{ "NDCC",   	"NDCC",     	process_ndcc,		SERVERREQ },
399    /* ninja stop */
400 	{ "NICK",	"NICK",		e_nick,			SERVERREQ },
401 	{ "NOTE",	"NOTE",		send_comm,		SERVERREQ },
402 	{ "NOTICE",	"NOTICE",	e_privmsg,		SERVERREQ },
403 	{ "NOTIFY",	NULL,		notify,			SERVERREQ },
404 #ifdef ALLOW_OJ
405    /* ninja start */
406 	{ "OJ",		"OJ",		oj,			SERVERREQ },
407    /* ninja stop */
408 #endif
409 	{ "ON",		NULL,		on,			0 },
410    /* ninja start */
411 	{ "OP",   	"OP",     	give_or_take_ops,      	SERVERREQ },
412    /* ninja stop */
413 	{ "OPER",	"OPER",		oper,			SERVERREQ },
414    /* ninja start */
415 	{ "ORIGNICK",  	"ORIGNICK",   	orignick_cmd,		0 },
416    /* ninja stop */
417 	{ "PARSEKEY",	NULL,		parsekeycmd,		0 },
418 	{ "PART",	"PART",		send_channel_1arg,	SERVERREQ },
419 	{ "PING",	NULL, 		pingcmd,		SERVERREQ },
420 	{ "QUERY",	NULL,		query,			0 },
421 	{ "QUEUE",      NULL,           queuecmd,               0 },
422 	{ "QUIT",	"QUIT",		e_quit,			NONOVICEABBREV },
423 	{ "QUOTE",	NULL,		quote,			SERVERREQ },
424 	{ "RBIND",	0,		rbindcmd,		0 },
425    /* ninja start */
426 	{ "RECONNECT", 	"RECONNECT",   	reconnect,		SERVERREQ },
427    /* ninja stop */
428 	{ "REDIRECT",	NULL,		redirect,		0 },
429 	{ "REHASH",	"REHASH",	send_comm,		SERVERREQ },
430    /* ninja start */
431 	{ "RELM",	"RELM",         ninja_redirect,         0 },
432 	{ "RELN",	"RELN",         ninja_redirect,         0 },
433 	{ "RELSM",	"RELSM",        ninja_redirect,         0 },
434 	{ "RELSN",	"RELSN",        ninja_redirect,         0 },
435 	{ "REME",	"REME",         add_enemy,              0 },
436 	{ "REMEC",	"REMEC",        add_enemy_chan,         0 },
437 	{ "REMSERVER",	NULL,		removeserver,		0 },
438    /* ninja stop */
439 	{ "REQUEST",	NULL,		ctcp,			SERVERREQ },
440 	{ "RESTART",	"RESTART",	send_comm,		SERVERREQ },
441    /* ninja start */
442 #ifdef ALLOW_RESYNC
443 	{ "RESYNC",	"RESYNC",      	removeserver,		SERVERREQ },
444 #endif
445 	{ "SAVE",	"SAVE",		ninja_save,		0 },
446    /* ninja stop */
447 	{ "SAY",	CP(empty_string), do_send_text,		SERVERREQ },
448    /* ninja start */
449 	{ "SCAN",	"SCAN",		ninja_scan,		0 },
450    /* ninja stop */
451 	{ "SEND",	NULL,		do_send_text,		SERVERREQ },
452 	{ "SENDLINE",	CP(empty_string), sendlinecmd,		0 },
453 	{ "SERVER",	NULL,		servercmd,		0 },
454 	{ "SET",	NULL,		set_variable,		0 },
455 	{ "SIGNOFF",	"QUIT",		e_quit,			NONOVICEABBREV },
456 	{ "SLEEP",	NULL,		sleepcmd,		0 },
457 	{ "SQUERY",	"SQUERY",	send_squery,		SERVERREQ },
458 	{ "SQUIT",	"SQUIT",	send_2comm,		SERVERREQ },
459 	{ "SRVLIST",	"SERVLIST",	send_comm,		SERVERREQ },
460 	{ "STACK",	NULL,		stackcmd,		0 },
461 	{ "STATS",	"STATS",	send_comm,		SERVERREQ },
462 	{ "SUMMON",	"SUMMON",	send_comm,		SERVERREQ },
463 	{ "TIME",	"TIME",		send_comm,		SERVERREQ },
464 	{ "TIMER",	"TIMER",	timercmd,		0 },
465 	{ "TOPIC",	"TOPIC",	send_topic,		SERVERREQ },
466 	{ "TRACE",	"TRACE",	send_comm,		SERVERREQ },
467 	{ "TYPE",	NULL,		type,			0 },
468    /* ninja start */
469 	{ "UNBAN",	"UNBAN",       	do_ban_stuff, 		SERVERREQ },
470 	{ "UPDATE",	NULL,		update_cmd,    		0 },
471 	{ "UPTIME",	NULL,		uptime,			0 },
472    /* ninja start */
473 	{ "USER",	"USER",		users,			0 },
474    /* ninja stop */
475 	{ "USERHOST",	NULL,		userhost,		SERVERREQ },
476 	{ "USERS",	"USERS",	send_comm,		SERVERREQ },
477 	{ "VERSION",	"VERSION",	version,		0 },
478    /* ninja start */
479 	{ "VOICE",	"VOICE",	give_or_take_ops,      	SERVERREQ },
480    /* ninja stop */
481 	{ "WAIT",	NULL,		waitcmd,		SERVERREQ },
482    /* ninja start */
483 	{ "WALL",	"WALL",		do_wall,       		SERVERREQ },
484    /* ninja stop */
485 	{ "WALLOPERS",	"WALLOPERS",	e_wall,			SERVERREQ },
486    /* ninja start */
487 	{ "WALLOPS",	"WALLOPS",	do_wall,	      	SERVERREQ },
488    /* ninja stop */
489 	{ "WHICH",	"WHICH",	load,			0 },
490 	{ "WHILE",	NULL,		whilecmd,		0 },
491 	{ "WHO",	"WHO",		who,			SERVERREQ },
492 	{ "WHOIS",	"WHOIS",	whois,			SERVERREQ },
493 	{ "WHOWAS",	"WHOWAS",	whois,			SERVERREQ },
494    /* ninja start */
495 	{ "WI",		"WHOIS",      	whois,  		0 },
496 	{ "WII",	"WHOIS",      	whois2,  		0 },
497    /* ninja stop */
498 	{ "WINDOW",	NULL,		windowcmd,		0 },
499    /* ninja start */
500 	{ "WW",		"WHOWAS",      	whois,  		0 },
501    /* ninja stop */
502 	{ "XECHO",	"XECHO",	my_echo,		0 },
503 	{ "XTRA",	"XTRA",		e_privmsg,		SERVERREQ },
504 	{ "XTYPE",	NULL,		xtypecmd,		0 },
505 	{ NULL,		NULL,		commentcmd,		0 }
506 };
507 
508 /* number of entries in irc_command array */
509 # define	NUMBER_OF_COMMANDS (sizeof(irc_command) / sizeof(IrcCommand)) - 2
510 
511 /*
512  * find_command: looks for the given name in the command list, returning a
513  * pointer to the first match and the number of matches in cnt.  If no
514  * matches are found, null is returned (as well as cnt being 0). The command
515  * list is sorted, so we do a binary search.  The returned commands always
516  * points to the first match in the list.  If the match is exact, it is
517  * returned and cnt is set to the number of matches * -1.  Thus is 4 commands
518  * matched, but the first was as exact match, cnt is -4.
519  */
520 static	IrcCommand *
find_command(com,cnt)521 find_command(com, cnt)
522 	u_char	*com;
523 	int	*cnt;
524 {
525 	size_t	len;
526 
527 	if (com && (len = my_strlen(com)))
528 	{
529 		int	min,
530 			max,
531 			pos,
532 			old_pos = -1,
533 			c;
534 
535 		min = 1;
536 		max = NUMBER_OF_COMMANDS + 1;
537 		while (1)
538 		{
539 			pos = (max + min) / 2;
540 			if (pos == old_pos)
541 			{
542 				*cnt = 0;
543 				return ((IrcCommand *) 0);
544 			}
545 			old_pos = pos;
546 			c = my_strncmp(com, irc_command[pos].name, len);
547 			if (c == 0)
548 				break;
549 			else if (c > 0)
550 				min = pos;
551 			else
552 				max = pos;
553 		}
554 		*cnt = 0;
555 		(*cnt)++;
556 		min = pos - 1;
557 		while ((min > 0) && (my_strncmp(com, irc_command[min].name,
558 				len) == 0))
559 		{
560 			(*cnt)++;
561 			min--;
562 		}
563 		min++;
564 		max = pos + 1;
565 		while ((max < NUMBER_OF_COMMANDS + 1) && (my_strncmp(com,
566 				irc_command[max].name, len) == 0))
567 		{
568 			(*cnt)++;
569 			max++;
570 		}
571 		if (*cnt)
572 		{
573 			if (my_strlen(irc_command[min].name) == len)
574 				*cnt *= -1;
575 			else if (*cnt == 1 &&
576 					irc_command[min].flags&NONOVICEABBREV &&
577 					get_int_var(NOVICE_VAR))
578 			{
579 				say("As a novice you may not abbreviate the %s command", irc_command[min].name);
580 				*cnt=0;
581 				return ((IrcCommand *) 0);
582 			}
583 			return (&(irc_command[min]));
584 		}
585 		else
586 			return ((IrcCommand *) 0);
587 	}
588 	else
589 	{
590 		*cnt = -1;
591 		return (irc_command);
592 	}
593 }
594 
595 /*ARGSUSED*/
596 static	void
ctcp(command,args,subargs)597 ctcp(command, args, subargs)
598 	u_char	*command,
599 		*args,
600 		*subargs;
601 {
602 	u_char	*to,
603 		*tag;
604 	int	ctcptype;
605 
606 	if ((to = next_arg(args, &args)) != NULL)
607 	{
608 		if (!my_strcmp(to, "*"))
609 			if ((to = get_channel_by_refnum(0)) == NULL)
610 				to = zero;
611 		if ((tag = next_arg(args, &args)) != NULL)
612 			upper(tag);
613 		else
614 			tag = UP("VERSION");
615 		if ((ctcptype = in_ctcp()) == -1)
616 			my_echo(NULL, UP("*** You may not use the CTCP command in an ON CTCP_REPLY!"), empty_string);
617 		else
618 		{
619 			if (args && *args)
620 				send_ctcp(ctcp_type[ctcptype], to, tag, "%s", args);
621 			else
622 				send_ctcp(ctcp_type[ctcptype], to, tag, NULL);
623 		}
624 	}
625    else
626      usage("ctcp", "<nick> [<request>]");
627 }
628 
629 /*ARGSUSED*/
630 static	void
hook(command,args,subargs)631 hook(command, args, subargs)
632 	u_char	*command,
633 		*args,
634 		*subargs;
635 {
636 	if (*args)
637 		do_hook(HOOK_LIST, "%s", args);
638    else
639      usage("hook","<argument>");
640 }
641 
642 /*ARGSUSED*/
643 static	void
dcc(command,args,subargs)644 dcc(command, args, subargs)
645 	u_char	*command,
646 		*args,
647 		*subargs;
648 {
649 	if (*args)
650 		process_dcc(args);
651 	else
652 		dcc_list((u_char *) 0);
653 }
654 
655 /*ARGSUSED*/
656 static	void
deop(command,args,subargs)657 deop(command, args, subargs)
658 	u_char	*command,
659 		*args,
660 		*subargs;
661 {
662 	send_to_server("MODE %s -o", get_server_nickname(from_server));
663 }
664 
665 static	void
funny_stuff(command,args,subargs)666 funny_stuff(command, args, subargs)
667 	u_char	*command,
668 		*args,
669 		*subargs;
670 {
671 	u_char	*arg,
672 		*cmd = (u_char *) 0,
673 		*stuff,
674 		*s;
675 	int	min = 0,
676 		max = 0,
677 		flags = 0;
678 	size_t	len;
679 
680 #ifdef SUPPORT_ICB
681 	if (get_server_version(from_server) == ServerICB)
682 	{
683 		icb_put_funny_stuff(command, args, subargs);
684 		return;
685 	}
686 #endif
687 	stuff = empty_string;
688 	while ((arg = next_arg(args, &args)) != NULL)
689 	{
690 		len = my_strlen(arg);
691 		malloc_strcpy(&cmd, arg);
692 		upper(cmd);
693 		if (my_strncmp(cmd, "-MAX", len) == 0)
694 		{
695 			if ((arg = next_arg(args, &args)) != NULL)
696 				max = my_atoi(arg);
697 		}
698 		else if (my_strncmp(cmd, "-MIN", len) == 0)
699 		{
700 			if ((arg = next_arg(args, &args)) != NULL)
701 				min = my_atoi(arg);
702 		}
703 		else if (my_strncmp(cmd, "-ALL", len) == 0)
704 		{
705 			flags &= ~(FUNNY_PUBLIC | FUNNY_PRIVATE);
706 		}
707 		else if (my_strncmp(cmd, "-PUBLIC", len) == 0)
708 		{
709 			flags |= FUNNY_PUBLIC;
710 			flags &= ~FUNNY_PRIVATE;
711 		}
712 		else if (my_strncmp(cmd, "-PRIVATE", len) == 0)
713 		{
714 			flags |= FUNNY_PRIVATE;
715 			flags &= ~FUNNY_PUBLIC;
716 		}
717 		else if (my_strncmp(cmd, "-TOPIC", len) == 0)
718 			flags |= FUNNY_TOPIC;
719 		else if (my_strncmp(cmd, "-WIDE", len) == 0)
720 			flags |= FUNNY_WIDE;
721 		else if (my_strncmp(cmd, "-USERS", len) == 0)
722 			flags |= FUNNY_USERS;
723 		else if (my_strncmp(cmd, "-NAME", len) == 0)
724 			flags |= FUNNY_NAME;
725 		else
726 			stuff = arg;
727 		new_free(&cmd);
728 	}
729 	set_funny_flags(min, max, flags);
730    if (my_strcmp(stuff, "*") == 0)
731      if (!(stuff = get_channel_by_refnum(0)))
732        stuff = empty_string;
733    if ((s = my_index(stuff, '*')) && !is_on_channel(stuff, from_server, get_server_nickname(from_server)))
734      {
735 	funny_match(stuff);
736 	send_to_server("%s %s", command, empty_string);
737 	return;
738      }
739    /* don't allow the /names showing all channels without explicitly asking for ** */
740    if (!stuff || stuff == empty_string)
741      {
742 	if (!server_list[from_server].chan_list)
743 	  {
744 	     usage(command, "*, **, or <channel>");
745 	     return;
746 	  }
747 	else
748 	  stuff = get_channel_by_refnum(0);
749      }
750    if (!stuff)
751      {
752 	usage(command, "*, **, or <channel>");
753 	return;
754      }
755    funny_match(NULL);
756    send_to_server("%s %s", command, stuff);
757 }
758 
759 /*ARGSUSED*/
760 static void
waitcmd(command,args,subargs)761 waitcmd(command, args, subargs)
762 	u_char	*command,
763 		*args,
764 		*subargs;
765 {
766 #ifdef _Windows
767 	yell("WAIT is not available under Windows");
768 #else /* Windows */
769 	int	wait_index;
770 	u_char	*flag;
771 	u_char	*procindex;
772 	int	cmd = 0;
773 	size_t	len;
774 	u_char	buffer[BIG_BUFFER_SIZE];
775 
776 	while (args && *args == '-')
777 	{
778 		flag = next_arg(args, &args);
779 		len = my_strlen(++flag);
780 		if (!my_strnicmp(UP("CMD"), flag, len))
781 		{
782 			cmd = 1;
783 			break;
784 		}
785 		else
786 			yell("Unknown argument to WAIT: %s", flag);
787 	}
788 	if ((procindex = next_arg(args, &args)) && *procindex == '%' &&
789 			(wait_index = get_process_index(&procindex)) != -1)
790 	{
791 		if (is_process_running(wait_index))
792 		{
793 			if (cmd)
794 			{
795 				add_process_wait(wait_index, args?args:empty_string);
796 				return;
797 			}
798 			else
799 				set_wait_process(wait_index);
800 		}
801 		else
802 		{
803 			say("Not a valid process!");
804 			return;
805 		}
806 	}
807 	else if (cmd)
808 	{
809 		WaitCmd	*new;
810 
811 		snprintf(CP(buffer), sizeof(buffer)-1, "%s %s", procindex, args);
812 	   	buffer[sizeof(buffer)-1] = '\0';
813 		new = (WaitCmd *) new_malloc(sizeof(WaitCmd));
814 		new->stuff = NULL;
815 		malloc_strcpy(&new->stuff, buffer);
816 		new->next = NULL;
817 		if (end_wait_list)
818 			end_wait_list->next = new;
819 		end_wait_list = new;
820 		if (!start_wait_list)
821 			start_wait_list = new;
822 		send_to_server("%s", wait_nick);
823 		return;
824 	}
825 	else
826 		send_to_server("%s", lame_wait_nick);
827 	if (waiting)
828 		yell("WAIT has been called recursively.");
829 
830 	waiting++;
831 	irc_io(NULL, NULL, 0, 1);
832 	waiting--;
833 #endif /* _Windows */
834 }
835 
836 int
check_wait_command(nick)837 check_wait_command(nick)
838 	u_char 	*nick;
839 {
840 	if (waiting && !my_strcmp(nick, lame_wait_nick))
841 	{
842 		irc_io_loop = 0;
843 		return 1;
844 	}
845 	if (start_wait_list && !my_strcmp(nick, wait_nick))
846 	{
847 		if (start_wait_list->stuff)
848 		{
849 			parse_command(start_wait_list->stuff, 0, empty_string);
850 			new_free(&start_wait_list->stuff);
851 		}
852 		start_wait_list = start_wait_list->next;
853 		return 1;
854 	}
855 	return 0;
856 }
857 
858 /*ARGSUSED*/
859 static	void
redirect(command,args,subargs)860 redirect(command, args, subargs)
861 	u_char	*command,
862 		*args,
863 		*subargs;
864 {
865 	u_char	*to;
866 
867 	if ((to = next_arg(args, &args)) != NULL)
868 	{
869 		if (!my_strcmp(to, "*"))
870 			if (!(to = get_channel_by_refnum(0)))
871 			{
872 				say("Must be on a channel to redirect to '*'");
873 				return;
874 			}
875 		if (!my_stricmp(to, get_server_nickname(from_server)))
876 		{
877 			say("You may not redirect output to yourself");
878 			return;
879 		}
880 		window_redirect(to, from_server);
881 		server_list[from_server].sent = 0;
882 		parse_line((u_char *) 0, args, (u_char *) 0, 0, 0, 0);
883 		if (server_list[from_server].sent)
884 			send_to_server("%s", current_screen->redirect_token,
885 				current_screen->screennum);
886 		else
887 			window_redirect(NULL, from_server);
888 	}
889    else
890      usage("redirect", "<nick, channel, or %process> <cmd>");
891 }
892 
893 /*ARGSUSED*/
894 static	void
sleepcmd(command,args,subargs)895 sleepcmd(command, args, subargs)
896 	u_char	*command,
897 		*args,
898 		*subargs;
899 {
900 #ifndef _Windows
901 	u_char	*arg;
902 
903 	if ((arg = next_arg(args, &args)) != NULL)
904 		sleep((unsigned)my_atoi(arg));
905 	else
906      		usage("sleep", "<seconds>");
907 #else
908 	say("SLEEP: Not available under Windows");
909 #endif /* _Windows */
910 }
911 
912 /*
913  * my_echo: simply displays the args to the screen, or, if it's XECHO,
914  * processes the flags first, then displays the text on
915  * the screen
916  */
917 static void
my_echo(command,args,subargs)918 my_echo(command, args, subargs)
919 	u_char	*command,
920 		*args,
921 		*subargs;
922 {
923 	unsigned int	display;
924 	int	lastlog_level = 0;
925 	int	from_level = 0;
926 	u_char	*flag_arg;
927 	int	temp;
928 	Window *old_to_window;
929 
930 	save_message_from();
931 	old_to_window = to_window;
932 	if (command && *command == 'X')
933 	{
934 		while (args && *args == '-')
935 		{
936 			flag_arg = next_arg(args, &args);
937 			switch(flag_arg[1])
938 			{
939 
940 			 case 'H':
941 			 case 'h':
942 			   usage("echo", "[-l <lastlog level>] [-w <window #>] <stuff>");
943 			   break;
944 
945 			case 'L':
946 			case 'l':
947 				if (!(flag_arg = next_arg(args, &args)))
948 					break;
949 				if ((temp = parse_lastlog_level(flag_arg)) != 0)
950 				{
951 					lastlog_level = set_lastlog_msg_level(temp);
952 					from_level = message_from_level(temp);
953 				}
954 				break;
955 			case 'W':
956 			case 'w':
957 				if (!(flag_arg = next_arg(args, &args)))
958 					break;
959 				if (isdigit(*flag_arg))
960 					to_window = get_window_by_refnum((unsigned)my_atoi(flag_arg));
961 				else
962 					to_window = get_window_by_name(flag_arg);
963 				lastlog_level = set_lastlog_msg_level(LOG_CRAP);
964 				from_level = message_from_level(LOG_CRAP);
965 				break;
966 			}
967 			if (!args)
968 				args = empty_string;
969 		}
970 	}
971 	display = window_display;
972 	window_display = 1;
973 	put_it("%s", args);
974 	window_display = display;
975 	if (lastlog_level)
976 		set_lastlog_msg_level(lastlog_level);
977 	if (from_level)
978 		message_from_level(from_level);
979 	restore_message_from();
980 	to_window = old_to_window;
981 }
982 
983 /*
984  */
985 static	void
oper_password_received(data,line)986 oper_password_received(data, line)
987 	u_char	*data;
988 	u_char	*line;
989 {
990 	send_to_server("OPER %s %s", data, line);
991 }
992 
993 /* oper: the OPER command.  */
994 /*ARGSUSED*/
995 static	void
oper(command,args,subargs)996 oper(command, args, subargs)
997 	u_char	*command,
998 		*args,
999 		*subargs;
1000 {
1001 	u_char	*password;
1002 	u_char	*nick;
1003 
1004 	oper_command = 1;
1005 	if (!(nick =  next_arg(args, &args)))
1006 		nick =  nickname;
1007 	if (!(password = next_arg(args, &args)))
1008 	{
1009 		add_wait_prompt(UP("Operator Password:"),
1010 			oper_password_received, nick, WAIT_PROMPT_LINE);
1011 		return;
1012 	}
1013 	send_to_server("OPER %s %s", nick, password);
1014 }
1015 
1016 /* Full scale abort.  Does a "save" into the filename in line, and
1017         then does a coredump */
1018 static  void
abortcmd(command,args,subargs)1019 abortcmd(command, args, subargs)
1020 	u_char	*command,
1021 		*args,
1022 		*subargs;
1023 {
1024         u_char    *filename = (u_char *) next_arg(args, &args);
1025 
1026 	if (!filename)
1027 		filename = UP("irc.aborted");
1028 	save_which = SFLAG_ALIAS | SFLAG_BIND | SFLAG_ON | SFLAG_SET |
1029 			     SFLAG_NOTIFY | SFLAG_DIGRAPH;
1030         really_save(filename, UP("y"));
1031 #ifdef ALLOC_DEBUG
1032         alloc_cmd("ALLOC", "d", (u_char *) 0);
1033 #endif /* ALLOC_DEBUG */
1034         abort();
1035 }
1036 
1037 /* This generates a file of your ircII setup */
1038 static	void
really_save(file,line)1039 really_save(file, line)
1040 	u_char	*file;
1041 	u_char	*line;
1042 {
1043 	FILE	*fp;
1044 
1045 	if (*line != 'y' && *line != 'Y')
1046 		return;
1047 	if ((fp = fopen(CP(file), "w")) != NULL)
1048 	{
1049 		if (save_which & SFLAG_BIND)
1050 			save_bindings(fp, save_do_all);
1051 		if (save_which & SFLAG_ON)
1052 			save_hooks(fp, save_do_all);
1053 		if (save_which & SFLAG_NOTIFY)
1054 			save_notify(fp);
1055 		if (save_which & SFLAG_SET)
1056 			save_variables(fp, save_do_all);
1057 		if (save_which & SFLAG_ALIAS)
1058 			save_aliases(fp, save_do_all);
1059 		if (save_which & SFLAG_DIGRAPH)
1060 			save_digraphs(fp);
1061 		fclose(fp);
1062 		say("IRCII settings saved to %s", file);
1063 	}
1064 	else
1065 		say("Error opening %s: %s", file, strerror(errno));
1066 }
1067 
1068 /* save_settings: saves the current state of IRCII to a file */
1069 /*ARGSUSED*/
1070 static	void
save_settings(command,args,subargs)1071 save_settings(command, args, subargs)
1072 	u_char	*command,
1073 		*args,
1074 		*subargs;
1075 {
1076 	u_char	buffer[BIG_BUFFER_SIZE];
1077 	u_char	*arg, *temp;
1078 	int	all = 1, save_force = 0;
1079 
1080 	save_which = save_do_all = 0;
1081 	while ((arg = next_arg(args, &args)) != NULL)
1082 	{
1083 		if ('-' == *arg)
1084 		{
1085 			u_char	*cmd = NULL;
1086 
1087 			all = 0;
1088 			malloc_strcpy(&cmd, arg+1);
1089 			upper(cmd);
1090 			if (0 == my_strncmp("ALIAS", cmd, 5))
1091 				save_which |= SFLAG_ALIAS;
1092 			else if (0 == my_strncmp("ASSIGN", cmd, 6))
1093 				save_which |= SFLAG_ALIAS;
1094 			else if (0 == my_strncmp("BIND", cmd, 4))
1095 				save_which |= SFLAG_BIND;
1096 			else if (0 == my_strncmp("ON", cmd, 2))
1097 				save_which |= SFLAG_ON;
1098 			else if (0 == my_strncmp("SET", cmd, 3))
1099 				save_which |= SFLAG_SET;
1100 			else if (0 == my_strncmp("NOTIFY", cmd, 6))
1101 				save_which |= SFLAG_NOTIFY;
1102 			else if (0 == my_strncmp("DIGRAPH", cmd, 7))
1103 				save_which |= SFLAG_DIGRAPH;
1104 			else if (0 == my_strncmp("ALL", cmd, 3))
1105 				save_do_all = 1;
1106 			else if (0 == my_strncmp("FORCE", cmd, 3))
1107 				save_force = 1;
1108 			else
1109 			{
1110 				say("%s: unknown argument", arg);
1111 				new_free(&cmd);
1112 				return;
1113 			}
1114 			new_free(&cmd);
1115 			continue;
1116 		}
1117 #ifdef DAEMON_UID
1118 		if (getuid() == DAEMON_UID)
1119 		{
1120 			say("You may only use the default value");
1121 			return;
1122 		}
1123 #endif /* DAEMON_UID */
1124 		temp = expand_twiddle(arg);
1125 		if (temp)
1126 		{
1127 			if (ircrc_file)
1128 				new_free(&ircrc_file);
1129 			ircrc_file = temp;
1130 		}
1131 		else
1132 		{
1133 			say("Unknown user");
1134 			return;
1135 		}
1136 	}
1137 	if (all)
1138 		save_which = SFLAG_ALIAS | SFLAG_BIND | SFLAG_ON | SFLAG_SET |
1139 			     SFLAG_NOTIFY | SFLAG_DIGRAPH;
1140 	if (dumb || save_force)
1141 		really_save(ircrc_file, UP("y")); /* REAL dumb!  -lynx */
1142 	else
1143 	{
1144 		snprintf(CP(buffer), sizeof(buffer)-1, "Really write %s? ", ircrc_file);
1145 	   	buffer[sizeof(buffer)-1] = '\0';
1146 		add_wait_prompt(buffer, really_save, ircrc_file,
1147 				WAIT_PROMPT_LINE);
1148 	}
1149 }
1150 
1151 /*
1152  * do_channel : checks whether the channel has already been joined and
1153  * returns the channel's name if not
1154  */
1155 u_char *
do_channel(chan,force)1156 do_channel(chan, force)
1157 	u_char	*chan;
1158 	int force;
1159 {
1160 	Channel	*channel;
1161 	u_char		*old;
1162 
1163 	if (from_server < 0 || curr_scr_win->server < 0)
1164 		return (u_char *) 0;
1165 
1166    /* ninja extension to add a # by default */
1167    if (my_stricmp(chan, zero) != 0 && !is_channel(chan))
1168      chan = make_chan(chan);
1169 
1170 	channel = lookup_channel(chan, curr_scr_win->server, CHAN_NOUNLINK);
1171 
1172 	if (is_bound(chan, curr_scr_win->server) && channel && channel->window != curr_scr_win)
1173 		say("Channel %s is bound", chan);
1174 	else if (is_on_channel(chan, curr_scr_win->server, get_server_nickname(curr_scr_win->server)))
1175 	{
1176 		is_current_channel(chan, curr_scr_win->server, 1);
1177 		say("You are now talking to channel %s", set_channel_by_refnum(0, chan));
1178 		update_all_windows();
1179 	}
1180 	else
1181 	{
1182 		/* only do this if we're actually joining a new channel */
1183 		if (get_int_var(NOVICE_VAR))
1184 		{
1185 			if ((old = get_channel_by_refnum(0)) && my_strcmp(old, zero))
1186 				send_to_server("PART %s", old);
1187 		}
1188 		add_channel(chan, from_server, CHAN_JOINING, (Channel *) 0);
1189 		force = 1;
1190 	}
1191 	if (force)
1192 		return chan;
1193 	else
1194 		return (u_char *) 0;
1195 }
1196 
1197 /*
1198  * e_channel: does the channel command.  I just added displaying your current
1199  * channel if none is given
1200  */
1201 static	void
e_channel(command,args,subargs)1202 e_channel(command, args, subargs)
1203 	u_char	*command,
1204 		*args,
1205 		*subargs;
1206 {
1207 	u_char	*chan;
1208 	size_t	len;
1209 	u_char	*chanstr = (u_char *) 0,
1210 		*ptr;
1211 	int 	force = 0;
1212 
1213 #ifdef SUPPORT_ICB
1214 	if (get_server_version(from_server) == ServerICB)
1215 	{
1216 		icb_put_group(args);
1217 		return;
1218 	}
1219 #endif
1220 	if (get_server_version(from_server) == Server2_5)
1221 		command = UP("CHANNEL");
1222 	save_message_from();
1223 	message_from((u_char *) 0, LOG_CURRENT);		/* XXX should delete this */
1224 	if ((chan = next_arg(args, &args)) != NULL)
1225 	{
1226 		len = MAX(2, my_strlen(chan));
1227 		if (my_strnicmp(chan, UP("-force"), len) == 0)
1228 		{
1229 			force = 1;
1230 			if ((chan = next_arg(args, &args)) == NULL)
1231 				goto out;	/* XXX: allow /alias join join -force */
1232 			len = MAX(2, my_strlen(chan));
1233 		}
1234 	   if (my_strnicmp(chan, UP("-invite"), len) == 0)
1235 	     join_invite(force, UNULL);
1236 	   else
1237 	     {
1238 		u_char *key;
1239 
1240 		malloc_strcpy(&chanstr, chan);
1241 		chan = chanstr;
1242 
1243 		if (get_int_var(NOVICE_VAR))
1244 		  chanstr = UP(strtok(CP(chanstr), ","));
1245 
1246 		ptr = UP(strtok(CP(chanstr), (",")));
1247 		if ((ptr = do_channel(ptr, force)) && *ptr)
1248 		  {
1249 		     key = next_arg(args, &args);
1250 		     if (key)	/* i'm not positive we should add this here, but
1251 				 * it allows us to tell them what key we tried!
1252 				 */
1253 		       add_ckey(ptr, key);
1254 		     send_to_server("%s %s %s", command, ptr, get_ckey(ptr));
1255 		  }
1256 		while ((ptr = UP(strtok(NULL, ","))))
1257 		  if ((ptr = do_channel(ptr, force)) && *ptr)
1258 		    {
1259 		       key = next_arg(args, &args);
1260 		       if (key)
1261 			 add_ckey(ptr, key);
1262 		       send_to_server("%s %s %s", command, ptr, get_ckey(ptr));
1263 		    }
1264 		new_free(&chan);
1265 	     }
1266 	}
1267 	else
1268 out:
1269 		list_channels();
1270 	restore_message_from();
1271 }
1272 
1273 /* comment: does the /COMMENT command, useful in .ircrc */
1274 /*ARGSUSED*/
1275 static	void
commentcmd(command,args,subargs)1276 commentcmd(command, args, subargs)
1277 	u_char	*command,
1278 		*args,
1279 		*subargs;
1280 {
1281 	/* nothing to do... */
1282 }
1283 
1284 /*
1285  * e_nick: does the /NICK command.  Records the users current nickname and
1286  * sends the command on to the server
1287  */
1288 /*ARGSUSED*/
1289 static	void
e_nick(command,args,subargs)1290 e_nick(command, args, subargs)
1291 	u_char	*command,
1292 		*args,
1293 		*subargs;
1294 {
1295 	u_char	*nick;
1296 
1297 	if (!(nick = next_arg(args, &args)))
1298 	{
1299 		say("Your nickname is %s",
1300 			get_server_nickname(get_window_server(0)));
1301 		return;
1302 	}
1303 #ifdef SUPPORT_ICB
1304 	if (get_server_version(from_server) == ServerICB)
1305 	{
1306 		icb_put_nick(nick);
1307 		return;
1308 	}
1309 #endif
1310 	send_to_server("NICK %s", nick);
1311 	if (attempting_to_connect)
1312 		set_server_nickname(get_window_server(0), nick);
1313 	if (get_server_version(from_server) == Server2_5)
1314 		add_to_whois_queue(nick, whois_nickname, NULL);
1315 }
1316 
1317 /* version: does the /VERSION command with some IRCII version stuff */
1318 static	void
version(command,args,subargs)1319 version(command, args, subargs)
1320 	u_char	*command,
1321 		*args,
1322 		*subargs;
1323 {
1324 	u_char	*host;
1325 
1326 	if (
1327 #ifdef SUPPORT_ICB
1328 	    get_server_version(from_server) != ServerICB &&
1329 #endif
1330 	    ((host = next_arg(args, &args)) != NULL))
1331 	{
1332 	   if (my_index(host, '.'))
1333 		send_to_server("%s %s", command, host);
1334 	   else
1335 	     send_ctcp(ctcp_type[0], host, "VERSION", NULL);
1336 	}
1337 	else
1338 	{
1339 	   put_info("Client Ninja IRC v%s, build #%s made by %s@%s on %s [%s]",
1340 		    irc_version,
1341 		    compile_num, compile_user, compile_host, compile_time,
1342 		    ninja_release);
1343 	   /* say("Client: ircII %s (internal version %s)", irc_version, internal_version); */
1344 #ifdef SUPPORT_ICB
1345 		if (get_server_version(from_server) == ServerICB)
1346 			icb_put_version(args);
1347 		else
1348 #endif
1349 			send_to_server("%s", command);
1350 	}
1351 }
1352 
1353 /*
1354  * info: does the /INFO command.  I just added some credits
1355  * I updated most of the text -phone, feb 1993.
1356  */
1357 static	void
info(command,args,subargs)1358 info(command, args, subargs)
1359 	u_char	*command,
1360 		*args,
1361 		*subargs;
1362 {
1363 	if (!args || !*args)
1364 	{
1365 		say("ircii: originally written by Michael Sandrof");
1366 		say("       versions 2.1 to 2.2pre7 by Troy Rollo");
1367 		say("       development continued by matthew green");
1368 		say("       e-mail: mrg@eterna.com.au  irc: phone");
1369 		say("       copyright (c) 1990-2001");
1370 		say("       do a /help ircii copyright for the full copyright");
1371 		say("       ircii includes software developed by the university");
1372 		say("       of california, berkeley and its contributors");
1373 		say("");
1374 		say("ircii contributors");
1375 		say("");
1376 		say("       \tMichael Sandrof       Mark T. Dameu");
1377 		say("       \tStellan Klebom        Carl v. Loesch");
1378 		say("       \tTroy Rollo            Martin  Friedrich");
1379 		say("       \tMichael Weber         Bill Wisner");
1380 		say("       \tRiccardo Facchetti    Stephen van den Berg");
1381 		say("       \tVolker Paulsen        Kare Pettersson");
1382 		say("       \tIan Frechette         Charles Hannum");
1383 		say("       \tmatthew green         christopher williams");
1384 		say("       \tJonathan Lemon        Brian Koehmstedt");
1385 		say("       \tNicolas Pioch         Brian Fehdrau");
1386 		say("       \tDarren Reed           Jeff Grills");
1387 		say("       \tJeremy Nelson         Philippe Levan");
1388 		say("       \tScott Reynolds        Glen McCready");
1389 		say("       \tChristopher Kalt      Joel Yliluoma");
1390 	        say("");
1391 	        say("for ninja specific info try /about");
1392 	}
1393 	send_to_server("%s %s", command, args);
1394 }
1395 
1396 void
ison_now(notused,nicklist,notused2)1397 ison_now(notused, nicklist, notused2)
1398 	WhoisStuff	*notused;
1399 	u_char		*nicklist,
1400 			*notused2;
1401 {
1402 	if (do_hook(current_numeric, "%s", nicklist))
1403 		put_it("%sCurrently online: %s", numeric_banner(), nicklist);
1404 }
1405 
1406 static	void
ison(command,args,subargs)1407 ison(command, args, subargs)
1408 	u_char	*command,
1409 		*args,
1410 		*subargs;
1411 {
1412 	if (!args[strspn(CP(args), " ")])
1413 		usage("ison", "<nick 1> .. <nick n>"); /* args = get_server_nickname(from_server); */
1414 	add_ison_to_whois(args, ison_now);
1415 }
1416 
1417 /*
1418  * userhost: Does the USERHOST command.  Need to split up the queries,
1419  * since the server will only reply to 5 at a time.
1420  */
1421 static	void
userhost(command,args,subargs)1422 userhost(command, args, subargs)
1423 	u_char	*command,
1424 		*args,
1425 		*subargs;
1426 {
1427 	int	n = 0,
1428 		total = 0,
1429 		userhost_cmd = 0;
1430 	u_char	*nick;
1431 	u_char	buffer[BIG_BUFFER_SIZE];
1432 
1433 	while ((nick = next_arg(args, &args)) != NULL)
1434 	{
1435 		size_t	len;
1436 
1437 		++total;
1438 		len = my_strlen(nick);
1439 		if (!my_strnicmp(nick, UP("-CMD"), len))
1440 		{
1441 			if (total < 2)
1442 			{
1443 				yell("userhost -cmd with no nick!");
1444 				return;
1445 			}
1446 			userhost_cmd = 1;
1447 			break;
1448 		}
1449 		else
1450 		{
1451 			if (n++)
1452 				my_strmcat(buffer, " ", BIG_BUFFER_SIZE);
1453 			else
1454 				*buffer = '\0';
1455 			my_strmcat(buffer, nick, BIG_BUFFER_SIZE);
1456 		}
1457 	}
1458 	if (n)
1459 	{
1460 		u_char	*the_list = (u_char *) 0;
1461 		u_char	*s, *t;
1462 		int	i;
1463 
1464 		malloc_strcpy(&the_list, buffer);
1465 		s = t = the_list;
1466 		while (n)
1467 		{
1468 			for (i = 5; i && *s; s++)
1469 				if (' ' == *s)
1470 					i--, n--;
1471 			if (' ' == *(s - 1))
1472 				*(s - 1) = '\0';
1473 			else
1474 				n--;
1475 			my_strcpy(buffer, t);
1476 			t = s;
1477 
1478 			if (userhost_cmd)
1479 				add_to_whois_queue(buffer, userhost_cmd_returned, "%s", args);
1480 			else
1481 				add_to_whois_queue(buffer, USERHOST_USERHOST, 0);
1482 		}
1483 		new_free(&the_list);
1484 	}
1485 	else if (!total)
1486 		/* Default to yourself.
1487 		 *
1488 		 * WHY?!
1489 		add_to_whois_queue(get_server_nickname(from_server), USERHOST_USERHOST, 0);
1490 		 */
1491      		usage("userhost", "<nick> [-cmd <commands>]");
1492 }
1493 
1494 /*
1495  * whois: the WHOIS and WHOWAS commands.  This translates the
1496  * to the whois handlers in whois.c
1497  */
1498 static	void
whois(command,args,subargs)1499 whois(command, args, subargs)
1500 	u_char	*command,
1501 		*args,
1502 		*subargs;
1503 {
1504 #ifdef SUPPORT_ICB
1505 	if (get_server_version(from_server) == ServerICB)
1506 	{
1507 		int	display, len;
1508 		u_char	*buf;
1509 
1510 		display = window_display;
1511 		window_display = 0;
1512 	   len = 7 + 1 + my_strlen(args) + 1;
1513 		buf = new_malloc(len);
1514 	   snprintf(CP(buf), len-1, "whereis %s", args);
1515 		icb_put_msg2(UP("server"), buf);
1516 		new_free(&buf);
1517 		window_display = display;
1518 		return;
1519 	}
1520 #endif
1521 
1522 	if (args && *args)
1523 		send_to_server("%s %s", command, args);
1524 	else /* Default to yourself  -lynx */
1525      		send_to_server("%s %s", command, get_server_nickname(from_server));
1526 }
1527 
1528 /*
1529  * who: the /WHO command. Parses the who switches and sets the who_mask and
1530  * whoo_stuff accordingly.  Who_mask and who_stuff are used in whoreply() in
1531  * parse.c
1532  */
1533 static	void
who(command,args,subargs)1534 who(command, args, subargs)
1535 	u_char	*command,
1536 		*args,
1537 		*subargs;
1538 {
1539 	u_char	*arg,
1540 		*channel = NULL;
1541 	int	no_args = 1;
1542 	size_t	len;
1543 
1544 #ifdef SUPPORT_ICB
1545 	if (get_server_version(from_server) == ServerICB)
1546 	{
1547 		icb_put_who(args);
1548 		return;
1549 	}
1550 #endif
1551 	who_mask = 0;
1552 	new_free(&who_name);
1553 	new_free(&who_host);
1554 	new_free(&who_server);
1555 	new_free(&who_file);
1556 	new_free(&who_nick);
1557 	new_free(&who_real);
1558 	while ((arg = next_arg(args, &args)) != NULL)
1559 	{
1560 		no_args = 0;
1561 		if ((*arg == '-') && (!isdigit(*(arg + 1))))
1562 		{
1563 			u_char	*cmd = NULL;
1564 
1565 			arg++;
1566 			if ((len = my_strlen(arg)) == 0)
1567 			{
1568 			   usage(command, "[<flags>] [<channel>]");
1569 			   return;
1570 			}
1571 			malloc_strcpy(&cmd, arg);
1572 			lower(cmd);
1573 			if (my_strncmp(cmd, "operators", len) == 0)
1574 				who_mask |= WHO_OPS;
1575 			else if (my_strncmp(cmd, "lusers", len) == 0)
1576 				who_mask |= WHO_LUSERS;
1577 			else if (my_strncmp(cmd, "chops", len) == 0)
1578 				who_mask |= WHO_CHOPS;
1579 			else if (my_strncmp(cmd, "hosts", len) == 0)
1580 			{
1581 				if ((arg = next_arg(args, &args)) != NULL)
1582 				{
1583 					who_mask |= WHO_HOST;
1584 					malloc_strcpy(&who_host, arg);
1585 					channel = who_host;
1586 				}
1587 				else
1588 				{
1589 				   /* say("WHO -HOSTS: missing arguement"); */
1590 				   usage(command, "-host <hostmask> [<channel>]");
1591 					new_free(&cmd);
1592 					return;
1593 				}
1594 			}
1595 			else if (my_strncmp(cmd, "here", len) ==0)
1596 				who_mask |= WHO_HERE;
1597 			else if (my_strncmp(cmd, "away", len) ==0)
1598 				who_mask |= WHO_AWAY;
1599 			else if (my_strncmp(cmd, "servers", len) == 0)
1600 			{
1601 				if ((arg = next_arg(args, &args)) != NULL)
1602 				{
1603 					who_mask |= WHO_SERVER;
1604 					malloc_strcpy(&who_server, arg);
1605 					channel = who_server;
1606 				}
1607 				else
1608 				{
1609 				   /* say("WHO -SERVERS: missing arguement"); */
1610 				   usage(command, "-server <server mask> [<channel>]");
1611 					new_free(&cmd);
1612 					return;
1613 				}
1614 			}
1615 			else if (my_strncmp(cmd, "name", len) == 0
1616 				 || my_strncmp(cmd, "user", len) == 0)
1617 			{
1618 				if ((arg = next_arg(args, &args)) != NULL)
1619 				{
1620 					who_mask |= WHO_NAME;
1621 					malloc_strcpy(&who_name, arg);
1622 					channel = who_name;
1623 				}
1624 				else
1625 				{
1626 				   /* say("WHO -NAME: missing arguement"); */
1627 				   usage(command, "-name <username mask> [<channel>]");
1628 					new_free(&cmd);
1629 					return;
1630 				}
1631 			}
1632 			else if (my_strncmp(cmd, "realname", len) == 0)
1633 			{
1634 				if ((arg = next_arg(args, &args)) != NULL)
1635 				{
1636 					who_mask |= WHO_REAL;
1637 					malloc_strcpy(&who_real, arg);
1638 					channel = who_real;
1639 				}
1640 				else
1641 				{
1642 				   /* say("WHO -REALNAME: missing arguement"); */
1643 				   usage(command, "-realname <real mask> [<channel>]");
1644 					new_free(&cmd);
1645 					return;
1646 				}
1647 			}
1648 			else if (my_strncmp(cmd, "nick", len) == 0)
1649 			{
1650 				if ((arg = next_arg(args, &args)) != NULL)
1651 				{
1652 					who_mask |= WHO_NICK;
1653 					malloc_strcpy(&who_nick, arg);
1654 					channel = who_nick;
1655 				}
1656 				else
1657 				{
1658 				   /* say("WHO -NICK: missing arguement"); */
1659 				   usage(command, "-nick <nick name mask> [<channel>]");
1660 					new_free(&cmd);
1661 					return;
1662 				}
1663 				/* WHO -FILE by Martin 'Efchen' Friedrich */
1664 			}
1665 			else if (my_strncmp(cmd, "file", len) == 0)
1666 			{
1667 				who_mask |= WHO_FILE;
1668 				if ((arg = next_arg(args, &args)) != NULL)
1669 				{
1670 					malloc_strcpy(&who_file, arg);
1671 				}
1672 				else
1673 				{
1674 				   /* say("WHO -FILE: missing arguement"); */
1675 				   usage(command, "-file <mask file> [<channel>]");
1676 					new_free(&cmd);
1677 					return;
1678 				}
1679 			}
1680 			else
1681 			{
1682 			   /* say("Unknown or missing flag"); */
1683 			   usage(command, "[<flags>] [<channel>]");
1684 			   new_free(&cmd);
1685 				return;
1686 			}
1687 			new_free(&cmd);
1688 		}
1689 		else if (my_strcmp(arg, "*") == 0)
1690 		{
1691 			channel = get_channel_by_refnum(0);
1692 			if (!channel || *channel == '0')
1693 
1694 			{
1695 				say("I wouldn't do that if I were you");
1696 				return;
1697 			}
1698 		}
1699 		else
1700 			channel = arg;
1701 	}
1702 	if (no_args)
1703      	{
1704 	   if ((channel = get_channel_by_refnum(0)))
1705 	     {
1706 		send_to_server("%s %s %c", command, channel ? channel :
1707 				empty_string, (who_mask & WHO_OPS) ?
1708 					'o' : '\0');
1709 		return;
1710 	     }
1711 	   /* say("No argument specified"); */
1712 	   usage(command, "[<flags>] [<channel>]");
1713 	}
1714 	else
1715 	{
1716 		if (!channel && who_mask & WHO_OPS)
1717 			channel = UP("*");
1718 		send_to_server("%s %s %c", command, channel ? channel :
1719 				empty_string, (who_mask & WHO_OPS) ?
1720 					'o' : '\0');
1721 	}
1722 }
1723 
1724 /*
1725  * query: the /QUERY command.  Works much like the /MSG, I'll let you figure
1726  * it out.
1727  */
1728 /*ARGSUSED*/
1729 void
query(command,args,subargs)1730 query(command, args, subargs)
1731 	u_char	*command,
1732 		*args,
1733 		*subargs;
1734 {
1735 	u_char	*nick,
1736 		*rest;
1737 
1738    u_char *ntmp = UNULL;
1739 
1740 	save_message_from();
1741 	message_from((u_char *) 0, LOG_CURRENT);
1742 	if ((nick = next_arg(args, &rest)) != NULL)
1743 	{
1744 		if (my_strcmp(nick, ".") == 0)
1745 		{
1746 			if (!(nick = sent_nick))
1747 			{
1748 				say("You have not messaged anyone yet");
1749 				goto out;
1750 			}
1751 		}
1752 		else if (my_strcmp(nick, ",") == 0)
1753 		{
1754 			if (!(nick = recv_nick))
1755 			{
1756 				say("You have not received a message from \
1757 						anyone yet");
1758 				goto out;
1759 			}
1760 		}
1761 		else if (my_strcmp(nick, "*") == 0)
1762 	     	{
1763 
1764 			if (!(nick = get_channel_by_refnum(0)))
1765 			{
1766 				say("You are not on a channel");
1767 				goto out;
1768 			}
1769 		}
1770 
1771 	   /* /query = to first connected dcc chat */
1772 	   else if (my_strcmp(nick, "=") == 0)
1773 	     {
1774 		DCC_list *Client = dcc_searchlist("chat", NULL, DCC_CHAT, 0, NULL, 0);
1775 
1776 		if (Client)
1777 		  {
1778 		     ntmp = dma_Malloc(my_strlen(Client->user) + 2);
1779 		     if (ntmp)
1780 		       {
1781 			  *ntmp++ = '=';
1782 			  my_strcpy(ntmp, Client->user); /* safe */
1783 			  nick = ntmp;
1784 		       }
1785 		  }
1786 	     }
1787 
1788 
1789 #ifndef _Windows
1790 		if (*nick == '%')
1791 		{
1792 			if (is_process(nick) == 0)
1793 			{
1794 				say("Invalid processes specification");
1795 				goto out;
1796 			}
1797 		}
1798 #endif /* _Windows */
1799 
1800 
1801 		say("Starting conversation with %s", nick);
1802 		set_query_nick(nick);
1803 	   	dma_Free(&ntmp);
1804 	}
1805 	else
1806 	{
1807 		if (query_nick())
1808 		{
1809 			say("Ending conversation with %s", query_nick());
1810 			set_query_nick(NULL);
1811 		}
1812 		else
1813 			say("You aren't querying anyone!");
1814 	}
1815 	update_input(UPDATE_ALL);
1816 out:
1817 	restore_message_from();
1818 }
1819 
1820 /*
1821  *
1822  * NINJA IRC HAS ITS OWN /AWAY
1823  *
1824  * away: the /AWAY command.  Keeps track of the away message locally, and
1825  * sends the command on to the server.
1826  *
1827 static	void
1828 away(command, args, subargs)
1829 	u_char	*command,
1830 		*args,
1831 		*subargs;
1832 {
1833 	size_t	len;
1834 	u_char	*arg = NULL;
1835 	int	flag = AWAY_ONE;
1836 	int	i;
1837 
1838 	if (*args)
1839 	{
1840 		if (*args == '-')
1841 		{
1842 			u_char	*cmd = (u_char *) 0;
1843 
1844 			args = next_arg(args, &arg);
1845 			len = my_strlen(args);
1846 			if (len == 0)
1847 			{
1848 				say("%s: No argument given with -", command);
1849 				return;
1850 			}
1851 			malloc_strcpy(&cmd, args);
1852 			upper(cmd);
1853 			if (0 == my_strncmp(cmd, "-ALL", len))
1854 			{
1855 				flag = AWAY_ALL;
1856 				args = arg;
1857 			}
1858 			else if (0 == my_strncmp(cmd, "-ONE", len))
1859 			{
1860 				flag = AWAY_ONE;
1861 				args = arg;
1862 			}
1863 			else
1864 			{
1865 				say("%s: %s unknown flag", command, args);
1866 				new_free(&cmd);
1867 				return;
1868 			}
1869 			new_free(&cmd);
1870 		}
1871 	}
1872 	if (flag == AWAY_ALL)
1873 		if (*args)
1874 		{
1875 			away_set = 1;
1876 			MarkAllAway(command, args);
1877 		}
1878 		else
1879 		{
1880 			away_set = 0;
1881 			for(i = 0; (i < number_of_servers); i++)
1882 				if (server_list[i].whois_stuff.away)
1883 					new_free(&(server_list[i].away));
1884 		}
1885 	else
1886 	{
1887 		send_to_server("%s :%s", command, args);
1888 		if (*args)
1889 		{
1890 			away_set = 1;
1891 			malloc_strcpy(&(server_list[
1892 				curr_scr_win->server].away), args);
1893 		}
1894 		else
1895 		{
1896 			new_free(&(server_list[
1897 				curr_scr_win->server].away));
1898 			away_set = 0;
1899 			for(i = 0; (i < number_of_servers) && !away_set ; i++)
1900 				if (server_list[i].read != -1 &&
1901 						server_list[i].away)
1902 					away_set = 1;
1903 		}
1904 	}
1905 	update_all_status();
1906 }
1907  *
1908  */
1909 
1910 /* e_quit: The /QUIT, /EXIT, etc command */
1911 /*ARGSUSED*/
1912 void
e_quit(command,args,subargs)1913 e_quit(command, args, subargs)
1914 	u_char	*command,
1915 		*args,
1916 		*subargs;
1917 {
1918 	int	max;
1919 	int	i;
1920 	u_char	Reason[512];
1921 
1922    if (args && *args)
1923      my_strncpy(Reason, args, sizeof(Reason)-1);
1924    else
1925      snprintf(Reason, sizeof(Reason)-1, "Ninja IRC v%s(#%s) exiting after %s of use",
1926 	      irc_version, compile_num,
1927 	      ninja_etime(time(NULL)-start_time));
1928    Reason[sizeof(Reason)-1] = '\0';
1929 
1930    /* Reason = ((args && *args) ? args : (u_char *) "Leaving"); */
1931 	max = number_of_servers;
1932 	for (i = 0; i < max; i++)
1933 		if (is_server_connected(i))
1934 		{
1935 			from_server = i;
1936 #ifdef SUPPORT_ICB
1937 			if (get_server_version(i) != ServerICB)
1938 #endif
1939 				send_to_server("QUIT :%s", Reason);
1940 		}
1941 	irc_exit(Reason);
1942 }
1943 
1944 /* flush: flushes all pending stuff coming from the server */
1945 /*ARGSUSED*/
1946 static	void
flush(command,args,subargs)1947 flush(command, args, subargs)
1948 	u_char	*command,
1949 		*args,
1950 		*subargs;
1951 {
1952 	if (get_int_var(HOLD_MODE_VAR))
1953 	{
1954 		while (curr_scr_win->held_lines)
1955 			remove_from_hold_list(curr_scr_win);
1956 		hold_mode((Window *) 0, OFF, 1);
1957 	}
1958 	say("Standby, Flushing server output...");
1959 	flush_server();
1960 	say("Done");
1961 }
1962 
1963 /* e_wall: used for WALL and WALLOPS */
1964 static	void
e_wall(command,args,subargs)1965 e_wall(command, args, subargs)
1966 	u_char	*command,
1967 		*args,
1968 		*subargs;
1969 {
1970 	save_message_from();
1971 	if (my_strcmp(command, "WALL") == 0)
1972 	{	/* I hate this */
1973 		message_from(NULL, LOG_WALL);
1974 		if (!get_server_operator(from_server))
1975 			put_it("## %s", args);
1976 	}
1977 	else
1978 	{
1979 		message_from(NULL, LOG_WALLOP);
1980 		if (!get_server_flag(from_server, USER_MODE_W))
1981 			put_it("!! %s", args);
1982 	}
1983 	if (!in_on_who)
1984 		send_to_server("%s :%s", command, args);
1985 	restore_message_from();
1986 }
1987 
1988 void
redirect_msg(dest,msg)1989 redirect_msg(dest, msg)
1990 	u_char *dest;
1991 	u_char *msg;
1992 {
1993 	u_char	buffer[BIG_BUFFER_SIZE];
1994 
1995 	my_strcpy(buffer, dest);
1996 	my_strcat(buffer, " ");
1997    if (get_int_var(STRIP_REDIRECT_ANSI_VAR))
1998      my_strcat(buffer, strip_ansi(msg));
1999    else
2000 	my_strcat(buffer, msg);
2001 	e_privmsg("PRIVMSG", buffer, NULL);
2002 }
2003 
2004 /*
2005  * e_privmsg: The MSG command, displaying a message on the screen indicating
2006  * the message was sent.  Also, this works for the NOTICE command.
2007  */
2008 static	void
e_privmsg(command,args,subargs)2009 e_privmsg(command, args, subargs)
2010 	u_char	*command,
2011 		*args,
2012 		*subargs;
2013 {
2014 	u_char	*nick;
2015 
2016 	if ((nick = next_arg(args, &args)) != NULL)
2017 	{
2018 		if (my_strcmp(nick, ".") == 0)
2019 		{
2020 			if (!(nick = sent_nick))
2021 			{
2022 				say("You have not sent a message to anyone yet");
2023 				return;
2024 			}
2025 		}
2026 
2027 		else if (my_strcmp(nick, ",") == 0)
2028 		{
2029 			if (!(nick = recv_nick))
2030 			{
2031 				say("You have not received a message from anyone yet");
2032 				return;
2033 			}
2034 		}
2035 		else if (!my_strcmp(nick, "*"))
2036 			if (!(nick = get_channel_by_refnum(0)))
2037 				nick = zero;
2038 		send_text(nick, args, command);
2039 	}
2040 	else
2041      /* say("You must specify a nickname or channel!"); */
2042      usage(command, "<nick/channel> <message>");
2043 }
2044 
2045 /*
2046  * quote: handles the QUOTE command.  args are a direct server command which
2047  * is simply send directly to the server
2048  */
2049 /*ARGSUSED*/
2050 static	void
quote(command,args,subargs)2051 quote(command, args, subargs)
2052 	u_char	*command,
2053 		*args,
2054 		*subargs;
2055 {
2056 	if (!in_on_who)
2057 		send_to_server("%s", args);
2058 }
2059 
2060 /* clear: the CLEAR command.  Figure it out */
2061 /*ARGSUSED*/
2062 static	void
my_clear(command,args,subargs)2063 my_clear(command, args, subargs)
2064 	u_char	*command,
2065 		*args,
2066 		*subargs;
2067 {
2068 	u_char	*arg;
2069 	int	all = 0,
2070 		unhold = 0;
2071 
2072 	while ((arg = next_arg(args, &args)) != NULL)
2073 	{
2074 		upper(arg);
2075 		/* -ALL and ALL here becuase the help files used to be wrong */
2076 		if (!my_strncmp(arg, "ALL", my_strlen(arg))
2077 				|| !my_strncmp(arg, "-ALL", my_strlen(arg)))
2078 			all = 1;
2079 		else if (!my_strncmp(arg, "-UNHOLD", my_strlen(arg)))
2080 			unhold = 1;
2081 		else
2082 			/* say("Unknown flag: %s", arg); */
2083 	     		usage("clear", "[-ALL] [-UNHOLD]");
2084 	}
2085 	if (all)
2086 		clear_all_windows(unhold);
2087 	else
2088 	{
2089 		if (unhold)
2090 			hold_mode((Window *) 0, OFF, 1);
2091 		clear_window_by_refnum(0);
2092 	}
2093 	update_input(UPDATE_JUST_CURSOR);
2094 }
2095 
2096 /*
2097  * send_comm: the generic command function.  Uses the full command name found
2098  * in 'command', combines it with the 'args', and sends it to the server
2099  */
2100 static	void
send_comm(command,args,subargs)2101 send_comm(command, args, subargs)
2102 	u_char	*command,
2103 		*args,
2104 		*subargs;
2105 {
2106 	if (args && *args)
2107 		send_to_server("%s %s", command, args);
2108 	else
2109 		send_to_server("%s", command);
2110 }
2111 
2112 static	void
send_invite(command,args,subargs)2113 send_invite(command, args, subargs)
2114 	u_char	*command,
2115 		*args,
2116 		*subargs;
2117 {
2118    u_char *chan, *nick;
2119 
2120 #ifdef SUPPORT_ICB
2121 	if (get_server_version(from_server) == ServerICB)
2122      	{
2123 		icb_put_invite(args);
2124 	   	return;
2125 	}
2126 #endif
2127 
2128    nick = next_arg(args, &args);
2129    if (!nick)
2130      {
2131 	usage(command, "<nick> [<channel>]");
2132 	return;
2133      }
2134    chan = next_arg(args, &args);
2135    if (!chan)
2136      chan = get_channel_by_refnum(0);
2137    if (!chan)
2138      {
2139 	put_error("%s: No target", command);
2140 	return;
2141      }
2142    send_to_server("%s %s %s", command, nick, chan);
2143 }
2144 
2145 static	void
send_motd(command,args,subargs)2146 send_motd(command, args, subargs)
2147 	u_char	*command,
2148 		*args,
2149 		*subargs;
2150 {
2151 
2152 #ifdef SUPPORT_ICB
2153 	if (get_server_version(from_server) == ServerICB)
2154 		icb_put_motd(args);
2155 	else
2156 #endif
2157 		send_comm(command, args, subargs);
2158 }
2159 
2160 static	void
send_topic(command,args,subargs)2161 send_topic(command, args, subargs)
2162 	u_char	*command,
2163 		*args,
2164 		*subargs;
2165 {
2166 	u_char	*arg;
2167 	u_char	*arg2;
2168 
2169 #ifdef SUPPORT_ICB
2170 	if (get_server_version(from_server) == ServerICB)
2171 	{
2172 		icb_put_topic(args);
2173 		return;
2174 	}
2175 #endif
2176 	if (!(arg = next_arg(args, &args)) || (my_strcmp(arg, "*") == 0))
2177 		arg = get_channel_by_refnum(0);
2178 
2179 	if (!arg)
2180 	{
2181 	   usage("topic", "[<channel>] [- or <new topic>]");
2182 	   return;
2183 	}
2184 	if (is_channel(arg))
2185 	{
2186 		if ((arg2 = next_arg(args, &args)) != NULL)
2187 	        {
2188 		   if (my_strcmp(arg2, "-") == 0)
2189 		     {
2190 			send_to_server("%s %s :", command, arg);
2191 			return;
2192 		     }
2193 		   send_to_server("%s %s :%s %s", command, arg,
2194 				  arg2, args);
2195 		}
2196 		else
2197 			send_to_server("%s %s", command, arg);
2198 	}
2199 	else
2200      	{
2201 	   arg2 = arg;
2202 	   if ((arg = get_channel_by_refnum(0)))
2203 	     {
2204 		if (my_strcmp(arg2, "-") == 0)
2205 		  {
2206 		     send_to_server("%s %s :", command, arg);
2207 		     return;
2208 		  }
2209 		send_to_server("%s %s :%s", command, arg, subargs);
2210 	     }
2211 	   else
2212 	     say("You aren't on a channel in this window");
2213 	}
2214 }
2215 
2216 
2217 static void
send_squery(command,args,subargs)2218 send_squery(command, args, subargs)
2219 	u_char	*command,
2220 		*args,
2221 		*subargs;
2222 {
2223 	put_it("*** Sent to service %s: %s", command, args);
2224 	send_2comm(command, args, subargs);
2225 }
2226 
2227 static void
send_brick(command,args,subargs)2228 send_brick(command, args, subargs)
2229 	u_char	*command,
2230 		*args,
2231 		*subargs;
2232 {
2233 
2234 	if (args && *args)
2235 	{
2236 		u_char	*channel;
2237 
2238 		channel = next_arg(args, &args);
2239 		send_to_server("%s %s :%s", command, channel, args);
2240 	}
2241 	else
2242 		send_to_server("%s", command);
2243 }
2244 
2245 /*
2246  * send_2comm: Sends a command to the server with one arg and
2247  * one comment. Used for KILL and SQUIT.
2248  */
2249 static	void
send_2comm(command,args,subargs)2250 send_2comm(command, args, subargs)
2251 	u_char	*command,
2252 		*args,
2253 		*subargs;
2254 {
2255 	u_char	*comment;
2256 
2257 	args = next_arg(args, &comment);
2258 
2259 	send_to_server("%s %s %c%s",
2260 		       command,
2261 		       args && *args ? args : (u_char *) "",
2262 		       comment && *comment ? ':' : ' ',
2263 		       comment && *comment ? comment : (u_char *) "");
2264 }
2265 
2266 /*
2267  * send_channel_nargs: Sends a command to the server with one channel,
2268  * and 0-n args. Used for MODE.
2269  */
2270 
2271 static	void
send_channel_nargs(command,args,subargs)2272 send_channel_nargs(command, args, subargs)
2273 	u_char	*command,
2274 		*args,
2275 		*subargs;
2276 {
2277 	u_char	*arg1 = 0,
2278 	        *s = get_channel_by_refnum(0);
2279 
2280 	args = next_arg(args, &arg1);
2281 	if (!args || !my_strcmp(args, "*"))
2282 	{
2283 		if (s)
2284 			args = s;
2285 		else
2286 		{
2287 			say("You aren't on a channel in this window");
2288 			return;
2289 		}
2290 	}
2291 
2292 	send_to_server("%s %s %s",
2293 		       command,
2294 		       args,
2295 		       arg1 && *arg1 ? arg1 : (u_char *) "");
2296 }
2297 
2298 /*
2299  * this will remain commented out until it is used... -jjd
2300  *
2301  * send_channel_2args: Sends a command to the server with one channel,
2302  * one arg and one comment. Used for KICK
2303  *
2304  *
2305 static	void
2306 send_channel_2args(command, args, subargs)
2307 	u_char	*command,
2308 		*args,
2309 		*subargs;
2310 {
2311 	u_char	*arg1 = 0,
2312 		*comment = 0,
2313 	        *s = get_channel_by_refnum(0);
2314 
2315 	args = next_arg(args, &arg1);
2316 	if (!args || !my_strcmp(args, "*"))
2317 	{
2318 		if (s)
2319 			args = s;
2320 		else
2321 		{
2322 			say("You aren't on a channel in this window");
2323 			return;
2324 		}
2325 	}
2326 
2327 	if (arg1 && *arg1)
2328 		arg1 = next_arg(arg1, &comment);
2329 
2330 	send_to_server("%s %s %s %c%s",
2331 		       command,
2332 		       args,
2333 		       arg1 && *arg1 ? arg1 : (u_char *) "",
2334 		       comment && *comment ? ':' : ' ',
2335 		       comment && *comment ? comment : (u_char *) "");
2336 }
2337  *
2338  */
2339 
2340 /*
2341  * send_channel_1arg: Sends a command to the server with one channel
2342  * and one comment. Used for PART (LEAVE)
2343  */
2344 static	void
send_channel_1arg(command,args,subargs)2345 send_channel_1arg(command, args, subargs)
2346 	u_char	*command,
2347 		*args,
2348 		*subargs;
2349 {
2350 	u_char	*comment, *tch,
2351 		*s = get_channel_by_refnum(0);
2352 
2353 	args = next_arg(args, &comment);
2354 
2355 	if (!args || !my_strcmp(args, "*"))
2356 	{
2357 		if (s)
2358 			args = s;
2359 		else
2360 		{
2361 			say("You aren't on a channel in this window");
2362 			return;
2363 		}
2364 	}
2365 
2366    if (!is_channel(args))
2367      tch = make_chan(args);
2368    else
2369      tch = args;
2370 
2371 	send_to_server("%s %s %c%s",
2372 		       command,
2373 		       tch,
2374 		       comment && *comment ? ':' : ' ',
2375 		       comment && *comment ? comment : (u_char *) "");
2376 }
2377 
2378 /*
2379  * send_text: Sends the line of text to whomever the user is currently
2380  * talking.  If they are quering someone, it goes to that user, otherwise
2381  * it's the current channel.  Some tricky parameter business going on. If
2382  * nick is null (as if you had typed "/ testing" on the command line) the
2383  * line is sent to your channel, and the command parameter is never used. If
2384  * nick is not null, and command is null, the line is sent as a PRIVMSG.  If
2385  * nick is not null and command is not null, the message is sent using
2386  * command.  Currently, only NOTICEs and PRIVMSGS work.
2387  * fixed to not be anal about "/msg foo,bar foobar" -phone
2388  */
2389 void
send_text(org_nick,line,command)2390 send_text(org_nick, line, command)
2391 	u_char	*org_nick;
2392 	u_char	*line;
2393 	u_char	*command;
2394 {
2395 	crypt_key	*key;
2396 	u_char 	*ptr,
2397 		*free_nick,
2398 		*nick = NULL;
2399 	int	lastlog_level,
2400 		list_type,
2401 		old_server;
2402 	int	check_away = 0;
2403 	u_char	the_thing = '?';
2404 	u_char	*query_command = NULL;
2405 	u_char	nick_list[IRCD_BUFFER_SIZE];
2406 	int	do_final_send = 0;
2407 
2408 	if (dumb && translation)
2409 	{
2410 		ptr = line;
2411 		while (*ptr)
2412 		{
2413 			*ptr = transFromClient[*(u_char*) ptr];
2414 			ptr++;
2415 		}
2416 	}
2417 
2418 	*nick_list = '\0';
2419 	malloc_strcpy(&nick, org_nick);
2420 	free_nick = ptr = nick;
2421 	save_message_from();
2422 	while ((nick = ptr) != NULL)
2423 	{
2424 		if ((ptr = my_index(nick, ',')) != NULL)
2425 			*(ptr++) = (u_char) 0;
2426 		if (!*nick)
2427 			continue;
2428 #ifndef _Windows
2429 		if (is_process(nick))
2430 		{
2431 			int	i;
2432 
2433 			if ((i = get_process_index(&nick)) == -1)
2434 				say("Invalid process specification");
2435 			else
2436 				text_to_process(i, line, 1);
2437 			continue;
2438 		}
2439 #endif /* _Windows */
2440 		if (!*line)
2441 			continue; /* lynx */
2442 		if (in_on_who && *nick != '=') /* allow dcc messages anyway */
2443 		{
2444 			say("You may not send messages from ON WHO, ON WHOIS, or ON JOIN");
2445 			continue;
2446 		}
2447 		if (doing_privmsg)
2448 			command	= UP("NOTICE");
2449 		if (is_current_channel(nick, curr_scr_win->server, 0))
2450 		{
2451 			/* nothing */
2452 		}
2453 		/* Query quote -lynx */
2454 		if (my_strcmp(nick, "\"") == 0) /* quote */
2455 		{
2456 			send_to_server("%s", line);
2457 			continue;
2458 		}
2459 		else if (*nick == '=') /* DCC chat */
2460 		{
2461 			old_server = from_server;
2462 			from_server = -1;
2463 			dcc_chat_transmit(nick + 1, line);
2464 			from_server = old_server;
2465 			continue;
2466 		}
2467 		else if (*nick == '@') /* DCC talk */
2468 		{
2469 			old_server = from_server;
2470 			from_server = -1;
2471 			dcc_message_transmit(nick + 1, line, DCC_TALK, 1);
2472 			from_server = old_server;
2473 			continue;
2474 		}
2475 		else if (*nick == '/') /* Command */
2476 		{
2477 			malloc_strcpy(&query_command, nick);
2478 			malloc_strcat(&query_command, UP(" "));
2479 			malloc_strcat(&query_command, line);
2480 			parse_command(query_command, 0, empty_string);
2481 			new_free(&query_command);
2482 			continue;
2483 		}
2484 		switch (send_text_flag)
2485 		{
2486 		case MSG_LIST:
2487 			command = UP("NOTICE");
2488 			break;
2489 		case NOTICE_LIST:
2490 			say("You cannot send a message from a NOTICE");
2491 			new_free(&free_nick);
2492 			goto out;
2493 		}
2494 #ifdef SUPPORT_ICB
2495 		if (get_server_version(from_server) == ServerICB)
2496 		{
2497 			if (my_stricmp(nick, get_server_icbgroup(from_server)) != 0)
2498 				icb_put_msg2(nick, line);
2499 			else
2500 				icb_put_public(line);
2501 		}
2502 		else
2503 #endif
2504 		if (is_channel(nick))
2505 		{
2506 			int	current;
2507 
2508 			current = is_current_channel(nick, curr_scr_win->server, 0);
2509 			if (!command || my_strcmp(command, "NOTICE"))
2510 			{
2511 				check_away = 1;
2512 				command = UP("PRIVMSG");
2513 				lastlog_level = set_lastlog_msg_level(LOG_PUBLIC);
2514 				message_from(nick, LOG_PUBLIC);
2515 				list_type = SEND_PUBLIC_LIST;
2516 				the_thing = '>';
2517 			}
2518 			else
2519 			{
2520 				lastlog_level = set_lastlog_msg_level(LOG_NOTICE);
2521 				message_from(nick, LOG_NOTICE);
2522 				list_type = SEND_NOTICE_LIST;
2523 				the_thing = '-';
2524 			}
2525 			if (do_hook(list_type, "%s %s", nick, line))
2526 			{
2527 			   if (current)
2528 			     {
2529 				put_it("%c %s", the_thing, line);
2530 				if (server_list[curr_scr_win->server].away_set)
2531 				  add_to_awaylog("%c %s", the_thing, line);
2532 			     }
2533 			   else
2534 			     {
2535 				put_it("%c%s> %s", the_thing, nick, line);
2536 				if (server_list[curr_scr_win->server].away_set)
2537 				     add_to_awaylog("%c%s> %s", the_thing, nick, line);
2538 			     }
2539 			}
2540 			set_lastlog_msg_level(lastlog_level);
2541 			if ((key = is_crypted(nick)) != 0)
2542 			{
2543 				u_char	*crypt_line;
2544 
2545 				if ((crypt_line = crypt_msg(line, key, 1)))
2546 					send_to_server("%s %s :%s", command, nick, crypt_line);
2547 				continue;
2548 			}
2549 			if (!in_on_who)
2550 			{
2551 				if (*nick_list)
2552 				{
2553 					my_strcat(nick_list, ",");
2554 					my_strcat(nick_list, nick);
2555 				}
2556 				else
2557 					my_strcpy(nick_list, nick);
2558 			}
2559 			do_final_send = 1;
2560 		}
2561 		else
2562 		{
2563 			if (!command || my_strcmp(command, "NOTICE"))
2564 			{
2565 				check_away = 1;
2566 				lastlog_level = set_lastlog_msg_level(LOG_MSG);
2567 				command = UP("PRIVMSG");
2568 				message_from(nick, LOG_MSG);
2569 				list_type = SEND_MSG_LIST;
2570 				the_thing = '*';
2571 			   add_tab_key(0, "msg ", nick);
2572 			}
2573 			else
2574 			{
2575 				lastlog_level = set_lastlog_msg_level(LOG_NOTICE);
2576 				message_from(nick, LOG_NOTICE);
2577 				list_type = SEND_NOTICE_LIST;
2578 				the_thing = '-';
2579 			   add_tab_key(0, "notice ", nick);
2580 			}
2581 			if (window_display && do_hook(list_type, "%s %s", nick, line))
2582 				put_it("-> %c%s%c %s", the_thing, nick, the_thing, line);
2583 			if ((key = is_crypted(nick)) != NULL)
2584 			{
2585 				u_char	*crypt_line;
2586 
2587 				if ((crypt_line = crypt_msg(line, key, 1)))
2588 					send_to_server("%s %s :%s", command ? command : (u_char *) "PRIVMSG", nick, crypt_line);
2589 				continue;
2590 			}
2591 		   if (server_list[curr_scr_win->server].away_set)
2592 		     add_to_awaylog("-> %c%s%c %s", the_thing, nick, the_thing, line);
2593 
2594 			set_lastlog_msg_level(lastlog_level);
2595 
2596 			if (!in_on_who)
2597 			{
2598 				if (*nick_list)
2599 				{
2600 					my_strcat(nick_list, ",");
2601 					my_strcat(nick_list, nick);
2602 				}
2603 				else
2604 					my_strcpy(nick_list, nick);
2605 			}
2606 
2607 			if (get_int_var(WARN_OF_IGNORES_VAR) && (is_ignored(nick, IGNORE_MSGS) == IGNORED))
2608 				say("Warning: You are ignoring private messages from %s", nick);
2609 
2610 			malloc_strcpy(&sent_nick, nick);
2611 			do_final_send = 1;
2612 		}
2613 	}
2614 	if (check_away
2615 	    && server_list[curr_scr_win->server].away_set
2616 	    && get_int_var(AUTO_UNMARK_AWAY_VAR)
2617 #ifdef SUPPORT_ICB
2618 	    && get_server_version(from_server) != ServerICB
2619 #endif
2620 	    )
2621 		back(UP("back"), empty_string, empty_string);
2622 
2623 	malloc_strcpy(&sent_body, line);
2624 	if (do_final_send)
2625 		send_to_server("%s %s :%s", command ? command : (u_char *) "PRIVMSG", nick_list, line);
2626 	new_free(&free_nick);
2627 
2628    if (the_thing == '*')
2629      addredirect(REDIRECT_SENT_MSG, "-> %c%s%c %s", the_thing, nick_list, the_thing, line);
2630    else if (the_thing == '-')
2631      addredirect(REDIRECT_SENT_NOTICE, "-> %c%s%c %s", the_thing, nick_list, the_thing, line);
2632 
2633 out:
2634 	restore_message_from();
2635 }
2636 
2637 static void
do_send_text(command,args,subargs)2638 do_send_text(command, args, subargs)
2639 	u_char	*command,
2640 		*args,
2641 		*subargs;
2642 {
2643 	u_char	*tmp;
2644 
2645 	if (command)
2646 		tmp = get_channel_by_refnum(0);
2647 	else
2648 		tmp = get_target_by_refnum(0);
2649 	send_text(tmp, args, NULL);
2650 }
2651 
2652 /*
2653  * command_completion: builds lists of commands and aliases that match the
2654  * given command and displays them for the user's lookseeing
2655  */
2656 void
command_completion(key,ptr)2657 command_completion(key, ptr)
2658 	u_int	key;
2659 	u_char	*ptr;
2660 {
2661 	int	do_aliases;
2662 	int	cmd_cnt,
2663 		alias_cnt,
2664 		i,
2665 		c,
2666 		len;
2667 	u_char	**aliases = NULL;
2668 	u_char	*line = NULL,
2669 		*com,
2670 		*cmdchars,
2671 		*rest,
2672 		firstcmdchar = '/';
2673 	u_char	buffer[BIG_BUFFER_SIZE];
2674 	IrcCommand	*command;
2675 
2676 	malloc_strcpy(&line, get_input());
2677 	if ((com = next_arg(line, &rest)) != NULL)
2678 	{
2679 		if (!(cmdchars = get_string_var(CMDCHARS_VAR)))
2680 			cmdchars = UP(DEFAULT_CMDCHARS);
2681 		if (my_index(cmdchars, *com))
2682 		{
2683 			firstcmdchar = *cmdchars;
2684 			com++;
2685 			if (*com && my_index(cmdchars, *com))
2686 			{
2687 				do_aliases = 0;
2688 				alias_cnt = 0;
2689 				com++;
2690 			}
2691 			else
2692 				do_aliases = 1;
2693 			upper(com);
2694 			if (do_aliases)
2695 				aliases = match_alias(com, &alias_cnt,
2696 					COMMAND_ALIAS);
2697 			if ((command = find_command(com, &cmd_cnt)) != NULL)
2698 			{
2699 				if (cmd_cnt < 0)
2700 					cmd_cnt *= -1;
2701 				/* special case for the empty string */
2702 
2703 				if (*(command[0].name) == (u_char) 0)
2704 				{
2705 					command++;
2706 					cmd_cnt = NUMBER_OF_COMMANDS;
2707 				}
2708 			}
2709 		   	memset(buffer, 0, sizeof(buffer));
2710 			if ((alias_cnt == 1) && (cmd_cnt == 0))
2711 			{
2712 				snprintf(CP(buffer), sizeof(buffer)-1, "%c%s %s", firstcmdchar,
2713 					aliases[0], rest);
2714 				set_input(buffer);
2715 				new_free(&(aliases[0]));
2716 				new_free(&aliases);
2717 				update_input(UPDATE_ALL);
2718 			}
2719 			else if (((cmd_cnt == 1) && (alias_cnt == 0)) ||
2720 			    ((cmd_cnt == 1) && (alias_cnt == 1) &&
2721 			    (my_strcmp(aliases[0], command[0].name) == 0)))
2722 			{
2723 				snprintf(CP(buffer), sizeof(buffer)-1, "%c%s%s %s", firstcmdchar,
2724 					do_aliases ? (u_char *) "" : &firstcmdchar,
2725 					command[0].name, rest);
2726 				set_input(buffer);
2727 				update_input(UPDATE_ALL);
2728 			}
2729 			else
2730 			{
2731 				*buffer = (u_char) 0;
2732 				if (command)
2733 				{
2734 					say("Commands:");
2735 					my_strmcpy(buffer, "\t", sizeof(buffer)-1);
2736 					c = 0;
2737 					for (i = 0; i < cmd_cnt; i++)
2738 					{
2739 						my_strmcat(buffer, command[i].name,
2740 							sizeof(buffer)-1);
2741 						for (len =
2742 						    my_strlen(command[i].name);
2743 						    len < 15; len++)
2744 							my_strmcat(buffer, " ",
2745 							    sizeof(buffer)-1);
2746 						if (++c == 4)
2747 						{
2748 							say("%s", buffer);
2749 							my_strmcpy(buffer, "\t",
2750 							    sizeof(buffer)-1);
2751 							c = 0;
2752 						}
2753 					}
2754 					if (c)
2755 						say("%s", buffer);
2756 				}
2757 				if (aliases)
2758 				{
2759 					say("Aliases:");
2760 					my_strmcpy(buffer, "\t", sizeof(buffer)-1);
2761 					c = 0;
2762 					for (i = 0; i < alias_cnt; i++)
2763 					{
2764 						my_strmcat(buffer, aliases[i],
2765 							sizeof(buffer)-1);
2766 						for (len = my_strlen(aliases[i]);
2767 								len < 15; len++)
2768 							my_strmcat(buffer, " ",
2769 							    sizeof(buffer)-1);
2770 						if (++c == 4)
2771 						{
2772 							say("%s", buffer);
2773 							my_strmcpy(buffer, "\t",
2774 							    sizeof(buffer)-1);
2775 							c = 0;
2776 						}
2777 						new_free(&(aliases[i]));
2778 					}
2779 					if ((int) my_strlen(buffer) > 1)
2780 						say("%s", buffer);
2781 					new_free(&aliases);
2782 				}
2783 				if (!*buffer)
2784 					term_beep();
2785 			}
2786 		}
2787 		else
2788 			term_beep();
2789 	}
2790 	else
2791 		term_beep();
2792 	new_free(&line);
2793 }
2794 
2795 /*
2796  * parse_line: This is the main parsing routine.  It should be called in
2797  * almost all circumstances over parse_command().
2798  *
2799  * parse_line breaks up the line into commands separated by unescaped
2800  * semicolons if we are in non interactive mode. Otherwise it tries to leave
2801  * the line untouched.
2802  *
2803  * Currently, a carriage return or newline breaks the line into multiple
2804  * commands too. This is expected to stop at some point when parse_command
2805  * will check for such things and escape them using the ^P convention.
2806  * We'll also try to check before we get to this stage and escape them before
2807  * they become a problem.
2808  *
2809  * Other than these two conventions the line is left basically untouched.
2810  */
2811 void
parse_line(name,org_line,args,hist_flag,append_flag,eat_space)2812 parse_line(name, org_line, args, hist_flag, append_flag, eat_space)
2813 	u_char	*name,
2814 		*org_line,
2815 		*args;
2816 	int	hist_flag,
2817 		append_flag,
2818   		eat_space;
2819 {
2820 	u_char	*line = NULL,
2821 		*free_line, *stuff, *start, *lbuf, *s, *t;
2822 	int	args_flag;
2823 
2824 	malloc_strcpy(&line, org_line);
2825 	free_line = line;
2826 	args_flag = 0;
2827 	if (!*line)
2828 		do_send_text(NULL, empty_string, empty_string);
2829 	else if (args)
2830 		do
2831 		{
2832 			stuff = expand_alias(name, line, args, &args_flag,
2833 					&line);
2834 			start = stuff;
2835 			if (eat_space)
2836 				for (; isspace(*start); start++)
2837 					;
2838 
2839 			if (!line && append_flag && !args_flag && args && *args)
2840 			{
2841 				lbuf = (u_char *) new_malloc(my_strlen(stuff) + 1 + my_strlen(args) + 1);
2842 				my_strcpy(lbuf, start);
2843 				my_strcat(lbuf, " ");
2844 				my_strcat(lbuf, args);
2845 				new_free(&stuff);
2846 				start = stuff = lbuf;
2847 			}
2848 			parse_command(start, hist_flag, args);
2849 			new_free(&stuff);
2850 		}
2851 		while (line);
2852 	else
2853 	{
2854 		start = line;
2855 		if (eat_space)
2856 			for (; isspace(*start); start++)
2857 				;
2858 		if (load_depth)
2859 			parse_command(start, hist_flag, args);
2860 		else
2861 			while ((s = line))
2862 			{
2863 				if ((t = sindex(line, UP("\r\n"))) != NULL)
2864 				{
2865 					*t++ = '\0';
2866 					if (eat_space)
2867 						for (; isspace(*t); t++)
2868 							;
2869 					line = t;
2870 				}
2871 				else
2872 					line = NULL;
2873 				parse_command(s, hist_flag, args);
2874 			}
2875 	}
2876 	new_free(&free_line);
2877 	return;
2878 }
2879 
2880 /*
2881  * parse_command: parses a line of input from the user.  If the first
2882  * character of the line is equal to irc_variable[CMDCHAR_VAR].value, the
2883  * line is used as an irc command and parsed appropriately.  If the first
2884  * character is anything else, the line is sent to the current channel or to
2885  * the current query user.  If hist_flag is true, commands will be added to
2886  * the command history as appropriate.  Otherwise, parsed commands will not
2887  * be added.
2888  *
2889  * Parse_command() only parses a single command.  In general, you will want
2890  * to use parse_line() to execute things.Parse command recognized no quoted
2891  * characters or anything (beyond those specific for a given command being
2892  * executed).
2893  */
2894 void
parse_command(line,hist_flag,sub_args)2895 parse_command(line, hist_flag, sub_args)
2896 	u_char	*line;
2897 	int	hist_flag;
2898 	u_char	*sub_args;
2899 {
2900 	static	unsigned int	 level = 0;
2901 	unsigned int	display,
2902 			old_display_var;
2903 	u_char	*cmdchars,
2904 		*com,
2905 		*this_cmd = NULL;
2906 	int	args_flag,
2907 		add_to_hist,
2908 		cmdchar_used;
2909 
2910 	if (!line || !*line)
2911 		return;
2912 	if (get_int_var(DEBUG_VAR) & DEBUG_COMMANDS)
2913 		yell("Executing [%d] %s", level, line);
2914 	level++;
2915 	if (!(cmdchars = get_string_var(CMDCHARS_VAR)))
2916 		cmdchars = UP(DEFAULT_CMDCHARS);
2917 	malloc_strcpy(&this_cmd, line);
2918 	add_to_hist = 1;
2919 	if (my_index(cmdchars, *line))
2920 	{
2921 		cmdchar_used = 1;
2922 		com = line + 1;
2923 	}
2924 	else
2925 	{
2926 		cmdchar_used = 0;
2927 		com = line;
2928 	}
2929 	/*
2930 	 * always consider input a command unless we are in interactive mode
2931 	 * and command_mode is off.   -lynx
2932 	 */
2933 	if (hist_flag && !cmdchar_used && !get_int_var(COMMAND_MODE_VAR))
2934 	{
2935 		do_send_text(NULL, line, empty_string);
2936 		if (hist_flag && add_to_hist)
2937 		{
2938 			add_to_history(this_cmd);
2939 			set_input(empty_string);
2940 		}
2941 		/* Special handling for '
2942 		 * and : * /
2943 		 *
2944 		 * i dont see the and.. -jjd
2945 		 */
2946 	}
2947 	else if (*com == '\'' && get_int_var(COMMAND_MODE_VAR))
2948 	{
2949 		do_send_text(NULL, line+1, empty_string);
2950 		if (hist_flag && add_to_hist)
2951 		{
2952 			add_to_history(this_cmd);
2953 			set_input(empty_string);
2954 		}
2955 	}
2956 	else if (*com == '@')
2957 	{
2958 		/* This kludge fixes a memory leak */
2959 		u_char	*tmp;
2960 
2961 		tmp = parse_inline(line + 1, sub_args, &args_flag);
2962 		if (tmp)
2963 			new_free(&tmp);
2964 		if (hist_flag && add_to_hist)
2965 		{
2966 			add_to_history(this_cmd);
2967 			set_input(empty_string);
2968 		}
2969 	}
2970 	else
2971 	{
2972 		u_char	*rest,
2973 			*nalias = NULL,
2974 			*alias_name;
2975 		int	cmd_cnt,
2976 			alias_cnt;
2977 		IrcCommand	*command; /* = (IrcCommand *) 0 */
2978 
2979 		display = window_display;
2980 		old_display_var = (unsigned) get_int_var(DISPLAY_VAR);
2981 		if ((rest = my_index(com, ' ')) != NULL)
2982 			*(rest++) = (u_char) 0;
2983 		else
2984 			rest = empty_string;
2985 		upper(com);
2986 
2987 		/* first, check aliases */
2988 		if (*com && my_index(cmdchars, *com))
2989 		{
2990 			alias_cnt = 0;
2991 			com++;
2992 			if (*com == '^')
2993 			{
2994 				com++;
2995 				window_display = 0;
2996 			}
2997 		}
2998 		else
2999 		{
3000 			if (*com == '^')
3001 			{
3002 				com++;
3003 				window_display = 0;
3004 			}
3005 			nalias = get_alias(COMMAND_ALIAS, com, &alias_cnt,
3006 				&alias_name);
3007 		}
3008 		if (nalias && (alias_cnt == 0))
3009 		{
3010 			if (hist_flag && add_to_hist)
3011 			{
3012 				add_to_history(this_cmd);
3013 				set_input(empty_string);
3014 			}
3015 			execute_alias(alias_name, nalias, rest);
3016 			new_free(&alias_name);
3017 		}
3018 		else
3019 		{
3020 			/* History */
3021 			if (*com == '!')
3022 			{
3023 				if ((com = do_history(com + 1, rest)) != NULL)
3024 				{
3025 					if (level == 1)
3026 					{
3027 						set_input(com);
3028 						update_input(UPDATE_ALL);
3029 					}
3030 					else
3031 						parse_command(com, 0, sub_args);
3032 					new_free(&com);
3033 				}
3034 				else
3035 					set_input(empty_string);
3036 			}
3037 			else
3038 			{
3039 				if (hist_flag && add_to_hist)
3040 				{
3041 					add_to_history(this_cmd);
3042 					set_input(empty_string);
3043 				}
3044 				command = find_command(com, &cmd_cnt);
3045 				if ((command && cmd_cnt < 0) || (0 == alias_cnt && 1 == cmd_cnt))
3046 				{
3047 				   /*
3048 				    * ninja help is disabled for now..
3049 				    *
3050 				   	if (my_strcmp(rest, "-?") == 0
3051 					    || my_stricmp(rest, "--help") == 0)
3052 				     		ninja_help(NULL, command->name, NULL);
3053 					else */ if ((command->flags & SERVERREQ) && connected_to_server == 0)
3054 						say("%s: You are not connected to a server. Use /SERVER to connect.", com);
3055 					else if (command->func)
3056 						command->func(UP(command->server_func), rest, sub_args);
3057 					else
3058 						say("%s: command disabled", command->name);
3059 				}
3060 				else if (nalias && 1 == alias_cnt && cmd_cnt == 1 && !my_strcmp(alias_name, command[0].name))
3061 					execute_alias(alias_name, nalias, rest);
3062 				else if ((alias_cnt + cmd_cnt) > 1)
3063 					say("Ambiguous command: %s", com);
3064 				else if (nalias && 1 == alias_cnt)
3065 					execute_alias(alias_name, nalias, rest);
3066 				else if (!my_stricmp(com, nickname))
3067 						/* nick = /me  -lynx */
3068 					me(NULL, rest, empty_string);
3069 				else
3070 					say("Unknown command: %s", com);
3071 			}
3072 			if (nalias)
3073 				new_free(&alias_name);
3074 		}
3075 		if (old_display_var != get_int_var(DISPLAY_VAR))
3076 			window_display = get_int_var(DISPLAY_VAR);
3077 		else
3078 			window_display = display;
3079 	}
3080 	new_free(&this_cmd);
3081 	level--;
3082 }
3083 
3084 /*
3085  * load: the /LOAD command.  Reads the named file, parsing each line as
3086  * though it were typed in (passes each line to parse_command).
3087  */
3088 /*ARGSUSED*/
3089 void
load(command,args,subargs)3090 load(command, args, subargs)
3091 	u_char	*command,
3092 		*args,
3093 		*subargs;
3094 {
3095 	FILE	*fp;
3096 	u_char	*filename,
3097 		*expanded = NULL;
3098 	int	flag = 0;
3099 	struct	stat	stat_buf;
3100 	int	paste_level = 0;
3101 	u_char	*start,
3102 		*current_row = NULL,
3103 		lbuf[BIG_BUFFER_SIZE + 1];
3104 	int	no_semicolon = 1;
3105 	u_char	*ircpath;
3106 	int	display;
3107 #ifdef ZCAT
3108 	u_char	*expand_z = NULL;
3109 	int	exists;
3110 	int	pos;
3111 #endif /* ZCAT */
3112 
3113 	ircpath = get_string_var(LOAD_PATH_VAR);
3114 	if (!ircpath)
3115 	{
3116 		say("LOAD_PATH has not been set");
3117 		return;
3118 	}
3119 
3120 	if (load_depth == MAX_LOAD_DEPTH)
3121 	{
3122 		say("No more than %d levels of LOADs allowed", MAX_LOAD_DEPTH);
3123 		return;
3124 	}
3125 	load_depth++;
3126 	status_update(0);
3127 #ifdef DAEMON_UID
3128 	if (getuid() == DAEMON_UID)
3129 	{
3130 		say("You may only load your SAVED file");
3131 		filename = ircrc_file;
3132 	}
3133 	else
3134 #endif /* DAEMON_UID */
3135 		while ((filename = next_arg(args, &args)) != NULL)
3136 		{
3137 			if (my_strnicmp(filename, UP("-args"), my_strlen(filename)) == 0)
3138 				flag = 1;
3139 			else
3140 				break;
3141 		}
3142 	if (filename)
3143 	{
3144 		if ((expanded = expand_twiddle(filename)) != NULL)
3145 		{
3146 #ifdef ZCAT
3147 			/* Handle both <expanded> and <expanded>.Z */
3148 			pos = my_strlen(expanded) - my_strlen(ZSUFFIX);
3149 			if (pos < 0 || my_strcmp(expanded + pos, ZSUFFIX))
3150 			{
3151 				malloc_strcpy(&expand_z, expanded);
3152 				malloc_strcat(&expand_z, UP(ZSUFFIX));
3153 			}
3154 #endif /* ZCAT */
3155 			if (*expanded != '/')
3156 			{
3157 				filename = path_search(expanded, ircpath);
3158 #ifdef ZCAT
3159 				if (!filename && expand_z)
3160 					filename = path_search(expand_z, ircpath);
3161 #endif /* ZCAT */
3162 				if (!filename)
3163 				{
3164 					say("%s: File not found", expanded);
3165 					status_update(1);
3166 					load_depth--;
3167 #ifdef ZCAT
3168 					new_free(&expand_z);
3169 #endif /* ZCAT */
3170 					new_free(&expanded);
3171 					return;
3172 				}
3173 				else
3174 					malloc_strcpy(&expanded, filename);
3175 			}
3176 #ifdef ZCAT
3177 			if ((exists = stat_file(CP(expanded), &stat_buf)) == -1)
3178 			{
3179 				if (!(exists = stat_file(CP(expand_z), &stat_buf)))
3180 				{
3181 					if (expanded)
3182 						new_free(&expanded);
3183 					expanded = expand_z;
3184 				}
3185 				else
3186 					new_free(&expand_z);
3187 			}
3188 			if (exists == 0)
3189 #else
3190 				if (!stat_file(expanded, &stat_buf))
3191 #endif /* ZCAT */
3192 				{
3193 					if (stat_buf.st_mode & S_IFDIR)
3194 					{
3195 						say("%s is a directory", expanded);
3196 						status_update(1);
3197 						load_depth--;
3198 #ifdef ZCAT
3199 						new_free(&expand_z);
3200 #endif /* ZCAT */
3201 						new_free(&expanded);
3202 						return;
3203 					}
3204 					/* sigh.  this is lame */
3205 #if defined(S_IXUSR) && defined(S_IXGRP) && defined(S_IXOTH)
3206 # define IS_EXECUTABLE (S_IXUSR|S_IXGRP|S_IXOTH)
3207 #else
3208 # define IS_EXECUTABLE 0111
3209 #endif /* S_IXUSR && S_IXGRP && S_IXOTH */
3210 					if (stat_buf.st_mode & IS_EXECUTABLE)
3211 					{
3212 						yell("*** %s is executable and may not be loaded", expanded);
3213 						status_update(1);
3214 						load_depth--;
3215 #ifdef ZCAT
3216 						new_free(&expand_z);
3217 #endif /* ZCAT */
3218 						new_free(&expanded);
3219 						return;
3220 					}
3221 				}
3222 			if (command && *command == 'W')
3223 			{
3224 				say("%s", expanded);
3225 				status_update(1);
3226 				load_depth--;
3227 				new_free(&expanded);
3228 #ifdef ZCAT
3229 				new_free(&expand_z);
3230 #endif /* ZCAT */
3231 				return;
3232 			}
3233 #ifdef ZCAT
3234 			/* Open if uncompressed, zcat if compressed */
3235 			pos = my_strlen(expanded) - my_strlen(ZSUFFIX);
3236 			if (pos >= 0 && !my_strcmp(expanded + pos, ZSUFFIX))
3237 				fp = zcat(expanded);
3238 			else
3239 				fp = fopen(CP(expanded), "r");
3240 			if (fp != NULL)
3241 #else
3242 				if ((fp = fopen(CP(expanded), "r")))
3243 #endif /* ZCAT */
3244 				{
3245 					display = window_display;
3246 					window_display = 0;
3247 					current_row = NULL;
3248 					if (!flag)
3249 						args = NULL;
3250 					for (;;)
3251 					{
3252 						if (fgets(CP(lbuf), BIG_BUFFER_SIZE / 2, fp))	/* XXX need better /load policy, but this will do for now */
3253 	{
3254 		size_t	len;
3255 		u_char	*ptr;
3256 
3257 		for (start = lbuf; isspace(*start); start++)
3258 			;
3259 		if (!*start || *start == '#')
3260 			continue;
3261 
3262 		len = my_strlen(start);
3263 	/*
3264 	 * this line from stargazer to allow \'s in scripts for continued
3265 	 * lines <spz@specklec.mpifr-bonn.mpg.de>
3266 	 */
3267 		while (start[len-1] == '\n' && start[len-2] == '\\' &&
3268 		    len < BIG_BUFFER_SIZE / 2 && fgets(CP(&(start[len-2])),
3269 		    (int)(BIG_BUFFER_SIZE / 2 - len), fp))
3270 			len = my_strlen(start);
3271 
3272 		if (start[len - 1] == '\n')
3273 		    start[--len] = '\0';
3274 
3275 		while (start && *start)
3276 		{
3277 			u_char	*optr = start;
3278 			while ((ptr = sindex(optr, UP("{};"))) &&
3279 					ptr != optr &&
3280 					ptr[-1] == '\\')
3281 				optr = ptr+1;
3282 
3283 			if (no_semicolon)
3284 				no_semicolon = 0;
3285 			else if ((!ptr || ptr != start) && current_row)
3286 			{
3287 				if (!paste_level)
3288 				{
3289 					parse_line(NULL, current_row,
3290 						args, 0, 0, 0);
3291 					new_free(&current_row);
3292 				}
3293 				else
3294 					malloc_strcat(&current_row, UP(";"));
3295 			}
3296 
3297 			if (ptr)
3298 			{
3299 				u_char	c = *ptr;
3300 
3301 				*ptr = '\0';
3302 				malloc_strcat(&current_row, start);
3303 				*ptr = c;
3304 
3305 				switch (c)
3306 				{
3307 				case '{' :
3308 					paste_level++;
3309 					if (ptr == start)
3310 						malloc_strcat(&current_row, UP(" {"));
3311 					else
3312 						malloc_strcat(&current_row, UP("{"));
3313 					no_semicolon = 1;
3314 					break;
3315 
3316 				case '}' :
3317 					if (!paste_level)
3318 						yell("Unexpected }");
3319 					else
3320 					{
3321 						--paste_level;
3322 						malloc_strcat(&current_row, UP("}"));
3323 						no_semicolon = ptr[1] ? 1 : 0;
3324 					}
3325 					break;
3326 
3327 				case ';' :
3328 					malloc_strcat(&current_row, UP(";"));
3329 					no_semicolon = 1;
3330 					break;
3331 				}
3332 
3333 				start = ptr+1;
3334 			}
3335 			else
3336 			{
3337 				malloc_strcat(&current_row, start);
3338 				start = NULL;
3339 			}
3340 		}
3341 	}
3342 						else
3343 							break;
3344 					}
3345 					if (current_row)
3346 					{
3347 						if (paste_level)
3348 							yell("Unexpected EOF");
3349 						else
3350 							parse_line(NULL,
3351 								current_row,
3352 								args, 0, 0, 0);
3353 						new_free(&current_row);
3354 					}
3355 					window_display = display;
3356 					fclose(fp);
3357 				}
3358 				else
3359 					say("Couldn't open %s: %s", expanded,
3360 						strerror(errno));
3361 			new_free(&expanded);
3362 #ifdef ZCAT
3363 			new_free(&expand_z);
3364 #endif /* ZCAT */
3365 		}
3366 		else
3367 			say("Unknown user");
3368 	}
3369 	else
3370      		usage("load", "[-args] <file>");
3371 		/* say("No filename specified"); */
3372 	status_update(1);
3373 	load_depth--;
3374 }
3375 
3376 /*
3377  * get_history: gets the next history entry, either the PREV entry or the
3378  * NEXT entry, and sets it to the current input string
3379  */
3380 static void
get_history(which)3381 get_history(which)
3382 	int	which;
3383 {
3384 	u_char	*ptr;
3385 
3386 	if ((ptr = get_from_history(which)) != NULL)
3387 	{
3388 		set_input(ptr);
3389 		update_input(UPDATE_ALL);
3390 	}
3391 }
3392 
3393 /* BIND function: */
3394 void
forward_character(key,ptr)3395 forward_character(key, ptr)
3396 	u_int	key;
3397 	u_char	*ptr;
3398 {
3399 	input_move_cursor(RIGHT);
3400 }
3401 
3402 void
backward_character(key,ptr)3403 backward_character(key, ptr)
3404 	u_int	key;
3405 	u_char	*ptr;
3406 {
3407 	input_move_cursor(LEFT);
3408 }
3409 
3410 void
backward_history(key,ptr)3411 backward_history(key, ptr)
3412 	u_int	key;
3413 	u_char	*ptr;
3414 {
3415 	get_history(PREV);
3416 }
3417 
3418 void
forward_history(key,ptr)3419 forward_history(key, ptr)
3420 	u_int	key;
3421 	u_char	*ptr;
3422 {
3423 	get_history(NEXT);
3424 }
3425 
3426 void
toggle_insert_mode(key,ptr)3427 toggle_insert_mode(key, ptr)
3428 	u_int	key;
3429 	u_char	*ptr;
3430 {
3431 	set_var_value(INSERT_MODE_VAR, UP("TOGGLE"));
3432 }
3433 
3434 /*ARGSUSED*/
3435 void
send_line(key,ptr)3436 send_line(key, ptr)
3437 	u_int	key;
3438 	u_char	*ptr;
3439 {
3440 	int	server;
3441 	WaitPrompt	*OldPrompt;
3442 
3443 	server = from_server;
3444 	from_server = get_window_server(0);
3445 	reset_hold((Window *) 0);
3446 	hold_mode((Window *) 0, OFF, 1);
3447 	if (current_screen->promptlist && current_screen->promptlist->type == WAIT_PROMPT_LINE)
3448 	{
3449 		OldPrompt = current_screen->promptlist;
3450 		(*OldPrompt->func)(OldPrompt->data, get_input());
3451 		set_input(empty_string);
3452 		current_screen->promptlist = OldPrompt->next;
3453 		new_free(&OldPrompt->data);
3454 		new_free(&OldPrompt->prompt);
3455 		new_free(&OldPrompt);
3456 		change_input_prompt(-1);
3457 	}
3458 	else
3459 	{
3460 		u_char	*line,
3461 			*tmp = NULL;
3462 
3463 		line = get_input();
3464 		malloc_strcpy(&tmp, line);
3465 
3466 		if (do_hook(INPUT_LIST, "%s", tmp))
3467 		{
3468 			if (get_int_var(INPUT_ALIASES_VAR))
3469 				parse_line(NULL, tmp, empty_string,
3470 					1, 0, 0);
3471 			else
3472 				parse_line(NULL, tmp, NULL,
3473 					1, 0, 0);
3474 		}
3475 		update_input(UPDATE_ALL);
3476 		new_free(&tmp);
3477 	}
3478 	from_server = server;
3479 }
3480 
3481 /* The SENDLINE command.. */
3482 static	void
sendlinecmd(command,args,subargs)3483 sendlinecmd(command, args, subargs)
3484 	u_char	*command,
3485 		*args,
3486 		*subargs;
3487 {
3488 	int	server;
3489 	int	display;
3490 
3491 	server = from_server;
3492 	display = window_display;
3493 	window_display = 1;
3494 	if (get_int_var(INPUT_ALIASES_VAR))
3495 		parse_line(NULL, args, empty_string, 1, 0, 0);
3496 	else
3497 		parse_line(NULL, args, NULL, 1, 0, 0);
3498 	update_input(UPDATE_ALL);
3499 	window_display = display;
3500 	from_server = server;
3501 }
3502 
3503 /*ARGSUSED*/
3504 void
meta8_char(key,ptr)3505 meta8_char(key, ptr)
3506 	u_int	key;
3507 	u_char	*ptr;
3508 {
3509 	current_screen->meta8_hit = 1;
3510 }
3511 
3512 /*ARGSUSED*/
3513 void
meta7_char(key,ptr)3514 meta7_char(key, ptr)
3515 	u_int	key;
3516 	u_char	*ptr;
3517 {
3518 	current_screen->meta7_hit = 1;
3519 }
3520 
3521 /*ARGSUSED*/
3522 void
meta6_char(key,ptr)3523 meta6_char(key, ptr)
3524 	u_int	key;
3525 	u_char	*ptr;
3526 {
3527 	current_screen->meta6_hit = 1;
3528 }
3529 
3530 /*ARGSUSED*/
3531 void
meta5_char(key,ptr)3532 meta5_char(key, ptr)
3533 	u_int	key;
3534 	u_char	*ptr;
3535 {
3536 	current_screen->meta5_hit = 1;
3537 }
3538 
3539 /*ARGSUSED*/
3540 void
meta4_char(key,ptr)3541 meta4_char(key, ptr)
3542 	u_int	key;
3543 	u_char	*ptr;
3544 {
3545 	current_screen->meta4_hit = 1 - current_screen->meta4_hit;
3546 }
3547 
3548 /*ARGSUSED*/
3549 void
meta3_char(key,ptr)3550 meta3_char(key, ptr)
3551 	u_int	key;
3552 	u_char	*ptr;
3553 {
3554 	current_screen->meta3_hit = 1;
3555 }
3556 
3557 /*ARGSUSED*/
3558 void
meta2_char(key,ptr)3559 meta2_char(key, ptr)
3560 	u_int	key;
3561 	u_char	*ptr;
3562 {
3563 	current_screen->meta2_hit = 1;
3564 }
3565 
3566 /*ARGSUSED*/
3567 void
meta1_char(key,ptr)3568 meta1_char(key, ptr)
3569 	u_int	key;
3570 	u_char	*ptr;
3571 {
3572 	current_screen->meta1_hit = 1;
3573 }
3574 
3575 void
quote_char(key,ptr)3576 quote_char(key, ptr)
3577 	u_int	key;
3578 	u_char	*ptr;
3579 {
3580 	current_screen->quote_hit = 1;
3581 }
3582 
3583 /* type_text: the BIND function TYPE_TEXT */
3584 /*ARGSUSED*/
3585 void
type_text(key,ptr)3586 type_text(key, ptr)
3587 	u_int	key;
3588 	u_char	*ptr;
3589 {
3590 	for (; *ptr; ptr++)
3591 		input_add_character((u_int)*ptr, (u_char *) 0);
3592 }
3593 
3594 /*
3595  * irc_clear_screen: the CLEAR_SCREEN function for BIND.  Clears the screen and
3596  * starts it if it is held
3597  */
3598 /*ARGSUSED*/
3599 void
irc_clear_screen(key,ptr)3600 irc_clear_screen(key, ptr)
3601 	u_int	key;
3602 	u_char	*ptr;
3603 {
3604 	hold_mode((Window *) 0, OFF, 1);
3605 	my_clear(NULL, empty_string, empty_string);
3606 }
3607 
3608 /* parse_text: the bindable function that executes its string */
3609 void
parse_text(key,ptr)3610 parse_text(key, ptr)
3611 	u_int	key;
3612 	u_char	*ptr;
3613 {
3614 	parse_line(NULL, ptr, empty_string, 0, 0, 0);
3615 }
3616 
3617 /*
3618  * edit_char: handles each character for an input stream.  Not too difficult
3619  * to work out.
3620  */
3621 void
edit_char(ikey)3622 edit_char(ikey)
3623 	u_int ikey;
3624 {
3625 	void	(*func) _((u_int, u_char *));
3626 	u_char	*str;
3627 	u_char	extended_key, key = (u_char)ikey;
3628 	WaitPrompt *oldprompt;
3629 
3630 	if (current_screen->promptlist &&
3631 			current_screen->promptlist->type == WAIT_PROMPT_KEY)
3632 	{
3633 		oldprompt = current_screen->promptlist;
3634 		(*oldprompt->func)(oldprompt->data, (u_char *)&key);
3635 		set_input(empty_string);
3636 		current_screen->promptlist = oldprompt->next;
3637 		new_free(&oldprompt->data);
3638 		new_free(&oldprompt->prompt);
3639 		new_free(&oldprompt);
3640 		change_input_prompt(-1);
3641 		return;
3642 	}
3643 	if (!get_int_var(EIGHT_BIT_CHARACTERS_VAR))
3644 		key &= 0x7f;			/* mask out non-ascii crap */
3645 
3646 	if (translation)
3647 		extended_key = transFromClient[key];
3648 	else
3649 		extended_key = key;
3650 
3651 	if (current_screen->meta1_hit)
3652 	{
3653 		func = key_names[meta1_keys[key].index].func;
3654 		str = meta1_keys[key].stuff;
3655 		current_screen->meta1_hit = 0;
3656 	}
3657 	else if (current_screen->meta2_hit)
3658 	{
3659 		func = key_names[meta2_keys[key].index].func;
3660 		str = meta2_keys[key].stuff;
3661 		current_screen->meta2_hit = 0;
3662 	}
3663 	else if (current_screen->meta3_hit)
3664 	{
3665 		func = key_names[meta3_keys[key].index].func;
3666 		str = meta3_keys[key].stuff;
3667 		current_screen->meta3_hit = 0;
3668 	}
3669 	else if (current_screen->meta4_hit)
3670 	{
3671 		func = key_names[meta4_keys[key].index].func;
3672 		str = meta4_keys[key].stuff;
3673 	}
3674 	else if (current_screen->meta5_hit)
3675 	{
3676 		func = key_names[meta5_keys[key].index].func;
3677 		str = meta5_keys[key].stuff;
3678 		current_screen->meta5_hit = 0;
3679 	}
3680 	else if (current_screen->meta6_hit)
3681 	{
3682 		func = key_names[meta6_keys[key].index].func;
3683 		str = meta6_keys[key].stuff;
3684 	}
3685 	else if (current_screen->meta7_hit)
3686 	{
3687 		func = key_names[meta7_keys[key].index].func;
3688 		str = meta7_keys[key].stuff;
3689 	}
3690 	else if (current_screen->meta8_hit)
3691 	{
3692 		func = key_names[meta8_keys[key].index].func;
3693 		str = meta8_keys[key].stuff;
3694 	}
3695 	else
3696 	{
3697 		func = key_names[keys[key].index].func;
3698 		str = keys[key].stuff;
3699 	}
3700 	if (!current_screen->meta1_hit && !current_screen->meta2_hit &&
3701 			!current_screen->meta3_hit)
3702 	{
3703 		if (current_screen->inside_menu == 1)
3704 			menu_key((u_int)key);
3705 		else if (current_screen->digraph_hit)
3706 		{
3707 			if (extended_key == 0x08 || extended_key == 0x7f)
3708 				current_screen->digraph_hit = 0;
3709 			else if (current_screen->digraph_hit == 1)
3710 			{
3711 				current_screen->digraph_first = extended_key;
3712 				current_screen->digraph_hit = 2;
3713 			}
3714 			else if (current_screen->digraph_hit == 2)
3715 			{
3716 				if ((extended_key =
3717 				    get_digraph((u_int)extended_key)) != '\0')
3718 					input_add_character((u_int)extended_key, (u_char *) 0);
3719 				else
3720 					term_beep();
3721 			}
3722 		}
3723 		else if (current_screen->quote_hit)
3724 		{
3725 			current_screen->quote_hit = 0;
3726 			input_add_character((u_int)extended_key, (u_char *) 0);
3727 		}
3728 		else if (func)
3729 			func(extended_key, str ? str : empty_string);
3730 	}
3731 	else
3732 		term_beep();
3733 }
3734 
3735 /*ARGSUSED*/
3736 static	void
catter(command,args,subargs)3737 catter(command, args, subargs)
3738 	u_char	*command,
3739 		*args,
3740 		*subargs;
3741 {
3742 	u_char *target = next_arg(args, &args);
3743 
3744 	if (target && args && *args)
3745 	{
3746 		u_char *text = args;
3747 		FILE *fp = fopen(CP(target), "r+");
3748 
3749 		if (!fp)
3750 		{
3751 			fp = fopen(CP(target), "w");
3752 			if (!fp)
3753 			{
3754 				say("CAT: error: '%s': %s", target, strerror(errno));
3755 				return;
3756 		}	}
3757 
3758 		fseek(fp, 0, SEEK_END);
3759 		fprintf(fp, "%s\n", text),
3760 		fclose(fp);
3761 	}
3762 	else
3763 		say("Usage: /CAT <destfile> <line>");
3764 }
3765 
3766 
3767 /*ARGSUSED*/
3768 static	void
cd(command,args,subargs)3769 cd(command, args, subargs)
3770 	u_char	*command,
3771 		*args,
3772 		*subargs;
3773 {
3774 	u_char	lbuf[BIG_BUFFER_SIZE];
3775 	u_char	*arg,
3776 		*expand;
3777 
3778 #ifdef DAEMON_UID
3779 	if (getuid() == DAEMON_UID)
3780 	{
3781 		say("You are not permitted to use this command");
3782 		return;
3783 	}
3784 #endif /* DAEMON_UID */
3785 	if ((arg = next_arg(args, &args)) != NULL)
3786 	{
3787 		if ((expand = expand_twiddle(arg)) != NULL)
3788 		{
3789 			if (chdir(CP(expand)))
3790 				put_error("CD: %s", strerror(errno));
3791 			new_free(&expand);
3792 		}
3793 		else
3794 			put_error("CD: No such user?");
3795 	}
3796 
3797    if (!getcwd(CP(lbuf), BIG_BUFFER_SIZE-1))
3798      put_error("Unable to get CWD: %s", strerror(errno));
3799    else
3800      {
3801 	lbuf[sizeof(lbuf)-1] = '\0';
3802 	say("Current directory: %s", lbuf);
3803      }
3804 }
3805 
3806 	void
send_action(target,text)3807 send_action(target, text)
3808 	u_char	*target, *text;
3809 {
3810 #ifdef SUPPORT_ICB
3811 	if (get_server_version(from_server) == ServerICB)
3812 	{
3813 		u_char	*s;
3814 		int      old_display = window_display;
3815 
3816 		s = new_malloc(2 + strlen(text) + 2 + 1);
3817 		strcpy(CP(s), "*");
3818 		strcat(CP(s), CP(text));
3819 		strcat(CP(s), "*");
3820 		window_display = 0;
3821 		if (is_current_channel(target, from_server, -1))
3822 			icb_put_public(s);
3823 		else
3824 			icb_put_msg2(target, s);
3825 		window_display = old_display;
3826 		new_free(&s);
3827 	}
3828 	else
3829 #endif
3830 	send_ctcp(ctcp_type[CTCP_PRIVMSG], target, UP("ACTION"), "%s", text);
3831 }
3832 
3833 #ifdef LYNX_STUFF
3834 static	u_char	*
prepare_action(string)3835 prepare_action(string)
3836 	u_char	*string;
3837 {
3838 	short	last;
3839 	u_char	*message;
3840 
3841 	last = my_strlen(string) - 1;
3842 	while(string[last] == ' ')
3843 		if (--last < 0) return NULL;
3844 
3845 	if ((string[last] > 'a' && string[last] < 'z') ||
3846 			(string[last] > 'A' && string[last] < 'Z'))
3847 	{
3848 		message = new_malloc(last + 2);
3849 		my_strmcpy(message, string, last+1);
3850 		message[last + 1] = '.';
3851 		message[last + 2] = '\0';
3852 		return message;
3853 	}
3854 	else
3855 		return NULL;
3856 }
3857 #endif /* LYNX_STUFF */
3858 
3859 static	void
describe(command,args,subargs)3860 describe(command, args, subargs)
3861 	u_char	*command,
3862 		*args,
3863 		*subargs;
3864 {
3865 	u_char	*target;
3866 
3867 	target = next_arg(args, &args);
3868 	if (target && args && *args)
3869 	{
3870 		int	old /* , from_level */;
3871 #ifdef LYNX_STUFF
3872 		u_char	*result;
3873 #endif /* LYNX_STUFF */
3874 		u_char	*message;
3875 
3876 #ifdef LYNX_STUFF
3877 		if (result = prepare_action(args))
3878 			message = result;
3879 		else
3880 #endif /* LYNX_STUFF */
3881 			message = args;
3882 
3883 		old = set_lastlog_msg_level(LOG_ACTION);
3884 		save_message_from();
3885 	   /* from_level = message_from_level(LOG_ACTION); */
3886 	   message_from(target, LOG_ACTION);
3887 		send_action(target, message);
3888 		if (do_hook(SEND_ACTION_LIST, "%s %s", target, message))
3889 			put_it("* -> %s: %s %s", target,
3890 				get_server_nickname(from_server), message);
3891 		set_lastlog_msg_level(old);
3892 		restore_message_from();
3893 
3894 #ifdef LYNX_STUFF
3895 		if (result)
3896 			new_free(&result);
3897 #endif /* LYNX_STUFF */
3898 	}
3899 	else
3900 		/* say("Usage: /DESCRIBE <target> <action description>"); */
3901      usage("describe", "<target> <action>");
3902 }
3903 
3904 /*
3905  * New 'me' command - now automatically appends period.
3906  * Necessary for new 'action' script.   -lynx'92
3907  * Hardly, removed this as it was generally considered offensive
3908  */
3909 static	void
me(command,args,subargs)3910 me(command, args, subargs)
3911 	u_char	*command,
3912 		*args,
3913 		*subargs;
3914 {
3915 	if (args && *args)
3916 	{
3917 		u_char	*target;
3918 
3919 		if ((target = get_target_by_refnum(0)) != NULL)
3920 		{
3921 			int	old;
3922 #ifdef LYNX_STUFF
3923 			u_char	*result;
3924 #endif /* LYNX_STUFF */
3925 			u_char	*message;
3926 
3927 			/* handle "/ foo" */
3928 			if (!my_strncmp(target, get_string_var(CMDCHARS_VAR), 1) &&
3929 			    (!(target = get_channel_by_refnum(0))))
3930 			{
3931 				say("No target, neither channel nor query");
3932 				return;
3933 			}
3934 #ifdef LYNX_STUFF
3935 			if (result = prepare_action(args))
3936 				message = result;
3937 			else
3938 #endif /* LYNX_STUFF */
3939 
3940 				message = args;
3941 
3942 			old = set_lastlog_msg_level(LOG_ACTION);
3943 			save_message_from();
3944 			message_from(target, LOG_ACTION);
3945 			send_action(target, message);
3946 			if (do_hook(SEND_ACTION_LIST, "%s %s", target, message))
3947 				put_it("* %s %s",
3948 				    get_server_nickname(from_server), message);
3949 			set_lastlog_msg_level(old);
3950 			restore_message_from();
3951 
3952 #ifdef LYNX_STUFF
3953 			if (result)
3954 				new_free(&result);
3955 #endif /* LYNX_STUFF */
3956 		}
3957 		else
3958 			say("No target, neither channel nor query");
3959 	}
3960 	else
3961      /* say("Usage: /ME <action description>"); */
3962      usage("me", "<action>");
3963 }
3964 
3965 static	void
mload(command,args,subargs)3966 mload(command, args, subargs)
3967 	u_char	*command,
3968 		*args,
3969 		*subargs;
3970 {
3971 	u_char	*file;
3972 
3973 	while ((file = next_arg(args, &args)) != NULL)
3974 		load_menu(file);
3975 }
3976 
3977 static	void
mlist(command,args,subargs)3978 mlist(command, args, subargs)
3979 	u_char	*command,
3980 		*args,
3981 		*subargs;
3982 {
3983 	u_char	*menu;
3984 
3985 	while ((menu = new_next_arg(args, &args)) != NULL)
3986 		(void) ShowMenu(menu);
3987 }
3988 
3989 static	void
evalcmd(command,args,subargs)3990 evalcmd(command, args, subargs)
3991 	u_char	*command,
3992 		*args,
3993 		*subargs;
3994 {
3995 	parse_line(NULL, args, subargs ? subargs : empty_string, 0, 0, 0);
3996 }
3997 
3998 /*
3999  * execute_timer:  checks to see if any currently pending timers have
4000  * gone off, and if so, execute them, delete them, etc, setting the
4001  * current_exec_timer, so that we can't remove the timer while its
4002  * still executing.
4003  */
4004 extern	void
execute_timer()4005 execute_timer()
4006 {
4007 	time_t	current;
4008 	TimerList *next;
4009 	int	old_in_on_who,
4010 		old_server = from_server;
4011 
4012 	time(&current);
4013 	while (PendingTimers && PendingTimers->time <= current)
4014 	{
4015 		old_in_on_who = in_on_who;
4016 		in_on_who = PendingTimers->in_on_who;
4017 		current_exec_timer = PendingTimers->ref;
4018 		save_message_from();
4019 		(void)message_from_level(LOG_CURRENT);
4020 		if (PendingTimers->server >= 0)
4021 			from_server = PendingTimers->server;
4022 		parse_command(PendingTimers->command, 0, empty_string);
4023 		from_server = old_server;
4024 		restore_message_from();
4025 		current_exec_timer = -1;
4026 		new_free(&PendingTimers->command);
4027 		next = PendingTimers->next;
4028 		new_free(&PendingTimers);
4029 		PendingTimers = next;
4030 		in_on_who = old_in_on_who;
4031 	}
4032 }
4033 
4034 /*
4035  * timercmd: the bit that handles the TIMER command.  If there are no
4036  * arguements, then just list the currently pending timers, if we are
4037  * give a -DELETE flag, attempt to delete the timer from the list.  Else
4038  * consider it to be a timer to add, and add it.
4039  */
4040 void
timercmd(command,args,subargs)4041 timercmd(command, args, subargs)
4042 	u_char	*command,
4043 		*args,
4044 		*subargs;
4045 {
4046 	u_char	*waittime,
4047 		*flag;
4048 	time_t	current;
4049 	TimerList	**slot,
4050 			*ntimer;
4051 	int	want = -1,
4052 		refnum;
4053 
4054 	if (*args == '-')
4055 	{
4056 		size_t	len;
4057 
4058 		flag = next_arg(args, &args);
4059 		len = my_strlen(flag);
4060 		upper(flag);
4061 
4062 		/* first check for the -DELETE flag */
4063 
4064 		if (!my_strncmp(flag, "-DELETE", len))
4065 		{
4066 			u_char	*ptr;
4067 			int	ref;
4068 			TimerList	*tmp,
4069 					*prev;
4070 
4071 			if (current_exec_timer != -1)
4072 			{
4073 				say("You may not remove a TIMER from itself");
4074 				return;
4075 			}
4076 			if (!(ptr = next_arg(args, &args)))
4077 			{
4078 				say("%s: Need a timer reference number for -DELETE", command);
4079 				return;
4080 			}
4081 			ref = my_atoi(ptr);
4082 			for (prev = tmp = PendingTimers; tmp; prev = tmp,
4083 					tmp = tmp->next)
4084 			{
4085 				if (tmp->ref == ref)
4086 				{
4087 					if (tmp == prev)
4088 						PendingTimers =
4089 							PendingTimers->next;
4090 					else
4091 						prev->next = tmp->next;
4092 					new_free(&tmp->command);
4093 					new_free(&tmp);
4094 					return;
4095 				}
4096 			}
4097 			say("%s: Can't delete %d, no such refnum",
4098 				command, ref);
4099 			return;
4100 		}
4101 		else if (!my_strncmp(flag, "-REFNUM", len))
4102 		{
4103 			u_char	*ptr;
4104 
4105 			ptr = next_arg(args, &args);
4106 			want = my_atoi(ptr);
4107 			if (want < 0)
4108 			{
4109 				say("%s: Illegal refnum %d", command, want);
4110 				return;
4111 			}
4112 		}
4113 		else
4114 		{
4115 			say("%s: %s no such flag", command, flag);
4116 			return;
4117 		}
4118 	}
4119 
4120 	/* else check to see if we have no args -> list */
4121 
4122 	if (!(waittime = next_arg(args, &args)))
4123 	{
4124 		show_timer(command);
4125 		return;
4126 	}
4127 
4128 	/* must be something to add */
4129 
4130 	if ((refnum = create_timer_ref(want)) == -1)
4131 	{
4132 		say("%s: Refnum %d already exists", command, want);
4133 		return;
4134 	}
4135 	time(&current);
4136 	ntimer = (TimerList *) new_malloc(sizeof(TimerList));
4137 	ntimer->in_on_who = in_on_who;
4138 	ntimer->time = current + my_atol(waittime);
4139 	ntimer->server = from_server;
4140 	ntimer->ref = refnum;
4141 	ntimer->command = NULL;
4142 	malloc_strcpy(&ntimer->command, args);
4143 
4144 	/* we've created it, now put it in order */
4145 
4146 	for (slot = &PendingTimers; *slot; slot = &(*slot)->next)
4147 	{
4148 		if ((*slot)->time > ntimer->time)
4149 			break;
4150 	}
4151 	ntimer->next = *slot;
4152 	*slot = ntimer;
4153 }
4154 
4155 /*
4156  * show_timer:  Display a list of all the TIMER commands that are
4157  * pending to be executed.
4158  */
4159 static	void
show_timer(command)4160 show_timer(command)
4161 	u_char	*command;
4162 {
4163 	TimerList	*tmp;
4164 	time_t	current,
4165 		time_left;
4166 
4167 	if (!PendingTimers)
4168 	{
4169 		say("%s: No commands pending to be executed", command);
4170 		return;
4171 	}
4172 
4173 	time(&current);
4174 	say("Timer Seconds   Command");
4175 	for (tmp = PendingTimers; tmp; tmp = tmp->next)
4176 	{
4177 		time_left = tmp->time - current;
4178 		if (time_left < 0)
4179 			time_left = 0;
4180 		say("%-5d %-10d %s", tmp->ref, time_left, tmp->command);
4181 	}
4182 }
4183 
4184 /*
4185  * create_timer_ref:  returns the lowest unused reference number for
4186  * a timer
4187  */
4188 static	int
create_timer_ref(want)4189 create_timer_ref(want)
4190 	int	want;
4191 {
4192 	TimerList	*tmp;
4193 	int	ref = 0;
4194 	int	done = 0;
4195 
4196 	if (want == -1)
4197 		while (!done)
4198 		{
4199 			done = 1;
4200 			for (tmp = PendingTimers; tmp; tmp = tmp->next)
4201 				if (ref == tmp->ref)
4202 				{
4203 					ref++;
4204 					done = 0;
4205 					break;
4206 				}
4207 		}
4208 	else
4209 	{
4210 		ref = want;
4211 		for (tmp = PendingTimers; tmp; tmp = tmp->next)
4212 			if (ref == tmp->ref)
4213 			{
4214 				ref = -1;
4215 				break;
4216 			}
4217 	}
4218 
4219 	return (ref);
4220 }
4221 
4222 /*
4223  * inputcmd:  the INPUT command.   Takes a couple of arguements...
4224  * the first surrounded in double quotes, and the rest makes up
4225  * a normal ircII command.  The command is evalutated, with $*
4226  * being the line that you input.  Used add_wait_prompt() to prompt
4227  * the user...  -phone, jan 1993.
4228  */
4229 
4230 static	void
inputcmd(command,args,subargs)4231 inputcmd(command, args, subargs)
4232 	u_char	*command,
4233 		*args,
4234 		*subargs;
4235 {
4236 	u_char	*prompt;
4237 
4238 	if (!args || !*args)
4239 		return;
4240 
4241 	if (*args++ != '"')
4242 	{
4243 		say("Need \" to begin prompt for INPUT");
4244 		return;
4245 	}
4246 
4247 	prompt = args;
4248 	if ((args = my_index(prompt, '"')) != NULL)
4249 		*args++ = '\0';
4250 	else
4251 	{
4252 		say("Missing \" in INPUT");
4253 		return;
4254 	}
4255 
4256 	for (; *args == ' '; args++)
4257 		;
4258 
4259 	add_wait_prompt(prompt, eval_inputlist, args, WAIT_PROMPT_LINE);
4260 }
4261 
4262 /*
4263  * eval_inputlist:  Cute little wrapper that calls parse_line() when we
4264  * get an input prompt ..
4265  */
4266 
4267 void
eval_inputlist(args,line)4268 eval_inputlist(args, line)
4269 	u_char	*args,
4270 		*line;
4271 {
4272 	parse_line(NULL, args, line ? line : empty_string, 0, 0, 0);
4273 }
4274 
4275 /* pingcmd: ctcp ping, duh - phone, jan 1993. */
4276 static	void
pingcmd(command,args,subargs)4277 pingcmd(command, args, subargs)
4278 	u_char    *command,
4279 		*args,
4280 		*subargs;
4281 {
4282    u_char	buffer[512], *target;
4283    struct timeval tv;
4284 
4285    target = next_arg(args, &args);
4286    if (!target)
4287      target = get_channel_by_refnum(0);
4288    if (!target)
4289      {
4290 	put_error("No target for /%s", command);
4291 	return;
4292      }
4293    if (gettimeofday(&tv, NULL) == -1)
4294      {
4295 	put_error("%s: Unable to gettimeofday(): %s", strerror(errno));
4296 	return;
4297      }
4298    snprintf(CP(buffer), sizeof(buffer)-1, "%s PING %lu %lu", target, tv.tv_sec, tv.tv_usec);
4299    buffer[sizeof(buffer)-1] = '\0';
4300    ctcp(command, buffer, empty_string);
4301 }
4302 
4303 static	void
xtypecmd(command,args,subargs)4304 xtypecmd(command, args, subargs)
4305 	u_char	*command,
4306 		*args,
4307 		*subargs;
4308 {
4309 	u_char	*arg;
4310 	size_t	len;
4311 
4312 	if (args && *args == '-')
4313 	{
4314 		args++;
4315 		if ((arg = next_arg(args, &args)) != NULL)
4316 		{
4317 			len = my_strlen(arg);
4318 			if (!my_strnicmp(arg, UP("LITERAL"), len))
4319 			{
4320 				for (; *args; args++)
4321 					input_add_character((u_int)*args, (u_char *) 0);
4322 			}
4323 #ifdef _Windows
4324 			else if (!my_strnicmp(arg, UP("REPLACE"), len))
4325 			{
4326 				set_input(args);
4327 				term_resetall();
4328 			}
4329 #endif /* _Windows */
4330 			else
4331 				say ("Unknown flag -%s to XTYPE", arg);
4332 			return;
4333 		}
4334 		input_add_character('-', (u_char *) 0);
4335 	}
4336 	else
4337 		type(command, args, empty_string);
4338 	return;
4339 }
4340 
4341 static	void
beepcmd(command,args,subargs)4342 beepcmd(command, args, subargs)
4343 	u_char	*command,
4344 		*args,
4345 		*subargs;
4346 {
4347 	term_beep();
4348 }
4349