Mercurial > pidgin.yaz
annotate src/log.c @ 9763:b85df3f44350
[gaim-migrate @ 10631]
"Can someone test this patch, diff'ed with 0.81 (anoncvs is
down, as usual).
http://javabsp.org/software/gaim/syslog_fd_leak.diff
This keeps the double .system 0 length files from being
created everytime you list the system log, which for some
reason aren't closed (although reading from the code, they
should be). Anyhow, since they are not created anymore, they
won't waste any fd's.
Another change that I've made, previously gaim is logging
chats to
logs/<prpl>/<my sn>.chat/<chatroom name>/<date-time>, now
it's logging to logs/<prpl>/<my sn>/<chatroom
name>.chat>/<date-time>. I think this makes more sense.
Oh, and gaim_normalize is not meant to be called a second
time while expecting the value of the first call to remain
what it should be." --Ka-Hing Cheung
committer: Tailor Script <tailor@pidgin.im>
author | Luke Schierer <lschiere@pidgin.im> |
---|---|
date | Mon, 16 Aug 2004 03:24:00 +0000 |
parents | 70ff55c0939b |
children | 34b468bdc1c5 |
rev | line source |
---|---|
7431 | 1 /** |
2 * @file log.c Logging API | |
3 * @ingroup core | |
4 * | |
5 * gaim | |
6 * | |
8046 | 7 * Gaim is the legal property of its developers, whose names are too numerous |
8 * to list here. Please refer to the COPYRIGHT file distributed with this | |
9 * source distribution. | |
7436 | 10 * |
7431 | 11 * This program is free software; you can redistribute it and/or modify |
12 * it under the terms of the GNU General Public License as published by | |
13 * the Free Software Foundation; either version 2 of the License, or | |
14 * (at your option) any later version. | |
15 * | |
16 * This program is distributed in the hope that it will be useful, | |
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 * GNU General Public License for more details. | |
20 * | |
21 * You should have received a copy of the GNU General Public License | |
22 * along with this program; if not, write to the Free Software | |
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
4184 | 24 */ |
4195 | 25 |
7431 | 26 #include "account.h" |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5839
diff
changeset
|
27 #include "debug.h" |
7431 | 28 #include "internal.h" |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5839
diff
changeset
|
29 #include "log.h" |
5548 | 30 #include "prefs.h" |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5839
diff
changeset
|
31 #include "util.h" |
7764 | 32 #include "stringref.h" |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5839
diff
changeset
|
33 |
8096 | 34 static GSList *loggers = NULL; |
35 | |
7457 | 36 static GaimLogLogger html_logger; |
7431 | 37 static GaimLogLogger txt_logger; |
38 static GaimLogLogger old_logger; | |
5872
059d95c67cda
[gaim-migrate @ 6304]
Christian Hammond <chipx86@chipx86.com>
parents:
5839
diff
changeset
|
39 |
8635 | 40 struct _gaim_logsize_user { |
41 char *name; | |
42 GaimAccount *account; | |
43 }; | |
44 static GHashTable *logsize_users = NULL; | |
45 | |
46 | |
7431 | 47 /************************************************************************** |
48 * PUBLIC LOGGING FUNCTIONS *********************************************** | |
49 **************************************************************************/ | |
4184 | 50 |
7431 | 51 GaimLog *gaim_log_new(GaimLogType type, const char *name, GaimAccount *account, time_t time) |
52 { | |
53 GaimLog *log = g_new0(GaimLog, 1); | |
8635 | 54 log->name = g_strdup(gaim_normalize(account, name)); |
7431 | 55 log->account = account; |
56 log->time = time; | |
8573 | 57 log->type = type; |
8096 | 58 log->logger_data = NULL; |
7431 | 59 log->logger = gaim_log_logger_get(); |
7440 | 60 if (log->logger && log->logger->create) |
61 log->logger->create(log); | |
7431 | 62 return log; |
4184 | 63 } |
64 | |
7431 | 65 void gaim_log_free(GaimLog *log) |
4184 | 66 { |
7431 | 67 g_return_if_fail(log); |
68 if (log->logger && log->logger->finalize) | |
69 log->logger->finalize(log); | |
70 g_free(log->name); | |
71 g_free(log); | |
72 } | |
7436 | 73 |
74 void gaim_log_write(GaimLog *log, GaimMessageFlags type, | |
7431 | 75 const char *from, time_t time, const char *message) |
76 { | |
8635 | 77 struct _gaim_logsize_user lu; |
78 | |
7431 | 79 g_return_if_fail(log); |
80 g_return_if_fail(log->logger); | |
7442 | 81 g_return_if_fail(log->logger->write); |
7431 | 82 |
8635 | 83 if ((log->type == GAIM_LOG_IM && |
84 gaim_prefs_get_bool("/core/logging/log_ims")) || | |
85 (log->type == GAIM_LOG_CHAT && | |
86 gaim_prefs_get_bool("/core/logging/log_chats")) || | |
87 (log->type == GAIM_LOG_SYSTEM && | |
88 gaim_prefs_get_bool("/core/logging/log_system"))) { | |
7553 | 89 (log->logger->write)(log, type, from, time, message); |
8635 | 90 lu.name = g_strdup(gaim_normalize(log->account, log->name)); |
91 lu.account = log->account; | |
92 g_hash_table_remove(logsize_users, &lu); | |
93 g_free(lu.name); | |
94 } | |
4184 | 95 } |
96 | |
7431 | 97 char *gaim_log_read(GaimLog *log, GaimLogReadFlags *flags) |
4184 | 98 { |
7542 | 99 GaimLogReadFlags mflags; |
7431 | 100 g_return_val_if_fail(log && log->logger, NULL); |
7462 | 101 if (log->logger->read) { |
7535 | 102 char *ret = (log->logger->read)(log, flags ? flags : &mflags); |
7478
3c21f3084ff0
[gaim-migrate @ 8091]
Herman Bloggs <hermanator12002@yahoo.com>
parents:
7473
diff
changeset
|
103 gaim_str_strip_cr(ret); |
7462 | 104 return ret; |
105 } | |
7470 | 106 return (_("<b><font color=\"red\">The logger has no read function</font></b>")); |
4184 | 107 } |
7616 | 108 |
7556 | 109 int gaim_log_get_size(GaimLog *log) |
110 { | |
111 g_return_val_if_fail(log && log->logger, 0); | |
8096 | 112 |
7556 | 113 if (log->logger->size) |
114 return log->logger->size(log); | |
115 return 0; | |
116 } | |
117 | |
8635 | 118 static guint _gaim_logsize_user_hash(struct _gaim_logsize_user *lu) |
119 { | |
120 return g_str_hash(lu->name); | |
121 } | |
122 | |
123 static guint _gaim_logsize_user_equal(struct _gaim_logsize_user *lu1, | |
124 struct _gaim_logsize_user *lu2) | |
125 { | |
126 return ((!strcmp(lu1->name, lu2->name)) && lu1->account == lu2->account); | |
127 } | |
128 | |
129 static void _gaim_logsize_user_free_key(struct _gaim_logsize_user *lu) | |
130 { | |
131 g_free(lu->name); | |
132 g_free(lu); | |
133 } | |
134 | |
8898 | 135 int gaim_log_get_total_size(GaimLogType type, const char *name, GaimAccount *account) |
7556 | 136 { |
9677 | 137 gpointer ptrsize; |
138 int size = 0; | |
8096 | 139 GSList *n; |
8635 | 140 struct _gaim_logsize_user *lu; |
8096 | 141 |
8635 | 142 lu = g_new(struct _gaim_logsize_user, 1); |
143 lu->name = g_strdup(gaim_normalize(account, name)); | |
144 lu->account = account; | |
145 | |
9677 | 146 if(g_hash_table_lookup_extended(logsize_users, lu, NULL, &ptrsize)) { |
147 size = GPOINTER_TO_INT(ptrsize); | |
8635 | 148 g_free(lu->name); |
149 g_free(lu); | |
150 } else { | |
151 for (n = loggers; n; n = n->next) { | |
152 GaimLogLogger *logger = n->data; | |
7616 | 153 |
8635 | 154 if(logger->total_size){ |
8898 | 155 size += (logger->total_size)(type, name, account); |
8635 | 156 } else if(logger->list) { |
8898 | 157 GList *logs = (logger->list)(type, name, account); |
8635 | 158 int this_size = 0; |
159 | |
160 while (logs) { | |
161 GList *logs2 = logs->next; | |
162 GaimLog *log = (GaimLog*)(logs->data); | |
163 this_size += gaim_log_get_size(log); | |
164 gaim_log_free(log); | |
165 g_list_free_1(logs); | |
166 logs = logs2; | |
167 } | |
168 | |
169 size += this_size; | |
8096 | 170 } |
8635 | 171 } |
8096 | 172 |
8635 | 173 g_hash_table_replace(logsize_users, lu, GINT_TO_POINTER(size)); |
7556 | 174 } |
175 return size; | |
176 } | |
4184 | 177 |
7431 | 178 /**************************************************************************** |
179 * LOGGER FUNCTIONS ********************************************************* | |
180 ****************************************************************************/ | |
4184 | 181 |
7431 | 182 static GaimLogLogger *current_logger = NULL; |
7436 | 183 |
7431 | 184 static void logger_pref_cb(const char *name, GaimPrefType type, |
185 gpointer value, gpointer data) | |
186 { | |
187 GaimLogLogger *logger; | |
188 GSList *l = loggers; | |
189 while (l) { | |
190 logger = l->data; | |
191 if (!strcmp(logger->id, value)) { | |
192 gaim_log_logger_set(logger); | |
193 return; | |
4184 | 194 } |
7431 | 195 l = l->next; |
196 } | |
197 gaim_log_logger_set(&txt_logger); | |
198 } | |
4184 | 199 |
200 | |
8898 | 201 GaimLogLogger *gaim_log_logger_new( |
202 void(*create)(GaimLog *), | |
203 void(*write)(GaimLog *, GaimMessageFlags, const char *, time_t, const char *), | |
204 void(*finalize)(GaimLog *), | |
205 GList*(*list)(GaimLogType type, const char*, GaimAccount*), | |
206 char*(*read)(GaimLog*, GaimLogReadFlags*), | |
207 int(*size)(GaimLog*)) | |
7431 | 208 { |
209 GaimLogLogger *logger = g_new0(GaimLogLogger, 1); | |
7440 | 210 logger->create = create; |
7431 | 211 logger->write = write; |
212 logger->finalize = finalize; | |
213 logger->list = list; | |
214 logger->read = read; | |
7556 | 215 logger->size = size; |
7431 | 216 return logger; |
4184 | 217 } |
218 | |
7431 | 219 void gaim_log_logger_free(GaimLogLogger *logger) |
4184 | 220 { |
7431 | 221 g_free(logger); |
222 } | |
4184 | 223 |
7431 | 224 void gaim_log_logger_add (GaimLogLogger *logger) |
225 { | |
226 g_return_if_fail(logger); | |
227 if (g_slist_find(loggers, logger)) | |
228 return; | |
229 loggers = g_slist_append(loggers, logger); | |
230 } | |
231 | |
232 void gaim_log_logger_remove (GaimLogLogger *logger) | |
233 { | |
234 g_return_if_fail(logger); | |
235 g_slist_remove(loggers, logger); | |
4184 | 236 } |
237 | |
7431 | 238 void gaim_log_logger_set (GaimLogLogger *logger) |
4184 | 239 { |
7431 | 240 g_return_if_fail(logger); |
241 current_logger = logger; | |
7436 | 242 } |
4184 | 243 |
7431 | 244 GaimLogLogger *gaim_log_logger_get() |
245 { | |
246 return current_logger; | |
247 } | |
4184 | 248 |
7431 | 249 GList *gaim_log_logger_get_options(void) |
250 { | |
251 GSList *n; | |
252 GList *list = NULL; | |
253 GaimLogLogger *data; | |
4184 | 254 |
7431 | 255 for (n = loggers; n; n = n->next) { |
256 data = n->data; | |
257 if (!data->write) | |
258 continue; | |
7494 | 259 list = g_list_append(list, _(data->name)); |
7431 | 260 list = g_list_append(list, data->id); |
4184 | 261 } |
262 | |
7431 | 263 return list; |
264 } | |
265 | |
8573 | 266 gint gaim_log_compare(gconstpointer y, gconstpointer z) |
7431 | 267 { |
7436 | 268 const GaimLog *a = y; |
269 const GaimLog *b = z; | |
270 | |
7431 | 271 return b->time - a->time; |
272 } | |
273 | |
8898 | 274 GList *gaim_log_get_logs(GaimLogType type, const char *name, GaimAccount *account) |
7431 | 275 { |
276 GList *logs = NULL; | |
277 GSList *n; | |
278 for (n = loggers; n; n = n->next) { | |
279 GaimLogLogger *logger = n->data; | |
280 if (!logger->list) | |
281 continue; | |
8898 | 282 logs = g_list_concat(logs, logger->list(type, name, account)); |
7431 | 283 } |
7436 | 284 |
8573 | 285 return g_list_sort(logs, gaim_log_compare); |
286 } | |
287 | |
288 GList *gaim_log_get_system_logs(GaimAccount *account) | |
289 { | |
290 GList *logs = NULL; | |
291 GSList *n; | |
292 for (n = loggers; n; n = n->next) { | |
293 GaimLogLogger *logger = n->data; | |
294 if (!logger->list_syslog) | |
295 continue; | |
296 logs = g_list_concat(logs, logger->list_syslog(account)); | |
297 } | |
298 | |
299 return g_list_sort(logs, gaim_log_compare); | |
7431 | 300 } |
301 | |
302 void gaim_log_init(void) | |
7436 | 303 { |
7431 | 304 gaim_prefs_add_none("/core/logging"); |
7555 | 305 gaim_prefs_add_bool("/core/logging/log_ims", FALSE); |
306 gaim_prefs_add_bool("/core/logging/log_chats", FALSE); | |
8573 | 307 gaim_prefs_add_bool("/core/logging/log_system", FALSE); |
308 gaim_prefs_add_bool("/core/logging/log_signon_signoff", FALSE); | |
309 gaim_prefs_add_bool("/core/logging/log_idle_state", FALSE); | |
310 gaim_prefs_add_bool("/core/logging/log_away_state", FALSE); | |
311 gaim_prefs_add_bool("/core/logging/log_own_states", FALSE); | |
312 | |
7431 | 313 gaim_prefs_add_string("/core/logging/format", "txt"); |
7457 | 314 gaim_log_logger_add(&html_logger); |
7431 | 315 gaim_log_logger_add(&txt_logger); |
316 gaim_log_logger_add(&old_logger); | |
317 gaim_prefs_connect_callback("/core/logging/format", | |
318 logger_pref_cb, NULL); | |
319 gaim_prefs_trigger_callback("/core/logging/format"); | |
8635 | 320 |
321 logsize_users = g_hash_table_new_full((GHashFunc)_gaim_logsize_user_hash, | |
322 (GEqualFunc)_gaim_logsize_user_equal, | |
323 (GDestroyNotify)_gaim_logsize_user_free_key, NULL); | |
7431 | 324 } |
325 | |
326 /**************************************************************************** | |
327 * LOGGERS ****************************************************************** | |
328 ****************************************************************************/ | |
329 | |
7616 | 330 struct generic_logger_data { |
331 char *path; | |
332 FILE *file; | |
333 }; | |
334 | |
9763 | 335 static void log_writer_common(GaimLog *log, GaimMessageFlags type, |
336 const char *prpl, time_t time, | |
337 const char *ext) | |
338 { | |
339 char date[64]; | |
340 struct generic_logger_data *data = log->logger_data; | |
341 | |
342 if(!data) { | |
343 /* This log is new */ | |
344 char *ud = gaim_user_dir(); | |
345 char *acct_name = g_strdup(gaim_normalize(log->account, | |
346 gaim_account_get_username(log->account))); | |
347 char *target; | |
348 char *dir; | |
349 char *filename, *path; | |
350 | |
351 printf("%s\n", acct_name); | |
352 | |
353 if (log->type == GAIM_LOG_CHAT) { | |
354 target = g_strdup_printf("%s.chat", gaim_normalize(log->account, | |
355 log->name)); | |
356 } else if(log->type == GAIM_LOG_SYSTEM) { | |
357 target = g_strdup(".system"); | |
358 } else { | |
359 target = g_strdup(gaim_normalize(log->account, log->name)); | |
360 } | |
361 | |
362 strftime(date, sizeof(date), "%Y-%m-%d.%H%M%S", localtime(&log->time)); | |
363 | |
364 dir = g_build_filename(ud, "logs", | |
365 prpl, acct_name, target, NULL); | |
366 gaim_build_dir (dir, S_IRUSR | S_IWUSR | S_IXUSR); | |
367 g_free(target); | |
368 g_free(acct_name); | |
369 | |
370 filename = g_strdup_printf("%s%s", date, ext ? ext : ""); | |
371 | |
372 path = g_build_filename(dir, filename, NULL); | |
373 g_free(dir); | |
374 g_free(filename); | |
375 | |
376 log->logger_data = data = g_new0(struct generic_logger_data, 1); | |
377 | |
378 data->file = fopen(path, "a"); | |
379 if (!data->file) { | |
380 gaim_debug(GAIM_DEBUG_ERROR, "log", | |
381 "Could not create log file %s\n", filename); | |
382 g_free(path); | |
383 return; | |
384 } | |
385 g_free(path); | |
386 } | |
387 } | |
388 | |
8898 | 389 static GList *log_lister_common(GaimLogType type, const char *name, GaimAccount *account, const char *ext, GaimLogLogger *logger) |
7431 | 390 { |
391 GDir *dir; | |
392 GList *list = NULL; | |
7628 | 393 const char *filename; |
8111 | 394 char *me; |
395 const char *prpl; | |
396 char *path; | |
397 | |
398 if(!account) | |
399 return NULL; | |
400 | |
8898 | 401 if (type == GAIM_LOG_CHAT) |
402 me = g_strdup_printf("%s.chat", gaim_normalize(account, gaim_account_get_username(account))); | |
403 else | |
404 me = g_strdup(gaim_normalize(account, gaim_account_get_username(account))); | |
4184 | 405 |
7956 | 406 /* does this seem like a bad way to get this component of the path to anyone else? --Nathan */ |
8111 | 407 prpl = GAIM_PLUGIN_PROTOCOL_INFO |
7956 | 408 (gaim_find_prpl(gaim_account_get_protocol_id(account)))->list_icon(account, NULL); |
9500 | 409 if(type == GAIM_LOG_SYSTEM) |
410 path = g_build_filename(gaim_user_dir(),"logs", prpl, me, name, NULL); | |
411 else | |
412 path = g_build_filename(gaim_user_dir(),"logs", prpl, me, gaim_normalize(account, name), NULL); | |
7447 | 413 g_free(me); |
414 | |
7431 | 415 if (!(dir = g_dir_open(path, 0, NULL))) { |
416 g_free(path); | |
417 return NULL; | |
418 } | |
8898 | 419 |
7431 | 420 while ((filename = g_dir_read_name(dir))) { |
8577 | 421 if (gaim_str_has_suffix(filename, ext) && |
422 strlen(filename) == 17 + strlen(ext)) { | |
7431 | 423 GaimLog *log; |
7616 | 424 struct generic_logger_data *data; |
8577 | 425 time_t stamp = gaim_str_to_time(filename, FALSE); |
7431 | 426 |
8898 | 427 log = gaim_log_new(type, name, account, stamp); |
7431 | 428 log->logger = logger; |
7616 | 429 log->logger_data = data = g_new0(struct generic_logger_data, 1); |
430 data->path = g_build_filename(path, filename, NULL); | |
7431 | 431 list = g_list_append(list, log); |
4184 | 432 } |
433 } | |
7431 | 434 g_dir_close(dir); |
7447 | 435 g_free(path); |
7431 | 436 return list; |
437 } | |
4184 | 438 |
7556 | 439 /* Only to be used with logs listed from log_lister_common */ |
7616 | 440 int log_sizer_common(GaimLog *log) |
7556 | 441 { |
442 struct stat st; | |
7616 | 443 struct generic_logger_data *data = log->logger_data; |
7556 | 444 |
7616 | 445 if (!data->path || stat(data->path, &st)) |
7556 | 446 st.st_size = 0; |
447 | |
448 return st.st_size; | |
449 } | |
450 | |
7431 | 451 #if 0 /* Maybe some other time. */ |
7443 | 452 /**************** |
7431 | 453 ** XML LOGGER ** |
454 ****************/ | |
455 | |
456 static const char *str_from_msg_type (GaimMessageFlags type) | |
457 { | |
7443 | 458 |
7431 | 459 return ""; |
7443 | 460 |
7431 | 461 } |
462 | |
7443 | 463 static void xml_logger_write(GaimLog *log, |
464 GaimMessageFlags type, | |
7431 | 465 const char *from, time_t time, const char *message) |
466 { | |
467 char date[64]; | |
468 char *xhtml = NULL; | |
469 if (!log->logger_data) { | |
470 /* This log is new. We could use the loggers 'new' function, but | |
471 * creating a new file there would result in empty files in the case | |
472 * that you open a convo with someone, but don't say anything. | |
473 */ | |
474 char *ud = gaim_user_dir(); | |
475 char *guy = g_strdup(gaim_normalize(log->account, gaim_account_get_username(log->account))); | |
476 const char *prpl = GAIM_PLUGIN_PROTOCOL_INFO | |
477 (gaim_find_prpl(gaim_account_get_protocol(log->account)))->list_icon(log->account, NULL); | |
478 char *dir; | |
479 FILE *file; | |
480 | |
8898 | 481 if (log->type == GAIM_LOG_CHAT) { |
482 char *chat = g_strdup_printf("%s.chat", guy); | |
483 g_free(guy); | |
484 guy = chat; | |
485 } | |
486 | |
7453 | 487 strftime(date, sizeof(date), "%Y-%m-%d.%H%M%S.xml", localtime(&log->time)); |
7443 | 488 |
489 dir = g_build_filename(ud, "logs", | |
7431 | 490 prpl, guy, gaim_normalize(log->account, log->name), NULL); |
7612 | 491 gaim_build_dir (dir, S_IRUSR | S_IWUSR | S_IXUSR); |
7447 | 492 g_free(guy); |
7443 | 493 |
7431 | 494 char *filename = g_build_filename(dir, date, NULL); |
495 g_free(dir); | |
7443 | 496 |
7431 | 497 log->logger_data = fopen(filename, "a"); |
498 if (!log->logger_data) { | |
499 gaim_debug(GAIM_DEBUG_ERROR, "log", "Could not create log file %s\n", filename); | |
7564 | 500 g_free(filename); |
7431 | 501 return; |
502 } | |
7564 | 503 g_free(filename); |
7431 | 504 fprintf(log->logger_data, "<?xml version='1.0' encoding='UTF-8' ?>\n" |
505 "<?xml-stylesheet href='file:///usr/src/web/htdocs/log-stylesheet.xsl' type='text/xml' ?>\n"); | |
7443 | 506 |
7453 | 507 strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&log->time)); |
7431 | 508 fprintf(log->logger_data, "<conversation time='%s' screenname='%s' protocol='%s'>\n", |
509 date, log->name, prpl); | |
510 } | |
7443 | 511 |
7453 | 512 strftime(date, sizeof(date), "%H:%M:%S", localtime(&time)); |
7431 | 513 gaim_markup_html_to_xhtml(message, &xhtml, NULL); |
514 if (from) | |
7443 | 515 fprintf(log->logger_data, "<message %s %s from='%s' time='%s'>%s</message>\n", |
516 str_from_msg_type(type), | |
7431 | 517 type & GAIM_MESSAGE_SEND ? "direction='sent'" : |
518 type & GAIM_MESSAGE_RECV ? "direction='received'" : "", | |
519 from, date, xhtml); | |
520 else | |
7443 | 521 fprintf(log->logger_data, "<message %s %s time='%s'>%s</message>\n", |
522 str_from_msg_type(type), | |
7431 | 523 type & GAIM_MESSAGE_SEND ? "direction='sent'" : |
524 type & GAIM_MESSAGE_RECV ? "direction='received'" : "", | |
7443 | 525 date, xhtml): |
7431 | 526 fflush(log->logger_data); |
527 g_free(xhtml); | |
7443 | 528 } |
529 | |
7431 | 530 static void xml_logger_finalize(GaimLog *log) |
531 { | |
532 if (log->logger_data) { | |
533 fprintf(log->logger_data, "</conversation>\n"); | |
534 fclose(log->logger_data); | |
535 log->logger_data = NULL; | |
536 } | |
537 } | |
7443 | 538 |
8898 | 539 static GList *xml_logger_list(GaimLogType type, const char *sn, GaimAccount *account) |
7431 | 540 { |
8898 | 541 return log_lister_common(type, sn, account, ".xml", &xml_logger); |
4184 | 542 } |
543 | |
7431 | 544 static GaimLogLogger xml_logger = { |
545 N_("XML"), "xml", | |
546 NULL, | |
547 xml_logger_write, | |
548 xml_logger_finalize, | |
549 xml_logger_list, | |
8096 | 550 NULL, |
7431 | 551 NULL |
552 }; | |
553 #endif | |
5563
9eb5b13fd412
[gaim-migrate @ 5965]
Christian Hammond <chipx86@chipx86.com>
parents:
5560
diff
changeset
|
554 |
7431 | 555 /**************************** |
7457 | 556 ** HTML LOGGER ************* |
557 ****************************/ | |
558 | |
559 static void html_logger_write(GaimLog *log, GaimMessageFlags type, | |
560 const char *from, time_t time, const char *message) | |
561 { | |
9763 | 562 char *msg_fixed; |
7457 | 563 char date[64]; |
9613 | 564 GaimPlugin *plugin = gaim_find_prpl(gaim_account_get_protocol_id(log->account)); |
565 const char *prpl_name = plugin->info->name; | |
9763 | 566 struct generic_logger_data *data = log->logger_data; |
9613 | 567 |
7618 | 568 if(!data) { |
9763 | 569 const char *prpl = |
570 GAIM_PLUGIN_PROTOCOL_INFO(plugin)->list_icon(log->account, NULL); | |
571 log_writer_common(log, type, prpl, time, ".html"); | |
7457 | 572 |
9763 | 573 data = log->logger_data; |
7457 | 574 |
9763 | 575 /* if we can't write to the file, give up before we hurt ourselves */ |
576 if(!data->file) | |
577 return; | |
7616 | 578 |
7457 | 579 strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&log->time)); |
7616 | 580 fprintf(data->file, "<html><head><title>"); |
581 fprintf(data->file, "Conversation with %s at %s on %s (%s)", | |
7457 | 582 log->name, date, gaim_account_get_username(log->account), prpl); |
7616 | 583 fprintf(data->file, "</title></head><body>"); |
584 fprintf(data->file, | |
7457 | 585 "<h3>Conversation with %s at %s on %s (%s)</h3>\n", |
586 log->name, date, gaim_account_get_username(log->account), prpl); | |
9763 | 587 |
7457 | 588 } |
7623 | 589 |
7882 | 590 gaim_markup_html_to_xhtml(message, &msg_fixed, NULL); |
591 | |
8577 | 592 if(log->type == GAIM_LOG_SYSTEM){ |
9592 | 593 strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&time)); |
8577 | 594 fprintf(data->file, "---- %s @ %s ----<br/>\n", msg_fixed, date); |
595 } else { | |
596 strftime(date, sizeof(date), "%H:%M:%S", localtime(&time)); | |
597 if (type & GAIM_MESSAGE_SYSTEM) | |
598 fprintf(data->file, "<font size=\"2\">(%s)</font><b> %s</b><br/>\n", date, msg_fixed); | |
599 else if (type & GAIM_MESSAGE_WHISPER) | |
600 fprintf(data->file, "<font color=\"#6C2585\"><font size=\"2\">(%s)</font><b> %s:</b></font> %s<br/>\n", | |
601 date, from, msg_fixed); | |
602 else if (type & GAIM_MESSAGE_AUTO_RESP) { | |
603 if (type & GAIM_MESSAGE_SEND) | |
604 fprintf(data->file, _("<font color=\"#16569E\"><font size=\"2\">(%s)</font> <b>%s <AUTO-REPLY>:</b></font> %s<br/>\n"), date, from, msg_fixed); | |
605 else if (type & GAIM_MESSAGE_RECV) | |
606 fprintf(data->file, _("<font color=\"#A82F2F\"><font size=\"2\">(%s)</font> <b>%s <AUTO-REPLY>:</b></font> %s<br/>\n"), date, from, msg_fixed); | |
607 } else if (type & GAIM_MESSAGE_RECV) { | |
608 if(gaim_message_meify(msg_fixed, -1)) | |
609 fprintf(data->file, "<font color=\"#6C2585\"><font size=\"2\">(%s)</font> <b>***%s</b></font> <font sml=\"%s\">%s</font><br/>\n", | |
9613 | 610 date, from, prpl_name, msg_fixed); |
8577 | 611 else |
612 fprintf(data->file, "<font color=\"#A82F2F\"><font size=\"2\">(%s)</font> <b>%s:</b></font> <font sml=\"%s\">%s</font><br/>\n", | |
9613 | 613 date, from, prpl_name, msg_fixed); |
8577 | 614 } else if (type & GAIM_MESSAGE_SEND) { |
615 if(gaim_message_meify(msg_fixed, -1)) | |
616 fprintf(data->file, "<font color=\"#6C2585\"><font size=\"2\">(%s)</font> <b>***%s</b></font> <font sml=\"%s\">%s</font><br/>\n", | |
9613 | 617 date, from, prpl_name, msg_fixed); |
8577 | 618 else |
619 fprintf(data->file, "<font color=\"#16569E\"><font size=\"2\">(%s)</font> <b>%s:</b></font> <font sml=\"%s\">%s</font><br/>\n", | |
9613 | 620 date, from, prpl_name, msg_fixed); |
8577 | 621 } |
7564 | 622 } |
8573 | 623 |
7882 | 624 g_free(msg_fixed); |
7616 | 625 fflush(data->file); |
7457 | 626 } |
627 | |
628 static void html_logger_finalize(GaimLog *log) | |
629 { | |
7616 | 630 struct generic_logger_data *data = log->logger_data; |
631 if (data) { | |
632 if(data->file) { | |
633 fprintf(data->file, "</body></html>"); | |
634 fclose(data->file); | |
635 } | |
636 g_free(data->path); | |
7752 | 637 g_free(data); |
7463 | 638 } |
7457 | 639 } |
640 | |
8898 | 641 static GList *html_logger_list(GaimLogType type, const char *sn, GaimAccount *account) |
7457 | 642 { |
8898 | 643 return log_lister_common(type, sn, account, ".html", &html_logger); |
7457 | 644 } |
645 | |
8573 | 646 static GList *html_logger_list_syslog(GaimAccount *account) |
647 { | |
8898 | 648 return log_lister_common(GAIM_LOG_SYSTEM, ".system", account, ".html", &html_logger); |
8573 | 649 } |
650 | |
7457 | 651 static char *html_logger_read(GaimLog *log, GaimLogReadFlags *flags) |
652 { | |
653 char *read, *minus_header; | |
7616 | 654 struct generic_logger_data *data = log->logger_data; |
7457 | 655 *flags = GAIM_LOG_READ_NO_NEWLINE; |
7616 | 656 if (!data || !data->path) |
657 return g_strdup(_("<font color=\"red\"><b>Unable to find log path!</b></font>")); | |
658 if (g_file_get_contents(data->path, &read, NULL, NULL)) { | |
7457 | 659 minus_header = strchr(read, '\n'); |
660 if (!minus_header) | |
661 minus_header = g_strdup(read); | |
662 else | |
663 minus_header = g_strdup(minus_header + 1); | |
664 g_free(read); | |
665 return minus_header; | |
666 } | |
8578 | 667 return g_strdup_printf(_("<font color=\"red\"><b>Could not read file: %s</b></font>"), data->path); |
7457 | 668 } |
669 | |
8573 | 670 static void html_logger_create(GaimLog *log) |
671 { | |
672 } | |
673 | |
7457 | 674 static GaimLogLogger html_logger = { |
675 N_("HTML"), "html", | |
8573 | 676 html_logger_create, |
7457 | 677 html_logger_write, |
678 html_logger_finalize, | |
679 html_logger_list, | |
7556 | 680 html_logger_read, |
8096 | 681 log_sizer_common, |
8573 | 682 NULL, |
683 html_logger_list_syslog | |
7457 | 684 }; |
685 | |
686 | |
687 | |
688 | |
689 /**************************** | |
7431 | 690 ** PLAIN TEXT LOGGER ******* |
691 ****************************/ | |
4184 | 692 |
7436 | 693 static void txt_logger_write(GaimLog *log, |
694 GaimMessageFlags type, | |
7431 | 695 const char *from, time_t time, const char *message) |
696 { | |
697 char date[64]; | |
9763 | 698 GaimPlugin *plugin = gaim_find_prpl(gaim_account_get_protocol_id(log->account)); |
7616 | 699 struct generic_logger_data *data = log->logger_data; |
9763 | 700 char *stripped = NULL; |
701 | |
702 if(!data) { | |
7431 | 703 /* This log is new. We could use the loggers 'new' function, but |
704 * creating a new file there would result in empty files in the case | |
705 * that you open a convo with someone, but don't say anything. | |
706 */ | |
9763 | 707 const char *prpl = |
708 GAIM_PLUGIN_PROTOCOL_INFO(plugin)->list_icon(log->account, NULL); | |
709 log_writer_common(log, type, prpl, time, ".txt"); | |
8898 | 710 |
9763 | 711 data = log->logger_data; |
7436 | 712 |
9763 | 713 /* if we can't write to the file, give up before we hurt ourselves */ |
714 if(!data->file) | |
715 return; | |
7616 | 716 |
7453 | 717 strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&log->time)); |
7616 | 718 fprintf(data->file, "Conversation with %s at %s on %s (%s)\n", |
7431 | 719 log->name, date, gaim_account_get_username(log->account), prpl); |
720 } | |
7436 | 721 |
7623 | 722 /* if we can't write to the file, give up before we hurt ourselves */ |
723 if(!data->file) | |
724 return; | |
725 | |
8573 | 726 stripped = gaim_markup_strip_html(message); |
727 | |
728 if(log->type == GAIM_LOG_SYSTEM){ | |
9592 | 729 strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&time)); |
8573 | 730 fprintf(data->file, "---- %s @ %s ----\n", stripped, date); |
731 } else { | |
732 strftime(date, sizeof(date), "%H:%M:%S", localtime(&time)); | |
733 if (type & GAIM_MESSAGE_SEND || | |
734 type & GAIM_MESSAGE_RECV) { | |
735 if (type & GAIM_MESSAGE_AUTO_RESP) { | |
736 fprintf(data->file, _("(%s) %s <AUTO-REPLY>: %s\n"), date, | |
737 from, stripped); | |
738 } else { | |
739 if(gaim_message_meify(stripped, -1)) | |
740 fprintf(data->file, "(%s) ***%s %s\n", date, from, | |
741 stripped); | |
742 else | |
743 fprintf(data->file, "(%s) %s: %s\n", date, from, | |
744 stripped); | |
745 } | |
746 } else if (type & GAIM_MESSAGE_SYSTEM) | |
747 fprintf(data->file, "(%s) %s\n", date, stripped); | |
748 else if (type & GAIM_MESSAGE_NO_LOG) { | |
749 /* This shouldn't happen */ | |
750 g_free(stripped); | |
751 return; | |
752 } else if (type & GAIM_MESSAGE_WHISPER) | |
753 fprintf(data->file, "(%s) *%s* %s", date, from, stripped); | |
754 else | |
755 fprintf(data->file, "(%s) %s%s %s\n", date, from ? from : "", | |
756 from ? ":" : "", stripped); | |
757 } | |
758 | |
759 fflush(data->file); | |
760 g_free(stripped); | |
7431 | 761 } |
762 | |
763 static void txt_logger_finalize(GaimLog *log) | |
764 { | |
7616 | 765 struct generic_logger_data *data = log->logger_data; |
766 if (data) { | |
767 if(data->file) | |
768 fclose(data->file); | |
769 if(data->path) | |
770 g_free(data->path); | |
7752 | 771 g_free(data); |
7616 | 772 } |
7431 | 773 } |
774 | |
8898 | 775 static GList *txt_logger_list(GaimLogType type, const char *sn, GaimAccount *account) |
7431 | 776 { |
8898 | 777 return log_lister_common(type, sn, account, ".txt", &txt_logger); |
7431 | 778 } |
779 | |
8573 | 780 static GList *txt_logger_list_syslog(GaimAccount *account) |
781 { | |
8898 | 782 return log_lister_common(GAIM_LOG_SYSTEM, ".system", account, ".txt", &txt_logger); |
8573 | 783 } |
784 | |
7431 | 785 static char *txt_logger_read(GaimLog *log, GaimLogReadFlags *flags) |
786 { | |
8517 | 787 char *read, *minus_header, *minus_header2; |
7616 | 788 struct generic_logger_data *data = log->logger_data; |
7457 | 789 *flags = 0; |
7616 | 790 if (!data || !data->path) |
791 return g_strdup(_("<font color=\"red\"><b>Unable to find log path!</b></font>")); | |
792 if (g_file_get_contents(data->path, &read, NULL, NULL)) { | |
7431 | 793 minus_header = strchr(read, '\n'); |
794 if (!minus_header) | |
795 minus_header = g_strdup(read); | |
7436 | 796 else |
7431 | 797 minus_header = g_strdup(minus_header + 1); |
798 g_free(read); | |
8517 | 799 minus_header2 = gaim_escape_html(minus_header); |
800 g_free(minus_header); | |
801 return minus_header2; | |
7431 | 802 } |
8578 | 803 return g_strdup_printf(_("<font color=\"red\"><b>Could not read file: %s</b></font>"), data->path); |
7436 | 804 } |
7431 | 805 |
8573 | 806 static void txt_logger_create(GaimLog *log) |
807 { | |
808 } | |
809 | |
7431 | 810 static GaimLogLogger txt_logger = { |
811 N_("Plain text"), "txt", | |
8573 | 812 txt_logger_create, |
7431 | 813 txt_logger_write, |
814 txt_logger_finalize, | |
815 txt_logger_list, | |
7556 | 816 txt_logger_read, |
8096 | 817 log_sizer_common, |
8573 | 818 NULL, |
819 txt_logger_list_syslog | |
7431 | 820 }; |
821 | |
822 /**************** | |
823 * OLD LOGGER *** | |
824 ****************/ | |
825 | |
826 /* The old logger doesn't write logs, only reads them. This is to include | |
827 * old logs in the log viewer transparently. | |
828 */ | |
829 | |
830 struct old_logger_data { | |
7764 | 831 GaimStringref *pathref; |
7431 | 832 int offset; |
833 int length; | |
834 }; | |
835 | |
8898 | 836 static GList *old_logger_list(GaimLogType type, const char *sn, GaimAccount *account) |
7431 | 837 { |
838 FILE *file; | |
839 char buf[BUF_LONG]; | |
840 struct tm tm; | |
7761 | 841 char month[4]; |
7431 | 842 struct old_logger_data *data = NULL; |
843 char *logfile = g_strdup_printf("%s.log", gaim_normalize(account, sn)); | |
7764 | 844 char *pathstr = g_build_filename(gaim_user_dir(), "logs", logfile, NULL); |
845 GaimStringref *pathref = gaim_stringref_new(pathstr); | |
7431 | 846 char *newlog; |
7761 | 847 int logfound = 0; |
848 int lastoff = 0; | |
849 int newlen; | |
7791 | 850 time_t lasttime = 0; |
7431 | 851 |
852 GaimLog *log = NULL; | |
853 GList *list = NULL; | |
854 | |
7473 | 855 g_free(logfile); |
7764 | 856 g_free(pathstr); |
7473 | 857 |
7764 | 858 if (!(file = fopen(gaim_stringref_value(pathref), "rb"))) { |
859 gaim_stringref_unref(pathref); | |
7431 | 860 return NULL; |
7447 | 861 } |
7436 | 862 |
7431 | 863 while (fgets(buf, BUF_LONG, file)) { |
864 if ((newlog = strstr(buf, "---- New C"))) { | |
865 int length; | |
866 int offset; | |
867 char convostart[32]; | |
868 char *temp = strchr(buf, '@'); | |
7436 | 869 |
7431 | 870 if (temp == NULL || strlen(temp) < 2) |
871 continue; | |
7436 | 872 |
7431 | 873 temp++; |
874 length = strcspn(temp, "-"); | |
875 if (length > 31) length = 31; | |
7436 | 876 |
7431 | 877 offset = ftell(file); |
7436 | 878 |
7761 | 879 if (logfound) { |
880 newlen = offset - lastoff - length; | |
7436 | 881 if(strstr(buf, "----</H3><BR>")) { |
7761 | 882 newlen -= |
883 sizeof("<HR><BR><H3 Align=Center> ---- New Conversation @ ") + | |
884 sizeof("----</H3><BR>") - 2; | |
7436 | 885 } else { |
7761 | 886 newlen -= |
887 sizeof("---- New Conversation @ ") + sizeof("----") - 2; | |
7436 | 888 } |
889 | |
7461 | 890 if(strchr(buf, '\r')) |
7770 | 891 newlen--; |
7461 | 892 |
7761 | 893 if (newlen != 0) { |
894 log = gaim_log_new(GAIM_LOG_IM, sn, account, -1); | |
895 log->logger = &old_logger; | |
896 log->time = lasttime; | |
897 data = g_new0(struct old_logger_data, 1); | |
898 data->offset = lastoff; | |
899 data->length = newlen; | |
7764 | 900 data->pathref = gaim_stringref_ref(pathref); |
7761 | 901 log->logger_data = data; |
7431 | 902 list = g_list_append(list, log); |
7761 | 903 } |
7431 | 904 } |
905 | |
7761 | 906 logfound = 1; |
907 lastoff = offset; | |
7436 | 908 |
7431 | 909 g_snprintf(convostart, length, "%s", temp); |
7676 | 910 sscanf(convostart, "%*s %s %d %d:%d:%d %d", |
911 month, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &tm.tm_year); | |
912 /* Ugly hack, in case current locale is not English */ | |
913 if (strcmp(month, "Jan") == 0) { | |
914 tm.tm_mon= 0; | |
915 } else if (strcmp(month, "Feb") == 0) { | |
916 tm.tm_mon = 1; | |
917 } else if (strcmp(month, "Mar") == 0) { | |
918 tm.tm_mon = 2; | |
919 } else if (strcmp(month, "Apr") == 0) { | |
920 tm.tm_mon = 3; | |
921 } else if (strcmp(month, "May") == 0) { | |
922 tm.tm_mon = 4; | |
923 } else if (strcmp(month, "Jun") == 0) { | |
924 tm.tm_mon = 5; | |
925 } else if (strcmp(month, "Jul") == 0) { | |
926 tm.tm_mon = 6; | |
927 } else if (strcmp(month, "Aug") == 0) { | |
928 tm.tm_mon = 7; | |
929 } else if (strcmp(month, "Sep") == 0) { | |
930 tm.tm_mon = 8; | |
931 } else if (strcmp(month, "Oct") == 0) { | |
932 tm.tm_mon = 9; | |
933 } else if (strcmp(month, "Nov") == 0) { | |
934 tm.tm_mon = 10; | |
935 } else if (strcmp(month, "Dec") == 0) { | |
936 tm.tm_mon = 11; | |
937 } | |
938 tm.tm_year -= 1900; | |
7761 | 939 lasttime = mktime(&tm); |
4184 | 940 } |
941 } | |
7613 | 942 |
7761 | 943 if (logfound) { |
944 if ((newlen = ftell(file) - lastoff) != 0) { | |
945 log = gaim_log_new(GAIM_LOG_IM, sn, account, -1); | |
946 log->logger = &old_logger; | |
947 log->time = lasttime; | |
948 data = g_new0(struct old_logger_data, 1); | |
949 data->offset = lastoff; | |
950 data->length = newlen; | |
7764 | 951 data->pathref = gaim_stringref_ref(pathref); |
7761 | 952 log->logger_data = data; |
7613 | 953 list = g_list_append(list, log); |
7761 | 954 } |
7613 | 955 } |
956 | |
7764 | 957 gaim_stringref_unref(pathref); |
7431 | 958 fclose(file); |
959 return list; | |
4184 | 960 } |
4359
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4227
diff
changeset
|
961 |
8898 | 962 static int old_logger_total_size(GaimLogType type, const char *name, GaimAccount *account) |
8096 | 963 { |
964 char *logfile = g_strdup_printf("%s.log", gaim_normalize(account, name)); | |
965 char *pathstr = g_build_filename(gaim_user_dir(), "logs", logfile, NULL); | |
966 int size; | |
967 struct stat st; | |
968 | |
969 if (stat(pathstr, &st)) | |
970 size = 0; | |
971 else | |
972 size = st.st_size; | |
973 | |
974 g_free(logfile); | |
975 g_free(pathstr); | |
976 | |
977 return size; | |
978 } | |
979 | |
7616 | 980 static char * old_logger_read (GaimLog *log, GaimLogReadFlags *flags) |
4359
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4227
diff
changeset
|
981 { |
7431 | 982 struct old_logger_data *data = log->logger_data; |
7764 | 983 FILE *file = fopen(gaim_stringref_value(data->pathref), "rb"); |
7431 | 984 char *read = g_malloc(data->length + 1); |
985 fseek(file, data->offset, SEEK_SET); | |
986 fread(read, data->length, 1, file); | |
8370 | 987 fclose(file); |
7431 | 988 read[data->length] = '\0'; |
7436 | 989 *flags = 0; |
990 if(strstr(read, "<BR>")) | |
991 *flags |= GAIM_LOG_READ_NO_NEWLINE; | |
7431 | 992 return read; |
993 } | |
4359
5fb47ec9bfe4
[gaim-migrate @ 4625]
Christian Hammond <chipx86@chipx86.com>
parents:
4227
diff
changeset
|
994 |
7616 | 995 static int old_logger_size (GaimLog *log) |
7556 | 996 { |
997 struct old_logger_data *data = log->logger_data; | |
7616 | 998 return data ? data->length : 0; |
999 } | |
1000 | |
1001 static void old_logger_finalize(GaimLog *log) | |
1002 { | |
1003 struct old_logger_data *data = log->logger_data; | |
7764 | 1004 gaim_stringref_unref(data->pathref); |
7616 | 1005 g_free(data); |
7556 | 1006 } |
1007 | |
7431 | 1008 static GaimLogLogger old_logger = { |
1009 "old logger", "old", | |
7616 | 1010 NULL, NULL, |
1011 old_logger_finalize, | |
7431 | 1012 old_logger_list, |
7616 | 1013 old_logger_read, |
8096 | 1014 old_logger_size, |
8573 | 1015 old_logger_total_size, |
1016 NULL | |
7431 | 1017 }; |