Mercurial > pidgin
annotate libgaim/plugins/log_reader.c @ 14416:eeca8be382a5
[gaim-migrate @ 17124]
This is a Gaim::Gtk perl module for use by gaim plugins to get access to the
gtkgaim interface functions. It isn't complete because anything dealing with
Gtk widgets themselves doesn't work yet (I need to figure out the best way to
do that). To use this a perl plugin just needs to include 'use Gaim::Gtk;'
either on top of 'use Gaim;' or instead of it.
I'm not done with this yet.
At the moment you have to 'use Gaim;' or 'use Gaim::Gtk;' which loads all the
parts, I'm planning to let you actually say 'use Gaim::Gtk::Debug;' to just
get the gtkdebug.h functions. Though 'use Gaim' would work the same way as
always.
committer: Tailor Script <tailor@pidgin.im>
| author | Etan Reisner <pidgin@unreliablesource.net> |
|---|---|
| date | Sat, 02 Sep 2006 05:31:10 +0000 |
| parents | 7635195195c0 |
| children | 5025e146a876 |
| 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); | |
| 851 int alias_length = strlen(log->account->alias); | |
| 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 | |
| 975 if (name_guessed == NAME_GUESS_ME) | |
| 976 text = g_string_append(text, log->account->alias); | |
| 977 else if (name_guessed == NAME_GUESS_THEM) | |
| 978 text = g_string_append(text, their_name); | |
| 979 else | |
| 980 text = g_string_append(text, from_name); | |
| 981 | |
| 982 text = g_string_append(text, ":</b> "); | |
| 983 } | |
| 984 | |
| 985 if (name_guessed != NAME_GUESS_UNKNOWN) | |
| 986 text = g_string_append(text, "</span>"); | |
| 987 | |
| 988 style = xmlnode_get_attrib(text_node, "Style"); | |
| 989 | |
| 990 tmp = xmlnode_get_data(text_node); | |
| 991 if (style && *style) { | |
| 992 text = g_string_append(text, "<span style=\""); | |
| 993 text = g_string_append(text, style); | |
| 994 text = g_string_append(text, "\">"); | |
| 995 text = g_string_append(text, tmp); | |
| 996 text = g_string_append(text, "</span>\n"); | |
| 997 } else { | |
| 998 text = g_string_append(text, tmp); | |
| 999 text = g_string_append(text, "\n"); | |
| 1000 } | |
| 1001 g_free(tmp); | |
| 1002 } | |
| 1003 | |
| 1004 data->text = text; | |
| 1005 | |
| 1006 return text->str; | |
| 1007 } | |
| 1008 | |
| 1009 static int msn_logger_size (GaimLog *log) | |
| 1010 { | |
| 1011 char *text; | |
| 1012 size_t size; | |
| 1013 | |
| 1014 g_return_val_if_fail(log != NULL, 0); | |
| 1015 | |
| 1016 if (gaim_prefs_get_bool("/plugins/core/log_reader/fast_sizes")) | |
| 1017 return 0; | |
| 1018 | |
| 1019 text = msn_logger_read(log, NULL); | |
| 1020 size = strlen(text); | |
| 1021 g_free(text); | |
| 1022 | |
| 1023 return size; | |
| 1024 } | |
| 1025 | |
| 1026 static void msn_logger_finalize(GaimLog *log) | |
| 1027 { | |
| 1028 struct msn_logger_data *data; | |
| 1029 | |
| 1030 g_return_if_fail(log != NULL); | |
| 1031 | |
| 1032 data = log->logger_data; | |
| 1033 | |
| 1034 if (data->last_log) | |
| 1035 xmlnode_free(data->root); | |
| 1036 | |
| 1037 if (data->text) | |
| 1038 g_string_free(data->text, FALSE); | |
| 1039 } | |
| 1040 | |
| 1041 | |
| 1042 /***************************************************************************** | |
| 1043 * Trillian Logger * | |
| 1044 *****************************************************************************/ | |
| 1045 | |
| 1046 /* The trillian logger doesn't write logs, only reads them. This is to include | |
| 1047 * Trillian logs in the log viewer transparently. | |
| 1048 */ | |
| 1049 | |
| 1050 static GaimLogLogger *trillian_logger; | |
| 1051 static void trillian_logger_finalize(GaimLog *log); | |
| 1052 | |
| 1053 struct trillian_logger_data { | |
| 1054 char *path; /* FIXME: Change this to use GaimStringref like log.c:old_logger_list */ | |
| 1055 int offset; | |
| 1056 int length; | |
| 1057 char *their_nickname; | |
| 1058 }; | |
| 1059 | |
| 1060 static GList *trillian_logger_list(GaimLogType type, const char *sn, GaimAccount *account) | |
| 1061 { | |
| 1062 GList *list = NULL; | |
| 1063 const char *logdir; | |
| 1064 GaimPlugin *plugin; | |
| 1065 GaimPluginProtocolInfo *prpl_info; | |
| 1066 char *prpl_name; | |
| 1067 const char *buddy_name; | |
| 1068 char *filename; | |
| 1069 char *path; | |
| 1070 GError *error = NULL; | |
| 1071 gchar *contents = NULL; | |
| 1072 gsize length; | |
| 1073 gchar *line; | |
| 1074 gchar *c; | |
| 1075 | |
| 1076 g_return_val_if_fail(sn != NULL, list); | |
| 1077 g_return_val_if_fail(account != NULL, list); | |
| 1078 | |
| 1079 logdir = gaim_prefs_get_string("/plugins/core/log_reader/trillian/log_directory"); | |
| 1080 | |
| 1081 /* By clearing the log directory path, this logger can be (effectively) disabled. */ | |
| 1082 if (!*logdir) | |
| 1083 return list; | |
| 1084 | |
| 1085 plugin = gaim_find_prpl(gaim_account_get_protocol_id(account)); | |
| 1086 if (!plugin) | |
| 1087 return NULL; | |
| 1088 | |
| 1089 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(plugin); | |
| 1090 if (!prpl_info->list_icon) | |
| 1091 return NULL; | |
| 1092 | |
| 1093 prpl_name = g_ascii_strup(prpl_info->list_icon(account, NULL), -1); | |
| 1094 | |
| 1095 buddy_name = gaim_normalize(account, sn); | |
| 1096 | |
| 1097 filename = g_strdup_printf("%s.log", buddy_name); | |
| 1098 path = g_build_filename( | |
| 1099 logdir, prpl_name, filename, NULL); | |
| 1100 | |
| 1101 gaim_debug(GAIM_DEBUG_INFO, "Trillian log list", | |
| 1102 "Reading %s\n", path); | |
| 1103 /* FIXME: There's really no need to read the entire file at once. | |
| 1104 * See src/log.c:old_logger_list for a better approach. | |
| 1105 */ | |
| 1106 if (!g_file_get_contents(path, &contents, &length, &error)) { | |
| 1107 if (error) { | |
| 1108 g_error_free(error); | |
| 1109 error = NULL; | |
| 1110 } | |
| 1111 g_free(path); | |
| 1112 | |
| 1113 path = g_build_filename( | |
| 1114 logdir, prpl_name, "Query", filename, NULL); | |
| 1115 gaim_debug(GAIM_DEBUG_INFO, "Trillian log list", | |
| 1116 "Reading %s\n", path); | |
| 1117 if (!g_file_get_contents(path, &contents, &length, &error)) { | |
| 1118 if (error) | |
| 1119 g_error_free(error); | |
| 1120 } | |
| 1121 } | |
| 1122 g_free(filename); | |
| 1123 | |
| 1124 if (contents) { | |
| 1125 struct trillian_logger_data *data = NULL; | |
| 1126 int offset = 0; | |
| 1127 int last_line_offset = 0; | |
| 1128 | |
| 1129 line = contents; | |
| 1130 c = contents; | |
| 1131 while (*c) { | |
| 1132 offset++; | |
| 1133 | |
| 1134 if (*c != '\n') { | |
| 1135 c++; | |
| 1136 continue; | |
| 1137 } | |
| 1138 | |
| 1139 *c = '\0'; | |
| 1140 if (gaim_str_has_prefix(line, "Session Close ")) { | |
| 1141 if (data && !data->length) { | |
| 1142 if (!(data->length = last_line_offset - data->offset)) { | |
| 1143 /* This log had no data, so we remove it. */ | |
| 1144 GList *last = g_list_last(list); | |
| 1145 | |
| 1146 gaim_debug(GAIM_DEBUG_INFO, "Trillian log list", | |
| 1147 "Empty log. Offset %i\n", data->offset); | |
| 1148 | |
| 1149 trillian_logger_finalize((GaimLog *)last->data); | |
| 1150 list = g_list_delete_link(list, last); | |
| 1151 } | |
| 1152 } | |
| 1153 } else if (line[0] && line[1] && line [3] && | |
| 1154 gaim_str_has_prefix(&line[3], "sion Start ")) { | |
| 1155 | |
| 1156 char *their_nickname = line; | |
| 1157 char *timestamp; | |
| 1158 | |
| 1159 if (data && !data->length) | |
| 1160 data->length = last_line_offset - data->offset; | |
| 1161 | |
| 1162 while (*their_nickname && (*their_nickname != ':')) | |
| 1163 their_nickname++; | |
| 1164 their_nickname++; | |
| 1165 | |
| 1166 /* This code actually has nothing to do with | |
| 1167 * the timestamp YET. I'm simply using this | |
| 1168 * variable for now to NUL-terminate the | |
| 1169 * their_nickname string. | |
| 1170 */ | |
| 1171 timestamp = their_nickname; | |
| 1172 while (*timestamp && *timestamp != ')') | |
| 1173 timestamp++; | |
| 1174 | |
| 1175 if (*timestamp == ')') { | |
| 1176 char *month; | |
| 1177 struct tm tm; | |
| 1178 | |
| 1179 *timestamp = '\0'; | |
| 1180 if (line[0] && line[1] && line[2]) | |
| 1181 timestamp += 3; | |
| 1182 | |
| 1183 /* Now we start dealing with the timestamp. */ | |
| 1184 | |
| 1185 /* Skip over the day name. */ | |
| 1186 while (*timestamp && (*timestamp != ' ')) | |
| 1187 timestamp++; | |
| 1188 *timestamp = '\0'; | |
| 1189 timestamp++; | |
| 1190 | |
| 1191 /* Parse out the month. */ | |
| 1192 month = timestamp; | |
| 1193 while (*timestamp && (*timestamp != ' ')) | |
| 1194 timestamp++; | |
| 1195 *timestamp = '\0'; | |
| 1196 timestamp++; | |
| 1197 | |
| 1198 /* Parse the day, time, and year. */ | |
| 1199 if (sscanf(timestamp, "%u %u:%u:%u %u", | |
| 1200 &tm.tm_mday, &tm.tm_hour, | |
| 1201 &tm.tm_min, &tm.tm_sec, | |
| 1202 &tm.tm_year) != 5) { | |
| 1203 | |
| 1204 gaim_debug(GAIM_DEBUG_ERROR, | |
| 1205 "Trillian log timestamp parse", | |
| 1206 "Session Start parsing error\n"); | |
| 1207 } else { | |
| 1208 GaimLog *log; | |
| 1209 | |
| 1210 tm.tm_year -= 1900; | |
| 1211 | |
| 1212 /* Let the C library deal with | |
| 1213 * daylight savings time. | |
| 1214 */ | |
| 1215 tm.tm_isdst = -1; | |
| 1216 | |
| 1217 /* Ugly hack, in case current locale | |
| 1218 * is not English. This code is taken | |
| 1219 * from log.c. | |
| 1220 */ | |
| 1221 if (strcmp(month, "Jan") == 0) { | |
| 1222 tm.tm_mon= 0; | |
| 1223 } else if (strcmp(month, "Feb") == 0) { | |
| 1224 tm.tm_mon = 1; | |
| 1225 } else if (strcmp(month, "Mar") == 0) { | |
| 1226 tm.tm_mon = 2; | |
| 1227 } else if (strcmp(month, "Apr") == 0) { | |
| 1228 tm.tm_mon = 3; | |
| 1229 } else if (strcmp(month, "May") == 0) { | |
| 1230 tm.tm_mon = 4; | |
| 1231 } else if (strcmp(month, "Jun") == 0) { | |
| 1232 tm.tm_mon = 5; | |
| 1233 } else if (strcmp(month, "Jul") == 0) { | |
| 1234 tm.tm_mon = 6; | |
| 1235 } else if (strcmp(month, "Aug") == 0) { | |
| 1236 tm.tm_mon = 7; | |
| 1237 } else if (strcmp(month, "Sep") == 0) { | |
| 1238 tm.tm_mon = 8; | |
| 1239 } else if (strcmp(month, "Oct") == 0) { | |
| 1240 tm.tm_mon = 9; | |
| 1241 } else if (strcmp(month, "Nov") == 0) { | |
| 1242 tm.tm_mon = 10; | |
| 1243 } else if (strcmp(month, "Dec") == 0) { | |
| 1244 tm.tm_mon = 11; | |
| 1245 } | |
| 1246 | |
| 1247 data = g_new0( | |
| 1248 struct trillian_logger_data, 1); | |
| 1249 data->path = g_strdup(path); | |
| 1250 data->offset = offset; | |
| 1251 data->length = 0; | |
| 1252 data->their_nickname = | |
| 1253 g_strdup(their_nickname); | |
| 1254 | |
| 1255 /* XXX: Look into this later... Should we pass in a struct tm? */ | |
| 1256 log = gaim_log_new(GAIM_LOG_IM, | |
| 1257 sn, account, NULL, mktime(&tm), NULL); | |
| 1258 log->logger = trillian_logger; | |
| 1259 log->logger_data = data; | |
| 1260 | |
| 1261 list = g_list_append(list, log); | |
| 1262 } | |
| 1263 } | |
| 1264 } | |
| 1265 c++; | |
| 1266 line = c; | |
| 1267 last_line_offset = offset; | |
| 1268 } | |
| 1269 | |
| 1270 g_free(contents); | |
| 1271 } | |
| 1272 g_free(path); | |
| 1273 | |
| 1274 g_free(prpl_name); | |
| 1275 | |
| 1276 return list; | |
| 1277 } | |
| 1278 | |
| 1279 static char * trillian_logger_read (GaimLog *log, GaimLogReadFlags *flags) | |
| 1280 { | |
| 1281 struct trillian_logger_data *data; | |
| 1282 char *read; | |
| 1283 FILE *file; | |
| 1284 GaimBuddy *buddy; | |
| 1285 char *escaped; | |
| 1286 GString *formatted; | |
| 1287 char *c; | |
| 1288 char *line; | |
| 1289 | |
| 1290 g_return_val_if_fail(log != NULL, g_strdup("")); | |
| 1291 | |
| 1292 data = log->logger_data; | |
| 1293 | |
| 1294 g_return_val_if_fail(data->path != NULL, g_strdup("")); | |
| 1295 g_return_val_if_fail(data->length > 0, g_strdup("")); | |
| 1296 g_return_val_if_fail(data->their_nickname != NULL, g_strdup("")); | |
| 1297 | |
| 1298 gaim_debug(GAIM_DEBUG_INFO, "Trillian log read", | |
| 1299 "Reading %s\n", data->path); | |
| 1300 | |
| 1301 read = g_malloc(data->length + 2); | |
| 1302 | |
| 1303 file = g_fopen(data->path, "rb"); | |
| 1304 fseek(file, data->offset, SEEK_SET); | |
| 1305 fread(read, data->length, 1, file); | |
| 1306 fclose(file); | |
| 1307 | |
| 1308 if (read[data->length-1] == '\n') { | |
| 1309 read[data->length] = '\0'; | |
| 1310 } else { | |
| 1311 read[data->length] = '\n'; | |
| 1312 read[data->length+1] = '\0'; | |
| 1313 } | |
| 1314 | |
| 1315 /* Load miscellaneous data. */ | |
| 1316 buddy = gaim_find_buddy(log->account, log->name); | |
| 1317 | |
| 1318 escaped = g_markup_escape_text(read, -1); | |
| 1319 g_free(read); | |
| 1320 read = escaped; | |
| 1321 | |
| 1322 /* Apply formatting... */ | |
| 1323 formatted = g_string_new(""); | |
| 1324 c = read; | |
| 1325 line = read; | |
| 1326 while (*c) | |
| 1327 { | |
| 1328 if (*c == '\n') | |
| 1329 { | |
| 1330 char *link_temp_line; | |
| 1331 char *link; | |
| 1332 char *timestamp; | |
| 1333 char *footer = NULL; | |
| 1334 *c = '\0'; | |
| 1335 | |
| 1336 /* Convert links. | |
| 1337 * | |
| 1338 * The format is (Link: URL)URL | |
| 1339 * So, I want to find each occurance of "(Link: " and replace that chunk with: | |
| 1340 * <a href=" | |
| 1341 * Then, replace the next ")" with: | |
| 1342 * "> | |
| 1343 * Then, replace the next " " (or add this if the end-of-line is reached) with: | |
| 1344 * </a> | |
| 1345 */ | |
| 1346 link_temp_line = NULL; | |
| 1347 while ((link = g_strstr_len(line, strlen(line), "(Link: "))) { | |
| 1348 GString *temp; | |
| 1349 | |
| 1350 if (!*link) | |
| 1351 continue; | |
| 1352 | |
| 1353 *link = '\0'; | |
| 1354 link++; | |
| 1355 | |
| 1356 temp = g_string_new(line); | |
| 1357 g_string_append(temp, "<a href=\""); | |
| 1358 | |
| 1359 if (strlen(link) >= 6) { | |
| 1360 link += (sizeof("(Link: ") - 1); | |
| 1361 | |
| 1362 while (*link && *link != ')') { | |
| 1363 g_string_append_c(temp, *link); | |
| 1364 link++; | |
| 1365 } | |
| 1366 if (link) { | |
| 1367 link++; | |
| 1368 | |
| 1369 g_string_append(temp, "\">"); | |
| 1370 while (*link && *link != ' ') { | |
| 1371 g_string_append_c(temp, *link); | |
| 1372 link++; | |
| 1373 } | |
| 1374 g_string_append(temp, "</a>"); | |
| 1375 } | |
| 1376 | |
| 1377 g_string_append(temp, link); | |
| 1378 | |
| 1379 /* Free the last round's line. */ | |
| 1380 if (link_temp_line) | |
| 1381 g_free(line); | |
| 1382 | |
| 1383 line = temp->str; | |
| 1384 g_string_free(temp, FALSE); | |
| 1385 | |
| 1386 /* Save this memory location so we can free it later. */ | |
| 1387 link_temp_line = line; | |
| 1388 } | |
| 1389 } | |
| 1390 | |
| 1391 timestamp = ""; | |
| 1392 if (*line == '[') { | |
| 1393 timestamp = line; | |
| 1394 while (*timestamp && *timestamp != ']') | |
| 1395 timestamp++; | |
| 1396 if (*timestamp == ']') { | |
| 1397 *timestamp = '\0'; | |
| 1398 line++; | |
| 1399 /* TODO: Parse the timestamp and convert it to Gaim's format. */ | |
| 1400 g_string_append_printf(formatted, | |
| 1401 "<font size=\"2\">(%s)</font> ", line); | |
| 1402 line = timestamp; | |
| 1403 if (line[1] && line[2]) | |
| 1404 line += 2; | |
| 1405 } | |
| 1406 | |
| 1407 if (gaim_str_has_prefix(line, "*** ")) { | |
| 1408 line += (sizeof("*** ") - 1); | |
| 1409 g_string_append(formatted, "<b>"); | |
| 1410 footer = "</b>"; | |
| 1411 if (gaim_str_has_prefix(line, "NOTE: This user is offline.")) { | |
| 1412 line = _("User is offline."); | |
| 1413 } else if (gaim_str_has_prefix(line, | |
| 1414 "NOTE: Your status is currently set to ")) { | |
| 1415 | |
| 1416 line += (sizeof("NOTE: ") - 1); | |
| 1417 } else if (gaim_str_has_prefix(line, "Auto-response sent to ")) { | |
| 1418 g_string_append(formatted, _("Auto-response sent:")); | |
| 1419 while (*line && *line != ':') | |
| 1420 line++; | |
| 1421 if (*line) | |
| 1422 line++; | |
| 1423 g_string_append(formatted, "</b>"); | |
| 1424 footer = NULL; | |
| 1425 } else if (strstr(line, " signed off ")) { | |
| 1426 if (buddy != NULL && buddy->alias) | |
| 1427 g_string_append_printf(formatted, | |
| 1428 _("%s has signed off."), buddy->alias); | |
| 1429 else | |
| 1430 g_string_append_printf(formatted, | |
| 1431 _("%s has signed off."), log->name); | |
| 1432 line = ""; | |
| 1433 } else if (strstr(line, " signed on ")) { | |
| 1434 if (buddy != NULL && buddy->alias) | |
| 1435 g_string_append(formatted, buddy->alias); | |
| 1436 else | |
| 1437 g_string_append(formatted, log->name); | |
| 1438 line = " logged in."; | |
| 1439 } else if (gaim_str_has_prefix(line, | |
| 1440 "One or more messages may have been undeliverable.")) { | |
| 1441 | |
| 1442 g_string_append(formatted, | |
| 1443 "<span style=\"color: #ff0000;\">"); | |
| 1444 g_string_append(formatted, | |
| 1445 _("One or more messages may have been " | |
| 1446 "undeliverable.")); | |
| 1447 line = ""; | |
| 1448 footer = "</span></b>"; | |
| 1449 } else if (gaim_str_has_prefix(line, | |
| 1450 "You have been disconnected.")) { | |
| 1451 | |
| 1452 g_string_append(formatted, | |
| 1453 "<span style=\"color: #ff0000;\">"); | |
| 1454 g_string_append(formatted, | |
| 1455 _("You were disconnected from the server.")); | |
| 1456 line = ""; | |
| 1457 footer = "</span></b>"; | |
| 1458 } else if (gaim_str_has_prefix(line, | |
| 1459 "You are currently disconnected.")) { | |
| 1460 | |
| 1461 g_string_append(formatted, | |
| 1462 "<span style=\"color: #ff0000;\">"); | |
| 1463 line = _("You are currently disconnected. Messages " | |
| 1464 "will not be received unless you are " | |
| 1465 "logged in."); | |
| 1466 footer = "</span></b>"; | |
| 1467 } else if (gaim_str_has_prefix(line, | |
| 1468 "Your previous message has not been sent.")) { | |
| 1469 | |
| 1470 g_string_append(formatted, | |
| 1471 "<span style=\"color: #ff0000;\">"); | |
| 1472 | |
| 1473 if (gaim_str_has_prefix(line, | |
| 1474 "Your previous message has not been sent. " | |
| 1475 "Reason: Maximum length exceeded.")) { | |
| 1476 | |
| 1477 g_string_append(formatted, | |
| 1478 _("Message could not be sent because " | |
| 1479 "the maximum length was exceeded.")); | |
| 1480 line = ""; | |
| 1481 } else { | |
| 1482 g_string_append(formatted, | |
| 1483 _("Message could not be sent.")); | |
| 1484 line += (sizeof( | |
| 1485 "Your previous message " | |
| 1486 "has not been sent. ") - 1); | |
| 1487 } | |
| 1488 | |
| 1489 footer = "</span></b>"; | |
| 1490 } | |
| 1491 } else if (gaim_str_has_prefix(line, data->their_nickname)) { | |
| 1492 if (buddy != NULL && buddy->alias) { | |
| 1493 line += strlen(data->their_nickname) + 2; | |
| 1494 g_string_append_printf(formatted, | |
| 1495 "<span style=\"color: #A82F2F;\">" | |
| 1496 "<b>%s</b></span>: ", buddy->alias); | |
| 1497 } | |
| 1498 } else { | |
| 1499 char *line2 = line; | |
| 1500 while (*line2 && *line2 != ':') | |
| 1501 line2++; | |
| 1502 if (*line2 == ':') { | |
| 1503 line2++; | |
| 1504 line = line2; | |
| 1505 g_string_append_printf(formatted, | |
| 1506 "<span style=\"color: #16569E;\">" | |
| 1507 "<b>%s</b></span>:", log->account->alias); | |
| 1508 } | |
| 1509 } | |
| 1510 } | |
| 1511 | |
| 1512 g_string_append(formatted, line); | |
| 1513 | |
| 1514 if (footer) | |
| 1515 g_string_append(formatted, footer); | |
| 1516 | |
| 1517 g_string_append_c(formatted, '\n'); | |
| 1518 | |
| 1519 if (link_temp_line) | |
| 1520 g_free(link_temp_line); | |
| 1521 | |
| 1522 c++; | |
| 1523 line = c; | |
| 1524 } else | |
| 1525 c++; | |
| 1526 } | |
| 1527 | |
| 1528 g_free(read); | |
| 1529 read = formatted->str; | |
| 1530 g_string_free(formatted, FALSE); | |
| 1531 | |
| 1532 return read; | |
| 1533 } | |
| 1534 | |
| 1535 static int trillian_logger_size (GaimLog *log) | |
| 1536 { | |
| 1537 struct trillian_logger_data *data; | |
| 1538 char *text; | |
| 1539 size_t size; | |
| 1540 | |
| 1541 g_return_val_if_fail(log != NULL, 0); | |
| 1542 | |
| 1543 data = log->logger_data; | |
| 1544 | |
| 1545 if (gaim_prefs_get_bool("/plugins/core/log_reader/fast_sizes")) { | |
| 1546 return data ? data->length : 0; | |
| 1547 } | |
| 1548 | |
| 1549 text = trillian_logger_read(log, NULL); | |
| 1550 size = strlen(text); | |
| 1551 g_free(text); | |
| 1552 | |
| 1553 return size; | |
| 1554 } | |
| 1555 | |
| 1556 static void trillian_logger_finalize(GaimLog *log) | |
| 1557 { | |
| 1558 struct trillian_logger_data *data; | |
| 1559 | |
| 1560 g_return_if_fail(log != NULL); | |
| 1561 | |
| 1562 data = log->logger_data; | |
| 1563 | |
| 1564 g_free(data->path); | |
| 1565 g_free(data->their_nickname); | |
| 1566 | |
| 1567 } | |
| 1568 | |
| 1569 | |
| 1570 /***************************************************************************** | |
| 1571 * Plugin Code * | |
| 1572 *****************************************************************************/ | |
| 1573 | |
| 1574 static void | |
| 1575 init_plugin(GaimPlugin *plugin) | |
| 1576 { | |
| 1577 char *path; | |
| 1578 #ifdef _WIN32 | |
| 1579 char *folder; | |
|
14272
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1580 gboolean found = FALSE; |
| 14235 | 1581 #endif |
| 1582 | |
| 1583 g_return_if_fail(plugin != NULL); | |
| 1584 | |
| 1585 gaim_prefs_add_none("/plugins/core/log_reader"); | |
| 1586 | |
| 1587 | |
| 1588 /* Add general preferences. */ | |
| 1589 | |
| 1590 gaim_prefs_add_bool("/plugins/core/log_reader/fast_sizes", FALSE); | |
| 1591 gaim_prefs_add_bool("/plugins/core/log_reader/use_name_heuristics", TRUE); | |
| 1592 | |
| 1593 | |
| 1594 /* Add Adium log directory preference. */ | |
| 1595 gaim_prefs_add_none("/plugins/core/log_reader/adium"); | |
| 1596 | |
| 1597 /* Calculate default Adium log directory. */ | |
| 1598 #ifdef _WIN32 | |
| 1599 path = ""; | |
| 1600 #else | |
| 1601 path = g_build_filename(gaim_home_dir(), "Library", "Application Support", | |
| 1602 "Adium 2.0", "Users", "Default", "Logs", NULL); | |
| 1603 #endif | |
| 1604 | |
| 1605 gaim_prefs_add_string("/plugins/core/log_reader/adium/log_directory", path); | |
| 1606 | |
| 1607 #ifndef _WIN32 | |
| 1608 g_free(path); | |
| 1609 #endif | |
| 1610 | |
| 1611 | |
| 1612 /* Add Fire log directory preference. */ | |
| 1613 gaim_prefs_add_none("/plugins/core/log_reader/fire"); | |
| 1614 | |
| 1615 /* Calculate default Fire log directory. */ | |
| 1616 #ifdef _WIN32 | |
| 1617 path = ""; | |
| 1618 #else | |
| 1619 path = g_build_filename(gaim_home_dir(), "Library", "Application Support", | |
| 1620 "Fire", "Sessions", NULL); | |
| 1621 #endif | |
| 1622 | |
| 1623 gaim_prefs_add_string("/plugins/core/log_reader/fire/log_directory", path); | |
| 1624 | |
| 1625 #ifndef _WIN32 | |
| 1626 g_free(path); | |
| 1627 #endif | |
| 1628 | |
| 1629 | |
| 1630 /* Add Messenger Plus! log directory preference. */ | |
| 1631 gaim_prefs_add_none("/plugins/core/log_reader/messenger_plus"); | |
| 1632 | |
| 1633 /* Calculate default Messenger Plus! log directory. */ | |
| 1634 #ifdef _WIN32 | |
| 1635 folder = wgaim_get_special_folder(CSIDL_PERSONAL); | |
| 1636 if (folder) { | |
| 1637 #endif | |
| 1638 path = g_build_filename( | |
| 1639 #ifdef _WIN32 | |
| 1640 folder, | |
| 1641 #else | |
| 1642 GAIM_LOG_READER_WINDOWS_MOUNT_POINT, "Documents and Settings", | |
| 1643 g_get_user_name(), "My Documents", | |
| 1644 #endif | |
| 1645 "My Chat Logs", NULL); | |
| 1646 #ifdef _WIN32 | |
| 1647 g_free(folder); | |
| 1648 } else /* !folder */ | |
| 1649 path = g_strdup(""); | |
| 1650 #endif | |
| 1651 | |
| 1652 gaim_prefs_add_string("/plugins/core/log_reader/messenger_plus/log_directory", path); | |
| 1653 g_free(path); | |
| 1654 | |
| 1655 | |
| 1656 /* Add MSN Messenger log directory preference. */ | |
| 1657 gaim_prefs_add_none("/plugins/core/log_reader/msn"); | |
| 1658 | |
| 1659 /* Calculate default MSN message history directory. */ | |
| 1660 #ifdef _WIN32 | |
| 1661 folder = wgaim_get_special_folder(CSIDL_PERSONAL); | |
| 1662 if (folder) { | |
| 1663 #endif | |
| 1664 path = g_build_filename( | |
| 1665 #ifdef _WIN32 | |
| 1666 folder, | |
| 1667 #else | |
| 1668 GAIM_LOG_READER_WINDOWS_MOUNT_POINT, "Documents and Settings", | |
| 1669 g_get_user_name(), "My Documents", | |
| 1670 #endif | |
| 1671 "My Received Files", NULL); | |
| 1672 #ifdef _WIN32 | |
| 1673 g_free(folder); | |
| 1674 } else /* !folder */ | |
| 1675 path = g_strdup(""); | |
| 1676 #endif | |
| 1677 | |
| 1678 gaim_prefs_add_string("/plugins/core/log_reader/msn/log_directory", path); | |
| 1679 g_free(path); | |
| 1680 | |
| 1681 | |
| 1682 /* Add Trillian log directory preference. */ | |
| 1683 gaim_prefs_add_none("/plugins/core/log_reader/trillian"); | |
| 1684 | |
| 1685 #ifdef _WIN32 | |
| 1686 /* XXX: While a major hack, this is the most reliable way I could | |
| 1687 * think of to determine the Trillian installation directory. | |
| 1688 */ | |
| 1689 | |
| 1690 path = NULL; | |
|
14272
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1691 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
|
1692 char *value = folder; |
|
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1693 char *temp; |
| 14235 | 1694 |
|
14272
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1695 /* Break apart buffer. */ |
|
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1696 if (*value == '"') { |
|
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1697 value++; |
|
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1698 temp = value; |
|
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1699 while (*temp && *temp != '"') |
|
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1700 temp++; |
|
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1701 } else { |
|
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1702 temp = value; |
|
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1703 while (*temp && *temp != ' ') |
|
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1704 temp++; |
|
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1705 } |
|
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1706 *temp = '\0'; |
| 14235 | 1707 |
|
14272
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1708 /* Set path. */ |
|
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1709 if (gaim_str_has_suffix(value, "trillian.exe")) { |
|
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1710 value[strlen(value) - (sizeof("trillian.exe") - 1)] = '\0'; |
|
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1711 path = g_build_filename(value, "users", "default", "talk.ini", NULL); |
| 14235 | 1712 } |
|
14272
7635195195c0
[gaim-migrate @ 16957]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
14235
diff
changeset
|
1713 g_free(folder); |
| 14235 | 1714 } |
| 1715 | |
| 1716 if (!path) { | |
| 1717 char *folder = wgaim_get_special_folder(CSIDL_PROGRAM_FILES); | |
| 1718 if (folder) { | |
| 1719 path = g_build_filename(folder, "Trillian", | |
| 1720 "users", "default", "talk.ini", NULL); | |
| 1721 g_free(folder); | |
| 1722 } | |
| 1723 } | |
| 1724 | |
| 1725 if (path) { | |
| 1726 /* Read talk.ini file to find the log directory. */ | |
| 1727 GError *error = NULL; | |
| 1728 | |
| 1729 #if 0 && GLIB_CHECK_VERSION(2,6,0) /* FIXME: Not tested yet. */ | |
| 1730 GKeyFile *key_file; | |
| 1731 | |
| 1732 gaim_debug(GAIM_DEBUG_INFO, "Trillian talk.ini read", | |
| 1733 "Reading %s\n", path); | |
| 1734 if (!g_key_file_load_from_file(key_file, path, G_KEY_FILE_NONE, GError &error)) { | |
| 1735 gaim_debug(GAIM_DEBUG_ERROR, "Trillian talk.ini read", | |
| 1736 "Error reading talk.ini\n"); | |
| 1737 if (error) | |
| 1738 g_error_free(error); | |
| 1739 } else { | |
| 1740 char *logdir = g_key_file_get_string(key_file, "Logging", "Directory", &error); | |
| 1741 if (error) { | |
| 1742 gaim_debug(GAIM_DEBUG_ERROR, "Trillian talk.ini read", | |
| 1743 "Error reading Directory value from Logging section\n"); | |
| 1744 g_error_free(error); | |
| 1745 } | |
| 1746 | |
| 1747 if (logdir) { | |
| 1748 g_strchomp(logdir); | |
| 1749 gaim_prefs_add_string( | |
| 1750 "/plugins/core/log_reader/trillian/log_directory", logdir); | |
| 1751 found = TRUE; | |
| 1752 } | |
| 1753 | |
| 1754 g_key_file_free(key_file); | |
| 1755 } | |
| 1756 #else /* !GLIB_CHECK_VERSION(2,6,0) */ | |
| 1757 gsize length; | |
| 1758 gchar *contents = NULL; | |
| 1759 | |
| 1760 gaim_debug(GAIM_DEBUG_INFO, "Trillian talk.ini read", | |
| 1761 "Reading %s\n", path); | |
| 1762 if (!g_file_get_contents(path, &contents, &length, &error)) { | |
| 1763 gaim_debug(GAIM_DEBUG_ERROR, "Trillian talk.ini read", | |
| 1764 "Error reading talk.ini\n"); | |
| 1765 if (error) | |
| 1766 g_error_free(error); | |
| 1767 } else { | |
| 1768 char *line = contents; | |
| 1769 while (*contents) { | |
| 1770 if (*contents == '\n') { | |
| 1771 *contents = '\0'; | |
| 1772 | |
| 1773 /* XXX: This assumes the first Directory key is under [Logging]. */ | |
| 1774 if (gaim_str_has_prefix(line, "Directory=")) { | |
| 1775 line += (sizeof("Directory=") - 1); | |
| 1776 g_strchomp(line); | |
| 1777 gaim_prefs_add_string( | |
| 1778 "/plugins/core/log_reader/trillian/log_directory", | |
| 1779 line); | |
| 1780 found = TRUE; | |
| 1781 } | |
| 1782 | |
| 1783 contents++; | |
| 1784 line = contents; | |
| 1785 } else | |
| 1786 contents++; | |
| 1787 } | |
| 1788 g_free(path); | |
| 1789 g_free(contents); | |
| 1790 } | |
| 1791 #endif /* !GTK_CHECK_VERSION(2,6,0) */ | |
| 1792 } /* path */ | |
| 1793 | |
| 1794 if (!found) { | |
| 1795 #endif /* defined(_WIN32) */ | |
| 1796 | |
| 1797 /* Calculate default Trillian log directory. */ | |
| 1798 #ifdef _WIN32 | |
| 1799 folder = wgaim_get_special_folder(CSIDL_PROGRAM_FILES); | |
| 1800 if (folder) { | |
| 1801 #endif | |
| 1802 path = g_build_filename( | |
| 1803 #ifdef _WIN32 | |
| 1804 folder, | |
| 1805 #else | |
| 1806 GAIM_LOG_READER_WINDOWS_MOUNT_POINT, "Program Files", | |
| 1807 #endif | |
| 1808 "Trillian", "users", "default", "logs", NULL); | |
| 1809 #ifdef _WIN32 | |
| 1810 g_free(folder); | |
| 1811 } else /* !folder */ | |
| 1812 path = g_strdup(""); | |
| 1813 #endif | |
| 1814 | |
| 1815 gaim_prefs_add_string("/plugins/core/log_reader/trillian/log_directory", path); | |
| 1816 g_free(path); | |
| 1817 | |
| 1818 #ifdef _WIN32 | |
| 1819 } /* !found */ | |
| 1820 #endif | |
| 1821 } | |
| 1822 | |
| 1823 static gboolean | |
| 1824 plugin_load(GaimPlugin *plugin) | |
| 1825 { | |
| 1826 g_return_val_if_fail(plugin != NULL, FALSE); | |
| 1827 | |
| 1828 /* The names of IM clients are marked for translation at the request of | |
| 1829 translators who wanted to transliterate them. Many translators | |
| 1830 choose to leave them alone. Choose what's best for your language. */ | |
| 1831 adium_logger = gaim_log_logger_new("adium", _("Adium"), 6, | |
| 1832 NULL, | |
| 1833 NULL, | |
| 1834 adium_logger_finalize, | |
| 1835 adium_logger_list, | |
| 1836 adium_logger_read, | |
| 1837 adium_logger_size); | |
| 1838 gaim_log_logger_add(adium_logger); | |
| 1839 | |
| 1840 #if 0 | |
| 1841 /* The names of IM clients are marked for translation at the request of | |
| 1842 translators who wanted to transliterate them. Many translators | |
| 1843 choose to leave them alone. Choose what's best for your language. */ | |
| 1844 fire_logger = gaim_log_logger_new("fire", _("Fire"), 6, | |
| 1845 NULL, | |
| 1846 NULL, | |
| 1847 fire_logger_finalize, | |
| 1848 fire_logger_list, | |
| 1849 fire_logger_read, | |
| 1850 fire_logger_size); | |
| 1851 gaim_log_logger_add(fire_logger); | |
| 1852 | |
| 1853 /* The names of IM clients are marked for translation at the request of | |
| 1854 translators who wanted to transliterate them. Many translators | |
| 1855 choose to leave them alone. Choose what's best for your language. */ | |
| 1856 messenger_plus_logger = gaim_log_logger_new("messenger_plus", _("Messenger Plus!"), 6, | |
| 1857 NULL, | |
| 1858 NULL, | |
| 1859 messenger_plus_logger_finalize, | |
| 1860 messenger_plus_logger_list, | |
| 1861 messenger_plus_logger_read, | |
| 1862 messenger_plus_logger_size); | |
| 1863 gaim_log_logger_add(messenger_plus_logger); | |
| 1864 #endif | |
| 1865 | |
| 1866 /* The names of IM clients are marked for translation at the request of | |
| 1867 translators who wanted to transliterate them. Many translators | |
| 1868 choose to leave them alone. Choose what's best for your language. */ | |
| 1869 msn_logger = gaim_log_logger_new("msn", _("MSN Messenger"), 6, | |
| 1870 NULL, | |
| 1871 NULL, | |
| 1872 msn_logger_finalize, | |
| 1873 msn_logger_list, | |
| 1874 msn_logger_read, | |
| 1875 msn_logger_size); | |
| 1876 gaim_log_logger_add(msn_logger); | |
| 1877 | |
| 1878 /* The names of IM clients are marked for translation at the request of | |
| 1879 translators who wanted to transliterate them. Many translators | |
| 1880 choose to leave them alone. Choose what's best for your language. */ | |
| 1881 trillian_logger = gaim_log_logger_new("trillian", _("Trillian"), 6, | |
| 1882 NULL, | |
| 1883 NULL, | |
| 1884 trillian_logger_finalize, | |
| 1885 trillian_logger_list, | |
| 1886 trillian_logger_read, | |
| 1887 trillian_logger_size); | |
| 1888 gaim_log_logger_add(trillian_logger); | |
| 1889 | |
| 1890 return TRUE; | |
| 1891 } | |
| 1892 | |
| 1893 static gboolean | |
| 1894 plugin_unload(GaimPlugin *plugin) | |
| 1895 { | |
| 1896 g_return_val_if_fail(plugin != NULL, FALSE); | |
| 1897 | |
| 1898 gaim_log_logger_remove(adium_logger); | |
| 1899 #if 0 | |
| 1900 gaim_log_logger_remove(fire_logger); | |
| 1901 gaim_log_logger_remove(messenger_plus_logger); | |
| 1902 #endif | |
| 1903 gaim_log_logger_remove(msn_logger); | |
| 1904 gaim_log_logger_remove(trillian_logger); | |
| 1905 | |
| 1906 return TRUE; | |
| 1907 } | |
| 1908 | |
| 1909 static GaimPluginPrefFrame * | |
| 1910 get_plugin_pref_frame(GaimPlugin *plugin) | |
| 1911 { | |
| 1912 GaimPluginPrefFrame *frame; | |
| 1913 GaimPluginPref *ppref; | |
| 1914 | |
| 1915 g_return_val_if_fail(plugin != NULL, FALSE); | |
| 1916 | |
| 1917 frame = gaim_plugin_pref_frame_new(); | |
| 1918 | |
| 1919 | |
| 1920 /* Add general preferences. */ | |
| 1921 | |
| 1922 ppref = gaim_plugin_pref_new_with_label(_("General Log Reading Configuration")); | |
| 1923 gaim_plugin_pref_frame_add(frame, ppref); | |
| 1924 | |
| 1925 ppref = gaim_plugin_pref_new_with_name_and_label( | |
| 1926 "/plugins/core/log_reader/fast_sizes", _("Fast size calculations")); | |
| 1927 gaim_plugin_pref_frame_add(frame, ppref); | |
| 1928 | |
| 1929 ppref = gaim_plugin_pref_new_with_name_and_label( | |
| 1930 "/plugins/core/log_reader/use_name_heuristics", _("Use name heuristics")); | |
| 1931 gaim_plugin_pref_frame_add(frame, ppref); | |
| 1932 | |
| 1933 | |
| 1934 /* Add Log Directory preferences. */ | |
| 1935 | |
| 1936 ppref = gaim_plugin_pref_new_with_label(_("Log Directory")); | |
| 1937 gaim_plugin_pref_frame_add(frame, ppref); | |
| 1938 | |
| 1939 ppref = gaim_plugin_pref_new_with_name_and_label( | |
| 1940 "/plugins/core/log_reader/adium/log_directory", _("Adium")); | |
| 1941 gaim_plugin_pref_frame_add(frame, ppref); | |
| 1942 | |
| 1943 #if 0 | |
| 1944 ppref = gaim_plugin_pref_new_with_name_and_label( | |
| 1945 "/plugins/core/log_reader/fire/log_directory", _("Fire")); | |
| 1946 gaim_plugin_pref_frame_add(frame, ppref); | |
| 1947 | |
| 1948 ppref = gaim_plugin_pref_new_with_name_and_label( | |
| 1949 "/plugins/core/log_reader/messenger_plus/log_directory", _("Messenger Plus!")); | |
| 1950 gaim_plugin_pref_frame_add(frame, ppref); | |
| 1951 #endif | |
| 1952 | |
| 1953 ppref = gaim_plugin_pref_new_with_name_and_label( | |
| 1954 "/plugins/core/log_reader/msn/log_directory", _("MSN Messenger")); | |
| 1955 gaim_plugin_pref_frame_add(frame, ppref); | |
| 1956 | |
| 1957 ppref = gaim_plugin_pref_new_with_name_and_label( | |
| 1958 "/plugins/core/log_reader/trillian/log_directory", _("Trillian")); | |
| 1959 gaim_plugin_pref_frame_add(frame, ppref); | |
| 1960 | |
| 1961 return frame; | |
| 1962 } | |
| 1963 | |
| 1964 static GaimPluginUiInfo prefs_info = { | |
| 1965 get_plugin_pref_frame, | |
| 1966 0, /* page_num (reserved) */ | |
| 1967 NULL /* frame (reserved) */ | |
| 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, MSN Messenger, and Trillian.\n\n" | |
| 1992 "WARNING: This plugin is still alpha code and " | |
| 1993 "may crash frequently. Use it at your own risk!"), | |
| 1994 | |
| 1995 "Richard Laager <rlaager@users.sf.net>", /**< author */ | |
| 1996 GAIM_WEBSITE, /**< homepage */ | |
| 1997 plugin_load, /**< load */ | |
| 1998 plugin_unload, /**< unload */ | |
| 1999 NULL, /**< destroy */ | |
| 2000 NULL, /**< ui_info */ | |
| 2001 NULL, /**< extra_info */ | |
| 2002 &prefs_info, /**< prefs_info */ | |
| 2003 NULL /**< actions */ | |
| 2004 }; | |
| 2005 | |
| 2006 GAIM_INIT_PLUGIN(log_reader, init_plugin, info) |
