Mercurial > pidgin.yaz
annotate libgaim/plugins/log_reader.c @ 14996:0d9f69b23352
[gaim-migrate @ 17774]
The data for "plugin_action" is set with a destructor function. So freeing it
twice would cause a crash. The reason it's not crashing is, the children of the
container are not the menuitems, but GtkAccelLabel (or some such thing). So all
we are doing is freeing null. Also, when the menu is destroyed, all the
menuitems are also destroyed anyway. So get rid of the unrequired loop.
Also, isdigit expects a character, not a string.
committer: Tailor Script <tailor@pidgin.im>
author | Sadrul Habib Chowdhury <imadil@gmail.com> |
---|---|
date | Sat, 18 Nov 2006 05:30:57 +0000 |
parents | 5025e146a876 |
children | 82d1a2fc6d25 |
rev | line source |
---|---|
14235 | 1 #ifdef HAVE_CONFIG_H |
2 # include <config.h> | |
3 #endif | |
4 | |
5 #include <stdio.h> | |
6 | |
7 #ifndef GAIM_PLUGINS | |
8 # define GAIM_PLUGINS | |
9 #endif | |
10 | |
11 #include "internal.h" | |
12 | |
13 #include "debug.h" | |
14 #include "log.h" | |
15 #include "plugin.h" | |
16 #include "pluginpref.h" | |
17 #include "prefs.h" | |
18 #include "stringref.h" | |
19 #include "util.h" | |
20 #include "version.h" | |
21 #include "xmlnode.h" | |
22 | |
23 /* This must be the last Gaim header included. */ | |
24 #ifdef _WIN32 | |
25 #include "win32dep.h" | |
26 #endif | |
27 | |
28 /* Where is the Windows partition mounted? */ | |
29 #ifndef GAIM_LOG_READER_WINDOWS_MOUNT_POINT | |
30 #define GAIM_LOG_READER_WINDOWS_MOUNT_POINT "/mnt/windows" | |
31 #endif | |
32 | |
33 enum name_guesses { | |
34 NAME_GUESS_UNKNOWN, | |
35 NAME_GUESS_ME, | |
36 NAME_GUESS_THEM | |
37 }; | |
38 | |
39 | |
40 /***************************************************************************** | |
41 * Adium Logger * | |
42 *****************************************************************************/ | |
43 | |
44 /* The adium logger doesn't write logs, only reads them. This is to include | |
45 * Adium logs in the log viewer transparently. | |
46 */ | |
47 | |
48 static GaimLogLogger *adium_logger; | |
49 | |
50 enum adium_log_type { | |
51 ADIUM_HTML, | |
52 ADIUM_TEXT, | |
53 }; | |
54 | |
55 struct adium_logger_data { | |
56 char *path; | |
57 enum adium_log_type type; | |
58 }; | |
59 | |
60 static GList *adium_logger_list(GaimLogType type, const char *sn, GaimAccount *account) | |
61 { | |
62 GList *list = NULL; | |
63 const char *logdir; | |
64 GaimPlugin *plugin; | |
65 GaimPluginProtocolInfo *prpl_info; | |
66 char *prpl_name; | |
67 char *temp; | |
68 char *path; | |
69 GDir *dir; | |
70 | |
71 g_return_val_if_fail(sn != NULL, list); | |
72 g_return_val_if_fail(account != NULL, list); | |
73 | |
74 logdir = gaim_prefs_get_string("/plugins/core/log_reader/adium/log_directory"); | |
75 | |
76 /* By clearing the log directory path, this logger can be (effectively) disabled. */ | |
77 if (!*logdir) | |
78 return list; | |
79 | |
80 plugin = gaim_find_prpl(gaim_account_get_protocol_id(account)); | |
81 if (!plugin) | |
82 return NULL; | |
83 | |
84 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(plugin); | |
85 if (!prpl_info->list_icon) | |
86 return NULL; | |
87 | |
88 prpl_name = g_ascii_strup(prpl_info->list_icon(account, NULL), -1); | |
89 | |
90 temp = g_strdup_printf("%s.%s", prpl_name, account->username); | |
91 path = g_build_filename(logdir, temp, sn, NULL); | |
92 g_free(temp); | |
93 | |
94 dir = g_dir_open(path, 0, NULL); | |
95 if (dir) { | |
96 const gchar *file; | |
97 | |
98 while ((file = g_dir_read_name(dir))) { | |
99 if (!gaim_str_has_prefix(file, sn)) | |
100 continue; | |
101 if (gaim_str_has_suffix(file, ".html") || gaim_str_has_suffix(file, ".AdiumHTMLLog")) { | |
102 struct tm tm; | |
103 const char *date = file; | |
104 | |
105 date += strlen(sn) + 2; | |
106 if (sscanf(date, "%u|%u|%u", | |
107 &tm.tm_year, &tm.tm_mon, &tm.tm_mday) != 3) { | |
108 | |
109 gaim_debug(GAIM_DEBUG_ERROR, "Adium log parse", | |
110 "Filename timestamp parsing error\n"); | |
111 } else { | |
112 char *filename = g_build_filename(path, file, NULL); | |
113 FILE *handle = g_fopen(filename, "rb"); | |
114 char *contents; | |
115 char *contents2; | |
116 struct adium_logger_data *data; | |
117 GaimLog *log; | |
118 | |
119 if (!handle) { | |
120 g_free(filename); | |
121 continue; | |
122 } | |
123 | |
124 /* XXX: This is really inflexible. */ | |
125 contents = g_malloc(57); | |
126 fread(contents, 56, 1, handle); | |
127 fclose(handle); | |
128 contents[56] = '\0'; | |
129 | |
130 /* XXX: This is fairly inflexible. */ | |
131 contents2 = contents; | |
132 while (*contents2 && *contents2 != '>') | |
133 contents2++; | |
134 if (*contents2) | |
135 contents2++; | |
136 while (*contents2 && *contents2 != '>') | |
137 contents2++; | |
138 if (*contents2) | |
139 contents2++; | |
140 | |
141 if (sscanf(contents2, "%u.%u.%u", | |
142 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 3) { | |
143 | |
144 gaim_debug(GAIM_DEBUG_ERROR, "Adium log parse", | |
145 "Contents timestamp parsing error\n"); | |
146 g_free(contents); | |
147 g_free(filename); | |
148 continue; | |
149 } | |
150 g_free(contents); | |
151 | |
152 data = g_new0(struct adium_logger_data, 1); | |
153 data->path = filename; | |
154 data->type = ADIUM_HTML; | |
155 | |
156 tm.tm_year -= 1900; | |
157 tm.tm_mon -= 1; | |
158 | |
159 /* XXX: Look into this later... Should we pass in a struct tm? */ | |
160 log = gaim_log_new(GAIM_LOG_IM, sn, account, NULL, mktime(&tm), NULL); | |
161 log->logger = adium_logger; | |
162 log->logger_data = data; | |
163 | |
164 list = g_list_append(list, log); | |
165 } | |
166 } else if (gaim_str_has_suffix(file, ".adiumLog")) { | |
167 struct tm tm; | |
168 const char *date = file; | |
169 | |
170 date += strlen(sn) + 2; | |
171 if (sscanf(date, "%u|%u|%u", | |
172 &tm.tm_year, &tm.tm_mon, &tm.tm_mday) != 3) { | |
173 | |
174 gaim_debug(GAIM_DEBUG_ERROR, "Adium log parse", | |
175 "Filename timestamp parsing error\n"); | |
176 } else { | |
177 char *filename = g_build_filename(path, file, NULL); | |
178 FILE *handle = g_fopen(filename, "rb"); | |
179 char *contents; | |
180 char *contents2; | |
181 struct adium_logger_data *data; | |
182 GaimLog *log; | |
183 | |
184 if (!handle) { | |
185 g_free(filename); | |
186 continue; | |
187 } | |
188 | |
189 /* XXX: This is really inflexible. */ | |
190 contents = g_malloc(14); | |
191 fread(contents, 13, 1, handle); | |
192 fclose(handle); | |
193 contents[13] = '\0'; | |
194 | |
195 contents2 = contents; | |
196 while (*contents2 && *contents2 != '(') | |
197 contents2++; | |
198 if (*contents2) | |
199 contents2++; | |
200 | |
201 if (sscanf(contents2, "%u.%u.%u", | |
202 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 3) { | |
203 | |
204 gaim_debug(GAIM_DEBUG_ERROR, "Adium log parse", | |
205 "Contents timestamp parsing error\n"); | |
206 g_free(contents); | |
207 g_free(filename); | |
208 continue; | |
209 } | |
210 | |
211 g_free(contents); | |
212 | |
213 tm.tm_year -= 1900; | |
214 tm.tm_mon -= 1; | |
215 | |
216 data = g_new0(struct adium_logger_data, 1); | |
217 data->path = filename; | |
218 data->type = ADIUM_TEXT; | |
219 | |
220 /* XXX: Look into this later... Should we pass in a struct tm? */ | |
221 log = gaim_log_new(GAIM_LOG_IM, sn, account, NULL, mktime(&tm), NULL); | |
222 log->logger = adium_logger; | |
223 log->logger_data = data; | |
224 | |
225 list = g_list_append(list, log); | |
226 } | |
227 } | |
228 } | |
229 g_dir_close(dir); | |
230 } | |
231 | |
232 g_free(prpl_name); | |
233 g_free(path); | |
234 | |
235 return list; | |
236 } | |
237 | |
238 static char *adium_logger_read (GaimLog *log, GaimLogReadFlags *flags) | |
239 { | |
240 struct adium_logger_data *data; | |
241 GError *error = NULL; | |
242 gchar *read = NULL; | |
243 gsize length; | |
244 | |
245 g_return_val_if_fail(log != NULL, g_strdup("")); | |
246 | |
247 data = log->logger_data; | |
248 | |
249 g_return_val_if_fail(data->path != NULL, g_strdup("")); | |
250 | |
251 gaim_debug(GAIM_DEBUG_INFO, "Adium log read", | |
252 "Reading %s\n", data->path); | |
253 if (!g_file_get_contents(data->path, &read, &length, &error)) { | |
254 gaim_debug(GAIM_DEBUG_ERROR, "Adium log read", | |
255 "Error reading log\n"); | |
256 if (error) | |
257 g_error_free(error); | |
258 return g_strdup(""); | |
259 } | |
260 | |
261 if (data->type != ADIUM_HTML) { | |
262 char *escaped = g_markup_escape_text(read, -1); | |
263 g_free(read); | |
264 read = escaped; | |
265 } | |
266 | |
267 #ifdef WIN32 | |
268 /* This problem only seems to show up on Windows. | |
269 * The BOM is displaying as a space at the beginning of the log. | |
270 */ | |
271 if (gaim_str_has_prefix(read, "\xef\xbb\xbf")) | |
272 { | |
273 /* FIXME: This feels so wrong... */ | |
274 char *temp = g_strdup(&(read[3])); | |
275 g_free(read); | |
276 read = temp; | |
277 } | |
278 #endif | |
279 | |
280 /* TODO: Apply formatting. | |
281 * Replace the above hack with something better, since we'll | |
282 * be looping over the entire log file contents anyway. | |
283 */ | |
284 | |
285 return read; | |
286 } | |
287 | |
288 static int adium_logger_size (GaimLog *log) | |
289 { | |
290 struct adium_logger_data *data; | |
291 char *text; | |
292 size_t size; | |
293 | |
294 g_return_val_if_fail(log != NULL, 0); | |
295 | |
296 data = log->logger_data; | |
297 | |
298 if (gaim_prefs_get_bool("/plugins/core/log_reader/fast_sizes")) { | |
299 struct stat st; | |
300 | |
301 if (!data->path || stat(data->path, &st)) | |
302 st.st_size = 0; | |
303 | |
304 return st.st_size; | |
305 } | |
306 | |
307 text = adium_logger_read(log, NULL); | |
308 size = strlen(text); | |
309 g_free(text); | |
310 | |
311 return size; | |
312 } | |
313 | |
314 static void adium_logger_finalize(GaimLog *log) | |
315 { | |
316 struct adium_logger_data *data; | |
317 | |
318 g_return_if_fail(log != NULL); | |
319 | |
320 data = log->logger_data; | |
321 | |
322 g_free(data->path); | |
323 } | |
324 | |
325 | |
326 /***************************************************************************** | |
327 * Fire Logger * | |
328 *****************************************************************************/ | |
329 | |
330 #if 0 | |
331 /* The fire logger doesn't write logs, only reads them. This is to include | |
332 * Fire logs in the log viewer transparently. | |
333 */ | |
334 | |
335 static GaimLogLogger *fire_logger; | |
336 | |
337 struct fire_logger_data { | |
338 }; | |
339 | |
340 static GList *fire_logger_list(GaimLogType type, const char *sn, GaimAccount *account) | |
341 { | |
342 /* TODO: Do something here. */ | |
343 return NULL; | |
344 } | |
345 | |
346 static char * fire_logger_read (GaimLog *log, GaimLogReadFlags *flags) | |
347 { | |
348 struct fire_logger_data *data; | |
349 | |
350 g_return_val_if_fail(log != NULL, g_strdup("")); | |
351 | |
352 data = log->logger_data; | |
353 | |
354 /* TODO: Do something here. */ | |
355 return g_strdup(""); | |
356 } | |
357 | |
358 static int fire_logger_size (GaimLog *log) | |
359 { | |
360 g_return_val_if_fail(log != NULL, 0); | |
361 | |
362 if (gaim_prefs_get_bool("/plugins/core/log_reader/fast_sizes")) | |
363 return 0; | |
364 | |
365 /* TODO: Do something here. */ | |
366 return 0; | |
367 } | |
368 | |
369 static void fire_logger_finalize(GaimLog *log) | |
370 { | |
371 g_return_if_fail(log != NULL); | |
372 | |
373 /* TODO: Do something here. */ | |
374 } | |
375 #endif | |
376 | |
377 | |
378 /***************************************************************************** | |
379 * Messenger Plus! Logger * | |
380 *****************************************************************************/ | |
381 | |
382 #if 0 | |
383 /* The messenger_plus logger doesn't write logs, only reads them. This is to include | |
384 * Messenger Plus! logs in the log viewer transparently. | |
385 */ | |
386 | |
387 static GaimLogLogger *messenger_plus_logger; | |
388 | |
389 struct messenger_plus_logger_data { | |
390 }; | |
391 | |
392 static GList *messenger_plus_logger_list(GaimLogType type, const char *sn, GaimAccount *account) | |
393 { | |
394 /* TODO: Do something here. */ | |
395 return NULL; | |
396 } | |
397 | |
398 static char * messenger_plus_logger_read (GaimLog *log, GaimLogReadFlags *flags) | |
399 { | |
400 struct messenger_plus_logger_data *data = log->logger_data; | |
401 | |
402 g_return_val_if_fail(log != NULL, g_strdup("")); | |
403 | |
404 data = log->logger_data; | |
405 | |
406 /* TODO: Do something here. */ | |
407 return g_strdup(""); | |
408 } | |
409 | |
410 static int messenger_plus_logger_size (GaimLog *log) | |
411 { | |
412 g_return_val_if_fail(log != NULL, 0); | |
413 | |
414 if (gaim_prefs_get_bool("/plugins/core/log_reader/fast_sizes")) | |
415 return 0; | |
416 | |
417 /* TODO: Do something here. */ | |
418 return 0; | |
419 } | |
420 | |
421 static void messenger_plus_logger_finalize(GaimLog *log) | |
422 { | |
423 g_return_if_fail(log != NULL); | |
424 | |
425 /* TODO: Do something here. */ | |
426 } | |
427 #endif | |
428 | |
429 | |
430 /***************************************************************************** | |
431 * MSN Messenger Logger * | |
432 *****************************************************************************/ | |
433 | |
434 /* The msn logger doesn't write logs, only reads them. This is to include | |
435 * MSN Messenger message histories in the log viewer transparently. | |
436 */ | |
437 | |
438 static GaimLogLogger *msn_logger; | |
439 | |
440 struct msn_logger_data { | |
441 xmlnode *root; | |
442 xmlnode *message; | |
443 const char *session_id; | |
444 int last_log; | |
445 GString *text; | |
446 }; | |
447 | |
448 static time_t msn_logger_parse_timestamp(xmlnode *message) | |
449 { | |
450 const char *date; | |
451 const char *time; | |
452 struct tm tm; | |
453 char am_pm; | |
454 | |
455 g_return_val_if_fail(message != NULL, (time_t)0); | |
456 | |
457 date = xmlnode_get_attrib(message, "Date"); | |
458 if (!(date && *date)) { | |
459 gaim_debug(GAIM_DEBUG_ERROR, "MSN log timestamp parse", | |
460 "Attribute missing: %s\n", "Date"); | |
461 return (time_t)0; | |
462 } | |
463 | |
464 time = xmlnode_get_attrib(message, "Time"); | |
465 if (!(time && *time)) { | |
466 gaim_debug(GAIM_DEBUG_ERROR, "MSN log timestamp parse", | |
467 "Attribute missing: %s\n", "Time"); | |
468 return (time_t)0; | |
469 } | |
470 | |
471 if (sscanf(date, "%u/%u/%u", &tm.tm_mon, &tm.tm_mday, &tm.tm_year) != 3) | |
472 gaim_debug(GAIM_DEBUG_ERROR, "MSN log timestamp parse", | |
473 "%s parsing error\n", "Date"); | |
474 | |
475 if (sscanf(time, "%u:%u:%u %c", &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &am_pm) != 4) | |
476 gaim_debug(GAIM_DEBUG_ERROR, "MSN log timestamp parse", | |
477 "%s parsing error\n", "Time"); | |
478 | |
479 tm.tm_year -= 1900; | |
480 tm.tm_mon -= 1; | |
481 if (am_pm == 'P') { | |
482 tm.tm_hour += 12; | |
483 } else if (tm.tm_hour == 12) { | |
484 /* 12 AM = 00 hr */ | |
485 tm.tm_hour = 0; | |
486 } | |
487 /* Let the C library deal with daylight savings time. */ | |
488 tm.tm_isdst = -1; | |
489 | |
490 return mktime(&tm); | |
491 } | |
492 | |
493 | |
494 static GList *msn_logger_list(GaimLogType type, const char *sn, GaimAccount *account) | |
495 { | |
496 GList *list = NULL; | |
497 char *username; | |
498 GaimBuddy *buddy; | |
499 const char *logdir; | |
500 const char *savedfilename = NULL; | |
501 char *logfile; | |
502 char *path; | |
503 GError *error = NULL; | |
504 gchar *contents = NULL; | |
505 gsize length; | |
506 xmlnode *root; | |
507 xmlnode *message; | |
508 const char *old_session_id = ""; | |
509 struct msn_logger_data *data = NULL; | |
510 | |
511 g_return_val_if_fail(sn != NULL, list); | |
512 g_return_val_if_fail(account != NULL, list); | |
513 | |
514 if (strcmp(account->protocol_id, "prpl-msn")) | |
515 return list; | |
516 | |
517 logdir = gaim_prefs_get_string("/plugins/core/log_reader/msn/log_directory"); | |
518 | |
519 /* By clearing the log directory path, this logger can be (effectively) disabled. */ | |
520 if (!*logdir) | |
521 return list; | |
522 | |
523 buddy = gaim_find_buddy(account, sn); | |
524 | |
525 if ((username = g_strdup(gaim_account_get_string( | |
526 account, "log_reader_msn_log_folder", NULL)))) { | |
527 /* As a special case, we allow the null string to kill the parsing | |
528 * straight away. This would allow the user to deal with the case | |
529 * when two account have the same username at different domains and | |
530 * only one has logs stored. | |
531 */ | |
532 if (!*username) { | |
533 g_free(username); | |
534 return list; | |
535 } | |
536 } else { | |
537 username = g_strdup(gaim_normalize(account, account->username)); | |
538 } | |
539 | |
540 if (buddy) | |
541 savedfilename = gaim_blist_node_get_string(&buddy->node, "log_reader_msn_log_filename"); | |
542 | |
543 if (savedfilename) { | |
544 /* As a special case, we allow the null string to kill the parsing | |
545 * straight away. This would allow the user to deal with the case | |
546 * when two buddies have the same username at different domains and | |
547 * only one has logs stored. | |
548 */ | |
549 if (!*savedfilename) { | |
550 g_free(username); | |
551 return list; | |
552 } | |
553 | |
554 logfile = g_strdup(savedfilename); | |
555 } else { | |
556 logfile = g_strdup_printf("%s.xml", gaim_normalize(account, sn)); | |
557 } | |
558 | |
559 path = g_build_filename(logdir, username, "History", logfile, NULL); | |
560 | |
561 if (!g_file_test(path, G_FILE_TEST_EXISTS)) { | |
562 gboolean found = FALSE; | |
563 char *at_sign; | |
564 GDir *dir; | |
565 | |
566 g_free(path); | |
567 | |
568 if (savedfilename) { | |
569 /* We had a saved filename, but it doesn't exist. | |
570 * Returning now is the right course of action because we don't | |
571 * want to detect another file incorrectly. | |
572 */ | |
573 g_free(username); | |
574 g_free(logfile); | |
575 return list; | |
576 } | |
577 | |
578 /* Perhaps we're using a new version of MSN with the weird numbered folders. | |
579 * I don't know how the numbers are calculated, so I'm going to attempt to | |
580 * find logs by pattern matching... | |
581 */ | |
582 | |
583 at_sign = g_strrstr(username, "@"); | |
584 if (at_sign) | |
585 *at_sign = '\0'; | |
586 | |
587 dir = g_dir_open(logdir, 0, NULL); | |
588 if (dir) { | |
589 const gchar *name; | |
590 | |
591 while ((name = g_dir_read_name(dir))) { | |
592 const char *c = name; | |
593 | |
594 if (!gaim_str_has_prefix(c, username)) | |
595 continue; | |
596 | |
597 c += strlen(username); | |
598 while (*c) { | |
599 if (!g_ascii_isdigit(*c)) | |
600 break; | |
601 | |
602 c++; | |
603 } | |
604 | |
605 path = g_build_filename(logdir, name, NULL); | |
606 /* The !c makes sure we got to the end of the while loop above. */ | |
607 if (!*c && g_file_test(path, G_FILE_TEST_IS_DIR)) { | |
608 char *history_path = g_build_filename( | |
609 path, "History", NULL); | |
610 if (g_file_test(history_path, G_FILE_TEST_IS_DIR)) { | |
611 gaim_account_set_string(account, | |
612 "log_reader_msn_log_folder", name); | |
613 g_free(path); | |
614 path = history_path; | |
615 found = TRUE; | |
616 break; | |
617 } | |
618 g_free(path); | |
619 g_free(history_path); | |
620 } | |
621 else | |
622 g_free(path); | |
623 } | |
624 g_dir_close(dir); | |
625 } | |
626 g_free(username); | |
627 | |
628 if (!found) { | |
629 g_free(logfile); | |
630 return list; | |
631 } | |
632 | |
633 /* If we've reached this point, we've found a History folder. */ | |
634 | |
635 username = g_strdup(gaim_normalize(account, sn)); | |
636 at_sign = g_strrstr(username, "@"); | |
637 if (at_sign) | |
638 *at_sign = '\0'; | |
639 | |
640 found = FALSE; | |
641 dir = g_dir_open(path, 0, NULL); | |
642 if (dir) { | |
643 const gchar *name; | |
644 | |
645 while ((name = g_dir_read_name(dir))) { | |
646 const char *c = name; | |
647 | |
648 if (!gaim_str_has_prefix(c, username)) | |
649 continue; | |
650 | |
651 c += strlen(username); | |
652 while (*c) { | |
653 if (!g_ascii_isdigit(*c)) | |
654 break; | |
655 | |
656 c++; | |
657 } | |
658 | |
659 path = g_build_filename(path, name, NULL); | |
660 if (!strcmp(c, ".xml") && | |
661 g_file_test(path, G_FILE_TEST_EXISTS)) { | |
662 found = TRUE; | |
663 g_free(logfile); | |
664 logfile = g_strdup(name); | |
665 break; | |
666 } | |
667 else | |
668 g_free(path); | |
669 } | |
670 g_dir_close(dir); | |
671 } | |
672 g_free(username); | |
673 | |
674 if (!found) { | |
675 g_free(logfile); | |
676 return list; | |
677 } | |
678 } else { | |
679 g_free(username); | |
680 g_free(logfile); | |
681 logfile = NULL; /* No sense saving the obvious buddy@domain.com. */ | |
682 } | |
683 | |
684 gaim_debug(GAIM_DEBUG_INFO, "MSN log read", | |
685 "Reading %s\n", path); | |
686 if (!g_file_get_contents(path, &contents, &length, &error)) { | |
687 g_free(path); | |
688 gaim_debug(GAIM_DEBUG_ERROR, "MSN log read", | |
689 "Error reading log\n"); | |
690 if (error) | |
691 g_error_free(error); | |
692 return list; | |
693 } | |
694 g_free(path); | |
695 | |
696 /* Reading the file was successful... | |
697 * Save its name if it involves the crazy numbers. The idea here is that you could | |
698 * then tweak the blist.xml file by hand if need be. This would be the case if two | |
699 * buddies have the same username at different domains. One set of logs would get | |
700 * detected for both buddies. | |
701 */ | |
702 if (buddy && logfile) { | |
703 gaim_blist_node_set_string(&buddy->node, "log_reader_msn_log_filename", logfile); | |
704 g_free(logfile); | |
705 } | |
706 | |
707 root = xmlnode_from_str(contents, length); | |
708 g_free(contents); | |
709 if (!root) | |
710 return list; | |
711 | |
712 for (message = xmlnode_get_child(root, "Message"); message; | |
713 message = xmlnode_get_next_twin(message)) { | |
714 const char *session_id; | |
715 | |
716 session_id = xmlnode_get_attrib(message, "SessionID"); | |
717 if (!session_id) { | |
718 gaim_debug(GAIM_DEBUG_ERROR, "MSN log parse", | |
719 "Error parsing message: %s\n", "SessionID missing"); | |
720 continue; | |
721 } | |
722 | |
723 if (strcmp(session_id, old_session_id)) { | |
724 /* | |
725 * The session ID differs from the last message. | |
726 * Thus, this is the start of a new conversation. | |
727 */ | |
728 GaimLog *log; | |
729 | |
730 data = g_new0(struct msn_logger_data, 1); | |
731 data->root = root; | |
732 data->message = message; | |
733 data->session_id = session_id; | |
734 data->text = NULL; | |
735 data->last_log = FALSE; | |
736 | |
737 /* XXX: Look into this later... Should we pass in a struct tm? */ | |
738 log = gaim_log_new(GAIM_LOG_IM, sn, account, NULL, msn_logger_parse_timestamp(message), NULL); | |
739 log->logger = msn_logger; | |
740 log->logger_data = data; | |
741 | |
742 list = g_list_append(list, log); | |
743 } | |
744 old_session_id = session_id; | |
745 } | |
746 | |
747 if (data) | |
748 data->last_log = TRUE; | |
749 | |
750 return list; | |
751 } | |
752 | |
753 static char * msn_logger_read (GaimLog *log, GaimLogReadFlags *flags) | |
754 { | |
755 struct msn_logger_data *data; | |
756 GString *text = NULL; | |
757 xmlnode *message; | |
758 | |
759 g_return_val_if_fail(log != NULL, g_strdup("")); | |
760 | |
761 data = log->logger_data; | |
762 | |
763 if (data->text) { | |
764 /* The GTK code which displays the logs g_free()s whatever is | |
765 * returned from this function. Thus, we can't reuse the str | |
766 * part of the GString. The only solution is to free it and | |
767 * start over. | |
768 */ | |
769 g_string_free(data->text, FALSE); | |
770 } | |
771 | |
772 text = g_string_new(""); | |
773 | |
774 if (!data->root || !data->message || !data->session_id) { | |
775 /* Something isn't allocated correctly. */ | |
776 gaim_debug(GAIM_DEBUG_ERROR, "MSN log parse", | |
777 "Error parsing message: %s\n", "Internal variables inconsistent"); | |
778 data->text = text; | |
779 | |
780 return text->str; | |
781 } | |
782 | |
783 for (message = data->message; message; | |
784 message = xmlnode_get_next_twin(message)) { | |
785 | |
786 const char *new_session_id; | |
787 xmlnode *text_node; | |
788 const char *from_name = NULL; | |
789 const char *to_name = NULL; | |
790 xmlnode *from; | |
791 xmlnode *to; | |
792 enum name_guesses name_guessed = NAME_GUESS_UNKNOWN; | |
793 const char *their_name; | |
794 time_t time_unix; | |
795 struct tm *tm_new; | |
796 char *timestamp; | |
797 char *tmp; | |
798 const char *style; | |
799 | |
800 new_session_id = xmlnode_get_attrib(message, "SessionID"); | |
801 | |
802 /* If this triggers, something is wrong with the XML. */ | |
803 if (!new_session_id) { | |
804 gaim_debug(GAIM_DEBUG_ERROR, "MSN log parse", | |
805 "Error parsing message: %s\n", "New SessionID missing"); | |
806 break; | |
807 } | |
808 | |
809 if (strcmp(new_session_id, data->session_id)) { | |
810 /* The session ID differs from the first message. | |
811 * Thus, this is the start of a new conversation. | |
812 */ | |
813 break; | |
814 } | |
815 | |
816 text_node = xmlnode_get_child(message, "Text"); | |
817 if (!text_node) | |
818 continue; | |
819 | |
820 from = xmlnode_get_child(message, "From"); | |
821 if (from) { | |
822 xmlnode *user = xmlnode_get_child(from, "User"); | |
823 | |
824 if (user) { | |
825 from_name = xmlnode_get_attrib(user, "FriendlyName"); | |
826 | |
827 /* This saves a check later. */ | |
828 if (!*from_name) | |
829 from_name = NULL; | |
830 } | |
831 } | |
832 | |
833 to = xmlnode_get_child(message, "To"); | |
834 if (to) { | |
835 xmlnode *user = xmlnode_get_child(to, "User"); | |
836 if (user) { | |
837 to_name = xmlnode_get_attrib(user, "FriendlyName"); | |
838 | |
839 /* This saves a check later. */ | |
840 if (!*to_name) | |
841 to_name = NULL; | |
842 } | |
843 } | |
844 | |
845 their_name = from_name; | |
846 if (from_name && gaim_prefs_get_bool("/plugins/core/log_reader/use_name_heuristics")) { | |
847 const char *friendly_name = gaim_connection_get_display_name(log->account->gc); | |
848 | |
849 if (friendly_name != NULL) { | |
850 int friendly_name_length = strlen(friendly_name); | |
14936
5025e146a876
[gaim-migrate @ 17708]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14272
diff
changeset
|
851 int alias_length = log->account->alias ? strlen(log->account->alias) : 0; |
14235 | 852 GaimBuddy *buddy = gaim_find_buddy(log->account, log->name); |
853 gboolean from_name_matches; | |
854 gboolean to_name_matches; | |
855 | |
856 if (buddy && buddy->alias) | |
857 their_name = buddy->alias; | |
858 | |
859 /* Try to guess which user is me. | |
860 * The first step is to determine if either of the names matches either my | |
861 * friendly name or alias. For this test, "match" is defined as: | |
862 * ^(friendly_name|alias)([^a-zA-Z0-9].*)?$ | |
863 */ | |
864 from_name_matches = (gaim_str_has_prefix(from_name, friendly_name) && | |
865 !isalnum(*(from_name + friendly_name_length))) || | |
866 (gaim_str_has_prefix(from_name, log->account->alias) && | |
867 !isalnum(*(from_name + alias_length))); | |
868 | |
869 to_name_matches = to_name != NULL && ( | |
870 (gaim_str_has_prefix(to_name, friendly_name) && | |
871 !isalnum(*(to_name + friendly_name_length))) || | |
872 (gaim_str_has_prefix(to_name, log->account->alias) && | |
873 !isalnum(*(to_name + alias_length)))); | |
874 | |
875 if (from_name_matches) { | |
876 if (!to_name_matches) { | |
877 name_guessed = NAME_GUESS_ME; | |
878 } | |
879 } else if (to_name_matches) { | |
880 name_guessed = NAME_GUESS_THEM; | |
881 } else { | |
882 if (buddy && buddy->alias) { | |
883 char *alias = g_strdup(buddy->alias); | |
884 | |
885 /* "Truncate" the string at the first non-alphanumeric | |
886 * character. The idea is to relax the comparison. | |
887 */ | |
888 char *temp; | |
889 for (temp = alias; *temp ; temp++) { | |
890 if (!isalnum(*temp)) { | |
891 *temp = '\0'; | |
892 break; | |
893 } | |
894 } | |
895 alias_length = strlen(alias); | |
896 | |
897 /* Try to guess which user is them. | |
898 * The first step is to determine if either of the names | |
899 * matches their alias. For this test, "match" is | |
900 * defined as: ^alias([^a-zA-Z0-9].*)?$ | |
901 */ | |
902 from_name_matches = (gaim_str_has_prefix( | |
903 from_name, alias) && | |
904 !isalnum(*(from_name + | |
905 alias_length))); | |
906 | |
907 to_name_matches = to_name && (gaim_str_has_prefix( | |
908 to_name, alias) && | |
909 !isalnum(*(to_name + | |
910 alias_length))); | |
911 | |
912 g_free(alias); | |
913 | |
914 if (from_name_matches) { | |
915 if (!to_name_matches) { | |
916 name_guessed = NAME_GUESS_THEM; | |
917 } | |
918 } else if (to_name_matches) { | |
919 name_guessed = NAME_GUESS_ME; | |
920 } else if (buddy->server_alias) { | |
921 friendly_name_length = | |
922 strlen(buddy->server_alias); | |
923 | |
924 /* Try to guess which user is them. | |
925 * The first step is to determine if either of | |
926 * the names matches their friendly name. For | |
927 * this test, "match" is defined as: | |
928 * ^friendly_name([^a-zA-Z0-9].*)?$ | |
929 */ | |
930 from_name_matches = (gaim_str_has_prefix( | |
931 from_name, | |
932 buddy->server_alias) && | |
933 !isalnum(*(from_name + | |
934 friendly_name_length))); | |
935 | |
936 to_name_matches = to_name && ( | |
937 (gaim_str_has_prefix( | |
938 to_name, buddy->server_alias) && | |
939 !isalnum(*(to_name + | |
940 friendly_name_length)))); | |
941 | |
942 if (from_name_matches) { | |
943 if (!to_name_matches) { | |
944 name_guessed = NAME_GUESS_THEM; | |
945 } | |
946 } else if (to_name_matches) { | |
947 name_guessed = NAME_GUESS_ME; | |
948 } | |
949 } | |
950 } | |
951 } | |
952 } | |
953 } | |
954 | |
955 if (name_guessed != NAME_GUESS_UNKNOWN) { | |
956 text = g_string_append(text, "<span style=\"color: #"); | |
957 if (name_guessed == NAME_GUESS_ME) | |
958 text = g_string_append(text, "16569E"); | |
959 else | |
960 text = g_string_append(text, "A82F2F"); | |
961 text = g_string_append(text, ";\">"); | |
962 } | |
963 | |
964 time_unix = msn_logger_parse_timestamp(message); | |
965 tm_new = localtime(&time_unix); | |
966 | |
967 timestamp = g_strdup_printf("<font size=\"2\">(%02u:%02u:%02u)</font> ", | |
968 tm_new->tm_hour, tm_new->tm_min, tm_new->tm_sec); | |
969 text = g_string_append(text, timestamp); | |
970 g_free(timestamp); | |
971 | |
972 if (from_name) { | |
973 text = g_string_append(text, "<b>"); | |
974 | |
14936
5025e146a876
[gaim-migrate @ 17708]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14272
diff
changeset
|
975 if (name_guessed == NAME_GUESS_ME) { |
5025e146a876
[gaim-migrate @ 17708]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14272
diff
changeset
|
976 if (log->account->alias) |
5025e146a876
[gaim-migrate @ 17708]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14272
diff
changeset
|
977 text = g_string_append(text, log->account->alias); |
5025e146a876
[gaim-migrate @ 17708]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14272
diff
changeset
|
978 else |
5025e146a876
[gaim-migrate @ 17708]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14272
diff
changeset
|
979 text = g_string_append(text, log->account->username); |
5025e146a876
[gaim-migrate @ 17708]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14272
diff
changeset
|
980 } |
14235 | 981 else if (name_guessed == NAME_GUESS_THEM) |
982 text = g_string_append(text, their_name); | |
983 else | |
984 text = g_string_append(text, from_name); | |
985 | |
986 text = g_string_append(text, ":</b> "); | |
987 } | |
988 | |
989 if (name_guessed != NAME_GUESS_UNKNOWN) | |
990 text = g_string_append(text, "</span>"); | |
991 | |
992 style = xmlnode_get_attrib(text_node, "Style"); | |
993 | |
994 tmp = xmlnode_get_data(text_node); | |
995 if (style && *style) { | |
996 text = g_string_append(text, "<span style=\""); | |
997 text = g_string_append(text, style); | |
998 text = g_string_append(text, "\">"); | |
999 text = g_string_append(text, tmp); | |
1000 text = g_string_append(text, "</span>\n"); | |
1001 } else { | |
1002 text = g_string_append(text, tmp); | |
1003 text = g_string_append(text, "\n"); | |
1004 } | |
1005 g_free(tmp); | |
1006 } | |
1007 | |
1008 data->text = text; | |
1009 | |
1010 return text->str; | |
1011 } | |
1012 | |
1013 static int msn_logger_size (GaimLog *log) | |
1014 { | |
1015 char *text; | |
1016 size_t size; | |
1017 | |
1018 g_return_val_if_fail(log != NULL, 0); | |
1019 | |
1020 if (gaim_prefs_get_bool("/plugins/core/log_reader/fast_sizes")) | |
1021 return 0; | |
1022 | |
1023 text = msn_logger_read(log, NULL); | |
1024 size = strlen(text); | |
1025 g_free(text); | |
1026 | |
1027 return size; | |
1028 } | |
1029 | |
1030 static void msn_logger_finalize(GaimLog *log) | |
1031 { | |
1032 struct msn_logger_data *data; | |
1033 | |
1034 g_return_if_fail(log != NULL); | |
1035 | |
1036 data = log->logger_data; | |
1037 | |
1038 if (data->last_log) | |
1039 xmlnode_free(data->root); | |
1040 | |
1041 if (data->text) | |
1042 g_string_free(data->text, FALSE); | |
1043 } | |
1044 | |
1045 | |
1046 /***************************************************************************** | |
1047 * Trillian Logger * | |
1048 *****************************************************************************/ | |
1049 | |
1050 /* The trillian logger doesn't write logs, only reads them. This is to include | |
1051 * Trillian logs in the log viewer transparently. | |
1052 */ | |
1053 | |
1054 static GaimLogLogger *trillian_logger; | |
1055 static void trillian_logger_finalize(GaimLog *log); | |
1056 | |
1057 struct trillian_logger_data { | |
1058 char *path; /* FIXME: Change this to use GaimStringref like log.c:old_logger_list */ | |
1059 int offset; | |
1060 int length; | |
1061 char *their_nickname; | |
1062 }; | |
1063 | |
1064 static GList *trillian_logger_list(GaimLogType type, const char *sn, GaimAccount *account) | |
1065 { | |
1066 GList *list = NULL; | |
1067 const char *logdir; | |
1068 GaimPlugin *plugin; | |
1069 GaimPluginProtocolInfo *prpl_info; | |
1070 char *prpl_name; | |
1071 const char *buddy_name; | |
1072 char *filename; | |
1073 char *path; | |
1074 GError *error = NULL; | |
1075 gchar *contents = NULL; | |
1076 gsize length; | |
1077 gchar *line; | |
1078 gchar *c; | |
1079 | |
1080 g_return_val_if_fail(sn != NULL, list); | |
1081 g_return_val_if_fail(account != NULL, list); | |
1082 | |
1083 logdir = gaim_prefs_get_string("/plugins/core/log_reader/trillian/log_directory"); | |
1084 | |
1085 /* By clearing the log directory path, this logger can be (effectively) disabled. */ | |
1086 if (!*logdir) | |
1087 return list; | |
1088 | |
1089 plugin = gaim_find_prpl(gaim_account_get_protocol_id(account)); | |
1090 if (!plugin) | |
1091 return NULL; | |
1092 | |
1093 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(plugin); | |
1094 if (!prpl_info->list_icon) | |
1095 return NULL; | |
1096 | |
1097 prpl_name = g_ascii_strup(prpl_info->list_icon(account, NULL), -1); | |
1098 | |
1099 buddy_name = gaim_normalize(account, sn); | |
1100 | |
1101 filename = g_strdup_printf("%s.log", buddy_name); | |
1102 path = g_build_filename( | |
1103 logdir, prpl_name, filename, NULL); | |
1104 | |
1105 gaim_debug(GAIM_DEBUG_INFO, "Trillian log list", | |
1106 "Reading %s\n", path); | |
1107 /* FIXME: There's really no need to read the entire file at once. | |
1108 * See src/log.c:old_logger_list for a better approach. | |
1109 */ | |
1110 if (!g_file_get_contents(path, &contents, &length, &error)) { | |
1111 if (error) { | |
1112 g_error_free(error); | |
1113 error = NULL; | |
1114 } | |
1115 g_free(path); | |
1116 | |
1117 path = g_build_filename( | |
1118 logdir, prpl_name, "Query", filename, NULL); | |
1119 gaim_debug(GAIM_DEBUG_INFO, "Trillian log list", | |
1120 "Reading %s\n", path); | |
1121 if (!g_file_get_contents(path, &contents, &length, &error)) { | |
1122 if (error) | |
1123 g_error_free(error); | |
1124 } | |
1125 } | |
1126 g_free(filename); | |
1127 | |
1128 if (contents) { | |
1129 struct trillian_logger_data *data = NULL; | |
1130 int offset = 0; | |
1131 int last_line_offset = 0; | |
1132 | |
1133 line = contents; | |
1134 c = contents; | |
1135 while (*c) { | |
1136 offset++; | |
1137 | |
1138 if (*c != '\n') { | |
1139 c++; | |
1140 continue; | |
1141 } | |
1142 | |
1143 *c = '\0'; | |
1144 if (gaim_str_has_prefix(line, "Session Close ")) { | |
1145 if (data && !data->length) { | |
1146 if (!(data->length = last_line_offset - data->offset)) { | |
1147 /* This log had no data, so we remove it. */ | |
1148 GList *last = g_list_last(list); | |
1149 | |
1150 gaim_debug(GAIM_DEBUG_INFO, "Trillian log list", | |
1151 "Empty log. Offset %i\n", data->offset); | |
1152 | |
1153 trillian_logger_finalize((GaimLog *)last->data); | |
1154 list = g_list_delete_link(list, last); | |
1155 } | |
1156 } | |
1157 } else if (line[0] && line[1] && line [3] && | |
1158 gaim_str_has_prefix(&line[3], "sion Start ")) { | |
1159 | |
1160 char *their_nickname = line; | |
1161 char *timestamp; | |
1162 | |
1163 if (data && !data->length) | |
1164 data->length = last_line_offset - data->offset; | |
1165 | |
1166 while (*their_nickname && (*their_nickname != ':')) | |
1167 their_nickname++; | |
1168 their_nickname++; | |
1169 | |
1170 /* This code actually has nothing to do with | |
1171 * the timestamp YET. I'm simply using this | |
1172 * variable for now to NUL-terminate the | |
1173 * their_nickname string. | |
1174 */ | |
1175 timestamp = their_nickname; | |
1176 while (*timestamp && *timestamp != ')') | |
1177 timestamp++; | |
1178 | |
1179 if (*timestamp == ')') { | |
1180 char *month; | |
1181 struct tm tm; | |
1182 | |
1183 *timestamp = '\0'; | |
1184 if (line[0] && line[1] && line[2]) | |
1185 timestamp += 3; | |
1186 | |
1187 /* Now we start dealing with the timestamp. */ | |
1188 | |
1189 /* Skip over the day name. */ | |
1190 while (*timestamp && (*timestamp != ' ')) | |
1191 timestamp++; | |
1192 *timestamp = '\0'; | |
1193 timestamp++; | |
1194 | |
1195 /* Parse out the month. */ | |
1196 month = timestamp; | |
1197 while (*timestamp && (*timestamp != ' ')) | |
1198 timestamp++; | |
1199 *timestamp = '\0'; | |
1200 timestamp++; | |
1201 | |
1202 /* Parse the day, time, and year. */ | |
1203 if (sscanf(timestamp, "%u %u:%u:%u %u", | |
1204 &tm.tm_mday, &tm.tm_hour, | |
1205 &tm.tm_min, &tm.tm_sec, | |
1206 &tm.tm_year) != 5) { | |
1207 | |
1208 gaim_debug(GAIM_DEBUG_ERROR, | |
1209 "Trillian log timestamp parse", | |
1210 "Session Start parsing error\n"); | |
1211 } else { | |
1212 GaimLog *log; | |
1213 | |
1214 tm.tm_year -= 1900; | |
1215 | |
1216 /* Let the C library deal with | |
1217 * daylight savings time. | |
1218 */ | |
1219 tm.tm_isdst = -1; | |
1220 | |
1221 /* Ugly hack, in case current locale | |
1222 * is not English. This code is taken | |
1223 * from log.c. | |
1224 */ | |
1225 if (strcmp(month, "Jan") == 0) { | |
1226 tm.tm_mon= 0; | |
1227 } else if (strcmp(month, "Feb") == 0) { | |
1228 tm.tm_mon = 1; | |
1229 } else if (strcmp(month, "Mar") == 0) { | |
1230 tm.tm_mon = 2; | |
1231 } else if (strcmp(month, "Apr") == 0) { | |
1232 tm.tm_mon = 3; | |
1233 } else if (strcmp(month, "May") == 0) { | |
1234 tm.tm_mon = 4; | |
1235 } else if (strcmp(month, "Jun") == 0) { | |
1236 tm.tm_mon = 5; | |
1237 } else if (strcmp(month, "Jul") == 0) { | |
1238 tm.tm_mon = 6; | |
1239 } else if (strcmp(month, "Aug") == 0) { | |
1240 tm.tm_mon = 7; | |
1241 } else if (strcmp(month, "Sep") == 0) { | |
1242 tm.tm_mon = 8; | |
1243 } else if (strcmp(month, "Oct") == 0) { | |
1244 tm.tm_mon = 9; | |
1245 } else if (strcmp(month, "Nov") == 0) { | |
1246 tm.tm_mon = 10; | |
1247 } else if (strcmp(month, "Dec") == 0) { | |
1248 tm.tm_mon = 11; | |
1249 } | |
1250 | |
1251 data = g_new0( | |
1252 struct trillian_logger_data, 1); | |
1253 data->path = g_strdup(path); | |
1254 data->offset = offset; | |
1255 data->length = 0; | |
1256 data->their_nickname = | |
1257 g_strdup(their_nickname); | |
1258 | |
1259 /* XXX: Look into this later... Should we pass in a struct tm? */ | |
1260 log = gaim_log_new(GAIM_LOG_IM, | |
1261 sn, account, NULL, mktime(&tm), NULL); | |
1262 log->logger = trillian_logger; | |
1263 log->logger_data = data; | |
1264 | |
1265 list = g_list_append(list, log); | |
1266 } | |
1267 } | |
1268 } | |
1269 c++; | |
1270 line = c; | |
1271 last_line_offset = offset; | |
1272 } | |
1273 | |
1274 g_free(contents); | |
1275 } | |
1276 g_free(path); | |
1277 | |
1278 g_free(prpl_name); | |
1279 | |
1280 return list; | |
1281 } | |
1282 | |
1283 static char * trillian_logger_read (GaimLog *log, GaimLogReadFlags *flags) | |
1284 { | |
1285 struct trillian_logger_data *data; | |
1286 char *read; | |
1287 FILE *file; | |
1288 GaimBuddy *buddy; | |
1289 char *escaped; | |
1290 GString *formatted; | |
1291 char *c; | |
1292 char *line; | |
1293 | |
1294 g_return_val_if_fail(log != NULL, g_strdup("")); | |
1295 | |
1296 data = log->logger_data; | |
1297 | |
1298 g_return_val_if_fail(data->path != NULL, g_strdup("")); | |
1299 g_return_val_if_fail(data->length > 0, g_strdup("")); | |
1300 g_return_val_if_fail(data->their_nickname != NULL, g_strdup("")); | |
1301 | |
1302 gaim_debug(GAIM_DEBUG_INFO, "Trillian log read", | |
1303 "Reading %s\n", data->path); | |
1304 | |
1305 read = g_malloc(data->length + 2); | |
1306 | |
1307 file = g_fopen(data->path, "rb"); | |
1308 fseek(file, data->offset, SEEK_SET); | |
1309 fread(read, data->length, 1, file); | |
1310 fclose(file); | |
1311 | |
1312 if (read[data->length-1] == '\n') { | |
1313 read[data->length] = '\0'; | |
1314 } else { | |
1315 read[data->length] = '\n'; | |
1316 read[data->length+1] = '\0'; | |
1317 } | |
1318 | |
1319 /* Load miscellaneous data. */ | |
1320 buddy = gaim_find_buddy(log->account, log->name); | |
1321 | |
1322 escaped = g_markup_escape_text(read, -1); | |
1323 g_free(read); | |
1324 read = escaped; | |
1325 | |
1326 /* Apply formatting... */ | |
1327 formatted = g_string_new(""); | |
1328 c = read; | |
1329 line = read; | |
1330 while (*c) | |
1331 { | |
1332 if (*c == '\n') | |
1333 { | |
1334 char *link_temp_line; | |
1335 char *link; | |
1336 char *timestamp; | |
1337 char *footer = NULL; | |
1338 *c = '\0'; | |
1339 | |
1340 /* Convert links. | |
1341 * | |
1342 * The format is (Link: URL)URL | |
1343 * So, I want to find each occurance of "(Link: " and replace that chunk with: | |
1344 * <a href=" | |
1345 * Then, replace the next ")" with: | |
1346 * "> | |
1347 * Then, replace the next " " (or add this if the end-of-line is reached) with: | |
1348 * </a> | |
1349 */ | |
1350 link_temp_line = NULL; | |
1351 while ((link = g_strstr_len(line, strlen(line), "(Link: "))) { | |
1352 GString *temp; | |
1353 | |
1354 if (!*link) | |
1355 continue; | |
1356 | |
1357 *link = '\0'; | |
1358 link++; | |
1359 | |
1360 temp = g_string_new(line); | |
1361 g_string_append(temp, "<a href=\""); | |
1362 | |
1363 if (strlen(link) >= 6) { | |
1364 link += (sizeof("(Link: ") - 1); | |
1365 | |
1366 while (*link && *link != ')') { | |
1367 g_string_append_c(temp, *link); | |
1368 link++; | |
1369 } | |
1370 if (link) { | |
1371 link++; | |
1372 | |
1373 g_string_append(temp, "\">"); | |
1374 while (*link && *link != ' ') { | |
1375 g_string_append_c(temp, *link); | |
1376 link++; | |
1377 } | |
1378 g_string_append(temp, "</a>"); | |
1379 } | |
1380 | |
1381 g_string_append(temp, link); | |
1382 | |
1383 /* Free the last round's line. */ | |
1384 if (link_temp_line) | |
1385 g_free(line); | |
1386 | |
1387 line = temp->str; | |
1388 g_string_free(temp, FALSE); | |
1389 | |
1390 /* Save this memory location so we can free it later. */ | |
1391 link_temp_line = line; | |
1392 } | |
1393 } | |
1394 | |
1395 timestamp = ""; | |
1396 if (*line == '[') { | |
1397 timestamp = line; | |
1398 while (*timestamp && *timestamp != ']') | |
1399 timestamp++; | |
1400 if (*timestamp == ']') { | |
1401 *timestamp = '\0'; | |
1402 line++; | |
1403 /* TODO: Parse the timestamp and convert it to Gaim's format. */ | |
1404 g_string_append_printf(formatted, | |
1405 "<font size=\"2\">(%s)</font> ", line); | |
1406 line = timestamp; | |
1407 if (line[1] && line[2]) | |
1408 line += 2; | |
1409 } | |
1410 | |
1411 if (gaim_str_has_prefix(line, "*** ")) { | |
1412 line += (sizeof("*** ") - 1); | |
1413 g_string_append(formatted, "<b>"); | |
1414 footer = "</b>"; | |
1415 if (gaim_str_has_prefix(line, "NOTE: This user is offline.")) { | |
1416 line = _("User is offline."); | |
1417 } else if (gaim_str_has_prefix(line, | |
1418 "NOTE: Your status is currently set to ")) { | |
1419 | |
1420 line += (sizeof("NOTE: ") - 1); | |
1421 } else if (gaim_str_has_prefix(line, "Auto-response sent to ")) { | |
1422 g_string_append(formatted, _("Auto-response sent:")); | |
1423 while (*line && *line != ':') | |
1424 line++; | |
1425 if (*line) | |
1426 line++; | |
1427 g_string_append(formatted, "</b>"); | |
1428 footer = NULL; | |
1429 } else if (strstr(line, " signed off ")) { | |
1430 if (buddy != NULL && buddy->alias) | |
1431 g_string_append_printf(formatted, | |
1432 _("%s has signed off."), buddy->alias); | |
1433 else | |
1434 g_string_append_printf(formatted, | |
1435 _("%s has signed off."), log->name); | |
1436 line = ""; | |
1437 } else if (strstr(line, " signed on ")) { | |
1438 if (buddy != NULL && buddy->alias) | |
1439 g_string_append(formatted, buddy->alias); | |
1440 else | |
1441 g_string_append(formatted, log->name); | |
1442 line = " logged in."; | |
1443 } else if (gaim_str_has_prefix(line, | |
1444 "One or more messages may have been undeliverable.")) { | |
1445 | |
1446 g_string_append(formatted, | |
1447 "<span style=\"color: #ff0000;\">"); | |
1448 g_string_append(formatted, | |
1449 _("One or more messages may have been " | |
1450 "undeliverable.")); | |
1451 line = ""; | |
1452 footer = "</span></b>"; | |
1453 } else if (gaim_str_has_prefix(line, | |
1454 "You have been disconnected.")) { | |
1455 | |
1456 g_string_append(formatted, | |
1457 "<span style=\"color: #ff0000;\">"); | |
1458 g_string_append(formatted, | |
1459 _("You were disconnected from the server.")); | |
1460 line = ""; | |
1461 footer = "</span></b>"; | |
1462 } else if (gaim_str_has_prefix(line, | |
1463 "You are currently disconnected.")) { | |
1464 | |
1465 g_string_append(formatted, | |
1466 "<span style=\"color: #ff0000;\">"); | |
1467 line = _("You are currently disconnected. Messages " | |
1468 "will not be received unless you are " | |
1469 "logged in."); | |
1470 footer = "</span></b>"; | |
1471 } else if (gaim_str_has_prefix(line, | |
1472 "Your previous message has not been sent.")) { | |
1473 | |
1474 g_string_append(formatted, | |
1475 "<span style=\"color: #ff0000;\">"); | |
1476 | |
1477 if (gaim_str_has_prefix(line, | |
1478 "Your previous message has not been sent. " | |
1479 "Reason: Maximum length exceeded.")) { | |
1480 | |
1481 g_string_append(formatted, | |
1482 _("Message could not be sent because " | |
1483 "the maximum length was exceeded.")); | |
1484 line = ""; | |
1485 } else { | |
1486 g_string_append(formatted, | |
1487 _("Message could not be sent.")); | |
1488 line += (sizeof( | |
1489 "Your previous message " | |
1490 "has not been sent. ") - 1); | |
1491 } | |
1492 | |
1493 footer = "</span></b>"; | |
1494 } | |
1495 } else if (gaim_str_has_prefix(line, data->their_nickname)) { | |
1496 if (buddy != NULL && buddy->alias) { | |
1497 line += strlen(data->their_nickname) + 2; | |
1498 g_string_append_printf(formatted, | |
1499 "<span style=\"color: #A82F2F;\">" | |
1500 "<b>%s</b></span>: ", buddy->alias); | |
1501 } | |
1502 } else { | |
1503 char *line2 = line; | |
1504 while (*line2 && *line2 != ':') | |
1505 line2++; | |
1506 if (*line2 == ':') { | |
14936
5025e146a876
[gaim-migrate @ 17708]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14272
diff
changeset
|
1507 char *acct_name; |
14235 | 1508 line2++; |
1509 line = line2; | |
14936
5025e146a876
[gaim-migrate @ 17708]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14272
diff
changeset
|
1510 acct_name = gaim_account_get_alias(log->account); |
5025e146a876
[gaim-migrate @ 17708]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14272
diff
changeset
|
1511 if (!acct_name) |
5025e146a876
[gaim-migrate @ 17708]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14272
diff
changeset
|
1512 acct_name = gaim_account_get_username(log->account); |
5025e146a876
[gaim-migrate @ 17708]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14272
diff
changeset
|
1513 |
14235 | 1514 g_string_append_printf(formatted, |
1515 "<span style=\"color: #16569E;\">" | |
14936
5025e146a876
[gaim-migrate @ 17708]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14272
diff
changeset
|
1516 "<b>%s</b></span>:", acct_name); |
14235 | 1517 } |
1518 } | |
1519 } | |
1520 | |
1521 g_string_append(formatted, line); | |
1522 | |
1523 if (footer) | |
1524 g_string_append(formatted, footer); | |
1525 | |
1526 g_string_append_c(formatted, '\n'); | |
1527 | |
1528 if (link_temp_line) | |
1529 g_free(link_temp_line); | |
1530 | |
1531 c++; | |
1532 line = c; | |
1533 } else | |
1534 c++; | |
1535 } | |
1536 | |
1537 g_free(read); | |
1538 read = formatted->str; | |
1539 g_string_free(formatted, FALSE); | |
1540 | |
1541 return read; | |
1542 } | |
1543 | |
1544 static int trillian_logger_size (GaimLog *log) | |
1545 { | |
1546 struct trillian_logger_data *data; | |
1547 char *text; | |
1548 size_t size; | |
1549 | |
1550 g_return_val_if_fail(log != NULL, 0); | |
1551 | |
1552 data = log->logger_data; | |
1553 | |
1554 if (gaim_prefs_get_bool("/plugins/core/log_reader/fast_sizes")) { | |
1555 return data ? data->length : 0; | |
1556 } | |
1557 | |
1558 text = trillian_logger_read(log, NULL); | |
1559 size = strlen(text); | |
1560 g_free(text); | |
1561 | |
1562 return size; | |
1563 } | |
1564 | |
1565 static void trillian_logger_finalize(GaimLog *log) | |
1566 { | |
1567 struct trillian_logger_data *data; | |
1568 | |
1569 g_return_if_fail(log != NULL); | |
1570 | |
1571 data = log->logger_data; | |
1572 | |
1573 g_free(data->path); | |
1574 g_free(data->their_nickname); | |
1575 | |
1576 } | |
1577 | |
1578 | |
1579 /***************************************************************************** | |
1580 * Plugin Code * | |
1581 *****************************************************************************/ | |
1582 | |
1583 static void | |
1584 init_plugin(GaimPlugin *plugin) | |
1585 { | |
1586 char *path; | |
1587 #ifdef _WIN32 | |
1588 char *folder; | |
14272
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1589 gboolean found = FALSE; |
14235 | 1590 #endif |
1591 | |
1592 g_return_if_fail(plugin != NULL); | |
1593 | |
1594 gaim_prefs_add_none("/plugins/core/log_reader"); | |
1595 | |
1596 | |
1597 /* Add general preferences. */ | |
1598 | |
1599 gaim_prefs_add_bool("/plugins/core/log_reader/fast_sizes", FALSE); | |
1600 gaim_prefs_add_bool("/plugins/core/log_reader/use_name_heuristics", TRUE); | |
1601 | |
1602 | |
1603 /* Add Adium log directory preference. */ | |
1604 gaim_prefs_add_none("/plugins/core/log_reader/adium"); | |
1605 | |
1606 /* Calculate default Adium log directory. */ | |
1607 #ifdef _WIN32 | |
1608 path = ""; | |
1609 #else | |
1610 path = g_build_filename(gaim_home_dir(), "Library", "Application Support", | |
1611 "Adium 2.0", "Users", "Default", "Logs", NULL); | |
1612 #endif | |
1613 | |
1614 gaim_prefs_add_string("/plugins/core/log_reader/adium/log_directory", path); | |
1615 | |
1616 #ifndef _WIN32 | |
1617 g_free(path); | |
1618 #endif | |
1619 | |
1620 | |
1621 /* Add Fire log directory preference. */ | |
1622 gaim_prefs_add_none("/plugins/core/log_reader/fire"); | |
1623 | |
1624 /* Calculate default Fire log directory. */ | |
1625 #ifdef _WIN32 | |
1626 path = ""; | |
1627 #else | |
1628 path = g_build_filename(gaim_home_dir(), "Library", "Application Support", | |
1629 "Fire", "Sessions", NULL); | |
1630 #endif | |
1631 | |
1632 gaim_prefs_add_string("/plugins/core/log_reader/fire/log_directory", path); | |
1633 | |
1634 #ifndef _WIN32 | |
1635 g_free(path); | |
1636 #endif | |
1637 | |
1638 | |
1639 /* Add Messenger Plus! log directory preference. */ | |
1640 gaim_prefs_add_none("/plugins/core/log_reader/messenger_plus"); | |
1641 | |
1642 /* Calculate default Messenger Plus! log directory. */ | |
1643 #ifdef _WIN32 | |
1644 folder = wgaim_get_special_folder(CSIDL_PERSONAL); | |
1645 if (folder) { | |
1646 #endif | |
1647 path = g_build_filename( | |
1648 #ifdef _WIN32 | |
1649 folder, | |
1650 #else | |
1651 GAIM_LOG_READER_WINDOWS_MOUNT_POINT, "Documents and Settings", | |
1652 g_get_user_name(), "My Documents", | |
1653 #endif | |
1654 "My Chat Logs", NULL); | |
1655 #ifdef _WIN32 | |
1656 g_free(folder); | |
1657 } else /* !folder */ | |
1658 path = g_strdup(""); | |
1659 #endif | |
1660 | |
1661 gaim_prefs_add_string("/plugins/core/log_reader/messenger_plus/log_directory", path); | |
1662 g_free(path); | |
1663 | |
1664 | |
1665 /* Add MSN Messenger log directory preference. */ | |
1666 gaim_prefs_add_none("/plugins/core/log_reader/msn"); | |
1667 | |
1668 /* Calculate default MSN message history directory. */ | |
1669 #ifdef _WIN32 | |
1670 folder = wgaim_get_special_folder(CSIDL_PERSONAL); | |
1671 if (folder) { | |
1672 #endif | |
1673 path = g_build_filename( | |
1674 #ifdef _WIN32 | |
1675 folder, | |
1676 #else | |
1677 GAIM_LOG_READER_WINDOWS_MOUNT_POINT, "Documents and Settings", | |
1678 g_get_user_name(), "My Documents", | |
1679 #endif | |
1680 "My Received Files", NULL); | |
1681 #ifdef _WIN32 | |
1682 g_free(folder); | |
1683 } else /* !folder */ | |
1684 path = g_strdup(""); | |
1685 #endif | |
1686 | |
1687 gaim_prefs_add_string("/plugins/core/log_reader/msn/log_directory", path); | |
1688 g_free(path); | |
1689 | |
1690 | |
1691 /* Add Trillian log directory preference. */ | |
1692 gaim_prefs_add_none("/plugins/core/log_reader/trillian"); | |
1693 | |
1694 #ifdef _WIN32 | |
1695 /* XXX: While a major hack, this is the most reliable way I could | |
1696 * think of to determine the Trillian installation directory. | |
1697 */ | |
1698 | |
1699 path = NULL; | |
14272
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1700 if ((folder = wgaim_read_reg_string(HKEY_CLASSES_ROOT, "Trillian.SkinZip\\shell\\Add\\command\\", NULL))) { |
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1701 char *value = folder; |
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1702 char *temp; |
14235 | 1703 |
14272
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1704 /* Break apart buffer. */ |
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1705 if (*value == '"') { |
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1706 value++; |
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1707 temp = value; |
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1708 while (*temp && *temp != '"') |
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1709 temp++; |
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1710 } else { |
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1711 temp = value; |
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1712 while (*temp && *temp != ' ') |
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1713 temp++; |
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1714 } |
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1715 *temp = '\0'; |
14235 | 1716 |
14272
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1717 /* Set path. */ |
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1718 if (gaim_str_has_suffix(value, "trillian.exe")) { |
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1719 value[strlen(value) - (sizeof("trillian.exe") - 1)] = '\0'; |
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1720 path = g_build_filename(value, "users", "default", "talk.ini", NULL); |
14235 | 1721 } |
14272
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1722 g_free(folder); |
14235 | 1723 } |
1724 | |
1725 if (!path) { | |
1726 char *folder = wgaim_get_special_folder(CSIDL_PROGRAM_FILES); | |
1727 if (folder) { | |
1728 path = g_build_filename(folder, "Trillian", | |
1729 "users", "default", "talk.ini", NULL); | |
1730 g_free(folder); | |
1731 } | |
1732 } | |
1733 | |
1734 if (path) { | |
1735 /* Read talk.ini file to find the log directory. */ | |
1736 GError *error = NULL; | |
1737 | |
1738 #if 0 && GLIB_CHECK_VERSION(2,6,0) /* FIXME: Not tested yet. */ | |
1739 GKeyFile *key_file; | |
1740 | |
1741 gaim_debug(GAIM_DEBUG_INFO, "Trillian talk.ini read", | |
1742 "Reading %s\n", path); | |
1743 if (!g_key_file_load_from_file(key_file, path, G_KEY_FILE_NONE, GError &error)) { | |
1744 gaim_debug(GAIM_DEBUG_ERROR, "Trillian talk.ini read", | |
1745 "Error reading talk.ini\n"); | |
1746 if (error) | |
1747 g_error_free(error); | |
1748 } else { | |
1749 char *logdir = g_key_file_get_string(key_file, "Logging", "Directory", &error); | |
1750 if (error) { | |
1751 gaim_debug(GAIM_DEBUG_ERROR, "Trillian talk.ini read", | |
1752 "Error reading Directory value from Logging section\n"); | |
1753 g_error_free(error); | |
1754 } | |
1755 | |
1756 if (logdir) { | |
1757 g_strchomp(logdir); | |
1758 gaim_prefs_add_string( | |
1759 "/plugins/core/log_reader/trillian/log_directory", logdir); | |
1760 found = TRUE; | |
1761 } | |
1762 | |
1763 g_key_file_free(key_file); | |
1764 } | |
1765 #else /* !GLIB_CHECK_VERSION(2,6,0) */ | |
1766 gsize length; | |
1767 gchar *contents = NULL; | |
1768 | |
1769 gaim_debug(GAIM_DEBUG_INFO, "Trillian talk.ini read", | |
1770 "Reading %s\n", path); | |
1771 if (!g_file_get_contents(path, &contents, &length, &error)) { | |
1772 gaim_debug(GAIM_DEBUG_ERROR, "Trillian talk.ini read", | |
1773 "Error reading talk.ini\n"); | |
1774 if (error) | |
1775 g_error_free(error); | |
1776 } else { | |
1777 char *line = contents; | |
1778 while (*contents) { | |
1779 if (*contents == '\n') { | |
1780 *contents = '\0'; | |
1781 | |
1782 /* XXX: This assumes the first Directory key is under [Logging]. */ | |
1783 if (gaim_str_has_prefix(line, "Directory=")) { | |
1784 line += (sizeof("Directory=") - 1); | |
1785 g_strchomp(line); | |
1786 gaim_prefs_add_string( | |
1787 "/plugins/core/log_reader/trillian/log_directory", | |
1788 line); | |
1789 found = TRUE; | |
1790 } | |
1791 | |
1792 contents++; | |
1793 line = contents; | |
1794 } else | |
1795 contents++; | |
1796 } | |
1797 g_free(path); | |
1798 g_free(contents); | |
1799 } | |
1800 #endif /* !GTK_CHECK_VERSION(2,6,0) */ | |
1801 } /* path */ | |
1802 | |
1803 if (!found) { | |
1804 #endif /* defined(_WIN32) */ | |
1805 | |
1806 /* Calculate default Trillian log directory. */ | |
1807 #ifdef _WIN32 | |
1808 folder = wgaim_get_special_folder(CSIDL_PROGRAM_FILES); | |
1809 if (folder) { | |
1810 #endif | |
1811 path = g_build_filename( | |
1812 #ifdef _WIN32 | |
1813 folder, | |
1814 #else | |
1815 GAIM_LOG_READER_WINDOWS_MOUNT_POINT, "Program Files", | |
1816 #endif | |
1817 "Trillian", "users", "default", "logs", NULL); | |
1818 #ifdef _WIN32 | |
1819 g_free(folder); | |
1820 } else /* !folder */ | |
1821 path = g_strdup(""); | |
1822 #endif | |
1823 | |
1824 gaim_prefs_add_string("/plugins/core/log_reader/trillian/log_directory", path); | |
1825 g_free(path); | |
1826 | |
1827 #ifdef _WIN32 | |
1828 } /* !found */ | |
1829 #endif | |
1830 } | |
1831 | |
1832 static gboolean | |
1833 plugin_load(GaimPlugin *plugin) | |
1834 { | |
1835 g_return_val_if_fail(plugin != NULL, FALSE); | |
1836 | |
1837 /* The names of IM clients are marked for translation at the request of | |
1838 translators who wanted to transliterate them. Many translators | |
1839 choose to leave them alone. Choose what's best for your language. */ | |
1840 adium_logger = gaim_log_logger_new("adium", _("Adium"), 6, | |
1841 NULL, | |
1842 NULL, | |
1843 adium_logger_finalize, | |
1844 adium_logger_list, | |
1845 adium_logger_read, | |
1846 adium_logger_size); | |
1847 gaim_log_logger_add(adium_logger); | |
1848 | |
1849 #if 0 | |
1850 /* The names of IM clients are marked for translation at the request of | |
1851 translators who wanted to transliterate them. Many translators | |
1852 choose to leave them alone. Choose what's best for your language. */ | |
1853 fire_logger = gaim_log_logger_new("fire", _("Fire"), 6, | |
1854 NULL, | |
1855 NULL, | |
1856 fire_logger_finalize, | |
1857 fire_logger_list, | |
1858 fire_logger_read, | |
1859 fire_logger_size); | |
1860 gaim_log_logger_add(fire_logger); | |
1861 | |
1862 /* The names of IM clients are marked for translation at the request of | |
1863 translators who wanted to transliterate them. Many translators | |
1864 choose to leave them alone. Choose what's best for your language. */ | |
1865 messenger_plus_logger = gaim_log_logger_new("messenger_plus", _("Messenger Plus!"), 6, | |
1866 NULL, | |
1867 NULL, | |
1868 messenger_plus_logger_finalize, | |
1869 messenger_plus_logger_list, | |
1870 messenger_plus_logger_read, | |
1871 messenger_plus_logger_size); | |
1872 gaim_log_logger_add(messenger_plus_logger); | |
1873 #endif | |
1874 | |
1875 /* The names of IM clients are marked for translation at the request of | |
1876 translators who wanted to transliterate them. Many translators | |
1877 choose to leave them alone. Choose what's best for your language. */ | |
1878 msn_logger = gaim_log_logger_new("msn", _("MSN Messenger"), 6, | |
1879 NULL, | |
1880 NULL, | |
1881 msn_logger_finalize, | |
1882 msn_logger_list, | |
1883 msn_logger_read, | |
1884 msn_logger_size); | |
1885 gaim_log_logger_add(msn_logger); | |
1886 | |
1887 /* The names of IM clients are marked for translation at the request of | |
1888 translators who wanted to transliterate them. Many translators | |
1889 choose to leave them alone. Choose what's best for your language. */ | |
1890 trillian_logger = gaim_log_logger_new("trillian", _("Trillian"), 6, | |
1891 NULL, | |
1892 NULL, | |
1893 trillian_logger_finalize, | |
1894 trillian_logger_list, | |
1895 trillian_logger_read, | |
1896 trillian_logger_size); | |
1897 gaim_log_logger_add(trillian_logger); | |
1898 | |
1899 return TRUE; | |
1900 } | |
1901 | |
1902 static gboolean | |
1903 plugin_unload(GaimPlugin *plugin) | |
1904 { | |
1905 g_return_val_if_fail(plugin != NULL, FALSE); | |
1906 | |
1907 gaim_log_logger_remove(adium_logger); | |
1908 #if 0 | |
1909 gaim_log_logger_remove(fire_logger); | |
1910 gaim_log_logger_remove(messenger_plus_logger); | |
1911 #endif | |
1912 gaim_log_logger_remove(msn_logger); | |
1913 gaim_log_logger_remove(trillian_logger); | |
1914 | |
1915 return TRUE; | |
1916 } | |
1917 | |
1918 static GaimPluginPrefFrame * | |
1919 get_plugin_pref_frame(GaimPlugin *plugin) | |
1920 { | |
1921 GaimPluginPrefFrame *frame; | |
1922 GaimPluginPref *ppref; | |
1923 | |
1924 g_return_val_if_fail(plugin != NULL, FALSE); | |
1925 | |
1926 frame = gaim_plugin_pref_frame_new(); | |
1927 | |
1928 | |
1929 /* Add general preferences. */ | |
1930 | |
1931 ppref = gaim_plugin_pref_new_with_label(_("General Log Reading Configuration")); | |
1932 gaim_plugin_pref_frame_add(frame, ppref); | |
1933 | |
1934 ppref = gaim_plugin_pref_new_with_name_and_label( | |
1935 "/plugins/core/log_reader/fast_sizes", _("Fast size calculations")); | |
1936 gaim_plugin_pref_frame_add(frame, ppref); | |
1937 | |
1938 ppref = gaim_plugin_pref_new_with_name_and_label( | |
1939 "/plugins/core/log_reader/use_name_heuristics", _("Use name heuristics")); | |
1940 gaim_plugin_pref_frame_add(frame, ppref); | |
1941 | |
1942 | |
1943 /* Add Log Directory preferences. */ | |
1944 | |
1945 ppref = gaim_plugin_pref_new_with_label(_("Log Directory")); | |
1946 gaim_plugin_pref_frame_add(frame, ppref); | |
1947 | |
1948 ppref = gaim_plugin_pref_new_with_name_and_label( | |
1949 "/plugins/core/log_reader/adium/log_directory", _("Adium")); | |
1950 gaim_plugin_pref_frame_add(frame, ppref); | |
1951 | |
1952 #if 0 | |
1953 ppref = gaim_plugin_pref_new_with_name_and_label( | |
1954 "/plugins/core/log_reader/fire/log_directory", _("Fire")); | |
1955 gaim_plugin_pref_frame_add(frame, ppref); | |
1956 | |
1957 ppref = gaim_plugin_pref_new_with_name_and_label( | |
1958 "/plugins/core/log_reader/messenger_plus/log_directory", _("Messenger Plus!")); | |
1959 gaim_plugin_pref_frame_add(frame, ppref); | |
1960 #endif | |
1961 | |
1962 ppref = gaim_plugin_pref_new_with_name_and_label( | |
1963 "/plugins/core/log_reader/msn/log_directory", _("MSN Messenger")); | |
1964 gaim_plugin_pref_frame_add(frame, ppref); | |
1965 | |
1966 ppref = gaim_plugin_pref_new_with_name_and_label( | |
1967 "/plugins/core/log_reader/trillian/log_directory", _("Trillian")); | |
1968 gaim_plugin_pref_frame_add(frame, ppref); | |
1969 | |
1970 return frame; | |
1971 } | |
1972 | |
1973 static GaimPluginUiInfo prefs_info = { | |
1974 get_plugin_pref_frame, | |
1975 0, /* page_num (reserved) */ | |
1976 NULL /* frame (reserved) */ | |
1977 }; | |
1978 | |
1979 static GaimPluginInfo info = | |
1980 { | |
1981 GAIM_PLUGIN_MAGIC, | |
1982 GAIM_MAJOR_VERSION, | |
1983 GAIM_MINOR_VERSION, | |
1984 GAIM_PLUGIN_STANDARD, /**< type */ | |
1985 NULL, /**< ui_requirement */ | |
1986 0, /**< flags */ | |
1987 NULL, /**< dependencies */ | |
1988 GAIM_PRIORITY_DEFAULT, /**< priority */ | |
1989 "core-log_reader", /**< id */ | |
1990 N_("Log Reader"), /**< name */ | |
1991 VERSION, /**< version */ | |
1992 | |
1993 /** summary */ | |
1994 N_("Includes other IM clients' logs in the " | |
1995 "log viewer."), | |
1996 | |
1997 /** description */ | |
1998 N_("When viewing logs, this plugin will include " | |
1999 "logs from other IM clients. Currently, this " | |
2000 "includes Adium, MSN Messenger, and Trillian.\n\n" | |
2001 "WARNING: This plugin is still alpha code and " | |
2002 "may crash frequently. Use it at your own risk!"), | |
2003 | |
2004 "Richard Laager <rlaager@users.sf.net>", /**< author */ | |
2005 GAIM_WEBSITE, /**< homepage */ | |
2006 plugin_load, /**< load */ | |
2007 plugin_unload, /**< unload */ | |
2008 NULL, /**< destroy */ | |
2009 NULL, /**< ui_info */ | |
2010 NULL, /**< extra_info */ | |
2011 &prefs_info, /**< prefs_info */ | |
2012 NULL /**< actions */ | |
2013 }; | |
2014 | |
2015 GAIM_INIT_PLUGIN(log_reader, init_plugin, info) |