talons

Fork of Claws Mail https://www.claws-mail
Log | Files | Refs | README | LICENSE

log.c (7600B)


      1 /*
      2  * Claws Mail -- a GTK based, lightweight, and fast e-mail client
      3  * Copyright (C) 1999-2021 the Claws Mail team and Hiroyuki Yamamoto
      4  *
      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.
      9  *
     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.
     14  *
     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/>.
     17  *
     18  */
     19 
     20 #include "defs.h"
     21 
     22 #include <glib.h>
     23 #include <glib/gi18n.h>
     24 
     25 #include "utils.h"
     26 #include "log.h"
     27 #include "hooks.h"
     28 #include "file-utils.h"
     29 
     30 #define FWRITE(_b,_s,_n,_f)	if (fwrite(_b,_s,_n,_f) != _n) { \
     31 					g_message("log fwrite failed!\n"); \
     32 					return; \
     33 				}
     34 #define FPUTS(_b,_f)		if (fputs(_b,_f) == EOF) { \
     35 					g_message("log fputs failed!\n"); \
     36 					return; \
     37 				}
     38 #define FFLUSH(_f)		if (fflush(_f) != 0) { \
     39 					g_message("log fflush failed!\n"); \
     40 					return; \
     41 				}
     42 
     43 static FILE *log_fp[LOG_INSTANCE_MAX] = {
     44 	NULL,
     45 	NULL
     46 };
     47 
     48 static size_t log_size[LOG_INSTANCE_MAX] = {
     49 	0,
     50 	0
     51 };
     52 
     53 static gchar *log_filename[LOG_INSTANCE_MAX] = {
     54 	NULL,
     55 	NULL
     56 };
     57 
     58 /* read-only */
     59 static gboolean log_error_capability[LOG_INSTANCE_MAX] = {
     60 	TRUE,
     61 	FALSE
     62 };
     63 
     64 typedef struct _LogInstanceData LogInstanceData;
     65 
     66 struct _LogInstanceData {
     67 	const char *hook;
     68 	gchar *title;
     69 	int *prefs_logwin_width;
     70 	int *prefs_logwin_height;
     71 };
     72 
     73 static LogInstanceData log_instances[LOG_INSTANCE_MAX] = {
     74 	{ LOG_APPEND_TEXT_HOOKLIST, NULL, NULL, NULL },
     75 	{ DEBUG_FILTERING_APPEND_TEXT_HOOKLIST, NULL, NULL, NULL }
     76 };
     77 
     78 static gboolean invoke_hook_cb (gpointer data)
     79 {
     80 	LogText *logtext = (LogText *)data;
     81 	hooks_invoke(get_log_hook(logtext->instance), logtext);
     82 	g_free(logtext->text);
     83 	g_free(logtext);
     84 	return FALSE;
     85 }
     86 
     87 void set_log_file(LogInstance instance, const gchar *filename)
     88 {
     89 	gchar *fullname = NULL;
     90 	if (log_fp[instance])
     91 		return;
     92 
     93 	if (!g_path_is_absolute(filename)) {
     94 		fullname = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
     95 					filename, NULL);
     96 	} else {
     97 		fullname = g_strdup(filename);
     98 	}
     99 	/* backup old logfile if existing */
    100 	if (is_file_exist(fullname)) {
    101 		gchar *backupname;
    102 
    103 		backupname = g_strconcat(fullname, ".bak", NULL);
    104 		unlink(backupname);
    105 		if (g_rename(fullname, backupname) < 0)
    106 			FILE_OP_ERROR(fullname, "rename");
    107 		g_free(backupname);
    108 	}
    109 
    110 	log_fp[instance] = fopen(fullname, "wb");
    111 	if (!log_fp[instance]) {
    112 		FILE_OP_ERROR(fullname, "fopen");
    113 		log_filename[instance] = NULL;
    114 		g_free(fullname);
    115 		return;
    116 	}
    117 
    118 	log_filename[instance] = g_strdup(fullname);
    119 	log_size[instance] = 0;
    120 	g_free(fullname);
    121 }
    122 
    123 void close_log_file(LogInstance instance)
    124 {
    125 	if (log_fp[instance]) {
    126 		fclose(log_fp[instance]);
    127 		log_fp[instance] = NULL;
    128 		log_size[instance] = 0;
    129 		g_free(log_filename[instance]);
    130 		log_filename[instance] = NULL;
    131 	}
    132 }
    133 
    134 static void rotate_log(LogInstance instance)
    135 {
    136 	if (log_size[instance] > 10 * 1024* 1024) {
    137 		gchar *filename = g_strdup(log_filename[instance]);
    138 		debug_print("rotating %s\n", filename);
    139 		close_log_file(instance);
    140 		set_log_file(instance, filename);
    141 		g_free(filename);
    142 	}
    143 }
    144 
    145 const char *get_log_hook(LogInstance instance)
    146 {
    147 	return log_instances[instance].hook;
    148 }
    149 
    150 void set_log_title(LogInstance instance, gchar *title)
    151 {
    152 	log_instances[instance].title = title;
    153 }
    154 
    155 gchar *get_log_title(LogInstance instance)
    156 {
    157 	return log_instances[instance].title;
    158 }
    159 
    160 void set_log_prefs(LogInstance instance, int* logwin_width, int* logwin_height)
    161 {
    162 	log_instances[instance].prefs_logwin_width = logwin_width;
    163 	log_instances[instance].prefs_logwin_height = logwin_height;
    164 }
    165 
    166 void get_log_prefs(LogInstance instance, int** logwin_width, int** logwin_height)
    167 {
    168 	if (logwin_width)
    169 		*logwin_width = log_instances[instance].prefs_logwin_width;
    170 	if (logwin_height)
    171 		*logwin_height = log_instances[instance].prefs_logwin_height;
    172 }
    173 
    174 gboolean get_log_error_capability(LogInstance instance)
    175 {
    176 	return log_error_capability[instance];
    177 
    178 }
    179 
    180 void log_print(LogInstance instance, const gchar *format, ...)
    181 {
    182 	va_list args;
    183 	gchar buf[BUFFSIZE + LOG_TIME_LEN];
    184 	time_t t;
    185 	LogText *logtext = g_new0(LogText, 1);
    186 	struct tm buft;
    187 
    188 	time(&t);
    189 	strftime(buf, LOG_TIME_LEN + 1, LOG_TIME_FORMAT, localtime_r(&t, &buft));
    190 
    191 	va_start(args, format);
    192 	g_vsnprintf(buf + LOG_TIME_LEN, BUFFSIZE, format, args);
    193 	va_end(args);
    194 
    195 	if (debug_get_mode()) g_print("%s", buf);
    196 
    197 	logtext->instance = instance;
    198 	logtext->text = g_strdup(buf);
    199 	logtext->type = LOG_NORMAL;
    200 
    201 	g_timeout_add(0, invoke_hook_cb, logtext);
    202 
    203 	if (log_fp[instance]) {
    204 		FPUTS(buf, log_fp[instance])
    205 		log_size[instance] += strlen(buf);
    206 		FFLUSH(log_fp[instance])
    207 		rotate_log(instance);
    208 	}
    209 }
    210 
    211 void log_message(LogInstance instance, const gchar *format, ...)
    212 {
    213 	va_list args;
    214 	gchar buf[BUFFSIZE + LOG_TIME_LEN];
    215 	time_t t;
    216 	LogText *logtext = g_new0(LogText, 1);
    217 	struct tm buft;
    218 
    219 	time(&t);
    220 	strftime(buf, LOG_TIME_LEN + 1, LOG_TIME_FORMAT, localtime_r(&t, &buft));
    221 
    222 	va_start(args, format);
    223 	g_vsnprintf(buf + LOG_TIME_LEN, BUFFSIZE, format, args);
    224 	va_end(args);
    225 
    226 	if (debug_get_mode()) g_message("%s", buf + LOG_TIME_LEN);
    227 
    228 	logtext->instance = instance;
    229 	logtext->text = g_strdup(buf + LOG_TIME_LEN);
    230 	logtext->type = LOG_MSG;
    231 
    232 	g_timeout_add(0, invoke_hook_cb, logtext);
    233 
    234 	if (log_fp[instance]) {
    235 		FWRITE(buf, 1, LOG_TIME_LEN, log_fp[instance])
    236 		FPUTS("* message: ", log_fp[instance])
    237 		log_size[instance] += strlen("* message: ");
    238 		FPUTS(buf + LOG_TIME_LEN, log_fp[instance])
    239 		log_size[instance] += strlen(buf);
    240 		FFLUSH(log_fp[instance])
    241 		rotate_log(instance);
    242 	}
    243 }
    244 
    245 void log_warning(LogInstance instance, const gchar *format, ...)
    246 {
    247 	va_list args;
    248 	gchar buf[BUFFSIZE + LOG_TIME_LEN];
    249 	time_t t;
    250 	LogText *logtext = g_new0(LogText, 1);
    251 	struct tm buft;
    252 
    253 	time(&t);
    254 	strftime(buf, LOG_TIME_LEN + 1, LOG_TIME_FORMAT, localtime_r(&t, &buft));
    255 
    256 	va_start(args, format);
    257 	g_vsnprintf(buf + LOG_TIME_LEN, BUFFSIZE, format, args);
    258 	va_end(args);
    259 
    260 	g_warning("%s", buf);
    261 
    262 	logtext->instance = instance;
    263 	logtext->text = g_strdup(buf + LOG_TIME_LEN);
    264 	logtext->type = LOG_WARN;
    265 
    266 	g_timeout_add(0, invoke_hook_cb, logtext);
    267 
    268 	if (log_fp[instance]) {
    269 		FWRITE(buf, 1, LOG_TIME_LEN, log_fp[instance])
    270 		FPUTS("** warning: ", log_fp[instance])
    271 		log_size[instance] += strlen("** warning: ");
    272 		FPUTS(buf + LOG_TIME_LEN, log_fp[instance])
    273 		log_size[instance] += strlen(buf);
    274 		FFLUSH(log_fp[instance])
    275 		rotate_log(instance);
    276 	}
    277 }
    278 
    279 void log_error(LogInstance instance, const gchar *format, ...)
    280 {
    281 	va_list args;
    282 	gchar buf[BUFFSIZE + LOG_TIME_LEN];
    283 	time_t t;
    284 	LogText *logtext = g_new0(LogText, 1);
    285 	struct tm buft;
    286 
    287 	time(&t);
    288 	strftime(buf, LOG_TIME_LEN + 1, LOG_TIME_FORMAT, localtime_r(&t, &buft));
    289 
    290 	va_start(args, format);
    291 	g_vsnprintf(buf + LOG_TIME_LEN, BUFFSIZE, format, args);
    292 	va_end(args);
    293 
    294 	g_warning("%s", buf);
    295 
    296 	logtext->instance = instance;
    297 	logtext->text = g_strdup(buf + LOG_TIME_LEN);
    298 	logtext->type = LOG_ERROR;
    299 
    300 	g_timeout_add(0, invoke_hook_cb, logtext);
    301 
    302 	if (log_fp[instance]) {
    303 		FWRITE(buf, 1, LOG_TIME_LEN, log_fp[instance])
    304 		FPUTS("*** error: ", log_fp[instance])
    305 		log_size[instance] += strlen("*** error: ");
    306 		FPUTS(buf + LOG_TIME_LEN, log_fp[instance])
    307 		log_size[instance] += strlen(buf);
    308 		FFLUSH(log_fp[instance])
    309 		rotate_log(instance);
    310 	}
    311 }
    312 
    313 #undef FWRITE
    314 #undef FPUTS
    315 #undef FFLUSH
    316