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