comparison libgaim/protocols/msn/msn-utils.c @ 20392:9ba7dee775e1

The first msn-p13-merge-head.diff.gz from SF Patch #1621854 from Ka-Hing Cheung. "uploaded a diff, this diff is unchanged from the last tarball that I previously uploaded, except that it's against HEAD. This should be a little easier for most people." (This was apparently msn-p13-merge-head.diff, which SourceForge didn't allow to be uploaded.) PLUS "Updated the diff with basically no change, except with simom's icon fix. The previous diff was broken because some of the files were not added"
author Richard Laager <rlaager@wiktel.com>
date Sun, 15 Apr 2007 03:01:41 +0000
parents 0b0ecee55091
children
comparison
equal deleted inserted replaced
20391:0b0ecee55091 20392:9ba7dee775e1
21 * along with this program; if not, write to the Free Software 21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */ 23 */
24 #include "msn.h" 24 #include "msn.h"
25 #include "msn-utils.h" 25 #include "msn-utils.h"
26 #include "time.h"
27 //#include <openssl/md5.h>
28
29 char *rand_guid(void);
30
31 /**************************************************************************
32 * Util
33 **************************************************************************/
34 char *
35 rand_guid()
36 {
37 return g_strdup_printf("%4X%4X-%4X-%4X-%4X-%4X%4X%4X",
38 rand() % 0xAAFF + 0x1111,
39 rand() % 0xAAFF + 0x1111,
40 rand() % 0xAAFF + 0x1111,
41 rand() % 0xAAFF + 0x1111,
42 rand() % 0xAAFF + 0x1111,
43 rand() % 0xAAFF + 0x1111,
44 rand() % 0xAAFF + 0x1111,
45 rand() % 0xAAFF + 0x1111);
46 }
47 26
48 void 27 void
49 msn_parse_format(const char *mime, char **pre_ret, char **post_ret) 28 msn_parse_format(const char *mime, char **pre_ret, char **post_ret)
50 { 29 {
51 char *cur; 30 char *cur;
144 123
145 if (post_ret != NULL) 124 if (post_ret != NULL)
146 *post_ret = cur; 125 *post_ret = cur;
147 else 126 else
148 g_free(cur); 127 g_free(cur);
149 }
150
151 /*encode the str to RFC2047 style
152 * Currently only support the UTF-8 and base64 encode
153 */
154 char *
155 msn_encode_mime(const char *str)
156 {
157 char *base64;
158
159 base64 = gaim_base64_encode((guchar *)str, strlen(str));
160 return g_strdup_printf("=?utf-8?B?%s?=", base64);
161 } 128 }
162 129
163 /* 130 /*
164 * We need this because we're only supposed to encode spaces in the font 131 * We need this because we're only supposed to encode spaces in the font
165 * names. gaim_url_encode() isn't acceptable. 132 * names. gaim_url_encode() isn't acceptable.
382 char *c; 349 char *c;
383 int port; 350 int port;
384 351
385 host = g_strdup(str); 352 host = g_strdup(str);
386 353
387 if ((c = strchr(host, ':')) != NULL){ 354 if ((c = strchr(host, ':')) != NULL)
355 {
388 *c = '\0'; 356 *c = '\0';
389 port = atoi(c + 1); 357 port = atoi(c + 1);
390 }else{ 358 }
359 else
391 port = 1863; 360 port = 1863;
392 }
393 361
394 *ret_host = host; 362 *ret_host = host;
395 *ret_port = port; 363 *ret_port = port;
396 } 364 }
397 /***************************************************************************
398 * MSN Time Related Funciton
399 ***************************************************************************/
400 #if 0
401 int
402 msn_convert_iso8601(const char *timestr,struct tm tm_time)
403 {
404 char temp[64];
405 struct tm ctime;
406 time_t ts;
407
408 gaim_debug_info("MaYuan","convert string is{%s}\n",timestr);
409 tzset();
410 /*copy string first*/
411 memset(temp, 0, sizeof(temp));
412 strncpy(temp, timestr, strlen(timestr));
413
414 /*convert via strptime()*/
415 memset(&ctime, 0, sizeof(struct tm));
416 strptime(temp, "%d %b %Y %T %Z", &ctime);
417 ts = mktime(&ctime) - timezone;
418 localtime_r(&ts, tm_time);
419 }
420 #endif
421
422 /***************************************************************************
423 * MSN Challenge Computing Function
424 ***************************************************************************/
425 /*check the edian of system*/
426 int
427 isBigEndian(void)
428 {
429 short int word = 0x0100;
430 char *byte = (char *)&word;
431
432 return(byte[0]);
433 }
434
435 /*swap utility*/
436 unsigned int
437 swapInt(unsigned int dw)
438 {
439 unsigned int tmp;
440 tmp = (dw & 0x000000FF);
441 tmp = ((dw & 0x0000FF00) >> 0x08) | (tmp << 0x08);
442 tmp = ((dw & 0x00FF0000) >> 0x10) | (tmp << 0x08);
443 tmp = ((dw & 0xFF000000) >> 0x18) | (tmp << 0x08);
444 return(tmp);
445 }
446
447 /*
448 * Handle MSN Chanllege computation
449 *This algorithm reference with http://msnpiki.msnfanatic.com/index.php/MSNP11:Challenges
450 */
451 #define BUFSIZE 256
452 void
453 msn_handle_chl(char *input, char *output)
454 {
455 GaimCipher *cipher;
456 GaimCipherContext *context;
457 char *productKey = MSNP13_WLM_PRODUCT_KEY,
458 *productID = MSNP13_WLM_PRODUCT_ID,
459 *hexChars = "0123456789abcdef",
460 buf[BUFSIZE];
461 unsigned char md5Hash[16], *newHash;
462 unsigned int *md5Parts, *chlStringParts, newHashParts[5];
463
464 long long nHigh=0, nLow=0;
465
466 int i, bigEndian;
467
468 /* Determine our endianess */
469 bigEndian = isBigEndian();
470
471 /* Create the MD5 hash by using Gaim MD5 algorithm*/
472 cipher = gaim_ciphers_find_cipher("md5");
473 context = gaim_cipher_context_new(cipher, NULL);
474
475 gaim_cipher_context_append(context, (const guchar *)input,
476 strlen(input));
477 gaim_cipher_context_append(context, (const guchar *)productKey,
478 strlen(productKey));
479 gaim_cipher_context_digest(context, sizeof(md5Hash), md5Hash, NULL);
480 gaim_cipher_context_destroy(context);
481
482 /* Split it into four integers */
483 md5Parts = (unsigned int *)md5Hash;
484 for(i=0; i<4; i++){
485 /* check for endianess */
486 if(bigEndian)
487 md5Parts[i] = swapInt(md5Parts[i]);
488
489 /* & each integer with 0x7FFFFFFF */
490 /* and save one unmodified array for later */
491 newHashParts[i] = md5Parts[i];
492 md5Parts[i] &= 0x7FFFFFFF;
493 }
494
495 /* make a new string and pad with '0' */
496 snprintf(buf, BUFSIZE-5, "%s%s", input, productID);
497 i = strlen(buf);
498 memset(&buf[i], '0', 8 - (i % 8));
499 buf[i + (8 - (i % 8))]='\0';
500
501 /* split into integers */
502 chlStringParts = (unsigned int *)buf;
503
504 /* this is magic */
505 for (i=0; i<(strlen(buf)/4)-1; i+=2){
506 long long temp;
507
508 if(bigEndian){
509 chlStringParts[i] = swapInt(chlStringParts[i]);
510 chlStringParts[i+1] = swapInt(chlStringParts[i+1]);
511 }
512
513 temp=(md5Parts[0] * (((0x0E79A9C1 * (long long)chlStringParts[i]) % 0x7FFFFFFF)+nHigh) + md5Parts[1])%0x7FFFFFFF;
514 nHigh=(md5Parts[2] * (((long long)chlStringParts[i+1]+temp) % 0x7FFFFFFF) + md5Parts[3]) % 0x7FFFFFFF;
515 nLow=nLow + nHigh + temp;
516 }
517 nHigh=(nHigh+md5Parts[1]) % 0x7FFFFFFF;
518 nLow=(nLow+md5Parts[3]) % 0x7FFFFFFF;
519
520 newHashParts[0]^=nHigh;
521 newHashParts[1]^=nLow;
522 newHashParts[2]^=nHigh;
523 newHashParts[3]^=nLow;
524
525 /* swap more bytes if big endian */
526 for(i=0; i<4 && bigEndian; i++)
527 newHashParts[i] = swapInt(newHashParts[i]);
528
529 /* make a string of the parts */
530 newHash = (unsigned char *)newHashParts;
531
532 /* convert to hexadecimal */
533 for (i=0; i<16; i++)
534 {
535 output[i*2]=hexChars[(newHash[i]>>4)&0xF];
536 output[(i*2)+1]=hexChars[newHash[i]&0xF];
537 }
538
539 output[32]='\0';
540
541 // gaim_debug_info("MaYuan","chl output{%s}\n",output);
542 }
543
544 #if (!defined(_XOPEN_SOURCE))||defined(_WIN32)
545
546 #ifndef __P
547 # if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
548 # define __P(args) args
549 # else
550 # define __P(args) ()
551 # endif /* GCC. */
552 #endif /* Not __P. */
553
554 #if defined(HAVE_LOCALTIME_R) && ! HAVE_LOCALTIME_R && ! defined localtime_r
555 # ifdef _LIBC
556 # define localtime_r __localtime_r
557 # else
558 /* Approximate localtime_r as best we can in its absence. */
559 # define localtime_r my_localtime_r
560 static struct tm *localtime_r __P ((const time_t *, struct tm *));
561 static struct tm *
562 localtime_r (t, tp)
563 const time_t *t;
564 struct tm *tp;
565 {
566 struct tm *l = localtime (t);
567 if (! l)
568 return 0;
569 *tp = *l;
570 return tp;
571 }
572 # endif /* ! _LIBC */
573 #endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */
574
575
576 #define match_char(ch1, ch2) if (ch1 != ch2) return NULL
577
578 #if defined __GNUC__ && __GNUC__ >= 2
579 # define match_string(cs1, s2) \
580 ({ size_t len = strlen (cs1); \
581 int result = strncasecmp ((cs1), (s2), len) == 0; \
582 if (result) (s2) += len; \
583 result; })
584 #else
585 /* Oh come on. Get a reasonable compiler. */
586 # define match_string(cs1, s2) \
587 (strncasecmp ((cs1), (s2), strlen (cs1)) ? 0 : ((s2) += strlen (cs1), 1))
588 #endif
589
590 /* We intentionally do not use isdigit() for testing because this will
591 lead to problems with the wide character version. */
592 #define get_number(from, to, n) \
593 do { \
594 int __n = n; \
595 val = 0; \
596 while (*rp == ' ') \
597 ++rp; \
598 if ((*rp < '0') || (*rp > '9')) \
599 return NULL; \
600 do { \
601 val *= 10; \
602 val += *rp++ - '0'; \
603 } while ((--__n > 0) && (val * 10 <= to) && (*rp >= '0') && (*rp <= '9')); \
604 if ((val < from) || (val > to)) \
605 return NULL; \
606 } while (0)
607
608 #ifdef _NL_CURRENT
609 # define get_alt_number(from, to, n) \
610 ({ \
611 __label__ do_normal; \
612 if (*decided != raw) \
613 { \
614 const char *alts = _NL_CURRENT (LC_TIME, ALT_DIGITS); \
615 int __n = n; \
616 int any = 0; \
617 while (*rp == ' ') \
618 ++rp; \
619 val = 0; \
620 do { \
621 val *= 10; \
622 while (*alts != '\0') \
623 { \
624 size_t len = strlen (alts); \
625 if (strncasecmp (alts, rp, len) == 0) \
626 break; \
627 alts += len + 1; \
628 ++val; \
629 } \
630 if (*alts == '\0') \
631 { \
632 if (*decided == not && ! any) \
633 goto do_normal; \
634 /* If we haven't read anything it's an error. */ \
635 if (! any) \
636 return NULL; \
637 /* Correct the premature multiplication. */ \
638 val /= 10; \
639 break; \
640 } \
641 else \
642 *decided = loc; \
643 } while (--__n > 0 && val * 10 <= to); \
644 if (val < from || val > to) \
645 return NULL; \
646 } \
647 else \
648 { \
649 do_normal: \
650 get_number (from, to, n); \
651 } \
652 0; \
653 })
654 #else
655 # define get_alt_number(from, to, n) \
656 /* We don't have the alternate representation. */ \
657 get_number(from, to, n)
658 #endif
659
660 #define recursive(new_fmt) \
661 (*(new_fmt) != '\0' \
662 && (rp = strptime_internal (rp, (new_fmt), tm, decided, era_cnt)) != NULL)
663
664
665 #ifdef _LIBC
666 /* This is defined in locale/C-time.c in the GNU libc. */
667 extern const struct locale_data _nl_C_LC_TIME;
668 extern const unsigned short int __mon_yday[2][13];
669
670 # define weekday_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (DAY_1)].string)
671 # define ab_weekday_name \
672 (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABDAY_1)].string)
673 # define month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (MON_1)].string)
674 # define ab_month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABMON_1)].string)
675 # define HERE_D_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_T_FMT)].string)
676 # define HERE_D_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_FMT)].string)
677 # define HERE_AM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (AM_STR)].string)
678 # define HERE_PM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (PM_STR)].string)
679 # define HERE_T_FMT_AMPM \
680 (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT_AMPM)].string)
681 # define HERE_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT)].string)
682
683 # define strncasecmp(s1, s2, n) __strncasecmp (s1, s2, n)
684 #else
685 static char const weekday_name[][10] =
686 {
687 "Sunday", "Monday", "Tuesday", "Wednesday",
688 "Thursday", "Friday", "Saturday"
689 };
690 static char const ab_weekday_name[][4] =
691 {
692 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
693 };
694 static char const month_name[][10] =
695 {
696 "January", "February", "March", "April", "May", "June",
697 "July", "August", "September", "October", "November", "December"
698 };
699 static char const ab_month_name[][4] =
700 {
701 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
702 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
703 };
704 # define HERE_D_T_FMT "%a %b %e %H:%M:%S %Y"
705 # define HERE_D_FMT "%m/%d/%y"
706 # define HERE_AM_STR "AM"
707 # define HERE_PM_STR "PM"
708 # define HERE_T_FMT_AMPM "%I:%M:%S %p"
709 # define HERE_T_FMT "%H:%M:%S"
710
711 const unsigned short int __mon_yday[2][13] =
712 {
713 /* Normal years. */
714 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
715 /* Leap years. */
716 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
717 };
718 #endif
719
720 /* Status of lookup: do we use the locale data or the raw data? */
721 enum locale_status { not, loc, raw };
722
723
724 #ifndef __isleap
725 /* Nonzero if YEAR is a leap year (every 4 years,
726 except every 100th isn't, and every 400th is). */
727 # define __isleap(year) \
728 ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
729 #endif
730
731 /* Compute the day of the week. */
732 static void
733 day_of_the_week (struct tm *tm)
734 {
735 /* We know that January 1st 1970 was a Thursday (= 4). Compute the
736 the difference between this data in the one on TM and so determine
737 the weekday. */
738 int corr_year = 1900 + tm->tm_year - (tm->tm_mon < 2);
739 int wday = (-473
740 + (365 * (tm->tm_year - 70))
741 + (corr_year / 4)
742 - ((corr_year / 4) / 25) + ((corr_year / 4) % 25 < 0)
743 + (((corr_year / 4) / 25) / 4)
744 + __mon_yday[0][tm->tm_mon]
745 + tm->tm_mday - 1);
746 tm->tm_wday = ((wday % 7) + 7) % 7;
747 }
748
749 /* Compute the day of the year. */
750 static void
751 day_of_the_year (struct tm *tm)
752 {
753 tm->tm_yday = (__mon_yday[__isleap (1900 + tm->tm_year)][tm->tm_mon]
754 + (tm->tm_mday - 1));
755 }
756
757 static char *
758 #ifdef _LIBC
759 internal_function
760 #endif
761 strptime_internal __P ((const char *rp, const char *fmt, struct tm *tm,
762 enum locale_status *decided, int era_cnt));
763
764 static char *
765 #ifdef _LIBC
766 internal_function
767 #endif
768 strptime_internal (rp, fmt, tm, decided, era_cnt)
769 const char *rp;
770 const char *fmt;
771 struct tm *tm;
772 enum locale_status *decided;
773 int era_cnt;
774 {
775 const char *rp_backup;
776 int cnt;
777 size_t val;
778 int have_I, is_pm;
779 int century, want_century;
780 int want_era;
781 int have_wday, want_xday;
782 int have_yday;
783 int have_mon, have_mday;
784 #ifdef _NL_CURRENT
785 size_t num_eras;
786 #endif
787 struct era_entry *era;
788
789 have_I = is_pm = 0;
790 century = -1;
791 want_century = 0;
792 want_era = 0;
793 era = NULL;
794
795 have_wday = want_xday = have_yday = have_mon = have_mday = 0;
796
797 while (*fmt != '\0')
798 {
799 /* A white space in the format string matches 0 more or white
800 space in the input string. */
801 if (isspace (*fmt))
802 {
803 while (isspace (*rp))
804 ++rp;
805 ++fmt;
806 continue;
807 }
808
809 /* Any character but `%' must be matched by the same character
810 in the iput string. */
811 if (*fmt != '%')
812 {
813 match_char (*fmt++, *rp++);
814 continue;
815 }
816
817 ++fmt;
818 #ifndef _NL_CURRENT
819 /* We need this for handling the `E' modifier. */
820 start_over:
821 #endif
822
823 /* Make back up of current processing pointer. */
824 rp_backup = rp;
825
826 switch (*fmt++)
827 {
828 case '%':
829 /* Match the `%' character itself. */
830 match_char ('%', *rp++);
831 break;
832 case 'a':
833 case 'A':
834 /* Match day of week. */
835 for (cnt = 0; cnt < 7; ++cnt)
836 {
837 #ifdef _NL_CURRENT
838 if (*decided !=raw)
839 {
840 if (match_string (_NL_CURRENT (LC_TIME, DAY_1 + cnt), rp))
841 {
842 if (*decided == not
843 && strcmp (_NL_CURRENT (LC_TIME, DAY_1 + cnt),
844 weekday_name[cnt]))
845 *decided = loc;
846 break;
847 }
848 if (match_string (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt), rp))
849 {
850 if (*decided == not
851 && strcmp (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt),
852 ab_weekday_name[cnt]))
853 *decided = loc;
854 break;
855 }
856 }
857 #endif
858 if (*decided != loc
859 && (match_string (weekday_name[cnt], rp)
860 || match_string (ab_weekday_name[cnt], rp)))
861 {
862 *decided = raw;
863 break;
864 }
865 }
866 if (cnt == 7)
867 /* Does not match a weekday name. */
868 return NULL;
869 tm->tm_wday = cnt;
870 have_wday = 1;
871 break;
872 case 'b':
873 case 'B':
874 case 'h':
875 /* Match month name. */
876 for (cnt = 0; cnt < 12; ++cnt)
877 {
878 #ifdef _NL_CURRENT
879 if (*decided !=raw)
880 {
881 if (match_string (_NL_CURRENT (LC_TIME, MON_1 + cnt), rp))
882 {
883 if (*decided == not
884 && strcmp (_NL_CURRENT (LC_TIME, MON_1 + cnt),
885 month_name[cnt]))
886 *decided = loc;
887 break;
888 }
889 if (match_string (_NL_CURRENT (LC_TIME, ABMON_1 + cnt), rp))
890 {
891 if (*decided == not
892 && strcmp (_NL_CURRENT (LC_TIME, ABMON_1 + cnt),
893 ab_month_name[cnt]))
894 *decided = loc;
895 break;
896 }
897 }
898 #endif
899 if (match_string (month_name[cnt], rp)
900 || match_string (ab_month_name[cnt], rp))
901 {
902 *decided = raw;
903 break;
904 }
905 }
906 if (cnt == 12)
907 /* Does not match a month name. */
908 return NULL;
909 tm->tm_mon = cnt;
910 want_xday = 1;
911 break;
912 case 'c':
913 /* Match locale's date and time format. */
914 #ifdef _NL_CURRENT
915 if (*decided != raw)
916 {
917 if (!recursive (_NL_CURRENT (LC_TIME, D_T_FMT)))
918 {
919 if (*decided == loc)
920 return NULL;
921 else
922 rp = rp_backup;
923 }
924 else
925 {
926 if (*decided == not &&
927 strcmp (_NL_CURRENT (LC_TIME, D_T_FMT), HERE_D_T_FMT))
928 *decided = loc;
929 want_xday = 1;
930 break;
931 }
932 *decided = raw;
933 }
934 #endif
935 if (!recursive (HERE_D_T_FMT))
936 return NULL;
937 want_xday = 1;
938 break;
939 case 'C':
940 /* Match century number. */
941 #ifdef _NL_CURRENT
942 match_century:
943 #endif
944 get_number (0, 99, 2);
945 century = val;
946 want_xday = 1;
947 break;
948 case 'd':
949 case 'e':
950 /* Match day of month. */
951 get_number (1, 31, 2);
952 tm->tm_mday = val;
953 have_mday = 1;
954 want_xday = 1;
955 break;
956 case 'F':
957 if (!recursive ("%Y-%m-%d"))
958 return NULL;
959 want_xday = 1;
960 break;
961 case 'x':
962 #ifdef _NL_CURRENT
963 if (*decided != raw)
964 {
965 if (!recursive (_NL_CURRENT (LC_TIME, D_FMT)))
966 {
967 if (*decided == loc)
968 return NULL;
969 else
970 rp = rp_backup;
971 }
972 else
973 {
974 if (*decided == not
975 && strcmp (_NL_CURRENT (LC_TIME, D_FMT), HERE_D_FMT))
976 *decided = loc;
977 want_xday = 1;
978 break;
979 }
980 *decided = raw;
981 }
982 #endif
983 /* Fall through. */
984 case 'D':
985 /* Match standard day format. */
986 if (!recursive (HERE_D_FMT))
987 return NULL;
988 want_xday = 1;
989 break;
990 case 'k':
991 case 'H':
992 /* Match hour in 24-hour clock. */
993 get_number (0, 23, 2);
994 tm->tm_hour = val;
995 have_I = 0;
996 break;
997 case 'I':
998 /* Match hour in 12-hour clock. */
999 get_number (1, 12, 2);
1000 tm->tm_hour = val % 12;
1001 have_I = 1;
1002 break;
1003 case 'j':
1004 /* Match day number of year. */
1005 get_number (1, 366, 3);
1006 tm->tm_yday = val - 1;
1007 have_yday = 1;
1008 break;
1009 case 'm':
1010 /* Match number of month. */
1011 get_number (1, 12, 2);
1012 tm->tm_mon = val - 1;
1013 have_mon = 1;
1014 want_xday = 1;
1015 break;
1016 case 'M':
1017 /* Match minute. */
1018 get_number (0, 59, 2);
1019 tm->tm_min = val;
1020 break;
1021 case 'n':
1022 case 't':
1023 /* Match any white space. */
1024 while (isspace (*rp))
1025 ++rp;
1026 break;
1027 case 'p':
1028 /* Match locale's equivalent of AM/PM. */
1029 #ifdef _NL_CURRENT
1030 if (*decided != raw)
1031 {
1032 if (match_string (_NL_CURRENT (LC_TIME, AM_STR), rp))
1033 {
1034 if (strcmp (_NL_CURRENT (LC_TIME, AM_STR), HERE_AM_STR))
1035 *decided = loc;
1036 break;
1037 }
1038 if (match_string (_NL_CURRENT (LC_TIME, PM_STR), rp))
1039 {
1040 if (strcmp (_NL_CURRENT (LC_TIME, PM_STR), HERE_PM_STR))
1041 *decided = loc;
1042 is_pm = 1;
1043 break;
1044 }
1045 *decided = raw;
1046 }
1047 #endif
1048 if (!match_string (HERE_AM_STR, rp))
1049 if (match_string (HERE_PM_STR, rp))
1050 is_pm = 1;
1051 else
1052 return NULL;
1053 break;
1054 case 'r':
1055 #ifdef _NL_CURRENT
1056 if (*decided != raw)
1057 {
1058 if (!recursive (_NL_CURRENT (LC_TIME, T_FMT_AMPM)))
1059 {
1060 if (*decided == loc)
1061 return NULL;
1062 else
1063 rp = rp_backup;
1064 }
1065 else
1066 {
1067 if (*decided == not &&
1068 strcmp (_NL_CURRENT (LC_TIME, T_FMT_AMPM),
1069 HERE_T_FMT_AMPM))
1070 *decided = loc;
1071 break;
1072 }
1073 *decided = raw;
1074 }
1075 #endif
1076 if (!recursive (HERE_T_FMT_AMPM))
1077 return NULL;
1078 break;
1079 case 'R':
1080 if (!recursive ("%H:%M"))
1081 return NULL;
1082 break;
1083 case 's':
1084 {
1085 /* The number of seconds may be very high so we cannot use
1086 the `get_number' macro. Instead read the number
1087 character for character and construct the result while
1088 doing this. */
1089 time_t secs = 0;
1090 if (*rp < '0' || *rp > '9')
1091 /* We need at least one digit. */
1092 return NULL;
1093
1094 do
1095 {
1096 secs *= 10;
1097 secs += *rp++ - '0';
1098 }
1099 while (*rp >= '0' && *rp <= '9');
1100
1101 if (localtime_r (&secs, tm) == NULL)
1102 /* Error in function. */
1103 return NULL;
1104 }
1105 break;
1106 case 'S':
1107 get_number (0, 61, 2);
1108 tm->tm_sec = val;
1109 break;
1110 case 'X':
1111 #ifdef _NL_CURRENT
1112 if (*decided != raw)
1113 {
1114 if (!recursive (_NL_CURRENT (LC_TIME, T_FMT)))
1115 {
1116 if (*decided == loc)
1117 return NULL;
1118 else
1119 rp = rp_backup;
1120 }
1121 else
1122 {
1123 if (strcmp (_NL_CURRENT (LC_TIME, T_FMT), HERE_T_FMT))
1124 *decided = loc;
1125 break;
1126 }
1127 *decided = raw;
1128 }
1129 #endif
1130 /* Fall through. */
1131 case 'T':
1132 if (!recursive (HERE_T_FMT))
1133 return NULL;
1134 break;
1135 case 'u':
1136 get_number (1, 7, 1);
1137 tm->tm_wday = val % 7;
1138 have_wday = 1;
1139 break;
1140 case 'g':
1141 get_number (0, 99, 2);
1142 /* XXX This cannot determine any field in TM. */
1143 break;
1144 case 'G':
1145 if (*rp < '0' || *rp > '9')
1146 return NULL;
1147 /* XXX Ignore the number since we would need some more
1148 information to compute a real date. */
1149 do
1150 ++rp;
1151 while (*rp >= '0' && *rp <= '9');
1152 break;
1153 case 'U':
1154 case 'V':
1155 case 'W':
1156 get_number (0, 53, 2);
1157 /* XXX This cannot determine any field in TM without some
1158 information. */
1159 break;
1160 case 'w':
1161 /* Match number of weekday. */
1162 get_number (0, 6, 1);
1163 tm->tm_wday = val;
1164 have_wday = 1;
1165 break;
1166 case 'y':
1167 #ifdef _NL_CURRENT
1168 match_year_in_century:
1169 #endif
1170 /* Match year within century. */
1171 get_number (0, 99, 2);
1172 /* The "Year 2000: The Millennium Rollover" paper suggests that
1173 values in the range 69-99 refer to the twentieth century. */
1174 tm->tm_year = val >= 69 ? val : val + 100;
1175 /* Indicate that we want to use the century, if specified. */
1176 want_century = 1;
1177 want_xday = 1;
1178 break;
1179 case 'Y':
1180 /* Match year including century number. */
1181 get_number (0, 9999, 4);
1182 tm->tm_year = val - 1900;
1183 want_century = 0;
1184 want_xday = 1;
1185 break;
1186 case 'Z':
1187 /* XXX How to handle this? */
1188 break;
1189 case 'E':
1190 #ifdef _NL_CURRENT
1191 switch (*fmt++)
1192 {
1193 case 'c':
1194 /* Match locale's alternate date and time format. */
1195 if (*decided != raw)
1196 {
1197 const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT);
1198
1199 if (*fmt == '\0')
1200 fmt = _NL_CURRENT (LC_TIME, D_T_FMT);
1201
1202 if (!recursive (fmt))
1203 {
1204 if (*decided == loc)
1205 return NULL;
1206 else
1207 rp = rp_backup;
1208 }
1209 else
1210 {
1211 if (strcmp (fmt, HERE_D_T_FMT))
1212 *decided = loc;
1213 want_xday = 1;
1214 break;
1215 }
1216 *decided = raw;
1217 }
1218 /* The C locale has no era information, so use the
1219 normal representation. */
1220 if (!recursive (HERE_D_T_FMT))
1221 return NULL;
1222 want_xday = 1;
1223 break;
1224 case 'C':
1225 if (*decided != raw)
1226 {
1227 if (era_cnt >= 0)
1228 {
1229 era = _nl_select_era_entry (era_cnt);
1230 if (match_string (era->era_name, rp))
1231 {
1232 *decided = loc;
1233 break;
1234 }
1235 else
1236 return NULL;
1237 }
1238 else
1239 {
1240 num_eras = _NL_CURRENT_WORD (LC_TIME,
1241 _NL_TIME_ERA_NUM_ENTRIES);
1242 for (era_cnt = 0; era_cnt < (int) num_eras;
1243 ++era_cnt, rp = rp_backup)
1244 {
1245 era = _nl_select_era_entry (era_cnt);
1246 if (match_string (era->era_name, rp))
1247 {
1248 *decided = loc;
1249 break;
1250 }
1251 }
1252 if (era_cnt == (int) num_eras)
1253 {
1254 era_cnt = -1;
1255 if (*decided == loc)
1256 return NULL;
1257 }
1258 else
1259 break;
1260 }
1261
1262 *decided = raw;
1263 }
1264 /* The C locale has no era information, so use the
1265 normal representation. */
1266 goto match_century;
1267 case 'y':
1268 if (*decided == raw)
1269 goto match_year_in_century;
1270
1271 get_number(0, 9999, 4);
1272 tm->tm_year = val;
1273 want_era = 1;
1274 want_xday = 1;
1275 break;
1276 case 'Y':
1277 if (*decided != raw)
1278 {
1279 num_eras = _NL_CURRENT_WORD (LC_TIME,
1280 _NL_TIME_ERA_NUM_ENTRIES);
1281 for (era_cnt = 0; era_cnt < (int) num_eras;
1282 ++era_cnt, rp = rp_backup)
1283 {
1284 era = _nl_select_era_entry (era_cnt);
1285 if (recursive (era->era_format))
1286 break;
1287 }
1288 if (era_cnt == (int) num_eras)
1289 {
1290 era_cnt = -1;
1291 if (*decided == loc)
1292 return NULL;
1293 else
1294 rp = rp_backup;
1295 }
1296 else
1297 {
1298 *decided = loc;
1299 era_cnt = -1;
1300 break;
1301 }
1302
1303 *decided = raw;
1304 }
1305 get_number (0, 9999, 4);
1306 tm->tm_year = val - 1900;
1307 want_century = 0;
1308 want_xday = 1;
1309 break;
1310 case 'x':
1311 if (*decided != raw)
1312 {
1313 const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_FMT);
1314
1315 if (*fmt == '\0')
1316 fmt = _NL_CURRENT (LC_TIME, D_FMT);
1317
1318 if (!recursive (fmt))
1319 {
1320 if (*decided == loc)
1321 return NULL;
1322 else
1323 rp = rp_backup;
1324 }
1325 else
1326 {
1327 if (strcmp (fmt, HERE_D_FMT))
1328 *decided = loc;
1329 break;
1330 }
1331 *decided = raw;
1332 }
1333 if (!recursive (HERE_D_FMT))
1334 return NULL;
1335 break;
1336 case 'X':
1337 if (*decided != raw)
1338 {
1339 const char *fmt = _NL_CURRENT (LC_TIME, ERA_T_FMT);
1340
1341 if (*fmt == '\0')
1342 fmt = _NL_CURRENT (LC_TIME, T_FMT);
1343
1344 if (!recursive (fmt))
1345 {
1346 if (*decided == loc)
1347 return NULL;
1348 else
1349 rp = rp_backup;
1350 }
1351 else
1352 {
1353 if (strcmp (fmt, HERE_T_FMT))
1354 *decided = loc;
1355 break;
1356 }
1357 *decided = raw;
1358 }
1359 if (!recursive (HERE_T_FMT))
1360 return NULL;
1361 break;
1362 default:
1363 return NULL;
1364 }
1365 break;
1366 #else
1367 /* We have no information about the era format. Just use
1368 the normal format. */
1369 if (*fmt != 'c' && *fmt != 'C' && *fmt != 'y' && *fmt != 'Y'
1370 && *fmt != 'x' && *fmt != 'X')
1371 /* This is an illegal format. */
1372 return NULL;
1373
1374 goto start_over;
1375 #endif
1376 case 'O':
1377 switch (*fmt++)
1378 {
1379 case 'd':
1380 case 'e':
1381 /* Match day of month using alternate numeric symbols. */
1382 get_alt_number (1, 31, 2);
1383 tm->tm_mday = val;
1384 have_mday = 1;
1385 want_xday = 1;
1386 break;
1387 case 'H':
1388 /* Match hour in 24-hour clock using alternate numeric
1389 symbols. */
1390 get_alt_number (0, 23, 2);
1391 tm->tm_hour = val;
1392 have_I = 0;
1393 break;
1394 case 'I':
1395 /* Match hour in 12-hour clock using alternate numeric
1396 symbols. */
1397 get_alt_number (1, 12, 2);
1398 tm->tm_hour = val - 1;
1399 have_I = 1;
1400 break;
1401 case 'm':
1402 /* Match month using alternate numeric symbols. */
1403 get_alt_number (1, 12, 2);
1404 tm->tm_mon = val - 1;
1405 have_mon = 1;
1406 want_xday = 1;
1407 break;
1408 case 'M':
1409 /* Match minutes using alternate numeric symbols. */
1410 get_alt_number (0, 59, 2);
1411 tm->tm_min = val;
1412 break;
1413 case 'S':
1414 /* Match seconds using alternate numeric symbols. */
1415 get_alt_number (0, 61, 2);
1416 tm->tm_sec = val;
1417 break;
1418 case 'U':
1419 case 'V':
1420 case 'W':
1421 get_alt_number (0, 53, 2);
1422 /* XXX This cannot determine any field in TM without
1423 further information. */
1424 break;
1425 case 'w':
1426 /* Match number of weekday using alternate numeric symbols. */
1427 get_alt_number (0, 6, 1);
1428 tm->tm_wday = val;
1429 have_wday = 1;
1430 break;
1431 case 'y':
1432 /* Match year within century using alternate numeric symbols. */
1433 get_alt_number (0, 99, 2);
1434 tm->tm_year = val >= 69 ? val : val + 100;
1435 want_xday = 1;
1436 break;
1437 default:
1438 return NULL;
1439 }
1440 break;
1441 default:
1442 return NULL;
1443 }
1444 }
1445
1446 if (have_I && is_pm)
1447 tm->tm_hour += 12;
1448
1449 if (century != -1)
1450 {
1451 if (want_century)
1452 tm->tm_year = tm->tm_year % 100 + (century - 19) * 100;
1453 else
1454 /* Only the century, but not the year. Strange, but so be it. */
1455 tm->tm_year = (century - 19) * 100;
1456 }
1457
1458 #ifdef _NL_CURRENT
1459 if (era_cnt != -1)
1460 {
1461 era = _nl_select_era_entry(era_cnt);
1462 if (want_era)
1463 tm->tm_year = (era->start_date[0]
1464 + ((tm->tm_year - era->offset)
1465 * era->absolute_direction));
1466 else
1467 /* Era start year assumed. */
1468 tm->tm_year = era->start_date[0];
1469 }
1470 else
1471 #endif
1472 if (want_era)
1473 return NULL;
1474
1475 if (want_xday && !have_wday)
1476 {
1477 if ( !(have_mon && have_mday) && have_yday)
1478 {
1479 /* We don't have tm_mon and/or tm_mday, compute them. */
1480 int t_mon = 0;
1481 while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon] <= tm->tm_yday)
1482 t_mon++;
1483 if (!have_mon)
1484 tm->tm_mon = t_mon - 1;
1485 if (!have_mday)
1486 tm->tm_mday =
1487 (tm->tm_yday
1488 - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
1489 }
1490 day_of_the_week (tm);
1491 }
1492 if (want_xday && !have_yday)
1493 day_of_the_year (tm);
1494
1495 return (char *) rp;
1496 }
1497
1498
1499 char *
1500 msn_strptime (buf, format, tm)
1501 const char *buf;
1502 const char *format;
1503 struct tm *tm;
1504 {
1505 enum locale_status decided;
1506
1507 #ifdef _NL_CURRENT
1508 decided = not;
1509 #else
1510 decided = raw;
1511 #endif
1512 return strptime_internal (buf, format, tm, &decided, -1);
1513 }
1514 #else
1515 #define msn_strptime strptime
1516 #endif