f71e8a0ab8634b1854c8f47251e10cf22714d998
[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 <ctype.h>
15 #include <string.h>
16
17 #include <lib-lib/lib-lib.h>
18
19 #include "mutt.h"
20
21 int mutt_check_month (const char *s)
22 {
23   int i;
24
25   for (i = 0; i < 12; i++)
26     if (m_strncasecmp(s, Months[i], 3) == 0)
27       return (i);
28   return (-1);                  /* error */
29 }
30
31 static int is_day_name (const char *s)
32 {
33   int i;
34
35   if ((m_strlen(s) < 3) || !*(s + 3) || !ISSPACE (*(s + 3)))
36     return 0;
37   for (i = 0; i < 7; i++)
38     if (m_strncasecmp(s, Weekdays[i], 3) == 0)
39       return 1;
40   return 0;
41 }
42
43 /*
44  * A valid message separator looks like:
45  *
46  * From [ <return-path> ] <weekday> <month> <day> <time> [ <timezone> ] <year>
47  */
48
49 int is_from (const char *s, char *path, ssize_t pathlen, time_t * tp)
50 {
51   struct tm tm;
52   int yr;
53
54   if (path)
55     *path = 0;
56
57   if (m_strncmp("From ", s, 5) != 0)
58     return 0;
59
60   s = m_strnextsp(s);            /* skip over the From part. */
61   s = skipspaces(s);
62   if (!*s)
63     return 0;
64
65   if (!is_day_name (s)) {
66     const char *p;
67     ssize_t len;
68     short q = 0;
69
70     for (p = s; *p && (q || !ISSPACE (*p)); p++) {
71       if (*p == '\\') {
72         if (*++p == '\0')
73           return 0;
74       }
75       else if (*p == '"') {
76         q = !q;
77       }
78     }
79
80     if (q || !*p)
81       return 0;
82
83     if (path) {
84       len = p - s;
85       if (len + 1 > pathlen)
86         len = pathlen - 1;
87       memcpy (path, s, len);
88       path[len] = 0;
89     }
90
91     s = vskipspaces(p + 1);
92     if (!*s)
93       return 0;
94
95     if (!is_day_name (s)) {
96       return 0;
97     }
98   }
99
100   s = m_strnextsp(s);
101   s = skipspaces(s);
102   if (!*s)
103     return 0;
104
105   /* do a quick check to make sure that this isn't really the day of the week.
106    * this could happen when receiving mail from a local user whose login name
107    * is the same as a three-letter abbreviation of the day of the week.
108    */
109   if (is_day_name (s)) {
110     s = m_strnextsp(s);
111     s = skipspaces(s);
112     if (!*s)
113       return 0;
114   }
115
116   /* now we should be on the month. */
117   if ((tm.tm_mon = mutt_check_month (s)) < 0)
118     return 0;
119
120   /* day */
121   s = m_strnextsp(s);
122   s = skipspaces(s);
123   if (!*s)
124     return 0;
125   if (sscanf (s, "%d", &tm.tm_mday) != 1)
126     return 0;
127
128   /* time */
129   s = m_strnextsp(s);
130   s = skipspaces(s);
131   if (!*s)
132     return 0;
133
134   /* Accept either HH:MM or HH:MM:SS */
135   if (sscanf (s, "%d:%d:%d", &tm.tm_hour, &tm.tm_min, &tm.tm_sec) == 3);
136   else if (sscanf (s, "%d:%d", &tm.tm_hour, &tm.tm_min) == 2)
137     tm.tm_sec = 0;
138   else
139     return 0;
140
141   s = m_strnextsp(s);
142   s = skipspaces(s);
143   if (!*s)
144     return 0;
145
146   /* timezone? */
147   if (isalpha ((unsigned char) *s) || *s == '+' || *s == '-') {
148     s = m_strnextsp(s);
149     s = skipspaces(s);
150     if (!*s)
151       return 0;
152
153     /*
154      * some places have two timezone fields after the time, e.g.
155      *      From xxxx@yyyyyyy.fr Wed Aug  2 00:39:12 MET DST 1995
156      */
157     if (isalpha ((unsigned char) *s)) {
158       s = m_strnextsp(s);
159       s = skipspaces(s);
160       if (!*s)
161         return 0;
162     }
163   }
164
165   /* year */
166   if (sscanf (s, "%d", &yr) != 1)
167     return 0;
168   tm.tm_year = yr > 1900 ? yr - 1900 : (yr < 70 ? yr + 100 : yr);
169
170   tm.tm_isdst = -1;
171
172   if (tp)
173     *tp = mutt_mktime (&tm, 0);
174   return 1;
175 }