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

Contents of /eggdrop1.9/src/userrec.c

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


Revision 1.47 - (show annotations) (download) (as text)
Sun May 5 15:19:12 2002 UTC (17 years, 8 months ago) by wingman
Branch: MAIN
Changes since 1.46: +13 -1 lines
File MIME type: text/x-chdr
Changes:

 * removed patch.h
 * added proper <filename>.h to (nearly) all <filename.h>
 * moved fixcolon to server.mod and irc.mod
 * moved ip2long to net.h
 * removed some unused function (forgot the name :-P)

Todo:

 * move config.h #include's away from main.h to files which
   needs them
 * clean up lib/eggdrop/module.h
   (now not just main.h is included but nearly all .h files from
    the core, but i guess this fixes itself when the global func
    table is abandon - then the modules must be revised too and
    we can clean up module.h)

And i'll bet i forgot something... ;-)

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.46 2002/04/25 23:18:03 stdarg Exp $
8 */
9 /*
10 * Copyright (C) 1997 Robey Pointer
11 * Copyright (C) 1999, 2000, 2001, 2002 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 #include "logfile.h"
35 #include "modules.h" /* encrypt_pass */
36 #include "cmdt.h" /* cmd_t */
37 #include "chanprog.h" /* clear_chanlist, set_chanlist */
38 #include "dccutil.h" /* shareout, chanout_but */
39 #include "irccmp.h" /* irccmp */
40 #include "tclhash.h" /* check_tcl_nkch */
41 #include "match.h" /* wild_match */
42 #include "userrec.h" /* prototypes */
43
44 extern struct dcc_t *dcc;
45 extern struct chanset_t *chanset;
46 extern int default_flags, default_uflags, quiet_save,
47 dcc_total, share_greet;
48 extern char userfile[], ver[], botnetnick[];
49 extern time_t now;
50
51 #ifndef MAKING_MODS
52 extern struct dcc_table DCC_CHAT, DCC_BOT;
53 #endif /* MAKING_MODS */
54
55 int noshare = 1; /* don't send out to sharebots */
56 int sort_users = 0; /* sort the userlist when saving */
57 struct userrec *userlist = NULL; /* user records are stored here */
58 struct userrec *lastuser = NULL; /* last accessed user record */
59 maskrec *global_bans = NULL,
60 *global_exempts = NULL,
61 *global_invites = NULL;
62 struct igrec *global_ign = NULL;
63 int cache_hit = 0,
64 cache_miss = 0; /* temporary cache accounting */
65 int strict_host = 0;
66 int userfile_perm = 0600; /* Userfile permissions,
67 default rw------- */
68
69 int count_users(struct userrec *bu)
70 {
71 int tot = 0;
72 struct userrec *u ;
73
74 for (u = bu; u; u = u->next)
75 tot++;
76 return tot;
77 }
78
79 /* Convert "nick!~user@host", "nick!+user@host" and "nick!-user@host"
80 * to "nick!user@host" if necessary. (drummer)
81 */
82 char *fixfrom(char *s)
83 {
84 char *p;
85 static char buf[512];
86
87 if (s == NULL)
88 return NULL;
89 strlcpy(buf, s, sizeof buf);
90 if (strict_host)
91 return buf;
92 if ((p = strchr(buf, '!')))
93 p++;
94 else
95 p = s; /* Sometimes we get passed just a
96 * user@host here... */
97 /* These are ludicrous. */
98 if (strchr("~+-^=", *p) && (p[1] != '@')) /* added check for @ - drummer */
99 strcpy(p, p + 1);
100 /* Bug was: n!~@host -> n!@host now: n!~@host */
101 return buf;
102 }
103
104 struct userrec *check_dcclist_hand(char *handle)
105 {
106 int i;
107
108 for (i = 0; i < dcc_total; i++)
109 if (dcc[i].type && !strcasecmp(dcc[i].nick, handle))
110 return dcc[i].user;
111 return NULL;
112 }
113
114 struct userrec *get_user_by_handle(struct userrec *bu, char *handle)
115 {
116 struct userrec *u, *ret;
117
118 if (!handle)
119 return NULL;
120 /* FIXME: This should be done outside of this function. */
121 /* handle might and should be const */
122 rmspace(handle);
123 if (!handle[0] || (handle[0] == '*'))
124 return NULL;
125 if (bu == userlist) {
126 if (lastuser && !strcasecmp(lastuser->handle, handle)) {
127 cache_hit++;
128 return lastuser;
129 }
130 ret = check_dcclist_hand(handle);
131 if (ret) {
132 cache_hit++;
133 return ret;
134 }
135 ret = check_chanlist_hand(handle);
136 if (ret) {
137 cache_hit++;
138 return ret;
139 }
140 cache_miss++;
141 }
142 for (u = bu; u; u = u->next)
143 if (!strcasecmp(u->handle, handle)) {
144 if (bu == userlist)
145 lastuser = u;
146 return u;
147 }
148 return NULL;
149 }
150
151 /* Fix capitalization, etc
152 */
153 void correct_handle(char *handle)
154 {
155 struct userrec *u;
156
157 u = get_user_by_handle(userlist, handle);
158 if (u == NULL)
159 return;
160 strcpy(handle, u->handle);
161 }
162
163 /* This will be usefull in a lot of places, much more code re-use so we
164 * endup with a smaller executable bot. <cybah>
165 */
166 void clear_masks(maskrec *m)
167 {
168 maskrec *temp = NULL;
169
170 for (; m; m = temp) {
171 temp = m->next;
172 if (m->mask)
173 free(m->mask);
174 if (m->user)
175 free(m->user);
176 if (m->desc)
177 free(m->desc);
178 free(m);
179 }
180 }
181
182 void clear_userlist(struct userrec *bu)
183 {
184 struct userrec *u, *v;
185 int i;
186
187 for (u = bu; u; u = v) {
188 v = u->next;
189 freeuser(u);
190 }
191 if (userlist == bu) {
192 struct chanset_t *cst;
193
194 for (i = 0; i < dcc_total; i++)
195 dcc[i].user = NULL;
196 clear_chanlist();
197 lastuser = NULL;
198
199 while (global_ign)
200 delignore(global_ign->igmask);
201
202 clear_masks(global_bans);
203 clear_masks(global_exempts);
204 clear_masks(global_invites);
205 global_exempts = global_invites = global_bans = NULL;
206
207 for (cst = chanset; cst; cst = cst->next) {
208 clear_masks(cst->bans);
209 clear_masks(cst->exempts);
210 clear_masks(cst->invites);
211
212 cst->bans = cst->exempts = cst->invites = NULL;
213 }
214 }
215 /* Remember to set your userlist to NULL after calling this */
216 }
217
218 /* Find CLOSEST host match
219 * (if "*!*@*" and "*!*@*clemson.edu" both match, use the latter!)
220 *
221 * Checks the chanlist first, to possibly avoid needless search.
222 */
223 struct userrec *get_user_by_host(char *host)
224 {
225 struct userrec *u, *ret;
226 struct list_type *q;
227 int cnt, i;
228 char host2[UHOSTLEN];
229
230 if (host == NULL)
231 return NULL;
232 rmspace(host);
233 if (!host[0])
234 return NULL;
235 ret = check_chanlist(host);
236 cnt = 0;
237 if (ret != NULL) {
238 cache_hit++;
239 return ret;
240 }
241 cache_miss++;
242 strlcpy(host2, host, sizeof host2);
243 host = fixfrom(host);
244 for (u = userlist; u; u = u->next) {
245 q = get_user(&USERENTRY_HOSTS, u);
246 for (; q; q = q->next) {
247 i = wild_match(q->extra, host);
248 if (i > cnt) {
249 ret = u;
250 cnt = i;
251 }
252 }
253 }
254 if (ret != NULL) {
255 lastuser = ret;
256 set_chanlist(host2, ret);
257 }
258 return ret;
259 }
260
261 /* use fixfrom() or dont? (drummer)
262 */
263 struct userrec *get_user_by_equal_host(char *host)
264 {
265 struct userrec *u;
266 struct list_type *q;
267
268 for (u = userlist; u; u = u->next)
269 for (q = get_user(&USERENTRY_HOSTS, u); q; q = q->next)
270 if (!irccmp(q->extra, host))
271 return u;
272 return NULL;
273 }
274
275 /* Try: pass_match_by_host("-",host)
276 * will return 1 if no password is set for that host
277 */
278 int u_pass_match(struct userrec *u, char *pass)
279 {
280 char *cmp, new[32];
281
282 if (!u)
283 return 0;
284 cmp = get_user(&USERENTRY_PASS, u);
285 if (!cmp && (!pass[0] || (pass[0] == '-')))
286 return 1;
287 if (!cmp || !pass || !pass[0] || (pass[0] == '-'))
288 return 0;
289 if (u->flags & USER_BOT) {
290 if (!strcmp(cmp, pass))
291 return 1;
292 } else {
293 if (strlen(pass) > 15)
294 pass[15] = 0;
295 encrypt_pass(pass, new);
296 if (!strcmp(cmp, new))
297 return 1;
298 }
299 return 0;
300 }
301
302 int write_user(struct userrec *u, FILE * f, int idx)
303 {
304 char s[181];
305 struct chanuserrec *ch;
306 struct chanset_t *cst;
307 struct user_entry *ue;
308 struct flag_record fr = {FR_GLOBAL, 0, 0, 0, 0, 0};
309
310 fr.global = u->flags;
311 fr.udef_global = u->flags_udef;
312 build_flags(s, &fr, NULL);
313 if (fprintf(f, "%-10s - %-24s\n", u->handle, s) == EOF)
314 return 0;
315 for (ch = u->chanrec; ch; ch = ch->next) {
316 cst = findchan_by_dname(ch->channel);
317 if (cst && ((idx < 0) || channel_shared(cst))) {
318 if (idx >= 0) {
319 fr.match = (FR_CHAN | FR_BOT);
320 get_user_flagrec(dcc[idx].user, &fr, ch->channel);
321 } else
322 fr.chan = BOT_SHARE;
323 if ((fr.chan & BOT_SHARE) || (fr.bot & BOT_GLOBAL)) {
324 fr.match = FR_CHAN;
325 fr.chan = ch->flags;
326 fr.udef_chan = ch->flags_udef;
327 build_flags(s, &fr, NULL);
328 if (fprintf(f, "! %-20s %lu %-10s %s\n", ch->channel, ch->laston, s,
329 (((idx < 0) || share_greet) && ch->info) ? ch->info
330 : "") == EOF)
331 return 0;
332 }
333 }
334 }
335 for (ue = u->entries; ue; ue = ue->next) {
336 if (ue->name) {
337 struct list_type *lt;
338
339 for (lt = ue->u.list; lt; lt = lt->next)
340 if (fprintf(f, "--%s %s\n", ue->name, lt->extra) == EOF)
341 return 0;
342 } else {
343 if (!ue->type->write_userfile(f, u, ue))
344 return 0;
345 }
346 }
347 return 1;
348 }
349
350 int sort_compare(struct userrec *a, struct userrec *b)
351 {
352 /* Order by flags, then alphabetically
353 * first bots: +h / +a / +l / other bots
354 * then users: +n / +m / +o / other users
355 * return true if (a > b)
356 */
357 if (a->flags & b->flags & USER_BOT) {
358 if (~bot_flags(a) & bot_flags(b) & BOT_HUB)
359 return 1;
360 if (bot_flags(a) & ~bot_flags(b) & BOT_HUB)
361 return 0;
362 if (~bot_flags(a) & bot_flags(b) & BOT_ALT)
363 return 1;
364 if (bot_flags(a) & ~bot_flags(b) & BOT_ALT)
365 return 0;
366 if (~bot_flags(a) & bot_flags(b) & BOT_LEAF)
367 return 1;
368 if (bot_flags(a) & ~bot_flags(b) & BOT_LEAF)
369 return 0;
370 } else {
371 if (~a->flags & b->flags & USER_BOT)
372 return 1;
373 if (a->flags & ~b->flags & USER_BOT)
374 return 0;
375 if (~a->flags & b->flags & USER_OWNER)
376 return 1;
377 if (a->flags & ~b->flags & USER_OWNER)
378 return 0;
379 if (~a->flags & b->flags & USER_MASTER)
380 return 1;
381 if (a->flags & ~b->flags & USER_MASTER)
382 return 0;
383 if (~a->flags & b->flags & USER_OP)
384 return 1;
385 if (a->flags & ~b->flags & USER_OP)
386 return 0;
387 }
388 return (strcasecmp(a->handle, b->handle) > 0);
389 }
390
391 void sort_userlist()
392 {
393 int again;
394 struct userrec *last, *p, *c, *n;
395
396 again = 1;
397 last = NULL;
398 while ((userlist != last) && (again)) {
399 p = NULL;
400 c = userlist;
401 n = c->next;
402 again = 0;
403 while (n != last) {
404 if (sort_compare(c, n)) {
405 again = 1;
406 c->next = n->next;
407 n->next = c;
408 if (p == NULL)
409 userlist = n;
410 else
411 p->next = n;
412 }
413 p = c;
414 c = n;
415 n = n->next;
416 }
417 last = c;
418 }
419 }
420
421 /* Rewrite the entire user file. Call USERFILE hook as well, probably
422 * causing the channel file to be rewritten as well.
423 */
424 void write_userfile(int idx)
425 {
426 FILE *f;
427 char *new_userfile;
428 char s1[81];
429 time_t tt;
430 struct userrec *u;
431 int ok;
432
433 if (userlist == NULL)
434 return; /* No point in saving userfile */
435
436 new_userfile = malloc(strlen(userfile) + 5);
437 sprintf(new_userfile, "%s~new", userfile);
438
439 f = fopen(new_userfile, "w");
440 chmod(new_userfile, userfile_perm);
441 if (f == NULL) {
442 putlog(LOG_MISC, "*", _("ERROR writing user file."));
443 free(new_userfile);
444 return;
445 }
446 if (!quiet_save)
447 putlog(LOG_MISC, "*", _("Writing user file..."));
448 if (sort_users)
449 sort_userlist();
450 tt = now;
451 strcpy(s1, ctime(&tt));
452 fprintf(f, "#4v: %s -- %s -- written %s", ver, botnetnick, s1);
453 ok = 1;
454 for (u = userlist; u && ok; u = u->next)
455 ok = write_user(u, f, idx);
456 if (!ok || fflush(f)) {
457 putlog(LOG_MISC, "*", "%s (%s)", _("ERROR writing user file."), strerror(ferror(f)));
458 fclose(f);
459 free(new_userfile);
460 return;
461 }
462 fclose(f);
463 call_hook(HOOK_USERFILE);
464 movefile(new_userfile, userfile);
465 free(new_userfile);
466 }
467
468 int change_handle(struct userrec *u, char *newh)
469 {
470 int i;
471 char s[HANDLEN + 1];
472
473 if (!u)
474 return 0;
475 /* Nothing that will confuse the userfile */
476 if (!newh[1] && strchr(BADHANDCHARS, newh[0]))
477 return 0;
478 check_tcl_nkch(u->handle, newh);
479 /* Yes, even send bot nick changes now: */
480 if (!noshare && !(u->flags & USER_UNSHARED))
481 shareout(NULL, "h %s %s\n", u->handle, newh);
482 strlcpy(s, u->handle, sizeof s);
483 strlcpy(u->handle, newh, sizeof u->handle);
484 for (i = 0; i < dcc_total; i++)
485 if (dcc[i].type && dcc[i].type != &DCC_BOT && !strcasecmp(dcc[i].nick, s)) {
486 strlcpy(dcc[i].nick, newh, sizeof dcc[i].nick);
487 if (dcc[i].type == &DCC_CHAT && dcc[i].u.chat->channel >= 0) {
488 chanout_but(-1, dcc[i].u.chat->channel,
489 "*** Handle change: %s -> %s\n", s, newh);
490 if (dcc[i].u.chat->channel < 100000)
491 botnet_send_nkch(i, s);
492 }
493 }
494 return 1;
495 }
496
497 extern int noxtra;
498
499 struct userrec *adduser(struct userrec *bu, char *handle, char *host,
500 char *pass, int flags)
501 {
502 struct userrec *u, *x;
503 struct xtra_key *xk;
504 int oldshare = noshare;
505
506 noshare = 1;
507 u = (struct userrec *) malloc(sizeof(struct userrec));
508
509 /* u->next=bu; bu=u; */
510 strlcpy(u->handle, handle, sizeof u->handle);
511 u->next = NULL;
512 u->chanrec = NULL;
513 u->entries = NULL;
514 if (flags != USER_DEFAULT) { /* drummer */
515 u->flags = flags;
516 u->flags_udef = 0;
517 } else {
518 u->flags = default_flags;
519 u->flags_udef = default_uflags;
520 }
521 set_user(&USERENTRY_PASS, u, pass);
522 if (!noxtra) {
523 char *now2;
524 xk = malloc(sizeof(struct xtra_key));
525 xk->key = strdup("created");
526 now2 = malloc(15);
527 sprintf(now2, "%lu", now);
528 xk->data = malloc(strlen(now2) +1);
529 sprintf(xk->data, "%lu", now);
530 set_user(&USERENTRY_XTRA, u, xk);
531 free(now2);
532 }
533 /* Strip out commas -- they're illegal */
534 if (host && host[0]) {
535 char *p;
536
537 /* About this fixfrom():
538 * We should use this fixfrom before every call of adduser()
539 * but its much easier to use here... (drummer)
540 * Only use it if we have a host :) (dw)
541 */
542 host = fixfrom(host);
543 p = strchr(host, ',');
544
545 while (p != NULL) {
546 *p = '?';
547 p = strchr(host, ',');
548 }
549 set_user(&USERENTRY_HOSTS, u, host);
550 } else
551 set_user(&USERENTRY_HOSTS, u, "none");
552 if (bu == userlist)
553 clear_chanlist();
554 noshare = oldshare;
555 if ((!noshare) && (handle[0] != '*') && (!(flags & USER_UNSHARED)) &&
556 (bu == userlist)) {
557 struct flag_record fr = {FR_GLOBAL, 0, 0, 0, 0, 0};
558 char x[100];
559
560 fr.global = u->flags;
561 fr.udef_global = u->flags_udef;
562 build_flags(x, &fr, 0);
563 shareout(NULL, "n %s %s %s %s\n", handle, host && host[0] ? host : "none",
564 pass, x);
565 }
566 if (bu == NULL)
567 bu = u;
568 else {
569 if ((bu == userlist) && (lastuser != NULL))
570 x = lastuser;
571 else
572 x = bu;
573 while (x->next != NULL)
574 x = x->next;
575 x->next = u;
576 if (bu == userlist)
577 lastuser = u;
578 }
579 return bu;
580 }
581
582 void freeuser(struct userrec *u)
583 {
584 struct user_entry *ue, *ut;
585 struct chanuserrec *ch, *z;
586
587 if (u == NULL)
588 return;
589 ch = u->chanrec;
590 while (ch) {
591 z = ch;
592 ch = ch->next;
593 if (z->info != NULL)
594 free(z->info);
595 free(z);
596 }
597 u->chanrec = NULL;
598 for (ue = u->entries; ue; ue = ut) {
599 ut = ue->next;
600 if (ue->name) {
601 struct list_type *lt, *ltt;
602
603 for (lt = ue->u.list; lt; lt = ltt) {
604 ltt = lt->next;
605 free(lt->extra);
606 free(lt);
607 }
608 free(ue->name);
609 free(ue);
610 } else {
611 ue->type->kill(ue);
612 }
613 }
614 free(u);
615 }
616
617 int deluser(char *handle)
618 {
619 struct userrec *u = userlist, *prev = NULL;
620 int fnd = 0;
621
622 while ((u != NULL) && (!fnd)) {
623 if (!strcasecmp(u->handle, handle))
624 fnd = 1;
625 else {
626 prev = u;
627 u = u->next;
628 }
629 }
630 if (!fnd)
631 return 0;
632 if (prev == NULL)
633 userlist = u->next;
634 else
635 prev->next = u->next;
636 if (!noshare && (handle[0] != '*') && !(u->flags & USER_UNSHARED))
637 shareout(NULL, "k %s\n", handle);
638 for (fnd = 0; fnd < dcc_total; fnd++)
639 if (dcc[fnd].type && dcc[fnd].user == u)
640 dcc[fnd].user = 0; /* Clear any dcc users for this entry,
641 * null is safe-ish */
642 clear_chanlist();
643 freeuser(u);
644 lastuser = NULL;
645 return 1;
646 }
647
648 int delhost_by_handle(char *handle, char *host)
649 {
650 struct userrec *u;
651 struct list_type *q, *qnext, *qprev;
652 struct user_entry *e = NULL;
653 int i = 0;
654
655 u = get_user_by_handle(userlist, handle);
656 if (!u)
657 return 0;
658 q = get_user(&USERENTRY_HOSTS, u);
659 qprev = q;
660 if (q) {
661 if (!irccmp(q->extra, host)) {
662 e = find_user_entry(&USERENTRY_HOSTS, u);
663 e->u.extra = q->next;
664 free(q->extra);
665 free(q);
666 i++;
667 qprev = NULL;
668 q = e->u.extra;
669 } else
670 q = q->next;
671 while (q) {
672 qnext = q->next;
673 if (!irccmp(q->extra, host)) {
674 if (qprev)
675 qprev->next = q->next;
676 else if (e) {
677 e->u.extra = q->next;
678 qprev = NULL;
679 }
680 free(q->extra);
681 free(q);
682 i++;
683 } else
684 qprev = q;
685 q = qnext;
686 }
687 }
688 if (!qprev)
689 set_user(&USERENTRY_HOSTS, u, "none");
690 if (!noshare && i && !(u->flags & USER_UNSHARED))
691 shareout(NULL, "-h %s %s\n", handle, host);
692 clear_chanlist();
693 return i;
694 }
695
696 void addhost_by_handle(char *handle, char *host)
697 {
698 struct userrec *u = get_user_by_handle(userlist, handle);
699
700 set_user(&USERENTRY_HOSTS, u, host);
701 /* u will be cached, so really no overhead, even tho this looks dumb: */
702 if ((!noshare) && !(u->flags & USER_UNSHARED)) {
703 if (u->flags & USER_BOT)
704 shareout(NULL, "+bh %s %s\n", handle, host);
705 else
706 shareout(NULL, "+h %s %s\n", handle, host);
707 }
708 clear_chanlist();
709 }
710
711 void touch_laston(struct userrec *u, char *where, time_t timeval)
712 {
713 if (!u)
714 return;
715 if (timeval > 1) {
716 struct laston_info *li =
717 (struct laston_info *) get_user(&USERENTRY_LASTON, u);
718
719 if (!li)
720 li = malloc(sizeof(struct laston_info));
721
722 else if (li->lastonplace)
723 free(li->lastonplace);
724 li->laston = timeval;
725 if (where)
726 li->lastonplace = strdup(where);
727 else
728 li->lastonplace = NULL;
729 set_user(&USERENTRY_LASTON, u, li);
730 } else if (timeval == 1) {
731 set_user(&USERENTRY_LASTON, u, 0);
732 }
733 }
734
735 /* Go through all channel records and try to find a matching
736 * nick. Will return the user's user record if that is known
737 * to the bot. (Fabian)
738 *
739 * Warning: This is unreliable by concept!
740 */
741 struct userrec *get_user_by_nick(char *nick)
742 {
743 struct chanset_t *chan;
744 memberlist *m;
745
746 for (chan = chanset; chan; chan = chan->next) {
747 for (m = chan->channel.member; m && m->nick[0] ;m = m->next) {
748 if (!irccmp(nick, m->nick)) {
749 char word[512];
750
751 snprintf(word, sizeof word, "%s!%s", m->nick, m->userhost);
752 /* No need to check the return value ourself */
753 return get_user_by_host(word);;
754 }
755 }
756 }
757 /* Sorry, no matches */
758 return NULL;
759 }
760
761 void user_del_chan(char *dname)
762 {
763 struct chanuserrec *ch, *och;
764 struct userrec *u;
765
766 for (u = userlist; u; u = u->next) {
767 ch = u->chanrec;
768 och = NULL;
769 while (ch) {
770 if (!irccmp(dname, ch->channel)) {
771 if (och)
772 och->next = ch->next;
773 else
774 u->chanrec = ch->next;
775
776 if (ch->info)
777 free(ch->info);
778 free(ch);
779 break;
780 }
781 och = ch;
782 ch = ch->next;
783 }
784 }
785 }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23