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