/[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.6 - (show annotations) (download) (as text)
Tue Nov 30 23:04:14 1999 UTC (20 years, 2 months ago) by fabian
Branch: MAIN
Changes since 1.5: +1 -1 lines
File MIME type: text/x-chdr
egg1.4 resync 991130

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23