Commit 93717359 937173596bd77d773c3fc8330a1ebbe2c8c13df6 by Sergey Poznyakoff

Implement mu_scan_datetime.

* include/mailutils/stream.h (mu_fixed_memory_stream_create): New proto.
* libmailutils/stream/memory_stream.c
(mu_fixed_memory_stream_create): New function.

* include/mailutils/util.h (mu_parse_imap_date_time)
(mu_parse_ctime_date_time): Remove.
(mu_scan_datetime): New proto.
(mu_strftime): Remove const from the last arg.
(MU_DATETIME_FROM,MU_DATETIME_IMAP)
(MU_DATETIME_IMAP_SEARCH,MU_DATETIME_INTERNALDATE): New defines.
* libmailutils/base/strftime.c: New file.
* libmailutils/base/Makefile.am (libbase_la_SOURCES): Add strftime.c.
* libmailutils/base/date.c (mu_scan_datetime): New function.
* libmailutils/base/mutil.c (mu_strftime): Remove.

* libmailutils/tests/scantime.at: New file.
* libmailutils/tests/scantime.c: New file.
* libmailutils/tests/Makefile.am (noinst_PROGRAMS): Add scantime.
(TESTSUITE_AT): Add scantime.at.
* libmailutils/tests/strftime.c (main): Call mu_set_program_name.
* libmailutils/tests/testsuite.at: Include scantime.at

* libmu_sieve/actions.c (mime_create_reason): Use mu_c_streamftime.

* imap4d/fetch.c (_frt_internaldate): Use mu_scan_datetime.
* imap4d/util.c (util_parse_internal_date): Likewise.
* libmu_scm/mu_message.c (mu-message-get-envelope-date): Likewise.
* libproto/imap/fetch.c (_date_mapper): Likewise.
* mail/from.c (hdr_date): Use mu_scan_datetime.
1 parent 025c888a
...@@ -960,16 +960,12 @@ _frt_internaldate (struct fetch_function_closure *ffc, ...@@ -960,16 +960,12 @@ _frt_internaldate (struct fetch_function_closure *ffc,
960 mu_envelope_t env = NULL; 960 mu_envelope_t env = NULL;
961 struct tm tm, *tmp = NULL; 961 struct tm tm, *tmp = NULL;
962 mu_timezone tz; 962 mu_timezone tz;
963 char datebuf[sizeof ("13-Jul-2002 00:00:00")];
964 int tzoff;
965 int tzh = 0, tzm = 0;
966 963
967 mu_message_get_envelope (frt->msg, &env); 964 mu_message_get_envelope (frt->msg, &env);
968 if (mu_envelope_sget_date (env, &date) == 0 965 if (mu_envelope_sget_date (env, &date) == 0
969 && mu_parse_ctime_date_time (&date, &tm, &tz) == 0) 966 && mu_scan_datetime (date, MU_DATETIME_FROM, &tm, &tz, NULL) == 0)
970 { 967 {
971 tmp = &tm; 968 tmp = &tm;
972 tzoff = tz.utc_offset;
973 } 969 }
974 else 970 else
975 { 971 {
...@@ -977,18 +973,13 @@ _frt_internaldate (struct fetch_function_closure *ffc, ...@@ -977,18 +973,13 @@ _frt_internaldate (struct fetch_function_closure *ffc,
977 struct timeval stv; 973 struct timeval stv;
978 struct timezone stz; 974 struct timezone stz;
979 975
980 gettimeofday(&stv, &stz); 976 gettimeofday (&stv, &stz);
981 t = stv.tv_sec; 977 t = stv.tv_sec;
982 tzoff = - stz.tz_minuteswest; 978 tz.utc_offset = - stz.tz_minuteswest;
983 tmp = localtime (&t); 979 tmp = localtime (&t);
984 } 980 }
985 tzh = tzoff / 3600;
986 if (tzoff < 0)
987 tzoff = - tzoff;
988 tzm = tzoff % 3600;
989 mu_strftime (datebuf, sizeof (datebuf), "%d-%b-%Y %H:%M:%S", tmp);
990 io_sendf ("%s", ffc->name); 981 io_sendf ("%s", ffc->name);
991 io_sendf (" \"%s %+03d%02d\"", datebuf, tzh, tzm); 982 mu_c_streamftime (iostream, " \"%d-%b-%Y %H:%M:%S %z\"", tmp, &tz);
992 return 0; 983 return 0;
993 } 984 }
994 985
......
...@@ -373,9 +373,8 @@ util_parse_internal_date (char *date, time_t *timep, ...@@ -373,9 +373,8 @@ util_parse_internal_date (char *date, time_t *timep,
373 struct tm tm; 373 struct tm tm;
374 mu_timezone tz; 374 mu_timezone tz;
375 time_t time; 375 time_t time;
376 char **datep = &date;
377 376
378 if (mu_parse_imap_date_time ((const char **) datep, &tm, &tz)) 377 if (mu_scan_datetime (date, MU_DATETIME_IMAP_SEARCH, &tm, &tz, NULL))
379 return 1; 378 return 1;
380 379
381 adjust_tm (&tm, &tz, flag); 380 adjust_tm (&tm, &tz, flag);
...@@ -412,7 +411,7 @@ util_parse_ctime_date (const char *date, time_t *timep, ...@@ -412,7 +411,7 @@ util_parse_ctime_date (const char *date, time_t *timep,
412 struct tm tm; 411 struct tm tm;
413 mu_timezone tz; 412 mu_timezone tz;
414 413
415 if (mu_parse_ctime_date_time (&date, &tm, &tz) == 0) 414 if (mu_scan_datetime (date, MU_DATETIME_FROM, &tm, &tz, NULL) == 0)
416 { 415 {
417 adjust_tm (&tm, &tz, flag); 416 adjust_tm (&tm, &tz, flag);
418 *timep = mu_tm2time (&tm, &tz); 417 *timep = mu_tm2time (&tm, &tz);
......
...@@ -305,6 +305,8 @@ int mu_stdio_stream_create (mu_stream_t *pstream, int fd, int flags); ...@@ -305,6 +305,8 @@ int mu_stdio_stream_create (mu_stream_t *pstream, int fd, int flags);
305 int mu_memory_stream_create (mu_stream_t *pstream, int flags); 305 int mu_memory_stream_create (mu_stream_t *pstream, int flags);
306 int mu_static_memory_stream_create (mu_stream_t *pstream, const void *mem, 306 int mu_static_memory_stream_create (mu_stream_t *pstream, const void *mem,
307 size_t size); 307 size_t size);
308 int mu_fixed_memory_stream_create (mu_stream_t *pstream, void *mem,
309 size_t size, int flags);
308 310
309 int mu_mapfile_stream_create (mu_stream_t *pstream, const char *filename, 311 int mu_mapfile_stream_create (mu_stream_t *pstream, const char *filename,
310 int flags); 312 int flags);
......
...@@ -61,18 +61,22 @@ struct mu_timezone ...@@ -61,18 +61,22 @@ struct mu_timezone
61 typedef struct mu_timezone mu_timezone; 61 typedef struct mu_timezone mu_timezone;
62 62
63 int mu_parse_date (const char *p, time_t *rettime, const time_t *now); 63 int mu_parse_date (const char *p, time_t *rettime, const time_t *now);
64 int mu_parse_imap_date_time (const char **p, struct tm *tm,
65 mu_timezone *tz);
66 int mu_parse_ctime_date_time (const char **p, struct tm *tm,
67 mu_timezone *tz);
68 64
69 time_t mu_utc_offset (void); 65 time_t mu_utc_offset (void);
70 time_t mu_tm2time (struct tm *timeptr, mu_timezone *tz); 66 time_t mu_tm2time (struct tm *timeptr, mu_timezone *tz);
71 size_t mu_strftime (char *s, size_t max, const char *format, 67 size_t mu_strftime (char *s, size_t max, const char *format, struct tm *tm);
72 const struct tm *tm);
73 68
74 int mu_c_streamftime (mu_stream_t str, const char *fmt, struct tm *tm, 69 int mu_c_streamftime (mu_stream_t str, const char *fmt, struct tm *tm,
75 struct mu_timezone *tz); 70 struct mu_timezone *tz);
71 int mu_scan_datetime (const char *input, const char *fmt, struct tm *tm,
72 struct mu_timezone *tz, char **endp);
73
74 /* Common datetime formats: */
75 #define MU_DATETIME_FROM "%a %b %e %H:%M:%S %Y"
76 #define MU_DATETIME_IMAP "%d-%b-%Y %H:%M:%S %z"
77 #define MU_DATETIME_IMAP_SEARCH "%d-%b-%Y%? %H:%M:%S %z"
78 #define MU_DATETIME_INTERNALDATE "%a, %e %b %Y %H:%M:%S %z"
79
76 80
77 /* ----------------------- */ 81 /* ----------------------- */
78 /* File & path names. */ 82 /* File & path names. */
......
...@@ -61,6 +61,7 @@ libbase_la_SOURCES = \ ...@@ -61,6 +61,7 @@ libbase_la_SOURCES = \
61 sha1.c\ 61 sha1.c\
62 secret.c\ 62 secret.c\
63 spawnvp.c\ 63 spawnvp.c\
64 strftime.c\
64 symlink.c\ 65 symlink.c\
65 tempfile.c\ 66 tempfile.c\
66 ticket.c\ 67 ticket.c\
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
26 #include <mailutils/stream.h> 26 #include <mailutils/stream.h>
27 #include <mailutils/errno.h> 27 #include <mailutils/errno.h>
28 #include <mailutils/cstr.h> 28 #include <mailutils/cstr.h>
29 #include <mailutils/cctype.h>
29 30
30 #define SECS_PER_DAY 86400 31 #define SECS_PER_DAY 86400
31 #define ADJUSTMENT -719162L 32 #define ADJUSTMENT -719162L
...@@ -528,140 +529,349 @@ mu_c_streamftime (mu_stream_t str, const char *fmt, struct tm *input_tm, ...@@ -528,140 +529,349 @@ mu_c_streamftime (mu_stream_t str, const char *fmt, struct tm *input_tm,
528 return rc; 529 return rc;
529 } 530 }
530 531
531 int 532 static int
532 mu_parse_imap_date_time (const char **p, struct tm *tm, mu_timezone *tz) 533 _mu_short_weekday_string (const char *str)
533 { 534 {
534 int year, mon, day, hour, min, sec;
535 char zone[6] = "+0000"; /* ( "+" / "-" ) hhmm */
536 char month[5] = "";
537 int hh = 0;
538 int mm = 0;
539 int sign = 1;
540 int scanned = 0, scanned3;
541 int i; 535 int i;
542 int tzoffset; 536
543 537 for (i = 0; i < 7; i++)
544 day = mon = year = hour = min = sec = 0;
545
546 memset (tm, 0, sizeof (*tm));
547
548 switch (sscanf (*p,
549 "%2d-%3s-%4d%n %2d:%2d:%2d %5s%n",
550 &day, month, &year, &scanned3, &hour, &min, &sec, zone,
551 &scanned))
552 { 538 {
553 case 3: 539 if (mu_c_strncasecmp (str, short_wday[i], 3) == 0)
554 scanned = scanned3; 540 return i;
555 break;
556 case 7:
557 break;
558 default:
559 return -1;
560 } 541 }
542 return -1;
543 }
561 544
562 tm->tm_sec = sec; 545 static int
563 tm->tm_min = min; 546 _mu_full_weekday_string (const char *str, char **endp)
564 tm->tm_hour = hour; 547 {
565 tm->tm_mday = day; 548 int i;
566 549
567 for (i = 0; i < 12; i++) 550 for (i = 0; i < 7; i++)
568 { 551 {
569 if (mu_c_strncasecmp (month, short_month[i], 3) == 0) 552 if (mu_c_strcasecmp (str, full_wday[i]) == 0)
570 { 553 {
571 mon = i; 554 if (endp)
572 break; 555 *endp = (char*) (str + strlen (full_wday[i]));
556 return i;
573 } 557 }
574 } 558 }
575 tm->tm_mon = mon; 559 return -1;
576 tm->tm_year = (year > 1900) ? year - 1900 : year; 560 }
577 tm->tm_yday = 0; /* unknown. */
578 tm->tm_wday = 0; /* unknown. */
579 #if HAVE_STRUCT_TM_TM_ISDST
580 tm->tm_isdst = -1; /* unknown. */
581 #endif
582
583 hh = (zone[1] - '0') * 10 + (zone[2] - '0');
584 mm = (zone[3] - '0') * 10 + (zone[4] - '0');
585 sign = (zone[0] == '-') ? -1 : +1;
586 tzoffset = sign * (hh * 60 * 60 + mm * 60);
587 561
588 #if HAVE_STRUCT_TM_TM_GMTOFF
589 tm->tm_gmtoff = tzoffset;
590 #endif
591 562
592 if (tz) 563 static int
564 _mu_short_month_string (const char *str)
565 {
566 int i;
567
568 for (i = 0; i < 12; i++)
593 { 569 {
594 tz->utc_offset = tzoffset; 570 if (mu_c_strncasecmp (str, short_month[i], 3) == 0)
595 tz->tz_name = NULL; 571 return i;
596 } 572 }
573 return -1;
574 }
597 575
598 *p += scanned; 576 static int
599 577 _mu_full_month_string (const char *str, char **endp)
600 return 0; 578 {
579 int i;
580
581 for (i = 0; i < 12; i++)
582 {
583 if (mu_c_strcasecmp (str, full_month[i]) == 0)
584 {
585 if (endp)
586 *endp = (char*) (str + strlen (full_month[i]));
587 return i;
588 }
589 }
590 return -1;
601 } 591 }
602 592
603 /* "ctime" format is: Thu Jul 01 15:58:27 1999, with no trailing \n. */
604 int 593 int
605 mu_parse_ctime_date_time (const char **p, struct tm *tm, mu_timezone *tz) 594 get_num (const char *str, char **endp, int ndig, int minval, int maxval,
595 int *pn)
606 { 596 {
607 int wday = 0; 597 int x = 0;
608 int year = 0;
609 int mon = 0;
610 int day = 0;
611 int hour = 0;
612 int min = 0;
613 int sec = 0;
614 int n = 0;
615 int i; 598 int i;
616 char weekday[5] = ""; 599
617 char month[5] = ""; 600 errno = 0;
601 for (i = 0; i < ndig && *str && mu_isdigit (*str); str++, i++)
602 x = x * 10 + *str - '0';
618 603
619 if (sscanf (*p, "%3s %3s %2d %2d:%2d:%2d %d%n\n", 604 *endp = (char*) str;
620 weekday, month, &day, &hour, &min, &sec, &year, &n) != 7) 605 if (i == 0)
606 return -1;
607 else if (pn)
608 *pn = i;
609 else if (i != ndig)
621 return -1; 610 return -1;
611 if (x < minval || x > maxval)
612 return -1;
613 return x;
614 }
622 615
623 *p += n; 616 #define DT_YEAR 0x01
617 #define DT_MONTH 0x02
618 #define DT_MDAY 0x04
619 #define DT_WDAY 0x08
620 #define DT_HOUR 0x10
621 #define DT_MIN 0x20
622 #define DT_SEC 0x40
624 623
625 for (i = 0; i < 7; i++) 624 int
625 mu_scan_datetime (const char *input, const char *fmt,
626 struct tm *tm, struct mu_timezone *tz, char **endp)
627 {
628 int rc = 0;
629 char *p;
630 int n;
631 int eof_ok = 0;
632 int datetime_parts = 0;
633
634 memset (tm, 0, sizeof *tm);
635 #ifdef HAVE_STRUCT_TM_TM_ISDST
636 tm->tm_isdst = -1; /* unknown. */
637 #endif
638 /* provide default timezone, in case it is not supplied in input */
639 if (tz)
626 { 640 {
627 if (mu_c_strncasecmp (weekday, short_wday[i], 3) == 0) 641 memset (tz, 0, sizeof *tz);
628 { 642 tz->utc_offset = mu_utc_offset ();
629 wday = i;
630 break;
631 }
632 } 643 }
633 644
634 for (i = 0; i < 12; i++) 645 /* Skip leading whitespace */
646 input = mu_str_skip_class (input, MU_CTYPE_BLANK);
647 for (; *fmt && rc == 0; fmt++)
635 { 648 {
636 if (mu_c_strncasecmp (month, short_month[i], 3) == 0) 649 if (mu_isspace (*fmt))
637 { 650 {
638 mon = i; 651 fmt = mu_str_skip_class (fmt, MU_CTYPE_BLANK);
639 break; 652 input = mu_str_skip_class (input, MU_CTYPE_BLANK);
653 if (!*fmt)
654 break;
640 } 655 }
656 eof_ok = 0;
657
658 if (*fmt == '%')
659 {
660 switch (*++fmt)
661 {
662 case 'a':
663 /* The abbreviated weekday name. */
664 n = _mu_short_weekday_string (input);
665 if (n == -1)
666 rc = MU_ERR_PARSE;
667 else
668 {
669 tm->tm_wday = n;
670 datetime_parts |= DT_WDAY;
671 input += 3;
672 }
673 break;
674
675 case 'A':
676 /* The full weekday name. */
677 n = _mu_full_weekday_string (input, &p);
678 if (n == -1)
679 rc = MU_ERR_PARSE;
680 else
681 {
682 tm->tm_wday = n;
683 datetime_parts |= DT_WDAY;
684 input = p;
685 }
686 break;
687
688 case 'b':
689 /* The abbreviated month name. */
690 n = _mu_short_month_string (input);
691 if (n == -1)
692 rc = MU_ERR_PARSE;
693 else
694 {
695 tm->tm_mon = n;
696 datetime_parts |= DT_MONTH;
697 input += 3;
698 }
699 break;
700
701 case 'B':
702 /* The full month name. */
703 n = _mu_full_month_string (input, &p);
704 if (n == -1)
705 rc = MU_ERR_PARSE;
706 else
707 {
708 tm->tm_mon = n;
709 datetime_parts |= DT_MONTH;
710 input = p;
711 }
712 break;
713
714 case 'd':
715 /* The day of the month as a decimal number (range 01 to 31). */
716 n = get_num (input, &p, 2, 1, 31, NULL);
717 if (n == -1)
718 rc = MU_ERR_PARSE;
719 else
720 {
721 tm->tm_mday = n;
722 datetime_parts |= DT_MDAY;
723 input = p;
724 }
725 break;
726
727 case 'e':
728 /* Like %d, the day of the month as a decimal number, but a
729 leading zero is replaced by a space. */
730 {
731 int ndig;
732
733 n = get_num (input, &p, 2, 1, 31, &ndig);
734 if (n == -1)
735 rc = MU_ERR_PARSE;
736 else
737 {
738 tm->tm_mday = n;
739 datetime_parts |= DT_MDAY;
740 input = p;
741 }
742 }
743 break;
744
745 case 'H':
746 /* The hour as a decimal number using a 24-hour clock (range
747 00 to 23). */
748 n = get_num (input, &p, 2, 0, 23, NULL);
749 if (n == -1)
750 rc = MU_ERR_PARSE;
751 else
752 {
753 tm->tm_hour = n;
754 datetime_parts |= DT_HOUR;
755 input = p;
756 }
757 break;
758
759 case 'm':
760 /* The month as a decimal number (range 01 to 12). */
761 n = get_num (input, &p, 2, 1, 12, NULL);
762 if (n == -1)
763 rc = MU_ERR_PARSE;
764 else
765 {
766 tm->tm_mon = n - 1;
767 datetime_parts |= DT_MONTH;
768 input = p;
769 }
770 break;
771
772 case 'M':
773 /* The minute as a decimal number (range 00 to 59). */
774 n = get_num (input, &p, 2, 0, 59, NULL);
775 if (n == -1)
776 rc = MU_ERR_PARSE;
777 else
778 {
779 tm->tm_min = n;
780 datetime_parts |= DT_MIN;
781 input = p;
782 }
783 break;
784
785 case 'S':
786 /* The second as a decimal number (range 00 to 60) */
787 n = get_num (input, &p, 2, 0, 60, NULL);
788 if (n == -1)
789 rc = MU_ERR_PARSE;
790 else
791 {
792 tm->tm_sec = n;
793 datetime_parts |= DT_SEC;
794 input = p;
795 }
796 break;
797
798 case 'Y':
799 /* The year as a decimal number including the century. */
800 errno = 0;
801 n = strtoul (input, &p, 10);
802 if (errno || p == input)
803 rc = MU_ERR_PARSE;
804 else
805 {
806 tm->tm_year = n - 1900;
807 datetime_parts |= DT_YEAR;
808 input = p;
809 }
810 break;
811
812 case 'z':
813 /* The time-zone as hour offset from GMT */
814 {
815 int sign = 1;
816 int hr;
817
818 if (*input == '+')
819 input++;
820 else if (*input == '-')
821 {
822 input++;
823 sign = -1;
824 }
825 n = get_num (input, &p, 2, 0, 11, NULL);
826 if (n == -1)
827 rc = MU_ERR_PARSE;
828 else
829 {
830 input = p;
831 hr = n;
832 n = get_num (input, &p, 2, 0, 59, NULL);
833 if (n == -1)
834 rc = MU_ERR_PARSE;
835 else
836 {
837 input = p;
838 if (tz)
839 tz->utc_offset = sign * (hr * 60 + n) * 60;
840 }
841 }
842 }
843 break;
844
845 case '%':
846 if (*input == '%')
847 input++;
848 else
849 rc = MU_ERR_PARSE;
850 break;
851
852 case '?':
853 eof_ok = 1;
854 break;
855 }
856 if (eof_ok && rc == 0 && *input == 0)
857 break;
858 }
859 else if (*input != *fmt)
860 rc = MU_ERR_PARSE;
861 else
862 input++;
641 } 863 }
642 864
643 if (tm) 865 if (!eof_ok && rc == 0 && *input == 0 && *fmt)
644 { 866 rc = MU_ERR_PARSE;
645 memset (tm, 0, sizeof (struct tm));
646
647 tm->tm_sec = sec;
648 tm->tm_min = min;
649 tm->tm_hour = hour;
650 tm->tm_mday = day;
651 tm->tm_wday = wday;
652 tm->tm_mon = mon;
653 tm->tm_year = (year > 1900) ? year - 1900 : year;
654 #ifdef HAVE_STRUCT_TM_TM_ISDST
655 tm->tm_isdst = -1; /* unknown. */
656 #endif
657 }
658 867
659 /* ctime has no timezone information, set tz to local TZ if they ask. */ 868 if (!(datetime_parts & DT_WDAY) &&
660 if (tz) 869 (datetime_parts & (DT_YEAR|DT_MONTH|DT_MDAY)) ==
661 { 870 (DT_YEAR|DT_MONTH|DT_MDAY))
662 tz->utc_offset = mu_utc_offset (); 871 tm->tm_wday = dayofweek (tm->tm_year + 1900, tm->tm_mon, tm->tm_mday);
663 tz->tz_name = NULL;
664 }
665 872
666 return 0; 873 if (endp)
874 *endp = (char*) input;
875
876 return rc;
667 } 877 }
......
...@@ -56,18 +56,6 @@ mu_mh_delim (const char *str) ...@@ -56,18 +56,6 @@ mu_mh_delim (const char *str)
56 return str[0] == '\n'; 56 return str[0] == '\n';
57 } 57 }
58 58
59 /* A locale-independent version of strftime */
60 size_t
61 mu_strftime (char *s, size_t max, const char *format, const struct tm *tm)
62 {
63 size_t size;
64 mu_set_locale ("C");
65 size = strftime (s, max, format, tm);
66 mu_restore_locale ();
67 return size;
68 }
69
70
71 static void 59 static void
72 assoc_str_free (void *data) 60 assoc_str_free (void *data)
73 { 61 {
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2011 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library. If not, see
16 <http://www.gnu.org/licenses/>. */
17
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21 #include <mailutils/util.h>
22 #include <mailutils/stream.h>
23 #include <mailutils/errno.h>
24 #include <mailutils/cstr.h>
25
26 /* A locale-independent version of strftime */
27 size_t
28 mu_strftime (char *buf, size_t size, const char *format, struct tm *tm)
29 {
30 int rc;
31 mu_stream_t str;
32 mu_stream_stat_buffer stat;
33
34 if (mu_fixed_memory_stream_create (&str, buf, size, MU_STREAM_WRITE))
35 return 0;
36 mu_stream_set_stat (str, MU_STREAM_STAT_MASK (MU_STREAM_STAT_OUT), stat);
37 rc = mu_c_streamftime (str, format, tm, NULL);
38 if (rc == 0)
39 rc = mu_stream_write (str, "", 1, NULL);
40 mu_stream_unref (str);
41 return rc ? 0 : stat[MU_STREAM_STAT_OUT] - 1;
42 }
43
44
...@@ -88,6 +88,27 @@ _memory_write (mu_stream_t stream, const char *iptr, size_t isize, ...@@ -88,6 +88,27 @@ _memory_write (mu_stream_t stream, const char *iptr, size_t isize,
88 } 88 }
89 89
90 static int 90 static int
91 _fixed_size_memory_write (mu_stream_t stream, const char *iptr, size_t isize,
92 size_t *nbytes)
93 {
94 struct _mu_memory_stream *mfs = (struct _mu_memory_stream *) stream;
95
96 if (mfs->capacity < mfs->offset + isize)
97 isize = mfs->capacity - mfs->offset;
98
99 memcpy (mfs->ptr + mfs->offset, iptr, isize);
100
101 mfs->offset += isize;
102
103 if (mfs->offset > mfs->size)
104 mfs->size = mfs->offset;
105
106 if (nbytes)
107 *nbytes = isize;
108 return 0;
109 }
110
111 static int
91 _memory_truncate (mu_stream_t stream, mu_off_t len) 112 _memory_truncate (mu_stream_t stream, mu_off_t len)
92 { 113 {
93 struct _mu_memory_stream *mfs = (struct _mu_memory_stream *) stream; 114 struct _mu_memory_stream *mfs = (struct _mu_memory_stream *) stream;
...@@ -271,3 +292,39 @@ mu_static_memory_stream_create (mu_stream_t *pstream, const void *mem, ...@@ -271,3 +292,39 @@ mu_static_memory_stream_create (mu_stream_t *pstream, const void *mem,
271 return 0; 292 return 0;
272 } 293 }
273 294
295 int
296 mu_fixed_memory_stream_create (mu_stream_t *pstream, void *mem,
297 size_t size, int flags)
298 {
299 mu_stream_t stream;
300 struct _mu_memory_stream *str;
301
302 flags &= (MU_STREAM_READ|MU_STREAM_WRITE);
303 if (!flags)
304 return EINVAL;
305
306 str = (struct _mu_memory_stream *)
307 _mu_stream_create (sizeof (*str), flags | MU_STREAM_SEEK);
308
309 if (!str)
310 return ENOMEM;
311
312 str->ptr = (void*) mem;
313 str->size = size;
314 str->offset = 0;
315 str->capacity = size;
316
317 str->stream.flags |= _MU_STR_OPEN;
318 if (flags & MU_STREAM_READ)
319 str->stream.read = _memory_read;
320 if (flags & MU_STREAM_WRITE)
321 str->stream.write = _fixed_size_memory_write;
322 str->stream.size = _memory_size;
323 str->stream.ctl = _memory_ioctl;
324 str->stream.seek = _memory_seek;
325
326 stream = (mu_stream_t) str;
327 *pstream = stream;
328
329 return 0;
330 }
......
...@@ -51,6 +51,7 @@ noinst_PROGRAMS = \ ...@@ -51,6 +51,7 @@ noinst_PROGRAMS = \
51 listop\ 51 listop\
52 mailcap\ 52 mailcap\
53 prop\ 53 prop\
54 scantime\
54 strftime\ 55 strftime\
55 tempfile\ 56 tempfile\
56 url-comp\ 57 url-comp\
...@@ -82,6 +83,7 @@ TESTSUITE_AT = \ ...@@ -82,6 +83,7 @@ TESTSUITE_AT = \
82 list.at\ 83 list.at\
83 mailcap.at\ 84 mailcap.at\
84 prop.at\ 85 prop.at\
86 scantime.at\
85 strftime.at\ 87 strftime.at\
86 testsuite.at\ 88 testsuite.at\
87 url.at\ 89 url.at\
......
1 # This file is part of GNU Mailutils. -*- Autotest -*-
2 # Copyright (C) 2011 Free Software Foundation, Inc.
3 #
4 # GNU Mailutils is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License as
6 # published by the Free Software Foundation; either version 3, or (at
7 # your option) any later version.
8 #
9 # GNU Mailutils is distributed in the hope that it will be useful, but
10 # WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>.
16
17 AT_BANNER(mu_scan_datetime)
18
19 dnl ---------------------------------------------------------------------
20 dnl SCANTIME([NAME], [KW], [FMT], [INPUT], [STDOUT = `'], [STDERR = `'])
21 dnl
22 m4_pushdef([SCANTIME],[
23 m4_pushdef([MU_TEST_GROUP],[scantime])
24 m4_pushdef([MU_TEST_KEYWORDS],[scantime mu_scan_datetime])
25 m4_pushdef([MU_TEST_COMMAND],[TZ=0 scantime -format='$3'])
26 MU_GENERIC_TEST([$1],[$2],[$4],[],[$5],[$6])
27 m4_popdef([MU_TEST_COMMAND])
28 m4_popdef([MU_TEST_KEYWORDS])
29 m4_popdef([MU_TEST_GROUP])
30 ])
31 dnl ---------------------------------------------------------------------
32
33 SCANTIME([RFC-822 time],[rfc822],
34 [%a %b %e %H:%M:%S %Y],
35 [Tue May 3 13:25:26 2011
36 Fri Nov 11 11:55:01 2011],
37 [sec=26,min=25,hour=13,mday=3,mon=4,year=111,wday=2,tz=0
38 sec=1,min=55,hour=11,mday=11,mon=10,year=111,wday=5,tz=0
39 ])
40
41 SCANTIME([IMAP time format],[imap],
42 [%d-%b-%Y %H:%M:%S %z],
43 [03-May-2011 13:25:26 +0100
44 11-Nov-2011 11:55:01 +0100],
45 [sec=26,min=25,hour=13,mday=3,mon=4,year=111,wday=2,tz=3600
46 sec=1,min=55,hour=11,mday=11,mon=10,year=111,wday=5,tz=3600
47 ])
48
49 SCANTIME([IMAP search time format],[imap-search],
50 [%d-%b-%Y%? %H:%M:%S %z],
51 [03-May-2011 13:25:26 +0100
52 03-May-2011],
53 [sec=26,min=25,hour=13,mday=3,mon=4,year=111,wday=2,tz=3600
54 sec=0,min=0,hour=0,mday=3,mon=4,year=111,wday=2,tz=0
55 ])
56
57 SCANTIME([IMAP INTERNALDATE],[imap-internaldate],
58 [%a, %d %b %Y %H:%M:%S %z],
59 [Tue, 03 May 2011 13:25:26 +0200],
60 [sec=26,min=25,hour=13,mday=3,mon=4,year=111,wday=2,tz=7200
61 ])
62
63 m4_popdef([SCANTIME])
64 dnl ---------------------------------------------------------------------
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000, 2001, 2007, 2009, 2010, 2011 Free Software
3 Foundation, Inc.
4
5 GNU Mailutils is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3, or (at your option)
8 any later version.
9
10 GNU Mailutils is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
17
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <mailutils/error.h>
25 #include <mailutils/errno.h>
26 #include <mailutils/util.h>
27 #include <mailutils/stream.h>
28 #include <mailutils/cctype.h>
29 #include <mailutils/cstr.h>
30 #include <mailutils/stdstream.h>
31
32 void
33 usage ()
34 {
35 mu_stream_printf (mu_strout, "usage: %s [-format=FMT] [-tz=TZ]\n",
36 mu_program_name);
37 exit (0);
38 }
39
40 int
41 main (int argc, char **argv)
42 {
43 int rc, i;
44 char *format = "%d-%b-%Y%? %H:%M:%S %z";
45 char *buf = NULL;
46 size_t size = 0;
47 size_t n;
48
49 mu_set_program_name (argv[0]);
50
51 mu_stdstream_setup (MU_STDSTREAM_RESET_NONE);
52
53 for (i = 1; i < argc; i++)
54 {
55 char *opt = argv[i];
56
57 if (strncmp (opt, "-format=", 8) == 0)
58 format = opt + 8;
59 else if (strcmp (opt, "-h") == 0)
60 usage ();
61 else
62 {
63 mu_error ("%s: unrecognized argument", opt);
64 exit (1);
65 }
66 }
67
68 while ((rc = mu_stream_getline (mu_strin, &buf, &size, &n)) == 0 && n > 0)
69 {
70 char *endp;
71 struct tm tm;
72 struct mu_timezone tz;
73
74 mu_rtrim_class (buf, MU_CTYPE_ENDLN);
75
76 rc = mu_scan_datetime (buf, format, &tm, &tz, &endp);
77 if (rc)
78 {
79 if (*endp)
80 mu_error ("parse failed near %s", endp);
81 else
82 mu_error ("parse failed at end of input");
83 continue;
84 }
85 if (*endp)
86 mu_printf ("# stopped at %s\n", endp);
87 /* FIXME: add tm_yday? */
88 mu_printf ("sec=%d,min=%d,hour=%d,mday=%d,mon=%d,year=%d,wday=%d,tz=%d\n",
89 tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mday, tm.tm_mon,
90 tm.tm_year, tm.tm_wday, tz.utc_offset);
91
92 //mu_c_streamftime (mu_strout, "%c %z%n", &tm, &tz);
93 }
94
95 if (rc)
96 {
97 mu_error ("%s", mu_strerror (rc));
98 return 1;
99 }
100 return 0;
101 }
...@@ -32,7 +32,7 @@ m4_popdef([MU_TEST_GROUP]) ...@@ -32,7 +32,7 @@ m4_popdef([MU_TEST_GROUP])
32 ]) 32 ])
33 33
34 dnl ------------------------------------------------------------ 34 dnl ------------------------------------------------------------
35 # Test data 35 # Some test data
36 36
37 # January 1970 37 # January 1970
38 # Su Mo Tu We Th Fr Sa 38 # Su Mo Tu We Th Fr Sa
......
...@@ -46,6 +46,8 @@ main (int argc, char **argv) ...@@ -46,6 +46,8 @@ main (int argc, char **argv)
46 size_t size = 0; 46 size_t size = 0;
47 size_t n; 47 size_t n;
48 struct mu_timezone tz, *tzp = NULL; 48 struct mu_timezone tz, *tzp = NULL;
49
50 mu_set_program_name (argv[0]);
49 51
50 mu_set_program_name (argv[0]); 52 mu_set_program_name (argv[0]);
51 mu_stdstream_setup (MU_STDSTREAM_RESET_NONE); 53 mu_stdstream_setup (MU_STDSTREAM_RESET_NONE);
......
...@@ -24,7 +24,7 @@ m4_define([MU_TEST_KEYWORDS]) ...@@ -24,7 +24,7 @@ m4_define([MU_TEST_KEYWORDS])
24 dnl ------------------------------------------------------------ 24 dnl ------------------------------------------------------------
25 m4_define([MU_TEST_COMMAND]) 25 m4_define([MU_TEST_COMMAND])
26 26
27 m4_define([mu_trimstr],[m4_if([$2],-1,[$1],[m4_substr($1,0,$2)...])]) 27 m4_define([mu_trimstr],[m4_if([$2],-1,[$1],[m4_substr([$1],0,$2)...])])
28 m4_define([mu_firstline],[mu_trimstr([$1],m4_index([$1],[ 28 m4_define([mu_firstline],[mu_trimstr([$1],m4_index([$1],[
29 ]))]) 29 ]))])
30 30
...@@ -43,7 +43,7 @@ dnl RUN-IF-FAIL $7 ...@@ -43,7 +43,7 @@ dnl RUN-IF-FAIL $7
43 dnl RUN-IF-PASS $8 43 dnl RUN-IF-PASS $8
44 dnl 44 dnl
45 m4_define([MU_GENERIC_TEST],[ 45 m4_define([MU_GENERIC_TEST],[
46 AT_SETUP([m4_if(MU_TEST_GROUP,[],,MU_TEST_GROUP: )m4_if([$1],[],mu_firstline([$3]),[$1])]) 46 AT_SETUP([m4_if(MU_TEST_GROUP,[],,MU_TEST_GROUP: )m4_if([$1],[],[mu_firstline([$3])],[$1])])
47 AT_KEYWORDS([MU_TEST_KEYWORDS $2]) 47 AT_KEYWORDS([MU_TEST_KEYWORDS $2])
48 AT_CHECK([ 48 AT_CHECK([
49 AT_DATA([input],[$3 49 AT_DATA([input],[$3
...@@ -83,6 +83,7 @@ m4_include([debugspec.at]) ...@@ -83,6 +83,7 @@ m4_include([debugspec.at])
83 AT_BANNER([IMAP IO]) 83 AT_BANNER([IMAP IO])
84 m4_include([imapio.at]) 84 m4_include([imapio.at])
85 85
86 m4_include([scantime.at])
86 m4_include([strftime.at]) 87 m4_include([strftime.at])
87 88
88 m4_include([fsaf.at]) 89 m4_include([fsaf.at])
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -104,7 +104,7 @@ mu_scm_message_print (SCM message_smob, SCM port, scm_print_state * pstate) ...@@ -104,7 +104,7 @@ mu_scm_message_print (SCM message_smob, SCM port, scm_print_state * pstate)
104 scm_puts ("UNKNOWN", port); 104 scm_puts ("UNKNOWN", port);
105 105
106 if (mu_envelope_sget_date (env, &p) == 0 106 if (mu_envelope_sget_date (env, &p) == 0
107 && mu_parse_ctime_date_time (&p, &tm, &tz) == 0) 107 && mu_scan_datetime (p, MU_DATETIME_FROM, &tm, &tz, NULL) == 0)
108 { 108 {
109 strftime (datebuf, sizeof (datebuf), "%a %b %e %H:%M", &tm); 109 strftime (datebuf, sizeof (datebuf), "%a %b %e %H:%M", &tm);
110 buffer = datebuf; 110 buffer = datebuf;
...@@ -416,7 +416,7 @@ SCM_DEFINE_PUBLIC (scm_mu_message_get_envelope_date, "mu-message-get-envelope-da ...@@ -416,7 +416,7 @@ SCM_DEFINE_PUBLIC (scm_mu_message_get_envelope_date, "mu-message-get-envelope-da
416 if (status) 416 if (status)
417 mu_scm_error (FUNC_NAME, status, "cannot get envelope date", 417 mu_scm_error (FUNC_NAME, status, "cannot get envelope date",
418 scm_list_1 (mesg)); 418 scm_list_1 (mesg));
419 status = mu_parse_ctime_date_time (&sdate, &tm, &tz); 419 status = mu_scan_datetime (sdate, MU_DATETIME_FROM, &tm, &tz, NULL);
420 if (status) 420 if (status)
421 mu_scm_error (FUNC_NAME, status, "invalid envelope date", 421 mu_scm_error (FUNC_NAME, status, "invalid envelope date",
422 scm_list_1 (scm_from_locale_string (sdate))); 422 scm_list_1 (scm_from_locale_string (sdate)));
......
...@@ -145,7 +145,6 @@ mime_create_reason (mu_mime_t mime, mu_message_t msg, const char *text) ...@@ -145,7 +145,6 @@ mime_create_reason (mu_mime_t mime, mu_message_t msg, const char *text)
145 char *sender; 145 char *sender;
146 mu_body_t body; 146 mu_body_t body;
147 mu_header_t hdr; 147 mu_header_t hdr;
148 char datestr[80];
149 static char *content_header = 148 static char *content_header =
150 "Content-Type: text/plain;charset=" MU_SIEVE_CHARSET "\n" 149 "Content-Type: text/plain;charset=" MU_SIEVE_CHARSET "\n"
151 "Content-Transfer-Encoding: 8bit\n"; 150 "Content-Transfer-Encoding: 8bit\n";
...@@ -156,13 +155,14 @@ mime_create_reason (mu_mime_t mime, mu_message_t msg, const char *text) ...@@ -156,13 +155,14 @@ mime_create_reason (mu_mime_t mime, mu_message_t msg, const char *text)
156 155
157 time (&t); 156 time (&t);
158 tm = localtime (&t); 157 tm = localtime (&t);
159 mu_strftime (datestr, sizeof datestr, "%a, %b %d %H:%M:%S %Y %Z", tm);
160 158
161 mu_sieve_get_message_sender (msg, &sender); 159 mu_sieve_get_message_sender (msg, &sender);
162 160
163 mu_stream_printf (stream, 161 mu_c_streamftime (stream,
164 "The original message was received at %s from %s.\n", 162 "The original message was received at "
165 datestr, sender); 163 "%a, %b %d %H:%M:%S %Y %Z", tm, NULL);
164
165 mu_stream_printf (stream, " from %s.\n", sender);
166 free (sender); 166 free (sender);
167 mu_stream_printf (stream, 167 mu_stream_printf (stream,
168 "Message was refused by recipient's mail filtering program.\n"); 168 "Message was refused by recipient's mail filtering program.\n");
...@@ -201,7 +201,7 @@ mime_create_ds (mu_mime_t mime, mu_message_t orig) ...@@ -201,7 +201,7 @@ mime_create_ds (mu_mime_t mime, mu_message_t orig)
201 201
202 mu_message_get_envelope (orig, &env); 202 mu_message_get_envelope (orig, &env);
203 if (mu_envelope_sget_date (env, &p) == 0 203 if (mu_envelope_sget_date (env, &p) == 0
204 && mu_parse_ctime_date_time (&p, &tm, &tz) == 0) 204 && mu_scan_datetime (p, MU_DATETIME_FROM, &tm, &tz, NULL) == 0)
205 t = mu_tm2time (&tm, &tz); 205 t = mu_tm2time (&tm, &tz);
206 else 206 else
207 /* Use local time instead */ 207 /* Use local time instead */
......
...@@ -339,14 +339,13 @@ _date_mapper (union mu_imap_fetch_response *resp, ...@@ -339,14 +339,13 @@ _date_mapper (union mu_imap_fetch_response *resp,
339 struct imap_list_element *elt, 339 struct imap_list_element *elt,
340 struct parse_response_env *parse_env) 340 struct parse_response_env *parse_env)
341 { 341 {
342 const char *p;
343 struct tm tm; 342 struct tm tm;
344 struct mu_timezone tz; 343 struct mu_timezone tz;
345 344
346 if (elt->type != imap_eltype_string) 345 if (elt->type != imap_eltype_string)
347 return MU_ERR_FAILURE; 346 return MU_ERR_FAILURE;
348 p = elt->v.string; 347 if (mu_scan_datetime (elt->v.string, MU_DATETIME_INTERNALDATE, &tm, &tz,
349 if (mu_parse_imap_date_time (&p, &tm, &tz)) 348 NULL))
350 return MU_ERR_FAILURE; 349 return MU_ERR_FAILURE;
351 resp->internaldate.tm = tm; 350 resp->internaldate.tm = tm;
352 resp->internaldate.tz = tz; 351 resp->internaldate.tz = tz;
...@@ -472,10 +471,10 @@ _fill_response (void *item, void *data) ...@@ -472,10 +471,10 @@ _fill_response (void *item, void *data)
472 rc = MU_ERR_FAILURE; 471 rc = MU_ERR_FAILURE;
473 else 472 else
474 { 473 {
475 char const *p = elt->v.string; 474 if (mu_scan_datetime (elt->v.string,
476 if (mu_parse_imap_date_time (&p, 475 MU_DATETIME_IMAP,
477 &env->envelope->date, 476 &env->envelope->date,
478 &env->envelope->tz)) 477 &env->envelope->tz, NULL))
479 rc = MU_ERR_FAILURE; 478 rc = MU_ERR_FAILURE;
480 else 479 else
481 rc = 0; 480 rc = 0;
......
...@@ -213,7 +213,7 @@ hdr_date (struct header_call_args *args, void *data) ...@@ -213,7 +213,7 @@ hdr_date (struct header_call_args *args, void *data)
213 213
214 mu_message_get_envelope (args->msg, &env); 214 mu_message_get_envelope (args->msg, &env);
215 if (mu_envelope_sget_date (env, &p) == 0 215 if (mu_envelope_sget_date (env, &p) == 0
216 && mu_parse_ctime_date_time (&p, &tm, &tz) == 0) 216 && mu_scan_datetime (p, MU_DATETIME_FROM, &tm, &tz, NULL) == 0)
217 strftime (date, sizeof(date), "%a %b %e %H:%M", &tm); 217 strftime (date, sizeof(date), "%a %b %e %H:%M", &tm);
218 } 218 }
219 return header_buf_string (args, date); 219 return header_buf_string (args, date);
......