/[cvs]/eggdrop1.8/src/users.c
ViewVC logotype

Contents of /eggdrop1.8/src/users.c

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.2 - (show annotations) (download) (as text)
Thu Aug 5 18:12:05 2010 UTC (8 years, 10 months ago) by pseudo
Branch: MAIN
CVS Tags: HEAD
Branch point for: gettext
Changes since 1.1: +1 -2 lines
File MIME type: text/x-chdr
Added new, full IPv6 support to eggdrop.

1 /*
2 * users.c -- handles:
3 * testing and enforcing ignores
4 * adding and removing ignores
5 * listing ignores
6 * auto-linking bots
7 * sending and receiving a userfile from a bot
8 * listing users ('.whois' and '.match')
9 * reading the user file
10 *
11 * dprintf'ized, 9nov1995
12 *
13 * $Id: users.c,v 1.1.1.1 2010/07/26 21:11:06 simple Exp $
14 */
15 /*
16 * Copyright (C) 1997 Robey Pointer
17 * Copyright (C) 1999 - 2010 Eggheads Development Team
18 *
19 * This program is free software; you can redistribute it and/or
20 * modify it under the terms of the GNU General Public License
21 * as published by the Free Software Foundation; either version 2
22 * of the License, or (at your option) any later version.
23 *
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 */
33
34 #include "main.h"
35 #include "users.h"
36 #include "chan.h"
37 #include "modules.h"
38 #include "tandem.h"
39
40 #include <netinet/in.h>
41 #include <arpa/inet.h>
42
43 extern struct dcc_t *dcc;
44 extern struct userrec *userlist, *lastuser;
45 extern struct chanset_t *chanset;
46 extern int dcc_total, noshare;
47 extern char botnetnick[];
48 extern Tcl_Interp *interp;
49 extern time_t now;
50
51 char userfile[121] = ""; /* where the user records are stored */
52 int ignore_time = 10; /* how many minutes will ignores last? */
53
54 /* is this nick!user@host being ignored? */
55 int match_ignore(char *uhost)
56 {
57 struct igrec *ir;
58
59 for (ir = global_ign; ir; ir = ir->next)
60 if (match_useraddr(ir->igmask, uhost))
61 return 1;
62 return 0;
63 }
64
65 int equals_ignore(char *uhost)
66 {
67 struct igrec *u = global_ign;
68
69 for (; u; u = u->next)
70 if (!rfc_casecmp(u->igmask, uhost)) {
71 if (u->flags & IGREC_PERM)
72 return 2;
73 else
74 return 1;
75 }
76 return 0;
77 }
78
79 int delignore(char *ign)
80 {
81 int i, j;
82 struct igrec **u;
83 struct igrec *t;
84 char temp[256];
85
86 i = 0;
87 if (!strchr(ign, '!') && (j = atoi(ign))) {
88 for (u = &global_ign, j--; *u && j; u = &((*u)->next), j--);
89 if (*u) {
90 strncpyz(temp, (*u)->igmask, sizeof temp);
91 i = 1;
92 }
93 } else {
94 /* find the matching host, if there is one */
95 for (u = &global_ign; *u && !i; u = &((*u)->next))
96 if (!rfc_casecmp(ign, (*u)->igmask)) {
97 strncpyz(temp, ign, sizeof temp);
98 i = 1;
99 break;
100 }
101 }
102 if (i) {
103 if (!noshare) {
104 char *mask = str_escape(temp, ':', '\\');
105
106 if (mask) {
107 shareout(NULL, "-i %s\n", mask);
108 nfree(mask);
109 }
110 }
111 nfree((*u)->igmask);
112 if ((*u)->msg)
113 nfree((*u)->msg);
114 if ((*u)->user)
115 nfree((*u)->user);
116 t = *u;
117 *u = (*u)->next;
118 nfree(t);
119 }
120 return i;
121 }
122
123 void addignore(char *ign, char *from, char *mnote, time_t expire_time)
124 {
125 struct igrec *p = NULL, *l;
126
127 for (l = global_ign; l; l = l->next)
128 if (!rfc_casecmp(l->igmask, ign)) {
129 p = l;
130 break;
131 }
132
133 if (p == NULL) {
134 p = user_malloc(sizeof(struct igrec));
135 p->next = global_ign;
136 global_ign = p;
137 } else {
138 nfree(p->igmask);
139 nfree(p->user);
140 nfree(p->msg);
141 }
142
143 p->expire = expire_time;
144 p->added = now;
145 p->flags = expire_time ? 0 : IGREC_PERM;
146 p->igmask = user_malloc(strlen(ign) + 1);
147 strcpy(p->igmask, ign);
148 p->user = user_malloc(strlen(from) + 1);
149 strcpy(p->user, from);
150 p->msg = user_malloc(strlen(mnote) + 1);
151 strcpy(p->msg, mnote);
152 if (!noshare) {
153 char *mask = str_escape(ign, ':', '\\');
154
155 if (mask) {
156 shareout(NULL, "+i %s %li %c %s %s\n", mask, expire_time - now,
157 (p->flags & IGREC_PERM) ? 'p' : '-', from, mnote);
158 nfree(mask);
159 }
160 }
161 }
162
163 /* take host entry from ignore list and display it ignore-style */
164 void display_ignore(int idx, int number, struct igrec *ignore)
165 {
166 char dates[81], s[41];
167
168 if (ignore->added) {
169 daysago(now, ignore->added, s);
170 sprintf(dates, "Started %s", s);
171 } else
172 dates[0] = 0;
173 if (ignore->flags & IGREC_PERM)
174 strcpy(s, "(perm)");
175 else {
176 char s1[41];
177
178 days(ignore->expire, now, s1);
179 sprintf(s, "(expires %s)", s1);
180 }
181 if (number >= 0)
182 dprintf(idx, " [%3d] %s %s\n", number, ignore->igmask, s);
183 else
184 dprintf(idx, "IGNORE: %s %s\n", ignore->igmask, s);
185 if (ignore->msg && ignore->msg[0])
186 dprintf(idx, " %s: %s\n", ignore->user, ignore->msg);
187 else
188 dprintf(idx, " %s %s\n", MODES_PLACEDBY, ignore->user);
189 if (dates[0])
190 dprintf(idx, " %s\n", dates);
191 }
192
193 /* list the ignores and how long they've been active */
194 void tell_ignores(int idx, char *match)
195 {
196 struct igrec *u = global_ign;
197 int k = 1;
198
199 if (u == NULL) {
200 dprintf(idx, "No ignores.\n");
201 return;
202 }
203 dprintf(idx, "%s:\n", IGN_CURRENT);
204 for (; u; u = u->next) {
205 if (match[0]) {
206 if (cmp_usermasks(match, u->igmask) ||
207 wild_match(match, u->msg) || wild_match(match, u->user))
208 display_ignore(idx, k, u);
209 k++;
210 } else
211 display_ignore(idx, k++, u);
212 }
213 }
214
215 /* check for expired timed-ignores */
216 void check_expired_ignores()
217 {
218 struct igrec **u = &global_ign;
219
220 if (!*u)
221 return;
222
223 while (*u) {
224 if (!((*u)->flags & IGREC_PERM) && (now >= (*u)->expire)) {
225 putlog(LOG_MISC, "*", "%s %s (%s)", IGN_NOLONGER, (*u)->igmask,
226 MISC_EXPIRED);
227 delignore((*u)->igmask);
228 } else
229 u = &((*u)->next);
230 }
231 }
232
233 /* Channel mask loaded from user file. This function is
234 * add(ban|invite|exempt)_fully merged into one. <cybah>
235 */
236 static void addmask_fully(struct chanset_t *chan, maskrec ** m,
237 maskrec ** global, char *mask, char *from, char *note,
238 time_t expire_time, int flags, time_t added,
239 time_t last)
240 {
241 maskrec *p = user_malloc(sizeof(maskrec));
242 maskrec **u = (chan) ? m : global;
243
244 p->next = *u;
245 *u = p;
246 p->expire = expire_time;
247 p->added = added;
248 p->lastactive = last;
249 p->flags = flags;
250 p->mask = user_malloc(strlen(mask) + 1);
251 strcpy(p->mask, mask);
252 p->user = user_malloc(strlen(from) + 1);
253 strcpy(p->user, from);
254 p->desc = user_malloc(strlen(note) + 1);
255 strcpy(p->desc, note);
256 }
257
258 static void restore_chanban(struct chanset_t *chan, char *host)
259 {
260 char *expi, *add, *last, *user, *desc;
261 int flags = 0;
262
263 expi = strchr_unescape(host, ':', '\\');
264 if (expi) {
265 if (*expi == '+') {
266 flags |= MASKREC_PERM;
267 expi++;
268 }
269 add = strchr(expi, ':');
270 if (add) {
271 if (add[-1] == '*') {
272 flags |= MASKREC_STICKY;
273 add[-1] = 0;
274 } else
275 *add = 0;
276 add++;
277 if (*add == '+') {
278 last = strchr(add, ':');
279 if (last) {
280 *last = 0;
281 last++;
282 user = strchr(last, ':');
283 if (user) {
284 *user = 0;
285 user++;
286 desc = strchr(user, ':');
287 if (desc) {
288 *desc = 0;
289 desc++;
290 addmask_fully(chan, &chan->bans, &global_bans, host, user,
291 desc, atoi(expi), flags, atoi(add), atoi(last));
292 return;
293 }
294 }
295 }
296 } else {
297 desc = strchr(add, ':');
298 if (desc) {
299 *desc = 0;
300 desc++;
301 addmask_fully(chan, &chan->bans, &global_bans, host, add, desc,
302 atoi(expi), flags, now, 0);
303 return;
304 }
305 }
306 }
307 }
308 putlog(LOG_MISC, "*", "*** Malformed banline for %s.",
309 chan ? chan->dname : "global_bans");
310 }
311
312 static void restore_chanexempt(struct chanset_t *chan, char *host)
313 {
314 char *expi, *add, *last, *user, *desc;
315 int flags = 0;
316
317 expi = strchr_unescape(host, ':', '\\');
318 if (expi) {
319 if (*expi == '+') {
320 flags |= MASKREC_PERM;
321 expi++;
322 }
323 add = strchr(expi, ':');
324 if (add) {
325 if (add[-1] == '*') {
326 flags |= MASKREC_STICKY;
327 add[-1] = 0;
328 } else
329 *add = 0;
330 add++;
331 if (*add == '+') {
332 last = strchr(add, ':');
333 if (last) {
334 *last = 0;
335 last++;
336 user = strchr(last, ':');
337 if (user) {
338 *user = 0;
339 user++;
340 desc = strchr(user, ':');
341 if (desc) {
342 *desc = 0;
343 desc++;
344 addmask_fully(chan, &chan->exempts, &global_exempts, host, user,
345 desc, atoi(expi), flags, atoi(add), atoi(last));
346 return;
347 }
348 }
349 }
350 } else {
351 desc = strchr(add, ':');
352 if (desc) {
353 *desc = 0;
354 desc++;
355 addmask_fully(chan, &chan->exempts, &global_exempts, host, add,
356 desc, atoi(expi), flags, now, 0);
357 return;
358 }
359 }
360 }
361 }
362 putlog(LOG_MISC, "*", "*** Malformed exemptline for %s.",
363 chan ? chan->dname : "global_exempts");
364 }
365
366 static void restore_chaninvite(struct chanset_t *chan, char *host)
367 {
368 char *expi, *add, *last, *user, *desc;
369 int flags = 0;
370
371 expi = strchr_unescape(host, ':', '\\');
372 if (expi) {
373 if (*expi == '+') {
374 flags |= MASKREC_PERM;
375 expi++;
376 }
377 add = strchr(expi, ':');
378 if (add) {
379 if (add[-1] == '*') {
380 flags |= MASKREC_STICKY;
381 add[-1] = 0;
382 } else
383 *add = 0;
384 add++;
385 if (*add == '+') {
386 last = strchr(add, ':');
387 if (last) {
388 *last = 0;
389 last++;
390 user = strchr(last, ':');
391 if (user) {
392 *user = 0;
393 user++;
394 desc = strchr(user, ':');
395 if (desc) {
396 *desc = 0;
397 desc++;
398 addmask_fully(chan, &chan->invites, &global_invites, host, user,
399 desc, atoi(expi), flags, atoi(add), atoi(last));
400 return;
401 }
402 }
403 }
404 } else {
405 desc = strchr(add, ':');
406 if (desc) {
407 *desc = 0;
408 desc++;
409 addmask_fully(chan, &chan->invites, &global_invites, host, add,
410 desc, atoi(expi), flags, now, 0);
411 return;
412 }
413 }
414 }
415 }
416 putlog(LOG_MISC, "*", "*** Malformed inviteline for %s.",
417 chan ? chan->dname : "global_invites");
418 }
419
420 static void restore_ignore(char *host)
421 {
422 char *expi, *user, *added, *desc;
423 int flags = 0;
424 struct igrec *p;
425
426 expi = strchr_unescape(host, ':', '\\');
427 if (expi) {
428 if (*expi == '+') {
429 flags |= IGREC_PERM;
430 expi++;
431 }
432 user = strchr(expi, ':');
433 if (user) {
434 *user = 0;
435 user++;
436 added = strchr(user, ':');
437 if (added) {
438 *added = 0;
439 added++;
440 desc = strchr(added, ':');
441 if (desc) {
442 *desc = 0;
443 desc++;
444 } else
445 desc = NULL;
446 } else {
447 added = "0";
448 desc = NULL;
449 }
450 p = user_malloc(sizeof(struct igrec));
451
452 p->next = global_ign;
453 global_ign = p;
454 p->expire = atoi(expi);
455 p->added = atoi(added);
456 p->flags = flags;
457 p->igmask = user_malloc(strlen(host) + 1);
458 strcpy(p->igmask, host);
459 p->user = user_malloc(strlen(user) + 1);
460 strcpy(p->user, user);
461 if (desc) {
462 p->msg = user_malloc(strlen(desc) + 1);
463 strcpy(p->msg, desc);
464 } else
465 p->msg = NULL;
466 return;
467 }
468 }
469 putlog(LOG_MISC, "*", "*** Malformed ignore line.");
470 }
471
472 void tell_user(int idx, struct userrec *u, int master)
473 {
474 char s[81], s1[81], format[81];
475 int n = 0;
476 time_t now2;
477 struct chanuserrec *ch;
478 struct user_entry *ue;
479 struct laston_info *li;
480 struct flag_record fr = { FR_GLOBAL, 0, 0, 0, 0, 0 };
481
482 fr.global = u->flags;
483
484 fr.udef_global = u->flags_udef;
485 build_flags(s, &fr, NULL);
486 if (module_find("notes", 0, 0)) {
487 Tcl_SetVar(interp, "_user", u->handle, 0);
488 if (Tcl_VarEval(interp, "notes ", "$_user", NULL) == TCL_OK)
489 n = tcl_resultint();
490 }
491 li = get_user(&USERENTRY_LASTON, u);
492 if (!li || !li->laston)
493 strcpy(s1, "never");
494 else {
495 now2 = now - li->laston;
496 if (now2 >= 86400)
497 egg_strftime(s1, 11, "%Y-%m-%d", localtime(&li->laston));
498 else
499 egg_strftime(s1, 6, "%H:%M", localtime(&li->laston));
500 }
501 egg_snprintf(format, sizeof format, "%%-%us %%-5s%%5d %%-15s %%s (%%s)\n",
502 HANDLEN);
503 dprintf(idx, format, u->handle,
504 get_user(&USERENTRY_PASS, u) ? "yes" : "no", n, s, s1,
505 (li && li->lastonplace) ? li->lastonplace : "nowhere");
506 /* channel flags? */
507 for (ch = u->chanrec; ch; ch = ch->next) {
508 fr.match = FR_CHAN | FR_GLOBAL;
509 get_user_flagrec(dcc[idx].user, &fr, ch->channel);
510 if (glob_op(fr) || chan_op(fr)) {
511 if (ch->laston == 0L)
512 strcpy(s1, "never");
513 else {
514 now2 = now - (ch->laston);
515 if (now2 >= 86400)
516 egg_strftime(s1, 11, "%Y-%m-%d", localtime(&ch->laston));
517 else
518 egg_strftime(s1, 6, "%H:%M", localtime(&ch->laston));
519 }
520 fr.match = FR_CHAN;
521 fr.chan = ch->flags;
522 fr.udef_chan = ch->flags_udef;
523 build_flags(s, &fr, NULL);
524 egg_snprintf(format, sizeof format, "%%%us %%-18s %%-15s %%s\n",
525 HANDLEN - 9);
526 dprintf(idx, format, " ", ch->channel, s, s1);
527 if (ch->info != NULL)
528 dprintf(idx, " INFO: %s\n", ch->info);
529 }
530 }
531 /* user-defined extra fields */
532 for (ue = u->entries; ue; ue = ue->next)
533 if (!ue->name && ue->type->display)
534 ue->type->display(idx, ue);
535 }
536
537 /* show user by ident */
538 void tell_user_ident(int idx, char *id, int master)
539 {
540 char format[81];
541 struct userrec *u;
542
543 u = get_user_by_handle(userlist, id);
544 if (u == NULL)
545 u = get_user_by_host(id);
546 if (u == NULL) {
547 dprintf(idx, "%s.\n", USERF_NOMATCH);
548 return;
549 }
550 egg_snprintf(format, sizeof format,
551 "%%-%us PASS NOTES FLAGS LAST\n", HANDLEN);
552 dprintf(idx, format, "HANDLE");
553 tell_user(idx, u, master);
554 }
555
556 /* match string:
557 * wildcard to match nickname or hostmasks
558 * +attr to find all with attr */
559 void tell_users_match(int idx, char *mtch, int start, int limit,
560 int master, char *chname)
561 {
562 char format[81];
563 struct userrec *u;
564 int fnd = 0, cnt, nomns = 0, flags = 0;
565 struct list_type *q;
566 struct flag_record user, pls, mns;
567
568 dprintf(idx, "*** %s '%s':\n", MISC_MATCHING, mtch);
569 cnt = 0;
570 egg_snprintf(format, sizeof format,
571 "%%-%us PASS NOTES FLAGS LAST\n", HANDLEN);
572 dprintf(idx, format, "HANDLE");
573 if (start > 1)
574 dprintf(idx, "(%s %d)\n", MISC_SKIPPING, start - 1);
575 if (strchr("+-&|", *mtch)) {
576 user.match = pls.match = FR_GLOBAL | FR_BOT | FR_CHAN;
577 break_down_flags(mtch, &pls, &mns);
578 mns.match = pls.match ^ (FR_AND | FR_OR);
579 if (!mns.global && !mns.udef_global && !mns.chan && !mns.udef_chan &&
580 !mns.bot) {
581 nomns = 1;
582 if (!pls.global && !pls.udef_global && !pls.chan && !pls.udef_chan &&
583 !pls.bot) {
584 /* happy now BB you weenie :P */
585 dprintf(idx, "Unknown flag specified for matching!!\n");
586 return;
587 }
588 }
589 if (!chname || !chname[0])
590 chname = dcc[idx].u.chat->con_chan;
591 flags = 1;
592 }
593
594 for (u = userlist; u; u = u->next) {
595 if (flags) {
596 get_user_flagrec(u, &user, chname);
597 if (flagrec_eq(&pls, &user)) {
598 if (nomns || !flagrec_eq(&mns, &user)) {
599 cnt++;
600 if ((cnt <= limit) && (cnt >= start)) {
601 tell_user(idx, u, master);
602 }
603 if (cnt == limit + 1) {
604 dprintf(idx, MISC_TRUNCATED, limit);
605 }
606 }
607 }
608 } else if (wild_match(mtch, u->handle)) {
609 cnt++;
610 if ((cnt <= limit) && (cnt >= start)) {
611 tell_user(idx, u, master);
612 }
613 if (cnt == limit + 1) {
614 dprintf(idx, MISC_TRUNCATED, limit);
615 }
616 } else {
617 fnd = 0;
618 for (q = get_user(&USERENTRY_HOSTS, u); q; q = q->next) {
619 if (wild_match(mtch, q->extra) && !fnd) {
620 cnt++;
621 fnd = 1;
622 if ((cnt <= limit) && (cnt >= start)) {
623 tell_user(idx, u, master);
624 }
625 if (cnt == limit + 1) {
626 dprintf(idx, MISC_TRUNCATED, limit);
627 }
628 }
629 }
630 }
631 }
632
633 dprintf(idx, MISC_FOUNDMATCH, cnt, cnt == 1 ? "" : MISC_MATCH_PLURAL);
634 }
635
636 /*
637 * tagged lines in the user file:
638 * * OLD:
639 * # (comment)
640 * ; (comment)
641 * - hostmask(s)
642 * + email
643 * * dcc directory
644 * = comment
645 * : info line
646 * . xtra (Tcl)
647 * ! channel-specific
648 * !! global laston
649 * :: channel-specific bans
650 * NEW:
651 * *ban global bans
652 * *ignore global ignores
653 * ::#chan channel bans
654 * - entries in each
655 * <handle> begin user entry
656 * --KEY INFO - info on each
657 * NEWER:
658 * % exemptmask(s)
659 * @ Invitemask(s)
660 * *exempt global exempts
661 * *Invite global Invites
662 * && channel-specific exempts
663 * &&#chan channel exempts
664 * $$ channel-specific Invites
665 * $$#chan channel Invites
666 */
667
668 int noxtra = 0;
669 int readuserfile(char *file, struct userrec **ret)
670 {
671 char *p, buf[512], lasthand[512], *attr, *pass, *code, s1[512], *s;
672 FILE *f;
673 struct userrec *bu, *u = NULL;
674 struct chanset_t *cst = NULL;
675 int i;
676 char ignored[LOGLINEMAX]; /* putlog() will truncate anything larger anyway */
677 struct flag_record fr;
678 struct chanuserrec *cr;
679
680 bu = (*ret);
681 ignored[0] = 0;
682 if (bu == userlist) {
683 clear_chanlist();
684 lastuser = NULL;
685 global_bans = NULL;
686 global_ign = NULL;
687 global_exempts = NULL;
688 global_invites = NULL;
689 }
690 lasthand[0] = 0;
691 f = fopen(file, "r");
692 if (f == NULL)
693 return 0;
694 noshare = noxtra = 1;
695 /* read opening comment */
696 s = buf;
697 fgets(s, 180, f);
698 if (s[1] < '4') {
699 fatal(USERF_OLDFMT, 0);
700 }
701 if (s[1] > '4')
702 fatal(USERF_INVALID, 0);
703 while (!feof(f)) {
704 s = buf;
705 fgets(s, 511, f);
706 if (!feof(f)) {
707 if (s[0] != '#' && s[0] != ';' && s[0]) {
708 code = newsplit(&s);
709 rmspace(s);
710 if (!strcmp(code, "-")) {
711 if (!lasthand[0])
712 continue; /* Skip this entry. */
713 if (u) { /* only break it down if there a real users */
714 p = strchr(s, ',');
715 while (p != NULL) {
716 splitc(s1, s, ',');
717 rmspace(s1);
718 if (s1[0])
719 set_user(&USERENTRY_HOSTS, u, s1);
720 p = strchr(s, ',');
721 }
722 }
723 /* channel bans are never stacked with , */
724 if (s[0]) {
725 if (lasthand[0] && strchr(CHANMETA, lasthand[0]) != NULL)
726 restore_chanban(cst, s);
727 else if (lasthand[0] == '*') {
728 if (lasthand[1] == 'i')
729 restore_ignore(s);
730 else
731 restore_chanban(NULL, s);
732 } else if (lasthand[0])
733 set_user(&USERENTRY_HOSTS, u, s);
734 }
735 } else if (!strcmp(code, "%")) { /* exemptmasks */
736 if (!lasthand[0])
737 continue; /* Skip this entry. */
738 if (s[0]) {
739 if (lasthand[0] == '#' || lasthand[0] == '+')
740 restore_chanexempt(cst, s);
741 else if (lasthand[0] == '*')
742 if (lasthand[1] == 'e')
743 restore_chanexempt(NULL, s);
744 }
745 } else if (!strcmp(code, "@")) { /* Invitemasks */
746 if (!lasthand[0])
747 continue; /* Skip this entry. */
748 if (s[0]) {
749 if (lasthand[0] == '#' || lasthand[0] == '+')
750 restore_chaninvite(cst, s);
751 else if (lasthand[0] == '*')
752 if (lasthand[1] == 'I')
753 restore_chaninvite(NULL, s);
754 }
755 } else if (!strcmp(code, "!")) {
756 /* ! #chan laston flags [info] */
757 char *chname, *st, *fl;
758
759 if (u) {
760 chname = newsplit(&s);
761 st = newsplit(&s);
762 fl = newsplit(&s);
763 rmspace(s);
764 fr.match = FR_CHAN;
765 break_down_flags(fl, &fr, 0);
766 if (findchan_by_dname(chname)) {
767 for (cr = u->chanrec; cr; cr = cr->next)
768 if (!rfc_casecmp(cr->channel, chname))
769 break;
770 if (!cr) {
771 cr = (struct chanuserrec *)
772 user_malloc(sizeof(struct chanuserrec));
773
774 cr->next = u->chanrec;
775 u->chanrec = cr;
776 strncpyz(cr->channel, chname, 80);
777 cr->laston = atoi(st);
778 cr->flags = fr.chan;
779 cr->flags_udef = fr.udef_chan;
780 if (s[0]) {
781 cr->info = (char *) user_malloc(strlen(s) + 1);
782 strcpy(cr->info, s);
783 } else
784 cr->info = NULL;
785 }
786 }
787 }
788 } else if (!strncmp(code, "::", 2)) {
789 /* channel-specific bans */
790 strcpy(lasthand, &code[2]);
791 u = NULL;
792 if (!findchan_by_dname(lasthand)) {
793 strcpy(s1, lasthand);
794 strcat(s1, " ");
795 if (strstr(ignored, s1) == NULL) {
796 strncat(ignored, lasthand,
797 sizeof(ignored) - 1 - strlen(ignored));
798 strncat(ignored, " ",
799 sizeof(ignored) - 1 - strlen(ignored));
800 }
801 lasthand[0] = 0;
802 } else {
803 /* Remove all bans for this channel to avoid dupes */
804 /* NOTE only remove bans for when getting a userfile
805 * from another bot & that channel is shared */
806 cst = findchan_by_dname(lasthand);
807 if ((*ret == userlist) || channel_shared(cst)) {
808 clear_masks(cst->bans);
809 cst->bans = NULL;
810 } else {
811 /* otherwise ignore any bans for this channel */
812 cst = NULL;
813 lasthand[0] = 0;
814 }
815 }
816 } else if (!strncmp(code, "&&", 2)) {
817 /* channel-specific exempts */
818 strcpy(lasthand, &code[2]);
819 u = NULL;
820 if (!findchan_by_dname(lasthand)) {
821 strcpy(s1, lasthand);
822 strcat(s1, " ");
823 if (strstr(ignored, s1) == NULL) {
824 strncat(ignored, lasthand,
825 sizeof(ignored) - 1 - strlen(ignored));
826 strncat(ignored, " ",
827 sizeof(ignored) - 1 - strlen(ignored));
828 }
829 lasthand[0] = 0;
830 } else {
831 /* Remove all exempts for this channel to avoid dupes */
832 /* NOTE only remove exempts for when getting a userfile
833 * from another bot & that channel is shared */
834 cst = findchan_by_dname(lasthand);
835 if ((*ret == userlist) || channel_shared(cst)) {
836 clear_masks(cst->exempts);
837 cst->exempts = NULL;
838 } else {
839 /* otherwise ignore any exempts for this channel */
840 cst = NULL;
841 lasthand[0] = 0;
842 }
843 }
844 } else if (!strncmp(code, "$$", 2)) {
845 /* channel-specific invites */
846 strcpy(lasthand, &code[2]);
847 u = NULL;
848 if (!findchan_by_dname(lasthand)) {
849 strcpy(s1, lasthand);
850 strcat(s1, " ");
851 if (strstr(ignored, s1) == NULL) {
852 strncat(ignored, lasthand,
853 sizeof(ignored) - 1 - strlen(ignored));
854 strncat(ignored, " ",
855 sizeof(ignored) - 1 - strlen(ignored));
856 }
857 lasthand[0] = 0;
858 } else {
859 /* Remove all invites for this channel to avoid dupes */
860 /* NOTE only remove invites for when getting a userfile
861 * from another bot & that channel is shared */
862 cst = findchan_by_dname(lasthand);
863 if ((*ret == userlist) || channel_shared(cst)) {
864 clear_masks(cst->invites);
865 cst->invites = NULL;
866 } else {
867 /* otherwise ignore any invites for this channel */
868 cst = NULL;
869 lasthand[0] = 0;
870 }
871 }
872 } else if (!strncmp(code, "--", 2)) {
873 if (u) {
874 /* new format storage */
875 struct user_entry *ue;
876 int ok = 0;
877
878 for (ue = u->entries; ue && !ok; ue = ue->next)
879 if (ue->name && !egg_strcasecmp(code + 2, ue->name)) {
880 struct list_type *list;
881
882 list = user_malloc(sizeof(struct list_type));
883
884 list->next = NULL;
885 list->extra = user_malloc(strlen(s) + 1);
886 strcpy(list->extra, s);
887 egg_list_append((&ue->u.list), list);
888 ok = 1;
889 }
890 if (!ok) {
891 ue = user_malloc(sizeof(struct user_entry));
892
893 ue->name = user_malloc(strlen(code + 1));
894 ue->type = NULL;
895 strcpy(ue->name, code + 2);
896 ue->u.list = user_malloc(sizeof(struct list_type));
897
898 ue->u.list->next = NULL;
899 ue->u.list->extra = user_malloc(strlen(s) + 1);
900 strcpy(ue->u.list->extra, s);
901 list_insert((&u->entries), ue);
902 }
903 }
904 } else if (!rfc_casecmp(code, BAN_NAME)) {
905 strcpy(lasthand, code);
906 u = NULL;
907 } else if (!rfc_casecmp(code, IGNORE_NAME)) {
908 strcpy(lasthand, code);
909 u = NULL;
910 } else if (!rfc_casecmp(code, EXEMPT_NAME)) {
911 strcpy(lasthand, code);
912 u = NULL;
913 } else if (!rfc_casecmp(code, INVITE_NAME)) {
914 strcpy(lasthand, code);
915 u = NULL;
916 } else if (code[0] == '*') {
917 lasthand[0] = 0;
918 u = NULL;
919 } else {
920 pass = newsplit(&s);
921 attr = newsplit(&s);
922 rmspace(s);
923 if (!attr[0] || !pass[0]) {
924 putlog(LOG_MISC, "*", "* %s '%s'!", USERF_CORRUPT, code);
925 lasthand[0] = 0;
926 } else {
927 u = get_user_by_handle(bu, code);
928 if (u && !(u->flags & USER_UNSHARED)) {
929 putlog(LOG_MISC, "*", "* %s '%s'!", USERF_DUPE, code);
930 lasthand[0] = 0;
931 u = NULL;
932 } else if (u) {
933 lasthand[0] = 0;
934 u = NULL;
935 } else {
936 fr.match = FR_GLOBAL;
937 break_down_flags(attr, &fr, 0);
938 strcpy(lasthand, code);
939 cst = NULL;
940 if (strlen(code) > HANDLEN)
941 code[HANDLEN] = 0;
942 if (strlen(pass) > 20) {
943 putlog(LOG_MISC, "*", "* %s '%s'", USERF_BROKEPASS, code);
944 strcpy(pass, "-");
945 }
946 bu = adduser(bu, code, 0, pass,
947 sanity_check(fr.global &USER_VALID));
948
949 u = get_user_by_handle(bu, code);
950 for (i = 0; i < dcc_total; i++)
951 if (!egg_strcasecmp(code, dcc[i].nick))
952 dcc[i].user = u;
953 u->flags_udef = fr.udef_global;
954 /* if s starts with '/' it's got file info */
955 }
956 }
957 }
958 }
959 }
960 }
961 fclose(f);
962 (*ret) = bu;
963 if (ignored[0]) {
964 putlog(LOG_MISC, "*", "%s %s", USERF_IGNBANS, ignored);
965 }
966 putlog(LOG_MISC, "*", "Userfile loaded, unpacking...");
967 for (u = bu; u; u = u->next) {
968 struct user_entry *e;
969
970 if (!(u->flags & USER_BOT) && !egg_strcasecmp(u->handle, botnetnick)) {
971 putlog(LOG_MISC, "*", "(!) I have a user record, but without +b");
972 /* u->flags |= USER_BOT; */
973 }
974
975 for (e = u->entries; e; e = e->next)
976 if (e->name) {
977 struct user_entry_type *uet = find_entry_type(e->name);
978
979 if (uet) {
980 e->type = uet;
981 uet->unpack(u, e);
982 nfree(e->name);
983 e->name = NULL;
984 }
985 }
986 }
987 noshare = noxtra = 0;
988 /* process the user data *now* */
989 return 1;
990 }
991
992 /* New methodology - cycle through list 3 times
993 * 1st time scan for +sh bots and link if none connected
994 * 2nd time scan for +h bots
995 * 3rd time scan for +a/+h bots */
996 void autolink_cycle(char *start)
997 {
998 struct userrec *u = userlist, *autc = NULL;
999 static int cycle = 0;
1000 int got_hub = 0, got_alt = 0, got_shared = 0, linked, ready = 0, i, bfl;
1001
1002 /* don't start a new cycle if some links are still pending */
1003 if (!start) {
1004 for (i = 0; i < dcc_total; i++) {
1005 if (dcc[i].type == &DCC_BOT_NEW)
1006 return;
1007 if (dcc[i].type == &DCC_FORK_BOT)
1008 return;
1009 if ((dcc[i].type == &DCC_DNSWAIT) &&
1010 (dcc[i].u.dns && (dcc[i].u.dns->type == &DCC_FORK_BOT)))
1011 return;
1012 }
1013 }
1014 if (!start) {
1015 ready = 1;
1016 cycle = 0;
1017 } /* new run through the user list */
1018 while (u && !autc) {
1019 while (u && !autc) {
1020 if (u->flags & USER_BOT && strcmp(u->handle, botnetnick)) { /* ignore our own user record */
1021 bfl = bot_flags(u);
1022 if (bfl & (BOT_HUB | BOT_ALT)) {
1023 linked = 0;
1024 for (i = 0; i < dcc_total; i++) {
1025 if (dcc[i].user == u) {
1026 if (dcc[i].type == &DCC_BOT)
1027 linked = 1;
1028 if (dcc[i].type == &DCC_BOT_NEW)
1029 linked = 1;
1030 if (dcc[i].type == &DCC_FORK_BOT)
1031 linked = 1;
1032 }
1033 }
1034 if ((bfl & BOT_HUB) && (bfl & BOT_SHARE)) {
1035 if (linked)
1036 got_shared = 1;
1037 else if (!cycle && ready && !autc)
1038 autc = u;
1039 } else if ((bfl & BOT_HUB) && cycle > 0) {
1040 if (linked)
1041 got_hub = 1;
1042 else if ((cycle == 1) && ready && !autc)
1043 autc = u;
1044 } else if ((bfl & BOT_ALT) && (cycle == 2)) {
1045 if (linked)
1046 got_alt = 1;
1047 else if (!in_chain(u->handle) && ready && !autc)
1048 autc = u;
1049 }
1050 /* did we make it where we're supposed to start? yay! */
1051 if (!ready)
1052 if (!egg_strcasecmp(u->handle, start)) {
1053 ready = 1;
1054 autc = NULL;
1055 /* if starting point is a +h bot, must be in 2nd cycle */
1056 if ((bfl & BOT_HUB) && !(bfl & BOT_SHARE)) {
1057 cycle = 1;
1058 }
1059 /* if starting point is a +a bot, must be in 3rd cycle */
1060 if (bfl & BOT_ALT) {
1061 cycle = 2;
1062 }
1063 }
1064 }
1065 if (!cycle && (bfl & BOT_REJECT) && in_chain(u->handle)) {
1066 /* get rid of nasty reject bot */
1067 int i;
1068
1069 i = nextbot(u->handle);
1070 if ((i >= 0) && !egg_strcasecmp(dcc[i].nick, u->handle)) {
1071 char *p = MISC_REJECTED;
1072
1073 /* we're directly connected to the offending bot?! (shudder!) */
1074 putlog(LOG_BOTS, "*", "%s %s", BOT_REJECTING, dcc[i].nick);
1075 chatout("*** %s bot %s\n", p, dcc[i].nick);
1076 botnet_send_unlinked(i, dcc[i].nick, p);
1077 dprintf(i, "bye %s\n", BOT_REJECTING);
1078 killsock(dcc[i].sock);
1079 lostdcc(i);
1080 } else if ((i < 0) && egg_strcasecmp(botnetnick, u->handle)) {
1081 /* The bot is not connected, but listed in our tandem list! */
1082 putlog(LOG_BOTS, "*", "(!) BUG: rejecting not connected bot %s!",
1083 u->handle);
1084 rembot(u->handle);
1085 }
1086 }
1087 }
1088 u = u->next;
1089 }
1090 if (!autc) {
1091 if (!cycle && !got_shared) {
1092 cycle++;
1093 u = userlist;
1094 } else if ((cycle == 1) && !(got_shared || got_hub)) {
1095 cycle++;
1096 u = userlist;
1097 }
1098 }
1099 }
1100 if (got_shared && !cycle)
1101 autc = NULL;
1102 else if ((got_shared || got_hub) && (cycle == 1))
1103 autc = NULL;
1104 else if ((got_shared || got_hub || got_alt) && (cycle == 2))
1105 autc = NULL;
1106 if (autc)
1107 botlink("", -3, autc->handle); /* try autoconnect */
1108 }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23