/[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.11 - (show annotations) (download) (as text)
Tue Dec 21 17:35:09 1999 UTC (19 years, 6 months ago) by fabian
Branch: MAIN
Changes since 1.10: +28 -15 lines
File MIME type: text/x-chdr
Tothwolf's id-header

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23