/[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.7 - (show annotations) (download) (as text)
Wed Nov 10 21:35:02 1999 UTC (19 years, 9 months ago) by fabian
Branch: MAIN
Changes since 1.6: +4 -1 lines
File MIME type: text/x-chdr
Resync with 1.4

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23