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