comparison libgaim/plugins/log_reader.c @ 14999:82d1a2fc6d25

[gaim-migrate @ 17778] SF Patch #1598994 from lexande Fixes SF Bug #1581999 Original Description: "The gaim 2.0.0beta5 log reader plugin uses the "Date" XML field in MSN logs, the format of which varies between locales, leading to logs being displayed on incorrect/future dates in locales that do not use the MM/DD/YYYY format. This patch fixes the plugin to use the "DateTime" field which has YYYY-MM-DD date in all locales." I totally Warmenhovened this patch. My approach: "I'm using the Date, Time, and DateTime fields. If I can determine that the log matches the current timezone, it'll display 100% properly in the log viewer. If it has a reasonable offset, it'll display as the original time, sort in the right place, but not have a timezone abbreviation. If the offset is bogus or I can't parse the Date or Time field, it'll display in UTC, but still sort properly. I think this is as ideal as is possible, given the data we have to work with." You don't have to understand this. ;) committer: Tailor Script <tailor@pidgin.im>
author Richard Laager <rlaager@wiktel.com>
date Sun, 19 Nov 2006 06:54:38 +0000
parents 5025e146a876
children c6fd017c4121
comparison
equal deleted inserted replaced
14998:db590283788d 14999:82d1a2fc6d25
443 const char *session_id; 443 const char *session_id;
444 int last_log; 444 int last_log;
445 GString *text; 445 GString *text;
446 }; 446 };
447 447
448 static time_t msn_logger_parse_timestamp(xmlnode *message) 448 /* This function is really confusing. It makes baby rlaager cry...
449 { 449 In other news: "You lost a lot of blood but we found most of it."
450 */
451 static time_t msn_logger_parse_timestamp(xmlnode *message, struct tm **tm_out)
452 {
453 const char *datetime;
454 static struct tm tm2;
455 time_t stamp;
450 const char *date; 456 const char *date;
451 const char *time; 457 const char *time;
452 struct tm tm; 458 int month;
459 int day;
460 int year;
461 int hour;
462 int min;
463 int sec;
453 char am_pm; 464 char am_pm;
454 465 char *str;
455 g_return_val_if_fail(message != NULL, (time_t)0); 466 static struct tm tm;
467 time_t t;
468 time_t diff;
469
470 #ifndef G_DISABLE_CHECKS
471 if (message != NULL)
472 {
473 *tm_out = NULL;
474
475 /* Trigger the usual warning. */
476 g_return_val_if_fail(message != NULL, (time_t)0);
477 }
478 #endif
479
480 datetime = xmlnode_get_attrib(message, "DateTime");
481 if (!(datetime && *datetime))
482 {
483 gaim_debug_error("MSN log timestamp parse",
484 "Attribute missing: %s\n", "DateTime");
485 return (time_t)0;
486 }
487
488 stamp = gaim_str_to_time(datetime, TRUE, &tm2, NULL, NULL);
489 #ifdef HAVE_TM_GMTOFF
490 tm2.tm_gmtoff = 0;
491 #endif
492 #ifdef HAVE_STRUCT_TM_TM_ZONE
493 /* This is used in the place of a timezone abbreviation if the
494 * offset is way off. The user should never really see it, but
495 * it's here just in case. The parens are to make it clear it's
496 * not a real timezone. */
497 tm2.tm_zone = _("(UTC)");
498 #endif
499
456 500
457 date = xmlnode_get_attrib(message, "Date"); 501 date = xmlnode_get_attrib(message, "Date");
458 if (!(date && *date)) { 502 if (!(date && *date))
459 gaim_debug(GAIM_DEBUG_ERROR, "MSN log timestamp parse", 503 {
460 "Attribute missing: %s\n", "Date"); 504 gaim_debug_error("MSN log timestamp parse",
461 return (time_t)0; 505 "Attribute missing: %s\n", "Date");
506 *tm_out = &tm2;
507 return stamp;
462 } 508 }
463 509
464 time = xmlnode_get_attrib(message, "Time"); 510 time = xmlnode_get_attrib(message, "Time");
465 if (!(time && *time)) { 511 if (!(time && *time))
466 gaim_debug(GAIM_DEBUG_ERROR, "MSN log timestamp parse", 512 {
467 "Attribute missing: %s\n", "Time"); 513 gaim_debug_error("MSN log timestamp parse",
468 return (time_t)0; 514 "Attribute missing: %s\n", "Time");
469 } 515 *tm_out = &tm2;
470 516 return stamp;
471 if (sscanf(date, "%u/%u/%u", &tm.tm_mon, &tm.tm_mday, &tm.tm_year) != 3) 517 }
472 gaim_debug(GAIM_DEBUG_ERROR, "MSN log timestamp parse", 518
473 "%s parsing error\n", "Date"); 519 if (sscanf(date, "%u/%u/%u", &month, &day, &year) != 3)
474 520 {
475 if (sscanf(time, "%u:%u:%u %c", &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &am_pm) != 4) 521 gaim_debug_error("MSN log timestamp parse",
476 gaim_debug(GAIM_DEBUG_ERROR, "MSN log timestamp parse", 522 "%s parsing error\n", "Date");
477 "%s parsing error\n", "Time"); 523 *tm_out = &tm2;
478 524 return stamp;
479 tm.tm_year -= 1900; 525 }
480 tm.tm_mon -= 1; 526 else
481 if (am_pm == 'P') { 527 {
482 tm.tm_hour += 12; 528 if (month > 12)
483 } else if (tm.tm_hour == 12) { 529 {
484 /* 12 AM = 00 hr */ 530 int tmp = day;
485 tm.tm_hour = 0; 531 day = month;
486 } 532 month = tmp;
487 /* Let the C library deal with daylight savings time. */ 533 }
488 tm.tm_isdst = -1; 534 }
489 535
490 return mktime(&tm); 536 if (sscanf(time, "%u:%u:%u %c", &hour, &min, &sec, &am_pm) != 4)
491 } 537 {
492 538 gaim_debug_error("MSN log timestamp parse",
539 "%s parsing error\n", "Time");
540 *tm_out = &tm2;
541 return stamp;
542 }
543
544 if (am_pm == 'P') {
545 hour += 12;
546 } else if (hour == 12) {
547 /* 12 AM = 00 hr */
548 hour = 0;
549 }
550
551 str = g_strdup_printf("%04i-%02i-%02iT%02i:%02i:%02i", year, month, day, hour, min, sec);
552 t = gaim_str_to_time(str, TRUE, &tm, NULL, NULL);
553
554
555 if (stamp > t)
556 diff = stamp - t;
557 else
558 diff = t - stamp;
559
560 if (diff > (14 * 60 * 60))
561 {
562 if (day <= 12)
563 {
564 /* Swap day & month variables, to see if it's a non-US date. */
565 g_free(str);
566 str = g_strdup_printf("%04i-%02i-%02iT%02i:%02i:%02i", year, month, day, hour, min, sec);
567 t = gaim_str_to_time(str, TRUE, &tm, NULL, NULL);
568
569 if (stamp > t)
570 diff = stamp - t;
571 else
572 diff = t - stamp;
573
574 if (diff > (14 * 60 * 60))
575 {
576 /* We got a time, it's not impossible, but
577 * the diff is too large. Display the UTC time. */
578 g_free(str);
579 *tm_out = &tm2;
580 return stamp;
581 }
582 else
583 {
584 /* Legal time */
585 /* Fall out */
586 }
587 }
588 else
589 {
590 /* We got a time, it's not impossible, but
591 * the diff is too large. Display the UTC time. */
592 g_free(str);
593 *tm_out = &tm2;
594 return stamp;
595 }
596 }
597
598 /* If we got here, the time is legal with a reasonable offset.
599 * Let's find out if it's in our TZ. */
600 if (gaim_str_to_time(str, FALSE, &tm, NULL, NULL) == stamp)
601 {
602 g_free(str);
603 *tm_out = &tm;
604 return stamp;
605 }
606 g_free(str);
607
608 /* The time isn't in our TZ, but it's reasonable. */
609 #ifdef HAVE_STRUCT_TM_TM_ZONE
610 tm.tm_zone = " ";
611 #endif
612 *tm_out = &tm;
613 return stamp;
614 }
493 615
494 static GList *msn_logger_list(GaimLogType type, const char *sn, GaimAccount *account) 616 static GList *msn_logger_list(GaimLogType type, const char *sn, GaimAccount *account)
495 { 617 {
496 GList *list = NULL; 618 GList *list = NULL;
497 char *username; 619 char *username;
723 if (strcmp(session_id, old_session_id)) { 845 if (strcmp(session_id, old_session_id)) {
724 /* 846 /*
725 * The session ID differs from the last message. 847 * The session ID differs from the last message.
726 * Thus, this is the start of a new conversation. 848 * Thus, this is the start of a new conversation.
727 */ 849 */
850 struct tm *tm;
851 time_t stamp;
728 GaimLog *log; 852 GaimLog *log;
729 853
730 data = g_new0(struct msn_logger_data, 1); 854 data = g_new0(struct msn_logger_data, 1);
731 data->root = root; 855 data->root = root;
732 data->message = message; 856 data->message = message;
733 data->session_id = session_id; 857 data->session_id = session_id;
734 data->text = NULL; 858 data->text = NULL;
735 data->last_log = FALSE; 859 data->last_log = FALSE;
736 860
737 /* XXX: Look into this later... Should we pass in a struct tm? */ 861 stamp = msn_logger_parse_timestamp(message, &tm);
738 log = gaim_log_new(GAIM_LOG_IM, sn, account, NULL, msn_logger_parse_timestamp(message), NULL); 862
863 log = gaim_log_new(GAIM_LOG_IM, sn, account, NULL, stamp, tm);
739 log->logger = msn_logger; 864 log->logger = msn_logger;
740 log->logger_data = data; 865 log->logger_data = data;
741 866
742 list = g_list_append(list, log); 867 list = g_list_append(list, log);
743 } 868 }
790 xmlnode *from; 915 xmlnode *from;
791 xmlnode *to; 916 xmlnode *to;
792 enum name_guesses name_guessed = NAME_GUESS_UNKNOWN; 917 enum name_guesses name_guessed = NAME_GUESS_UNKNOWN;
793 const char *their_name; 918 const char *their_name;
794 time_t time_unix; 919 time_t time_unix;
795 struct tm *tm_new; 920 struct tm *tm;
796 char *timestamp; 921 char *timestamp;
797 char *tmp; 922 char *tmp;
798 const char *style; 923 const char *style;
799 924
800 new_session_id = xmlnode_get_attrib(message, "SessionID"); 925 new_session_id = xmlnode_get_attrib(message, "SessionID");
959 else 1084 else
960 text = g_string_append(text, "A82F2F"); 1085 text = g_string_append(text, "A82F2F");
961 text = g_string_append(text, ";\">"); 1086 text = g_string_append(text, ";\">");
962 } 1087 }
963 1088
964 time_unix = msn_logger_parse_timestamp(message); 1089 time_unix = msn_logger_parse_timestamp(message, &tm);
965 tm_new = localtime(&time_unix);
966 1090
967 timestamp = g_strdup_printf("<font size=\"2\">(%02u:%02u:%02u)</font> ", 1091 timestamp = g_strdup_printf("<font size=\"2\">(%02u:%02u:%02u)</font> ",
968 tm_new->tm_hour, tm_new->tm_min, tm_new->tm_sec); 1092 tm->tm_hour, tm->tm_min, tm->tm_sec);
969 text = g_string_append(text, timestamp); 1093 text = g_string_append(text, timestamp);
970 g_free(timestamp); 1094 g_free(timestamp);
971 1095
972 if (from_name) { 1096 if (from_name) {
973 text = g_string_append(text, "<b>"); 1097 text = g_string_append(text, "<b>");