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