/[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.30 - (show annotations) (download) (as text)
Thu Oct 11 18:24:01 2001 UTC (18 years, 1 month ago) by tothwolf
Branch: MAIN
Changes since 1.29: +7 -7 lines
File MIME type: text/x-chdr
* rfc1459.c cleaned up and renamed to irccmp.c
* rfc_casecmp() renamed to irccmp()
* rfc_ncasecmp() renamed to ircncmp()
* rfc_toupper() renamed to irctoupper()
* rfc_tolower() renamed to irctolower()
* more match.c cleanups

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.29 2001/10/10 10:44:03 tothwolf 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 (!irccmp(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 (!irccmp(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 (!irccmp(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 (!irccmp(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 (!irccmp(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 (!irccmp(nick, m->nick) && !egg_strcasecmp(uhost, m->userhost))
203 m->user = rec;
204 }
205
206 /* Dump status info out to dcc
207 */
208 void tell_verbose_status(int idx)
209 {
210 char s[256], s1[121], s2[81];
211 char *vers_t, *uni_t;
212 int i;
213 time_t now2, hr, min;
214 #if HAVE_GETRUSAGE
215 struct rusage ru;
216 #else
217 # if HAVE_CLOCK
218 clock_t cl;
219 # endif
220 #endif
221 #ifdef HAVE_UNAME
222 struct utsname un;
223
224 if (!uname(&un) < 0) {
225 #endif
226 vers_t = " ";
227 uni_t = "*unknown*";
228 #ifdef HAVE_UNAME
229 } else {
230 vers_t = un.release;
231 uni_t = un.sysname;
232 }
233 #endif
234
235 i = count_users(userlist);
236 dprintf(idx, "I am %s, running %s: %d user%s\n",
237 botnetnick, ver, i, i == 1 ? "" : "s");
238 dprintf(idx, "Running on %s %s\n", uni_t, vers_t);
239 if (admin[0])
240 dprintf(idx, "Admin: %s\n", admin);
241 now2 = now - online_since;
242 s[0] = 0;
243 if (now2 > 86400) {
244 /* days */
245 sprintf(s, "%d day", (int) (now2 / 86400));
246 if ((int) (now2 / 86400) >= 2)
247 strcat(s, "s");
248 strcat(s, ", ");
249 now2 -= (((int) (now2 / 86400)) * 86400);
250 }
251 hr = (time_t) ((int) now2 / 3600);
252 now2 -= (hr * 3600);
253 min = (time_t) ((int) now2 / 60);
254 sprintf(&s[strlen(s)], "%02d:%02d", (int) hr, (int) min);
255 s1[0] = 0;
256 if (backgrd)
257 strcpy(s1, _("background"));
258 else {
259 if (term_z)
260 strcpy(s1, _("terminal mode"));
261 else if (con_chan)
262 strcpy(s1, _("status mode"));
263 else
264 strcpy(s1, _("log dump mode"));
265 }
266 #if HAVE_GETRUSAGE
267 getrusage(RUSAGE_SELF, &ru);
268 hr = (int) ((ru.ru_utime.tv_sec + ru.ru_stime.tv_sec) / 60);
269 min = (int) ((ru.ru_utime.tv_sec + ru.ru_stime.tv_sec) - (hr * 60));
270 sprintf(s2, "CPU %02d:%02d", (int) hr, (int) min); /* Actally min/sec */
271 #else
272 # if HAVE_CLOCK
273 cl = (clock() / CLOCKS_PER_SEC);
274 hr = (int) (cl / 60);
275 min = (int) (cl - (hr * 60));
276 sprintf(s2, "CPU %02d:%02d", (int) hr, (int) min); /* Actually min/sec */
277 # else
278 sprintf(s2, "CPU ???");
279 # endif
280 #endif
281 dprintf(idx, "%s %s (%s) %s %s %4.1f%%\n", _("Online for"),
282 s, s1, s2, _("cache hit"),
283 100.0 * ((float) cache_hit) / ((float) (cache_hit + cache_miss)));
284
285 /* info library */
286 dprintf(idx, "%s %s\n", _("Tcl library:"),
287 ((interp) && (Tcl_Eval(interp, "info library") == TCL_OK)) ?
288 interp->result : "*unknown*");
289
290 /* info tclversion/patchlevel */
291 dprintf(idx, "%s %s (%s %s)\n", _("Tcl version:"),
292 ((interp) && (Tcl_Eval(interp, "info patchlevel") == TCL_OK)) ?
293 interp->result : (Tcl_Eval(interp, "info tclversion") == TCL_OK) ?
294 interp->result : "*unknown*", _("header version"),
295 TCL_PATCH_LEVEL ? TCL_PATCH_LEVEL : "*unknown*");
296
297 #if HAVE_TCL_THREADS
298 dprintf(idx, "Tcl is threaded\n");
299 #endif
300
301 }
302
303 /* Show all internal state variables
304 */
305 void tell_settings(int idx)
306 {
307 char s[1024];
308 int i;
309 struct flag_record fr = {FR_GLOBAL, 0, 0, 0, 0, 0};
310
311 dprintf(idx, "Botnet Nickname: %s\n", botnetnick);
312 if (firewall[0])
313 dprintf(idx, "Firewall: %s, port %d\n", firewall, firewallport);
314 dprintf(idx, "Userfile: %s Motd: %s\n", userfile, motdfile);
315 dprintf(idx, "Directories:\n");
316 dprintf(idx, " Help : %s\n", helpdir);
317 dprintf(idx, " Temp : %s\n", tempdir);
318 #ifndef STATIC
319 dprintf(idx, " Modules : %s\n", moddir);
320 #endif
321 fr.global = default_flags;
322
323 build_flags(s, &fr, NULL);
324 dprintf(idx, "%s [%s], %s: %s\n", _("New users get flags"), s,
325 _("notify"), notify_new);
326 if (owner[0])
327 dprintf(idx, "%s: %s\n", _("Permanent owner(s)"), owner);
328 for (i = 0; i < max_logs; i++)
329 if (logs[i].filename != NULL) {
330 dprintf(idx, "Logfile #%d: %s on %s (%s: %s)\n", i + 1,
331 logs[i].filename, logs[i].chname,
332 masktype(logs[i].mask), maskname(logs[i].mask));
333 }
334 dprintf(idx, "Ignores last %d mins\n", ignore_time);
335 }
336
337 void reaffirm_owners()
338 {
339 char *p, *q, s[121];
340 struct userrec *u;
341
342 /* Make sure default owners are +n */
343 if (owner[0]) {
344 q = owner;
345 p = strchr(q, ',');
346 while (p) {
347 strncpyz(s, q, p - q);
348 rmspace(s);
349 u = get_user_by_handle(userlist, s);
350 if (u)
351 u->flags = sanity_check(u->flags | USER_OWNER);
352 q = p + 1;
353 p = strchr(q, ',');
354 }
355 strcpy(s, q);
356 rmspace(s);
357 u = get_user_by_handle(userlist, s);
358 if (u)
359 u->flags = sanity_check(u->flags | USER_OWNER);
360 }
361 }
362
363 void chanprog()
364 {
365 int i;
366
367 admin[0] = 0;
368 helpdir[0] = 0;
369 tempdir[0] = 0;
370 for (i = 0; i < max_logs; i++)
371 logs[i].flags |= LF_EXPIRING;
372 conmask = 0;
373 /* Turn off read-only variables (make them write-able) for rehash */
374 protect_readonly = 0;
375 /* Now read it */
376 if (!readtclprog(configfile))
377 fatal(_("CONFIG FILE NOT LOADED (NOT FOUND, OR ERROR)"), 0);
378 for (i = 0; i < max_logs; i++) {
379 if (logs[i].flags & LF_EXPIRING) {
380 if (logs[i].filename != NULL)
381 free_null(logs[i].filename);
382 if (logs[i].chname != NULL)
383 free_null(logs[i].chname);
384 if (logs[i].f != NULL) {
385 fclose(logs[i].f);
386 logs[i].f = NULL;
387 }
388 logs[i].mask = 0;
389 logs[i].flags = 0;
390 }
391 }
392 /* We should be safe now */
393 call_hook(HOOK_REHASH);
394 protect_readonly = 1;
395 if (!userfile[0])
396 fatal(_("STARTING BOT IN USERFILE CREATION MODE.\n\
397 Telnet to the bot and enter 'NEW' as your nickname."), 0);
398 if (!readuserfile(userfile, &userlist)) {
399 if (!make_userfile) {
400 char tmp[178];
401
402 egg_snprintf(tmp, sizeof tmp, _("USER FILE NOT FOUND! (try ./eggdrop -m %s to make one)\n"), configfile);
403 fatal(tmp, 0);
404 }
405 printf(_("\n\nSTARTING BOT IN USERFILE CREATION MODE.\n\
406 Telnet to the bot and enter 'NEW' as your nickname.\n"));
407 if (module_find("server", 0, 0))
408 printf(_("OR Go to IRC and: /msg %s hello\n"), origbotname);
409 printf(_("This will make the bot recognize you as the master.\n\n"));
410 } else if (make_userfile) {
411 make_userfile = 0;
412 printf(_("USERFILE ALREADY EXISTS (drop the -m)\n"));
413 }
414 if (helpdir[0])
415 if (helpdir[strlen(helpdir) - 1] != '/')
416 strcat(helpdir, "/");
417 if (tempdir[0])
418 if (tempdir[strlen(tempdir) - 1] != '/')
419 strcat(tempdir, "/");
420 if (!botnetnick[0]) {
421 strncpyz(botnetnick, origbotname, HANDLEN + 1);
422 }
423 if (!botnetnick[0])
424 fatal("I don't have a botnet nick!!\n", 0);
425 /* Test tempdir: it's vital */
426 {
427 FILE *f;
428 char s[161], rands[8];
429
430 /* Possible file race condition solved by using a random string
431 * and the process id in the filename.
432 * FIXME: This race is only partitially fixed. We could still be
433 * overwriting an existing file / following a malicious
434 * link.
435 */
436 make_rand_str(rands, 7); /* create random string */
437 sprintf(s, "%s.test-%u-%s", tempdir, getpid(), rands);
438 f = fopen(s, "w");
439 if (f == NULL)
440 fatal(_("CANT WRITE TO TEMP DIR"), 0);
441 fclose(f);
442 unlink(s);
443 }
444 reaffirm_owners();
445 }
446
447 /* Reload the user file from disk
448 */
449 void reload()
450 {
451 FILE *f;
452
453 f = fopen(userfile, "r");
454 if (f == NULL) {
455 putlog(LOG_MISC, "*", _("Cant reload user file!"));
456 return;
457 }
458 fclose(f);
459 noshare = 1;
460 clear_userlist(userlist);
461 noshare = 0;
462 userlist = NULL;
463 if (!readuserfile(userfile, &userlist))
464 fatal(_("User file is missing!"), 0);
465 reaffirm_owners();
466 call_hook(HOOK_READ_USERFILE);
467 }
468
469 void rehash()
470 {
471 call_hook(HOOK_PRE_REHASH);
472 noshare = 1;
473 clear_userlist(userlist);
474 noshare = 0;
475 userlist = NULL;
476 chanprog();
477 }
478
479 /*
480 * Brief venture into timers
481 */
482
483 /* Add a timer
484 */
485 unsigned long add_timer(tcl_timer_t **stack, int elapse, char *cmd,
486 unsigned long prev_id)
487 {
488 tcl_timer_t *old = (*stack);
489
490 *stack = (tcl_timer_t *) malloc(sizeof(tcl_timer_t));
491 (*stack)->next = old;
492 (*stack)->mins = elapse;
493 malloc_strcpy((*stack)->cmd, cmd);
494
495 /* If it's just being added back and already had an id,
496 * don't create a new one.
497 */
498 if (prev_id > 0)
499 (*stack)->id = prev_id;
500 else
501 (*stack)->id = timer_id++;
502 return (*stack)->id;
503 }
504
505 /* Remove a timer, by id
506 */
507 int remove_timer(tcl_timer_t **stack, unsigned long id)
508 {
509 tcl_timer_t *old;
510 int ok = 0;
511
512 while (*stack) {
513 if ((*stack)->id == id) {
514 ok++;
515 old = *stack;
516 *stack = ((*stack)->next);
517 free(old->cmd);
518 free(old);
519 } else
520 stack = &((*stack)->next);
521 }
522 return ok;
523 }
524
525 /* Check timers, execute the ones that have expired.
526 */
527 void do_check_timers(tcl_timer_t **stack)
528 {
529 tcl_timer_t *mark = *stack, *old = NULL;
530 char x[16];
531
532 /* New timers could be added by a Tcl script inside a current timer
533 * so i'll just clear out the timer list completely, and add any
534 * unexpired timers back on.
535 */
536 *stack = NULL;
537 while (mark) {
538 if (mark->mins > 0)
539 mark->mins--;
540 old = mark;
541 mark = mark->next;
542 if (!old->mins) {
543 egg_snprintf(x, sizeof x, "timer%lu", old->id);
544 do_tcl(x, old->cmd);
545 free(old->cmd);
546 free(old);
547 } else {
548 old->next = *stack;
549 *stack = old;
550 }
551 }
552 }
553
554 /* Wipe all timers.
555 */
556 void wipe_timers(Tcl_Interp *irp, tcl_timer_t **stack)
557 {
558 tcl_timer_t *mark = *stack, *old;
559
560 while (mark) {
561 old = mark;
562 mark = mark->next;
563 free(old->cmd);
564 free(old);
565 }
566 *stack = NULL;
567 }
568
569 /* Return list of timers
570 */
571 void list_timers(Tcl_Interp *irp, tcl_timer_t *stack)
572 {
573 tcl_timer_t *mark;
574 char mins[10], id[16], *argv[3], *x;
575
576 for (mark = stack; mark; mark = mark->next) {
577 egg_snprintf(mins, sizeof mins, "%u", mark->mins);
578 egg_snprintf(id, sizeof id, "timer%lu", mark->id);
579 argv[0] = mins;
580 argv[1] = mark->cmd;
581 argv[2] = id;
582 x = Tcl_Merge(3, argv);
583 Tcl_AppendElement(irp, x);
584 Tcl_Free((char *) x);
585 }
586 }
587
588 /* Oddly enough, written by proton (Emech's coder)
589 */
590 int isowner(char *name)
591 {
592 char *pa, *pb;
593 char nl, pl;
594
595 if (!owner || !*owner)
596 return (0);
597 if (!name || !*name)
598 return (0);
599 nl = strlen(name);
600 pa = owner;
601 pb = owner;
602 while (1) {
603 while (1) {
604 if ((*pb == 0) || (*pb == ',') || (*pb == ' '))
605 break;
606 pb++;
607 }
608 pl = (unsigned int) pb - (unsigned int) pa;
609 if (pl == nl && !egg_strncasecmp(pa, name, nl))
610 return (1);
611 while (1) {
612 if ((*pb == 0) || ((*pb != ',') && (*pb != ' ')))
613 break;
614 pb++;
615 }
616 if (*pb == 0)
617 return (0);
618 pa = pb;
619 }
620 }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23