/[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.27 - (show annotations) (download) (as text)
Mon Aug 13 16:52:13 2001 UTC (18 years, 3 months ago) by guppy
Branch: MAIN
Changes since 1.26: +6 -12 lines
File MIME type: text/x-chdr
Cleaned up the output of .status inregards to TCL ...

Instead of showing:

Using Tcl library: /usr/local/lib/tcl8.3
Tcl version: 8.3 (header version 8.3)
Tcl patchlevel: 8.3.3 (header patchlevel 8.3.3)
TCL isn't threaded

We now show:

Tcl library: /usr/lib/tcl8.3
Tcl version: 8.3.2 (header version 8.3.2)

and is TCL is threaded:

Tcl library: /usr/lib/tcl8.3
Tcl version: 8.3.2 (header version 8.3.2)
Tcl is threaded

Do we even need to show the header version?

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23