Bug Summary

File:fe-common/core/fe-log.c
Location:line 209, column 5
Description:Dereference of null pointer.

Annotated Source Code

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) (60*5)
43
44static int autolog_level;
45static int autoremove_tag;
46static const char *autolog_path;
47
48static THEME_REC *log_theme;
49static int skip_next_printtext;
50static const char *log_theme_name;
51
52static int log_dir_create_mode;
53
54static char **autolog_ignore_targets;
55
56static char *log_colorizer_strip(const char *str)
57{
58 return strip_codes(str);
59}
60
61static 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)do{ if (log != ((void *)0)) { } else { g_return_if_fail_warning
(((gchar*) 0), __PRETTY_FUNCTION__, "log != NULL"); return; }
; }while (0)
;
66 g_return_if_fail(targets != NULL)do{ if (targets != ((void *)0)) { } else { g_return_if_fail_warning
(((gchar*) 0), __PRETTY_FUNCTION__, "targets != NULL"); return
; }; }while (0)
;
67
68 items = g_strsplit(targets, " ", -1);
69
70 for (tmp = items; *tmp != NULL((void *)0); 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>] */
79static 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((sizeof(int) * 8 + 2) / 3 + 1)];
86 LOG_REC *log;
87 int level;
88
89 if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST0x00002000 |
90 PARAM_FLAG_UNKNOWN_OPTIONS0x00008000 | PARAM_FLAG_OPTIONS0x00004000,
91 "log open", &optlist, &fname, &levels))
92 return;
93 if (*fname == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS)do { cmd_params_free(free_arg); do { signal_emit("error command"
, 1, ((gpointer) (CMDERR_NOT_ENOUGH_PARAMS))); signal_stop();
return; } while (0); } while (0)
;
94
95 level = level2bits(levels, NULL((void *)0));
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((void *)0));
100 servertag = server == NULL((void *)0) ? NULL((void *)0) : 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((void *)0) || !is_numeric(targetarg, '\0')) {
106 ltoa(window, active_win->refnum)g_snprintf(window, sizeof(window), "%d", 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((void *)0) && *targetarg != '\0')
114 log_add_targets(log, targetarg, servertag);
115 else if (servertag != NULL((void *)0))
116 log_add_targets(log, "*", servertag);
117 }
118
119 if (g_hash_table_lookup(optlist, "autoopen"))
120 log->autoopen = TRUE(!(0));
121
122 if (g_hash_table_lookup(optlist, "colors") == NULL((void *)0))
123 log->colorizer = log_colorizer_strip;
124
125 log_update(log);
126
127 if (log->handle == -1 && g_hash_table_lookup(optlist, "noopen") == NULL((void *)0)) {
128 /* start logging */
129 if (log_start_logging(log)) {
130 printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,printformat_module("fe-common/core", ((void *)0), ((void *)0)
, MSGLEVEL_CLIENTNOTICE, TXT_LOG_OPENED, fname)
131 TXT_LOG_OPENED, fname)printformat_module("fe-common/core", ((void *)0), ((void *)0)
, MSGLEVEL_CLIENTNOTICE, TXT_LOG_OPENED, fname)
;
132 } else {
133 log_close(log);
134 }
135 }
136
137 cmd_params_free(free_arg);
138}
139
140static 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((void *)0) ? NULL((void *)0) : tmp->data;
150}
151
152/* SYNTAX: LOG CLOSE <id>|<file> */
153static void cmd_log_close(const char *data)
154{
155 LOG_REC *log;
156
157 log = log_find_from_data(data);
158 if (log == NULL((void *)0))
159 printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, TXT_LOG_NOT_OPEN, data)printformat_module("fe-common/core", ((void *)0), ((void *)0)
, MSGLEVEL_CLIENTERROR, TXT_LOG_NOT_OPEN, data)
;
160 else {
161 log_close(log);
162 printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_LOG_CLOSED, data)printformat_module("fe-common/core", ((void *)0), ((void *)0)
, MSGLEVEL_CLIENTNOTICE, TXT_LOG_CLOSED, data)
;
163 }
164}
165
166/* SYNTAX: LOG START <id>|<file> */
167static void cmd_log_start(const char *data)
168{
169 LOG_REC *log;
170
171 log = log_find_from_data(data);
172 if (log != NULL((void *)0)) {
173 log_start_logging(log);
174 printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_LOG_OPENED, data)printformat_module("fe-common/core", ((void *)0), ((void *)0)
, MSGLEVEL_CLIENTNOTICE, TXT_LOG_OPENED, data)
;
175 }
176}
177
178/* SYNTAX: LOG STOP <id>|<file> */
179static void cmd_log_stop(const char *data)
180{
181 LOG_REC *log;
182
183 log = log_find_from_data(data);
184 if (log == NULL((void *)0) || log->handle == -1)
185 printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, TXT_LOG_NOT_OPEN, data)printformat_module("fe-common/core", ((void *)0), ((void *)0)
, MSGLEVEL_CLIENTERROR, TXT_LOG_NOT_OPEN, data)
;
186 else {
187 log_stop_logging(log);
188 printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_LOG_CLOSED, data)printformat_module("fe-common/core", ((void *)0), ((void *)0)
, MSGLEVEL_CLIENTNOTICE, TXT_LOG_CLOSED, data)
;
189 }
190}
191
192static char *log_items_get_list(LOG_REC *log)
193{
194 GSList *tmp;
195 GString *str;
196 char *ret;
197 LOG_ITEM_REC *rec = NULL((void *)0);
198
199 g_return_val_if_fail(log != NULL, NULL)do{ if (log != ((void *)0)) { } else { g_return_if_fail_warning
(((gchar*) 0), __PRETTY_FUNCTION__, "log != NULL"); return (
((void *)0)); }; }while (0)
;
[1] Taking true branch
[2] Loop condition is false. Exiting loop
200 g_return_val_if_fail(log->items != NULL, NULL)do{ if (log->items != ((void *)0)) { } else { g_return_if_fail_warning
(((gchar*) 0), __PRETTY_FUNCTION__, "log->items != NULL")
; return (((void *)0)); }; }while (0)
;
[3] Taking true branch
[4] Loop condition is false. Exiting loop
201
202 str = g_string_new(NULL((void *)0));
203 for (tmp = log->items; tmp != NULL((void *)0); tmp = tmp->next) {
[5] Loop condition is false. Execution continues on line 208
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((void *)0))
[6] Dereference of null pointer
210 g_string_append_printf(str, " (%s)", rec->servertag);
211
212 ret = str->str;
213 g_string_free(str, FALSE(0));
214 return ret;
215}
216
217static 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)printformat_module("fe-common/core", ((void *)0), ((void *)0)
, MSGLEVEL_CLIENTCRAP, TXT_LOG_LIST_HEADER)
;
224 for (tmp = logs, index = 1; tmp != NULL((void *)0); tmp = tmp->next, index++) {
225 LOG_REC *rec = tmp->data;
226
227 levelstr = bits2level(rec->level);
228 items = rec->items == NULL((void *)0) ? NULL((void *)0) :
229 log_items_get_list(rec);
230
231 printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_LOG_LIST,printformat_module("fe-common/core", ((void *)0), ((void *)0)
, MSGLEVEL_CLIENTCRAP, TXT_LOG_LIST, index, rec->fname, items
!= ((void *)0) ? items : "", levelstr, rec->autoopen ? " -autoopen"
: "", rec->handle != -1 ? " active" : "")
232 index, rec->fname, items != NULL ? items : "",printformat_module("fe-common/core", ((void *)0), ((void *)0)
, MSGLEVEL_CLIENTCRAP, TXT_LOG_LIST, index, rec->fname, items
!= ((void *)0) ? items : "", levelstr, rec->autoopen ? " -autoopen"
: "", rec->handle != -1 ? " active" : "")
233 levelstr, rec->autoopen ? " -autoopen" : "",printformat_module("fe-common/core", ((void *)0), ((void *)0)
, MSGLEVEL_CLIENTCRAP, TXT_LOG_LIST, index, rec->fname, items
!= ((void *)0) ? items : "", levelstr, rec->autoopen ? " -autoopen"
: "", rec->handle != -1 ? " active" : "")
234 rec->handle != -1 ? " active" : "")printformat_module("fe-common/core", ((void *)0), ((void *)0)
, MSGLEVEL_CLIENTCRAP, TXT_LOG_LIST, index, rec->fname, items
!= ((void *)0) ? items : "", levelstr, rec->autoopen ? " -autoopen"
: "", rec->handle != -1 ? " active" : "")
;
235
236 g_free_not_null(items)g_free(items);
237 g_free(levelstr);
238 }
239 printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_LOG_LIST_FOOTER)printformat_module("fe-common/core", ((void *)0), ((void *)0)
, MSGLEVEL_CLIENTCRAP, TXT_LOG_LIST_FOOTER)
;
240}
241
242static 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
250static 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((void *)0); 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((void *)0)) {
262 if (ret_item != NULL((void *)0)) *ret_item = logitem;
263 return log;
264 }
265 }
266
267 return NULL((void *)0);
268}
269
270/* SYNTAX: WINDOW LOG on|off|toggle [<filename>] */
271static void cmd_window_log(const char *data)
272{
273 LOG_REC *log;
274 char *set, *fname, window[MAX_INT_STRLEN((sizeof(int) * 8 + 2) / 3 + 1)];
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)g_snprintf(window, sizeof(window), "%d", active_win->refnum
)
;
282 log = logs_find_item(LOG_ITEM_WINDOW_REFNUM, window, NULL((void *)0), NULL((void *)0));
283
284 open_log = close_log = FALSE(0);
285 if (g_ascii_strcasecmp(set, "ON") == 0)
286 open_log = TRUE(!(0));
287 else if (g_ascii_strcasecmp(set, "OFF") == 0) {
288 close_log = TRUE(!(0));
289 } else if (g_ascii_strcasecmp(set, "TOGGLE") == 0) {
290 open_log = log == NULL((void *)0);
291 close_log = log != NULL((void *)0);
292 } else {
293 printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, TXT_NOT_TOGGLE)printformat_module("fe-common/core", ((void *)0), ((void *)0)
, MSGLEVEL_CLIENTERROR, TXT_NOT_TOGGLE)
;
294 cmd_params_free(free_arg);
295 return;
296 }
297
298 if (open_log && log == NULL((void *)0)) {
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((void *)0) ? active_win->name : "Window",
303 active_win->name != NULL((void *)0) ? "" : 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((void *)0));
307 log_update(log);
308 g_free(fname);
309 }
310
311 if (open_log && log != NULL((void *)0)) {
312 log_start_logging(log);
313 printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_LOG_OPENED, log->fname)printformat_module("fe-common/core", ((void *)0), ((void *)0)
, MSGLEVEL_CLIENTNOTICE, TXT_LOG_OPENED, log->fname)
;
314 } else if (close_log && log != NULL((void *)0) && log->handle != -1) {
315 log_stop_logging(log);
316 printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_LOG_CLOSED, log->fname)printformat_module("fe-common/core", ((void *)0), ((void *)0)
, 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> */
324static void cmd_window_logfile(const char *data)
325{
326 LOG_REC *log;
327 char window[MAX_INT_STRLEN((sizeof(int) * 8 + 2) / 3 + 1)];
328
329 ltoa(window, active_win->refnum)g_snprintf(window, sizeof(window), "%d", active_win->refnum
)
;
330 log = logs_find_item(LOG_ITEM_WINDOW_REFNUM, window, NULL((void *)0), NULL((void *)0));
331
332 if (log != NULL((void *)0)) {
333 printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_WINDOWLOG_FILE_LOGGING)printformat_module("fe-common/core", ((void *)0), ((void *)0)
, 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((void *)0));
340 log_update(log);
341
342 printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_WINDOWLOG_FILE, data)printformat_module("fe-common/core", ((void *)0), ((void *)0)
, MSGLEVEL_CLIENTNOTICE, TXT_WINDOWLOG_FILE, data)
;
343}
344
345/* window's refnum changed - update the logs to log the new window refnum */
346static void sig_window_refnum_changed(WINDOW_REC *window, gpointer old_refnum)
347{
348 char winnum[MAX_INT_STRLEN((sizeof(int) * 8 + 2) / 3 + 1)];
349 LOG_REC *log;
350 LOG_ITEM_REC *item;
351
352 ltoa(winnum, GPOINTER_TO_INT(old_refnum))g_snprintf(winnum, sizeof(winnum), "%d", ((gint) (old_refnum)
))
;
353 log = logs_find_item(LOG_ITEM_WINDOW_REFNUM, winnum, NULL((void *)0), &item);
354
355 if (log != NULL((void *)0)) {
356 ltoa(winnum, window->refnum)g_snprintf(winnum, sizeof(winnum), "%d", window->refnum);
357
358 g_free(item->name);
359 item->name = g_strdup(winnum);
360 }
361}
362
363static void sig_server_disconnected(SERVER_REC *server)
364{
365 LOG_ITEM_REC *logitem;
366 GSList *tmp, *next;
367
368 for (tmp = logs; tmp != NULL((void *)0); tmp = next) {
369 LOG_REC *log = tmp->data;
370 next = tmp->next;
371
372 if (!log->temp || log->items == NULL((void *)0))
373 continue;
374
375 logitem = log->items->data;
376 if (logitem->type == LOG_ITEM_TARGET &&
377 logitem->servertag != NULL((void *)0) &&
378 g_strcasecmp(logitem->servertag, server->tag) == 0 &&
379 server_ischannel(server, logitem->name)(server)->ischannel(server, logitem->name)) /* kludge again.. so we won't close dcc chats */
380 log_close(log);
381 }
382}
383
384static void autologs_close_all(void)
385{
386 GSList *tmp, *next;
387
388 for (tmp = logs; tmp != NULL((void *)0); tmp = next) {
389 LOG_REC *rec = tmp->data;
390
391 next = tmp->next;
392 if (rec->temp) log_close(rec);
393 }
394}
395
396/* '%' -> '%%', '/' -> '_' */
397static 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 (*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
418static 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((void *)0));
425 if (log != NULL((void *)0) && !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
433 '%' -> '%%' - so strftime() won't mess with them */
434 fixed_target = escape_target(target);
435 if (CHAT_PROTOCOL(server)((server) == ((void *)0) ? chat_protocol_get_default() : chat_protocol_find_id
((server)->chat_type))
->case_insensitive)
436 g_strdown(fixed_target);
437
438 /* $0 = target, $1 = server tag */
439 params = g_strconcat(fixed_target, " ", server_tag, NULL((void *)0));
440 g_free(fixed_target);
441
442 fname = parse_special_string(autolog_path, server, NULL((void *)0),
443 params, NULL((void *)0), 0);
444 g_free(params);
445
446 if (log_find(fname) == NULL((void *)0)) {
447 log = log_create_rec(fname, autolog_level);
448 if (!settings_get_bool("autolog_colors"))
449 log->colorizer = log_colorizer_strip;
450 log_item_add(log, LOG_ITEM_TARGET, target, server_tag);
451
452 dir = g_path_get_dirname(log->real_fname);
453 mkpath(dir, log_dir_create_mode);
454 g_free(dir);
455
456 log->temp = TRUE(!(0));
457 log_update(log);
458 log_start_logging(log);
459 }
460 g_free(fname);
461}
462
463static void autolog_open_check(SERVER_REC *server, const char *server_tag,
464 const char *target, int level)
465{
466 const char *deftarget;
467
468 /* FIXME: kind of a kludge, but we don't want to reopen logs when
469 we're parting the channel with /WINDOW CLOSE.. Maybe a small
470 timeout would be nice instead of immediately closing the log file
471 after "window item destroyed" */
472 if (level == MSGLEVEL_PARTS ||
473 (autolog_level & level) == 0 || target == NULL((void *)0) || *target == '\0')
474 return;
475
476 deftarget = server ? server->nick : "unknown";
477
478 if (target != NULL((void *)0))
479 autolog_open(server, server_tag, strcmp(target, "*") ? target : deftarget);
480}
481
482static void log_single_line(WINDOW_REC *window, const char *server_tag,
483 const char *target, int level, const char *text)
484{
485 char windownum[MAX_INT_STRLEN((sizeof(int) * 8 + 2) / 3 + 1)];
486 LOG_REC *log;
487
488 if (window != NULL((void *)0)) {
489 /* save to log created with /WINDOW LOG */
490 ltoa(windownum, window->refnum)g_snprintf(windownum, sizeof(windownum), "%d", window->refnum
)
;
491 log = logs_find_item(LOG_ITEM_WINDOW_REFNUM,
492 windownum, NULL((void *)0), NULL((void *)0));
493 if (log != NULL((void *)0))
494 log_write_rec(log, text, level);
495 }
496
497 log_file_write(server_tag, target, level, text, FALSE(0));
498}
499
500static void log_line(TEXT_DEST_REC *dest, const char *text)
501{
502 char **lines, **tmp;
503
504 if (dest->level == MSGLEVEL_NEVER)
505 return;
506
507 if (autolog_ignore_targets != NULL((void *)0) && dest->target != NULL((void *)0))
508 if (strarray_find_dest(autolog_ignore_targets, dest))
509 return;
510
511 /* let autolog open the log records */
512 autolog_open_check(dest->server, dest->server_tag,
513 dest->target, dest->level);
514
515 if (logs == NULL((void *)0))
516 return;
517
518 /* text may contain one or more lines, log wants to eat them one
519 line at a time */
520 lines = g_strsplit(text, "\n", -1);
521 for (tmp = lines; *tmp != NULL((void *)0); tmp++)
522 log_single_line(dest->window, dest->server_tag,
523 dest->target, dest->level, *tmp);
524 g_strfreev(lines);
525}
526
527static void sig_printtext(TEXT_DEST_REC *dest, const char *text,
528 const char *stripped)
529{
530 if (skip_next_printtext) {
531 skip_next_printtext = FALSE(0);
532 return;
533 }
534
535 log_line(dest, text);
536}
537
538static void sig_print_format(THEME_REC *theme, const char *module,
539 TEXT_DEST_REC *dest, void *formatnum, char **args)
540{
541 char *str, *linestart, *tmp;
542
543 if (log_theme == NULL((void *)0)) {
544 /* theme isn't loaded for some reason (/reload destroys it),
545 reload it. */
546 log_theme = theme_load(log_theme_name);
547 if (log_theme == NULL((void *)0)) return;
548 }
549
550 if (theme == log_theme)
551 return;
552
553 str = format_get_text_theme_charargs(log_theme, module, dest,
554 GPOINTER_TO_INT(formatnum)((gint) (formatnum)), args);
555 skip_next_printtext = TRUE(!(0));
556
557 if (*str != '\0') {
558 /* add the line start format */
559 linestart = format_get_level_tag(log_theme, dest);
560 tmp = str;
561 str = format_add_linestart(tmp, linestart);
562 g_free_not_null(linestart)g_free(linestart);
563 g_free(tmp);
564
565 /* strip colors from text, log it. */
566 log_line(dest, str);
567 }
568 g_free(str);
569
570}
571
572static int sig_autoremove(void)
573{
574 SERVER_REC *server;
575 LOG_ITEM_REC *logitem;
576 GSList *tmp, *next;
577 time_t removetime;
578
579 removetime = time(NULL((void *)0))-AUTOLOG_INACTIVITY_CLOSE(60*5);
580 for (tmp = logs; tmp != NULL((void *)0); tmp = next) {
581 LOG_REC *log = tmp->data;
582
583 next = tmp->next;
584
585 if (!log->temp || log->last > removetime || log->items == NULL((void *)0))
586 continue;
587
588 /* Close only logs with private messages */
589 logitem = log->items->data;
590 if (logitem->servertag == NULL((void *)0))
591 continue;
592
593 server = server_find_tag(logitem->servertag);
594 if (logitem->type == LOG_ITEM_TARGET &&
595 server != NULL((void *)0) && !server_ischannel(server, logitem->name)(server)->ischannel(server, logitem->name))
596 log_close(log);
597 }
598 return 1;
599}
600
601static void sig_window_item_remove(WINDOW_REC *window, WI_ITEM_REC *item)
602{
603 LOG_REC *log;
604
605 log = logs_find_item(LOG_ITEM_TARGET, item->visible_name,
606 item->server == NULL((void *)0) ? NULL((void *)0) :
607 item->server->tag, NULL((void *)0));
608 if (log != NULL((void *)0) && log->temp)
609 log_close(log);
610}
611
612static void sig_log_locked(LOG_REC *log)
613{
614 printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,printformat_module("fe-common/core", ((void *)0), ((void *)0)
, MSGLEVEL_CLIENTERROR, TXT_LOG_LOCKED, log->fname)
615 TXT_LOG_LOCKED, log->fname)printformat_module("fe-common/core", ((void *)0), ((void *)0)
, MSGLEVEL_CLIENTERROR, TXT_LOG_LOCKED, log->fname)
;
616}
617
618static void sig_log_create_failed(LOG_REC *log)
619{
620 printformat(NULL, NULL, MSGLEVEL_CLIENTERROR,printformat_module("fe-common/core", ((void *)0), ((void *)0)
, MSGLEVEL_CLIENTERROR, TXT_LOG_CREATE_FAILED, log->real_fname
, g_strerror((* __error())))
621 TXT_LOG_CREATE_FAILED,printformat_module("fe-common/core", ((void *)0), ((void *)0)
, MSGLEVEL_CLIENTERROR, TXT_LOG_CREATE_FAILED, log->real_fname
, g_strerror((* __error())))
622 log->real_fname, g_strerror(errno))printformat_module("fe-common/core", ((void *)0), ((void *)0)
, MSGLEVEL_CLIENTERROR, TXT_LOG_CREATE_FAILED, log->real_fname
, g_strerror((* __error())))
;
623}
624
625static void sig_log_new(LOG_REC *log)
626{
627 if (!settings_get_bool("awaylog_colors") &&
628 strcmp(log->fname, settings_get_str("awaylog_file")) == 0)
629 log->colorizer = log_colorizer_strip;
630}
631
632static void sig_log_config_read(LOG_REC *log, CONFIG_NODE *node)
633{
634 if (!config_node_get_bool(node, "colors", FALSE(0)))
635 log->colorizer = log_colorizer_strip;
636}
637
638static void sig_log_config_save(LOG_REC *log, CONFIG_NODE *node)
639{
640 if (log->colorizer == NULL((void *)0))
641 iconfig_node_set_bool(node, "colors", TRUE)config_node_set_bool(mainconfig, node, "colors", (!(0)));
642 else
643 iconfig_node_set_str(node, "colors", NULL)config_node_set_str(mainconfig, node, "colors", ((void *)0));
644}
645
646static void sig_awaylog_show(LOG_REC *log, gpointer pmsgs, gpointer pfilepos)
647{
648 char *str;
649 int msgs, filepos;
650
651 msgs = GPOINTER_TO_INT(pmsgs)((gint) (pmsgs));
652 filepos = GPOINTER_TO_INT(pfilepos)((gint) (pfilepos));
653
654 if (msgs == 0)
655 printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_LOG_NO_AWAY_MSGS, log->fname)printformat_module("fe-common/core", ((void *)0), ((void *)0)
, MSGLEVEL_CLIENTNOTICE, TXT_LOG_NO_AWAY_MSGS, log->fname)
;
656 else {
657 printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_LOG_AWAY_MSGS, log->fname, msgs)printformat_module("fe-common/core", ((void *)0), ((void *)0)
, MSGLEVEL_CLIENTNOTICE, TXT_LOG_AWAY_MSGS, log->fname, msgs
)
;
658
659 str = g_strdup_printf("\"%s\" %d", log->fname, filepos);
660 signal_emit("command cat", 1, str);
661 g_free(str);
662 }
663}
664
665static void sig_theme_destroyed(THEME_REC *theme)
666{
667 if (theme == log_theme)
668 log_theme = NULL((void *)0);
669}
670
671static void read_settings(void)
672{
673 int old_autolog = autolog_level;
674 int log_file_create_mode;
675
676 autolog_path = settings_get_str("autolog_path");
677 autolog_level = !settings_get_bool("autolog") ? 0 :
678 settings_get_level("autolog_level");
679
680 if (old_autolog && !autolog_level)
681 autologs_close_all();
682
683 /* write to log files with different theme? */
684 if (log_theme_name != NULL((void *)0))
685 signal_remove("print format", (SIGNAL_FUNC) sig_print_format)signal_remove_full(("print format"), (SIGNAL_FUNC) ((SIGNAL_FUNC
) sig_print_format), ((void *)0))
;
686 log_theme_name = settings_get_str("log_theme");
687 if (*log_theme_name == '\0')
688 log_theme_name = NULL((void *)0);
689 else
690 signal_add("print format", (SIGNAL_FUNC) sig_print_format)signal_add_full("fe-common/core", 0, ("print format"), (SIGNAL_FUNC
) ((SIGNAL_FUNC) sig_print_format), ((void *)0))
;
691
692 log_theme = log_theme_name == NULL((void *)0) ? NULL((void *)0) :
693 theme_load(log_theme_name);
694
695 log_file_create_mode = octal2dec(settings_get_int("log_create_mode"));
696 log_dir_create_mode = log_file_create_mode;
697 if (log_file_create_mode & 0400) log_dir_create_mode |= 0100;
698 if (log_file_create_mode & 0040) log_dir_create_mode |= 0010;
699 if (log_file_create_mode & 0004) log_dir_create_mode |= 0001;
700
701 if (autolog_ignore_targets != NULL((void *)0))
702 g_strfreev(autolog_ignore_targets);
703
704 autolog_ignore_targets = g_strsplit(settings_get_str("autolog_ignore_targets"), " ", -1);
705}
706
707void fe_log_init(void)
708{
709 autoremove_tag = g_timeout_add(60000, (GSourceFunc) sig_autoremove, NULL((void *)0));
710 skip_next_printtext = FALSE(0);
711
712 settings_add_bool("log", "awaylog_colors", TRUE)settings_add_bool_module("fe-common/core", "log", "awaylog_colors"
, (!(0)))
;
713 settings_add_bool("log", "autolog", FALSE)settings_add_bool_module("fe-common/core", "log", "autolog", (
0))
;
714 settings_add_bool("log", "autolog_colors", FALSE)settings_add_bool_module("fe-common/core", "log", "autolog_colors"
, (0))
;
715 settings_add_str("log", "autolog_path", "~/irclogs/$tag/$0.log")settings_add_str_module("fe-common/core", "log", "autolog_path"
, "~/irclogs/$tag/$0.log")
;
716 settings_add_level("log", "autolog_level", "all -crap -clientcrap -ctcps")settings_add_level_module("fe-common/core", "log", "autolog_level"
, "all -crap -clientcrap -ctcps")
;
717 settings_add_str("log", "log_theme", "")settings_add_str_module("fe-common/core", "log", "log_theme",
"")
;
718 settings_add_str("log", "autolog_ignore_targets", "")settings_add_str_module("fe-common/core", "log", "autolog_ignore_targets"
, "")
;
719
720 autolog_level = 0;
721 log_theme_name = NULL((void *)0);
722 read_settings();
723
724 command_bind("log", NULL, (SIGNAL_FUNC) cmd_log)command_bind_full("fe-common/core", 0, "log", -1, ((void *)0)
, (SIGNAL_FUNC) cmd_log, ((void *)0))
;
725 command_bind("log open", NULL, (SIGNAL_FUNC) cmd_log_open)command_bind_full("fe-common/core", 0, "log open", -1, ((void
*)0), (SIGNAL_FUNC) cmd_log_open, ((void *)0))
;
726 command_bind("log close", NULL, (SIGNAL_FUNC) cmd_log_close)command_bind_full("fe-common/core", 0, "log close", -1, ((void
*)0), (SIGNAL_FUNC) cmd_log_close, ((void *)0))
;
727 command_bind("log start", NULL, (SIGNAL_FUNC) cmd_log_start)command_bind_full("fe-common/core", 0, "log start", -1, ((void
*)0), (SIGNAL_FUNC) cmd_log_start, ((void *)0))
;
728 command_bind("log stop", NULL, (SIGNAL_FUNC) cmd_log_stop)command_bind_full("fe-common/core", 0, "log stop", -1, ((void
*)0), (SIGNAL_FUNC) cmd_log_stop, ((void *)0))
;
729 command_bind("window log", NULL, (SIGNAL_FUNC) cmd_window_log)command_bind_full("fe-common/core", 0, "window log", -1, ((void
*)0), (SIGNAL_FUNC) cmd_window_log, ((void *)0))
;
730 command_bind("window logfile", NULL, (SIGNAL_FUNC) cmd_window_logfile)command_bind_full("fe-common/core", 0, "window logfile", -1, (
(void *)0), (SIGNAL_FUNC) cmd_window_logfile, ((void *)0))
;
731 signal_add_first("print text", (SIGNAL_FUNC) sig_printtext)signal_add_full("fe-common/core", -100, ("print text"), (SIGNAL_FUNC
) ((SIGNAL_FUNC) sig_printtext), ((void *)0))
;
732 signal_add("window item remove", (SIGNAL_FUNC) sig_window_item_remove)signal_add_full("fe-common/core", 0, ("window item remove"), (
SIGNAL_FUNC) ((SIGNAL_FUNC) sig_window_item_remove), ((void *
)0))
;
733 signal_add("window refnum changed", (SIGNAL_FUNC) sig_window_refnum_changed)signal_add_full("fe-common/core", 0, ("window refnum changed"
), (SIGNAL_FUNC) ((SIGNAL_FUNC) sig_window_refnum_changed), (
(void *)0))
;
734 signal_add("server disconnected", (SIGNAL_FUNC) sig_server_disconnected)signal_add_full("fe-common/core", 0, ("server disconnected"),
(SIGNAL_FUNC) ((SIGNAL_FUNC) sig_server_disconnected), ((void
*)0))
;
735 signal_add("log locked", (SIGNAL_FUNC) sig_log_locked)signal_add_full("fe-common/core", 0, ("log locked"), (SIGNAL_FUNC
) ((SIGNAL_FUNC) sig_log_locked), ((void *)0))
;
736 signal_add("log create failed", (SIGNAL_FUNC) sig_log_create_failed)signal_add_full("fe-common/core", 0, ("log create failed"), (
SIGNAL_FUNC) ((SIGNAL_FUNC) sig_log_create_failed), ((void *)
0))
;
737 signal_add("log new", (SIGNAL_FUNC) sig_log_new)signal_add_full("fe-common/core", 0, ("log new"), (SIGNAL_FUNC
) ((SIGNAL_FUNC) sig_log_new), ((void *)0))
;
738 signal_add("log config read", (SIGNAL_FUNC) sig_log_config_read)signal_add_full("fe-common/core", 0, ("log config read"), (SIGNAL_FUNC
) ((SIGNAL_FUNC) sig_log_config_read), ((void *)0))
;
739 signal_add("log config save", (SIGNAL_FUNC) sig_log_config_save)signal_add_full("fe-common/core", 0, ("log config save"), (SIGNAL_FUNC
) ((SIGNAL_FUNC) sig_log_config_save), ((void *)0))
;
740 signal_add("awaylog show", (SIGNAL_FUNC) sig_awaylog_show)signal_add_full("fe-common/core", 0, ("awaylog show"), (SIGNAL_FUNC
) ((SIGNAL_FUNC) sig_awaylog_show), ((void *)0))
;
741 signal_add("theme destroyed", (SIGNAL_FUNC) sig_theme_destroyed)signal_add_full("fe-common/core", 0, ("theme destroyed"), (SIGNAL_FUNC
) ((SIGNAL_FUNC) sig_theme_destroyed), ((void *)0))
;
742 signal_add("setup changed", (SIGNAL_FUNC) read_settings)signal_add_full("fe-common/core", 0, ("setup changed"), (SIGNAL_FUNC
) ((SIGNAL_FUNC) read_settings), ((void *)0))
;
743
744 command_set_options("log open", "noopen autoopen -targets window colors")command_set_options_module("fe-common/core", "log open", "noopen autoopen -targets window colors"
)
;
745}
746
747void fe_log_deinit(void)
748{
749 g_source_remove(autoremove_tag);
750 if (log_theme_name != NULL((void *)0))
751 signal_remove("print format", (SIGNAL_FUNC) sig_print_format)signal_remove_full(("print format"), (SIGNAL_FUNC) ((SIGNAL_FUNC
) sig_print_format), ((void *)0))
;
752
753 command_unbind("log", (SIGNAL_FUNC) cmd_log)command_unbind_full("log", (SIGNAL_FUNC) cmd_log, ((void *)0)
)
;
754 command_unbind("log open", (SIGNAL_FUNC) cmd_log_open)command_unbind_full("log open", (SIGNAL_FUNC) cmd_log_open, (
(void *)0))
;
755 command_unbind("log close", (SIGNAL_FUNC) cmd_log_close)command_unbind_full("log close", (SIGNAL_FUNC) cmd_log_close,
((void *)0))
;
756 command_unbind("log start", (SIGNAL_FUNC) cmd_log_start)command_unbind_full("log start", (SIGNAL_FUNC) cmd_log_start,
((void *)0))
;
757 command_unbind("log stop", (SIGNAL_FUNC) cmd_log_stop)command_unbind_full("log stop", (SIGNAL_FUNC) cmd_log_stop, (
(void *)0))
;
758 command_unbind("window log", (SIGNAL_FUNC) cmd_window_log)command_unbind_full("window log", (SIGNAL_FUNC) cmd_window_log
, ((void *)0))
;
759 command_unbind("window logfile", (SIGNAL_FUNC) cmd_window_logfile)command_unbind_full("window logfile", (SIGNAL_FUNC) cmd_window_logfile
, ((void *)0))
;
760 signal_remove("print text", (SIGNAL_FUNC) sig_printtext)signal_remove_full(("print text"), (SIGNAL_FUNC) ((SIGNAL_FUNC
) sig_printtext), ((void *)0))
;
761 signal_remove("window item remove", (SIGNAL_FUNC) sig_window_item_remove)signal_remove_full(("window item remove"), (SIGNAL_FUNC) ((SIGNAL_FUNC
) sig_window_item_remove), ((void *)0))
;
762 signal_remove("window refnum changed", (SIGNAL_FUNC) sig_window_refnum_changed)signal_remove_full(("window refnum changed"), (SIGNAL_FUNC) (
(SIGNAL_FUNC) sig_window_refnum_changed), ((void *)0))
;
763 signal_remove("server disconnected", (SIGNAL_FUNC) sig_server_disconnected)signal_remove_full(("server disconnected"), (SIGNAL_FUNC) ((SIGNAL_FUNC
) sig_server_disconnected), ((void *)0))
;
764 signal_remove("log locked", (SIGNAL_FUNC) sig_log_locked)signal_remove_full(("log locked"), (SIGNAL_FUNC) ((SIGNAL_FUNC
) sig_log_locked), ((void *)0))
;
765 signal_remove("log create failed", (SIGNAL_FUNC) sig_log_create_failed)signal_remove_full(("log create failed"), (SIGNAL_FUNC) ((SIGNAL_FUNC
) sig_log_create_failed), ((void *)0))
;
766 signal_remove("log new", (SIGNAL_FUNC) sig_log_new)signal_remove_full(("log new"), (SIGNAL_FUNC) ((SIGNAL_FUNC) sig_log_new
), ((void *)0))
;
767 signal_remove("log config read", (SIGNAL_FUNC) sig_log_config_read)signal_remove_full(("log config read"), (SIGNAL_FUNC) ((SIGNAL_FUNC
) sig_log_config_read), ((void *)0))
;
768 signal_remove("log config save", (SIGNAL_FUNC) sig_log_config_save)signal_remove_full(("log config save"), (SIGNAL_FUNC) ((SIGNAL_FUNC
) sig_log_config_save), ((void *)0))
;
769 signal_remove("awaylog show", (SIGNAL_FUNC) sig_awaylog_show)signal_remove_full(("awaylog show"), (SIGNAL_FUNC) ((SIGNAL_FUNC
) sig_awaylog_show), ((void *)0))
;
770 signal_remove("theme destroyed", (SIGNAL_FUNC) sig_theme_destroyed)signal_remove_full(("theme destroyed"), (SIGNAL_FUNC) ((SIGNAL_FUNC
) sig_theme_destroyed), ((void *)0))
;
771 signal_remove("setup changed", (SIGNAL_FUNC) read_settings)signal_remove_full(("setup changed"), (SIGNAL_FUNC) ((SIGNAL_FUNC
) read_settings), ((void *)0))
;
772
773 if (autolog_ignore_targets != NULL((void *)0))
774 g_strfreev(autolog_ignore_targets);
775}