00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #ifndef lint
00022 static const char rcsid[] = "$Id: logfile.c,v 1.51 2006-11-14 14:51:24 sven Exp $";
00023 #endif
00024
00025 #include <eggdrop/eggdrop.h>
00026 #include <unistd.h>
00027 #include "core_config.h"
00028 #include "terminal.h"
00029 #include "logfile.h"
00030
00031
00032 static logfile_t *logfiles = NULL;
00033 static int nlogfiles = 0;
00034
00035 extern int backgrd, use_stderr, terminal_mode;
00036 int terminal_enabled = 0;
00037 extern time_t now;
00038
00039 static int logfile_minutely();
00040 static int logfile_5minutely();
00041 static int logfile_cycle();
00042 static void check_logsizes();
00043 static void flushlog(logfile_t *log, char *timestamp);
00044
00045
00046
00047 static int on_putlog(int flags, const char *chan, const char *text, int len);
00048
00049 static script_command_t log_script_cmds[] = {
00050 {"", "logfile", logfile_add, NULL, 3, "sss", "modes chan filename", SCRIPT_STRING, 0},
00051 {0}
00052 };
00053
00054 void logfile_init(void)
00055 {
00056 void *root, *node;
00057 char *filename, *chname, *mask;
00058 int i;
00059
00060 script_create_commands(log_script_cmds);
00061 bind_add_simple("log", NULL, NULL, on_putlog);
00062 bind_add_simple("event", NULL, "minutely", logfile_minutely);
00063 bind_add_simple("event", NULL, "5minutely", logfile_5minutely);
00064
00065 root = config_get_root("eggdrop");
00066 node = config_lookup_section(root, "eggdrop.logging.logfiles", 0, NULL);
00067 for (i = 0; ; i++) {
00068 config_get_str(&filename, node, "logfile", i, "filename", 0, NULL);
00069 config_get_str(&chname, node, "logfile", i, "channel", 0, NULL);
00070 config_get_str(&mask, node, "logfile", i, "mask", 0, NULL);
00071 if (!filename || !chname || !mask) break;
00072 logfile_add(mask, chname, filename);
00073 }
00074 }
00075
00076 void logfile_shutdown(void)
00077 {
00078 void *root, *node;
00079 int i;
00080
00081 flushlogs();
00082
00083 root = config_get_root("eggdrop");
00084 node = config_lookup_section(root, "eggdrop.logging.logfiles", 0, NULL);
00085 for (i = 0; i < nlogfiles; i++) {
00086 config_set_str(logfiles[i].filename, node, "logfile", i, "filename", 0, NULL);
00087 config_set_str(logfiles[i].chname, node, "logfile", i, "channel", 0, NULL);
00088 config_set_str("*", node, "logfile", i, "mask", 0, NULL);
00089 }
00090
00091 bind_rem_simple("log", NULL, NULL, on_putlog);
00092 bind_rem_simple("event", NULL, "minutely", logfile_minutely);
00093 bind_rem_simple("event", NULL, "5minutely", logfile_5minutely);
00094 script_delete_commands(log_script_cmds);
00095 }
00096
00097 static int logfile_minutely()
00098 {
00099 struct tm *nowtm;
00100 int miltime;
00101
00102 if (core_config.logging.quick) {
00103 flushlogs();
00104 check_logsizes();
00105 }
00106
00107 nowtm = localtime(&now);
00108 miltime = 100 * nowtm->tm_hour + nowtm->tm_min;
00109
00110 if (miltime == core_config.logging.switch_at) logfile_cycle();
00111
00112 return(0);
00113 }
00114
00115 static int logfile_5minutely()
00116 {
00117 if (!core_config.logging.quick) {
00118 flushlogs();
00119 check_logsizes();
00120 }
00121 return(0);
00122 }
00123
00124 static int logfile_cycle()
00125 {
00126 logfile_t *log;
00127 int i;
00128 char suffix[32];
00129 char *newfname;
00130
00131 putlog(LOG_MISC, "*", _("Cycling logfiles..."));
00132 flushlogs();
00133
00134
00135 if (core_config.logging.keep_all) {
00136 strftime(suffix, 32, core_config.logging.suffix, localtime(&now));
00137 }
00138
00139 for (i = nlogfiles - 1; i >= 0; i--) {
00140 log = &logfiles[i];
00141
00142 fclose(log->fp);
00143
00144 if (core_config.logging.keep_all) newfname = egg_mprintf("%s%s", log->filename, suffix);
00145 else newfname = egg_mprintf("%s.yesterday", log->filename);
00146
00147 unlink(newfname);
00148 movefile(log->filename, newfname);
00149 free(newfname);
00150
00151 log->fp = fopen(log->filename, "a");
00152 if (!log->fp) logfile_del(log->filename);
00153 }
00154
00155 return(0);
00156 }
00157
00158 char *logfile_add(char *modes, char *chan, char *fname)
00159 {
00160 FILE *fp;
00161 logfile_t *log;
00162
00163
00164 logfile_del(fname);
00165
00166
00167 fp = fopen(fname, "a");
00168 if (!fp) return("");
00169
00170 logfiles = realloc(logfiles, (nlogfiles + 1) * sizeof(*logfiles));
00171
00172 log = &logfiles[nlogfiles++];
00173 memset(log, 0, sizeof(*log));
00174 log->filename = strdup(fname);
00175 log->chname = strdup(chan);
00176 log->last_msg = strdup("");
00177 log->mask = LOG_ALL;
00178 log->fp = fp;
00179
00180 return (log->filename);
00181 }
00182
00183 int logfile_del(char *filename)
00184 {
00185 logfile_t *log;
00186 int i;
00187
00188 log = NULL;
00189 for (i = 0; i < nlogfiles; i++) {
00190 log = &logfiles[i];
00191 if (!strcmp(log->filename, filename)) break;
00192 log = NULL;
00193 }
00194
00195 if (log == NULL) return(-1);
00196
00197 if (log->fp) {
00198 flushlog(log, timer_get_timestamp());
00199 fclose(log->fp);
00200 }
00201
00202 if (log->last_msg) free(log->last_msg);
00203 if (log->filename) free(log->filename);
00204
00205 if (nlogfiles == 1) {
00206 free(logfiles);
00207 logfiles = NULL;
00208 } else {
00209 memmove(logfiles + i, logfiles + i + 1, (nlogfiles - i - 1) * sizeof(logfile_t));
00210 logfiles = realloc(logfiles, (nlogfiles - 1) * sizeof(logfile_t));
00211 }
00212
00213 nlogfiles--;
00214
00215 return(0);
00216 }
00217
00218 static int on_putlog(int flags, const char *chan, const char *text, int len)
00219 {
00220 char *ts;
00221 int i;
00222
00223 ts = timer_get_timestamp();
00224 for (i = nlogfiles - 1; i >= 0; i--) {
00225 logfile_t *log = &logfiles[i];
00226
00227
00228 if (log->state != LOG_STATE_ENABLED)
00229 continue;
00230
00231
00232 if (!(log->mask & flags)) {
00233 continue;
00234 }
00235
00236 if (chan[0] != '*' && log->chname[0] != '*' && irccmp(chan, log->chname)) continue;
00237
00238
00239 if (log->last_msg && !strcasecmp(text, log->last_msg)) {
00240 log->repeats++;
00241 continue;
00242 }
00243
00244
00245
00246 if (log->repeats) {
00247 fprintf(log->fp, "%s", ts);
00248 fprintf(log->fp, _("Last message repeated %d time(s).\n"), log->repeats);
00249 log->repeats = 0;
00250 }
00251
00252
00253 str_redup(&log->last_msg, text);
00254
00255 if (log->fp == NULL) {
00256 if (log->fname == NULL) {
00257 char buf[1024];
00258 time_t now;
00259
00260 now = time(NULL);
00261 strftime(buf, sizeof(buf), log->filename, localtime(&now));
00262 log->fname = strdup(buf);
00263 }
00264
00265 log->fp = fopen(log->fname, "a+");
00266 if (log->fp == NULL) {
00267 log->state = LOG_STATE_DISABLED;
00268 putlog(LOG_MISC, "*", _("Failed to open log file: %s"), log->fname);
00269 putlog(LOG_MISC, "*", _(" Check if directory (if any) exists and is read- and writeable."));
00270 continue;
00271 }
00272 }
00273
00274
00275 fprintf(log->fp, "%s%s\n", ts, text);
00276 }
00277
00278 if (!backgrd || use_stderr) {
00279
00280 if (terminal_mode) {
00281
00282
00283
00284 if (!terminal_enabled) {
00285 terminal_enabled = (partymember_lookup(TERMINAL_NICK, NULL, -1) != NULL);
00286 }
00287 if (terminal_enabled)
00288 return 0;
00289
00290 }
00291
00292 fprintf (stdout, "%s %s%s\n", chan, ts, text);
00293 }
00294
00295 return(0);
00296 }
00297
00298 static void check_logsizes()
00299 {
00300 int size, i;
00301 char *newfname;
00302
00303 if (core_config.logging.keep_all || core_config.logging.max_size <= 0) return;
00304
00305 for (i = 0; i < nlogfiles; i++) {
00306 logfile_t *log = &logfiles[i];
00307
00308 size = ftell(log->fp) / 1024;
00309 if (size < core_config.logging.max_size) continue;
00310
00311
00312 putlog(LOG_MISC, "*", _("Cycling logfile %s: over max-logsize (%d kilobytes)."), log->filename, size);
00313 fclose(log->fp);
00314
00315 newfname = egg_mprintf("%s.yesterday", log->filename);
00316 unlink(newfname);
00317 movefile(log->filename, newfname);
00318 free(newfname);
00319 }
00320 }
00321
00322 static void flushlog(logfile_t *log, char *timestamp)
00323 {
00324 if (log->repeats) {
00325 fprintf(log->fp, "%s", timestamp);
00326 fprintf(log->fp, _("Last message repeated %d time(s).\n"), log->repeats);
00327 log->repeats = 0;
00328 str_redup(&log->last_msg, "");
00329 }
00330 fflush(log->fp);
00331 }
00332
00333
00334
00335 void flushlogs()
00336 {
00337 char *ts;
00338 int i;
00339
00340 ts = timer_get_timestamp();
00341 for (i = 0; i < nlogfiles; i++) {
00342 flushlog(&logfiles[i], ts);
00343 }
00344 }