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