1 /*
2  * friends.c: Ninja IRC friends list implementation
3  *
4  * written by Joshua J. Drake and Kraig Amador
5  */
6 
7 #include "irc.h"
8 #include "friends.h"
9 
10 #include "server.h"
11 #include "channels.h"
12 #include "dma.h"
13 #include "screen.h"
14 #include "vars.h"
15 #include "ircaux.h"
16 #include "output.h"
17 #include "ignore.h"
18 #include "whois.h"
19 
20 #include "ninja.h"
21 #include "ckey.h"
22 
23 /* arg... */
24 #include "enemies.h"
25 
26 #ifdef HAVE_CRYPT
27 # ifdef HAVE_CRYPT_H
28 #  include <crypt.h>
29 # endif
30 #endif
31 
32 #define MUST_BE_EXACT 1
33 
34 
35 /* local command translations.. */
36 static	void	fcmd_add _((u_char *));
37 static	void	fcmd_add_chan _((u_char *));
38 static	void	fcmd_chan_flags _((u_char *));
39 static	void	fcmd_flags _((u_char *));
40 static	void	fcmd_list _((u_char *));
41 static	void	fcmd_passwd _((u_char *));
42 static	void	fcmd_rehash _((u_char *));
43 static	void	fcmd_rm _((u_char *));
44 static	void	fcmd_rm_chan _((u_char *));
45 static	void	fcmd_rm_host _((u_char *));
46 static	void	fcmd_rename _((u_char *));
47 static	void	fcmd_whois _((u_char *));
48 
49 
50 /* struct/commands.. */
51 struct
52 {
53    u_char *name;
54    u_int uniq;
55    void (*function) _((u_char *));
56 }
57 friend_commands[] =
58 {
59      { UP("ADD"),		3, fcmd_add },
60      { UP("ADDCHANNEL"),	4, fcmd_add_chan },
61      { UP("ADDHOST"),		4, fcmd_add_host },
62      { UP("CFLAGS"),		1, fcmd_chan_flags },
63      { UP("FLAGS"),		1, fcmd_flags },
64      { UP("LIST"),		1, fcmd_list },
65      { UP("PASS"),		1, fcmd_passwd },
66      { UP("REHASH"),		3, fcmd_rehash },
67      { UP("REMOVE"),		3, fcmd_rm },
68      { UP("REMCHANNEL"),       	4, fcmd_rm_chan },
69      { UP("REMHOST"),		4, fcmd_rm_host },
70      { UP("RENAME"),		3, fcmd_rename },
71      { UP("WHOIS"),		1, fcmd_whois },
72      { NULL, 0, (void (*)())NULL }
73 };
74 
75 Friend *friend_list = NULL;
76 
77 static const u_char usermode_str[] = FL_UMODE_STRING;
78 static const u_char chanmode_str[] = FL_CMODE_STRING;
79 
80 /* for adding hosts from nicks that are on irc */
81 extern void addhost_queue _((WhoisStuff *, u_char *, u_char *));
82 extern void add_userhost_to_whois();
83 
84 extern	void	timercmd _((u_char *, u_char *, u_char *));
85 
86 /* static stuff */
87 static	int	decifer_usermode _((u_char *, unsigned long *));
88 static	int	decifer_chanmode _((u_char *, unsigned long *));
89 static	void	free_friend _((Friend *));
90 static	void	free_fchan _((FChan *));
91 static	void	free_fhost _((FHost *));
92 static	int 	friends_cmd_chk _((u_char *, u_char *, u_char *, u_char *, Friend **));
93 static	void	fc_sync_bans _((Channel *));
94 
95 
96 /*
97  * this routine dispatches the friend commands based on
98  * the first parameter to /friend
99  */
100 void
friend_cmd(command,args,subargs)101 friend_cmd(command, args, subargs)
102    u_char *command, *args, *subargs;
103 {
104    u_char *cmd;
105    u_int i, len;
106 
107    if (!(cmd = next_arg(args, &args)))
108      {
109 	usage("friend", "<command> [<args>]");
110 	return;
111      }
112 
113    len = my_strlen(cmd);
114    upper(cmd);
115    for (i = 0; friend_commands[i].name != NULL; i++)
116      {
117 	if (!my_strncmp(friend_commands[i].name, cmd, len))
118 	  {
119 	     if (len < friend_commands[i].uniq)
120 	       {
121 		  put_error("Friend: Ambiguous command: %s", cmd);
122 		  return;
123 	       }
124 	     friend_commands[i].function(args);
125 	     return;
126 	  }
127        }
128    put_error("Friend: Unknown command: %s", cmd);
129 }
130 
131 
132 /*
133  * add users to the friends list
134  */
135 void
fcmd_add(args)136 fcmd_add(args)
137    u_char *args;
138 {
139    u_char *nick, *passwd, *flags, tb1[512];
140    Friend *f;
141    int count = 0;
142    u_char *uastr = UP("<friend> [<flags> [<password>]]");
143    u_char *cmdstr = UP("friend add");
144 
145    nick = next_arg(args, &args);
146    if (!friends_cmd_chk(cmdstr, uastr, UNULL, nick, &f))
147      return;
148    if (f)
149      {
150 	put_info("%s is already on your friends list.", nick);
151 	return;
152      }
153 
154    /* we already know we they aren't there! */
155    flags = next_arg(args, &args);
156    passwd = next_arg(args, &args);
157    if ((f = (Friend *) dma_Malloc(sizeof(Friend))) != NULL)
158      {
159 	dma_strcpy(&f->nick, nick);
160 	if (passwd)
161 	  dma_strcpy(&f->password, UP(crypt(passwd, make_salt(f->nick))));
162 
163 	/* setup the flags.. */
164 	if (flags)
165 	  {
166 	     snprintf(tb1, sizeof(tb1)-1, "%s%s",
167 		      *flags == '+' ? empty_string : UP("+"),
168 		      flags);
169 	     tb1[sizeof(tb1)-1] = '\0';
170 	     decifer_usermode(tb1, &f->modes);
171 	  }
172 	add_to_list((List **) & friend_list, (List *) f);
173 
174 	add_userhost_to_whois(nick, addhost_queue);
175 	put_info("%s is now your friend with flags: %s%s%s",
176 		 nick,
177 		 f->modes ? UP("+") : empty_string,
178 		 f->modes ? recreate_umode(f) : UP("<none>"),
179 		 passwd ? UP(" with a password.") : UP("."));
180 
181 	/* tell them about it.. */
182 	my_strcpy(tb1, "You have been added to my friends list."); /* safe */
183 	if (f->modes)
184 	  {
185 	     strmcat(tb1, "  I will: ", sizeof(tb1)-1);
186 	     if (f->modes & FL_UMODE_AUTO_DCC)
187 	       {
188 		  count++;
189 		  strmcat(tb1, "auto-get DCC requests", sizeof(tb1)-1);
190 	       }
191 	     if (f->modes & FL_UMODE_NO_FLOOD)
192 	       {
193 		  if (count)
194 		    strmcat(tb1, ", ", sizeof(tb1)-1);
195 		  count++;
196 		  strmcat(tb1, "allow floods", sizeof(tb1)-1);
197 	       }
198 	     if (f->modes & FL_UMODE_SECURE_NDCC)
199 	       {
200 		  if (count)
201 		    strmcat(tb1, ", ", sizeof(tb1)-1);
202 		  count++;
203 		  strmcat(tb1, "allow secure NDCC access", sizeof(tb1)-1);
204 	       }
205 	     strmcat(tb1, " from you.", sizeof(tb1)-1);
206 	  }
207 	send_to_server("NOTICE %s :%s", nick, tb1);
208 
209 	/* tell them about their password and how to get help */
210 	snprintf(tb1, sizeof(tb1)-1, "Use \"/ctcp %s help\" for more information.", get_server_nickname(from_server));
211 	tb1[sizeof(tb1)-1] = '\0';
212 	if (passwd)
213 	  send_to_server("NOTICE %s :Your password is \"%s\", don't forget it.  %s", nick, passwd, tb1);
214 	else
215 	  send_to_server("NOTICE %s :Please set a password by typing /ctcp %s pass <password>   %s",
216 			 nick, get_server_nickname(from_server), tb1);
217      }
218    (void) save_friends(1);
219 }
220 
221 
222 /*
223  * add a channel to a friend's channel access list.
224  *
225  * accessed via /friend addchan
226  */
227 void
fcmd_add_chan(args)228 fcmd_add_chan(args)
229    u_char *args;
230 {
231    FChan *c;
232    Friend *f;
233    u_char *nick = NULL, *channel = NULL, *flags = NULL, tb1[32];
234    unsigned long tmpmodes = 0;
235    u_char *uastr = UP("<friend> <channel> <flags>");
236    u_char *cmdstr = UP("friend addchannel");
237 
238    nick = next_arg(args, &args);
239    if (!friends_cmd_chk(cmdstr, uastr, UNULL, nick, &f))
240      return;
241 
242    if (!(channel = next_arg(args, &args)))
243      {
244 	usage(cmdstr, uastr);
245 	return;
246      }
247 
248    /* for this we remove it regardless! */
249    if ((c = (FChan *) remove_from_list((List **) & (f->channels), channel)) != NULL)
250      free_fchan(c);
251 
252    flags = next_arg(args, &args);
253    if (flags == NULL)
254      {
255 	put_info("Why add a channel without any flags?");
256 	return;
257      }
258 
259    snprintf(tb1, sizeof(tb1)-1, "%s%s", *flags != '+' ? "+" : "", flags);
260    tb1[sizeof(tb1)-1] = '\0';
261    decifer_chanmode(tb1, &tmpmodes);
262 
263    /* alloc/add it.. */
264    c = (FChan *) dma_Malloc(sizeof(FChan));
265    c->modes = tmpmodes;
266    dma_strcpy(&(c->channel), channel);
267    add_to_list((List **) & (f->channels), (List *) c);
268    put_info("%s now has access to \"%s\" with flags: +%s", f->nick, channel, recreate_cmode(c));
269    (void) save_friends(1);
270 }
271 
272 
273 /*
274  * add a hostmask to a friend's entry in the friends list
275  *
276  * first argument: friend's nick
277  * remaining arguments: hostmask or current nickname
278  */
279 void
fcmd_add_host(args)280 fcmd_add_host(args)
281    u_char *args;
282 {
283    FHost *h;
284    Friend *tmp;
285    u_char *nick = NULL, *newhost = NULL;
286    u_char *uastr = UP("<friend> [<nick/host>] [<nick/host>] ...");
287    u_char *cmdstr = UP("friend addhost");
288    extern int in_ctcp_flag;
289 
290    nick = next_arg(args, &args);
291    if (!friends_cmd_chk(cmdstr, uastr, UNULL, nick, &tmp))
292      return;
293 
294    /* if there isn't at least one nick/host show usage.. */
295    newhost = next_arg(args, &args);
296    if (!newhost)
297      {
298 	usage(cmdstr, uastr);
299 	return;
300      }
301 
302    /* while we have one, add it.. */
303    while (newhost)
304      {
305 	/* is it a full hostmask?  if not use userhost information */
306 	if (!match("*!*@*", newhost))
307 	  add_to_whois_queue(newhost, addhost_queue, "%s", nick);
308 	else
309 	  {
310 	     h = (FHost *) remove_from_list((List **)&tmp->hosts, newhost);
311 	     if (h)
312 	       {
313 		  add_to_list((List **) & (tmp->hosts), (List *) h);
314 		  if (!in_ctcp_flag) /* quiet hack.. */
315 		    put_info("%s already has access from \"%s\".", nick, newhost);
316 	       }
317 	     else
318 	       {
319 		  h = (FHost *) dma_Malloc(sizeof(FHost));
320 		  dma_strcpy(&(h->host), newhost);
321 		  add_to_list((List **) & (tmp->hosts), (List *) h);
322 		  if (!in_ctcp_flag) /* quiet hack.. */
323 		    put_info("%s now has access from \"%s\".", nick, newhost);
324 	       }
325 	  }
326 	newhost = next_arg(args, &args);
327      }
328    (void) save_friends(1);
329 }
330 
331 
332 /*
333  * change a friends flags on a giving channel..
334  * accessable via /friend cflags
335  */
336 void
fcmd_chan_flags(args)337 fcmd_chan_flags(args)
338    u_char *args;
339 {
340    FChan *ptr;
341    Friend *tmp;
342    u_char *nick = NULL, *channel = NULL, *flags = NULL;
343 
344    nick = next_arg(args, &args);
345    channel = next_arg(args, &args);
346    flags = next_arg(args, &args);
347    if (!(flags && *flags))
348      {
349 	usage("friend cflags", "<friend> <channel> +/-<flags>");
350 	return;
351      }
352    if ((tmp = get_friend(nick)) == NULL)
353      {
354 	put_info("%s is not on your friends list.", nick);
355 	return;
356      }
357    if ((ptr = get_fchan(tmp, channel, MUST_BE_EXACT)) == NULL)
358      {
359 	put_info("%s does not have access to %s", nick, channel);
360 	return;
361      }
362    decifer_chanmode(flags, &ptr->modes);
363    put_info("%s's flags on %s are now: %s%s",
364 	    nick, channel,
365 	    ptr->modes ? "+" : "<empty>", recreate_cmode(ptr));
366    (void) save_friends(1);
367 }
368 
369 
370 /*
371  * change a friends user flags...
372  * accessable via /friend flags
373  */
374 void
fcmd_flags(args)375 fcmd_flags(args)
376    u_char *args;
377 {
378    Friend *tmp;
379    u_char *nick, *attribute;
380 
381    nick = next_arg(args, &args);
382    attribute = next_arg(args, &args);
383    if (!nick || !*nick || !attribute || !*attribute)
384      {
385 	usage("friend flags", "<friend's nick> +/-<flags>");
386 	return;
387      }
388    if ((tmp = get_friend(nick)) == NULL)
389      {
390 	put_info("%s is not on your friends list.", nick);
391 	return;
392      }
393    decifer_usermode(attribute, &tmp->modes);
394    put_info("%s's flags are now: %s%s", nick,
395 	    tmp->modes ? "+" : "<empty>", recreate_umode(tmp));
396    (void) save_friends(1);
397 }
398 
399 
400 /*
401  * list all friends on the list...
402  * accessed via /friend list
403  */
404 static	void
fcmd_list(args)405 fcmd_list(args)
406    u_char *args;
407 {
408    Friend *tmp;
409    FChan *chan;
410    int count = 0;
411    u_char tbuf1[2048], fmt[128];
412 
413    if (!friend_list)
414      {
415 	put_info("Your friends list is empty.");
416 	return;
417      }
418 
419    my_strncpy(fmt, "%-9.9s %-8.8s %s%-5.5s %s", sizeof(fmt)-1);
420    fmt[sizeof(fmt)-1] = '\0';
421 
422    put_info(fmt, "Nick", "Pass", " ", "Flags", "Channels");
423 
424    for (tmp = friend_list; tmp; tmp = tmp->next)
425      {
426 	tbuf1[0] = '\0';
427 	for (chan = tmp->channels; chan; chan = chan->next)
428 	  {
429 	     u_char tb2[256];
430 
431 	     snprintf(UP(tb2), sizeof(tb2)-1, "%s(%s%s)",
432 		      chan->channel,
433 		      chan->modes ? "+" : "",
434 		      recreate_cmode(chan));
435 	     tb2[sizeof(tb2)-1] = '\0';
436 
437 	     if (*tbuf1 != '\0')
438 	       my_strmcat(tbuf1, " ", sizeof(tbuf1)-1);
439 	     my_strmcat(tbuf1, tb2, sizeof(tbuf1)-1);
440 	  }
441 	put_info(fmt, tmp->nick, tmp->password ? "<hidden>" : "<none>",
442 		 tmp->modes ? "+" : " ", recreate_umode(tmp),
443 		 *tbuf1 == (u_char)'\0' ? empty_string : tbuf1);
444 	count++;
445      }
446    put_info("End of friends list, %d counted.", count);
447 }
448 
449 
450 /*
451  * change a friends password..
452  * accessed via /friend pass
453  */
454 static	void
fcmd_passwd(args)455 fcmd_passwd(args)
456    u_char *args;
457 {
458    Friend *tmp;
459    u_char *nick, *password;
460    int remove = 0;
461 
462    nick = next_arg(args, &args);
463    if (nick && *nick && *nick == '-')
464      {
465 	remove = 1;
466 	nick++;
467      }
468    password = next_arg(args, &args);
469    if (!nick || !*nick
470        || (!remove && (!password || !*password)))
471      {
472 	usage("friend pass", "[-]<friend> [<password>]");
473 	return;
474      }
475    if ((tmp = get_friend(nick)) == NULL)
476      {
477 	put_info("%s is not on your friends list.", nick);
478 	return;
479      }
480    if (!remove)
481      {
482 	if (tmp->password)
483 	  dma_Free(&tmp->password);
484 	dma_strcpy(&tmp->password, UP(crypt(password, make_salt(tmp->nick))));
485 	put_info("%s's password has been changed.", nick);
486      }
487    else
488      {
489 	if (tmp->password)
490 	  dma_Free(&tmp->password);
491 	tmp->password = UNULL;
492 	put_info("%s's password has been removed.", nick);
493      }
494    (void) save_friends(1);
495 }
496 
497 
498 /*
499  * clear and reload the friends list...
500  * for those manual edit people..
501  */
502 static	void
fcmd_rehash(args)503 fcmd_rehash(args)
504    u_char *args;
505 {
506    Friend *f, *n;
507 
508    /* clear the list.. */
509    for (f = friend_list; f; f = n)
510      {
511 	n = f->next;
512 	free_friend(f);
513      }
514    friend_list = (Friend *)NULL;
515 
516    /* reload it! */
517    put_info("Friend list rehashed, loaded %d friends.", load_friends(1));
518 }
519 
520 
521 /*
522  * remove a user from the friends list
523  */
524 void
fcmd_rm(args)525 fcmd_rm(args)
526    u_char *args;
527 {
528    u_char *nick;
529    Friend *f;
530    u_char *urstr = UP("<friend>");
531    u_char *cmdstr = UP("friend remove");
532 
533    nick = next_arg(args, &args);
534    if (!friends_cmd_chk(cmdstr, UNULL, urstr, nick, &f))
535      return;
536 
537    /* we now have f if its ok! */
538    f = (Friend *) remove_from_list((List **) & friend_list, f->nick);
539    if (f)
540      {
541 	free_friend(f);
542 	put_info("%s is no longer your friend.", nick);
543 	(void) save_friends(1);
544      }
545    else
546      put_error("Unable to remove \"%s\" from your friends list.", nick);
547 }
548 
549 
550 /*
551  * remove a channel from a friend's channel access list.
552  *
553  * accessed via /friend remchan
554  */
555 void
fcmd_rm_chan(args)556 fcmd_rm_chan(args)
557    u_char *args;
558 {
559    FChan *c;
560    Friend *f;
561    u_char *nick = NULL, *channel = NULL;
562    u_char *urstr = UP("<friend> <channel>");
563    u_char *cmdstr = UP("friend remchannel");
564 
565    nick = next_arg(args, &args);
566    if (!friends_cmd_chk(cmdstr, UNULL, urstr, nick, &f))
567      return;
568 
569    if (!(channel = next_arg(args, &args)))
570      {
571 	usage(cmdstr, urstr);
572 	return;
573      }
574 
575    /* for this we remove it regardless! */
576    if ((c = (FChan *) remove_from_list((List **) & (f->channels), channel)) != NULL)
577      free_fchan(c);
578 
579    put_info("%s no longer has access to \"%s\".", f->nick, channel);
580    (void) save_friends(1);
581 }
582 
583 
584 /*
585  * remove a hostmask from a friend's entry in the friends list
586  *
587  * first argument: friend's nick
588  * remaining arguments: hostmask or #
589  */
590 void
fcmd_rm_host(args)591 fcmd_rm_host(args)
592    u_char *args;
593 {
594    FHost *h;
595    Friend *tmp;
596    u_char *nick = NULL, *newhost = NULL;
597    u_char *urstr = UP("<friend> [<mask #>/<mask>] [<mask #>/<mask>] ..");
598    u_char *cmdstr = UP("friend remhost");
599    int shift_mod = 1;
600 
601    nick = next_arg(args, &args);
602    if (!friends_cmd_chk(cmdstr, UNULL, urstr, nick, &tmp))
603      return;
604 
605    /* if there isn't at least one nick/host show usage.. */
606    newhost = next_arg(args, &args);
607    if (!newhost)
608      {
609 	usage(cmdstr, urstr);
610 	return;
611      }
612 
613    /* while we have one, remove it.. */
614    while (newhost)
615      {
616 	int ti = atoi(newhost);
617 
618 	if (ti > 0)
619 	  {
620 	     int oti = ti;
621 
622 	     ti -= shift_mod;
623 	     for (h = tmp->hosts; h && ti > 0;
624 		  h = h->next, ti--);
625 	     ti = oti;
626 	     if (h)
627 	       {
628 		  h = (FHost *) remove_from_list((List **)&tmp->hosts, h->host);
629 		  if (ti >= shift_mod)
630 		    shift_mod++;
631 	       }
632 	  }
633 	else
634 	  h = (FHost *) remove_from_list((List **)&tmp->hosts, newhost);
635 
636 	/* if we have no host error.. else free it.. */
637 	if (!h)
638 	  {
639 	     if (ti > 0)
640 	       put_info("Unable to locate mask #%d for %s", ti, tmp->nick);
641 	     else
642 	       put_info("Unable to locate mask \"%s\" for %s.", newhost, nick);
643 	  }
644 	else
645 	  {
646 	     put_info("%s no longer has access from \"%s\".", nick, h->host);
647 	     free_fhost(h);
648 	  }
649 	newhost = next_arg(args, &args);
650      }
651    (void) save_friends(1);
652 }
653 
654 
655 /*
656  * rename a user on the friends list
657  */
658 void
fcmd_rename(args)659 fcmd_rename(args)
660    u_char *args;
661 {
662    u_char *nick, *nnick;
663    Friend *f;
664    u_char *urstr = UP("<friend> <new name>");
665    u_char *cmdstr = UP("friend rename");
666 
667    nick = next_arg(args, &args);
668    if (!friends_cmd_chk(cmdstr, UNULL, urstr, nick, &f))
669      return;
670    if (!(nnick = next_arg(args, &args)) || !*nnick)
671      {
672 	usage(cmdstr, urstr);
673 	return;
674      }
675 
676    /* check for new-nick in use */
677    if (get_friend(nnick))
678      {
679 	put_error("The new name you chose is already in use.");
680 	return;
681      }
682 
683    /* we now have f and a new name if its ok! */
684    dma_Free(&(f->nick));
685    dma_strcpy(&(f->nick), nnick);
686    put_info("%s is now known as %s.", nick, nnick);
687    (void) save_friends(1);
688 }
689 
690 
691 /*
692  * shows all information about a friend..
693  * accessed via /friend whois
694  */
695 static	void
fcmd_whois(args)696 fcmd_whois(args)
697    u_char *args;
698 {
699    Friend *tmp;
700    FChan *chan;
701    FHost *host;
702    u_char *nick = NULL;
703    u_char tobuf[BIG_BUFFER_SIZE], tb2[512];
704    int count = 0;
705 
706    if (!friend_list)
707      {
708 	put_info("Your friends list is empty.");
709 	return;
710      }
711    if ((nick = next_arg(args, &args)) == NULL)
712      {
713 	usage("friend whois", "<friend's nick>");
714 	return;
715      }
716    if ((tmp = get_friend(nick)) == NULL)
717      {
718 	put_info("The nickname \"%s\" is not on your friends list.", nick);
719 	return;
720      }
721    /* ok, we have a valid friend. */
722    put_info("Your friend %s%s%s%s %s", tmp->nick, tmp->modes ? "(+" : "", recreate_umode(tmp), tmp->modes ? ")" : "",
723    tmp->password ? "has a password set." : "does not have a password set.");
724 
725    /* show the channels they have access to, if any */
726    *tobuf = '\0';
727    for (chan = tmp->channels; chan; chan = chan->next)
728      {
729 	snprintf(tb2, sizeof(tb2)-1, " %s%s%s%s", chan->channel, chan->modes ? "(+" : "",
730 		 recreate_cmode(chan), chan->modes ? ")" : "");
731 	strmcat(tobuf, tb2, sizeof(tobuf)-1);
732 	count++;
733      }
734    if (*tobuf)
735      put_info("on channel%s:%s", PLURAL(count), tobuf);
736 
737    /* show what hostsmasks they use */
738    *tobuf = '\0';
739    count = 0;
740    for (host = tmp->hosts; host; host = host->next)
741      {
742 	strmcat(tobuf, " ", sizeof(tobuf)-1);
743 	strmcat(tobuf, host->host, sizeof(tobuf)-1);
744 	count++;
745      }
746    if (*tobuf)
747      put_info("from hostmask%s:%s", PLURAL(count), tobuf);
748 }
749 
750 
751 /*
752  * this does initial checking for a friend /command
753  * .. if 0 is return, the supplied information is no good.
754  *
755  * rm will be set to 1 or 0 depending on the first character of the cmd string.
756  * f will be set to the friend entry for removes or not modified for !rm
757  *
758  */
759 static	int
friends_cmd_chk(cmd,uastr,urstr,nick,f)760 friends_cmd_chk(cmd, uastr, urstr, nick, f)
761    u_char *cmd;
762    u_char *uastr, *urstr;
763    u_char *nick;
764    Friend **f;
765 {
766    Friend *tmp;
767 
768    if (!cmd || !*cmd) /* just in case */
769      return 0;
770    if (!nick || !*nick)
771      {
772 	if (urstr)
773 	  usage(cmd, urstr);
774 	else
775 	  usage(cmd, uastr);
776 	return 0;
777      }
778    tmp = get_friend(nick);
779    /* if no friend found and not adding a friend... */
780    if (!tmp
781        && my_stricmp(cmd, "friend add") != 0)
782      {
783 	put_error("Unable to locate \"%s\" in your friends list.", nick);
784 	return 0;
785      }
786    *f = tmp;
787    return 1;
788 }
789 
790 
791 /*
792  * decifer a user/channel mode string based on requested and allowed mode strings...
793  */
794 int
decifer_mode(mstr,mode,amstr)795 decifer_mode(mstr, mode, amstr)
796    u_char *mstr;
797    unsigned long *mode;
798    const u_char *amstr;
799 {
800    unsigned long value = 0;
801    int add = 0;
802    const u_char *p;
803 
804    /* sanity */
805    if (!mstr || !*mstr)
806      return 0;
807 
808    /* go through the mode string and look for valid mode characters */
809    for (; *mstr; mstr++)
810      {
811 	for (p = amstr; *p; p++)
812 	  if (*p == *mstr)
813 	    break;
814 	if (*p)
815 	  {
816 	     unsigned long tv = (p - amstr);
817 
818 	     if (tv == 0)
819 	       value = 1;
820 	     else
821 	       {
822 		  value = 2;
823 		  while (--tv)
824 		    value *= 2;
825 	       }
826 	  }
827 	else
828 	  {
829 	     switch (*mstr)
830 	       {
831 		case '+':
832 		  add = 1;
833 		  value = 0;
834 		  break;
835 		case '-':
836 		  add = 0;
837 		  value = 0;
838 		  break;
839 		default:
840 		  put_error("decifer_chanmode: unknown mode character '%c'", *mstr);
841 		  break;
842 	       }
843 	  }
844 	if (value)
845 	  {
846 	     if (add)
847 	       *mode |= value;
848 	     else
849 	       *mode &= ~value;
850 	  }
851      }
852    return 1;
853 }
854 
855 /*
856  * decifer the usermode from mode_string
857  * examples: +nfd +n +fd
858  * modifies the char pointed to by mode to
859  * resemble the modes.
860  */
861 int
decifer_usermode(mode_string,mode)862 decifer_usermode(mode_string, mode)
863    u_char *mode_string;
864    unsigned long *mode;
865 {
866    return decifer_mode(mode_string, mode, usermode_str);
867 }
868 
869 /*
870  * decifer the channel mode from mode_string
871  * examples: +aiouk +acn etc.
872  * modifies the long integer pointed to by mode to reflect the modes
873  */
874 int
decifer_chanmode(mode_string,mode)875 decifer_chanmode(mode_string, mode)
876    u_char *mode_string;
877    unsigned long *mode;
878 {
879    return decifer_mode(mode_string, mode, chanmode_str);
880 }
881 
882 
883 /*
884  * recreates a mode string from a bitwise mode and a string of correlating
885  * characters...
886  */
887 int
recreate_mode(bwm,mstr,dest,dlen)888 recreate_mode(bwm, mstr, dest, dlen)
889    int bwm;
890    const u_char *mstr;
891    u_char *dest;
892    int dlen;
893 {
894    u_char *p = dest;
895    int mi, mode;
896    const u_char func_str[] = "recreate_mode";
897 
898    /* reset the buffer.. */
899    memset(dest, 0, dlen);
900    if (!bwm)
901      return 1;
902 
903    /* go through the possible modes and check for
904     * each being set.. if so add the character to the
905     * return buffer
906     */
907    for (mode = bwm, mi = 0;
908 	mode && mstr[mi];
909 	mode /= 2, mi++)
910      {
911 	if ((p - dest) >= dlen)
912 	  {
913 	     put_error("%s: truncating buffer", func_str);
914 	     break;
915 	  }
916 	if (mi >= strlen(mstr))
917 	  {
918 	     put_error("%s: non-zero mode with no more mode characters", func_str);
919 	     break;
920 	  }
921 	if (mode % 2)
922 	  *p++ = mstr[mi];
923      }
924    if (!mstr[mi] && mode)
925      put_error("%s: ack! remaining mode value: 0x%08lx", func_str, mode);
926    return 1;
927 }
928 
929 
930 /*
931  * recreates the user mode..
932  *
933  * takes a pointer to a friends list entry (or the address of one) and
934  * returns a pointer to a string representing the ascii "readable" mode
935  * which is created from the entries' mode element
936  */
937 u_char *
recreate_umode(Friend * tmp)938 recreate_umode(Friend * tmp)
939 {
940    static u_char retbuf[32];
941 
942    (void) recreate_mode(tmp->modes, usermode_str, retbuf, sizeof(retbuf));
943    return retbuf;
944 }
945 
946 /*
947  * returns a pointer to a string with the ascii representation of the modes
948  * from the channel list entries' mode element
949  * takes an argument of an address of a FChan entry
950  */
951 u_char *
recreate_cmode(FChan * tmp)952 recreate_cmode(FChan * tmp)
953 {
954    static u_char retbuf[32];
955 
956    (void) recreate_mode(tmp->modes, chanmode_str, retbuf, sizeof(retbuf));
957    return retbuf;
958 }
959 
960 /*
961  * check to see if a protected friend is getting banned or deopped and
962  * reverse the action...
963  *
964  * future:
965  * - enforce modes defined for the user... (+[ao]vu) of +p
966  * - enforce bans on any friend hostmasks..
967  */
968 void
check_friend_protection(u_char * from,Channel * chan,u_char * line)969 check_friend_protection(u_char *from, Channel *chan, u_char *line)
970 {
971    Friend *f;
972    FChan *fc;
973    FHost *fh;
974    Nick *n;
975    int add = 0, itsme = 0;
976    u_char *user, *mode;
977    u_char tb1[1024];
978    u_char *free_copy = UNULL, *rest;
979 
980    if (!friend_list || !(chan->status & CHAN_CHOP))
981      return;
982 
983    /* make a copy so we can mangle it.. */
984    dma_strcpy(&free_copy, line);
985    rest = free_copy;
986    tb1[0] = '\0';
987 
988    /* me? */
989    itsme = my_stricmp(from, get_server_nickname(chan->server)) == 0;
990 
991    /* while we have something... */
992    mode = next_arg(rest, &rest);
993    for (; *mode; mode++)
994      {
995 	switch (*mode)
996 	  {
997 	   case '+':
998 	     add = 1;
999 	     break;
1000 	   case '-':
1001 	     add = 0;
1002 	     break;
1003 	   case 'o':
1004 	     if (add)
1005 	       break;
1006 
1007 	     /* who got deopped? */
1008 	     user = next_arg(rest, &rest);
1009 	     /* sanity... ignore: no-one, me-deopping, self deop.. (possibly friends deopping) */
1010 	     if (!user || my_stricmp(user, from) == 0 || itsme)
1011 	       break;
1012 	     /* if we can't find the person getting deopped on the channel, give up... */
1013 	     if ((n = find_nick(user, UNULL, chan->server, chan)) == NULL)
1014 	       continue;
1015 	     /* if the person getting deopped is a friend on this channel or * and is protected ... */
1016 	     if ((f = get_friend_by_nuh(n->nick, n->user, n->host))
1017 		 && (fc = get_fchan(f, chan->channel, !MUST_BE_EXACT))
1018 		 && (fc->modes & FL_CMODE_PROTECTED))
1019 	       {
1020 		  strmcat(tb1, " +o ", sizeof(tb1)-1);
1021 		  strmcat(tb1, user, sizeof(tb1)-1);
1022 	       }
1023 	     break;
1024 	   case 'b':
1025 	     if (!add)
1026 	       break;
1027 
1028 	     /* who got banned? */
1029 	     user = next_arg(rest, &rest);
1030 	     /* sanity... ignore: no-one, me-banning... (possibly friends banning) */
1031 	     if (!user || my_stricmp(user, from) == 0 || itsme)
1032 	       break;
1033 
1034 	     /* see if the mask getting banned matches any of our friends that are
1035 	      * protected on this channel..
1036 	      */
1037 	     for (f = friend_list; f; f = f->next)
1038 	       {
1039 		  if ((fc = get_fchan(f, chan->channel, !MUST_BE_EXACT))
1040 		      && (fc->modes & FL_CMODE_PROTECTED))
1041 		    {
1042 		       for (fh = f->hosts; fh; fh = fh->next)
1043 			 if (match(user, fh->host)
1044 			     || match(fh->host, user))
1045 			   break;
1046 		       if (fh)
1047 			 {
1048 			    strmcat(tb1, " -b ", sizeof(tb1)-1);
1049 			    strmcat(tb1, user, sizeof(tb1)-1);
1050 			 }
1051 		    }
1052 	       }
1053 	     break;
1054 	  }
1055      }
1056    if (*tb1)
1057       send_to_server("MODE %s %s", chan->channel, tb1);
1058 }
1059 
1060 /*
1061  * checks to see if:
1062  * a) friends with ops aren't opped
1063  * b) friends with voice can't talk
1064  * c) protected friends are banned
1065  * and proceeds to:
1066  * a) op them
1067  * b) voice them
1068  * c) unban them
1069  */
1070 void
friends_channel_sync(Channel * chan)1071 friends_channel_sync(Channel *chan)
1072 {
1073    Nick *n;
1074    Friend *f;
1075    FChan *fc;
1076 
1077    if (!friend_list
1078        || !(chan->status & CHAN_CHOP))
1079      return;
1080 
1081    /* see if anyone on the channel needs anything */
1082    for (n = chan->nicks; n; n = n->next)
1083      {
1084 	/* they're not a friend? */
1085 	if (!(f = get_friend_by_nuh(n->nick, n->user, n->host)))
1086 	  continue;
1087 
1088 	/* they've no access to the channel? */
1089 	if (!(fc = get_fchan(f, chan->channel, !MUST_BE_EXACT)))
1090 	  continue;
1091 
1092 	/* if there's something they need, give it to them */
1093 	if ((fc->modes & FL_CMODE_AUTOOP)
1094 	    && !(n->status & NICK_CHOP))
1095 	  adddelayop(chan->channel, n->nick, chan->server, 0, 1);
1096 	if ((fc->modes & FL_CMODE_VOICE)
1097 	    && !(n->status & NICK_VOICE))
1098 /*	    && !(n->status & NICK_CHOP)) */
1099 	  adddelayop(chan->channel, n->nick, chan->server, 1, 1);
1100      }
1101 
1102    /* see if any of my protected friend's hostmasks are banned.. if so remove the bans.. */
1103    fc_sync_bans(chan);
1104 }
1105 
1106 static void
fc_sync_bans(Channel * chan)1107 fc_sync_bans(Channel *chan)
1108 {
1109    Friend *f;
1110    FChan *fc;
1111    FHost *fh;
1112    Ban *b;
1113    int mch, rmch, count = 0;
1114    char tb[512];
1115 
1116    *tb = '\0';
1117    for (b = chan->bans; b; b = b->next)
1118      {
1119 	/* see if this ban matches any one of a protected friends' hosts */
1120 	for (f = friend_list; f; f = f->next)
1121 	  {
1122 	     /* no access to this channel? */
1123 	     if (!(fc = get_fchan(f, chan->channel, !MUST_BE_EXACT)))
1124 	       continue;
1125 
1126 	     /* not protected on this channel? */
1127 	     if (!(fc->modes & FL_CMODE_PROTECTED))
1128 	       continue;
1129 
1130 	     /* look for a matching host.. */
1131 	     for (fh = f->hosts; fh; fh = fh->next)
1132 	       {
1133 		  mch = match(fh->host, b->ban);
1134 		  rmch = match(b->ban, fh->host);
1135 		  /* found one?  add it! */
1136 		  if (mch || rmch)
1137 		    {
1138 		       if (*tb)
1139 			 strmcat(tb, " ", sizeof(tb)-1);
1140 		       strmcat(tb, b->ban, sizeof(tb)-1);
1141 		       count++;
1142 
1143 		       /* max bans per line? */
1144 		       if (count == 4)
1145 			 {
1146 			    send_to_server("MODE %s -bbbb %s", chan->channel, tb);
1147 			    *tb = '\0';
1148 			    count = 0;
1149 			 }
1150 		    }
1151 	       }
1152 	  }
1153      }
1154 
1155    /* if there are some left.. do the unbanning.. */
1156    if (count > 0)
1157      send_to_server("MODE %s -%s %s", chan->channel, strfill('b', count), tb);
1158 }
1159 
1160 void
floodprot(char * nick,char * user,char * host,char * type,int ctcp_type,int ignoretime,char * channel)1161 floodprot(char *nick, char *user, char *host, char *type, int ctcp_type, int ignoretime, char *channel)
1162 {
1163    int old_window_display;
1164    Friend *tmp;
1165    char tb1[1024];
1166 
1167    if (!my_stricmp(nick, get_server_nickname(from_server)))
1168       return;
1169    if (((tmp = get_friend_by_nuh(nick, user, host)) != NULL) && tmp->modes & FL_UMODE_NO_FLOOD)
1170       return;
1171    if (get_int_var(FLOOD_WARNING_VAR))
1172       put_info("%s flooding detected from %s(%s@%s)", type, nick, user, host);
1173    if (!get_int_var(FLOOD_PROTECTION_VAR) || !ignoretime)
1174       return;
1175 
1176    /* ignore user */
1177    snprintf(tb1, sizeof(tb1)-1, "%s@%s %s", user, host, type);
1178    tb1[sizeof(tb1)-1] = '\0';
1179    old_window_display = window_display;
1180    window_display = 0;
1181    ignore(NULL, tb1, NULL);
1182    window_display = old_window_display;
1183 
1184    /* auto-unignore user after a while */
1185    snprintf(tb1, sizeof(tb1)-1, "%d IGNORE %s@%s NONE", ignoretime, user, host);
1186    tb1[sizeof(tb1)-1] = '\0';
1187    timercmd("TIMER", tb1, NULL);
1188    put_info("Ignoring %s from %s@%s for %d seconds.", type, user, host, ignoretime);
1189 }
1190 
1191 /*
1192  * make a random salt.
1193  *
1194  * written by Joshua J. Drake
1195  * 1998-03-05 02:30:00
1196  *
1197  * doesn't use librand anymore, 11/20/98
1198  */
1199 u_char *
make_salt(u_char * nick)1200 make_salt(u_char *nick)
1201 {
1202    static u_char salt[3];
1203    const u_char *saltchars = "./abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
1204    long numscs = strlen(saltchars);
1205 
1206    srand(time(NULL));
1207    salt[0] = saltchars[rand() % numscs];
1208    srand(time(NULL));
1209    salt[1] = saltchars[rand() % numscs];
1210    salt[2] = '\0';
1211    return salt;
1212 }
1213 
1214 /*
1215  * load the friends list...
1216  */
1217 int
load_friends(quiet)1218 load_friends(quiet)
1219    int quiet;
1220 {
1221    Friend *f = NULL;
1222    FHost *fh;
1223    FChan *fc;
1224 
1225    u_char file[] = NINJA_FRIEND_FILE;
1226    FILE *infile;
1227 
1228    u_char *field, *kraig, *tm, *ptr, *tc;
1229    u_char linebuf[1024];
1230    int position, count = 0, errocc = 0, linecnt = 0, added = 0;
1231 
1232    /* initialize some stuff.. */
1233    field = kraig = tm = tc = UNULL;
1234 
1235    /* open the friends list file */
1236    ptr = expand_twiddle(file);
1237    infile = fopen(ptr, "r");
1238    dma_Free(&ptr);
1239    if (infile == (FILE *) NULL)
1240      {
1241 	if (!quiet)
1242 	  put_info("Unable to load friends from \"%s\"...", file);
1243 	return 0;
1244      }
1245 
1246    /* loop until we've read everything.. */
1247    memset(linebuf, 0, sizeof(linebuf));
1248    while (fgets(linebuf, sizeof(linebuf)-1, infile))
1249      {
1250 	/* line number.. regardless of comments */
1251 	linecnt++;
1252 
1253 	/* comments.. */
1254 	if (*linebuf == '#')
1255 	  continue;
1256 
1257 	/* strip cr/lf */
1258 	if ((ptr = strchr(linebuf, '\r')))
1259 	  *ptr = '\0';
1260 	if ((ptr = strchr(linebuf, '\n')))
1261 	  *ptr = '\0';
1262 
1263 	/* empty line? */
1264 	if (*linebuf == '\0')
1265 	  continue;
1266 
1267 	/* allocate a friend */
1268 	f = (Friend *) dma_Malloc(sizeof(Friend));
1269 	if (!f)
1270 	  {
1271 	     put_error("Unable to allocate memory for friend at %s:%d", file, linecnt);
1272 	     break;
1273 	  }
1274 
1275 	/* reset position */
1276 	position = added  = 0;
1277 
1278 	/* while we have more fields..
1279 	 *
1280 	 * nick:pass:mode:host1:..:hostN:#chan1+mode:..:#chanN+mode\n
1281 	 */
1282 	kraig = linebuf;
1283 	while ((ptr = my_strsep(&kraig, ":")))
1284 	  {
1285 	     /* what position are we in? */
1286 	     switch (position)
1287 	       {
1288 		  /* position 0: the nick */
1289 		case 0:
1290 		  if (!*ptr)
1291 		    {
1292 		       errocc = 1;
1293 		       break;
1294 		    }
1295 		  dma_strcpy(&f->nick, ptr);
1296 		  position++;
1297 		  break;
1298 
1299 		  /* position 1: the password */
1300 		case 1:
1301 		  if (*ptr != '\0')
1302 		    dma_strcpy(&f->password, ptr);
1303 		  position++;
1304 		  break;
1305 
1306 		  /* position 2: the user mode */
1307 		case 2:
1308 		  decifer_usermode(ptr, &f->modes);
1309 		  position++;
1310 		  add_to_list((List **) & friend_list, (List *) f);
1311 		  added = 1;
1312 
1313 		  /* increase the count */
1314 		  count++;
1315 		  break;
1316 
1317 		  /* position 3+: a host or channel */
1318 		default:
1319 		  /* a host? */
1320 		  if (!is_channel(ptr)
1321 		      && match("*!*@*", ptr))
1322 		    {
1323 		       /* free it we found it */
1324 		       if ((fh = (FHost *) remove_from_list((List **)&f->hosts, ptr)) != NULL)
1325 			 free_fhost(fh);
1326 
1327 		       /* add it (again?) */
1328 		       fh = (FHost *) dma_Malloc(sizeof(FHost));
1329 		       if (!fh)
1330 			 {
1331 			    put_error("Unable to allocate memory for friend host at %s:%d (%d)", file, linecnt, position);
1332 			    errocc = quiet = 1;
1333 			    break;
1334 			 }
1335 		       dma_strcpy(&fh->host, ptr);
1336 		       add_to_list((List **) & (f->hosts), (List *) fh);
1337 		    }
1338 
1339 		  /* a channel? */
1340 		  else if ((is_channel(ptr) || *ptr == '*'))
1341 		    {
1342 		       /* save the channel name because we can't overwrite the + with null.. */
1343 		       dma_strcpy(&tc, ptr);
1344 
1345 		       /* does it have a mode?? */
1346 		       tm = strrchr(ptr, '+');
1347 		       if (tm)
1348 			 {
1349 			    /* truncate the copied string to the channel name.. */
1350 			    *(strrchr(tc, '+')) = '\0';
1351 			 }
1352 
1353 		       /* free it if we found it */
1354 		       if ((fc = (FChan *) remove_from_list((List **)&f->channels, ptr)) != NULL)
1355 			 free_fchan(fc);
1356 
1357 		       fc = (FChan *) dma_Malloc(sizeof(FChan));
1358 		       if (!fc)
1359 			 {
1360 			    put_error("Unable to allocate memory for friend channel at %s:%d (%d)", file, linecnt, position);
1361 			    errocc = quiet = 1;
1362 			    break;
1363 			 }
1364 		       dma_strcpy(&fc->channel, tc);
1365 		       dma_Free(&tc);
1366 		       decifer_chanmode(tm, &fc->modes);
1367 		       add_to_list((List **) & (f->channels), (List *) fc);
1368 		    }
1369 
1370 		  /* regardless... */
1371 		  position++;
1372 		  break;
1373 	       }
1374 
1375 	     /* error occurred?? */
1376 	     if (errocc)
1377 	       {
1378 		  if (!quiet)
1379 		    put_error("Skipping malformed saved friend at %s:%d (at position %d)", file, linecnt, position);
1380 		  free_friend(f);
1381 		  break;
1382 	       }
1383 	  }
1384 	if (!added)
1385 	  {
1386 	     if (!quiet)
1387 	       put_error("Not adding malformed saved friend at %s:%d (at position %d)", file, linecnt, position-1);
1388 	     free_friend(f);
1389 	  }
1390 	memset(linebuf, 0, sizeof(linebuf));
1391      }
1392    fclose(infile);
1393    return count;
1394 }
1395 
1396 /*
1397  * Save's the friends list..
1398  * format:
1399  * <nick>:<enc pw>:<user modes>:<host1>:<hostn>:#channel1+chanmodes:*+chanmodes etc
1400  * saves to ~/.ninja/ninja.passwd  if (quiet) we don't show the output..  this is
1401  * when someone is ident'n (partially re-written by Senor Pato)
1402  *
1403  * returns the # of friends saved
1404  */
1405 int
save_friends(quiet)1406 save_friends(quiet)
1407     int quiet;
1408 {
1409    Friend *friend;
1410    FChan *channels;
1411    FHost *hosts;
1412    u_char file[] = NINJA_FRIEND_FILE;
1413    FILE *outfile;
1414    u_char *ptr, tb1[1024], tb2[256];
1415    int count = 0;
1416 
1417    ptr = expand_twiddle(file);
1418    outfile = fopen(ptr, "w");
1419    dma_Free(&ptr);
1420    if (outfile == (FILE *) NULL)
1421      {
1422 	put_info("Unable to write to \"%s\", aborting userlist save..", file);
1423 	return 0;
1424      }
1425    for (friend = friend_list; friend; friend = friend->next)
1426      {
1427 	snprintf(tb1, sizeof(tb1)-1, "%s:%s:+%s%s",
1428 		 friend->nick,
1429 		 friend->password ? friend->password : empty_string,
1430 		 recreate_umode(friend),
1431 		 friend->hosts || friend->channels ? UP(":") : empty_string);
1432 	tb1[sizeof(tb1)-1] = '\0';
1433 
1434 	for (hosts = friend->hosts; hosts; hosts = hosts->next)
1435 	  {
1436 	     snprintf(tb2, sizeof(tb2)-1, "%s%s", hosts->host, friend->channels ? ":" : "");
1437 	     tb2[sizeof(tb2)-1] = '\0';
1438 	     strmcat(tb1, tb2, sizeof(tb1)-1);
1439 	  }
1440 	for (channels = friend->channels; channels; channels = channels->next)
1441 	  {
1442 	     snprintf(tb2, sizeof(tb2)-1, "%s+%s%s", channels->channel, recreate_cmode(channels), channels->next ? ":" : "");
1443 	     tb2[sizeof(tb2)-1] = '\0';
1444 	     strmcat(tb1, tb2, sizeof(tb1)-1);
1445 	  }
1446 	count++;
1447 	fprintf(outfile, "%s\n", tb1);
1448      }
1449    fclose(outfile);
1450    if (!quiet && count > 0)
1451      put_info("Saved %d friend%s...", count, PLURAL(count));
1452    return count;
1453 }
1454 
1455 
1456 /*
1457  * lookup a friend in the list
1458  */
1459 Friend *
get_friend(u_char * nick)1460 get_friend(u_char *nick)
1461 {
1462    return (Friend *) find_in_list((List **)&friend_list, nick, !USE_WILDCARDS);
1463 }
1464 
1465 
1466 /*
1467  * lookup a channel for a friend
1468  */
1469 FChan *
get_fchan(Friend * f,u_char * chan,int exact)1470 get_fchan(Friend *f, u_char *chan, int exact)
1471 {
1472    FChan *fchan;
1473 
1474    if ((fchan = (FChan *) find_in_list((List **)&(f->channels), chan, !USE_WILDCARDS)) != NULL)
1475      return fchan;
1476    if (!exact)
1477      for (fchan = f->channels; fchan; fchan = fchan->next)
1478        {
1479 	  if (!strcmp(fchan->channel, "*"))
1480 	    return fchan;
1481        }
1482    return NULL;
1483 }
1484 
1485 /*
1486  * get a friends's host entry that the passed hostmask matches
1487  */
1488 FHost *
get_fhost(Friend * f,u_char * hostmask)1489 get_fhost(Friend *f, u_char *hostmask)
1490 {
1491    FHost *fh;
1492    int ip = 0;
1493    u_char *p, *oldp;
1494 
1495    for (fh = f->hosts; fh; fh = fh->next)
1496      {
1497 	/* first see if this host is an IP */
1498 	oldp = p = my_rindex(fh->host, '@');
1499 	if (!p)
1500 	  {
1501 	     put_error("missing @ in fh->host");
1502 	     return NULL;
1503 	  }
1504 	p++;
1505 	while (*p)
1506 	  {
1507 	     if (isdigit(*p) || *p == '.' || *p == '*' || *p == '?' || *p == '%')
1508 	       ip = 1;
1509 	     else
1510 	       {
1511 		  ip = 0;
1512 		  break;
1513 	       }
1514 	     p++;
1515 	  }
1516 
1517 	/* if its an IP treat it differently.. */
1518 	if (ip)
1519 	  {
1520 	     u_char *q;
1521 	     int mch = 0;
1522 
1523 	     /* split the hostmask */
1524 	     q = my_rindex(hostmask, '@');
1525 	     if (!q)
1526 	       {
1527 		  put_error("missing @ in hostmask");
1528 		  return NULL;
1529 	       }
1530 	     *q = *oldp = '\0';
1531 	     if (match(fh->host, hostmask)
1532 		 && ip_match(oldp+1, q+1))
1533 	       mch = 1;
1534 	     *q = *oldp = '@';
1535 	     if (mch)
1536 	       return fh;
1537 	  }
1538 	else if (match(fh->host, hostmask))
1539 	  return fh;
1540      }
1541    return NULL;
1542 }
1543 
1544 /*
1545  * find a friend by trying to match the passed user@host
1546  */
1547 Friend *
get_friend_by_mask(u_char * hostmask)1548 get_friend_by_mask(u_char *hostmask)
1549 {
1550    Friend *f, *done = NULL;
1551    FHost *fhost;
1552 
1553    /* must we traverse the whole thing?!
1554     *
1555     * well, its usually small and we need to check for dupes!
1556     * -jjd
1557     */
1558    for (f = friend_list; f; f = f->next)
1559      {
1560 	fhost = get_fhost(f, hostmask);
1561 	if (fhost)
1562 	  {
1563 	     if (done)
1564 	       put_info("WARNING: %s matches more than one friend, using %s", hostmask, done->nick);
1565 	     else
1566 	       done = f;
1567 	  }
1568      }
1569    return done;
1570 }
1571 
1572 /*
1573  * find a friend by trying to match the passed user@host
1574  */
1575 Friend *
get_friend_by_nuh(u_char * nick,u_char * user,u_char * host)1576 get_friend_by_nuh(u_char *nick, u_char *user, u_char *host)
1577 {
1578    u_char tb1[1024], *p;
1579 
1580    if (!user || !host)
1581      return NULL;
1582 
1583    p = user;
1584    if (*p == '~') /* skip no-ident char */
1585      p++;
1586    snprintf(tb1, sizeof(tb1)-1, "%s!%s@%s",
1587 	    nick ? nick : asterik,
1588 	    p ? p : empty_string,
1589 	    host);
1590    tb1[sizeof(tb1)-1] = '\0';
1591    return get_friend_by_mask(tb1);
1592 }
1593 
1594 /*
1595  * check to see if we should do something to this person that is joining
1596  * this channel...
1597  *
1598  */
1599 void
check_friend_join(chan,nick,user,host,delay)1600 check_friend_join(chan, nick, user, host, delay)
1601    Channel *chan;
1602    u_char *nick, *user, *host;
1603    u_int delay;
1604 {
1605    Friend *f;
1606    FChan *fc;
1607    Nick *n;
1608 
1609    /* there was not enough information specified? */
1610    if (!chan || !nick || !user || !host)
1611      return;
1612 
1613    /* they're not on the channel? */
1614    if (!(n = find_nick(nick, UNULL, chan->server, chan)))
1615      return;
1616 
1617    /* i'm not opped? */
1618    if (!(chan->status & CHAN_CHOP))
1619      return;
1620 
1621    /* they're not a friend? */
1622    if (!(f = get_friend_by_nuh(nick, user, host)))
1623      return;
1624 
1625    /* they've no access to the channel? */
1626    if (!(fc = get_fchan(f, chan->channel, !MUST_BE_EXACT)))
1627      return;
1628 
1629    /* if there's something they need, give it to them */
1630    if ((fc->modes & FL_CMODE_AUTOOP)
1631        && !(n->status & NICK_CHOP))
1632      adddelayop(chan->channel, nick, chan->server, 0, delay);
1633    if ((fc->modes & FL_CMODE_VOICE)
1634        && !(n->status & NICK_VOICE))
1635      adddelayop(chan->channel, nick, chan->server, 1, delay);
1636 }
1637 
1638 /*
1639  * check to see if the user on notify is a friend, if so,
1640  * see if they have +n and invite them to the channels they have +n on
1641  */
1642 void
check_friend_notify(u_char * nick,u_char * user,u_char * hostname)1643 check_friend_notify(u_char *nick, u_char *user, u_char *hostname)
1644 {
1645    Friend *f;
1646    FChan *fc;
1647    Channel *chan;
1648    Nick *n;
1649 
1650    if (!nick || !user || !hostname)
1651      return;
1652 
1653    if (!(f = get_friend_by_nuh(nick, user, hostname)))
1654      return;
1655 
1656    for (chan = server_list[from_server].chan_list; chan; chan = chan->next)
1657      {
1658 	fc = get_fchan(f, chan->channel, !MUST_BE_EXACT);
1659 	n = find_nick(nick, UNULL, from_server, chan);
1660 	if (fc && !n
1661 	    && (fc->modes & FL_CMODE_NOTIFY_INVITE))
1662 	  send_to_server("INVITE %s %s", nick, chan->channel);
1663      }
1664 }
1665 
1666 /*
1667  * see if we are to auto-join invites from user, if so, do it
1668  */
1669 void
check_friend_invite(channel,nick,user,host)1670 check_friend_invite(channel, nick, user, host)
1671    u_char *channel, *nick, *user, *host;
1672 {
1673    Friend *f;
1674    FChan *fc;
1675 
1676    if (!nick || !user || !host || !channel)
1677      return;
1678    if (!(f = get_friend_by_nuh(nick, user, host)))
1679      return;
1680 
1681    if (!(fc = get_fchan(f, channel, !MUST_BE_EXACT)))
1682      return;
1683 
1684    if (fc->modes & FL_CMODE_JOIN)
1685      {
1686 	put_info("Auto-joining \"%s\" on invite from your friend \"%s\".", channel, f->nick);
1687 	send_to_server("JOIN %s %s", channel, get_ckey(channel));
1688      }
1689 }
1690 
1691 /*
1692  * see if we should auto-get files from User@Host
1693  * if so, return a pointer to their friends list entry
1694  */
1695 Friend *
check_friend_autoget(nick,user,host)1696 check_friend_autoget(nick, user, host)
1697    u_char *nick, *user, *host;
1698 {
1699    Friend *f;
1700 
1701    if (!nick || !user || !host)
1702      return NULL;
1703    if (!(f = get_friend_by_nuh(nick, user, host)))
1704      return NULL;
1705 
1706    if (f->modes & FL_UMODE_AUTO_DCC)
1707      return f;
1708    return NULL;
1709 }
1710 
1711 /*
1712  * see if we shouled enforce protection for someone
1713  * getting kicked.
1714  */
1715 void
check_friend_kick(channel,nick,user,host,kickee)1716 check_friend_kick(channel, nick, user, host, kickee)
1717    u_char *channel, *nick, *user, *host, *kickee;
1718 {
1719    Friend *fe, *fk;
1720    FChan *fc;
1721    Nick *n;
1722    Channel *chan;
1723 
1724    chan = lookup_channel(channel, from_server, CHAN_NOUNLINK);
1725    if (!chan || !(chan->status & CHAN_CHOP))
1726      return;
1727    /* if its me, don't act.. */
1728    if (my_stricmp(nick, get_server_nickname(chan->server)) == 0)
1729      return;
1730    if (!(n = find_nick(kickee, UNULL, chan->server, chan)))
1731      return;
1732    if (!(fe = get_friend_by_nuh(n->nick, n->user, n->host)))
1733      return;
1734    /* don't enforce protection against friends */
1735    if ((fk = get_friend_by_nuh(nick, user, host))
1736        && (fc = get_fchan(fk, chan->channel, !MUST_BE_EXACT)))
1737      return;
1738    /* if the kickee is protected on this channel, enforce protection */
1739    if ((fc = get_fchan(fe, chan->channel, !MUST_BE_EXACT)) && (fc->modes & FL_CMODE_PROTECTED))
1740      {
1741 	send_to_server("KICK %s %s :%s > you.", chan->channel, nick, kickee);
1742 	send_to_server("INVITE %s %s", kickee, chan->channel);
1743      }
1744 }
1745 
1746 
1747 
1748 /* free routines... */
1749 static	void
free_friend(f)1750 free_friend(f)
1751    Friend *f;
1752 {
1753    FHost *host, *thost;
1754    FChan *chan, *tchan;
1755 
1756    dma_Free(&f->nick);
1757    dma_Free(&f->password);
1758    /* free hosts */
1759    for (host = f->hosts; host != NULL; host = thost)
1760      {
1761 	thost = host->next;
1762 	free_fhost(host);
1763      }
1764    /* free channels */
1765    for (chan = f->channels; chan != NULL; chan = tchan)
1766      {
1767 	tchan = chan->next;
1768 	free_fchan(chan);
1769      }
1770    dma_Free(&f);
1771 }
1772 
1773 static	void
free_fchan(fc)1774 free_fchan(fc)
1775    FChan *fc;
1776 {
1777    dma_Free(&fc->channel);
1778    dma_Free(&fc);
1779 }
1780 
1781 static	void
free_fhost(fh)1782 free_fhost(fh)
1783    FHost *fh;
1784 {
1785    dma_Free(&fh->host);
1786    dma_Free(&fh);
1787 }
1788 
1789