Rocco Rutte:
[apps/madmutt.git] / from.c
1 /*
2  * Copyright notice from original mutt:
3  * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
4  *
5  * This file is part of mutt-ng, see http://www.muttng.org/.
6  * It's licensed under the GNU General Public License,
7  * please see the file GPL in the top level source directory.
8  */
9
10 #if HAVE_CONFIG_H
11 # include "config.h"
12 #endif
13
14 #include "mutt.h"
15
16 #include <ctype.h>
17 #include <string.h>
18
19 static const char *next_word (const char *s)
20 {
21   while (*s && !ISSPACE (*s))
22     s++;
23   SKIPWS (s);
24   return s;
25 }
26
27 int mutt_check_month (const char *s)
28 {
29   int i;
30
31   for (i = 0; i < 12; i++)
32     if (mutt_strncasecmp (s, Months[i], 3) == 0)
33       return (i);
34   return (-1);                  /* error */
35 }
36
37 static int is_day_name (const char *s)
38 {
39   int i;
40
41   if ((mutt_strlen (s) < 3) || !*(s + 3) || !ISSPACE (*(s + 3)))
42     return 0;
43   for (i = 0; i < 7; i++)
44     if (mutt_strncasecmp (s, Weekdays[i], 3) == 0)
45       return 1;
46   return 0;
47 }
48
49 /*
50  * A valid message separator looks like:
51  *
52  * From [ <return-path> ] <weekday> <month> <day> <time> [ <timezone> ] <year>
53  */
54
55 int is_from (const char *s, char *path, size_t pathlen, time_t * tp)
56 {
57   struct tm tm;
58   int yr;
59
60   if (path)
61     *path = 0;
62
63   if (mutt_strncmp ("From ", s, 5) != 0)
64     return 0;
65
66   s = next_word (s);            /* skip over the From part. */
67   if (!*s)
68     return 0;
69
70   dprint (3, (debugfile, "\nis_from(): parsing: %s", s));
71
72   if (!is_day_name (s)) {
73     const char *p;
74     size_t len;
75     short q = 0;
76
77     for (p = s; *p && (q || !ISSPACE (*p)); p++) {
78       if (*p == '\\') {
79         if (*++p == '\0')
80           return 0;
81       }
82       else if (*p == '"') {
83         q = !q;
84       }
85     }
86
87     if (q || !*p)
88       return 0;
89
90     if (path) {
91       len = (size_t) (p - s);
92       if (len + 1 > pathlen)
93         len = pathlen - 1;
94       memcpy (path, s, len);
95       path[len] = 0;
96       dprint (3, (debugfile, "is_from(): got return path: %s\n", path));
97     }
98
99     s = p + 1;
100     SKIPWS (s);
101     if (!*s)
102       return 0;
103
104     if (!is_day_name (s)) {
105       dprint (1, (debugfile, "is_from():  expected weekday, got: %s\n", s));
106       return 0;
107     }
108   }
109
110   s = next_word (s);
111   if (!*s)
112     return 0;
113
114   /* do a quick check to make sure that this isn't really the day of the week.
115    * this could happen when receiving mail from a local user whose login name
116    * is the same as a three-letter abbreviation of the day of the week.
117    */
118   if (is_day_name (s)) {
119     s = next_word (s);
120     if (!*s)
121       return 0;
122   }
123
124   /* now we should be on the month. */
125   if ((tm.tm_mon = mutt_check_month (s)) < 0)
126     return 0;
127
128   /* day */
129   s = next_word (s);
130   if (!*s)
131     return 0;
132   if (sscanf (s, "%d", &tm.tm_mday) != 1)
133     return 0;
134
135   /* time */
136   s = next_word (s);
137   if (!*s)
138     return 0;
139
140   /* Accept either HH:MM or HH:MM:SS */
141   if (sscanf (s, "%d:%d:%d", &tm.tm_hour, &tm.tm_min, &tm.tm_sec) == 3);
142   else if (sscanf (s, "%d:%d", &tm.tm_hour, &tm.tm_min) == 2)
143     tm.tm_sec = 0;
144   else
145     return 0;
146
147   s = next_word (s);
148   if (!*s)
149     return 0;
150
151   /* timezone? */
152   if (isalpha ((unsigned char) *s) || *s == '+' || *s == '-') {
153     s = next_word (s);
154     if (!*s)
155       return 0;
156
157     /*
158      * some places have two timezone fields after the time, e.g.
159      *      From xxxx@yyyyyyy.fr Wed Aug  2 00:39:12 MET DST 1995
160      */
161     if (isalpha ((unsigned char) *s)) {
162       s = next_word (s);
163       if (!*s)
164         return 0;
165     }
166   }
167
168   /* year */
169   if (sscanf (s, "%d", &yr) != 1)
170     return 0;
171   tm.tm_year = yr > 1900 ? yr - 1900 : (yr < 70 ? yr + 100 : yr);
172
173   dprint (3,
174           (debugfile,
175            "is_from(): month=%d, day=%d, hr=%d, min=%d, sec=%d, yr=%d.\n",
176            tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
177            tm.tm_year));
178
179   tm.tm_isdst = -1;
180
181   if (tp)
182     *tp = mutt_mktime (&tm, 0);
183   return 1;
184 }