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(¤t_row);
3292 }
3293 else
3294 malloc_strcat(¤t_row, UP(";"));
3295 }
3296
3297 if (ptr)
3298 {
3299 u_char c = *ptr;
3300
3301 *ptr = '\0';
3302 malloc_strcat(¤t_row, start);
3303 *ptr = c;
3304
3305 switch (c)
3306 {
3307 case '{' :
3308 paste_level++;
3309 if (ptr == start)
3310 malloc_strcat(¤t_row, UP(" {"));
3311 else
3312 malloc_strcat(¤t_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(¤t_row, UP("}"));
3323 no_semicolon = ptr[1] ? 1 : 0;
3324 }
3325 break;
3326
3327 case ';' :
3328 malloc_strcat(¤t_row, UP(";"));
3329 no_semicolon = 1;
3330 break;
3331 }
3332
3333 start = ptr+1;
3334 }
3335 else
3336 {
3337 malloc_strcat(¤t_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(¤t_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(¤t);
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(¤t);
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(¤t);
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