/[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.59 - (show annotations) (download) (as text)
Sat Feb 15 05:04:58 2003 UTC (16 years, 11 months ago) by wcc
Branch: MAIN
Changes since 1.58: +4 -44 lines
File MIME type: text/x-chdr
* Removed share.mod (will be part of the new botnet module).
* More transfer removal.
* More botnet removal.
* Regenerated gettext stuff.
* More doc stuff.
* Removed eggdrop.conf (replaced by config.tcl for now).

1 /*
2 * userrec.c --
3 *
4 * add_q() del_q() str2flags() flags2str() str2chflags() chflags2str()
5 * a bunch of functions to find and change user records
6 * change and check user (and channel-specific) flags
7 */
8 /*
9 * Copyright (C) 1997 Robey Pointer
10 * Copyright (C) 1999, 2000, 2001, 2002, 2003 Eggheads Development Team
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 */
26
27 #ifndef lint
28 static const char rcsid[] = "$Id: userrec.c,v 1.58 2003/02/03 11:41:35 wcc Exp $";
29 #endif
30
31 #include <sys/stat.h>
32 #include "main.h"
33 #include "users.h"
34 #include "chan.h"
35 #include "modules.h"
36 #include "logfile.h"
37 #include "modules.h" /* encrypt_pass */
38 #include "cmdt.h" /* cmd_t */
39 #include "chanprog.h" /* clear_chanlist, set_chanlist */
40 #include "dccutil.h" /* chanout_but */
41 #include "irccmp.h" /* irccmp */
42 #include "flags.h"
43 #include "match.h" /* wild_match */
44 #include "userrec.h" /* prototypes */
45
46 extern struct dcc_t *dcc;
47 extern struct chanset_t *chanset;
48 extern int default_flags, default_uflags, dcc_total;
49 extern char userfile[], ver[], myname[];
50 extern time_t now;
51
52 #ifndef MAKING_MODS
53 extern struct dcc_table DCC_CHAT;
54 #endif /* MAKING_MODS */
55
56 struct userrec *userlist = NULL; /* user records are stored here */
57 struct userrec *lastuser = NULL; /* last accessed user record */
58 maskrec *global_bans = NULL, *global_exempts = NULL, *global_invites = NULL;
59 struct igrec *global_ign = NULL;
60 int cache_hit = 0, cache_miss = 0;
61 int strict_host = 0;
62 int userfile_perm = 0600;
63
64 int count_users(struct userrec *bu)
65 {
66 int tot = 0;
67 struct userrec *u ;
68
69 for (u = bu; u; u = u->next)
70 tot++;
71 return tot;
72 }
73
74 /* Convert "nick!~user@host", "nick!+user@host" and "nick!-user@host"
75 * to "nick!user@host" if necessary. (drummer)
76 */
77 char *fixfrom(char *s)
78 {
79 char *p;
80 static char buf[512];
81
82 if (s == NULL)
83 return NULL;
84 strlcpy(buf, s, sizeof buf);
85 if (strict_host)
86 return buf;
87 if ((p = strchr(buf, '!')))
88 p++;
89 else
90 p = s; /* Sometimes we get passed just a
91 * user@host here... */
92 /* These are ludicrous. */
93 if (strchr("~+-^=", *p) && (p[1] != '@')) /* added check for @ - drummer */
94 strcpy(p, p + 1);
95 /* Bug was: n!~@host -> n!@host now: n!~@host */
96 return buf;
97 }
98
99 struct userrec *check_dcclist_hand(const char *handle)
100 {
101 int i;
102
103 for (i = 0; i < dcc_total; i++)
104 if (dcc[i].type && !strcasecmp(dcc[i].nick, handle))
105 return dcc[i].user;
106 return NULL;
107 }
108
109 struct userrec *get_user_by_handle(struct userrec *bu, const char *handle)
110 {
111 struct userrec *u, *ret;
112
113 if (!handle)
114 return NULL;
115 if (!handle[0] || (handle[0] == '*'))
116 return NULL;
117 if (bu == userlist) {
118 if (lastuser && !strcasecmp(lastuser->handle, handle)) {
119 cache_hit++;
120 return lastuser;
121 }
122 ret = check_dcclist_hand(handle);
123 if (ret) {
124 cache_hit++;
125 return ret;
126 }
127 ret = check_chanlist_hand(handle);
128 if (ret) {
129 cache_hit++;
130 return ret;
131 }
132 cache_miss++;
133 }
134 for (u = bu; u; u = u->next)
135 if (!strcasecmp(u->handle, handle)) {
136 if (bu == userlist)
137 lastuser = u;
138 return u;
139 }
140 return NULL;
141 }
142
143 /* Fix capitalization, etc
144 */
145 void correct_handle(char *handle)
146 {
147 struct userrec *u;
148
149 u = get_user_by_handle(userlist, handle);
150 if (u == NULL)
151 return;
152 strcpy(handle, u->handle);
153 }
154
155 /* This will be usefull in a lot of places, much more code re-use so we
156 * endup with a smaller executable bot. <cybah>
157 */
158 void clear_masks(maskrec *m)
159 {
160 maskrec *temp = NULL;
161
162 for (; m; m = temp) {
163 temp = m->next;
164 if (m->mask)
165 free(m->mask);
166 if (m->user)
167 free(m->user);
168 if (m->desc)
169 free(m->desc);
170 free(m);
171 }
172 }
173
174 void clear_userlist(struct userrec *bu)
175 {
176 struct userrec *u, *v;
177 int i;
178
179 for (u = bu; u; u = v) {
180 v = u->next;
181 freeuser(u);
182 }
183 if (userlist == bu) {
184 struct chanset_t *cst;
185
186 for (i = 0; i < dcc_total; i++)
187 dcc[i].user = NULL;
188 clear_chanlist();
189 lastuser = NULL;
190
191 while (global_ign)
192 delignore(global_ign->igmask);
193
194 clear_masks(global_bans);
195 clear_masks(global_exempts);
196 clear_masks(global_invites);
197 global_exempts = global_invites = global_bans = NULL;
198
199 for (cst = chanset; cst; cst = cst->next) {
200 clear_masks(cst->bans);
201 clear_masks(cst->exempts);
202 clear_masks(cst->invites);
203
204 cst->bans = cst->exempts = cst->invites = NULL;
205 }
206 }
207 /* Remember to set your userlist to NULL after calling this */
208 }
209
210 /* Find CLOSEST host match
211 * (if "*!*@*" and "*!*@*clemson.edu" both match, use the latter!)
212 *
213 * Checks the chanlist first, to possibly avoid needless search.
214 */
215 struct userrec *get_user_by_host(char *host)
216 {
217 struct userrec *u, *ret;
218 struct list_type *q;
219 int cnt, i;
220 char host2[UHOSTLEN];
221
222 if (host == NULL)
223 return NULL;
224 rmspace(host);
225 if (!host[0])
226 return NULL;
227 ret = check_chanlist(host);
228 cnt = 0;
229 if (ret != NULL) {
230 cache_hit++;
231 return ret;
232 }
233 cache_miss++;
234 strlcpy(host2, host, sizeof host2);
235 host = fixfrom(host);
236 for (u = userlist; u; u = u->next) {
237 q = get_user(&USERENTRY_HOSTS, u);
238 for (; q; q = q->next) {
239 i = wild_match(q->extra, host);
240 if (i > cnt) {
241 ret = u;
242 cnt = i;
243 }
244 }
245 }
246 if (ret != NULL) {
247 lastuser = ret;
248 set_chanlist(host2, ret);
249 }
250 return ret;
251 }
252
253 /* use fixfrom() or dont? (drummer)
254 */
255 struct userrec *get_user_by_equal_host(char *host)
256 {
257 struct userrec *u;
258 struct list_type *q;
259
260 for (u = userlist; u; u = u->next)
261 for (q = get_user(&USERENTRY_HOSTS, u); q; q = q->next)
262 if (!irccmp(q->extra, host))
263 return u;
264 return NULL;
265 }
266
267 /* Try: pass_match_by_host("-",host)
268 * will return 1 if no password is set for that host
269 */
270 int u_pass_match(struct userrec *u, char *pass)
271 {
272 char *cmp, new[32];
273
274 if (!u)
275 return 0;
276 cmp = get_user(&USERENTRY_PASS, u);
277 if (!cmp && (!pass[0] || (pass[0] == '-')))
278 return 1;
279 if (!cmp || !pass || !pass[0] || (pass[0] == '-'))
280 return 0;
281 if (u->flags & USER_BOT) {
282 if (!strcmp(cmp, pass))
283 return 1;
284 } else {
285 if (strlen(pass) > 15)
286 pass[15] = 0;
287 encrypt_pass(pass, new);
288 if (!strcmp(cmp, new))
289 return 1;
290 }
291 return 0;
292 }
293
294 int write_user(struct userrec *u, FILE * f, int idx)
295 {
296 char s[181];
297 struct chanuserrec *ch;
298 struct chanset_t *cst;
299 struct user_entry *ue;
300 struct flag_record fr = {FR_GLOBAL, 0, 0, 0, 0, 0};
301
302 fr.global = u->flags;
303 fr.udef_global = u->flags_udef;
304 build_flags(s, &fr, NULL);
305 if (fprintf(f, "%-10s - %-24s\n", u->handle, s) == EOF)
306 return 0;
307 for (ch = u->chanrec; ch; ch = ch->next) {
308 cst = findchan_by_dname(ch->channel);
309 if (cst && (idx < 0)) {
310 if (idx >= 0) {
311 fr.match = (FR_CHAN | FR_BOT);
312 get_user_flagrec(dcc[idx].user, &fr, ch->channel);
313 }
314 }
315 }
316 for (ue = u->entries; ue; ue = ue->next) {
317 if (ue->name) {
318 struct list_type *lt;
319
320 for (lt = ue->u.list; lt; lt = lt->next)
321 if (fprintf(f, "--%s %s\n", ue->name, lt->extra) == EOF)
322 return 0;
323 } else {
324 if (!ue->type->write_userfile(f, u, ue))
325 return 0;
326 }
327 }
328 return 1;
329 }
330
331 int write_ignores(FILE *f, int idx)
332 {
333 struct igrec *i;
334 char *mask;
335
336 if ((global_ign) && (fprintf(f, IGNORE_NAME " - -\n") == EOF))
337 return 0;
338
339 for (i = global_ign; i; i = i->next) {
340 mask = str_escape(i->igmask, ':', '\\');
341 if (!mask || fprintf(f, "- %s:%s%lu:%s:%lu:%s\n", mask,
342 (i->flags & IGREC_PERM) ? "+" : "", i->expire, i->user ? i->user :
343 myname, i->added, i->msg ? i->msg : "") == EOF) {
344 if (mask)
345 free(mask);
346 return 0;
347 }
348 free(mask);
349 }
350 return 1;
351 }
352
353 /* Rewrite the entire user file. Call USERFILE hook as well, probably
354 * causing the channel file to be rewritten as well.
355 */
356 void write_userfile(int idx)
357 {
358 FILE *f;
359 char *new_userfile;
360 char s1[81];
361 time_t tt;
362 struct userrec *u;
363 int ok;
364
365 if (userlist == NULL)
366 return; /* No point in saving userfile */
367
368 new_userfile = malloc(strlen(userfile) + 5);
369 sprintf(new_userfile, "%s~new", userfile);
370
371 f = fopen(new_userfile, "w");
372 chmod(new_userfile, userfile_perm);
373 if (f == NULL) {
374 putlog(LOG_MISC, "*", _("ERROR writing user file."));
375 free(new_userfile);
376 return;
377 }
378 tt = now;
379 strcpy(s1, ctime(&tt));
380 fprintf(f, "#4v: %s -- %s -- written %s", ver, myname, s1);
381 ok = 1;
382 for (u = userlist; u && ok; u = u->next)
383 if (!write_user(u, f, idx))
384 ok = 0;
385 if (!ok || !write_ignores(f, -1) || fflush(f)) {
386 putlog(LOG_MISC, "*", "%s (%s)", _("ERROR writing user file."), strerror(ferror(f)));
387 fclose(f);
388 free(new_userfile);
389 return;
390 }
391 fclose(f);
392 call_hook(HOOK_USERFILE);
393 movefile(new_userfile, userfile);
394 free(new_userfile);
395 }
396
397 int change_handle(struct userrec *u, char *newh)
398 {
399 int i;
400 char s[HANDLEN + 1];
401
402 if (!u)
403 return 0;
404 /* Nothing that will confuse the userfile */
405 if (!newh[1] && strchr(BADHANDCHARS, newh[0]))
406 return 0;
407 strlcpy(s, u->handle, sizeof s);
408 strlcpy(u->handle, newh, sizeof u->handle);
409 for (i = 0; i < dcc_total; i++)
410 if (!strcasecmp(dcc[i].nick, s)) {
411 strlcpy(dcc[i].nick, newh, sizeof dcc[i].nick);
412 if (dcc[i].type == &DCC_CHAT && dcc[i].u.chat->channel >= 0) {
413 chanout_but(-1, dcc[i].u.chat->channel,
414 "*** Handle change: %s -> %s\n", s, newh);
415 }
416 }
417 return 1;
418 }
419
420 extern int noxtra;
421
422 struct userrec *adduser(struct userrec *bu, char *handle, char *host,
423 char *pass, int flags)
424 {
425 struct userrec *u, *x;
426 struct xtra_key *xk;
427
428 u = (struct userrec *) malloc(sizeof(struct userrec));
429
430 /* u->next=bu; bu=u; */
431 strlcpy(u->handle, handle, sizeof u->handle);
432 u->next = NULL;
433 u->chanrec = NULL;
434 u->entries = NULL;
435 if (flags != USER_DEFAULT) { /* drummer */
436 u->flags = flags;
437 u->flags_udef = 0;
438 } else {
439 u->flags = default_flags;
440 u->flags_udef = default_uflags;
441 }
442 set_user(&USERENTRY_PASS, u, pass);
443 if (!noxtra) {
444 char *now2;
445 xk = malloc(sizeof(struct xtra_key));
446 xk->key = strdup("created");
447 now2 = malloc(15);
448 sprintf(now2, "%lu", now);
449 xk->data = malloc(strlen(now2) +1);
450 sprintf(xk->data, "%lu", now);
451 set_user(&USERENTRY_XTRA, u, xk);
452 free(now2);
453 }
454 /* Strip out commas -- they're illegal */
455 if (host && host[0]) {
456 char *p;
457
458 /* About this fixfrom():
459 * We should use this fixfrom before every call of adduser()
460 * but its much easier to use here... (drummer)
461 * Only use it if we have a host :) (dw)
462 */
463 host = fixfrom(host);
464 p = strchr(host, ',');
465
466 while (p != NULL) {
467 *p = '?';
468 p = strchr(host, ',');
469 }
470 set_user(&USERENTRY_HOSTS, u, host);
471 } else
472 set_user(&USERENTRY_HOSTS, u, "none");
473 if (bu == userlist)
474 clear_chanlist();
475 if (bu == NULL)
476 bu = u;
477 else {
478 if ((bu == userlist) && (lastuser != NULL))
479 x = lastuser;
480 else
481 x = bu;
482 while (x->next != NULL)
483 x = x->next;
484 x->next = u;
485 if (bu == userlist)
486 lastuser = u;
487 }
488 return bu;
489 }
490
491 void freeuser(struct userrec *u)
492 {
493 struct user_entry *ue, *ut;
494 struct chanuserrec *ch, *z;
495
496 if (u == NULL)
497 return;
498 ch = u->chanrec;
499 while (ch) {
500 z = ch;
501 ch = ch->next;
502 if (z->info != NULL)
503 free(z->info);
504 free(z);
505 }
506 u->chanrec = NULL;
507 for (ue = u->entries; ue; ue = ut) {
508 ut = ue->next;
509 if (ue->name) {
510 struct list_type *lt, *ltt;
511
512 for (lt = ue->u.list; lt; lt = ltt) {
513 ltt = lt->next;
514 free(lt->extra);
515 free(lt);
516 }
517 free(ue->name);
518 free(ue);
519 } else {
520 ue->type->kill(ue);
521 }
522 }
523 free(u);
524 }
525
526 int deluser(char *handle)
527 {
528 struct userrec *u = userlist, *prev = NULL;
529 int fnd = 0;
530
531 while ((u != NULL) && (!fnd)) {
532 if (!strcasecmp(u->handle, handle))
533 fnd = 1;
534 else {
535 prev = u;
536 u = u->next;
537 }
538 }
539 if (!fnd)
540 return 0;
541 if (prev == NULL)
542 userlist = u->next;
543 else
544 prev->next = u->next;
545 for (fnd = 0; fnd < dcc_total; fnd++)
546 if (dcc[fnd].type && dcc[fnd].user == u)
547 dcc[fnd].user = 0; /* Clear any dcc users for this entry,
548 * null is safe-ish */
549 clear_chanlist();
550 freeuser(u);
551 lastuser = NULL;
552 return 1;
553 }
554
555 int delhost_by_handle(char *handle, char *host)
556 {
557 struct userrec *u;
558 struct list_type *q, *qnext, *qprev;
559 struct user_entry *e = NULL;
560 int i = 0;
561
562 u = get_user_by_handle(userlist, handle);
563 if (!u)
564 return 0;
565 q = get_user(&USERENTRY_HOSTS, u);
566 qprev = q;
567 if (q) {
568 if (!irccmp(q->extra, host)) {
569 e = find_user_entry(&USERENTRY_HOSTS, u);
570 e->u.extra = q->next;
571 free(q->extra);
572 free(q);
573 i++;
574 qprev = NULL;
575 q = e->u.extra;
576 } else
577 q = q->next;
578 while (q) {
579 qnext = q->next;
580 if (!irccmp(q->extra, host)) {
581 if (qprev)
582 qprev->next = q->next;
583 else if (e) {
584 e->u.extra = q->next;
585 qprev = NULL;
586 }
587 free(q->extra);
588 free(q);
589 i++;
590 } else
591 qprev = q;
592 q = qnext;
593 }
594 }
595 if (!qprev)
596 set_user(&USERENTRY_HOSTS, u, "none");
597 clear_chanlist();
598 return i;
599 }
600
601 void addhost_by_handle(char *handle, char *host)
602 {
603 struct userrec *u = get_user_by_handle(userlist, handle);
604
605 set_user(&USERENTRY_HOSTS, u, host);
606 clear_chanlist();
607 }
608
609 void touch_laston(struct userrec *u, char *where, time_t timeval)
610 {
611 if (!u)
612 return;
613 if (timeval > 1) {
614 struct laston_info *li =
615 (struct laston_info *) get_user(&USERENTRY_LASTON, u);
616
617 if (!li)
618 li = malloc(sizeof(struct laston_info));
619
620 else if (li->lastonplace)
621 free(li->lastonplace);
622 li->laston = timeval;
623 if (where)
624 li->lastonplace = strdup(where);
625 else
626 li->lastonplace = NULL;
627 set_user(&USERENTRY_LASTON, u, li);
628 } else if (timeval == 1) {
629 set_user(&USERENTRY_LASTON, u, 0);
630 }
631 }
632
633 /* Go through all channel records and try to find a matching
634 * nick. Will return the user's user record if that is known
635 * to the bot. (Fabian)
636 *
637 * Warning: This is unreliable by concept!
638 */
639 struct userrec *get_user_by_nick(char *nick)
640 {
641 struct chanset_t *chan;
642 memberlist *m;
643
644 for (chan = chanset; chan; chan = chan->next) {
645 for (m = chan->channel.member; m && m->nick[0] ;m = m->next) {
646 if (!irccmp(nick, m->nick)) {
647 char word[512];
648
649 snprintf(word, sizeof word, "%s!%s", m->nick, m->userhost);
650 /* No need to check the return value ourself */
651 return get_user_by_host(word);;
652 }
653 }
654 }
655 /* Sorry, no matches */
656 return NULL;
657 }
658
659 void user_del_chan(char *dname)
660 {
661 struct chanuserrec *ch, *och;
662 struct userrec *u;
663
664 for (u = userlist; u; u = u->next) {
665 ch = u->chanrec;
666 och = NULL;
667 while (ch) {
668 if (!irccmp(dname, ch->channel)) {
669 if (och)
670 och->next = ch->next;
671 else
672 u->chanrec = ch->next;
673
674 if (ch->info)
675 free(ch->info);
676 free(ch);
677 break;
678 }
679 och = ch;
680 ch = ch->next;
681 }
682 }
683 }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23