1 /*
2  * ninjacmd.c:
3  *
4  * this file contains code dealing with /commands for ninja irc
5  *
6  * written by Kraig Amador and Joshua J. Drake
7  *
8  */
9 
10 #include "irc.h"
11 #include "dma.h"
12 #include "ircterm.h"
13 #include "vars.h"
14 #include "ircaux.h"
15 #include "server.h"
16 #include "hook.h"
17 #include "window.h"
18 #include "screen.h"
19 #include "output.h"
20 #include "whois.h"
21 #include "parse.h"
22 #include "log.h"
23 #include "notify.h"
24 
25 #include "channels.h"
26 #include "bans.h"
27 #include "info.h"
28 #include "friends.h"
29 #include "enemies.h"
30 #include "hosts.h"
31 #include "how_many.h"
32 #include "grep.h"
33 #include "orignick.h"
34 #include "ninja.h"
35 #include "ckey.h"
36 #include "mileston.h"
37 #include "irc_comm.h"
38 #include "ninjacmd.h"
39 
40 /* little thingy to help /mdop out */
41 static int nodeop _((u_char **, u_char *));
42 
43 /* stuff in edit.c */
44 extern void send_action _((u_char *, u_char *));
45 
46 /* nasty global var!! */
47 int in_update_cmd = 0;
48 
49 /*
50  * does /whois but with the nickname twice
51  */
52 void
whois2(command,args,subargs)53 whois2(command, args, subargs)
54    u_char *command, *args, *subargs;
55 {
56    u_char *nick;
57 
58    if (args && *args)
59       nick = args;
60    else
61       nick = get_server_nickname(from_server);
62    send_to_server("%s %s %s", command, nick, nick);
63 }
64 
65 /*
66  * chhost() changes the source host name and tells the user
67  * to reconnect to the server..
68  */
69 void
chhost(command,args,subargs)70 chhost(command, args, subargs)
71    u_char *command, *args, *subargs;
72 {
73    u_char *nhn;
74 
75    if ((nhn = next_arg(args, &args)) == NULL)
76      {
77 	usage("chhost", "<new host name>");
78 	return;
79      }
80    set_var_value(IRCHOST_VAR, nhn);
81    put_info("Use /reconnect to make changes effective.");
82 }
83 
84 /*
85  *  chuname() changes the username (optionally the hostname and realname field)
86  */
87 void
chuname(command,args,subargs)88 chuname(command, args, subargs)
89    u_char *command, *args, *subargs;
90 {
91    u_char *nun, *nhn = UNULL;
92    u_char *identfn;
93 
94    nun = next_arg(args, &args);
95    if (nun)
96      {
97 	nhn = my_rindex(nun, '@');
98 	if (nhn)
99 	   *nhn++ = '\0';
100      }
101 
102    /* check for a username */
103    if (!nun || my_strlen(nun) < 1)
104      {
105 	usage(command, "<new user name>[@<host>] [<real name field>]");
106 	return;
107      }
108 
109    /* is there a hostname too? */
110    if (nhn)
111      {
112 	if (my_strlen(nhn) > 0)
113 	   set_var_value(IRCHOST_VAR, nhn);
114 	else
115 	  {
116 	     /* zero length host? */
117 	     put_error("Please specify a hostname after the @.");
118 	     return;
119 	  }
120      }
121 
122    /* make the username active */
123    my_strmcpy(username, nun, NAME_LEN - 1);
124 
125    /* if we have an ident file name, update it */
126    if ((identfn = get_string_var(HACKED_IDENTD_VAR)) != NULL)
127      {
128 	FILE *identf;
129 	u_char *ex_idfn = NULL;
130 
131 	if (*identfn == '~')
132 	   ex_idfn = expand_twiddle(identfn);
133 	if (!ex_idfn)
134 	   ex_idfn = identfn;
135 
136 	/* update it */
137 	identf = fopen(ex_idfn, "w");
138 	if (identf == NULL)
139 	   put_error("Unable to write to your HACKED_IDENTD file: %s", strerror(errno));
140 	else
141 	  {
142 	     fprintf(identf, "%s\n", nun);
143 	     fflush(identf);
144 	     fclose(identf);
145 	     put_info("Identity file, \"%s\", updated.", identfn);
146 	  }
147 	if (ex_idfn != identfn)
148 	   dma_Free(&ex_idfn);
149      }
150    /* just a username change? */
151    if (nhn == NULL)
152       put_info("Changed your user name to: %s", nun);
153    else				/* both user and host */
154       put_info("Changed your user@host to: %s@%s", nun, nhn);
155 
156    /* do we have a realname too?! */
157    if (args && *args)
158      {
159 	set_string_var(REALNAME_VAR, realname);
160 	put_info("Changed real name field to: %s", realname);
161      }
162 
163    put_info("Use /reconnect to make changes effective.");
164 }
165 
166 /*
167  * /about command
168  */
169 void
ninja_about(command,args,subargs)170 ninja_about(command, args, subargs)
171    u_char *command, *args, *subargs;
172 {
173    put_info("Ninja IRC v%s, build #%s by %s@%s on %s [%s]",
174 	    irc_version,
175 	    compile_num, compile_user, compile_host, compile_time,
176 	    ninja_release);
177    put_info("");
178    put_info("   started in 1997 with ircII 2.8.2 to");
179    put_info("   pass some time.  i wanted to make");
180    put_info("   ircII look better and have extra features");
181    put_info("   without the slowness of the scripts...");
182    put_info("");
183    put_info("ninja contributors");
184    put_info("");
185    put_info("   Joshua J. Drake         Kraig Amador");
186    put_info("");
187    put_info("bug reports and feedback should be aimed at");
188    put_info("IRC: jduck@EFNet or EMAIL: ninja@qoop.org");
189 }
190 
191 /*
192  * /uptime command
193  */
194 void
uptime(command,args,subargs)195 uptime(command, args, subargs)
196    u_char *command, *args, *subargs;
197 {
198    time_t uptime_val = time(NULL) - start_time;
199 
200    put_info("Your client has been running %s.", ninja_etime(uptime_val));
201    return;
202 }
203 
204 /*
205  * /update command
206  */
207 void
update_cmd(command,args,subargs)208 update_cmd(command, args, subargs)
209    u_char *command, *args, *subargs;
210 {
211    extern int checked_for_update;
212 
213    checked_for_update = 1;
214    in_update_cmd = 1;
215    ninja_check_update(0);
216 #ifndef NON_BLOCKING_CONNECTS
217    in_update_cmd = 0;
218 #endif
219 }
220 
221 #ifdef ALLOW_CHAN_RESYNC
222 /*
223  * re-sync a channel
224  *
225  * this is mostly just a debug command..
226  * if you thing its usefull enough, compile it in...
227  */
228 void
resync(command,args,subargs)229 resync(command, args, subargs)
230    u_char *command, *args, *subargs;
231 {
232    u_char *chan;
233    Channel *tmp;
234 
235    if ((chan = next_arg(args, &args)) == NULL)
236      {
237 	usage(command, "<channel>");
238 	return;
239      }
240    if ((tmp = lookup_channel(make_chan(chan), from_server, 0)) == (Channel *) NULL)
241      {
242 	put_error("You're not on %s", chan);
243 	return;
244      }
245    tmp->status = 0;
246    send_to_server("NAMES %s", tmp->channel);
247    send_to_server("WHO %s", tmp->channel);
248    send_to_server("MODE %s", tmp->channel);
249    send_to_server("MODE %s b", tmp->channel);
250    /*
251       if (my_index(server_list[from_server].cmodes, 'e'))
252       send_to_server("MODE %s e", tmp->channel);
253       if (my_index(server_list[from_server].cmodes, 'd'))
254       send_to_server("MODE %s d", tmp->channel);
255     */
256 }
257 #endif
258 
259 /*
260  * /sc command..
261  */
262 void
ninja_scan(command,args,subargs)263 ninja_scan(command, args, subargs)
264    u_char *command, *args, *subargs;
265 {
266    Channel *chan;
267    Nick *nick;
268    u_char *channel = NULL, ltb[64], tmpbuf1[1024];
269    int count = 0, vcount = 0, ocount = 0;
270    float op_pc, voi_pc;
271 
272    if (args && *args)
273       channel = make_chan(next_arg(args, &args));
274    else if (!get_channel_by_refnum(0))
275      {
276 	put_info("You are not on a channel!");
277 	return;
278      }
279    else
280       channel = get_channel_by_refnum(0);
281    if ((chan = lookup_channel(channel, from_server, 0)))
282      {
283 	u_char *nickstr = NULL, *space = " ", *at = "@", *plus = "+";
284 
285 	if (!(chan->status & CHAN_WHO))
286 	  {
287 	     put_info("Sorry, %s is not totally synched yet, please wait...", chan->channel);
288 	     return;
289 	  }
290 	for (nick = chan->nicks; nick; nick = nick->next)
291 	  {
292 	     if ((nick->status & NICK_CHOP))
293 		dma_strcat(&nickstr, at);
294 	     else if ((nick->status & NICK_VOICE))
295 		dma_strcat(&nickstr, plus);
296 	     dma_strcat(&nickstr, nick->nick);
297 	     if (nick->next)
298 		dma_strcat(&nickstr, space);
299 	  }
300 	if (do_hook(NAMES_LIST, "%s %s", chan->channel, nickstr))
301 	  {
302 	     for (nick = chan->nicks; nick; nick = nick->next)
303 	       {
304 		  if ((nick->status & NICK_VOICE) && !(nick->status & NICK_CHOP))
305 		     vcount++;
306 		  if (nick->status & NICK_CHOP)
307 		     ocount++;
308 		  count++;
309 	       }
310 	     op_pc = ((float) ocount * 100.0) / (float) count;
311 	     voi_pc = ((float) vcount * 100.0) / (float) count;
312 
313 	     snprintf(tmpbuf1, sizeof(tmpbuf1) - 1,
314 		      "--[ Users(%d) on %s ]-[ %.1f%% ops(%d), %.1f%% voiced(%d) ]--",
315 		      count, chan->channel, op_pc, ocount, voi_pc, vcount);
316 	     tmpbuf1[sizeof(tmpbuf1)-1] = '\0';
317 	     put_raw("%s%s", tmpbuf1, strfill('-', current_screen->co - my_strlen(tmpbuf1) - 2));
318 
319 	     tmpbuf1[0] = '\0';
320 	     if (count)
321 	       {
322 		  count = 0;
323 		  for (nick = chan->nicks; nick; nick = nick->next)
324 		    {
325 		       if ((nick->status & NICK_CHOP))
326 			  snprintf(ltb, sizeof(ltb) - 1, "@%-9.9s ", nick->nick);
327 		       else if ((nick->status & NICK_VOICE))
328 			  snprintf(ltb, sizeof(ltb) - 1, "+%-9.9s ", nick->nick);
329 		       else
330 			  snprintf(ltb, sizeof(ltb) - 1, " %-9.9s ", nick->nick);
331 		       ltb[sizeof(ltb)-1] = '\0';
332 		       strmcat(tmpbuf1, ltb, sizeof(tmpbuf1) - 1);
333 		       if (count++ == (((current_screen->co - 2) / 11) - 1))
334 			 {
335 			    put_raw("%s", tmpbuf1);
336 			    *tmpbuf1 = '\0';
337 			    count = 0;
338 			 }
339 		    }
340 		  if (count && tmpbuf1[0])
341 		     put_raw("%s", tmpbuf1);
342 	       }
343 	  }
344 	dma_Free(&nickstr);
345      }
346    else
347      {
348 	put_info("You're not on %s!", channel);
349 	return;
350      }
351 }
352 
353 /*
354  * /users command
355  *
356  * this command attempts to mimic /who but with cached information
357  */
358 void
users(command,args,subargs)359 users(command, args, subargs)
360    u_char *command, *args, *subargs;
361 {
362    Channel *chan;
363    Ban *banptr;
364    Nick *nicks;
365    Enemy *e;
366    EChan *ec;
367    Friend *f;
368    FChan *fc;
369    u_char *channel = NULL, *foo, *foo2;
370    u_char feb[16], format[128], tmpbuf1[384];
371    u_int cwidth, showhops;
372    /* this stuff is for /who comapatability.. */
373    u_char *arg, *nam, *hst, *srv, *file, *nick, *real, *no_open = UNULL;
374    int noargs = 1, len, mask = 0, ok = 1;
375    u_char buf_data[BUFSIZ];
376    FILE *fip;
377 
378    hst = srv = nam = file = nick = real = UNULL;
379    /* parse for [<flags>] */
380    while ((arg = next_arg(args, &args)))
381      {
382 	noargs = 0;
383 	if (*arg == '-' && !isdigit(*(arg + 1)))
384 	  {
385 	     u_char *cmd = UNULL;
386 
387 	     arg++;
388 	     if ((len = my_strlen(arg)) == 0)
389 	       {
390 		  usage(command, "[<flags>] [<channel>]");
391 		  goto out;
392 	       }
393 	     dma_strcpy(&cmd, arg);
394 	     lower(cmd);
395 	     if (my_strncmp(cmd, "operators", len) == 0)
396 		mask |= WHO_OPS;
397 	     else if (my_strncmp(cmd, "lusers", len) == 0)
398 		mask |= WHO_LUSERS;
399 	     else if (my_strncmp(cmd, "chops", len) == 0)
400 		mask |= WHO_CHOPS;
401 	     else if (my_strncmp(cmd, "hosts", len) == 0)
402 	       {
403 		  if ((arg = next_arg(args, &args)) != NULL)
404 		    {
405 		       mask |= WHO_HOST;
406 		       malloc_strcpy(&hst, arg);
407 		       channel = hst;
408 		    }
409 		  else
410 		    {
411 		       usage(command, "-host <hostmask> [<channel>]");
412 		       new_free(&cmd);
413 		       goto out;
414 		    }
415 	       }
416 	     else if (my_strncmp(cmd, "here", len) == 0)
417 		mask |= WHO_HERE;
418 	     else if (my_strncmp(cmd, "away", len) == 0)
419 		mask |= WHO_AWAY;
420 	     else if (my_strncmp(cmd, "servers", len) == 0)
421 	       {
422 		  if ((arg = next_arg(args, &args)) != NULL)
423 		    {
424 		       mask |= WHO_SERVER;
425 		       malloc_strcpy(&srv, arg);
426 		       channel = srv;
427 		    }
428 		  else
429 		    {
430 		       usage(command, "-server <server mask> [<channel>]");
431 		       new_free(&cmd);
432 		       goto out;
433 		    }
434 	       }
435 	     else if (my_strncmp(cmd, "name", len) == 0 || my_strncmp(cmd, "user", len) == 0)
436 	       {
437 		  if ((arg = next_arg(args, &args)) != NULL)
438 		    {
439 		       mask |= WHO_NAME;
440 		       malloc_strcpy(&nam, arg);
441 		       channel = nam;
442 		    }
443 		  else
444 		    {
445 		       usage(command, "-name <username mask> [<channel>]");
446 		       new_free(&cmd);
447 		       goto out;
448 		    }
449 	       }
450 	     else if (my_strncmp(cmd, "realname", len) == 0)
451 	       {
452 		  if ((arg = next_arg(args, &args)) != NULL)
453 		    {
454 		       mask |= WHO_REAL;
455 		       malloc_strcpy(&real, arg);
456 		       channel = real;
457 		    }
458 		  else
459 		    {
460 		       usage(command, "-realname <real mask> [<channel>]");
461 		       new_free(&cmd);
462 		       goto out;
463 		    }
464 	       }
465 	     else if (my_strncmp(cmd, "nick", len) == 0)
466 	       {
467 		  if ((arg = next_arg(args, &args)) != NULL)
468 		    {
469 		       mask |= WHO_NICK;
470 		       malloc_strcpy(&nick, arg);
471 		       channel = who_nick;
472 		    }
473 		  else
474 		    {
475 		       usage(command, "-nick <nick name mask> [<channel>]");
476 		       new_free(&cmd);
477 		       goto out;
478 		    }
479 		  /* WHO -FILE by Martin 'Efchen' Friedrich */
480 	       }
481 	     else if (my_strncmp(cmd, "file", len) == 0)
482 	       {
483 		  mask |= WHO_FILE;
484 		  if ((arg = next_arg(args, &args)) != NULL)
485 		     malloc_strcpy(&file, arg);
486 		  else
487 		    {
488 		       usage(command, "-file <mask file> [<channel>]");
489 		       new_free(&cmd);
490 		       goto out;
491 		    }
492 	       }
493 	     else
494 	       {
495 		  usage(command, "[<flags>] [<channel>]");
496 		  new_free(&cmd);
497 		  goto out;
498 	       }
499 	     new_free(&cmd);
500 	  }
501 	else if (my_strcmp(arg, "*") == 0)
502 	  {
503 	     channel = get_channel_by_refnum(0);
504 	     if (!channel || *channel == '0')
505 	       {
506 		  say("I wouldn't do that if I were you");
507 		  goto out;
508 	       }
509 	  }
510 	else
511 	   channel = arg;
512      }
513    /* get the channel to list */
514    if (noargs)
515       channel = get_channel_by_refnum(0);
516    if (channel && !is_channel(channel))
517       channel = make_chan(channel);
518    if (!channel)
519      {
520 	usage(command, "[<flags>] [<channel>]");
521 	goto out;;
522      }
523 
524    /* are we on the channel? */
525    if ((chan = lookup_channel(channel, from_server, 0)) == NULL)
526      {
527 	put_info("You're not on %s!", channel);
528 	goto out;
529      }
530 
531    /* is the channel fully cached? */
532    if (!(chan->status & CHAN_WHO))
533      {
534 #ifdef SHOW_JOIN_TIME
535 	put_info("Sorry, %s is not cached yet, please wait for the cache message.", chan->channel);
536 #else
537 	put_info("Sorry, %s is not cached yet, please wait..", chan->channel);
538 #endif
539 	goto out;
540      }
541 
542    /* create the format */
543    showhops = get_int_var(SHOW_WHO_HOPCOUNT_VAR);
544    if ((cwidth = get_int_var(CHANNEL_NAME_WIDTH_VAR)) != 0)
545      {
546 	snprintf(format, sizeof(format) - 1, "%%-%u.%us %%-9s |%%-3s", (u_char) cwidth, (u_char) cwidth);
547 	format[sizeof(format)-1] = '\0';
548      }
549    else
550       my_strmcpy(format, "%s\t%-9s |%-3s", sizeof(format) - 1);
551    if (showhops)
552       my_strmcat(format, " %2d", sizeof(format) - 1);
553    my_strmcat(format, "|", sizeof(format) - 1);
554    my_strmcat(format, " %s@%s (%s)", sizeof(format) - 1);
555 
556    /* show them.. */
557    for (nicks = chan->nicks; nicks; nicks = nicks->next)
558      {
559 	ok = 1;
560 
561 	memset(feb, 0, sizeof(feb));
562 	foo = feb;
563 	/* here or away? */
564 	if (nicks->status & NICK_HERE)
565 	   *foo++ = 'H';
566 	if (nicks->status & NICK_AWAY)
567 	   *foo++ = 'G';
568 	/* operator? */
569 	if (nicks->status & NICK_OPER)
570 	   *foo++ = '*';
571 	/* opped? */
572 	if (nicks->status & NICK_CHOP)
573 	   *foo++ = '@';
574 	/* voiced? */
575 	if (nicks->status & NICK_VOICE)
576 	   *foo++ = '+';
577 
578 /* enemy? *//* XXX: NEED TO CREATE GET_ENEMY_BY_NUH() */
579 	foo2 = nicks->user;
580 	if (foo2 && *foo2 == '~')
581 	   foo2++;
582 	snprintf(tmpbuf1, sizeof(tmpbuf1) - 1, "%s!%s@%s", nicks->nick, foo2 ? foo2 : empty_string, nicks->host);
583 	tmpbuf1[sizeof(tmpbuf1)-1] = '\0';
584 
585 	if ((e = get_enemy(tmpbuf1)) != NULL && (ec = get_enemy_chan(e, chan->channel, 0)) != NULL)
586 	   *foo++ = 'E';
587 
588 	/* banned? */
589 	for (banptr = chan->bans; banptr; banptr = banptr->next)
590 	  {
591 	     if (wild_match(banptr->ban, tmpbuf1))
592 	       {
593 		  *foo++ = 'B';
594 		  break;
595 	       }
596 	  }
597 
598 	/* friend? */
599 	f = get_friend_by_mask(tmpbuf1);
600 	if (f)
601 	  {
602 	     *foo++ = 'F';
603 	     if ((fc = get_fchan(f, chan->channel, 0)))
604 		*foo++ = 'C';
605 	  }
606 
607 	/* realname cached? */
608 	if (nicks->realname)
609 	   foo = nicks->realname;
610 	else
611 	   foo = empty_string;
612 
613 	/* check for mask flags */
614 	if (mask)
615 	  {
616 	     if (mask & WHO_HERE)
617 		ok = ok && (nicks->status & NICK_HERE);
618 	     if (mask & WHO_AWAY)
619 		ok = ok && (nicks->status & NICK_AWAY);
620 	     if (mask & WHO_OPS)
621 		ok = ok && (nicks->status & NICK_OPER);
622 	     if (mask & WHO_LUSERS)
623 		ok = ok && !(nicks->status & NICK_OPER);
624 	     if (mask & WHO_CHOPS)
625 		ok = ok && (nicks->status & NICK_CHOP);
626 	     if (mask & WHO_NAME)
627 		ok = ok && wild_match(nam, nicks->user);
628 	     if (mask & WHO_NICK)
629 		ok = ok && wild_match(nick, nicks->nick);
630 	     if (mask & WHO_HOST)
631 		ok = ok && wild_match(hst, nicks->host);
632 	     if (mask & WHO_REAL)
633 		ok = ok && wild_match(real, nicks->realname);
634 	     if (mask & WHO_SERVER)
635 		ok = ok && wild_match(srv, nicks->server);
636 	     if (mask & WHO_FILE)
637 	       {
638 		  ok = 0;
639 		  if ((fip = fopen(CP(file), "r")) != (FILE *) 0)
640 		    {
641 		       while (fgets((char *) buf_data, BUFSIZ, fip) != (char *) 0)
642 			 {
643 			    buf_data[my_strlen(buf_data) - 1] = '\0';
644 			    ok = ok || wild_match(buf_data, nicks->nick);
645 			 }
646 		       fclose(fip);
647 		    }
648 		  else
649 		     no_open = file;
650 	       }
651 	  }
652 
653 	/* show the line! */
654 	if (ok && do_hook(WHO_LIST, "%s %s %s %s %s %s", chan->channel, nicks->nick, feb, nicks->user, nicks->host, foo))
655 	  {
656 	     if (showhops)
657 		put_raw(format, chan->channel, nicks->nick, feb, nicks->hops, nicks->user, nicks->host, foo);
658 	     else
659 		put_raw(format, chan->channel, nicks->nick, feb, nicks->user, nicks->host, foo);
660 	  }
661      }
662    if (no_open)
663       put_error("Cannot open: %s", no_open);
664  out:
665    dma_Free(&hst);
666    dma_Free(&srv);
667    dma_Free(&nam);
668    dma_Free(&real);
669    dma_Free(&nick);
670    dma_Free(&file);
671 }
672 
673 /*
674  * just leave a channel and join it
675  */
676 void
cycle(command,args,subargs)677 cycle(command, args, subargs)
678    u_char *command, *args, *subargs;
679 {
680    u_char *tmpchannel = UNULL, tmpbuf[1024];
681    Channel *chan;
682 
683    if (args && *args)
684       tmpchannel = make_chan(next_arg(args, &args));
685    else if (!get_channel_by_refnum(0))
686      {
687 	put_info("You are not on a channel!");
688 	return;
689      }
690    else
691       tmpchannel = get_channel_by_refnum(0);
692 
693    if ((chan = lookup_channel(tmpchannel, from_server, 0)) == NULL)
694      {
695 	put_info("You are not on %s!", tmpchannel);
696 	return;
697      }
698 
699    my_strmcpy(tmpbuf, chan->channel, sizeof(tmpbuf) - 1);
700    if (chan->key)
701      {
702 	my_strmcat(tmpbuf, " ", sizeof(tmpbuf) - 1);
703 	my_strmcat(tmpbuf, chan->key, sizeof(tmpbuf) - 1);
704      }
705    send_to_server("PART %s", tmpchannel);
706    send_to_server("JOIN %s", tmpbuf);
707 }
708 
709 /*
710  * send a message to all ops on a channel
711  *
712  * note, this is currently broken due to the nick,nick,nick support
713  * in most servers being broken.
714  */
715 void
do_wall(command,args,subargs)716 do_wall(command, args, subargs)
717    u_char *command, *args, *subargs;
718 {
719    u_char *channel;
720    Nick *nickl;
721    Channel *chanl;
722 
723    if (!args || !*args)
724      {
725 	usage(command, "[<channel>] <message>");
726 	return;
727      }
728 
729    if (is_channel(args))
730       channel = next_arg(args, &args);
731    else if ((channel = get_channel_by_refnum(0)) == NULL)
732      {
733 	put_info("You're not on a channel.");
734 	return;
735      }
736 
737    /* am i on the channel? */
738    chanl = lookup_channel(channel, from_server, 0);
739    if (!chanl)
740      {
741 	put_error("You're not on %s.", channel);
742 	return;
743      }
744    else
745      {
746 	u_char wallline[1024], ops[1024];
747 	int count = 0, opcount = 0;
748 	int first = 1;
749 
750 	/* what are we going to send everyone? */
751 	snprintf(wallline, sizeof(wallline) - 1, "(%s WallOp) %s", channel, args);
752 	wallline[sizeof(wallline)-1] = '\0';
753 
754 	/* who are we going to send it to? */
755 	ops[0] = '\0';
756 	for (nickl = chanl->nicks; nickl; nickl = nickl->next)
757 	   if ((nickl->status & NICK_CHOP) && (strcmp(nickl->nick, nickname) != 0))
758 	     {
759 		if (first)
760 		  {
761 		     snprintf(ops, sizeof(ops) - 1, "%s,", nickl->nick);
762 		     ops[sizeof(ops)-1] = '\0';
763 		     first = 0;
764 		  }
765 		else
766 		  {
767 		     strmcat(ops, nickl->nick, sizeof(ops) - 1);
768 		     strmcat(ops, ",", sizeof(ops) - 1);
769 		  }
770 		count++;
771 		opcount++;
772 		if (count == 10)
773 		  {
774 		     count = 0;
775 		     first = 1;
776 		     send_to_server("NOTICE %s :%s", ops, wallline);
777 		     ops[0] = '\0';
778 		  }
779 	     }
780 	send_to_server("NOTICE %s :%s", ops, wallline);
781 	put_raw("-> (sent %d) %s", opcount, wallline);
782      }
783 }
784 
785 /*
786  * this handles kick and bankick
787  *
788  * 09/27/01 cleaned up/optimized by jjd
789  */
790 void
do_special_k(command,args,subargs)791 do_special_k(command, args, subargs)
792    u_char *command, *args, *subargs;
793 {
794    u_char *person, *channel, *reason = NULL;
795    Channel *chanl;
796 
797    if (!args || !*args)
798      {
799 	usage(command, "[<channel>] <nick> [<reason>]");
800 	return;
801      }
802 
803    if (is_channel(args))
804       channel = next_arg(args, &args);
805    else if ((channel = get_channel_by_refnum(0)) == NULL)
806      {
807 	put_info("You're not on a channel.");
808 	return;
809      }
810 
811    /* am i on the channel? */
812    chanl = lookup_channel(channel, from_server, 0);
813    if (!chanl)
814      {
815 	put_error("You're not on %s.", channel);
816 	return;
817      }
818 
819    if (!(chanl->status & CHAN_CHOP))
820      {
821 	put_error("You're not opped on %s.", channel);
822 	return;
823      }
824    else
825      {
826 	person = next_arg(args, &args);
827 	if (!is_on_channel(channel, from_server, person))
828 	  {
829 	     put_error("Hey! %s is not on %s!", person, channel);
830 	     return;
831 	  }
832 	/* do i have a reason? */
833 	if (args && *args)
834 	   reason = args;
835 	else
836 	   reason = UP("out!");
837 	/* should we ban them too? */
838 	if (*command == 'B' || my_strcmp(command, "KICKBAN") == 0 || my_strcmp(command, "KB") == 0)
839 	   do_ban_stuff("BAN", person, channel);
840 	/* kick them */
841 	send_to_server("KICK %s %s :%s", chanl->channel, person, reason);
842      }
843 }
844 
845 /*
846  * this handles /fk and /fbk
847  *
848  * 09/27/01 cleaned up/optimized by jjd
849  */
850 void
filter_kick(command,args,subargs)851 filter_kick(command, args, subargs)
852    u_char *command, *args, *subargs;
853 {
854    u_char *channel, *nuhmask, reason[128];
855    int ban = 0, old_limit, count = 0;
856    Channel *chanl;
857    Nick *nickl;
858 
859    if (my_strcmp(command, "FBK") == 0)
860       ban = 1;
861 
862    /* check for a mask */
863    nuhmask = next_arg(args, &args);
864    if (!nuhmask)
865      {
866 	usage(command, "<filter mask> [<channel> [<reason>]]");
867 	return;
868      }
869    if (!my_index(nuhmask, '!') || !my_index(nuhmask, '@'))
870      {
871 	put_error("You must specify a valid nick!user@host mask.");
872 	return;
873      }
874 
875    /* check out the channel situation */
876    if (args && is_channel(args))
877       channel = next_arg(args, &args);
878    else
879       channel = get_channel_by_refnum(0);
880    if (!channel)
881      {
882 	put_info("You're not on a channel.");
883 	return;
884      }
885 
886    /* see if i'm on the channel */
887    chanl = lookup_channel(channel, from_server, 0);
888    if (!chanl)
889      {
890 	put_error("You're not on %s.", channel);
891 	return;
892      }
893    if (!(chanl->status & CHAN_CHOP))
894      {
895 	put_error("You're not opped on %s.", channel);
896 	return;
897      }
898 
899    /* do we have a reason? */
900    if (args && *args)
901       my_strmcpy(reason, args, sizeof(reason) - 1);
902    else
903      {
904 	my_strmcpy(reason, "You match ", sizeof(reason) - 1);
905 	my_strmcat(reason, nuhmask, sizeof(reason) - 1);
906      }
907 
908    /* initial pass to see if anyone matches.. */
909    for (nickl = chanl->nicks; nickl; nickl = nickl->next)
910      {
911 	u_char nuh[384], *foo;
912 
913 	/* don't kick myself!! */
914 	if (my_stricmp(nickl->nick, get_server_nickname(chanl->server)) == 0)
915 	  continue;
916 	foo = nickl->user;
917 	if (*foo == '~')
918 	  foo++;
919 	snprintf(nuh, sizeof(nuh) - 1, "%s!*%s@%s", nickl->nick, foo, nickl->host);
920 	nuh[sizeof(nuh)-1] = '\0';
921 	if (wild_match(nuhmask, nuh))
922 	  count++;
923      }
924 
925    if (count < 1)
926      {
927 	put_error("Nobody on %s matches %s!", channel, nuhmask);
928 	return;
929      }
930 
931    /* if we are supposed to ban them, do it last, but for now, +l 1 */
932    old_limit = chanl->limit;
933    if (ban)
934      send_to_server("MODE %s +l 1", channel);
935 
936    /* kick those foolz */
937    for (nickl = chanl->nicks; nickl; nickl = nickl->next)
938      {
939 	u_char nuh[384], *foo;
940 
941 	/* don't kick myself!! */
942 	if (my_stricmp(nickl->nick, get_server_nickname(chanl->server)) == 0)
943 	   continue;
944 	foo = nickl->user;
945 	if (*foo == '~')
946 	   foo++;
947 	snprintf(nuh, sizeof(nuh) - 1, "%s!*%s@%s", nickl->nick, foo, nickl->host);
948 	nuh[sizeof(nuh)-1] = '\0';
949 	if (wild_match(nuhmask, nuh))
950 	   send_to_server("KICK %s %s :%s", chanl->channel, nickl->nick, reason);
951      }
952 
953    /* add the ban and restore the limit if necessary */
954    if (ban)
955      send_to_server("MODE %s +b %s", channel, nuhmask);
956    if (old_limit > 0)
957      send_to_server("MODE %s +l %u", channel, old_limit);
958    else
959      send_to_server("MODE %s -l", channel);
960 }
961 
962 /*
963  * kick all non-ops out of a channel
964  */
965 void
lamer_kick(command,args,subargs)966 lamer_kick(command, args, subargs)
967    u_char *command, *args, *subargs;
968 {
969    u_char *chan, reason[128];
970    Nick *nickl;
971    Channel *chanl;
972 
973    chan = next_arg(args, &args);
974    if (!chan)
975      {
976 	usage(command, "<channel> [<reason>]");
977 	return;
978      }
979    chan = make_chan(chan);
980 
981    /* make sure i'm on the channel */
982    chanl = lookup_channel(chan, from_server, 0);
983    if (!chanl)
984      {
985 	put_error("You're not on %s.", chan);
986 	return;
987      }
988 
989    /* make sure i can kick */
990    if (!(chanl->status & CHAN_CHOP))
991      {
992 	put_error("You're not opped on %s.", chan);
993 	return;
994      }
995 
996    /* setup the reason */
997    if (args && *args)
998      {
999 	my_strmcpy(reason, args, sizeof(reason) - 1);
1000 	my_strmcat(reason, " (", sizeof(reason) - 1);
1001 	my_strmcat(reason, "non-op", sizeof(reason) - 1);
1002 	my_strmcat(reason, ")", sizeof(reason) - 1);
1003      }
1004    else
1005       my_strmcpy(reason, "non-op", sizeof(reason) - 1);
1006 
1007    /* kick those lamers! */
1008    for (nickl = chanl->nicks; nickl; nickl = nickl->next)
1009       if (!(nickl->status & NICK_CHOP))
1010 	 send_to_server("KICK %s %s :%s", chan, nickl->nick, reason);
1011 }
1012 
1013 /*
1014  * give_or_take_ops() does a standard:
1015  * /mode [<channel>] +/-o[ooo] <nick> [.. .. ..]
1016  *
1017  * it gives/takes ops to/from all people in the args that are
1018  * on the specified channel (or current if no channel is specified)
1019  *
1020  * 07/05/97 does voice too. FUNCTION OVERLOAD!@#
1021  * 09/27/01 cleanup/optimization by jjd
1022  */
1023 void
give_or_take_ops(command,args,subargs)1024 give_or_take_ops(command, args, subargs)
1025    u_char *command, *args, *subargs;
1026 {
1027    u_char *opchan = UNULL;
1028    char *mstr = NULL;
1029    u_char sign, mch;
1030    int num_nicks = 0;
1031 
1032    /* do we have a channel? */
1033    if (is_channel(args))
1034      {
1035 	opchan = next_arg(args, &args);
1036 	if (!(args && *args))
1037 	  {
1038 	     usage(command, "[#/&<channel>] <nick1> ... <nickn>");
1039 	     return;
1040 	  }
1041      }
1042    else if ((opchan = get_channel_by_refnum(0)) == NULL)
1043      {
1044 	put_info("You are not on any channels!");
1045 	return;
1046      }
1047 
1048    /* plus or minus? */
1049    if ((my_strncmp(command, "OP", 2) == 0) || (my_strncmp(command, "VOICE", 5) == 0))
1050       sign = '+';
1051    else
1052       sign = '-';
1053 
1054    /* voice or ops? */
1055    if (!my_strncmp(command, "VOICE", 5) || !my_strncmp(command, "DVOICE", 6))
1056       mch = 'v';
1057    else
1058       mch = 'o';
1059 
1060    /* how many people were specified? */
1061    num_nicks = how_many(args, ' ') + 1;
1062    if (num_nicks >= 4)
1063       mstr = strfill(mch, 4);
1064    while (num_nicks >= 4)
1065      {
1066 	u_char *nick1 = NULL, *nick2 = NULL, *nick3 = NULL, *nick4 = NULL;
1067 
1068 	nick1 = next_arg(args, &args);
1069 	nick2 = next_arg(args, &args);
1070 	nick3 = next_arg(args, &args);
1071 	nick4 = next_arg(args, &args);
1072 	send_to_server("MODE %s %c%s %s %s %s %s", opchan, sign, mstr, nick1, nick2, nick3, nick4);
1073 	num_nicks -= 4;
1074      }
1075    if (num_nicks > 0)
1076      {
1077 	mstr = strfill(mch, num_nicks);
1078 	send_to_server("MODE %s %c%s %s", opchan, sign, mstr, args);
1079      }
1080 }
1081 
1082 #ifdef ALLOW_OJ			/* lets see if anyone misses, i won't */
1083 /*
1084  * on join ?
1085  * for /oj (op the last person to join)
1086  * this is bloat.
1087  */
1088 void
oj(char * command,char * args,char * subargs)1089 oj(char *command, char *args, char *subargs)
1090 {
1091    extern *joined_chan;
1092 
1093    if (!joined_nick)
1094       return;
1095    else
1096       send_to_server("MODE %s +o %s", joined_chan, joined_nick);
1097 }
1098 #endif
1099 
1100 /*
1101  * change a channel's key
1102  *
1103  * 09/27/01 cleaned up/optimized by jjd
1104  */
1105 void
chkey(command,args,subargs)1106 chkey(command, args, subargs)
1107    u_char *command, *args, *subargs;
1108 {
1109    u_char *mychan = NULL, *newkey = NULL;
1110    Channel *chan;
1111 
1112    if (!(args && *args))
1113      {
1114 	usage("chkey", "[<channel>] -|<new key>");
1115 	return;
1116      }
1117    newkey = next_arg(args, &args);
1118    if (args && *args)
1119      {
1120 	mychan = make_chan(newkey);
1121 	newkey = next_arg(args, &args);
1122      }
1123    else if (!get_channel_by_refnum(0))
1124      {
1125 	put_info("You are not on any channels!");
1126 	return;
1127      }
1128    else
1129       mychan = get_channel_by_refnum(0);
1130 
1131    /* am i on the channel? */
1132    chan = lookup_channel(mychan, from_server, 0);
1133    if (!chan)
1134      {
1135 	put_info("You are not on %s.", mychan);
1136 	return;
1137      }
1138 
1139    /* check for ops */
1140    if (!(chan->status & CHAN_CHOP))
1141      {
1142 	put_info("Changing the key requires ops.");
1143 	return;
1144      }
1145 
1146    /* change the key */
1147    if (chan->key)
1148       send_to_server("MODE %s -k %s", mychan, chan->key);
1149    if (my_strcmp(newkey, "-") != 0)
1150       send_to_server("MODE %s +k %s", mychan, newkey);
1151 }
1152 
1153 /*
1154  * change the channel limit
1155  */
1156 void
change_channel_limit(command,args,subargs)1157 change_channel_limit(command, args, subargs)
1158    u_char *command, *args, *subargs;
1159 {
1160    u_char *limit, *chann;
1161    long ldlimit;
1162 
1163    limit = next_arg(args, &args);
1164    if (!limit)
1165      {
1166 	usage(command, "<limit/-> [<channel>]");
1167 	return;
1168      }
1169 
1170    /* check out the channel situation */
1171    if (((chann = next_arg(args, &args)) != NULL) && (my_strcmp(chann, "*") != 0))
1172       chann = (u_char *) make_chan(chann);
1173    else if ((chann = get_channel_by_refnum(0)) == NULL)
1174      {
1175 	put_info("You are not on a channel.");
1176 	return;
1177      }
1178 
1179    ldlimit = my_atol(limit);
1180    if (ldlimit > 0)
1181       send_to_server("MODE %s +l %ld", chann, ldlimit);
1182    else if (my_strcmp(limit, "-") == 0)
1183       send_to_server("MODE %s -l", chann);
1184    else
1185       put_error("Invalid channel limit: %s", limit);
1186 }
1187 
1188 /*
1189  * mass modes!
1190  */
1191 void
mass(command,args,subargs)1192 mass(command, args, subargs)
1193    u_char *command, *args, *subargs;
1194 {
1195    Channel *chanl;
1196    Nick *nickl;
1197    u_char *type, *chann;
1198    u_char mode;
1199    int dickmode = 0, count = 0;
1200    u_char tmpbuf1[1024];
1201 
1202    if (!args || !*args)
1203      {
1204 	usage(command, "[+|-]<mode> [<channel>]");
1205 	return;
1206      }
1207    type = next_arg(args, &args);
1208    if (*type == '-')
1209       dickmode = 1;
1210    if (!isalpha(*type))
1211       type++;
1212    switch (*type)
1213      {
1214 	case 'v':
1215 	   mode = 'v';
1216 	   break;
1217 	case 'o':
1218 	   mode = 'o';
1219 	   break;
1220 	default:
1221 	   usage(command, "[+|-]<mode> [<channel>]");
1222 	   return;
1223      }
1224    if ((chann = next_arg(args, &args)) == NULL)
1225       if ((chann = get_channel_by_refnum(0)) == NULL)
1226 	{
1227 	   put_error("You must by on a channel to do mass modes..");
1228 	   return;
1229 	}
1230    chann = (u_char *) make_chan(chann);
1231    if ((chanl = lookup_channel(chann, from_server, 0)) == NULL)
1232      {
1233 	put_error("You're not on %s!", chann);
1234 	return;
1235      }
1236    if (!is_chanop(chann, get_server_nickname(from_server)))
1237      {
1238 	put_error("You must be opped to do mass modes.", chann);
1239 	return;
1240      }
1241    put_info("Executing a mass %s%c on %s.", dickmode ? "-" : "+", mode, chanl->channel);
1242    if ((mode == 'o') && dickmode)
1243      {
1244 	mdop("MDOP", chanl->channel, NULL);
1245 	return;
1246      }
1247    bzero(tmpbuf1, sizeof(tmpbuf1));
1248    for (nickl = chanl->nicks; nickl; nickl = nickl->next)
1249      {
1250 	if (my_strcmp(nickl->nick, get_server_nickname(from_server)) != 0)
1251 	  {
1252 	     if ((dickmode && mode == 'v' && (nickl->status & NICK_VOICE)) ||
1253 		 (!dickmode && mode == 'v' && !(nickl->status & NICK_VOICE) && !(nickl->status & NICK_CHOP)) ||
1254 		 (!dickmode && mode == 'o' && !(nickl->status & NICK_CHOP)))
1255 	       {
1256 		  strmcat(tmpbuf1, " ", sizeof(tmpbuf1) - 1);
1257 		  strmcat(tmpbuf1, nickl->nick, sizeof(tmpbuf1) - 1);
1258 		  count++;
1259 	       }
1260 	  }
1261 	if (count == 4)
1262 	  {
1263 	     count = 0;
1264 	     send_to_server("MODE %s %s%s %s", chanl->channel, dickmode ? "-" : "+", strfill(mode, 4), tmpbuf1);
1265 	     bzero(tmpbuf1, sizeof(tmpbuf1));
1266 	  }
1267      }
1268    send_to_server("MODE %s %s%s %s", chanl->channel, dickmode ? "-" : "+", strfill(mode, count), tmpbuf1);
1269    return;
1270 }
1271 
1272 /* dispatcher for abbreviated /mass commands:
1273  *  /mop, /mvoice, /mdvoice
1274  */
1275 void
mass_abbrev(command,args,subargs)1276 mass_abbrev(command, args, subargs)
1277    u_char *command, *args, *subargs;
1278 {
1279    u_char *tmp;
1280 
1281    tmp = (u_char *) dma_Malloc(strlen(args) + 4);
1282    if (strcmp(command, "MOP") == 0)
1283      {
1284 	sprintf(tmp, "+o %s", args);	/* safe, malloc()'d */
1285 	mass("MOP", tmp, NULL);
1286      }
1287    else if (strcmp(command, "MVOICE") == 0)
1288      {
1289 	sprintf(tmp, "+v %s", args);	/* safe, malloc()'d */
1290 	mass("MVOICE", tmp, NULL);
1291      }
1292    else if (strcmp(command, "MDVOICE") == 0)
1293      {
1294 	sprintf(tmp, "-v %s", args);	/* safe, malloc()'d */
1295 	mass("MDVOICE", tmp, NULL);
1296      }
1297    dma_Free(&tmp);
1298 }
1299 
1300 /*
1301  * super k-rad elite MASS DEOP code
1302  */
1303 void
mdop(command,args,subargs)1304 mdop(command, args, subargs)
1305    u_char *command, *args, *subargs;
1306 {
1307 #define DEADPPL_SIZE 1024
1308 #define MAX_DEADPPL 200
1309 #define MAX_SAFEPPL 20
1310 #define NINJA_BAN_MASK "ninja!irc@rulez"
1311    u_char *chann, deadppl[DEADPPL_SIZE][MAX_DEADPPL], *safeppl[MAX_SAFEPPL];
1312    u_char tmpbuf1[1024];
1313    Channel *chanl;
1314    Nick *nicks;
1315    int count = 0, lines = 0, i = 0, safecnt = 0, test = 0;
1316 
1317    chann = next_arg(args, &args);
1318    if (chann && my_strcmp(chann, "-t") == 0)
1319      {
1320 	test = 1;
1321 	chann = next_arg(args, &args);
1322      }
1323    if (!chann)
1324      {
1325 	usage(command, "[-t] <channel> [<nicks not to deop>]");
1326 	return;
1327      }
1328    /* zero out deadppl and safeppl.. */
1329    for (i = 0; i < MAX_DEADPPL; i++)
1330      *deadppl[i] = 0;
1331    for (i = 0; i < MAX_SAFEPPL; i++)
1332      safeppl[i] = NULL;
1333 
1334    if (my_strlen(args) > 0)
1335      {
1336 	put_info("I promise not to deop: %s", args);
1337 	safeppl[safecnt] = next_arg(args, &args);
1338 	while (safeppl[safecnt] != NULL)
1339 	  {
1340 	     safecnt++;
1341 	     safeppl[safecnt] = next_arg(args, &args);
1342 	  }
1343      }
1344    if (my_strcmp(chann, asterik) == 0)
1345       chann = get_channel_by_refnum(0);
1346    else
1347       chann = (u_char *) make_chan(chann);
1348    if (!chann || !(chanl = lookup_channel(chann, from_server, CHAN_NOUNLINK)))
1349      {
1350 	put_error("You're not on %s!", chann);
1351 	return;
1352      }
1353    if (!test && !(chanl->status & CHAN_CHOP))
1354      {
1355 	put_error("You must be opped to mass de-op!");
1356 	return;
1357      }
1358    bzero(tmpbuf1, sizeof(tmpbuf1));
1359    for (nicks = chanl->nicks; nicks; nicks = nicks->next)
1360      {
1361 	if ((strcmp(get_server_nickname(from_server), nicks->nick) != 0) &&
1362 	    (nicks->status & NICK_CHOP) && !nodeop(safeppl, nicks->nick))
1363 	  {
1364 	     if (*tmpbuf1)
1365 	       {
1366 		  strmcat(tmpbuf1, " ", sizeof(tmpbuf1) - 1);
1367 		  strmcat(tmpbuf1, nicks->nick, sizeof(tmpbuf1) - 1);
1368 	       }
1369 	     else
1370 		snprintf(tmpbuf1, sizeof(tmpbuf1), "%s", nicks->nick);
1371 	     count++;
1372 	  }
1373 	if (count == 3)
1374 	  {
1375 	     snprintf(deadppl[lines], DEADPPL_SIZE - 1, "MODE %s -b%s %s %s", chanl->channel,
1376 		      strfill('o', count), NINJA_BAN_MASK, tmpbuf1);
1377 	     *(deadppl[lines] + DEADPPL_SIZE - 1) = '\0';
1378 	     lines++;
1379 	     count = 0;
1380 	     *tmpbuf1 = '\0';
1381 	  }
1382      }
1383    if (count)
1384      {
1385 	snprintf(deadppl[lines], DEADPPL_SIZE - 1, "MODE %s -b%s %s %s", chanl->channel,
1386 		 strfill('o', count), NINJA_BAN_MASK, tmpbuf1);
1387 	*(deadppl[lines] + DEADPPL_SIZE - 1) = '\0';
1388 	lines++;
1389      }
1390    if (lines == 0)
1391      {
1392 	put_error("Nobody on %s is opped.", chanl->channel);
1393 	return;
1394      }
1395    for (i = 0; i < lines; i++)
1396      {
1397 	if (test)
1398 	   put_raw("%s", deadppl[i]);
1399 	else
1400 	   send_to_server("%s", deadppl[i]);
1401      }
1402 }
1403 
1404 /* this goes with /mdop */
1405 static int
nodeop(u_char * ppl[],u_char * user)1406 nodeop(u_char * ppl[], u_char * user)
1407 {
1408    int blehcnt = 0;
1409 
1410    if (ppl[blehcnt] == NULL)
1411       return 0;
1412    do
1413      {
1414 	if (!my_stricmp(ppl[blehcnt], user))
1415 	   return 1;
1416 	blehcnt++;
1417      }
1418    while (ppl[blehcnt] != NULL);
1419    return 0;
1420 }
1421 
1422 /*
1423  * ban/unban masks/nicks
1424  */
1425 void
do_ban_stuff(command,args,subargs)1426 do_ban_stuff(command, args, subargs)
1427    u_char *command, *args, *subargs;
1428 {
1429    int meany;
1430    u_char *person, *chann, *evil = NULL;
1431    u_char *ex, *at;
1432    Nick *nicks;
1433    Channel *c;
1434 
1435    if (command[0] == 'B')
1436       meany = 1;
1437    else
1438       meany = 0;
1439    if ((person = next_arg(args, &args)) != NULL)
1440      {
1441 	chann = next_arg(args, &args);
1442 	if (!chann)
1443 	   chann = get_channel_by_refnum(0);
1444 	if (!chann || !*chann)
1445 	  {
1446 	     put_info("You're not on a channel.");
1447 	     return;
1448 	  }
1449 	if (!is_channel(chann))
1450 	   chann = make_chan(chann);
1451 	/* now we should have a valid channel */
1452 	c = lookup_channel(chann, from_server, CHAN_NOUNLINK);
1453 	if (!c)
1454 	   return;
1455 
1456 	if (!(c->status & CHAN_CHOP))
1457 	  {
1458 	     put_info("You have no ops to add/remove bans with!");
1459 	     return;
1460 	  }
1461 
1462 	/* if we are specifying a mask instead of a nickname */
1463 	ex = my_index(person, '!');
1464 	at = my_index(person, '@');
1465 	if (ex || at)
1466 	  {
1467 	     u_char theshiz[512];
1468 
1469 	     if (!at && ex)
1470 		snprintf(theshiz, sizeof(theshiz) - 1, "%s@*", person);
1471 	     else if (at && !ex)
1472 		snprintf(theshiz, sizeof(theshiz) - 1, "*!%s", person);
1473 	     else
1474 		my_strncpy(theshiz, person, sizeof(theshiz) - 1);
1475 	     theshiz[sizeof(theshiz)-1] = '\0';
1476 	     if (meany)
1477 		send_to_server("MODE %s +b %s", chann, theshiz);
1478 	     else
1479 		remove_matching_bans(theshiz, NULL, NULL, chann, 0);
1480 	     return;
1481 	  }
1482 	else if ((nicks = find_nick(person, UNULL, from_server, c)) != NULL)
1483 	  {
1484 	     u_char *user = nicks->user;
1485 
1486 	     if (user && *user == '~')
1487 		user++;
1488 	     if (user && *user)
1489 		user++;
1490 	     if (meany)
1491 	       {
1492 		  if (nicks->status & NICK_CHOP)
1493 		     send_to_server("MODE %s -o+b %s *!*%s@%s", chann, nicks->nick, user, cluster(nicks->host));
1494 		  else
1495 		     send_to_server("MODE %s +b *!*%s@%s", chann, user, cluster(nicks->host));
1496 	       }
1497 	     else
1498 		remove_matching_bans(nicks->nick, user, nicks->host, chann, 0);
1499 	     evil--;
1500 	     return;
1501 	  }
1502 	if (meany)
1503 	   add_to_whois_queue(person, ban_queue, "%s", chann);
1504 	else
1505 	   add_to_whois_queue(person, unban_queue, "%s", chann);
1506      }
1507    else
1508       usage(command, "<nick/mask> [<channel>]");
1509 }
1510 
1511 /*
1512  * /adds
1513  */
1514 void
addserver(command,args,subargs)1515 addserver(command, args, subargs)
1516    u_char *command, *args, *subargs;
1517 {
1518    int port_num = 0;
1519    int old_server = 0;
1520    u_char *password, *port, *nick, *server, *extra, *umode;
1521 
1522    if (!(args && *args))
1523      {
1524 	usage("adds", "<server>[:<port>:<password>:<nick>:<umode>]");
1525 	return;
1526      }
1527    password = port = nick = extra = umode = UNULL;
1528    server = next_arg(args, &args);
1529    parse_server_info(&server, &port, &password, &nick, &umode, &extra);
1530    if (port && *port)
1531      {
1532 	port_num = my_atoi(port);
1533 	if (!port_num)
1534 	   port_num = irc_port;
1535      }
1536    else
1537       port_num = irc_port;
1538    old_server = from_server;
1539    add_to_server_list(server, port_num, password, nick, umode, 0);
1540    from_server = old_server;
1541    put_info("%s %d added to your server list.", server, port_num);
1542 }
1543 
1544 /*
1545  * /rems
1546  */
1547 void
removeserver(command,args,subargs)1548 removeserver(command, args, subargs)
1549    u_char *command, *args, *subargs;
1550 {
1551    int port_num = 0;
1552    int old_server = 0;
1553    int servernum = 0;
1554    u_char *password, *port, *nick, *server, *extra, *umode;
1555 
1556    if (!(args && *args))
1557      {
1558 	usage("rems", "<#> or <server>[:<port>]");
1559 	return;
1560      }
1561    password = port = nick = extra = umode = UNULL;
1562    server = next_arg(args, &args);
1563    parse_server_info(&server, &port, &password, &nick, &umode, &extra);
1564    if (port && *port)
1565      {
1566 	port_num = my_atoi(port);
1567 	if (!port_num)
1568 	   port_num = irc_port;
1569      }
1570    else
1571       port_num = irc_port;
1572 
1573    old_server = from_server;
1574    if ((servernum = atoi(server)) > 0 && servernum <= number_of_servers)
1575       servernum--;
1576    else
1577       servernum = find_in_server_list(server, port_num, NULL);
1578 
1579    if (servernum < 0 || servernum >= number_of_servers)
1580      {
1581 	put_info("Unable to locate server \"%s\" in the server list.", server);
1582 	return;
1583      }
1584 
1585    if (server_list[servernum].connected || server_list[servernum].read != -1)
1586       put_info("Server #%d (%s:%d) is connected, not removing.", servernum + 1, server_list[servernum].name,
1587 	       server_list[servernum].port);
1588    else
1589      {
1590 	put_info("Removed server #%d (%s:%d) from your list.", servernum + 1, server_list[servernum].name,
1591 		 server_list[servernum].port);
1592 	remove_from_server_list(servernum);
1593      }
1594    from_server = old_server;
1595 }
1596 
1597 /* this is an input prompt */
1598 void
short_playlog(u_char * data,u_char * line)1599 short_playlog(u_char * data, u_char * line)
1600 {
1601    if (!(strcasecmp(line, "Y")))
1602       playlog(NULL, NULL, NULL);
1603    else
1604       add_wait_prompt("Erase your stored messages? [y/N] ", short_eraselog, "", WAIT_PROMPT_LINE);
1605 }
1606 
1607 /*
1608  * away: the /AWAY command.  Keeps track of the away message locally, and
1609  * sends the command on to the server.
1610  * Only sets the current server away unless -all is specified
1611  * vars used: EMAIL_ADDRESS, SILENT_AWAY, DEFAULT_AWAY_MSG
1612  * if EMAIL_ADDRESS is non-NULL it is appened to the away message as
1613  * [email: blah@lemae.com], else ignored.  if SILENT_AWAY is set, the away
1614  * messages will not be sent to the channel(s)
1615  */
1616 void
away(command,args,subargs)1617 away(command, args, subargs)
1618    u_char *command, *args, *subargs;
1619 {
1620    u_char tmpu_char[BIG_BUFFER_SIZE], *defaway = NULL;
1621    u_char awaymsg[1024], *arg1, *email;
1622    int old_server = from_server;
1623 
1624    email = get_string_var(EMAIL_ADDRESS_VAR);
1625    if (args && *args)
1626      {
1627 	if (*args == '-')
1628 	  {
1629 	     arg1 = next_arg(args, &args);
1630 	     if (my_strnicmp(arg1 + 1, "ALL", 3) == 0)
1631 	       {
1632 		  if ((args && *args) || ((defaway = get_string_var(DEFAULT_AWAY_MSG_VAR)) != NULL))
1633 		     snprintf(awaymsg, sizeof(awaymsg) - 1, "(%s)", args && *args ? args : defaway);
1634 		  else
1635 		    {
1636 		       put_info("Either provide a reason or set DEFAULT_AWAY_MSG to something.");
1637 		       return;
1638 		    }
1639 		  if (email)
1640 		    {
1641 		       snprintf(tmpu_char, sizeof(tmpu_char) - 1, " [email: %s]", email);
1642 		       strmcat(awaymsg, tmpu_char, sizeof(awaymsg) - 1);
1643 		    }
1644 		  for (from_server = 0; from_server < number_of_servers; from_server++)
1645 		    {
1646 		       if (server_list[from_server].away_set == 0)
1647 			 {
1648 			    server_list[from_server].away_set = time(NULL);
1649 			    server_list[from_server].away_count = 0;
1650 			    dma_strcpy(&server_list[from_server].away, awaymsg);
1651 			    if (server_list[from_server].connected)
1652 			      {
1653 				 if (!get_int_var(SILENT_AWAY_VAR))
1654 				   {
1655 				      snprintf(tmpu_char, sizeof(tmpu_char), "is out. %s", awaymsg);
1656 				      ame("AME", tmpu_char, NULL);
1657 				   }
1658 				 send_to_server("%s :%s", command, awaymsg);
1659 			      }
1660 			 }
1661 		    }
1662 		  from_server = old_server;
1663 		  open_away_log(awaymsg);
1664 		  update_all_status();
1665 		  return;
1666 	       }
1667 	     else
1668 	       {
1669 		  put_error("Unknown option: %s", arg1);
1670 		  return;
1671 	       }
1672 	  }
1673 	else
1674 	   snprintf(awaymsg, sizeof(awaymsg) - 1, "(%s)", args);
1675      }
1676    else if ((defaway = get_string_var(DEFAULT_AWAY_MSG_VAR)) != NULL)
1677       snprintf(awaymsg, sizeof(awaymsg) - 1, "(%s)", defaway);
1678    else
1679      {
1680 	put_info("Either provide a reason or set DEFAULT_AWAY_MSG to something.");
1681 	return;
1682      }
1683    if (server_list[from_server].away_set != 0)
1684      {
1685 	put_error("You're already set away on this server. Use /back.");
1686 	return;
1687      }
1688    if (email)
1689      {
1690 	snprintf(tmpu_char, sizeof(tmpu_char) - 1, " [email: %s]", email);
1691 	strmcat(awaymsg, tmpu_char, sizeof(awaymsg) - 1);
1692      }
1693    if (!get_int_var(SILENT_AWAY_VAR))
1694      {
1695 	snprintf(tmpu_char, sizeof(tmpu_char), "is out. %s", awaymsg);
1696 	ame("AME", tmpu_char, NULL);
1697      }
1698    server_list[from_server].away_set = time(NULL);
1699    server_list[from_server].away_count = 0;
1700    dma_strcpy(&server_list[from_server].away, awaymsg);
1701    open_away_log(awaymsg);
1702    send_to_server("%s :%s", command, awaymsg);
1703    update_all_status();
1704 }
1705 
1706 /*
1707  * same algorithm as away, but messages reflect being back and away gets unset.
1708  * -ALL is honored, if not set, only the current server is set back..
1709  * vars used: SILENT_AWAY, DEFAULT_BACK_MSG
1710  * they are fairly self explanatory
1711  * asks the user if they want to view their away messages if they get set back
1712  */
1713 void
back(command,args,subargs)1714 back(command, args, subargs)
1715    u_char *command, *args, *subargs;
1716 {
1717    u_char *defback = NULL, *arg1;
1718    u_char backmsg[1024], tmpu_char[BIG_BUFFER_SIZE];
1719    time_t atime;
1720    int old_server = from_server;
1721 
1722    if (args && *args)
1723      {
1724 	if (*args == '-')
1725 	  {
1726 	     arg1 = next_arg(args, &args);
1727 	     if (my_strnicmp(arg1 + 1, "ALL", 3) == 0)
1728 	       {
1729 		  if ((args && *args) || ((defback = get_string_var(DEFAULT_BACK_MSG_VAR)) != NULL))
1730 		     snprintf(backmsg, sizeof(backmsg), "(%s)", args && *args ? args : defback);
1731 		  else
1732 		    {
1733 		       put_info("Either provide a reason or set DEFAULT_BACK_MSG to something.");
1734 		       return;
1735 		    }
1736 		  for (from_server = 0; from_server < number_of_servers; from_server++)
1737 		     if (server_list[from_server].away_set != 0)
1738 		       {
1739 			  atime = time(NULL) - server_list[from_server].away_set;
1740 			  server_list[from_server].away_set = 0;
1741 			  server_list[from_server].away_count = 0;
1742 			  dma_Free(&server_list[from_server].away);
1743 			  if (server_list[from_server].connected)
1744 			    {
1745 			       if (!get_int_var(SILENT_AWAY_VAR))
1746 				 {
1747 				    snprintf(tmpu_char, sizeof(tmpu_char), "is back after %s. %s", ninja_etime(atime), backmsg);
1748 				    ame("AME", tmpu_char, NULL);
1749 				 }
1750 			       send_to_server("%s :", command);
1751 			    }
1752 		       }
1753 		  from_server = old_server;
1754 		  update_all_status();
1755 		  close_away_log(backmsg);
1756 		  add_wait_prompt("Play your stored messages? [y/N] ", short_playlog, "", WAIT_PROMPT_LINE);
1757 		  return;
1758 	       }
1759 	     else
1760 	       {
1761 		  put_error("Unknown option: %s", arg1);
1762 		  return;
1763 	       }
1764 	  }
1765 	else
1766 	   snprintf(backmsg, sizeof(backmsg), "(%s)", args);
1767      }
1768    else if ((defback = get_string_var(DEFAULT_BACK_MSG_VAR)) != NULL)
1769       snprintf(backmsg, sizeof(backmsg), "(%s)", defback);
1770    else
1771      {
1772 	put_info("Either provide a reason or set DEFAULT_BACK_MSG to something.");
1773 	return;
1774      }
1775    if (server_list[from_server].away_set == 0)
1776      {
1777 	put_error("You're not marked away on this server.");
1778 	return;
1779      }
1780    atime = time(NULL) - server_list[from_server].away_set;
1781    if (!get_int_var(SILENT_AWAY_VAR))
1782      {
1783 	snprintf(tmpu_char, sizeof(tmpu_char), "has returned after %s. %s", ninja_etime(atime), backmsg);
1784 	ame("AME", tmpu_char, NULL);
1785      }
1786    server_list[from_server].away_set = 0;
1787    server_list[from_server].away_count = 0;
1788    dma_Free(&server_list[from_server].away);
1789    send_to_server("%s :", command);
1790    update_all_status();
1791    close_away_log(backmsg);
1792    add_wait_prompt("Play your stored messages? [y/N] ", short_playlog, "", WAIT_PROMPT_LINE);
1793 }
1794 
1795 /*
1796  * /me on all channels
1797  */
1798 void
ame(command,args,subargs)1799 ame(command, args, subargs)
1800    u_char *command, *args, *subargs;
1801 {
1802    Channel *tmp;
1803 
1804    if (!args || !*args)
1805      {
1806 	usage(command, "<message>");
1807 	return;
1808      }
1809    for (tmp = server_list[from_server].chan_list; tmp; tmp = tmp->next)
1810      {
1811 	int old = set_lastlog_msg_level(LOG_ACTION);
1812 
1813 	save_message_from();
1814 	send_action(tmp->channel, args);
1815 	message_from(tmp->channel, LOG_ACTION);
1816 	if (do_hook(SEND_ACTION_LIST, "%s %s", tmp->channel, args))
1817 	   put_raw("* %s %s", get_server_nickname(from_server), args);
1818 	set_lastlog_msg_level(old);
1819 	restore_message_from();
1820      }
1821 }
1822 
1823 /*
1824  *
1825  * XXX: at some point i will merge this with IRCII /save
1826  */
1827 void
ninja_save(command,args,subargs)1828 ninja_save(command, args, subargs)
1829    u_char *command, *args, *subargs;
1830 {
1831    ChanGrep *channel;
1832    u_char *filename = NULL, tmpoutbuf[1024], ltb[512];
1833    FILE *outfile;
1834    int vcount = 0, scount = 0, ncount = 0, gcount = 0;
1835    int fcount = 0, ecount = 0, kcount = 0;
1836    int first = 1;
1837    u_char *na, *pa, *ni, *um;
1838 
1839    if (qflag)
1840      {
1841 	put_error("You started Ninja IRC with the -q flag, saving is disabled.");
1842 	return;
1843      }
1844 
1845    filename = NINJA_SAVE_FILE;
1846    if (*filename == '~')
1847       filename = expand_twiddle(filename);
1848    outfile = fopen(filename, "w");
1849    if (outfile == NULL)
1850      {
1851 	put_error("Cannot open save file(%s), aborting save..", filename);
1852 	if (CP(filename) != NINJA_SAVE_FILE)
1853 	   dma_Free(&filename);
1854 	return;
1855      }
1856    if (CP(filename) != NINJA_SAVE_FILE)
1857       dma_Free(&filename);
1858    if (orignickname)
1859       fprintf(outfile, "ORIGNICK ON %s\n", orignickname);
1860    vcount = save_variables(outfile, 1);
1861    if (server_list)
1862       for (scount = 0; scount < number_of_servers; scount++)
1863 	{
1864 	   na = server_list[scount].name;
1865 	   first = server_list[scount].port;
1866 	   pa = server_list[scount].password;
1867 	   ni = server_list[scount].nickname;
1868 	   um = server_list[scount].usermode;
1869 	   fprintf(outfile, "ADDS %s:%d:%s:%s:%s\n",
1870 		   na ? na : empty_string, first, pa ? pa : empty_string, ni ? ni : empty_string, um ? um : empty_string);
1871 	}
1872    for (channel = grep_list; channel; channel = channel->next)
1873      {
1874 	fprintf(outfile, "GREP %s %s\n", channel->channel, channel->words);
1875 	gcount++;
1876      }
1877 
1878    /* save the notify list... */
1879    ncount = save_notify(outfile);
1880 
1881    /* friends, enemies, channel keys */
1882    fcount = save_friends(1);
1883    ecount = save_enemies(1);
1884    kcount = save_ckeys(1);
1885 
1886    /* build the output string.. */
1887    first = 1;
1888    strcpy(tmpoutbuf, "Saved:");
1889    if (vcount)
1890      {
1891 	if (!first)
1892 	  strmcat(tmpoutbuf, ",", sizeof(tmpoutbuf)-1);
1893 	first = 0;
1894 	snprintf(ltb, sizeof(ltb)-1,
1895 		 " %d variable%s", vcount, PLURAL(vcount));
1896 	ltb[sizeof(ltb)-1] = '\0';
1897 	strmcat(tmpoutbuf, ltb, sizeof(tmpoutbuf)-1);
1898      }
1899    if (scount)
1900      {
1901 	if (!first)
1902 	  strmcat(tmpoutbuf, ",", sizeof(tmpoutbuf)-1);
1903 	first = 0;
1904 	snprintf(ltb, sizeof(ltb)-1,
1905 		 " %d server%s", scount, PLURAL(scount));
1906 	ltb[sizeof(ltb)-1] = '\0';
1907 	strmcat(tmpoutbuf, ltb, sizeof(tmpoutbuf)-1);
1908      }
1909    if (gcount)
1910      {
1911 	if (!first)
1912 	  strmcat(tmpoutbuf, ",", sizeof(tmpoutbuf)-1);
1913 	first = 0;
1914 	snprintf(ltb, sizeof(ltb)-1,
1915 		 " %d grep entr%s", gcount, Y_PLURAL(gcount));
1916 	ltb[sizeof(ltb)-1] = '\0';
1917 	strmcat(tmpoutbuf, ltb, sizeof(tmpoutbuf)-1);
1918      }
1919    if (ncount)
1920      {
1921 	if (!first)
1922 	  strmcat(tmpoutbuf, ",", sizeof(tmpoutbuf)-1);
1923 	first = 0;
1924 	snprintf(ltb, sizeof(ltb)-1,
1925 		 " %d notify entr%s", ncount, Y_PLURAL(ncount));
1926 	ltb[sizeof(ltb)-1] = '\0';
1927 	strmcat(tmpoutbuf, ltb, sizeof(tmpoutbuf)-1);
1928      }
1929    if (fcount)
1930      {
1931 	if (!first)
1932 	  strmcat(tmpoutbuf, ",", sizeof(tmpoutbuf)-1);
1933 	first = 0;
1934 	snprintf(ltb, sizeof(ltb)-1,
1935 		 " %d friend%s", fcount, PLURAL(fcount));
1936 	ltb[sizeof(ltb)-1] = '\0';
1937 	strmcat(tmpoutbuf, ltb, sizeof(tmpoutbuf)-1);
1938      }
1939    if (ecount)
1940      {
1941 	if (!first)
1942 	  strmcat(tmpoutbuf, ",", sizeof(tmpoutbuf)-1);
1943 	first = 0;
1944 	snprintf(ltb, sizeof(ltb)-1,
1945 		 " %d enem%s", ecount, Y_PLURAL(ecount));
1946 	ltb[sizeof(ltb)-1] = '\0';
1947 	strmcat(tmpoutbuf, ltb, sizeof(tmpoutbuf)-1);
1948      }
1949    if (kcount)
1950      {
1951 	if (!first)
1952 	  strmcat(tmpoutbuf, ",", sizeof(tmpoutbuf)-1);
1953 	first = 0;
1954 	snprintf(ltb, sizeof(ltb)-1,
1955 		 " %d channel key%s", kcount, PLURAL(kcount));
1956 	ltb[sizeof(ltb)-1] = '\0';
1957 	strmcat(tmpoutbuf, ltb, sizeof(tmpoutbuf)-1);
1958      }
1959    if (!first)
1960      {
1961 	strmcat(tmpoutbuf, ".", sizeof(tmpoutbuf) - 1);
1962 	put_info("%s", tmpoutbuf);
1963      }
1964    fclose(outfile);
1965 }
1966 
1967 /*
1968  * show the bans from cache..
1969  */
1970 void
show_ban_cache(command,args,subargs)1971 show_ban_cache(command, args, subargs)
1972    u_char *command, *args, *subargs;
1973 {
1974    put_error("Not implemented yet.");
1975 }
1976