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