/[cvs]/eggdrop1.8/src/chanprog.c
ViewVC logotype

Annotation of /eggdrop1.8/src/chanprog.c

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.1 - (hide annotations) (download) (as text)
Mon Jul 26 21:11:06 2010 UTC (8 years, 11 months ago) by simple
Branch: MAIN
Branch point for: eggheads
File MIME type: text/x-chdr
Initial revision

1 simple 1.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.67 2010/06/29 15:52:24 thommey Exp $
11     */
12     /*
13     * Copyright (C) 1997 Robey Pointer
14     * Copyright (C) 1999 - 2010 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    
33     #ifdef HAVE_GETRUSAGE
34     # include <sys/resource.h>
35     # ifdef HAVE_SYS_RUSAGE_H
36     # include <sys/rusage.h>
37     # endif
38     #endif
39    
40     #ifdef HAVE_UNAME
41     # include <sys/utsname.h>
42     #endif
43    
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[], motdfile[], userfile[], helpdir[],
50     tempdir[], moddir[], notify_new[], owner[], configfile[];
51     extern time_t now, online_since;
52     extern int backgrd, term_z, con_chan, cache_hit, cache_miss, firewallport,
53     default_flags, max_logs, conmask, protect_readonly, make_userfile,
54     noshare, ignore_time, max_socks;
55    
56     tcl_timer_t *timer = NULL; /* Minutely timer */
57     tcl_timer_t *utimer = NULL; /* Secondly timer */
58     unsigned long timer_id = 1; /* Next timer of any sort will
59     * have this number */
60     struct chanset_t *chanset = NULL; /* Channel list */
61     char admin[121] = ""; /* Admin info */
62     char origbotname[NICKLEN + 1];
63     char botname[NICKLEN + 1]; /* Primary botname */
64    
65    
66     /* Remove leading and trailing whitespaces.
67     */
68     void rmspace(char *s)
69     {
70     register char *p = NULL, *q = NULL;
71    
72     if (!s || !*s)
73     return;
74    
75     /* Remove trailing whitespaces. */
76     for (q = s + strlen(s) - 1; q >= s && egg_isspace(*q); q--);
77     *(q + 1) = 0;
78    
79     /* Remove leading whitespaces. */
80     for (p = s; egg_isspace(*p); p++);
81    
82     if (p != s)
83     memmove(s, p, q - p + 2);
84     }
85    
86    
87     /* Returns memberfields if the nick is in the member list.
88     */
89     memberlist *ismember(struct chanset_t *chan, char *nick)
90     {
91     register memberlist *x;
92    
93     for (x = chan->channel.member; x && x->nick[0]; x = x->next)
94     if (!rfc_casecmp(x->nick, nick))
95     return x;
96     return NULL;
97     }
98    
99     /* Find a chanset by channel name as the server knows it (ie !ABCDEchannel)
100     */
101     struct chanset_t *findchan(const char *name)
102     {
103     register struct chanset_t *chan;
104    
105     for (chan = chanset; chan; chan = chan->next)
106     if (!rfc_casecmp(chan->name, name))
107     return chan;
108     return NULL;
109     }
110    
111     /* Find a chanset by display name (ie !channel)
112     */
113     struct chanset_t *findchan_by_dname(const char *name)
114     {
115     register struct chanset_t *chan;
116    
117     for (chan = chanset; chan; chan = chan->next)
118     if (!rfc_casecmp(chan->dname, name))
119     return chan;
120     return NULL;
121     }
122    
123    
124     /*
125     * "caching" functions
126     */
127    
128     /* Shortcut for get_user_by_host -- might have user record in one
129     * of the channel caches.
130     */
131     struct userrec *check_chanlist(const char *host)
132     {
133     char *nick, *uhost, buf[UHOSTLEN];
134     register memberlist *m;
135     register struct chanset_t *chan;
136    
137     strncpyz(buf, host, sizeof buf);
138     uhost = buf;
139     nick = splitnick(&uhost);
140     for (chan = chanset; chan; chan = chan->next)
141     for (m = chan->channel.member; m && m->nick[0]; m = m->next)
142     if (!rfc_casecmp(nick, m->nick) && !egg_strcasecmp(uhost, m->userhost))
143     return m->user;
144     return NULL;
145     }
146    
147     /* Shortcut for get_user_by_handle -- might have user record in channels
148     */
149     struct userrec *check_chanlist_hand(const char *hand)
150     {
151     register struct chanset_t *chan;
152     register memberlist *m;
153    
154     for (chan = chanset; chan; chan = chan->next)
155     for (m = chan->channel.member; m && m->nick[0]; m = m->next)
156     if (m->user && !egg_strcasecmp(m->user->handle, hand))
157     return m->user;
158     return NULL;
159     }
160    
161     /* Clear the user pointers in the chanlists.
162     *
163     * Necessary when a hostmask is added/removed, a user is added or a new
164     * userfile is loaded.
165     */
166     void clear_chanlist(void)
167     {
168     register memberlist *m;
169     register struct chanset_t *chan;
170    
171     for (chan = chanset; chan; chan = chan->next)
172     for (m = chan->channel.member; m && m->nick[0]; m = m->next) {
173     m->user = NULL;
174     m->tried_getuser = 0;
175     }
176     }
177    
178     /* Clear the user pointer of a specific nick in the chanlists.
179     *
180     * Necessary when a hostmask is added/removed, a nick changes, etc.
181     * Does not completely invalidate the channel cache like clear_chanlist().
182     */
183     void clear_chanlist_member(const char *nick)
184     {
185     register memberlist *m;
186     register struct chanset_t *chan;
187    
188     for (chan = chanset; chan; chan = chan->next)
189     for (m = chan->channel.member; m && m->nick[0]; m = m->next)
190     if (!rfc_casecmp(m->nick, nick)) {
191     m->user = NULL;
192     m->tried_getuser = 0;
193     break;
194     }
195     }
196    
197     /* If this user@host is in a channel, set it (it was null)
198     */
199     void set_chanlist(const char *host, struct userrec *rec)
200     {
201     char *nick, *uhost, buf[UHOSTLEN];
202     register memberlist *m;
203     register struct chanset_t *chan;
204    
205     strncpyz(buf, host, sizeof buf);
206     uhost = buf;
207     nick = splitnick(&uhost);
208     for (chan = chanset; chan; chan = chan->next)
209     for (m = chan->channel.member; m && m->nick[0]; m = m->next)
210     if (!rfc_casecmp(nick, m->nick) && !egg_strcasecmp(uhost, m->userhost))
211     m->user = rec;
212     }
213    
214     /* Calculate the memory we should be using
215     */
216     int expmem_chanprog()
217     {
218     register int tot = 0;
219     register tcl_timer_t *t;
220    
221     for (t = timer; t; t = t->next)
222     tot += sizeof(tcl_timer_t) + strlen(t->cmd) + 1;
223     for (t = utimer; t; t = t->next)
224     tot += sizeof(tcl_timer_t) + strlen(t->cmd) + 1;
225     return tot;
226     }
227    
228     /* Dump uptime info out to dcc (guppy 9Jan99)
229     */
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     */
265     void tell_verbose_status(int idx)
266     {
267     char s[256], s1[121], s2[81];
268     char *vers_t, *uni_t;
269     int i;
270     time_t now2 = now - online_since, hr, min;
271     #ifdef HAVE_GETRUSAGE
272     struct rusage ru;
273     #else
274     # ifdef HAVE_CLOCK
275     clock_t cl;
276     # endif
277     #endif
278     #ifdef HAVE_UNAME
279     struct utsname un;
280    
281     if (!uname(&un) < 0) {
282     #endif
283     vers_t = " ";
284     uni_t = "*unknown*";
285     #ifdef HAVE_UNAME
286     } else {
287     vers_t = un.release;
288     uni_t = un.sysname;
289     }
290     #endif
291    
292     i = count_users(userlist);
293     dprintf(idx, "I am %s, running %s: %d user%s (mem: %uk).\n",
294     botnetnick, ver, i, i == 1 ? "" : "s",
295     (int) (expected_memory() / 1024));
296    
297     s[0] = 0;
298     if (now2 > 86400) {
299     /* days */
300     sprintf(s, "%d day", (int) (now2 / 86400));
301     if ((int) (now2 / 86400) >= 2)
302     strcat(s, "s");
303     strcat(s, ", ");
304     now2 -= (((int) (now2 / 86400)) * 86400);
305     }
306     hr = (time_t) ((int) now2 / 3600);
307     now2 -= (hr * 3600);
308     min = (time_t) ((int) now2 / 60);
309     sprintf(&s[strlen(s)], "%02d:%02d", (int) hr, (int) min);
310     s1[0] = 0;
311     if (backgrd)
312     strcpy(s1, MISC_BACKGROUND);
313     else {
314     if (term_z)
315     strcpy(s1, MISC_TERMMODE);
316     else if (con_chan)
317     strcpy(s1, MISC_STATMODE);
318     else
319     strcpy(s1, MISC_LOGMODE);
320     }
321     #ifdef HAVE_GETRUSAGE
322     getrusage(RUSAGE_SELF, &ru);
323     hr = (int) ((ru.ru_utime.tv_sec + ru.ru_stime.tv_sec) / 60);
324     min = (int) ((ru.ru_utime.tv_sec + ru.ru_stime.tv_sec) - (hr * 60));
325     sprintf(s2, "CPU: %02d:%02d", (int) hr, (int) min); /* Actally min/sec */
326     #else
327     # ifdef HAVE_CLOCK
328     cl = (clock() / CLOCKS_PER_SEC);
329     hr = (int) (cl / 60);
330     min = (int) (cl - (hr * 60));
331     sprintf(s2, "CPU: %02d:%02d", (int) hr, (int) min); /* Actually min/sec */
332     # else
333     sprintf(s2, "CPU: unknown");
334     # endif
335     #endif
336     dprintf(idx, "%s %s (%s) - %s - %s: %4.1f%%\n", MISC_ONLINEFOR,
337     s, s1, s2, MISC_CACHEHIT,
338     100.0 * ((float) cache_hit) / ((float) (cache_hit + cache_miss)));
339    
340     if (admin[0])
341     dprintf(idx, "Admin: %s\n", admin);
342    
343     dprintf(idx, "Config file: %s\n", configfile);
344     dprintf(idx, "OS: %s %s\n", uni_t, vers_t);
345    
346     /* info library */
347     dprintf(idx, "%s %s\n", MISC_TCLLIBRARY,
348     ((interp) && (Tcl_Eval(interp, "info library") == TCL_OK)) ?
349     tcl_resultstring() : "*unknown*");
350    
351     /* info tclversion/patchlevel */
352     dprintf(idx, "%s %s (%s %s)\n", MISC_TCLVERSION,
353     ((interp) && (Tcl_Eval(interp, "info patchlevel") == TCL_OK)) ?
354     tcl_resultstring() : (Tcl_Eval(interp, "info tclversion") == TCL_OK) ?
355     tcl_resultstring() : "*unknown*", MISC_TCLHVERSION,
356     TCL_PATCH_LEVEL ? TCL_PATCH_LEVEL : "*unknown*");
357    
358     if (tcl_threaded())
359     dprintf(idx, "Tcl is threaded.\n");
360     dprintf(idx, "Socket table: %d/%d\n", threaddata()->MAXSOCKS, max_socks);
361     }
362    
363     /* Show all internal state variables
364     */
365     void tell_settings(int idx)
366     {
367     char s[1024];
368     int i;
369     struct flag_record fr = { FR_GLOBAL, 0, 0, 0, 0, 0 };
370    
371     dprintf(idx, "Botnet nickname: %s\n", botnetnick);
372     if (firewall[0])
373     dprintf(idx, "Firewall: %s:%d\n", firewall, firewallport);
374     dprintf(idx, "Userfile: %s\n", userfile);
375     dprintf(idx, "Motd: %s\n", motdfile);
376     dprintf(idx, "Directories:\n");
377     #ifndef STATIC
378     dprintf(idx, " Help : %s\n", helpdir);
379     dprintf(idx, " Temp : %s\n", tempdir);
380     dprintf(idx, " Modules: %s\n", moddir);
381     #else
382     dprintf(idx, " Help: %s\n", helpdir);
383     dprintf(idx, " Temp: %s\n", tempdir);
384     #endif
385     fr.global = default_flags;
386    
387     build_flags(s, &fr, NULL);
388     dprintf(idx, "%s [%s], %s: %s\n", MISC_NEWUSERFLAGS, s,
389     MISC_NOTIFY, notify_new);
390     if (owner[0])
391     dprintf(idx, "%s: %s\n", MISC_PERMOWNER, owner);
392     for (i = 0; i < max_logs; i++)
393     if (logs[i].filename != NULL) {
394     dprintf(idx, "Logfile #%d: %s on %s (%s: %s)\n", i + 1,
395     logs[i].filename, logs[i].chname,
396     masktype(logs[i].mask), maskname(logs[i].mask));
397     }
398     dprintf(idx, "Ignores last %d minute%s.\n", ignore_time,
399     (ignore_time != 1) ? "s" : "");
400     }
401    
402     void reaffirm_owners()
403     {
404     char *p, *q, s[121];
405     struct userrec *u;
406    
407     /* Please stop breaking this function. */
408     if (owner[0]) {
409     q = owner;
410     p = strchr(q, ',');
411     while (p) {
412     strncpyz(s, q, (p - q) + 1);
413     rmspace(s);
414     u = get_user_by_handle(userlist, s);
415     if (u)
416     u->flags = sanity_check(u->flags | USER_OWNER);
417     q = p + 1;
418     p = strchr(q, ',');
419     }
420     strcpy(s, q);
421     rmspace(s);
422     u = get_user_by_handle(userlist, s);
423     if (u)
424     u->flags = sanity_check(u->flags | USER_OWNER);
425     }
426     }
427    
428     void chanprog()
429     {
430     int i;
431     FILE *f;
432     char s[161], rands[8];
433    
434     admin[0] = 0;
435     helpdir[0] = 0;
436     tempdir[0] = 0;
437     conmask = 0;
438    
439     for (i = 0; i < max_logs; i++)
440     logs[i].flags |= LF_EXPIRING;
441    
442     /* Turn off read-only variables (make them write-able) for rehash */
443     protect_readonly = 0;
444    
445     /* Now read it */
446     if (!readtclprog(configfile))
447     fatal(MISC_NOCONFIGFILE, 0);
448    
449     for (i = 0; i < max_logs; i++) {
450     if (logs[i].flags & LF_EXPIRING) {
451     if (logs[i].filename != NULL) {
452     nfree(logs[i].filename);
453     logs[i].filename = NULL;
454     }
455     if (logs[i].chname != NULL) {
456     nfree(logs[i].chname);
457     logs[i].chname = NULL;
458     }
459     if (logs[i].f != NULL) {
460     fclose(logs[i].f);
461     logs[i].f = NULL;
462     }
463     logs[i].mask = 0;
464     logs[i].flags = 0;
465     }
466     }
467    
468     /* We should be safe now */
469     call_hook(HOOK_REHASH);
470     protect_readonly = 1;
471    
472     if (!botnetnick[0])
473     strncpyz(botnetnick, origbotname, HANDLEN + 1);
474    
475     if (!botnetnick[0])
476     fatal("I don't have a botnet nick!!\n", 0);
477    
478     if (!userfile[0])
479     fatal(MISC_NOUSERFILE2, 0);
480    
481     if (!readuserfile(userfile, &userlist)) {
482     if (!make_userfile) {
483     char tmp[178];
484    
485     egg_snprintf(tmp, sizeof tmp, MISC_NOUSERFILE, configfile);
486     fatal(tmp, 0);
487     }
488     printf("\n\n%s\n", MISC_NOUSERFILE2);
489     if (module_find("server", 0, 0))
490     printf(MISC_USERFCREATE1, origbotname);
491     printf("%s\n\n", MISC_USERFCREATE2);
492     } else if (make_userfile) {
493     make_userfile = 0;
494     printf("%s\n", MISC_USERFEXISTS);
495     }
496    
497     if (helpdir[0])
498     if (helpdir[strlen(helpdir) - 1] != '/')
499     strcat(helpdir, "/");
500    
501     if (tempdir[0])
502     if (tempdir[strlen(tempdir) - 1] != '/')
503     strcat(tempdir, "/");
504    
505     /* Test tempdir: it's vital. */
506    
507     /* Possible file race condition solved by using a random string
508     * and the process id in the filename.
509     * FIXME: This race is only partitially fixed. We could still be
510     * overwriting an existing file / following a malicious
511     * link.
512     */
513     make_rand_str(rands, 7); /* create random string */
514     sprintf(s, "%s.test-%u-%s", tempdir, getpid(), rands);
515     f = fopen(s, "w");
516     if (f == NULL)
517     fatal(MISC_CANTWRITETEMP, 0);
518     fclose(f);
519     unlink(s);
520     reaffirm_owners();
521     check_tcl_event("userfile-loaded");
522     }
523    
524     /* Reload the user file from disk
525     */
526     void reload()
527     {
528     if (!file_readable(userfile)) {
529     putlog(LOG_MISC, "*", MISC_CANTRELOADUSER);
530     return;
531     }
532    
533     noshare = 1;
534     clear_userlist(userlist);
535     noshare = 0;
536     userlist = NULL;
537     if (!readuserfile(userfile, &userlist))
538     fatal(MISC_MISSINGUSERF, 0);
539     reaffirm_owners();
540     check_tcl_event("userfile-loaded");
541     call_hook(HOOK_READ_USERFILE);
542     }
543    
544     void rehash()
545     {
546     call_hook(HOOK_PRE_REHASH);
547     noshare = 1;
548     clear_userlist(userlist);
549     noshare = 0;
550     userlist = NULL;
551     chanprog();
552     }
553    
554     /*
555     * Brief venture into timers
556     */
557    
558     /* Add a timer
559     */
560     unsigned long add_timer(tcl_timer_t ** stack, int elapse, char *cmd,
561     unsigned long prev_id)
562     {
563     tcl_timer_t *old = (*stack);
564    
565     *stack = nmalloc(sizeof **stack);
566     (*stack)->next = old;
567     (*stack)->mins = elapse;
568     (*stack)->cmd = nmalloc(strlen(cmd) + 1);
569     strcpy((*stack)->cmd, cmd);
570     /* If it's just being added back and already had an id,
571     * don't create a new one.
572     */
573     if (prev_id > 0)
574     (*stack)->id = prev_id;
575     else
576     (*stack)->id = timer_id++;
577     return (*stack)->id;
578     }
579    
580     /* Remove a timer, by id
581     */
582     int remove_timer(tcl_timer_t ** stack, unsigned long id)
583     {
584     tcl_timer_t *old;
585     int ok = 0;
586    
587     while (*stack) {
588     if ((*stack)->id == id) {
589     ok++;
590     old = *stack;
591     *stack = ((*stack)->next);
592     nfree(old->cmd);
593     nfree(old);
594     } else
595     stack = &((*stack)->next);
596     }
597     return ok;
598     }
599    
600     /* Check timers, execute the ones that have expired.
601     */
602     void do_check_timers(tcl_timer_t ** stack)
603     {
604     tcl_timer_t *mark = *stack, *old = NULL;
605     char x[16];
606    
607     /* New timers could be added by a Tcl script inside a current timer
608     * so i'll just clear out the timer list completely, and add any
609     * unexpired timers back on.
610     */
611     *stack = NULL;
612     while (mark) {
613     if (mark->mins > 0)
614     mark->mins--;
615     old = mark;
616     mark = mark->next;
617     if (!old->mins) {
618     egg_snprintf(x, sizeof x, "timer%lu", old->id);
619     do_tcl(x, old->cmd);
620     nfree(old->cmd);
621     nfree(old);
622     } else {
623     old->next = *stack;
624     *stack = old;
625     }
626     }
627     }
628    
629     /* Wipe all timers.
630     */
631     void wipe_timers(Tcl_Interp *irp, tcl_timer_t **stack)
632     {
633     tcl_timer_t *mark = *stack, *old;
634    
635     while (mark) {
636     old = mark;
637     mark = mark->next;
638     nfree(old->cmd);
639     nfree(old);
640     }
641     *stack = NULL;
642     }
643    
644     /* Return list of timers
645     */
646     void list_timers(Tcl_Interp *irp, tcl_timer_t *stack)
647     {
648     char mins[10], id[16], *x;
649     EGG_CONST char *argv[3];
650     tcl_timer_t *mark;
651    
652     for (mark = stack; mark; mark = mark->next) {
653     egg_snprintf(mins, sizeof mins, "%u", mark->mins);
654     egg_snprintf(id, sizeof id, "timer%lu", mark->id);
655     argv[0] = mins;
656     argv[1] = mark->cmd;
657     argv[2] = id;
658     x = Tcl_Merge(3, argv);
659     Tcl_AppendElement(irp, x);
660     Tcl_Free((char *) x);
661     }
662     }
663    
664     /* Oddly enough, written by Sup (former(?) Eggdrop coder)
665     */
666     int isowner(char *name)
667     {
668     register char *ptr = NULL, *s = NULL, *n = NULL;
669    
670     if (!name)
671     return 0;
672    
673     ptr = owner - 1;
674    
675     do {
676     ptr++;
677     if (*ptr && !egg_isspace(*ptr) && *ptr != ',') {
678     if (!s)
679     s = ptr;
680     } else if (s) {
681     for (n = name; *n && *s && s < ptr &&
682     tolower((unsigned) *n) == tolower((unsigned) *s); n++, s++);
683    
684     if (s == ptr && !*n)
685     return 1;
686    
687     s = NULL;
688     }
689     } while (*ptr);
690    
691     return 0;
692     }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23