/[cvs]/eggdrop1.9/src/logfile.c
ViewVC logotype

Contents of /eggdrop1.9/src/logfile.c

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


Revision 1.51 - (show annotations) (download) (as text)
Tue Nov 14 14:51:24 2006 UTC (12 years, 10 months ago) by sven
Branch: MAIN
CVS Tags: HEAD
Changes since 1.50: +2 -3 lines
File MIME type: text/x-chdr

Misc:
 * Bind table flag BIND_BREAKABLE now includes BIND_STACKABLE, doesn't make
   sense otherwise.
 * If the line buffer contains more than one line of text do a check if the
   index is still valid after every callback (the sockbuf might have been
   deleted).
 * Added a "Doxygen" file in the root dir. It will generate html output in
   doc/developer/html. (The dir will be created by doxygen.)

Partyline stuff:
 * Partychan join and quit functions have an extra parameter indicating if
   the event is triggered because of someone joining/quitting or botnet
   restructuring.
 * Renamed partychan_msg() to chan_msg and made it static. It can now either
   msg the whole channel or just everyone on the local bot on the channel.
 * New functions partychan_msg() (works like before) and localchan_msg() to
   send it to every local user of the chan.
 * Added stuff to the partymember struct: A pointer to the bot the user is
   on, a malloc'd string containing the full unique name in the form
   "id:nick@bot", a pointer into this string to the full name "nick@bot"
   and a pointer to the common name of the user, "nick" for local users and
   "nick@bot" for users on other bots.
 * The id of a partymember is no longer unique, only unique to the bot the
   user is on. The nick was never unique. TODO: Change the script modules
   to take care of that!
 * A partymember is now part of two double linked lists: A list of all
   partymembers and a list of all partymembers on the bot.
 * Removed the partymember_lookup_* functions. partymember_lookup() takes
   cares of all the stuff.
 * Added functions to count all users on a bot and delete all users on a bot.

Ircpartyline:
 * IRC requires nicks to be unique for everyone and useing the usual "@" in
   the "nick@bot" form doesn't work at all on IRC. Therefor the nick format
   is now: "nick*bot:id" for remote users and "nick:id" for local users.

Script stuff:
 * Added a new script parameter: 'B': A bot.
 * TODO: Change the script modules to use it!

Botnet stuff:
 * Added botnet.[ch]. Fully documented!
 * Changed the oldbotnet module to use the new botnet API. Only very basic
   stuff works atm: Bot links, unlinks, partymember joins, quits and chatter.
   But at least it doesn't matter any more if the bot is a leaf or a hub.

1 /* logfile.c: logging
2 *
3 * Copyright (C) 2001, 2002, 2003, 2004 Eggheads Development Team
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 *
19 */
20
21 #ifndef lint
22 static const char rcsid[] = "$Id: logfile.c,v 1.50 2004-10-17 05:14:07 stdarg Exp $";
23 #endif
24
25 #include <eggdrop/eggdrop.h>
26 #include <unistd.h>
27 #include "core_config.h"
28 #include "terminal.h" /* TERMINAL_NICK */
29 #include "logfile.h"
30
31
32 static logfile_t *logfiles = NULL;
33 static int nlogfiles = 0;
34
35 extern int backgrd, use_stderr, terminal_mode;
36 int terminal_enabled = 0;
37 extern time_t now;
38
39 static int logfile_minutely();
40 static int logfile_5minutely();
41 static int logfile_cycle();
42 static void check_logsizes();
43 static void flushlog(logfile_t *log, char *timestamp);
44
45 /* Bind for the log table. The core does logging to files and the partyline, but
46 * modules may implement sql logging or whatever. */
47 static int on_putlog(int flags, const char *chan, const char *text, int len);
48
49 static script_command_t log_script_cmds[] = {
50 {"", "logfile", logfile_add, NULL, 3, "sss", "modes chan filename", SCRIPT_STRING, 0}, /* DDD */
51 {0}
52 };
53
54 void logfile_init(void)
55 {
56 void *root, *node;
57 char *filename, *chname, *mask;
58 int i;
59
60 script_create_commands(log_script_cmds);
61 bind_add_simple("log", NULL, NULL, on_putlog);
62 bind_add_simple("event", NULL, "minutely", logfile_minutely);
63 bind_add_simple("event", NULL, "5minutely", logfile_5minutely);
64
65 root = config_get_root("eggdrop");
66 node = config_lookup_section(root, "eggdrop.logging.logfiles", 0, NULL);
67 for (i = 0; ; i++) {
68 config_get_str(&filename, node, "logfile", i, "filename", 0, NULL);
69 config_get_str(&chname, node, "logfile", i, "channel", 0, NULL);
70 config_get_str(&mask, node, "logfile", i, "mask", 0, NULL);
71 if (!filename || !chname || !mask) break;
72 logfile_add(mask, chname, filename);
73 }
74 }
75
76 void logfile_shutdown(void)
77 {
78 void *root, *node;
79 int i;
80
81 flushlogs();
82
83 root = config_get_root("eggdrop");
84 node = config_lookup_section(root, "eggdrop.logging.logfiles", 0, NULL);
85 for (i = 0; i < nlogfiles; i++) {
86 config_set_str(logfiles[i].filename, node, "logfile", i, "filename", 0, NULL);
87 config_set_str(logfiles[i].chname, node, "logfile", i, "channel", 0, NULL);
88 config_set_str("*", node, "logfile", i, "mask", 0, NULL);
89 }
90
91 bind_rem_simple("log", NULL, NULL, on_putlog);
92 bind_rem_simple("event", NULL, "minutely", logfile_minutely);
93 bind_rem_simple("event", NULL, "5minutely", logfile_5minutely);
94 script_delete_commands(log_script_cmds);
95 }
96
97 static int logfile_minutely()
98 {
99 struct tm *nowtm;
100 int miltime;
101
102 if (core_config.logging.quick) {
103 flushlogs();
104 check_logsizes();
105 }
106
107 nowtm = localtime(&now);
108 miltime = 100 * nowtm->tm_hour + nowtm->tm_min;
109
110 if (miltime == core_config.logging.switch_at) logfile_cycle();
111
112 return(0);
113 }
114
115 static int logfile_5minutely()
116 {
117 if (!core_config.logging.quick) {
118 flushlogs();
119 check_logsizes();
120 }
121 return(0);
122 }
123
124 static int logfile_cycle()
125 {
126 logfile_t *log;
127 int i;
128 char suffix[32];
129 char *newfname;
130
131 putlog(LOG_MISC, "*", _("Cycling logfiles..."));
132 flushlogs();
133
134 /* Determine suffix for cycled logfiles. */
135 if (core_config.logging.keep_all) {
136 strftime(suffix, 32, core_config.logging.suffix, localtime(&now));
137 }
138
139 for (i = nlogfiles - 1; i >= 0; i--) {
140 log = &logfiles[i];
141
142 fclose(log->fp);
143
144 if (core_config.logging.keep_all) newfname = egg_mprintf("%s%s", log->filename, suffix);
145 else newfname = egg_mprintf("%s.yesterday", log->filename);
146
147 unlink(newfname);
148 movefile(log->filename, newfname);
149 free(newfname);
150
151 log->fp = fopen(log->filename, "a");
152 if (!log->fp) logfile_del(log->filename);
153 }
154
155 return(0);
156 }
157
158 char *logfile_add(char *modes, char *chan, char *fname)
159 {
160 FILE *fp;
161 logfile_t *log;
162
163 /* Get rid of any duplicates. */
164 logfile_del(fname);
165
166 /* Test the filename. */
167 fp = fopen(fname, "a");
168 if (!fp) return("");
169
170 logfiles = realloc(logfiles, (nlogfiles + 1) * sizeof(*logfiles));
171
172 log = &logfiles[nlogfiles++];
173 memset(log, 0, sizeof(*log));
174 log->filename = strdup(fname);
175 log->chname = strdup(chan);
176 log->last_msg = strdup("");
177 log->mask = LOG_ALL;
178 log->fp = fp;
179
180 return (log->filename);
181 }
182
183 int logfile_del(char *filename)
184 {
185 logfile_t *log;
186 int i;
187
188 log = NULL;
189 for (i = 0; i < nlogfiles; i++) {
190 log = &logfiles[i];
191 if (!strcmp(log->filename, filename)) break;
192 log = NULL;
193 }
194
195 if (log == NULL) return(-1);
196
197 if (log->fp) {
198 flushlog(log, timer_get_timestamp());
199 fclose(log->fp);
200 }
201
202 if (log->last_msg) free(log->last_msg);
203 if (log->filename) free(log->filename);
204
205 if (nlogfiles == 1) {
206 free(logfiles);
207 logfiles = NULL;
208 } else {
209 memmove(logfiles + i, logfiles + i + 1, (nlogfiles - i - 1) * sizeof(logfile_t));
210 logfiles = realloc(logfiles, (nlogfiles - 1) * sizeof(logfile_t));
211 }
212
213 nlogfiles--;
214
215 return(0);
216 }
217
218 static int on_putlog(int flags, const char *chan, const char *text, int len)
219 {
220 char *ts;
221 int i;
222
223 ts = timer_get_timestamp();
224 for (i = nlogfiles - 1; i >= 0; i--) {
225 logfile_t *log = &logfiles[i];
226
227 /* If this log is disabled, skip it */
228 if (log->state != LOG_STATE_ENABLED)
229 continue;
230
231 /* If this log doesn't match, skip it. */
232 if (!(log->mask & flags)) {
233 continue;
234 }
235
236 if (chan[0] != '*' && log->chname[0] != '*' && irccmp(chan, log->chname)) continue;
237
238 /* If it's a repeat message, don't write it again. */
239 if (log->last_msg && !strcasecmp(text, log->last_msg)) {
240 log->repeats++;
241 continue;
242 }
243
244
245 /* If there was a repeated message, write the count. */
246 if (log->repeats) {
247 fprintf(log->fp, "%s", ts);
248 fprintf(log->fp, _("Last message repeated %d time(s).\n"), log->repeats);
249 log->repeats = 0;
250 }
251
252 /* Save this msg to check for repeats next time. */
253 str_redup(&log->last_msg, text);
254
255 if (log->fp == NULL) {
256 if (log->fname == NULL) {
257 char buf[1024];
258 time_t now;
259
260 now = time(NULL);
261 strftime(buf, sizeof(buf), log->filename, localtime(&now));
262 log->fname = strdup(buf);
263 }
264
265 log->fp = fopen(log->fname, "a+");
266 if (log->fp == NULL) {
267 log->state = LOG_STATE_DISABLED;
268 putlog(LOG_MISC, "*", _("Failed to open log file: %s"), log->fname);
269 putlog(LOG_MISC, "*", _(" Check if directory (if any) exists and is read- and writeable."));
270 continue;
271 }
272 }
273
274 /* Now output to the file. */
275 fprintf(log->fp, "%s%s\n", ts, text);
276 }
277
278 if (!backgrd || use_stderr) {
279
280 if (terminal_mode) {
281 /* check if HQ is on console. If yes we disable
282 * output to stdout since otherwise everything would
283 * be printed out twice. */
284 if (!terminal_enabled) {
285 terminal_enabled = (partymember_lookup(TERMINAL_NICK, NULL, -1) != NULL);
286 }
287 if (terminal_enabled)
288 return 0;
289
290 }
291
292 fprintf (stdout, "%s %s%s\n", chan, ts, text);
293 }
294
295 return(0);
296 }
297
298 static void check_logsizes()
299 {
300 int size, i;
301 char *newfname;
302
303 if (core_config.logging.keep_all || core_config.logging.max_size <= 0) return;
304
305 for (i = 0; i < nlogfiles; i++) {
306 logfile_t *log = &logfiles[i];
307
308 size = ftell(log->fp) / 1024; /* Size in kilobytes. */
309 if (size < core_config.logging.max_size) continue;
310
311 /* It's too big. */
312 putlog(LOG_MISC, "*", _("Cycling logfile %s: over max-logsize (%d kilobytes)."), log->filename, size);
313 fclose(log->fp);
314
315 newfname = egg_mprintf("%s.yesterday", log->filename);
316 unlink(newfname);
317 movefile(log->filename, newfname);
318 free(newfname);
319 }
320 }
321
322 static void flushlog(logfile_t *log, char *timestamp)
323 {
324 if (log->repeats) {
325 fprintf(log->fp, "%s", timestamp);
326 fprintf(log->fp, _("Last message repeated %d time(s).\n"), log->repeats);
327 log->repeats = 0;
328 str_redup(&log->last_msg, "");
329 }
330 fflush(log->fp);
331 }
332
333 /* Flush the logfiles to disk
334 */
335 void flushlogs()
336 {
337 char *ts;
338 int i;
339
340 ts = timer_get_timestamp();
341 for (i = 0; i < nlogfiles; i++) {
342 flushlog(&logfiles[i], ts);
343 }
344 }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23