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"
28 #include <glib/gi18n.h>
33 #include "file-utils.h"
35 #define FWRITE(_b,_s,_n,_f) if (fwrite(_b,_s,_n,_f) != _n) { \
36 g_message("log fwrite failed!\n"); \
39 #define FPUTS(_b,_f) if (fputs(_b,_f) == EOF) { \
40 g_message("log fputs failed!\n"); \
43 #define FFLUSH(_f) if (fflush(_f) != 0) { \
44 g_message("log fflush failed!\n"); \
48 static FILE *log_fp
[LOG_INSTANCE_MAX
] = {
53 static size_t log_size
[LOG_INSTANCE_MAX
] = {
58 static gchar
*log_filename
[LOG_INSTANCE_MAX
] = {
64 static gboolean log_error_capability
[LOG_INSTANCE_MAX
] = {
69 typedef struct _LogInstanceData LogInstanceData
;
71 struct _LogInstanceData
{
74 int *prefs_logwin_width
;
75 int *prefs_logwin_height
;
78 static LogInstanceData log_instances
[LOG_INSTANCE_MAX
] = {
79 { LOG_APPEND_TEXT_HOOKLIST
, NULL
, NULL
, NULL
},
80 { DEBUG_FILTERING_APPEND_TEXT_HOOKLIST
, NULL
, NULL
, NULL
}
83 gboolean
prefs_common_enable_log_standard(void);
84 gboolean
prefs_common_enable_log_warning(void);
85 gboolean
prefs_common_enable_log_error(void);
86 gboolean
prefs_common_enable_log_status(void);
88 static gboolean
invoke_hook_cb (gpointer data
)
90 LogText
*logtext
= (LogText
*)data
;
91 hooks_invoke(get_log_hook(logtext
->instance
), logtext
);
92 g_free(logtext
->text
);
97 void set_log_file(LogInstance instance
, const gchar
*filename
)
99 gchar
*fullname
= NULL
;
100 if (log_fp
[instance
])
103 if (!g_path_is_absolute(filename
)) {
104 fullname
= g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S
,
107 fullname
= g_strdup(filename
);
109 /* backup old logfile if existing */
110 if (is_file_exist(fullname
)) {
113 backupname
= g_strconcat(fullname
, ".bak", NULL
);
114 claws_unlink(backupname
);
115 if (g_rename(fullname
, backupname
) < 0)
116 FILE_OP_ERROR(fullname
, "rename");
120 log_fp
[instance
] = fopen(fullname
, "wb");
121 if (!log_fp
[instance
]) {
122 FILE_OP_ERROR(fullname
, "fopen");
123 log_filename
[instance
] = NULL
;
128 if (change_file_mode_rw(log_fp
[instance
], fullname
) < 0) {
129 FILE_OP_ERROR(fullname
, "chmod");
130 g_warning("can't change file mode: %s", fullname
);
133 log_filename
[instance
] = g_strdup(fullname
);
134 log_size
[instance
] = 0;
138 void close_log_file(LogInstance instance
)
140 if (log_fp
[instance
]) {
141 fclose(log_fp
[instance
]);
142 log_fp
[instance
] = NULL
;
143 log_size
[instance
] = 0;
144 g_free(log_filename
[instance
]);
145 log_filename
[instance
] = NULL
;
149 static void rotate_log(LogInstance instance
)
151 if (log_size
[instance
] > 10 * 1024* 1024) {
152 gchar
*filename
= g_strdup(log_filename
[instance
]);
153 debug_print("rotating %s\n", filename
);
154 close_log_file(instance
);
155 set_log_file(instance
, filename
);
160 const char *get_log_hook(LogInstance instance
)
162 return log_instances
[instance
].hook
;
165 void set_log_title(LogInstance instance
, gchar
*title
)
167 log_instances
[instance
].title
= title
;
170 gchar
*get_log_title(LogInstance instance
)
172 return log_instances
[instance
].title
;
175 void set_log_prefs(LogInstance instance
, int* logwin_width
, int* logwin_height
)
177 log_instances
[instance
].prefs_logwin_width
= logwin_width
;
178 log_instances
[instance
].prefs_logwin_height
= logwin_height
;
181 void get_log_prefs(LogInstance instance
, int** logwin_width
, int** logwin_height
)
184 *logwin_width
= log_instances
[instance
].prefs_logwin_width
;
186 *logwin_height
= log_instances
[instance
].prefs_logwin_height
;
189 gboolean
get_log_error_capability(LogInstance instance
)
191 return log_error_capability
[instance
];
195 void log_print(LogInstance instance
, const gchar
*format
, ...)
198 gchar buf
[BUFFSIZE
+ LOG_TIME_LEN
];
200 LogText
*logtext
= g_new0(LogText
, 1);
204 strftime(buf
, LOG_TIME_LEN
+ 1, LOG_TIME_FORMAT
, localtime_r(&t
, &buft
));
206 va_start(args
, format
);
207 g_vsnprintf(buf
+ LOG_TIME_LEN
, BUFFSIZE
, format
, args
);
210 if (debug_get_mode()) g_print("%s", buf
);
212 logtext
->instance
= instance
;
213 logtext
->text
= g_strdup(buf
);
214 logtext
->type
= LOG_NORMAL
;
216 g_timeout_add(0, invoke_hook_cb
, logtext
);
218 if (log_fp
[instance
] && prefs_common_enable_log_standard()) {
219 FPUTS(buf
, log_fp
[instance
])
220 log_size
[instance
] += strlen(buf
);
221 FFLUSH(log_fp
[instance
])
222 rotate_log(instance
);
226 void log_message(LogInstance instance
, const gchar
*format
, ...)
229 gchar buf
[BUFFSIZE
+ LOG_TIME_LEN
];
231 LogText
*logtext
= g_new0(LogText
, 1);
235 strftime(buf
, LOG_TIME_LEN
+ 1, LOG_TIME_FORMAT
, localtime_r(&t
, &buft
));
237 va_start(args
, format
);
238 g_vsnprintf(buf
+ LOG_TIME_LEN
, BUFFSIZE
, format
, args
);
241 if (debug_get_mode()) g_message("%s", buf
+ LOG_TIME_LEN
);
243 logtext
->instance
= instance
;
244 logtext
->text
= g_strdup(buf
+ LOG_TIME_LEN
);
245 logtext
->type
= LOG_MSG
;
247 g_timeout_add(0, invoke_hook_cb
, logtext
);
249 if (log_fp
[instance
] && prefs_common_enable_log_standard()) {
250 FWRITE(buf
, 1, LOG_TIME_LEN
, log_fp
[instance
])
251 FPUTS("* message: ", log_fp
[instance
])
252 log_size
[instance
] += strlen("* message: ");
253 FPUTS(buf
+ LOG_TIME_LEN
, log_fp
[instance
])
254 log_size
[instance
] += strlen(buf
);
255 FFLUSH(log_fp
[instance
])
256 rotate_log(instance
);
260 void log_warning(LogInstance instance
, const gchar
*format
, ...)
263 gchar buf
[BUFFSIZE
+ LOG_TIME_LEN
];
265 LogText
*logtext
= g_new0(LogText
, 1);
269 strftime(buf
, LOG_TIME_LEN
+ 1, LOG_TIME_FORMAT
, localtime_r(&t
, &buft
));
271 va_start(args
, format
);
272 g_vsnprintf(buf
+ LOG_TIME_LEN
, BUFFSIZE
, format
, args
);
275 g_warning("%s", buf
);
277 logtext
->instance
= instance
;
278 logtext
->text
= g_strdup(buf
+ LOG_TIME_LEN
);
279 logtext
->type
= LOG_WARN
;
281 g_timeout_add(0, invoke_hook_cb
, logtext
);
283 if (log_fp
[instance
] && prefs_common_enable_log_warning()) {
284 FWRITE(buf
, 1, LOG_TIME_LEN
, log_fp
[instance
])
285 FPUTS("** warning: ", log_fp
[instance
])
286 log_size
[instance
] += strlen("** warning: ");
287 FPUTS(buf
+ LOG_TIME_LEN
, log_fp
[instance
])
288 log_size
[instance
] += strlen(buf
);
289 FFLUSH(log_fp
[instance
])
290 rotate_log(instance
);
294 void log_error(LogInstance instance
, const gchar
*format
, ...)
297 gchar buf
[BUFFSIZE
+ LOG_TIME_LEN
];
299 LogText
*logtext
= g_new0(LogText
, 1);
303 strftime(buf
, LOG_TIME_LEN
+ 1, LOG_TIME_FORMAT
, localtime_r(&t
, &buft
));
305 va_start(args
, format
);
306 g_vsnprintf(buf
+ LOG_TIME_LEN
, BUFFSIZE
, format
, args
);
309 g_warning("%s", buf
);
311 logtext
->instance
= instance
;
312 logtext
->text
= g_strdup(buf
+ LOG_TIME_LEN
);
313 logtext
->type
= LOG_ERROR
;
315 g_timeout_add(0, invoke_hook_cb
, logtext
);
317 if (log_fp
[instance
] && prefs_common_enable_log_error()) {
318 FWRITE(buf
, 1, LOG_TIME_LEN
, log_fp
[instance
])
319 FPUTS("*** error: ", log_fp
[instance
])
320 log_size
[instance
] += strlen("*** error: ");
321 FPUTS(buf
+ LOG_TIME_LEN
, log_fp
[instance
])
322 log_size
[instance
] += strlen(buf
);
323 FFLUSH(log_fp
[instance
])
324 rotate_log(instance
);
328 void log_status_ok(LogInstance instance
, const gchar
*format
, ...)
331 gchar buf
[BUFFSIZE
+ LOG_TIME_LEN
];
333 LogText
*logtext
= g_new0(LogText
, 1);
337 strftime(buf
, LOG_TIME_LEN
+ 1, LOG_TIME_FORMAT
, localtime_r(&t
, &buft
));
339 va_start(args
, format
);
340 g_vsnprintf(buf
+ LOG_TIME_LEN
, BUFFSIZE
, format
, args
);
343 if (debug_get_mode()) g_message("%s", buf
+ LOG_TIME_LEN
);
345 logtext
->instance
= instance
;
346 logtext
->text
= g_strdup(buf
+ LOG_TIME_LEN
);
347 logtext
->type
= LOG_STATUS_OK
;
349 g_timeout_add(0, invoke_hook_cb
, logtext
);
351 if (log_fp
[instance
] && prefs_common_enable_log_status()) {
352 FWRITE(buf
, 1, LOG_TIME_LEN
, log_fp
[instance
])
353 FPUTS("* OK: ", log_fp
[instance
])
354 log_size
[instance
] += strlen("* OK: ");
355 FPUTS(buf
+ LOG_TIME_LEN
, log_fp
[instance
])
356 log_size
[instance
] += strlen(buf
);
357 FFLUSH(log_fp
[instance
])
358 rotate_log(instance
);
362 void log_status_nok(LogInstance instance
, const gchar
*format
, ...)
365 gchar buf
[BUFFSIZE
+ LOG_TIME_LEN
];
367 LogText
*logtext
= g_new0(LogText
, 1);
371 strftime(buf
, LOG_TIME_LEN
+ 1, LOG_TIME_FORMAT
, localtime_r(&t
, &buft
));
373 va_start(args
, format
);
374 g_vsnprintf(buf
+ LOG_TIME_LEN
, BUFFSIZE
, format
, args
);
377 if (debug_get_mode()) g_message("%s", buf
+ LOG_TIME_LEN
);
379 logtext
->instance
= instance
;
380 logtext
->text
= g_strdup(buf
+ LOG_TIME_LEN
);
381 logtext
->type
= LOG_STATUS_NOK
;
383 g_timeout_add(0, invoke_hook_cb
, logtext
);
385 if (log_fp
[instance
] && prefs_common_enable_log_status()) {
386 FWRITE(buf
, 1, LOG_TIME_LEN
, log_fp
[instance
])
387 FPUTS("* NOT OK: ", log_fp
[instance
])
388 log_size
[instance
] += strlen("* NOT OK: ");
389 FPUTS(buf
+ LOG_TIME_LEN
, log_fp
[instance
])
390 log_size
[instance
] += strlen(buf
);
391 FFLUSH(log_fp
[instance
])
392 rotate_log(instance
);
396 void log_status_skip(LogInstance instance
, const gchar
*format
, ...)
399 gchar buf
[BUFFSIZE
+ LOG_TIME_LEN
];
401 LogText
*logtext
= g_new0(LogText
, 1);
405 strftime(buf
, LOG_TIME_LEN
+ 1, LOG_TIME_FORMAT
, localtime_r(&t
, &buft
));
407 va_start(args
, format
);
408 g_vsnprintf(buf
+ LOG_TIME_LEN
, BUFFSIZE
, format
, args
);
411 if (debug_get_mode()) g_message("%s", buf
+ LOG_TIME_LEN
);
413 logtext
->instance
= instance
;
414 logtext
->text
= g_strdup(buf
+ LOG_TIME_LEN
);
415 logtext
->type
= LOG_STATUS_SKIP
;
417 g_timeout_add(0, invoke_hook_cb
, logtext
);
419 if (log_fp
[instance
] && prefs_common_enable_log_status()) {
420 FWRITE(buf
, 1, LOG_TIME_LEN
, log_fp
[instance
])
421 FPUTS("* SKIPPED: ", log_fp
[instance
])
422 log_size
[instance
] += strlen("* SKIPPED: ");
423 FPUTS(buf
+ LOG_TIME_LEN
, log_fp
[instance
])
424 log_size
[instance
] += strlen(buf
);
425 FFLUSH(log_fp
[instance
])
426 rotate_log(instance
);