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

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

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


Revision 1.6 - (show annotations) (download) (as text)
Tue Oct 26 21:46:42 1999 UTC (19 years, 9 months ago) by fabian
Branch: MAIN
Changes since 1.5: +14 -1 lines
File MIME type: text/x-chdr
Cybah's safechan patch

1 /*
2 * chanprog.c -- handles:
3 * rmspace()
4 * maintaining the server list
5 * revenge punishment
6 * timers, utimers
7 * telling the current programmed settings
8 * initializing a lot of stuff and loading the tcl scripts
9 * dprintf'ized, 1nov1995
10 */
11 /*
12 * This file is part of the eggdrop source code
13 * copyright (c) 1997 Robey Pointer
14 * and is distributed according to the GNU general public license.
15 * For full details, read the top of 'main.c' or the file called
16 * COPYING that was distributed with this code.
17 */
18
19 /* config file format changed 27jan1994 (Tcl outdates that) */
20
21 #include "main.h"
22 #if HAVE_GETRUSAGE
23 #include <sys/resource.h>
24 #if HAVE_SYS_RUSAGE_H
25 #include <sys/rusage.h>
26 #endif
27 #endif
28 #ifdef HAVE_UNAME
29 #include <sys/utsname.h>
30 #endif
31 #include "modules.h"
32
33 extern struct userrec *userlist;
34 extern log_t *logs;
35 extern Tcl_Interp *interp;
36 extern char ver[], botnetnick[], firewall[];
37 extern char motdfile[], userfile[], helpdir[], tempdir[];
38 extern char moddir[], notify_new[], owner[], configfile[];
39 extern time_t now, online_since;
40 extern int backgrd, term_z, con_chan, cache_hit, cache_miss, firewallport;
41 extern int default_flags, max_logs, conmask, protect_readonly, make_userfile;
42 extern int noshare, ignore_time;
43
44 tcl_timer_t *timer = NULL, *utimer = NULL; /* timers (minutely) and
45 * utimers (secondly) */
46 unsigned long timer_id = 1; /* next timer of any sort will have this
47 * number */
48 struct chanset_t *chanset = NULL; /* channel list */
49 char admin[121] = ""; /* admin info */
50 char origbotname[NICKLEN + 1];
51 char botname[NICKLEN + 1]; /* primary botname */
52
53 /* remove space characters from beginning and end of string */
54 /* (more efficent by Fred1) */
55 void rmspace(char *s)
56 {
57 #define whitespace(c) ( ((c)==32) || ((c)==9) || ((c)==13) || ((c)==10) )
58 char *p;
59
60 /* wipe end of string */
61 for (p = s + strlen(s) - 1; ((whitespace(*p)) && (p >= s)); p--);
62 if (p != s + strlen(s) - 1)
63 *(p + 1) = 0;
64 for (p = s; ((whitespace(*p)) && (*p)); p++);
65 if (p != s)
66 strcpy(s, p);
67 }
68
69 /* returns memberfields if the nick is in the member list */
70 memberlist *ismember(struct chanset_t *chan, char *nick)
71 {
72 memberlist *x;
73
74 x = chan->channel.member;
75 while (x->nick[0] && rfc_casecmp(x->nick, nick))
76 x = x->next;
77 if (!x->nick[0])
78 return NULL;
79 return x;
80 }
81
82 /* find a chanset by channel name as the server knows it (ie !ABCDEchannel) */
83 struct chanset_t *findchan(char *name)
84 {
85 struct chanset_t *chan = chanset;
86
87 while (chan != NULL) {
88 if (!rfc_casecmp(chan->name, name))
89 return chan;
90 chan = chan->next;
91 }
92 return NULL;
93 }
94
95 /* find a chanset by display name (ie !channel) */
96 struct chanset_t *findchan_by_dname(char *name)
97 {
98 struct chanset_t *chan = chanset;
99
100 while (chan != NULL) {
101 if (!rfc_casecmp(chan->dname, name))
102 return chan;
103 chan = chan->next;
104 }
105 return NULL;
106 }
107
108 /* stupid "caching" functions */
109 /* shortcut for get_user_by_host -- might have user record in one
110 * of the channel caches */
111 struct userrec *check_chanlist(char *host)
112 {
113 char *nick, *uhost, buf[UHOSTLEN];
114 memberlist *m;
115 struct chanset_t *chan;
116
117 strncpy(buf, host, UHOSTMAX);
118 buf[UHOSTMAX] = 0; /* why is this case sanely done, when there
119 * are so many others? */
120 uhost = buf;
121 nick = splitnick(&uhost);
122 for (chan = chanset; chan; chan = chan->next) {
123 m = chan->channel.member;
124 while (m->nick[0]) {
125 if (!rfc_casecmp(nick, m->nick) &&
126 !strcasecmp(uhost, m->userhost))
127 return m->user;
128 m = m->next;
129 }
130 }
131 return NULL;
132 }
133
134 /* shortcut for get_user_by_handle -- might have user record in channels */
135 struct userrec *check_chanlist_hand(char *hand)
136 {
137 struct chanset_t *chan = chanset;
138 memberlist *m;
139
140 while (chan) {
141 m = chan->channel.member;
142 while (m->nick[0]) {
143 if (m->user)
144 if (!strcasecmp(m->user->handle, hand))
145 return m->user;
146 m = m->next;
147 }
148 chan = chan->next;
149 }
150 return NULL;
151 }
152
153 /* clear the user pointers in the chanlists */
154 /* (necessary when a hostmask is added/removed or a user is added) */
155 void clear_chanlist()
156 {
157 memberlist *m;
158 struct chanset_t *chan = chanset;
159
160 while (chan) {
161 m = chan->channel.member;
162 while (m->nick[0]) {
163 m->user = NULL;
164 m = m->next;
165 }
166 chan = chan->next;
167 }
168 }
169
170 /* if this user@host is in a channel, set it (it was null) */
171 void set_chanlist(char *host, struct userrec *rec)
172 {
173 char *nick, *uhost, buf[UHOSTLEN];
174 memberlist *m;
175 struct chanset_t *chan = chanset;
176
177 context;
178 strcpy(buf, host);
179 uhost = buf;
180 nick = splitnick(&uhost);
181 while (chan) {
182 m = chan->channel.member;
183 while (m->nick[0]) {
184 if (!rfc_casecmp(nick, m->nick) &&
185 !strcasecmp(uhost, m->userhost))
186 m->user = rec;
187 m = m->next;
188 }
189 chan = chan->next;
190 }
191 }
192
193 /* memory we should be using */
194 int expmem_chanprog()
195 {
196 int tot;
197 tcl_timer_t *t;
198
199 context;
200 tot = 0;
201 for (t = timer; t; t = t->next) {
202 tot += sizeof(tcl_timer_t);
203 tot += strlen(t->cmd) + 1;
204 }
205 for (t = utimer; t; t = t->next) {
206 tot += sizeof(tcl_timer_t);
207 tot += strlen(t->cmd) + 1;
208 }
209 return tot;
210 }
211
212 /* dump uptime info out to dcc (guppy 9Jan99) */
213 void tell_verbose_uptime(int idx)
214 {
215 char s[256], s1[121];
216 time_t now2, hr, min;
217
218 now2 = now - online_since;
219 s[0] = 0;
220 if (now2 > 86400) {
221 /* days */
222 sprintf(s, "%d day", (int) (now2 / 86400));
223 if ((int) (now2 / 86400) >= 2)
224 strcat(s, "s");
225 strcat(s, ", ");
226 now2 -= (((int) (now2 / 86400)) * 86400);
227 }
228 hr = (time_t) ((int) now2 / 3600);
229 now2 -= (hr * 3600);
230 min = (time_t) ((int) now2 / 60);
231 sprintf(&s[strlen(s)], "%02d:%02d", (int) hr, (int) min);
232 s1[0] = 0;
233 if (backgrd)
234 strcpy(s1, MISC_BACKGROUND);
235 else {
236 if (term_z)
237 strcpy(s1, MISC_TERMMODE);
238 else if (con_chan)
239 strcpy(s1, MISC_STATMODE);
240 else
241 strcpy(s1, MISC_LOGMODE);
242 }
243 dprintf(idx, "%s %s (%s)\n", MISC_ONLINEFOR, s, s1);
244 }
245
246 /* dump status info out to dcc */
247 void tell_verbose_status(int idx)
248 {
249 char s[256], s1[121], s2[81];
250 char *vers_t, *uni_t;
251 int i;
252 time_t now2, hr, min;
253
254 #if HAVE_GETRUSAGE
255 struct rusage ru;
256
257 #else
258 #if HAVE_CLOCK
259 clock_t cl;
260
261 #endif
262 #endif
263 #ifdef HAVE_UNAME
264 struct utsname un;
265
266 if (!uname(&un) < 0) {
267 #endif
268 vers_t = " ";
269 uni_t = "*unknown*";
270 #ifdef HAVE_UNAME
271 } else {
272 vers_t = un.release;
273 uni_t = un.sysname;
274 }
275 #endif
276
277 i = count_users(userlist);
278 dprintf(idx, "I am %s, running %s: %d user%s (mem: %uk)\n",
279 botnetnick, ver, i, i == 1 ? "" : "s",
280 (int) (expected_memory() / 1024));
281 dprintf(idx, "Running on %s %s\n", uni_t, vers_t);
282 if (admin[0])
283 dprintf(idx, "Admin: %s\n", admin);
284 now2 = now - online_since;
285 s[0] = 0;
286 if (now2 > 86400) {
287 /* days */
288 sprintf(s, "%d day", (int) (now2 / 86400));
289 if ((int) (now2 / 86400) >= 2)
290 strcat(s, "s");
291 strcat(s, ", ");
292 now2 -= (((int) (now2 / 86400)) * 86400);
293 }
294 hr = (time_t) ((int) now2 / 3600);
295 now2 -= (hr * 3600);
296 min = (time_t) ((int) now2 / 60);
297 sprintf(&s[strlen(s)], "%02d:%02d", (int) hr, (int) min);
298 s1[0] = 0;
299 if (backgrd)
300 strcpy(s1, MISC_BACKGROUND);
301 else {
302 if (term_z)
303 strcpy(s1, MISC_TERMMODE);
304 else if (con_chan)
305 strcpy(s1, MISC_STATMODE);
306 else
307 strcpy(s1, MISC_LOGMODE);
308 }
309 #if HAVE_GETRUSAGE
310 getrusage(RUSAGE_SELF, &ru);
311 hr = (int) ((ru.ru_utime.tv_sec + ru.ru_stime.tv_sec) / 60);
312 min = (int) ((ru.ru_utime.tv_sec + ru.ru_stime.tv_sec) - (hr * 60));
313 sprintf(s2, "CPU %02d:%02d", (int) hr, (int) min); /* actally min/sec */
314 #else
315 #if HAVE_CLOCK
316 cl = (clock() / CLOCKS_PER_SEC);
317 hr = (int) (cl / 60);
318 min = (int) (cl - (hr * 60));
319 sprintf(s2, "CPU %02d:%02d", (int) hr, (int) min); /* actually min/sec */
320 #else
321 sprintf(s2, "CPU ???");
322 #endif
323 #endif
324 dprintf(idx, "%s %s (%s) %s %s %4.1f%%\n", MISC_ONLINEFOR,
325 s, s1, s2, MISC_CACHEHIT,
326 100.0 * ((float) cache_hit) / ((float) (cache_hit + cache_miss)));
327 strcpy(s, "info library");
328 if ((interp) && (Tcl_Eval(interp, s) == TCL_OK))
329 dprintf(idx, "%s %s\n", MISC_TCLLIBVER, interp->result);
330 }
331
332 /* show all internal state variables */
333 void tell_settings(int idx)
334 {
335 char s[1024];
336 int i;
337 struct flag_record fr =
338 {FR_GLOBAL, 0, 0, 0, 0, 0};
339
340 dprintf(idx, "Botnet Nickname: %s\n", botnetnick);
341 if (firewall[0])
342 dprintf(idx, "Firewall: %s, port %d\n", firewall, firewallport);
343 dprintf(idx, "Userfile: %s Motd: %s\n", userfile, motdfile);
344 dprintf(idx, "Directories:\n");
345 dprintf(idx, " Help : %s\n", helpdir);
346 dprintf(idx, " Temp : %s\n", tempdir);
347 #ifndef STATIC
348 dprintf(idx, " Modules : %s\n", moddir);
349 #endif
350 fr.global = default_flags;
351
352 build_flags(s, &fr, NULL);
353 dprintf(idx, "%s [%s], %s: %s\n", MISC_NEWUSERFLAGS, s,
354 MISC_NOTIFY, notify_new);
355 if (owner[0])
356 dprintf(idx, "%s: %s\n", MISC_PERMOWNER, owner);
357 for (i = 0; i < max_logs; i++)
358 if (logs[i].filename != NULL) {
359 dprintf(idx, "Logfile #%d: %s on %s (%s: %s)\n", i + 1,
360 logs[i].filename, logs[i].chname,
361 masktype(logs[i].mask), maskname(logs[i].mask));
362 }
363 dprintf(idx, "Ignores last %d mins\n", ignore_time);
364 }
365
366 void reaffirm_owners()
367 {
368 char *p, *q, s[121];
369 struct userrec *u;
370
371 /* make sure default owners are +n */
372 if (owner[0]) {
373 q = owner;
374 p = strchr(q, ',');
375 while (p) {
376 strncpy(s, q, p - q);
377 s[p - q] = 0;
378 rmspace(s);
379 u = get_user_by_handle(userlist, s);
380 if (u)
381 u->flags = sanity_check(u->flags | USER_OWNER);
382 q = p + 1;
383 p = strchr(q, ',');
384 }
385 strcpy(s, q);
386 rmspace(s);
387 u = get_user_by_handle(userlist, s);
388 if (u)
389 u->flags = sanity_check(u->flags | USER_OWNER);
390 }
391 }
392
393 void chanprog()
394 {
395 int i;
396
397 admin[0] = 0;
398 helpdir[0] = 0;
399 tempdir[0] = 0;
400 for (i = 0; i < max_logs; i++)
401 logs[i].flags |= LF_EXPIRING;
402 conmask = 0;
403 /* turn off read-only variables (make them write-able) for rehash */
404 protect_readonly = 0;
405 /* now read it */
406 context;
407 if (!readtclprog(configfile))
408 fatal(MISC_NOCONFIGFILE, 0);
409 for (i = 0; i < max_logs; i++) {
410 if (logs[i].flags & LF_EXPIRING) {
411 if (logs[i].filename != NULL) {
412 nfree(logs[i].filename);
413 logs[i].filename = NULL;
414 }
415 if (logs[i].chname != NULL) {
416 nfree(logs[i].chname);
417 logs[i].chname = NULL;
418 }
419 if (logs[i].f != NULL) {
420 fclose(logs[i].f);
421 logs[i].f = NULL;
422 }
423 logs[i].mask = 0;
424 logs[i].flags = 0;
425 }
426 }
427 /* We should be safe now */
428 call_hook(HOOK_REHASH);
429 context;
430 protect_readonly = 1;
431 if (!userfile[0])
432 fatal(MISC_NOUSERFILE2, 0);
433 if ((int) getuid() == 0) {
434 /* perhaps you should make it run something innocent here ;)
435 * like rm -rf /etc :) */
436 printf("\n\n%s\n", MISC_ROOTWARN);
437 }
438 if (!readuserfile(userfile, &userlist)) {
439 if (!make_userfile)
440 fatal(MISC_NOUSERFILE, 0);
441 printf("\n\n%s\n", MISC_NOUSERFILE2);
442 if (module_find("server", 0, 0))
443 printf(MISC_USERFCREATE1, origbotname);
444 printf("%s\n\n", MISC_USERFCREATE2);
445 } else if (make_userfile) {
446 make_userfile = 0;
447 printf("%s\n", MISC_USERFEXISTS);
448 }
449 context;
450 if (helpdir[0])
451 if (helpdir[strlen(helpdir) - 1] != '/')
452 strcat(helpdir, "/");
453 if (tempdir[0])
454 if (tempdir[strlen(tempdir) - 1] != '/')
455 strcat(tempdir, "/");
456 if (!botnetnick[0]) {
457 strncpy(botnetnick, origbotname, HANDLEN);
458 botnetnick[HANDLEN] = 0;
459 }
460 if (!botnetnick[0])
461 fatal("I don't have a botnet nick!!\n", 0);
462 context;
463 /* test tempdir: it's vital */
464 {
465 FILE *f;
466 char s[161], rands[8];
467
468 /* possible file race condition solved by using a random string
469 * and the process id in the filename */
470 make_rand_str(rands, 7); /* create random string */
471 sprintf(s, "%s.test-%u-%s", tempdir, getpid(), rands);
472 f = fopen(s, "w");
473 if (f == NULL)
474 fatal(MISC_CANTWRITETEMP, 0);
475 fclose(f);
476 unlink(s);
477 }
478 context;
479 reaffirm_owners();
480 }
481
482 /* reload the user file from disk */
483 void reload()
484 {
485 FILE *f;
486
487 f = fopen(userfile, "r");
488 if (f == NULL) {
489 putlog(LOG_MISC, "*", MISC_CANTRELOADUSER);
490 return;
491 }
492 fclose(f);
493 noshare = 1;
494 clear_userlist(userlist);
495 noshare = 0;
496 userlist = NULL;
497 if (!readuserfile(userfile, &userlist))
498 fatal(MISC_MISSINGUSERF, 0);
499 context;
500 reaffirm_owners();
501 call_hook(HOOK_READ_USERFILE);
502 }
503
504 void rehash()
505 {
506 call_hook(HOOK_PRE_REHASH);
507 noshare = 1;
508 clear_userlist(userlist);
509 noshare = 0;
510 userlist = NULL;
511 chanprog();
512 }
513
514 /* brief venture into timers */
515
516 /* add a timer */
517 unsigned long add_timer(tcl_timer_t ** stack, int elapse, char *cmd,
518 unsigned long prev_id)
519 {
520 tcl_timer_t *old = (*stack);
521
522 *stack = (tcl_timer_t *) nmalloc(sizeof(tcl_timer_t));
523 (*stack)->next = old;
524 (*stack)->mins = elapse;
525 (*stack)->cmd = (char *) nmalloc(strlen(cmd) + 1);
526 strcpy((*stack)->cmd, cmd);
527 /* if it's just being added back and already had an id,
528 * don't create a new one */
529 if (prev_id > 0)
530 (*stack)->id = prev_id;
531 else
532 (*stack)->id = timer_id++;
533 return (*stack)->id;
534 }
535
536 /* remove a timer, by id */
537 int remove_timer(tcl_timer_t ** stack, unsigned long id)
538 {
539 tcl_timer_t *old;
540 int ok = 0;
541
542 while (*stack) {
543 if ((*stack)->id == id) {
544 ok++;
545 old = *stack;
546 *stack = ((*stack)->next);
547 nfree(old->cmd);
548 nfree(old);
549 } else
550 stack = &((*stack)->next);
551 }
552 return ok;
553 }
554
555 /* check timers, execute the ones that have expired */
556 void do_check_timers(tcl_timer_t ** stack)
557 {
558 tcl_timer_t *mark = *stack, *old = NULL;
559 char x[30];
560
561 /* new timers could be added by a Tcl script inside a current timer */
562 /* so i'll just clear out the timer list completely, and add any
563 * unexpired timers back on */
564 context;
565 *stack = NULL;
566 while (mark) {
567 context;
568 if (mark->mins > 0)
569 mark->mins--;
570 old = mark;
571 mark = mark->next;
572 if (old->mins == 0) {
573 context;
574 simple_sprintf(x, "timer%d", old->id);
575 do_tcl(x, old->cmd);
576 nfree(old->cmd);
577 nfree(old);
578 } else {
579 context;
580 old->next = *stack;
581 *stack = old;
582 }
583 }
584 }
585
586 /* wipe all timers */
587 void wipe_timers(Tcl_Interp * irp, tcl_timer_t ** stack)
588 {
589 tcl_timer_t *mark = *stack, *old;
590
591 while (mark) {
592 old = mark;
593 mark = mark->next;
594 nfree(old->cmd);
595 nfree(old);
596 }
597 *stack = NULL;
598 }
599
600 /* return list of timers */
601 void list_timers(Tcl_Interp * irp, tcl_timer_t * stack)
602 {
603 tcl_timer_t *mark = stack;
604 char mins[10], id[20], *argv[3], *x;
605
606 while (mark != NULL) {
607 sprintf(mins, "%u", mark->mins);
608 sprintf(id, "timer%lu", mark->id);
609 argv[0] = mins;
610 argv[1] = mark->cmd;
611 argv[2] = id;
612 x = Tcl_Merge(3, argv);
613 Tcl_AppendElement(irp, x);
614 n_free(x, "", 0);
615 mark = mark->next;
616 }
617 }
618
619 /* Oddly enough, written by proton (Emech's coder) */
620
621 int isowner(char *name)
622 {
623 char *pa, *pb;
624 char nl, pl;
625
626 if (!owner || !*owner)
627 return (0);
628 if (!name || !*name)
629 return (0);
630 nl = strlen(name);
631 pa = owner;
632 pb = owner;
633 while (1) {
634 while (1) {
635 if ((*pb == 0) || (*pb == ',') || (*pb == ' '))
636 break;
637 pb++;
638 }
639 pl = (unsigned int) pb - (unsigned int) pa;
640 if ((pl == nl) && (!strncasecmp(pa, name, nl)))
641 return (1);
642 while (1) {
643 if ((*pb == 0) || ((*pb != ',') && (*pb != ' ')))
644 break;
645 pb++;
646 }
647 if (*pb == 0)
648 return (0);
649 pa = pb;
650 }
651 }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23