2 * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2021 the Claws Mail team and Hiroyuki Yamamoto
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
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.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "claws-features.h"
32 #include <glib/gi18n.h>
37 #include "file-utils.h"
39 #define FWRITE(_b,_s,_n,_f) if (fwrite(_b,_s,_n,_f) != _n) { \
40 g_message("log fwrite failed!\n"); \
43 #define FPUTS(_b,_f) if (fputs(_b,_f) == EOF) { \
44 g_message("log fputs failed!\n"); \
47 #define FFLUSH(_f) if (fflush(_f) != 0) { \
48 g_message("log fflush failed!\n"); \
52 static FILE *log_fp
[LOG_INSTANCE_MAX
] = {
57 static size_t log_size
[LOG_INSTANCE_MAX
] = {
62 static gchar
*log_filename
[LOG_INSTANCE_MAX
] = {
68 static gboolean log_error_capability
[LOG_INSTANCE_MAX
] = {
73 typedef struct _LogInstanceData LogInstanceData
;
75 struct _LogInstanceData
{
78 int *prefs_logwin_width
;
79 int *prefs_logwin_height
;
82 static LogInstanceData log_instances
[LOG_INSTANCE_MAX
] = {
83 { LOG_APPEND_TEXT_HOOKLIST
, NULL
, NULL
, NULL
},
84 { DEBUG_FILTERING_APPEND_TEXT_HOOKLIST
, NULL
, NULL
, NULL
}
87 gboolean
prefs_common_enable_log_standard(void);
88 gboolean
prefs_common_enable_log_warning(void);
89 gboolean
prefs_common_enable_log_error(void);
90 gboolean
prefs_common_enable_log_status(void);
92 static gboolean
invoke_hook_cb (gpointer data
)
94 LogText
*logtext
= (LogText
*)data
;
95 hooks_invoke(get_log_hook(logtext
->instance
), logtext
);
96 g_free(logtext
->text
);
101 void set_log_file(LogInstance instance
, const gchar
*filename
)
103 gchar
*fullname
= NULL
;
104 if (log_fp
[instance
])
107 if (!g_path_is_absolute(filename
)) {
108 fullname
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
111 fullname
= g_strdup(filename
);
113 /* backup old logfile if existing */
114 if (is_file_exist(fullname
)) {
117 backupname
= g_strconcat(fullname
, ".bak", NULL
);
118 claws_unlink(backupname
);
119 if (g_rename(fullname
, backupname
) < 0)
120 FILE_OP_ERROR(fullname
, "rename");
124 log_fp
[instance
] = fopen(fullname
, "wb");
125 if (!log_fp
[instance
]) {
126 FILE_OP_ERROR(fullname
, "fopen");
127 log_filename
[instance
] = NULL
;
132 if (change_file_mode_rw(log_fp
[instance
], fullname
) < 0) {
133 FILE_OP_ERROR(fullname
, "chmod");
134 g_warning("can't change file mode: %s", fullname
);
137 log_filename
[instance
] = g_strdup(fullname
);
138 log_size
[instance
] = 0;
142 void close_log_file(LogInstance instance
)
144 if (log_fp
[instance
]) {
145 fclose(log_fp
[instance
]);
146 log_fp
[instance
] = NULL
;
147 log_size
[instance
] = 0;
148 g_free(log_filename
[instance
]);
149 log_filename
[instance
] = NULL
;
153 static void rotate_log(LogInstance instance
)
155 if (log_size
[instance
] > 10 * 1024* 1024) {
156 gchar
*filename
= g_strdup(log_filename
[instance
]);
157 debug_print("rotating %s\n", filename
);
158 close_log_file(instance
);
159 set_log_file(instance
, filename
);
164 const char *get_log_hook(LogInstance instance
)
166 return log_instances
[instance
].hook
;
169 void set_log_title(LogInstance instance
, gchar
*title
)
171 log_instances
[instance
].title
= title
;
174 gchar
*get_log_title(LogInstance instance
)
176 return log_instances
[instance
].title
;
179 void set_log_prefs(LogInstance instance
, int* logwin_width
, int* logwin_height
)
181 log_instances
[instance
].prefs_logwin_width
= logwin_width
;
182 log_instances
[instance
].prefs_logwin_height
= logwin_height
;
185 void get_log_prefs(LogInstance instance
, int** logwin_width
, int** logwin_height
)
188 *logwin_width
= log_instances
[instance
].prefs_logwin_width
;
190 *logwin_height
= log_instances
[instance
].prefs_logwin_height
;
193 gboolean
get_log_error_capability(LogInstance instance
)
195 return log_error_capability
[instance
];
199 void log_print(LogInstance instance
, const gchar
*format
, ...)
202 gchar buf
[BUFFSIZE
+ LOG_TIME_LEN
];
204 LogText
*logtext
= g_new0(LogText
, 1);
208 strftime(buf
, LOG_TIME_LEN
+ 1, LOG_TIME_FORMAT
, localtime_r(&t
, &buft
));
210 va_start(args
, format
);
211 g_vsnprintf(buf
+ LOG_TIME_LEN
, BUFFSIZE
, format
, args
);
214 if (debug_get_mode()) g_print("%s", buf
);
216 logtext
->instance
= instance
;
217 logtext
->text
= g_strdup(buf
);
218 logtext
->type
= LOG_NORMAL
;
220 g_timeout_add(0, invoke_hook_cb
, logtext
);
222 if (log_fp
[instance
] && prefs_common_enable_log_standard()) {
223 FPUTS(buf
, log_fp
[instance
])
224 log_size
[instance
] += strlen(buf
);
225 FFLUSH(log_fp
[instance
])
226 rotate_log(instance
);
230 void log_message(LogInstance instance
, const gchar
*format
, ...)
233 gchar buf
[BUFFSIZE
+ LOG_TIME_LEN
];
235 LogText
*logtext
= g_new0(LogText
, 1);
239 strftime(buf
, LOG_TIME_LEN
+ 1, LOG_TIME_FORMAT
, localtime_r(&t
, &buft
));
241 va_start(args
, format
);
242 g_vsnprintf(buf
+ LOG_TIME_LEN
, BUFFSIZE
, format
, args
);
245 if (debug_get_mode()) g_message("%s", buf
+ LOG_TIME_LEN
);
247 logtext
->instance
= instance
;
248 logtext
->text
= g_strdup(buf
+ LOG_TIME_LEN
);
249 logtext
->type
= LOG_MSG
;
251 g_timeout_add(0, invoke_hook_cb
, logtext
);
253 if (log_fp
[instance
] && prefs_common_enable_log_standard()) {
254 FWRITE(buf
, 1, LOG_TIME_LEN
, log_fp
[instance
])
255 FPUTS("* message: ", log_fp
[instance
])
256 log_size
[instance
] += strlen("* message: ");
257 FPUTS(buf
+ LOG_TIME_LEN
, log_fp
[instance
])
258 log_size
[instance
] += strlen(buf
);
259 FFLUSH(log_fp
[instance
])
260 rotate_log(instance
);
264 void log_warning(LogInstance instance
, const gchar
*format
, ...)
267 gchar buf
[BUFFSIZE
+ LOG_TIME_LEN
];
269 LogText
*logtext
= g_new0(LogText
, 1);
273 strftime(buf
, LOG_TIME_LEN
+ 1, LOG_TIME_FORMAT
, localtime_r(&t
, &buft
));
275 va_start(args
, format
);
276 g_vsnprintf(buf
+ LOG_TIME_LEN
, BUFFSIZE
, format
, args
);
279 g_warning("%s", buf
);
281 logtext
->instance
= instance
;
282 logtext
->text
= g_strdup(buf
+ LOG_TIME_LEN
);
283 logtext
->type
= LOG_WARN
;
285 g_timeout_add(0, invoke_hook_cb
, logtext
);
287 if (log_fp
[instance
] && prefs_common_enable_log_warning()) {
288 FWRITE(buf
, 1, LOG_TIME_LEN
, log_fp
[instance
])
289 FPUTS("** warning: ", log_fp
[instance
])
290 log_size
[instance
] += strlen("** warning: ");
291 FPUTS(buf
+ LOG_TIME_LEN
, log_fp
[instance
])
292 log_size
[instance
] += strlen(buf
);
293 FFLUSH(log_fp
[instance
])
294 rotate_log(instance
);
298 void log_error(LogInstance instance
, const gchar
*format
, ...)
301 gchar buf
[BUFFSIZE
+ LOG_TIME_LEN
];
303 LogText
*logtext
= g_new0(LogText
, 1);
307 strftime(buf
, LOG_TIME_LEN
+ 1, LOG_TIME_FORMAT
, localtime_r(&t
, &buft
));
309 va_start(args
, format
);
310 g_vsnprintf(buf
+ LOG_TIME_LEN
, BUFFSIZE
, format
, args
);
313 g_warning("%s", buf
);
315 logtext
->instance
= instance
;
316 logtext
->text
= g_strdup(buf
+ LOG_TIME_LEN
);
317 logtext
->type
= LOG_ERROR
;
319 g_timeout_add(0, invoke_hook_cb
, logtext
);
321 if (log_fp
[instance
] && prefs_common_enable_log_error()) {
322 FWRITE(buf
, 1, LOG_TIME_LEN
, log_fp
[instance
])
323 FPUTS("*** error: ", log_fp
[instance
])
324 log_size
[instance
] += strlen("*** error: ");
325 FPUTS(buf
+ LOG_TIME_LEN
, log_fp
[instance
])
326 log_size
[instance
] += strlen(buf
);
327 FFLUSH(log_fp
[instance
])
328 rotate_log(instance
);
332 void log_status_ok(LogInstance instance
, const gchar
*format
, ...)
335 gchar buf
[BUFFSIZE
+ LOG_TIME_LEN
];
337 LogText
*logtext
= g_new0(LogText
, 1);
341 strftime(buf
, LOG_TIME_LEN
+ 1, LOG_TIME_FORMAT
, localtime_r(&t
, &buft
));
343 va_start(args
, format
);
344 g_vsnprintf(buf
+ LOG_TIME_LEN
, BUFFSIZE
, format
, args
);
347 if (debug_get_mode()) g_message("%s", buf
+ LOG_TIME_LEN
);
349 logtext
->instance
= instance
;
350 logtext
->text
= g_strdup(buf
+ LOG_TIME_LEN
);
351 logtext
->type
= LOG_STATUS_OK
;
353 g_timeout_add(0, invoke_hook_cb
, logtext
);
355 if (log_fp
[instance
] && prefs_common_enable_log_status()) {
356 FWRITE(buf
, 1, LOG_TIME_LEN
, log_fp
[instance
])
357 FPUTS("* OK: ", log_fp
[instance
])
358 log_size
[instance
] += strlen("* OK: ");
359 FPUTS(buf
+ LOG_TIME_LEN
, log_fp
[instance
])
360 log_size
[instance
] += strlen(buf
);
361 FFLUSH(log_fp
[instance
])
362 rotate_log(instance
);
366 void log_status_nok(LogInstance instance
, const gchar
*format
, ...)
369 gchar buf
[BUFFSIZE
+ LOG_TIME_LEN
];
371 LogText
*logtext
= g_new0(LogText
, 1);
375 strftime(buf
, LOG_TIME_LEN
+ 1, LOG_TIME_FORMAT
, localtime_r(&t
, &buft
));
377 va_start(args
, format
);
378 g_vsnprintf(buf
+ LOG_TIME_LEN
, BUFFSIZE
, format
, args
);
381 if (debug_get_mode()) g_message("%s", buf
+ LOG_TIME_LEN
);
383 logtext
->instance
= instance
;
384 logtext
->text
= g_strdup(buf
+ LOG_TIME_LEN
);
385 logtext
->type
= LOG_STATUS_NOK
;
387 g_timeout_add(0, invoke_hook_cb
, logtext
);
389 if (log_fp
[instance
] && prefs_common_enable_log_status()) {
390 FWRITE(buf
, 1, LOG_TIME_LEN
, log_fp
[instance
])
391 FPUTS("* NOT OK: ", log_fp
[instance
])
392 log_size
[instance
] += strlen("* NOT OK: ");
393 FPUTS(buf
+ LOG_TIME_LEN
, log_fp
[instance
])
394 log_size
[instance
] += strlen(buf
);
395 FFLUSH(log_fp
[instance
])
396 rotate_log(instance
);
400 void log_status_skip(LogInstance instance
, const gchar
*format
, ...)
403 gchar buf
[BUFFSIZE
+ LOG_TIME_LEN
];
405 LogText
*logtext
= g_new0(LogText
, 1);
409 strftime(buf
, LOG_TIME_LEN
+ 1, LOG_TIME_FORMAT
, localtime_r(&t
, &buft
));
411 va_start(args
, format
);
412 g_vsnprintf(buf
+ LOG_TIME_LEN
, BUFFSIZE
, format
, args
);
415 if (debug_get_mode()) g_message("%s", buf
+ LOG_TIME_LEN
);
417 logtext
->instance
= instance
;
418 logtext
->text
= g_strdup(buf
+ LOG_TIME_LEN
);
419 logtext
->type
= LOG_STATUS_SKIP
;
421 g_timeout_add(0, invoke_hook_cb
, logtext
);
423 if (log_fp
[instance
] && prefs_common_enable_log_status()) {
424 FWRITE(buf
, 1, LOG_TIME_LEN
, log_fp
[instance
])
425 FPUTS("* SKIPPED: ", log_fp
[instance
])
426 log_size
[instance
] += strlen("* SKIPPED: ");
427 FPUTS(buf
+ LOG_TIME_LEN
, log_fp
[instance
])
428 log_size
[instance
] += strlen(buf
);
429 FFLUSH(log_fp
[instance
])
430 rotate_log(instance
);