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

Annotation of /eggdrop1.8/src/userrec.c

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


Revision 1.1 - (hide annotations) (download) (as text)
Mon Jul 26 21:11:06 2010 UTC (8 years, 11 months ago) by simple
Branch: MAIN
Branch point for: eggheads
File MIME type: text/x-chdr
Initial revision

1 simple 1.1 /*
2     * userrec.c -- handles:
3     * add_q() del_q() str2flags() flags2str() str2chflags() chflags2str()
4     * a bunch of functions to find and change user records
5     * change and check user (and channel-specific) flags
6     *
7     * $Id: userrec.c,v 1.64 2010/07/05 12:07:05 pseudo Exp $
8     */
9     /*
10     * Copyright (C) 1997 Robey Pointer
11     * Copyright (C) 1999 - 2010 Eggheads Development Team
12     *
13     * This program is free software; you can redistribute it and/or
14     * modify it under the terms of the GNU General Public License
15     * as published by the Free Software Foundation; either version 2
16     * of the License, or (at your option) any later version.
17     *
18     * This program is distributed in the hope that it will be useful,
19     * but WITHOUT ANY WARRANTY; without even the implied warranty of
20     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21     * GNU General Public License for more details.
22     *
23     * You should have received a copy of the GNU General Public License
24     * along with this program; if not, write to the Free Software
25     * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26     */
27    
28     #include <sys/stat.h>
29     #include "main.h"
30     #include "users.h"
31     #include "chan.h"
32     #include "modules.h"
33     #include "tandem.h"
34    
35     extern struct dcc_t *dcc;
36     extern struct chanset_t *chanset;
37     extern int default_flags, default_uflags, quiet_save, dcc_total, share_greet;
38     extern char userfile[], ver[], botnetnick[];
39     extern time_t now;
40    
41     int noshare = 1; /* don't send out to sharebots */
42     int sort_users = 0; /* sort the userlist when saving */
43     struct userrec *userlist = NULL; /* user records are stored here */
44     struct userrec *lastuser = NULL; /* last accessed user record */
45     maskrec *global_bans = NULL, *global_exempts = NULL, *global_invites = NULL;
46     struct igrec *global_ign = NULL;
47     int cache_hit = 0, cache_miss = 0; /* temporary cache accounting */
48     int strict_host = 1;
49     int userfile_perm = 0600; /* Userfile permissions
50     * (default rw-------) */
51    
52     void *_user_malloc(int size, const char *file, int line)
53     {
54     #ifdef DEBUG_MEM
55     char x[1024];
56     const char *p;
57    
58     p = strrchr(file, '/');
59     simple_sprintf(x, "userrec.c:%s", p ? p + 1 : file);
60     return n_malloc(size, x, line);
61     #else
62     return nmalloc(size);
63     #endif
64     }
65    
66     void *_user_realloc(void *ptr, int size, const char *file, int line)
67     {
68     #ifdef DEBUG_MEM
69     char x[1024];
70     const char *p;
71    
72     p = strrchr(file, '/');
73     simple_sprintf(x, "userrec.c:%s", p ? p + 1 : file);
74     return n_realloc(ptr, size, x, line);
75     #else
76     return nrealloc(ptr, size);
77     #endif
78     }
79    
80     inline int expmem_mask(struct maskrec *m)
81     {
82     int result = 0;
83    
84     for (; m; m = m->next) {
85     result += sizeof(struct maskrec);
86     result += strlen(m->mask) + 1;
87     if (m->user)
88     result += strlen(m->user) + 1;
89     if (m->desc)
90     result += strlen(m->desc) + 1;
91     }
92    
93     return result;
94     }
95    
96     /* Memory we should be using
97     */
98     int expmem_users()
99     {
100     int tot;
101     struct userrec *u;
102     struct chanuserrec *ch;
103     struct chanset_t *chan;
104     struct user_entry *ue;
105     struct igrec *i;
106    
107     tot = 0;
108     for (u = userlist; u; u = u->next) {
109     for (ch = u->chanrec; ch; ch = ch->next) {
110     tot += sizeof(struct chanuserrec);
111    
112     if (ch->info != NULL)
113     tot += strlen(ch->info) + 1;
114     }
115     tot += sizeof(struct userrec);
116    
117     for (ue = u->entries; ue; ue = ue->next) {
118     tot += sizeof(struct user_entry);
119    
120     if (ue->name) {
121     tot += strlen(ue->name) + 1;
122     tot += list_type_expmem(ue->u.list);
123     } else
124     tot += ue->type->expmem(ue);
125     }
126     }
127     /* Account for each channel's masks */
128     for (chan = chanset; chan; chan = chan->next) {
129    
130     /* Account for each channel's ban-list user */
131     tot += expmem_mask(chan->bans);
132    
133     /* Account for each channel's exempt-list user */
134     tot += expmem_mask(chan->exempts);
135    
136     /* Account for each channel's invite-list user */
137     tot += expmem_mask(chan->invites);
138     }
139    
140     tot += expmem_mask(global_bans);
141     tot += expmem_mask(global_exempts);
142     tot += expmem_mask(global_invites);
143    
144     for (i = global_ign; i; i = i->next) {
145     tot += sizeof(struct igrec);
146    
147     tot += strlen(i->igmask) + 1;
148     if (i->user)
149     tot += strlen(i->user) + 1;
150     if (i->msg)
151     tot += strlen(i->msg) + 1;
152     }
153     return tot;
154     }
155    
156     int count_users(struct userrec *bu)
157     {
158     int tot = 0;
159     struct userrec *u;
160    
161     for (u = bu; u; u = u->next)
162     tot++;
163     return tot;
164     }
165    
166     /* Removes a username prefix (~+-^=) from a userhost.
167     * e.g, "nick!~user@host" -> "nick!user@host"
168     */
169     char *fixfrom(char *s)
170     {
171     static char uhost[UHOSTLEN];
172     char *p = uhost;
173    
174     if (!s || !*s || strict_host)
175     return s;
176    
177     while (*s) {
178     *p++ = *s;
179     if (*s == '!' && strchr("~+-^=", s[1]) && s[2] != '@') {
180     strcpy(p, s + 2);
181     return uhost;
182     }
183     s++;
184     }
185    
186     *p = 0;
187     return uhost;
188     }
189    
190     struct userrec *check_dcclist_hand(char *handle)
191     {
192     int i;
193    
194     for (i = 0; i < dcc_total; i++)
195     if (!egg_strcasecmp(dcc[i].nick, handle))
196     return dcc[i].user;
197     return NULL;
198     }
199    
200     struct userrec *get_user_by_handle(struct userrec *bu, char *handle)
201     {
202     struct userrec *u, *ret;
203    
204     if (!handle)
205     return NULL;
206     /* FIXME: This should be done outside of this function. */
207     rmspace(handle);
208     if (!handle[0] || (handle[0] == '*'))
209     return NULL;
210     if (bu == userlist) {
211     if (lastuser && !egg_strcasecmp(lastuser->handle, handle)) {
212     cache_hit++;
213     return lastuser;
214     }
215     ret = check_dcclist_hand(handle);
216     if (ret) {
217     cache_hit++;
218     return ret;
219     }
220     ret = check_chanlist_hand(handle);
221     if (ret) {
222     cache_hit++;
223     return ret;
224     }
225     cache_miss++;
226     }
227     for (u = bu; u; u = u->next)
228     if (!egg_strcasecmp(u->handle, handle)) {
229     if (bu == userlist)
230     lastuser = u;
231     return u;
232     }
233     return NULL;
234     }
235    
236     /* Fix capitalization, etc
237     */
238     void correct_handle(char *handle)
239     {
240     struct userrec *u;
241    
242     u = get_user_by_handle(userlist, handle);
243     if (u == NULL || handle == u->handle)
244     return;
245     strcpy(handle, u->handle);
246     }
247    
248     /* This will be usefull in a lot of places, much more code re-use so we
249     * endup with a smaller executable bot. <cybah>
250     */
251     void clear_masks(maskrec *m)
252     {
253     maskrec *temp = NULL;
254    
255     for (; m; m = temp) {
256     temp = m->next;
257     if (m->mask)
258     nfree(m->mask);
259     if (m->user)
260     nfree(m->user);
261     if (m->desc)
262     nfree(m->desc);
263     nfree(m);
264     }
265     }
266    
267     void clear_userlist(struct userrec *bu)
268     {
269     struct userrec *u, *v;
270     int i;
271    
272     for (u = bu; u; u = v) {
273     v = u->next;
274     freeuser(u);
275     }
276     if (userlist == bu) {
277     struct chanset_t *cst;
278    
279     for (i = 0; i < dcc_total; i++)
280     dcc[i].user = NULL;
281     clear_chanlist();
282     lastuser = NULL;
283    
284     while (global_ign)
285     delignore(global_ign->igmask);
286    
287     clear_masks(global_bans);
288     clear_masks(global_exempts);
289     clear_masks(global_invites);
290     global_exempts = global_invites = global_bans = NULL;
291    
292     for (cst = chanset; cst; cst = cst->next) {
293     clear_masks(cst->bans);
294     clear_masks(cst->exempts);
295     clear_masks(cst->invites);
296    
297     cst->bans = cst->exempts = cst->invites = NULL;
298     }
299     }
300     /* Remember to set your userlist to NULL after calling this */
301     }
302    
303     /* Find CLOSEST host match
304     * (if "*!*@*" and "*!*@*clemson.edu" both match, use the latter!)
305     *
306     * Checks the chanlist first, to possibly avoid needless search.
307     */
308     struct userrec *get_user_by_host(char *host)
309     {
310     struct userrec *u, *ret;
311     struct list_type *q;
312     int cnt, i;
313     char host2[UHOSTLEN];
314    
315     if (host == NULL)
316     return NULL;
317     rmspace(host);
318     if (!host[0])
319     return NULL;
320     ret = check_chanlist(host);
321     cnt = 0;
322     if (ret != NULL) {
323     cache_hit++;
324     return ret;
325     }
326     cache_miss++;
327     strncpyz(host2, host, sizeof host2);
328     host = fixfrom(host);
329     for (u = userlist; u; u = u->next) {
330     q = get_user(&USERENTRY_HOSTS, u);
331     for (; q; q = q->next) {
332     i = match_useraddr(q->extra, host);
333     if (i > cnt) {
334     ret = u;
335     cnt = i;
336     }
337     }
338     }
339     if (ret != NULL) {
340     lastuser = ret;
341     set_chanlist(host2, ret);
342     }
343     return ret;
344     }
345    
346     /* use fixfrom() or dont? (drummer)
347     */
348     struct userrec *get_user_by_equal_host(char *host)
349     {
350     struct userrec *u;
351     struct list_type *q;
352    
353     for (u = userlist; u; u = u->next)
354     for (q = get_user(&USERENTRY_HOSTS, u); q; q = q->next)
355     if (!rfc_casecmp(q->extra, host))
356     return u;
357     return NULL;
358     }
359    
360     /* Try: pass_match_by_host("-",host)
361     * will return 1 if no password is set for that host
362     */
363     int u_pass_match(struct userrec *u, char *pass)
364     {
365     char *cmp, new[32];
366    
367     if (!u)
368     return 0;
369     cmp = get_user(&USERENTRY_PASS, u);
370     if (!cmp && (!pass[0] || (pass[0] == '-')))
371     return 1;
372     if (!cmp || !pass || !pass[0] || (pass[0] == '-'))
373     return 0;
374     if (u->flags & USER_BOT) {
375     if (!strcmp(cmp, pass))
376     return 1;
377     } else {
378     if (strlen(pass) > 30)
379     pass[30] = 0;
380     encrypt_pass(pass, new);
381     if (!strcmp(cmp, new))
382     return 1;
383     }
384     return 0;
385     }
386    
387     int write_user(struct userrec *u, FILE *f, int idx)
388     {
389     char s[181];
390     long tv;
391     struct chanuserrec *ch;
392     struct chanset_t *cst;
393     struct user_entry *ue;
394     struct flag_record fr = { FR_GLOBAL, 0, 0, 0, 0, 0 };
395    
396     fr.global = u->flags;
397    
398     fr.udef_global = u->flags_udef;
399     build_flags(s, &fr, NULL);
400     if (fprintf(f, "%-10s - %-24s\n", u->handle, s) == EOF)
401     return 0;
402     for (ch = u->chanrec; ch; ch = ch->next) {
403     cst = findchan_by_dname(ch->channel);
404     if (cst && ((idx < 0) || channel_shared(cst))) {
405     if (idx >= 0) {
406     fr.match = (FR_CHAN | FR_BOT);
407     get_user_flagrec(dcc[idx].user, &fr, ch->channel);
408     } else
409     fr.chan = BOT_SHARE;
410     if ((fr.chan & BOT_SHARE) || (fr.bot & BOT_GLOBAL)) {
411     fr.match = FR_CHAN;
412     fr.chan = ch->flags;
413     fr.udef_chan = ch->flags_udef;
414     build_flags(s, &fr, NULL);
415     tv = ch->laston;
416     if (fprintf(f, "! %-20s %lu %-10s %s\n", ch->channel, tv, s,
417     (((idx < 0) || share_greet) && ch->info) ? ch->info : "") == EOF)
418     return 0;
419     }
420     }
421     }
422     for (ue = u->entries; ue; ue = ue->next) {
423     if (ue->name) {
424     struct list_type *lt;
425    
426     for (lt = ue->u.list; lt; lt = lt->next)
427     if (fprintf(f, "--%s %s\n", ue->name, lt->extra) == EOF)
428     return 0;
429     } else if (!ue->type->write_userfile(f, u, ue))
430     return 0;
431     }
432     return 1;
433     }
434    
435     int write_ignores(FILE *f, int idx)
436     {
437     struct igrec *i;
438     char *mask;
439     long expire, added;
440    
441     if (global_ign)
442     if (fprintf(f, IGNORE_NAME " - -\n") == EOF) /* Daemus */
443     return 0;
444     for (i = global_ign; i; i = i->next) {
445     mask = str_escape(i->igmask, ':', '\\');
446     expire = i->expire;
447     added = i->added;
448     if (!mask ||
449     fprintf(f, "- %s:%s%lu:%s:%lu:%s\n", mask,
450     (i->flags & IGREC_PERM) ? "+" : "", expire,
451     i->user ? i->user : botnetnick, added,
452     i->msg ? i->msg : "") == EOF) {
453     if (mask)
454     nfree(mask);
455     return 0;
456     }
457     nfree(mask);
458     }
459     return 1;
460     }
461    
462     int sort_compare(struct userrec *a, struct userrec *b)
463     {
464     /* Order by flags, then alphabetically
465     * first bots: +h / +a / +l / other bots
466     * then users: +n / +m / +o / other users
467     * return true if (a > b)
468     */
469     if (a->flags & b->flags & USER_BOT) {
470     if (~bot_flags(a) & bot_flags(b) & BOT_HUB)
471     return 1;
472     if (bot_flags(a) & ~bot_flags(b) & BOT_HUB)
473     return 0;
474     if (~bot_flags(a) & bot_flags(b) & BOT_ALT)
475     return 1;
476     if (bot_flags(a) & ~bot_flags(b) & BOT_ALT)
477     return 0;
478     if (~bot_flags(a) & bot_flags(b) & BOT_LEAF)
479     return 1;
480     if (bot_flags(a) & ~bot_flags(b) & BOT_LEAF)
481     return 0;
482     } else {
483     if (~a->flags & b->flags & USER_BOT)
484     return 1;
485     if (a->flags & ~b->flags & USER_BOT)
486     return 0;
487     if (~a->flags & b->flags & USER_OWNER)
488     return 1;
489     if (a->flags & ~b->flags & USER_OWNER)
490     return 0;
491     if (~a->flags & b->flags & USER_MASTER)
492     return 1;
493     if (a->flags & ~b->flags & USER_MASTER)
494     return 0;
495     if (~a->flags & b->flags & USER_OP)
496     return 1;
497     if (a->flags & ~b->flags & USER_OP)
498     return 0;
499     if (~a->flags & b->flags & USER_HALFOP)
500     return 1;
501     if (a->flags & ~b->flags & USER_HALFOP)
502     return 0;
503     }
504     return (egg_strcasecmp(a->handle, b->handle) > 0);
505     }
506    
507     void sort_userlist()
508     {
509     int again;
510     struct userrec *last, *p, *c, *n;
511    
512     again = 1;
513     last = NULL;
514     while ((userlist != last) && (again)) {
515     p = NULL;
516     c = userlist;
517     n = c->next;
518     again = 0;
519     while (n != last) {
520     if (sort_compare(c, n)) {
521     again = 1;
522     c->next = n->next;
523     n->next = c;
524     if (p == NULL)
525     userlist = n;
526     else
527     p->next = n;
528     }
529     p = c;
530     c = n;
531     n = n->next;
532     }
533     last = c;
534     }
535     }
536    
537     /* Rewrite the entire user file. Call USERFILE hook as well, probably
538     * causing the channel file to be rewritten as well.
539     */
540     void write_userfile(int idx)
541     {
542     FILE *f;
543     char *new_userfile;
544     char s1[81];
545     time_t tt;
546     struct userrec *u;
547     int ok;
548    
549     if (userlist == NULL)
550     return; /* No point in saving userfile */
551    
552     new_userfile = nmalloc(strlen(userfile) + 5);
553     sprintf(new_userfile, "%s~new", userfile);
554    
555     f = fopen(new_userfile, "w");
556     chmod(new_userfile, userfile_perm);
557     if (f == NULL) {
558     putlog(LOG_MISC, "*", USERF_ERRWRITE);
559     nfree(new_userfile);
560     return;
561     }
562     if (!quiet_save)
563     putlog(LOG_MISC, "*", USERF_WRITING);
564     if (sort_users)
565     sort_userlist();
566     tt = now;
567     strcpy(s1, ctime(&tt));
568     fprintf(f, "#4v: %s -- %s -- written %s", ver, botnetnick, s1);
569     ok = 1;
570     for (u = userlist; u && ok; u = u->next)
571     if (!write_user(u, f, idx))
572     ok = 0;
573     if (!ok || !write_ignores(f, -1) || fflush(f)) {
574     putlog(LOG_MISC, "*", "%s (%s)", USERF_ERRWRITE, strerror(ferror(f)));
575     fclose(f);
576     nfree(new_userfile);
577     return;
578     }
579     fclose(f);
580     call_hook(HOOK_USERFILE);
581     movefile(new_userfile, userfile);
582     nfree(new_userfile);
583     }
584    
585     int change_handle(struct userrec *u, char *newh)
586     {
587     int i;
588     char s[HANDLEN + 1];
589    
590     if (!u)
591     return 0;
592     /* Nothing that will confuse the userfile */
593     if (!newh[1] && strchr(BADHANDCHARS, newh[0]))
594     return 0;
595     check_tcl_nkch(u->handle, newh);
596     /* Yes, even send bot nick changes now: */
597     if (!noshare && !(u->flags & USER_UNSHARED))
598     shareout(NULL, "h %s %s\n", u->handle, newh);
599     strncpyz(s, u->handle, sizeof s);
600     strncpyz(u->handle, newh, sizeof u->handle);
601     for (i = 0; i < dcc_total; i++)
602     if ((dcc[i].type == &DCC_CHAT || dcc[i].type == &DCC_CHAT_PASS) &&
603     !egg_strcasecmp(dcc[i].nick, s)) {
604     strncpyz(dcc[i].nick, newh, sizeof dcc[i].nick);
605     if (dcc[i].type == &DCC_CHAT && dcc[i].u.chat->channel >= 0) {
606     chanout_but(-1, dcc[i].u.chat->channel,
607     "*** Handle change: %s -> %s\n", s, newh);
608     if (dcc[i].u.chat->channel < GLOBAL_CHANS)
609     botnet_send_nkch(i, s);
610     }
611     }
612     return 1;
613     }
614    
615     extern int noxtra;
616    
617     struct userrec *adduser(struct userrec *bu, char *handle, char *host,
618     char *pass, int flags)
619     {
620     struct userrec *u, *x;
621     struct xtra_key *xk;
622     int oldshare = noshare;
623     long tv;
624    
625     noshare = 1;
626     u = nmalloc(sizeof *u);
627    
628     /* u->next=bu; bu=u; */
629     strncpyz(u->handle, handle, sizeof u->handle);
630     u->next = NULL;
631     u->chanrec = NULL;
632     u->entries = NULL;
633     if (flags != USER_DEFAULT) { /* drummer */
634     u->flags = flags;
635     u->flags_udef = 0;
636     } else {
637     u->flags = default_flags;
638     u->flags_udef = default_uflags;
639     }
640     set_user(&USERENTRY_PASS, u, pass);
641     if (!noxtra) {
642     char *now2;
643     xk = nmalloc(sizeof *xk);
644     xk->key = nmalloc(8);
645     strcpy(xk->key, "created");
646     now2 = nmalloc(15);
647     tv = now;
648     sprintf(now2, "%li", tv);
649     xk->data = nmalloc(strlen(now2) + 1);
650     sprintf(xk->data, "%li", tv);
651     set_user(&USERENTRY_XTRA, u, xk);
652     nfree(now2);
653     }
654     /* Strip out commas -- they're illegal */
655     if (host && host[0]) {
656     char *p;
657    
658     /* About this fixfrom():
659     * We should use this fixfrom before every call of adduser()
660     * but its much easier to use here... (drummer)
661     * Only use it if we have a host :) (dw)
662     */
663     host = fixfrom(host);
664    
665     p = strchr(host, ',');
666     while (p != NULL) {
667     *p = '?';
668     p = strchr(host, ',');
669     }
670     set_user(&USERENTRY_HOSTS, u, host);
671     } else
672     set_user(&USERENTRY_HOSTS, u, "none");
673     if (bu == userlist)
674     clear_chanlist();
675     noshare = oldshare;
676     if ((!noshare) && (handle[0] != '*') && (!(flags & USER_UNSHARED)) &&
677     (bu == userlist)) {
678     struct flag_record fr = { FR_GLOBAL, 0, 0, 0, 0, 0 };
679     char x[100];
680    
681     fr.global = u->flags;
682    
683     fr.udef_global = u->flags_udef;
684     build_flags(x, &fr, 0);
685     shareout(NULL, "n %s %s %s %s\n", handle, host && host[0] ? host : "none",
686     pass, x);
687     }
688     if (bu == NULL)
689     bu = u;
690     else {
691     if ((bu == userlist) && (lastuser != NULL))
692     x = lastuser;
693     else
694     x = bu;
695     while (x->next != NULL)
696     x = x->next;
697     x->next = u;
698     if (bu == userlist)
699     lastuser = u;
700     }
701     return bu;
702     }
703    
704     void freeuser(struct userrec *u)
705     {
706     struct user_entry *ue, *ut;
707     struct chanuserrec *ch, *z;
708    
709     if (u == NULL)
710     return;
711    
712     ch = u->chanrec;
713     while (ch) {
714     z = ch;
715     ch = ch->next;
716     if (z->info != NULL)
717     nfree(z->info);
718     nfree(z);
719     }
720     u->chanrec = NULL;
721     for (ue = u->entries; ue; ue = ut) {
722     ut = ue->next;
723     if (ue->name) {
724     struct list_type *lt, *ltt;
725    
726     for (lt = ue->u.list; lt; lt = ltt) {
727     ltt = lt->next;
728     nfree(lt->extra);
729     nfree(lt);
730     }
731     nfree(ue->name);
732     nfree(ue);
733     } else
734     ue->type->kill(ue);
735     }
736     nfree(u);
737     }
738    
739     int deluser(char *handle)
740     {
741     struct userrec *u = userlist, *prev = NULL;
742     int fnd = 0;
743    
744     while ((u != NULL) && (!fnd)) {
745     if (!egg_strcasecmp(u->handle, handle))
746     fnd = 1;
747     else {
748     prev = u;
749     u = u->next;
750     }
751     }
752     if (!fnd)
753     return 0;
754     if (prev == NULL)
755     userlist = u->next;
756     else
757     prev->next = u->next;
758     if (!noshare && (handle[0] != '*') && !(u->flags & USER_UNSHARED))
759     shareout(NULL, "k %s\n", handle);
760     for (fnd = 0; fnd < dcc_total; fnd++)
761     if (dcc[fnd].user == u)
762     dcc[fnd].user = 0; /* Clear any dcc users for this entry,
763     * null is safe-ish */
764     clear_chanlist();
765     freeuser(u);
766     lastuser = NULL;
767     return 1;
768     }
769    
770     int delhost_by_handle(char *handle, char *host)
771     {
772     struct userrec *u;
773     struct list_type *q, *qnext, *qprev;
774     struct user_entry *e = NULL;
775     int i = 0;
776    
777     u = get_user_by_handle(userlist, handle);
778     if (!u)
779     return 0;
780     q = get_user(&USERENTRY_HOSTS, u);
781     qprev = q;
782     if (q) {
783     if (!rfc_casecmp(q->extra, host)) {
784     e = find_user_entry(&USERENTRY_HOSTS, u);
785     e->u.extra = q->next;
786     nfree(q->extra);
787     nfree(q);
788     i++;
789     qprev = NULL;
790     q = e->u.extra;
791     } else
792     q = q->next;
793     while (q) {
794     qnext = q->next;
795     if (!rfc_casecmp(q->extra, host)) {
796     if (qprev)
797     qprev->next = q->next;
798     else if (e) {
799     e->u.extra = q->next;
800     qprev = NULL;
801     }
802     nfree(q->extra);
803     nfree(q);
804     i++;
805     } else
806     qprev = q;
807     q = qnext;
808     }
809     }
810     if (!qprev)
811     set_user(&USERENTRY_HOSTS, u, "none");
812     if (!noshare && i && !(u->flags & USER_UNSHARED))
813     shareout(NULL, "-h %s %s\n", handle, host);
814     clear_chanlist();
815     return i;
816     }
817    
818     void addhost_by_handle(char *handle, char *host)
819     {
820     struct userrec *u = get_user_by_handle(userlist, handle);
821    
822     set_user(&USERENTRY_HOSTS, u, host);
823     /* u will be cached, so really no overhead, even tho this looks dumb: */
824     if ((!noshare) && !(u->flags & USER_UNSHARED)) {
825     if (u->flags & USER_BOT)
826     shareout(NULL, "+bh %s %s\n", handle, host);
827     else
828     shareout(NULL, "+h %s %s\n", handle, host);
829     }
830     clear_chanlist();
831     }
832    
833     void touch_laston(struct userrec *u, char *where, time_t timeval)
834     {
835     if (!u)
836     return;
837    
838     if (timeval > 1) {
839     struct laston_info *li = get_user(&USERENTRY_LASTON, u);
840    
841     if (!li)
842     li = nmalloc(sizeof *li);
843    
844     else if (li->lastonplace)
845     nfree(li->lastonplace);
846     li->laston = timeval;
847     if (where) {
848     li->lastonplace = nmalloc(strlen(where) + 1);
849     strcpy(li->lastonplace, where);
850     } else
851     li->lastonplace = NULL;
852     set_user(&USERENTRY_LASTON, u, li);
853     } else if (timeval == 1)
854     set_user(&USERENTRY_LASTON, u, 0);
855     }
856    
857     /* Go through all channel records and try to find a matching
858     * nick. Will return the user's user record if that is known
859     * to the bot. (Fabian)
860     *
861     * Warning: This is unreliable by concept!
862     */
863     struct userrec *get_user_by_nick(char *nick)
864     {
865     struct chanset_t *chan;
866     memberlist *m;
867    
868     for (chan = chanset; chan; chan = chan->next) {
869     for (m = chan->channel.member; m && m->nick[0]; m = m->next) {
870     if (!rfc_casecmp(nick, m->nick)) {
871     char word[512];
872    
873     egg_snprintf(word, sizeof word, "%s!%s", m->nick, m->userhost);
874     /* No need to check the return value ourself */
875     return get_user_by_host(word);;
876     }
877     }
878     }
879     /* Sorry, no matches */
880     return NULL;
881     }
882    
883     void user_del_chan(char *dname)
884     {
885     struct chanuserrec *ch, *och;
886     struct userrec *u;
887    
888     for (u = userlist; u; u = u->next) {
889     ch = u->chanrec;
890     och = NULL;
891     while (ch) {
892     if (!rfc_casecmp(dname, ch->channel)) {
893     if (och)
894     och->next = ch->next;
895     else
896     u->chanrec = ch->next;
897    
898     if (ch->info)
899     nfree(ch->info);
900     nfree(ch);
901     break;
902     }
903     och = ch;
904     ch = ch->next;
905     }
906     }
907     }
908    
909     /* Check if the console flags specified in md are permissible according
910     * to the given flagrec. If the FR_CHAN flag is not set in fr->match,
911     * only global user flags will be considered.
912     * Returns: md with all unallowed flags masked out.
913     */
914     int check_conflags(struct flag_record *fr, int md)
915     {
916     if (!glob_owner(*fr))
917     md &= ~(LOG_RAW | LOG_SRVOUT | LOG_BOTNET | LOG_BOTSHARE);
918     if (!glob_master(*fr)) {
919     md &= ~(LOG_FILES | LOG_LEV1 | LOG_LEV2 | LOG_LEV3 | LOG_LEV4 |
920     LOG_LEV5 | LOG_LEV6 | LOG_LEV7 | LOG_LEV8 | LOG_DEBUG |
921     LOG_WALL);
922     if ((fr->match & FR_CHAN) && !chan_master(*fr))
923     md &= ~(LOG_MISC | LOG_CMDS);
924     }
925     if (!glob_botmast(*fr))
926     md &= ~LOG_BOTS;
927     return md;
928     }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23