/[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.28 - (show annotations) (download) (as text)
Wed Aug 15 17:09:53 2001 UTC (18 years, 3 months ago) by guppy
Branch: MAIN
Changes since 1.27: +1 -38 lines
File MIME type: text/x-chdr
Cleaned up cmd_uptime and cmd_botinfo a bit -- started doing some more dummy _(text) ... that is gonna take alot of work to totally finish that

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

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23