Merge Irssi 0.8.16-rc1
[silc.git] / apps / irssi / src / fe-common / core / fe-log.c
1 /*
2  fe-log.c : irssi
3
4     Copyright (C) 1999-2000 Timo Sirainen
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License along
17     with this program; if not, write to the Free Software Foundation, Inc.,
18     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include "module.h"
22 #include "module-formats.h"
23 #include "signals.h"
24 #include "commands.h"
25 #include "chat-protocols.h"
26 #include "servers.h"
27 #include "levels.h"
28 #include "misc.h"
29 #include "log.h"
30 #include "special-vars.h"
31 #include "settings.h"
32 #include "lib-config/iconfig.h"
33
34 #include "fe-windows.h"
35 #include "window-items.h"
36 #include "formats.h"
37 #include "themes.h"
38 #include "printtext.h"
39 #include "fe-common-core.h"
40
41 /* close autologs after 5 minutes of inactivity */
42 #define AUTOLOG_INACTIVITY_CLOSE (60*5)
43
44 static int autolog_level;
45 static int autoremove_tag;
46 static const char *autolog_path;
47
48 static THEME_REC *log_theme;
49 static int skip_next_printtext;
50 static const char *log_theme_name;
51
52 static int log_dir_create_mode;
53
54 static char **autolog_ignore_targets;
55
56 static char *log_colorizer_strip(const char *str)
57 {
58         return strip_codes(str);
59 }
60
61 static void log_add_targets(LOG_REC *log, const char *targets, const char *tag)
62 {
63         char **tmp, **items;
64
65         g_return_if_fail(log != NULL);
66         g_return_if_fail(targets != NULL);
67
68         items = g_strsplit(targets, " ", -1);
69
70         for (tmp = items; *tmp != NULL; tmp++)
71                 log_item_add(log, LOG_ITEM_TARGET, *tmp, tag);
72
73         g_strfreev(items);
74 }
75
76 /* SYNTAX: LOG OPEN [-noopen] [-autoopen] [-window] [-<server tag>]
77                     [-targets <targets>] [-colors]
78                     <fname> [<levels>] */
79 static void cmd_log_open(const char *data)
80 {
81         SERVER_REC *server;
82         GHashTable *optlist;
83         char *targetarg, *fname, *levels, *servertag;
84         void *free_arg;
85         char window[MAX_INT_STRLEN];
86         LOG_REC *log;
87         int level;
88
89         if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST |
90                             PARAM_FLAG_UNKNOWN_OPTIONS | PARAM_FLAG_OPTIONS,
91                             "log open", &optlist, &fname, &levels))
92                 return;
93         if (*fname == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
94
95         level = level2bits(levels, NULL);
96         log = log_create_rec(fname, level != 0 ? level : MSGLEVEL_ALL);
97
98         /* -<server tag> */
99         server = cmd_options_get_server("log open", optlist, NULL);
100         servertag = server == NULL ? NULL : server->tag;
101
102         if (g_hash_table_lookup(optlist, "window")) {
103                 /* log by window ref# */
104                 targetarg = g_hash_table_lookup(optlist, "targets");
105                 if (targetarg == NULL || !is_numeric(targetarg, '\0')) {
106                         ltoa(window, active_win->refnum);
107                         targetarg = window;
108                 }
109                 log_item_add(log, LOG_ITEM_WINDOW_REFNUM, targetarg,
110                              servertag);
111         } else {
112                 targetarg = g_hash_table_lookup(optlist, "targets");
113                 if (targetarg != NULL && *targetarg != '\0')
114                         log_add_targets(log, targetarg, servertag);
115                 else if (servertag != NULL)
116                         log_add_targets(log, "*", servertag);
117         }
118
119         if (g_hash_table_lookup(optlist, "autoopen"))
120                 log->autoopen = TRUE;
121
122         if (g_hash_table_lookup(optlist, "colors") == NULL)
123                 log->colorizer = log_colorizer_strip;
124
125         log_update(log);
126
127         if (log->handle == -1 && g_hash_table_lookup(optlist, "noopen") == NULL) {
128                 /* start logging */
129                 if (log_start_logging(log)) {
130                         printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,
131                                     TXT_LOG_OPENED, fname);
132                 } else {
133                         log_close(log);
134                 }
135         }
136
137         cmd_params_free(free_arg);
138 }
139
140 static LOG_REC *log_find_from_data(const char *data)
141 {
142         GSList *tmp;
143
144         if (!is_numeric(data, ' '))
145                 return log_find(data);
146
147         /* with index number */
148         tmp = g_slist_nth(logs, atoi(data)-1);
149         return tmp == NULL ? NULL : tmp->data;
150 }
151
152 /* SYNTAX: LOG CLOSE <id>|<file> */
153 static void cmd_log_close(const char *data)
154 {
155         LOG_REC *log;
156
157         log = log_find_from_data(data);
158         if (log == NULL)
159                 printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, TXT_LOG_NOT_OPEN, data);
160         else {
161                 log_close(log);
162                 printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_LOG_CLOSED, data);
163         }
164 }
165
166 /* SYNTAX: LOG START <id>|<file> */
167 static void cmd_log_start(const char *data)
168 {
169         LOG_REC *log;
170
171         log = log_find_from_data(data);
172         if (log != NULL) {
173                 log_start_logging(log);
174                 printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_LOG_OPENED, data);
175         }
176 }
177
178 /* SYNTAX: LOG STOP <id>|<file> */
179 static void cmd_log_stop(const char *data)
180 {
181         LOG_REC *log;
182
183         log = log_find_from_data(data);
184         if (log == NULL || log->handle == -1)
185                 printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, TXT_LOG_NOT_OPEN, data);
186         else {
187                 log_stop_logging(log);
188                 printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_LOG_CLOSED, data);
189         }
190 }
191
192 static char *log_items_get_list(LOG_REC *log)
193 {
194         GSList *tmp;
195         GString *str;
196         char *ret;
197         LOG_ITEM_REC *rec = NULL;
198
199         g_return_val_if_fail(log != NULL, NULL);
200         g_return_val_if_fail(log->items != NULL, NULL);
201
202         str = g_string_new(NULL);
203         for (tmp = log->items; tmp != NULL; tmp = tmp->next) {
204                 rec = tmp->data;
205
206                 g_string_append_printf(str, "%s, ", rec->name);
207         }
208         g_string_truncate(str, str->len-2);
209         if(rec->servertag != NULL)
210                 g_string_append_printf(str, " (%s)", rec->servertag);
211
212         ret = str->str;
213         g_string_free(str, FALSE);
214         return ret;
215 }
216
217 static void cmd_log_list(void)
218 {
219         GSList *tmp;
220         char *levelstr, *items;
221         int index;
222
223         printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_LOG_LIST_HEADER);
224         for (tmp = logs, index = 1; tmp != NULL; tmp = tmp->next, index++) {
225                 LOG_REC *rec = tmp->data;
226
227                 levelstr = bits2level(rec->level);
228                 items = rec->items == NULL ? NULL :
229                         log_items_get_list(rec);
230
231                 printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_LOG_LIST,
232                             index, rec->fname, items != NULL ? items : "",
233                             levelstr, rec->autoopen ? " -autoopen" : "",
234                             rec->handle != -1 ? " active" : "");
235
236                 g_free_not_null(items);
237                 g_free(levelstr);
238         }
239         printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_LOG_LIST_FOOTER);
240 }
241
242 static void cmd_log(const char *data, SERVER_REC *server, void *item)
243 {
244         if (*data == '\0')
245                 cmd_log_list();
246         else
247                 command_runsub("log", data, server, item);
248 }
249
250 static LOG_REC *logs_find_item(int type, const char *item,
251                                const char *servertag, LOG_ITEM_REC **ret_item)
252 {
253         LOG_ITEM_REC *logitem;
254         GSList *tmp;
255
256         for (tmp = logs; tmp != NULL; tmp = tmp->next) {
257                 LOG_REC *log = tmp->data;
258
259                 if (type == LOG_ITEM_TARGET && log->temp == 0) continue;
260                 logitem = log_item_find(log, type, item, servertag);
261                 if (logitem != NULL) {
262                         if (ret_item != NULL) *ret_item = logitem;
263                         return log;
264                 }
265         }
266
267         return NULL;
268 }
269
270 /* SYNTAX: WINDOW LOG on|off|toggle [<filename>] */
271 static void cmd_window_log(const char *data)
272 {
273         LOG_REC *log;
274         char *set, *fname, window[MAX_INT_STRLEN];
275         void *free_arg;
276         int open_log, close_log;
277
278         if (!cmd_get_params(data, &free_arg, 2, &set, &fname))
279                 return;
280
281         ltoa(window, active_win->refnum);
282         log = logs_find_item(LOG_ITEM_WINDOW_REFNUM, window, NULL, NULL);
283
284         open_log = close_log = FALSE;
285         if (g_ascii_strcasecmp(set, "ON") == 0)
286                 open_log = TRUE;
287         else if (g_ascii_strcasecmp(set, "OFF") == 0) {
288                 close_log = TRUE;
289         } else if (g_ascii_strcasecmp(set, "TOGGLE") == 0) {
290                 open_log = log == NULL;
291                 close_log = log != NULL;
292         } else {
293                 printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, TXT_NOT_TOGGLE);
294                 cmd_params_free(free_arg);
295                 return;
296         }
297
298         if (open_log && log == NULL) {
299                 /* irc.log.<windowname> or irc.log.Window<ref#> */
300                 fname = *fname != '\0' ? g_strdup(fname) :
301                         g_strdup_printf("~/irc.log.%s%s",
302                                         active_win->name != NULL ? active_win->name : "Window",
303                                         active_win->name != NULL ? "" : window);
304                 log = log_create_rec(fname, MSGLEVEL_ALL);
305                 log->colorizer = log_colorizer_strip;
306                 log_item_add(log, LOG_ITEM_WINDOW_REFNUM, window, NULL);
307                 log_update(log);
308                 g_free(fname);
309         }
310
311         if (open_log && log != NULL) {
312                 log_start_logging(log);
313                 printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_LOG_OPENED, log->fname);
314         } else if (close_log && log != NULL && log->handle != -1) {
315                 log_stop_logging(log);
316                 printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_LOG_CLOSED, log->fname);
317         }
318
319         cmd_params_free(free_arg);
320 }
321
322 /* Create log file entry to window, but don't start logging */
323 /* SYNTAX: WINDOW LOGFILE <file> */
324 static void cmd_window_logfile(const char *data)
325 {
326         LOG_REC *log;
327         char window[MAX_INT_STRLEN];
328
329         ltoa(window, active_win->refnum);
330         log = logs_find_item(LOG_ITEM_WINDOW_REFNUM, window, NULL, NULL);
331
332         if (log != NULL) {
333                 printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_WINDOWLOG_FILE_LOGGING);
334                 return;
335         }
336
337         log = log_create_rec(data, MSGLEVEL_ALL);
338         log->colorizer = log_colorizer_strip;
339         log_item_add(log, LOG_ITEM_WINDOW_REFNUM, window, NULL);
340         log_update(log);
341
342         printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_WINDOWLOG_FILE, data);
343 }
344
345 /* window's refnum changed - update the logs to log the new window refnum */
346 static void sig_window_refnum_changed(WINDOW_REC *window, gpointer old_refnum)
347 {
348         char winnum[MAX_INT_STRLEN];
349         LOG_REC *log;
350         LOG_ITEM_REC *item;
351
352         ltoa(winnum, GPOINTER_TO_INT(old_refnum));
353         log = logs_find_item(LOG_ITEM_WINDOW_REFNUM, winnum, NULL, &item);
354
355         if (log != NULL) {
356                 ltoa(winnum, window->refnum);
357
358                 g_free(item->name);
359                 item->name = g_strdup(winnum);
360         }
361 }
362
363 static void sig_server_disconnected(SERVER_REC *server)
364 {
365         LOG_ITEM_REC *logitem;
366         GSList *tmp, *next;
367
368         for (tmp = logs; tmp != NULL; tmp = next) {
369                 LOG_REC *log = tmp->data;
370                 next = tmp->next;
371
372                 if (!log->temp || log->items == NULL)
373                         continue;
374
375                 logitem = log->items->data;
376                 if (logitem->type == LOG_ITEM_TARGET &&
377                     logitem->servertag != NULL &&
378                     g_strcasecmp(logitem->servertag, server->tag) == 0 &&
379                     server_ischannel(server, logitem->name)) /* kludge again.. so we won't close dcc chats */
380                         log_close(log);
381         }
382 }
383
384 static void autologs_close_all(void)
385 {
386         GSList *tmp, *next;
387
388         for (tmp = logs; tmp != NULL; tmp = next) {
389                 LOG_REC *rec = tmp->data;
390
391                 next = tmp->next;
392                 if (rec->temp) log_close(rec);
393         }
394 }
395
396 /* '%' -> '%%', badness -> '_' */
397 static char *escape_target(const char *target)
398 {
399         char *str, *p;
400
401         p = str = g_malloc(strlen(target)*2+1);
402         while (*target != '\0') {
403                 if (strchr("/\\|*?\"<>:", *target))
404                         *p++ = '_';
405                 else {
406                         if (*target == '%')
407                                 *p++ = '%';
408                         *p++ = *target;
409                 }
410
411                 target++;
412         }
413         *p = '\0';
414
415         return str;
416 }
417
418 static void autolog_open(SERVER_REC *server, const char *server_tag,
419                          const char *target)
420 {
421         LOG_REC *log;
422         char *fname, *dir, *fixed_target, *params;
423
424         log = logs_find_item(LOG_ITEM_TARGET, target, server_tag, NULL);
425         if (log != NULL && !log->failed) {
426                 log_start_logging(log);
427                 return;
428         }
429
430         /* '/' -> '_' - don't even accidentally try to log to
431            #../../../file if you happen to join to such channel..
432            similar for some characters that are metacharacters
433            and/or illegal in Windows filenames.
434
435            '%' -> '%%' - so strftime() won't mess with them */
436         fixed_target = escape_target(target);
437         if (CHAT_PROTOCOL(server)->case_insensitive)
438                 ascii_strdown(fixed_target);
439
440         /* $0 = target, $1 = server tag */
441         params = g_strconcat(fixed_target, " ", server_tag, NULL);
442         g_free(fixed_target);
443
444         fname = parse_special_string(autolog_path, server, NULL,
445                                      params, NULL, 0);
446         g_free(params);
447
448         if (log_find(fname) == NULL) {
449                 log = log_create_rec(fname, autolog_level);
450                 if (!settings_get_bool("autolog_colors"))
451                         log->colorizer = log_colorizer_strip;
452                 log_item_add(log, LOG_ITEM_TARGET, target, server_tag);
453
454                 dir = g_path_get_dirname(log->real_fname);
455                 mkpath(dir, log_dir_create_mode);
456                 g_free(dir);
457
458                 log->temp = TRUE;
459                 log_update(log);
460                 log_start_logging(log);
461         }
462         g_free(fname);
463 }
464
465 static void autolog_open_check(TEXT_DEST_REC *dest)
466 {
467         const char *deftarget;
468         SERVER_REC *server = dest->server;
469         const char *server_tag = dest->server_tag;
470         const char *target = dest->target;
471         int level = dest->level;
472
473         /* FIXME: kind of a kludge, but we don't want to reopen logs when
474            we're parting the channel with /WINDOW CLOSE.. Maybe a small
475            timeout would be nice instead of immediately closing the log file
476            after "window item destroyed" */
477         if (level == MSGLEVEL_PARTS ||
478             (autolog_level & level) == 0 || target == NULL || *target == '\0')
479                 return;
480
481         deftarget = server ? server->nick : "unknown";
482
483         if (autolog_ignore_targets != NULL &&
484             strarray_find_dest(autolog_ignore_targets, dest))
485                 return;
486
487         if (target != NULL)
488                 autolog_open(server, server_tag, strcmp(target, "*") ? target : deftarget);
489 }
490
491 static void log_single_line(WINDOW_REC *window, const char *server_tag,
492                             const char *target, int level, const char *text)
493 {
494         char windownum[MAX_INT_STRLEN];
495         LOG_REC *log;
496
497         if (window != NULL) {
498                 /* save to log created with /WINDOW LOG */
499                 ltoa(windownum, window->refnum);
500                 log = logs_find_item(LOG_ITEM_WINDOW_REFNUM,
501                                      windownum, NULL, NULL);
502                 if (log != NULL)
503                         log_write_rec(log, text, level);
504         }
505
506         log_file_write(server_tag, target, level, text, FALSE);
507 }
508
509 static void log_line(TEXT_DEST_REC *dest, const char *text)
510 {
511         char **lines, **tmp;
512
513         if (dest->level == MSGLEVEL_NEVER)
514                 return;
515
516         /* let autolog open the log records */
517         autolog_open_check(dest);
518
519         if (logs == NULL)
520                 return;
521
522         /* text may contain one or more lines, log wants to eat them one
523            line at a time */
524         lines = g_strsplit(text, "\n", -1);
525         for (tmp = lines; *tmp != NULL; tmp++)
526                 log_single_line(dest->window, dest->server_tag,
527                                 dest->target, dest->level, *tmp);
528         g_strfreev(lines);
529 }
530
531 static void sig_printtext(TEXT_DEST_REC *dest, const char *text,
532                           const char *stripped)
533 {
534         if (skip_next_printtext) {
535                 skip_next_printtext = FALSE;
536                 return;
537         }
538
539         log_line(dest, text);
540 }
541
542 static void sig_print_format(THEME_REC *theme, const char *module,
543                              TEXT_DEST_REC *dest, void *formatnum, char **args)
544 {
545         char *str, *linestart, *tmp;
546
547         if (log_theme == NULL) {
548                 /* theme isn't loaded for some reason (/reload destroys it),
549                    reload it. */
550                 log_theme = theme_load(log_theme_name);
551                 if (log_theme == NULL) return;
552         }
553
554         if (theme == log_theme)
555                 return;
556
557         str = format_get_text_theme_charargs(log_theme, module, dest,
558                                              GPOINTER_TO_INT(formatnum), args);
559         skip_next_printtext = TRUE;
560
561         if (*str != '\0') {
562                 /* add the line start format */
563                 linestart = format_get_level_tag(log_theme, dest);
564                 tmp = str;
565                 str = format_add_linestart(tmp, linestart);
566                 g_free_not_null(linestart);
567                 g_free(tmp);
568
569                 /* strip colors from text, log it. */
570                 log_line(dest, str);
571         }
572         g_free(str);
573
574 }
575
576 static int sig_autoremove(void)
577 {
578         SERVER_REC *server;
579         LOG_ITEM_REC *logitem;
580         GSList *tmp, *next;
581         time_t removetime;
582
583         removetime = time(NULL)-AUTOLOG_INACTIVITY_CLOSE;
584         for (tmp = logs; tmp != NULL; tmp = next) {
585                 LOG_REC *log = tmp->data;
586
587                 next = tmp->next;
588
589                 if (!log->temp || log->last > removetime || log->items == NULL)
590                         continue;
591
592                 /* Close only logs with private messages */
593                 logitem = log->items->data;
594                 if (logitem->servertag == NULL)
595                         continue;
596
597                 server = server_find_tag(logitem->servertag);
598                 if (logitem->type == LOG_ITEM_TARGET &&
599                     server != NULL && !server_ischannel(server, logitem->name))
600                         log_close(log);
601         }
602         return 1;
603 }
604
605 static void sig_window_item_remove(WINDOW_REC *window, WI_ITEM_REC *item)
606 {
607         LOG_REC *log;
608
609         log = logs_find_item(LOG_ITEM_TARGET, item->visible_name,
610                              item->server == NULL ? NULL :
611                              item->server->tag, NULL);
612         if (log != NULL && log->temp)
613                 log_close(log);
614 }
615
616 static void sig_log_locked(LOG_REC *log)
617 {
618         printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
619                     TXT_LOG_LOCKED, log->fname);
620 }
621
622 static void sig_log_create_failed(LOG_REC *log)
623 {
624         printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,
625                     TXT_LOG_CREATE_FAILED,
626                     log->real_fname, g_strerror(errno));
627 }
628
629 static void sig_log_new(LOG_REC *log)
630 {
631         if (!settings_get_bool("awaylog_colors") &&
632             strcmp(log->fname, settings_get_str("awaylog_file")) == 0)
633                 log->colorizer = log_colorizer_strip;
634 }
635
636 static void sig_log_config_read(LOG_REC *log, CONFIG_NODE *node)
637 {
638         if (!config_node_get_bool(node, "colors", FALSE))
639                 log->colorizer = log_colorizer_strip;
640 }
641
642 static void sig_log_config_save(LOG_REC *log, CONFIG_NODE *node)
643 {
644         if (log->colorizer == NULL)
645                 iconfig_node_set_bool(node, "colors", TRUE);
646         else
647                 iconfig_node_set_str(node, "colors", NULL);
648 }
649
650 static void sig_awaylog_show(LOG_REC *log, gpointer pmsgs, gpointer pfilepos)
651 {
652         char *str;
653         int msgs, filepos;
654
655         msgs = GPOINTER_TO_INT(pmsgs);
656         filepos = GPOINTER_TO_INT(pfilepos);
657
658         if (msgs == 0)
659                 printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_LOG_NO_AWAY_MSGS, log->fname);
660         else {
661                 printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_LOG_AWAY_MSGS, log->fname, msgs);
662
663                 str = g_strdup_printf("\"%s\" %d", log->fname, filepos);
664                 signal_emit("command cat", 1, str);
665                 g_free(str);
666         }
667 }
668
669 static void sig_theme_destroyed(THEME_REC *theme)
670 {
671         if (theme == log_theme)
672                 log_theme = NULL;
673 }
674
675 static void read_settings(void)
676 {
677         int old_autolog = autolog_level;
678         int log_file_create_mode;
679
680         autolog_path = settings_get_str("autolog_path");
681         autolog_level = !settings_get_bool("autolog") ? 0 :
682                 settings_get_level("autolog_level");
683
684         if (old_autolog && !autolog_level)
685                 autologs_close_all();
686
687         /* write to log files with different theme? */
688         if (log_theme_name != NULL)
689                 signal_remove("print format", (SIGNAL_FUNC) sig_print_format);
690         log_theme_name = settings_get_str("log_theme");
691         if (*log_theme_name == '\0')
692                 log_theme_name = NULL;
693         else
694                 signal_add("print format", (SIGNAL_FUNC) sig_print_format);
695
696         log_theme = log_theme_name == NULL ? NULL :
697                 theme_load(log_theme_name);
698
699         log_file_create_mode = octal2dec(settings_get_int("log_create_mode"));
700         log_dir_create_mode = log_file_create_mode;
701         if (log_file_create_mode & 0400) log_dir_create_mode |= 0100;
702         if (log_file_create_mode & 0040) log_dir_create_mode |= 0010;
703         if (log_file_create_mode & 0004) log_dir_create_mode |= 0001;
704
705         if (autolog_ignore_targets != NULL)
706                 g_strfreev(autolog_ignore_targets);
707
708         autolog_ignore_targets = g_strsplit(settings_get_str("autolog_ignore_targets"), " ", -1);
709 }
710
711 void fe_log_init(void)
712 {
713         autoremove_tag = g_timeout_add(60000, (GSourceFunc) sig_autoremove, NULL);
714         skip_next_printtext = FALSE;
715
716         settings_add_bool("log", "awaylog_colors", TRUE);
717         settings_add_bool("log", "autolog", FALSE);
718         settings_add_bool("log", "autolog_colors", FALSE);
719         settings_add_str("log", "autolog_path", "~/irclogs/$tag/$0.log");
720         settings_add_level("log", "autolog_level", "all -crap -clientcrap -ctcps");
721         settings_add_str("log", "log_theme", "");
722         settings_add_str("log", "autolog_ignore_targets", "");
723
724         autolog_level = 0;
725         log_theme_name = NULL;
726         read_settings();
727
728         command_bind("log", NULL, (SIGNAL_FUNC) cmd_log);
729         command_bind("log open", NULL, (SIGNAL_FUNC) cmd_log_open);
730         command_bind("log close", NULL, (SIGNAL_FUNC) cmd_log_close);
731         command_bind("log start", NULL, (SIGNAL_FUNC) cmd_log_start);
732         command_bind("log stop", NULL, (SIGNAL_FUNC) cmd_log_stop);
733         command_bind("window log", NULL, (SIGNAL_FUNC) cmd_window_log);
734         command_bind("window logfile", NULL, (SIGNAL_FUNC) cmd_window_logfile);
735         signal_add_first("print text", (SIGNAL_FUNC) sig_printtext);
736         signal_add("window item remove", (SIGNAL_FUNC) sig_window_item_remove);
737         signal_add("window refnum changed", (SIGNAL_FUNC) sig_window_refnum_changed);
738         signal_add("server disconnected", (SIGNAL_FUNC) sig_server_disconnected);
739         signal_add("log locked", (SIGNAL_FUNC) sig_log_locked);
740         signal_add("log create failed", (SIGNAL_FUNC) sig_log_create_failed);
741         signal_add("log new", (SIGNAL_FUNC) sig_log_new);
742         signal_add("log config read", (SIGNAL_FUNC) sig_log_config_read);
743         signal_add("log config save", (SIGNAL_FUNC) sig_log_config_save);
744         signal_add("awaylog show", (SIGNAL_FUNC) sig_awaylog_show);
745         signal_add("theme destroyed", (SIGNAL_FUNC) sig_theme_destroyed);
746         signal_add("setup changed", (SIGNAL_FUNC) read_settings);
747
748         command_set_options("log open", "noopen autoopen -targets window colors");
749 }
750
751 void fe_log_deinit(void)
752 {
753         g_source_remove(autoremove_tag);
754         if (log_theme_name != NULL)
755                 signal_remove("print format", (SIGNAL_FUNC) sig_print_format);
756
757         command_unbind("log", (SIGNAL_FUNC) cmd_log);
758         command_unbind("log open", (SIGNAL_FUNC) cmd_log_open);
759         command_unbind("log close", (SIGNAL_FUNC) cmd_log_close);
760         command_unbind("log start", (SIGNAL_FUNC) cmd_log_start);
761         command_unbind("log stop", (SIGNAL_FUNC) cmd_log_stop);
762         command_unbind("window log", (SIGNAL_FUNC) cmd_window_log);
763         command_unbind("window logfile", (SIGNAL_FUNC) cmd_window_logfile);
764         signal_remove("print text", (SIGNAL_FUNC) sig_printtext);
765         signal_remove("window item remove", (SIGNAL_FUNC) sig_window_item_remove);
766         signal_remove("window refnum changed", (SIGNAL_FUNC) sig_window_refnum_changed);
767         signal_remove("server disconnected", (SIGNAL_FUNC) sig_server_disconnected);
768         signal_remove("log locked", (SIGNAL_FUNC) sig_log_locked);
769         signal_remove("log create failed", (SIGNAL_FUNC) sig_log_create_failed);
770         signal_remove("log new", (SIGNAL_FUNC) sig_log_new);
771         signal_remove("log config read", (SIGNAL_FUNC) sig_log_config_read);
772         signal_remove("log config save", (SIGNAL_FUNC) sig_log_config_save);
773         signal_remove("awaylog show", (SIGNAL_FUNC) sig_awaylog_show);
774         signal_remove("theme destroyed", (SIGNAL_FUNC) sig_theme_destroyed);
775         signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
776
777         if (autolog_ignore_targets != NULL)
778                 g_strfreev(autolog_ignore_targets);
779 }