1 /*
2 * commands.c: all the client commands.
3 *
4 * Copyright(c) 1997-2000 - All Rights Reserved
5 *
6 * See the COPYRIGHT file.
7 */
8
9 #ifndef lint
10 static char rcsid[] = "@(#)$Id: commands.c,v 1.66 2001/03/14 19:50:20 kalt Exp $";
11 #endif
12
13 #include "os.h"
14
15 #include "struct.h"
16 #include "server.h"
17 #include "window.h"
18 #include "format.h"
19 #include "option.h"
20 #include "term.h"
21 #include "utils.h"
22 #include "input.h"
23
24 extern struct server_ *server;
25
26 extern char tab_add(char *, char *);
27 extern char space_add(char *, char *);
28 extern int cmd_ctcp(char *);
29 extern int cmd_ping(char *);
30 extern int cmd_seen(char *);
31 extern int cmd_lastlog(char *);
32 extern int sic_wreformat();
33 extern char *yow();
34
35 void parse_command(char *, int);
36
37 struct cmdlist_
38 {
39 char *name;
40 int (*func) (char *);
41 };
42
43 struct aliaslist_
44 {
45 char *name;
46 char *eval;
47 struct aliaslist_ *nexta;
48 };
49
50 static struct aliaslist_ *alias = NULL;
51
52 /* return codes:
53 * 0 "success"
54 * -1 "need more parameters"
55 * -2 "no recipient"
56 * -3 "no text to send"
57 * -4 "bad params"
58 * -5 "bind window to server first"
59 * -9 "not implemented"
60 */
61
62 static char outp[1024];
63 static u_char outa[1024];
64
65 /* cmd_smart: if the first word in the buffer is not a channel, prepend
66 * the window default channel name to the buffer.
67 */
68 static char *
cmd_smart(ibuf)69 cmd_smart(ibuf)
70 char *ibuf;
71 {
72 static char newbuf[1024];
73 struct channel_ *ctmp;
74 char *sp;
75
76 if (*ibuf == '&' || *ibuf == '#' || *ibuf == '+')
77 {
78 char known;
79 if (sp = index(ibuf, ' '))
80 *sp = '\0';
81 known = map_c2w(ibuf);
82 if (sp)
83 *sp = ' ';
84 if (known)
85 return ibuf;
86 }
87 ctmp = get_channel(NULL);
88 if (ctmp == NULL)
89 return "";
90 sprintf(newbuf, "%s%s%s", ctmp->chname, (*ibuf) ? " " : "", ibuf);
91 return newbuf;
92 }
93
94 /*
95 * IRC commands
96 */
97 static int
cmd_epart(p,forget)98 cmd_epart(p, forget)
99 char *p;
100 char forget;
101 {
102 char *c;
103
104 p = cmd_smart(p);
105 c = index(p, ' ');
106 if (!*p)
107 return -1;
108 if (c)
109 *c++ = '\0';
110
111 if (map_c2w(p) == 0)
112 {
113 vsic_slog(LOG_CLIENT, "--- Channel %s is unknown to me", p);
114 return 0;
115 }
116
117 part_channel(p, (c) ? c : "", forget);
118
119 return 0;
120 }
121
122 static int
cmd_cmode(p)123 cmd_cmode(p)
124 char *p;
125 {
126 p = cmd_smart(p);
127 if (!*p)
128 return -1;
129 vsic_write("MODE %s", p);
130 return 0;
131 }
132
133 static int
cmd_join(p)134 cmd_join(p)
135 char *p;
136 {
137 char *key = index(p, ' ');
138 struct channel_ *ctmp;
139
140 if (!*p)
141 return -1;
142 if (index(p, ','))
143 return -9; /* better this than a crash */
144 if (server == NULL)
145 return -5;
146 if (key)
147 *key++ = '\0';
148 switch (map_c2w(p))
149 {
150 case 0 :
151 new_channel(p);
152 break;
153 case 1 :
154 break;
155 case 2 :
156 vsic_slog(LOG_CLIENT,
157 "--- Channel %s was mapped to a different window", p);
158 sic_wchannel(p);
159 break;
160 default :
161 abort(); /* never */
162 }
163 ctmp = get_channel(p);
164 if (key && *key)
165 {
166 if (ctmp->chkey)
167 free(ctmp->chkey);
168 ctmp->chkey = strdup(key);
169 }
170 join_channel(p, 0);
171 return 0;
172 }
173
174 static int
cmd_kick(p)175 cmd_kick(p)
176 char *p;
177 {
178 char *comment;
179
180 p = cmd_smart(p);
181 if (!*p)
182 return -1;
183 if (comment = index(p, ' '))
184 if (comment = index(comment+1, ' '))
185 *comment++ = '\0';
186 vsic_write("KICK %s :%s", p, (comment) ? comment : "");
187 return 0;
188 }
189
190 static int
cmd_leave(p)191 cmd_leave(p)
192 {
193 return cmd_epart(p, 0);
194 }
195
196 static int
cmd_list(p)197 cmd_list(p)
198 char *p;
199 {
200 vsic_write("LIST %s", (*p) ? p : cmd_smart(p));
201 return 0;
202 }
203
204 int
cmd_msgnotice(cmd,p)205 cmd_msgnotice(cmd, p)
206 char *cmd, *p;
207 {
208 char *txt = index(p, ' '), fmt;
209 int rendering;
210 unsigned int flags = 0;
211
212 if (!*p)
213 return -2;
214 if (cmd)
215 {
216 if (!txt || !*(txt+1))
217 return -3;
218 *txt++ = '\0';
219 if (rmatch("*@[*]", p))
220 {
221 char *s = index(index(p, '@'), ']');
222
223 *s = '\0';
224 s = index(p, '@');
225 *s++ = '\0';
226 s += 1;
227 if (select_server(s) == NULL)
228 {
229 vsic_slog(LOG_CLIENT, "--- No connected to %s.", s);
230 return 0;
231 }
232 }
233 if (*p != '&' && *p != '#' && *p != '+' && *txt != '\001')
234 tab_add(p, (*cmd == 'S') ? NULL : "");
235 if (*p == '=')
236 if (*cmd == 'N')
237 return -4;
238 else
239 {
240 p++;
241 cmd = "DCC";
242 }
243 }
244 else
245 {
246 cmd = "PRIVMSG";
247 txt = p;
248 if (p = get_query())
249 {
250 if (*p == '=')
251 {
252 cmd = "DCC";
253 p++;
254 }
255 else if (index(p, '@'))
256 cmd = "SQUERY";
257 }
258 else
259 {
260 if (get_channel(NULL) == NULL)
261 return -3;
262 p = get_channel(NULL)->chname;
263 }
264 }
265
266 if (*p != '=' && server == NULL)
267 return -5;
268 fmt = get_channel(p) ? (*cmd == 'P') ? F_MYPUBM : F_MYPUBN :
269 (*cmd == 'D') ? F_MYDCC : (*cmd == 'P') ? F_MYPRIVM : F_MYPRIVN;
270 rendering = out_sprintf(outp, outa, get_format(fmt, p), p, cmd, txt);
271 select_active(get_channel(p) ? p : NULL, 0);
272 if (*cmd == 'P' && get_channel(p) == NULL)
273 {
274 char tmpq[512];
275
276 sprintf(tmpq, "%s%s", (*cmd == 'D') ? "=" : "", p);
277 select_query(tmpq);
278 }
279 flags = LOG_CLIENT;
280 flags |= (*cmd == 'D') ? LOG_DCC : (*cmd == 'P') ? LOG_MSG : LOG_NOTICE;
281 flags |= get_channel(p) ? LOG_PUBLIC : LOG_PRIVATE;
282 if (*cmd == 'N' && *txt == '\001'
283 && !get_option(Z_VCTCP, (get_channel(p)) ? p : NULL))
284 flags |= LOG_HIDE;
285 sic_log(flags, 0, NULL, cmd, p, txt, fmt, outp, rendering ? outa : NULL);
286 if (*cmd == 'D')
287 vsic_dwrite(p, "%s", txt);
288 else
289 vsic_write("%s %s :%s", cmd, p, txt);
290 if (get_channel(p) && (p = index(txt, ':')) < index(txt, ' ') && p)
291 {
292 *p = '\0';
293 space_add(txt, "");
294 }
295 return 0;
296 }
297
298 static int
cmd_msg(p)299 cmd_msg(p)
300 char *p;
301 {
302 return cmd_msgnotice("PRIVMSG", p);
303 }
304
305 static int
cmd_names(p)306 cmd_names(p)
307 char *p;
308 {
309 vsic_write("NAMES %s", (*p) ? p : cmd_smart(p));
310 return 0;
311 }
312
313 static int
cmd_notice(p)314 cmd_notice(p)
315 char *p;
316 {
317 return cmd_msgnotice("NOTICE", p);
318 }
319
320 static int
cmd_part(p)321 cmd_part(p)
322 char *p;
323 {
324 return cmd_epart(p, 1);
325 }
326
327 static int
cmd_quit(p)328 cmd_quit(p)
329 char *p;
330 {
331 vsic_write("QUIT :%s", p);
332 cmd_server(NULL);
333 return 0;
334 }
335
336 static int
cmd_squery(p)337 cmd_squery(p)
338 char *p;
339 {
340 char *txt = index(p, ' ');
341 int rendering;
342
343 if (!*p)
344 return -2;
345 if (server == NULL)
346 return -5;
347 if (!txt || !*(txt+1))
348 return -3;
349 *txt++ = '\0';
350
351 vsic_write("SQUERY %s :%s", p, txt);
352 rendering = out_sprintf(outp, outa, get_format(F_MYQUERY, NULL),
353 p, "SQUERY", txt);
354 select_active(NULL, 0);
355 sic_log(LOG_CLIENT|LOG_PRIVATE|LOG_MSG,
356 0, NULL, "SQUERY", p, txt, F_MYQUERY, outp, rendering ? outa : NULL);
357 return 0;
358 }
359
360 static int
cmd_topic(p)361 cmd_topic(p)
362 char *p;
363 {
364 char *comment;
365
366 if (!*p)
367 p = cmd_smart(p);
368 if (!*p)
369 return -1;
370 if (comment = index(p, ' '))
371 *comment++ = '\0';
372 vsic_write("TOPIC %s%c%s", p, (comment) ? ':' : ' ',
373 (comment) ? comment : "");
374 return 0;
375 }
376
377 static int
cmd_umode(p)378 cmd_umode(p)
379 char *p;
380 {
381 if (server == NULL)
382 return -5;
383 vsic_write("MODE %s %s", server->nick, p);
384 return 0;
385 }
386
387 static int
cmd_who(p)388 cmd_who(p)
389 char *p;
390 {
391 vsic_write("WHO %s", (*p) ? p : cmd_smart(p));
392 return 0;
393 }
394
395 /*
396 * internal commands
397 */
398 int
cmd_alias(p)399 cmd_alias(p)
400 char *p;
401 {
402 char tmp[1024], *wp = tmp, *txt;
403 struct aliaslist_ *atmp = alias;
404
405 if (txt = index(p, ' '))
406 {
407 *txt++ = '\0';
408
409 while (atmp)
410 {
411 if (!strcasecmp(p, atmp->name))
412 break;
413 atmp = atmp->nexta;
414 }
415 if (atmp)
416 free(atmp->eval);
417 else
418 {
419 atmp = (struct aliaslist_ *) malloc(sizeof(struct aliaslist_));
420 atmp->name = strdup(p);
421 atmp->nexta = alias;
422 alias = atmp;
423 }
424 while (*txt)
425 {
426 if (*txt == '%' && isdigit((int) *(txt+1)))
427 {
428 *wp++ = *txt++; /* % */
429 *wp++ = '{';
430 while (isdigit((int) *txt))
431 *wp++ = *txt++;
432 *wp++ = '}';
433 }
434 else
435 *wp++ = *txt++;
436 }
437 *wp = '\0';
438 atmp->eval = strdup(tmp);
439 }
440 else
441 {
442 int len = strlen(p);
443
444 sic_slog(LOG_CLIENT, "--- Aliases:");
445 while (atmp)
446 {
447 if (!strncasecmp(p, atmp->name, len))
448 vsic_slog(LOG_CLIENT, "--- %-8s: %s", atmp->name,atmp->eval);
449 atmp = atmp->nexta;
450 }
451 }
452 return 0;
453 }
454
455 static int
cmd_clear(p)456 cmd_clear(p)
457 char *p;
458 {
459 if (*p && !strcasecmp(p, "-f"))
460 sic_clog(1);
461 else
462 sic_clog(0);
463 sic_scroll2(+1, NULL);
464 sic_redowin(0);
465 return 0;
466 }
467
468 static int
cmd_exit(p)469 cmd_exit(p)
470 char *p;
471 {
472 sic_slog(LOG_CLIENT, "Exiting...");
473 term_end();
474 exit(0);
475 }
476
477 static int
cmd_dns(p)478 cmd_dns(p)
479 char *p;
480 {
481 if (*p)
482 {
483 vsic_slog(LOG_CLIENT, "--- Looking up \"%s\" in DNS", p);
484 dns_lookup(p, NULL);
485 return 0;
486 }
487 else
488 return -1;
489 }
490
491 int
cmd_option(p)492 cmd_option(p)
493 char *p;
494 {
495 static char *channel = NULL;
496 char *c, *v;
497 unsigned int flag, all = 0;
498 int fnum = -1;
499
500 if (!*p)
501 return -1;
502
503 if (channel)
504 {
505 free(channel);
506 channel = NULL;
507 }
508 if (v = index(p, ' '))
509 *v++ = '\0';
510
511 switch (*p)
512 {
513 case 'c': case 'C':
514 flag = O_CLEAR;
515 break;
516 case 'g': case 'G':
517 flag = O_GET;
518 break;
519 case 's': case 'S':
520 flag = O_SET;
521 break;
522 case 'r': case 'R':
523 sic_wreformat();
524 sic_redowin(1);
525 return 0;
526 default:
527 return -4;
528 }
529 if ((c = index(p, '.')) == NULL)
530 return -4;
531 switch (*(++c))
532 {
533 case 'a': case 'A':
534 all = 1;
535 if (flag != O_GET)
536 return -4;
537 break;
538 case 'c': case 'C':
539 if ((c = index(p, '=')) == NULL)
540 return -4;
541 if ((p = index(c, '.')) == NULL)
542 return -4;
543 c +=1 ;
544 *p = '\0';
545 if (c == p)
546 if (get_channel(NULL))
547 c = get_channel(NULL)->chname;
548 else
549 c = NULL;
550 if (c == NULL || map_c2w(c) == 0)
551 {
552 vsic_slog(LOG_CLIENT, "%s: No such channel", c);
553 return 0;
554 }
555 channel = strdup(c);
556 *(c = p) = '.';
557 break;
558 case 'd': case 'D':
559 if (flag != O_GET)
560 return -4;
561 flag |= O_DEFAULT;
562 break;
563 case 'p': case 'P':
564 flag |= O_PROTO;
565 break;
566 case 's': case 'S':
567 flag |= O_SERVER;
568 break;
569 case 't': case 'T':
570 flag |= O_TOPLVL;
571 break;
572 case 'w': case 'W':
573 flag |= O_WINDOW;
574 break;
575 default:
576 return -4;
577 }
578 if ((p = index(c, '.')) == NULL)
579 return -4;
580 if (c = index(++p, '.'))
581 *(c++) = '\0';
582 if (!strcasecmp(p, "on"))
583 flag |= O_ON;
584 else if (!strcasecmp(p, "off"))
585 flag |= O_OFF;
586 else if (*p == '#' && isdigit((int) *(p+1)))
587 fnum = atoi(p+1) + F_MAX+1;
588 else if (isdigit((int) *p))
589 fnum = atoi(p);
590 else if (*p == 'k' || *p == 'K')
591 flag |= O_KEYWORD;
592 else if (*p == 'l' || *p == 'L')
593 flag |= O_LOGFILE;
594 else if (*p == 's' || *p == 'S')
595 flag |= O_SWITCH;
596 else if (*p == 'r' || *p == 'R')
597 flag |= O_REWRITE;
598 else
599 return -4;
600 if (flag & (O_ON|O_OFF))
601 {
602 if (c == NULL)
603 return -4;
604 flag |= O_MASK;
605 }
606 if (flag & (O_GET|O_CLEAR))
607 {
608 unsigned char i;
609 char *str = NULL;
610 unsigned int all_list[] = {O_DEFAULT, O_TOPLVL, O_SERVER, O_WINDOW},
611 ui = 0;
612
613 for (i = 0; (i == 0 || all) && i < 4; i++)
614 {
615 if (flag & (O_MASK|O_SWITCH))
616 str = c;
617 if (flag & O_KEYWORD)
618 str = v;
619 if (flag & O_REWRITE)
620 {
621 ui = (c) ? atoi(c) : F_MAX+1;
622 str = v;
623 }
624 customize((all) ? flag|all_list[i] : flag, channel, fnum, &str, &ui);
625 if (flag & O_GET)
626 {
627 if (flag & (O_KEYWORD|O_REWRITE))
628 {
629 int count = fnum; /* -1 */
630
631 do
632 {
633 if (str)
634 if (flag & O_KEYWORD)
635 vsic_slog(LOG_CLIENT, "Keyword: %5.5X %s",
636 ui, str);
637 else
638 vsic_slog(LOG_CLIENT, "Rewrite: %3u %s",
639 ui, str);
640 str = v; fnum = --count;
641 if (flag & O_REWRITE)
642 ui = (c) ? atoi(c) : F_MAX+1;
643 customize((all) ? flag|all_list[i] : flag, channel,
644 fnum, &str, &ui);
645 }
646 while (str != NULL && v == NULL);
647 fnum = -1;
648 }
649 else if (flag & O_MASK)
650 {
651 char *str2 = c;
652 unsigned int ui2 = 0;
653
654 customize((all) ? (flag|all_list[i])^(O_ON|O_OFF) :
655 flag^(O_ON|O_OFF), channel, fnum, &str2, &ui2);
656
657 vsic_slog(LOG_CLIENT, "Set to: \"%8.8X\" - \"%8.8X\"",
658 ui, ui2);
659 }
660 else if (flag & O_LOGFILE)
661 vsic_slog(LOG_CLIENT, "Log: %s, Filter: %d", str, ui);
662 else if (str)
663 vsic_slog(LOG_CLIENT, "Set to: \"%c%s\"",
664 (*str) ? *str : ':', str+1);
665 else
666 vsic_slog(LOG_CLIENT, "Set to: %8.8X", ui);
667 }
668 }
669 return 0;
670 }
671 if (v)
672 {
673 unsigned int ui = 0;
674 char *str = NULL;
675
676 if (flag & O_SWITCH)
677 {
678 if (!strcasecmp(v, "on"))
679 ui = 1;
680 else
681 ui = 0;
682 str = c;
683 }
684 else
685 {
686 ui = (unsigned int) strtoul(v, &str, 0);
687 #if !defined(HAVE_REGEXP)
688 if (flag & O_REWRITE || ((flag & O_KEYWORD) && (ui & K_REGEXP)))
689 {
690 sic_slog(LOG_CLIENT,
691 "--- Option not available (requires regexp library).");
692 return 0;
693 }
694 #endif
695 if (flag & O_MASK)
696 str = c;
697 else if (flag & O_REWRITE)
698 ui = atoi(c);
699 else if (str)
700 while (*str && isspace((int) *str))
701 str++;
702 }
703 customize(flag, channel, fnum, &str, &ui);
704 if (flag & (O_LOGFILE|O_REWRITE|O_KEYWORD) && str)
705 vsic_slog(LOG_CLIENT, "--- Error: %s", str);
706 return 0;
707 }
708 else
709 return -4;
710 }
711
712 static int
cmd_query(p)713 cmd_query(p)
714 char *p;
715 {
716 char *txt = index(p, ' ');
717
718 if (txt)
719 *txt = '\0';
720 if (map_c2w(p) == 0)
721 {
722 default_channel(p);
723 if (txt && *(txt+1))
724 {
725 *txt = ' ';
726 cmd_msgnotice("PRIVMSG", p);
727 }
728 }
729 else
730 sic_slog(LOG_CLIENT,"--- Cannot query a channel!");
731 return 0;
732 }
733
734 static int
cmd_window(p)735 cmd_window(p)
736 char *p;
737 {
738 if (!*p)
739 return -1;
740 if (!strcasecmp(p, "new"))
741 sic_newwin();
742 else if (!strcasecmp(p, "next"))
743 sic_chgwin(1);
744 else if (!strcasecmp(p, "kill"))
745 sic_wkill();
746 else if (!strcasecmp(p, "last"))
747 sic_chgwin(-3);
748 else if (!strcasecmp(p, "list"))
749 sic_wlist();
750 else if (!strcasecmp(p, "previous"))
751 sic_chgwin(-2);
752 else if (!strcasecmp(p, "release"))
753 sic_swin(2);
754 else if (!strncasecmp(p, "number ", 7))
755 if (p = index(p, ' '))
756 if (atoi(++p) >= 0 && atoi(p) < 11)
757 sic_wch(atoi(p));
758 else
759 return -4;
760 else
761 return -1;
762 else if (!strncasecmp(p, "channel ", 8))
763 if (map_c2w(p+8) == 1)
764 default_channel(p+8);
765 else
766 sic_slog(LOG_CLIENT,"--- No such channel or channel not in window.");
767 else if (!strncasecmp(p, "dcc", 3))
768 sic_wdcc();
769 else
770 return -4;
771 return 0;
772 }
773
774 static int
cmd_yow(p)775 cmd_yow(p)
776 char *p;
777 {
778 char *zippy;
779
780 zippy = yow();
781 if (zippy)
782 vsic_slog(LOG_CLIENT, "--- %s", zippy);
783 return 0;
784 }
785
786 struct cmdlist_ cmdlist[] = {
787 { "ADMIN", NULL },
788 { "ALIAS", cmd_alias},
789 { "AWAY", NULL },
790 { "CLOSE", NULL },
791 { "CONNECT", NULL },
792 { "CLEAR", cmd_clear},
793 { "CMODE", cmd_cmode},
794 { "CTCP", cmd_ctcp},
795 { "DCC", cmd_dcc},
796 { "DIE", NULL },
797 { "DNS", cmd_dns},
798 { "EXIT", cmd_exit},
799 { "INFO", NULL },
800 { "INVITE", NULL },
801 { "ISON", NULL },
802 { "JOIN", cmd_join },
803 { "KICK", cmd_kick},
804 /*{ "KILL", NULL },*/
805 { "LASTLOG", cmd_lastlog},
806 { "LEAVE", cmd_leave},
807 { "LINKS", NULL },
808 { "LIST", cmd_list},
809 { "LUSERS", NULL },
810 { "MOTD", NULL },
811 { "MODE", NULL },
812 { "MSG", cmd_msg},
813 { "NAMES", cmd_names},
814 { "NICK", NULL },
815 { "NOTICE", cmd_notice},
816 { "OPER", NULL },
817 { "OPTION", cmd_option},
818 { "PART", cmd_part},
819 { "PING", cmd_ping},
820 /* PING/PONG */
821 { "QUERY", cmd_query},
822 { "QUIT", cmd_quit},
823 { "REHASH", NULL },
824 { "RESTART", NULL },
825 { "RUN", cmd_run},
826 { "SEEN", cmd_seen},
827 { "SERVER", cmd_server},
828 { "SERVLIST", NULL },
829 { "SQUERY", cmd_squery},
830 /*{ "SQUIT", NULL },*/
831 { "STATS", NULL },
832 { "TIME", NULL },
833 { "TOPIC", cmd_topic },
834 { "TRACE", NULL },
835 { "UMODE", cmd_umode},
836 { "USERHOST", NULL },
837 { "VERSION", NULL },
838 { "WINDOW", cmd_window },
839 { "WHO", cmd_who },
840 { "WHOIS", NULL },
841 { "WHOWAS", NULL },
842 { "YOW", cmd_yow },
843 { NULL, NULL }
844 };
845
846 /* parse_alias: parse and execute an alias */
847 void
parse_alias(acmd,str)848 parse_alias(acmd, str)
849 struct aliaslist_ *acmd;
850 char *str;
851 {
852 static unsigned char recursion = 0;
853 char *slice = acmd->eval, *wp = acmd->eval, *rp;
854 char command[1024];
855
856 if (recursion++ >= 5)
857 {
858 vsic_slog(LOG_CLIENT, "--- Alias %s: maximum recursion exceeded.",
859 acmd->name);
860 return;
861 }
862 while (wp)
863 {
864 slice = index(slice+1, ';');
865 command[0] = '\0'; rp = command;
866 while(*wp && (!slice || wp < slice))
867 {
868 while(*wp && (!slice || wp < slice) && *wp != '%')
869 *rp++ = *wp++;
870 if (*wp && (!slice || wp < slice))
871 {
872 wp++; /* skip % */
873 *rp = '\0'; /* for strcat() to work */
874 switch (*wp++)
875 {
876 case '%':
877 *rp++ = '%'; *rp = '\0';
878 break;
879 case '*':
880 strcat(command, str);
881 break;
882 case '{':
883 strcat(command, sic_split(str, wp-1));
884 while (*wp != '}')
885 wp++;
886 wp++;
887 break;
888 }
889 while (*rp != '\0')
890 rp++;
891 }
892 }
893 *rp = '\0';
894 if (*command == '/')
895 parse_command(command+1, 1);
896 else
897 cmd_msgnotice(NULL, command);
898 wp = slice;
899 }
900 recursion--;
901 }
902
903 /* parse_command: parse an input string that is a command/alias. */
904 void
parse_command(str,aliases)905 parse_command(str, aliases)
906 char *str;
907 int aliases;
908 {
909 int i = -1, len;
910 char *p;
911
912 select_active(NULL, 2);
913 p = index(str, ' ');
914 if (p)
915 {
916 *p = '\0';
917 while (*p++ == ' ');
918 }
919 else
920 p = "";
921 len = strlen(str);
922
923 while (cmdlist[++i].name)
924 {
925 if (!strncasecmp(cmdlist[i].name, str, len))
926 break;
927 }
928
929 if (aliases)
930 {
931 struct aliaslist_ *atmp = alias;
932 struct aliaslist_ *acmd = NULL;
933
934 while (atmp)
935 {
936 if (!strncasecmp(atmp->name, str, len))
937 {
938 if (len == strlen(atmp->name))
939 break;
940 if (!acmd)
941 acmd = atmp;
942 }
943 atmp = atmp->nexta;
944 }
945 if (atmp)
946 {
947 if (len != strlen(atmp->name) && acmd)
948 {
949 vsic_slog(LOG_CLIENT, "--- %s: Ambiguous command.", str);
950 return;
951 }
952 acmd = atmp;
953 if (cmdlist[i].name && len != strlen(acmd->name))
954 {
955 vsic_slog(LOG_CLIENT, "--- %s: Ambiguous command.", str);
956 return;
957 }
958 parse_alias(acmd, p);
959 return;
960 }
961 }
962
963 if (cmdlist[i].name)
964 {
965 if (len != strlen(cmdlist[i].name)
966 && cmdlist[i+1].name && !strncasecmp(cmdlist[i+1].name, str, len))
967 {
968 vsic_slog(LOG_CLIENT, "--- %s: Ambiguous command.", str);
969 return;
970 }
971
972 if (cmdlist[i].func)
973 switch (cmdlist[i].func(p))
974 {
975 case 0:
976 break;
977 case -1:
978 vsic_slog(LOG_CLIENT, "%s: Not enough parameters.",
979 cmdlist[i].name);
980 break;
981 case -2:
982 vsic_slog(LOG_CLIENT, "%s: No recipient specified.",
983 cmdlist[i].name);
984 break;
985 case -3:
986 vsic_slog(LOG_CLIENT, "%s: No text to send.", cmdlist[i].name);
987 break;
988 case -4:
989 vsic_slog(LOG_CLIENT, "%s: Invalid parameter(s).",
990 cmdlist[i].name);
991 break;
992 case -5:
993 vsic_slog(LOG_CLIENT, "%s: Bind the window to a server first!",
994 cmdlist[i].name);
995 break;
996 case -9:
997 vsic_slog(LOG_CLIENT, "%s: functionality not implemented.",
998 cmdlist[i].name);
999 break;
1000 default:
1001 abort(); /* never */
1002 }
1003 else
1004 vsic_write("%s %s", cmdlist[i].name, p);
1005 }
1006 else
1007 vsic_slog(LOG_CLIENT, "%s: Unknown command.", str);
1008 }
1009