2 Copyright (c) 2004 Joey Schulze <joey@infodrom.org>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program 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
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include <sys/types.h>
29 /* #define FROM_DETECTION */
43 * Like strncpy() but with terminated result.
45 char *stringcopy(char *dest, const char *src, size_t n)
47 strncpy (dest, src, n-1);
53 * Strips balanced quotes in the middle of the realname
55 char *strip_quotes(char *name)
57 static char realname[HDR_LEN];
61 if ((cpl = index(name, '"')) != NULL && (cpr = index(cpl+1, '"')) != NULL) {
62 for (cp=name,xp=realname; *cp && xp < realname+sizeof(realname)-1; cp++) {
63 if (cp != cpl && cp != cpr)
73 * Extract the realname from a mail address
75 * From: "Log Kristian Koehntopp" <joey@infodrom.org>
76 * From: "Jérôme" ATHIAS <jerome@athias.fr>
77 * From: frank@kuesterei.ch (=?iso-8859-1?q?Frank_K=FCster?=)
78 * From: root@luonnotar.infodrom.org (Cron Daemon)
79 * From: <JoMaBusch@web.de>
80 * From: root@luonnotar.infodrom.org
82 char *realname(char *from)
84 static char name[HDR_LEN];
89 /* From: REALNAME <login@host.domain> */
90 if ((cpr = index(from, '<')) != NULL && index(from, '>') != NULL) {
91 if (cpr > from) cpr--;
93 /* Strip trailing spaces */
94 while (cpr > from && isspace(*cpr)) cpr--;
96 /* Strip leading spaces */
97 cpl=from;while (*cpl && isspace(*cpl)) cpl++;
99 /* Strip balanced surrounding quotes */
100 if (*cpl == '"' && *cpr == '"') { cpl++;cpr--; }
103 stringcopy (name, cpl,
104 sizeof(name) < cpr-cpl+2?sizeof(name):cpr-cpl+2);
106 if (index(name, '"') != NULL)
107 stringcopy (name, strip_quotes(name), sizeof(name));
109 /* Apparently no realname included */
110 cpl = index(from, '<');
111 cpr = index(from, '>');
112 stringcopy (name, cpl+1,
113 sizeof(name) < cpr-cpl?sizeof(name):cpr-cpl);
116 /* From: login@host.domain (REALNAME) */
117 } else if ((cpl = index(from, '(')) != NULL && (cpr = index(from, ')')) != NULL) {
118 stringcopy (name, cpl+1,
119 sizeof(name) < cpr-cpl?sizeof(name):cpr-cpl);
121 /* From: login@host.domain */
123 /* Strip leading spaces */
124 cpl=from;while (*cpl && isspace(*cpl)) cpl++;
125 for (cpr=cpl; *cpr && !isspace(*cpr); cpr++);
126 stringcopy (name, cpl,
127 sizeof(name) < cpr-cpl+1?sizeof(name):cpr-cpl+1);
134 * Tries to extract useful content from the From_ line
136 char *reduce_from_(char *from_)
138 static char name[HDR_LEN];
141 for (cpl=from_; *cpl && isspace(*cpl); cpl++);
142 for (cpr=cpl; *cpr && !isspace(*cpr); cpr++);
145 stringcopy (name, cpl,
146 sizeof(name) < cpr-cpl+1?sizeof(name):cpr-cpl+1);
150 int inspect_mbox(char *path, char *prefix, off_t size, int opt_flags)
161 char from_[HDR_LEN] = "";
162 char from[HDR_LEN] = "";
163 char realfrom[HDR_LEN] = "";
164 #ifdef FROM_DETECTION
165 char to[HDR_LEN] = "";
167 char subject[HDR_LEN] = "";
170 if ((f = fopen(path, "r")) == NULL)
173 if (size > 0 && fseek(f, size, SEEK_SET) != 0)
177 if ((cp = fgets(buf, sizeof(buf), f)) == NULL)
179 if (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n') {
180 buf[strlen(buf)-1] = '\0';
181 if (strlen(buf) > 0 && buf[strlen(buf)-1] == '\r')
182 buf[strlen(buf)-1] = '\0';
184 if (inheader && !feof(f)) {
185 lookahead = fgetc(f);
186 if (lookahead == TAB || lookahead == LWSP) {
187 if (buf[strlen(buf)-1] != LWSP)
188 strncat (buf, " ", sizeof(buf)-strlen(buf)-1);
189 if ((cp = fgets(tmp, sizeof(tmp), f)) != NULL) {
190 strncat (buf, tmp, sizeof(buf)-strlen(buf)-1);
191 if (strlen(buf) > 0 && buf[strlen(buf)-1] == '\n')
192 buf[strlen(buf)-1] = '\0';
193 if (strlen(buf) > 0 && buf[strlen(buf)-1] == '\r')
194 buf[strlen(buf)-1] = '\0';
196 if (strlen(tmp) > 0 && buf[strlen(tmp)-1] == '\n') {
197 /* Read the remainder */
198 while (!feof(f) && fgets(tmp, sizeof(tmp), f) != NULL) {
199 if (strlen(tmp) > 0 && tmp[strlen(tmp)-1] == '\n')
205 /* Rewind by one character for next read */
206 if (lookahead != EOF)
207 fseek(f, -1, SEEK_CUR);
210 /* Read the remainder */
211 while (!feof(f) && fgets(tmp, sizeof(tmp), f) != NULL) {
212 if (strlen(tmp) > 0 && tmp[strlen(tmp)-1] == '\n')
218 if (strlen(buf) == 0) {
223 stringcopy (realfrom, realname(from), sizeof(realfrom));
225 stringcopy (realfrom, reduce_from_(from_), sizeof(realfrom));
227 emit (prefix, realfrom, subject, priority, opt_flags);
229 #ifdef FROM_DETECTION
230 from_[0] = from[0] = to[0] = subject[0] = '\0';
232 from_[0] = from[0] = subject[0] = '\0';
236 if (strncasecmp(buf, "From ", 5) == 0)
237 stringcopy (from_, buf+5, sizeof(from_));
238 else if (strncasecmp(buf, "From: ", 6) == 0)
239 stringcopy (from, buf+6, sizeof(from));
240 #ifdef FROM_DETECTION
241 else if (strncasecmp(buf, "To: ", 4) == 0)
242 stringcopy (to, buf+4, sizeof(to));
244 else if (strncasecmp(buf, "Subject: ", 9) == 0)
245 stringcopy (subject, buf+9, sizeof(subject));
246 else if (strncasecmp(buf, "Priority: urgent", 16) == 0 && buf[16] == '\0')
248 else if (strncasecmp(buf, "X-Priority: 1", 13) == 0 && buf[13] == '\0')
251 } else if (strlen(buf) == 0) {
253 } else if (readnewline && strncasecmp(buf, "From ", 5) == 0) {
256 stringcopy (from_, buf+5, sizeof(from_));
266 int watch_mbox(char *path, char *prefix, off_t *size, int opt_flags)
269 struct utimbuf timbuf;
272 if (stat(path, &st) == 0) {
273 if (st.st_size > *size)
274 if (access(path, R_OK) == 0) {
275 timbuf.actime = st.st_atime;
276 timbuf.modtime = st.st_mtime;
278 newmail = inspect_mbox(path, prefix, *size, opt_flags);
280 utime(path, &timbuf);