1 /**
2 * @file
3 * Determine who the email is from
4 *
5 * @authors
6 * Copyright (C) 1996-2000,2013 Michael R. Elkins <me@mutt.org>
7 *
8 * @copyright
9 * This program is free software: you can redistribute it and/or modify it under
10 * the terms of the GNU General Public License as published by the Free Software
11 * Foundation, either version 2 of the License, or (at your option) any later
12 * version.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 /**
24 * @page email_from Who is the email from?
25 *
26 * Determine who the email is from
27 */
28
29 #include "config.h"
30 #include <stdbool.h>
31 #include <stdio.h>
32 #include <time.h>
33 #include "mutt/lib.h"
34 #include "from.h"
35
36 /**
37 * is_from - Is a string a 'From' header line?
38 * @param[in] s String to test
39 * @param[out] path Buffer for extracted path
40 * @param[in] pathlen Length of buffer
41 * @param[out] tp Extracted time
42 * @retval 1 Yes, it is
43 * @retval 0 No, it isn't
44 *
45 * A valid message separator looks like:
46 * `From <return-path> <weekday> <month> <day> <time> <year>`
47 */
is_from(const char * s,char * path,size_t pathlen,time_t * tp)48 bool is_from(const char *s, char *path, size_t pathlen, time_t *tp)
49 {
50 bool lax = false;
51
52 const regmatch_t *match = mutt_prex_capture(PREX_MBOX_FROM, s);
53 if (!match)
54 {
55 match = mutt_prex_capture(PREX_MBOX_FROM_LAX, s);
56 if (!match)
57 {
58 mutt_debug(LL_DEBUG1, "Could not parse From line: <%s>\n", s);
59 return false;
60 }
61 lax = true;
62 mutt_debug(LL_DEBUG2, "Fallback regex for From line: <%s>\n", s);
63 }
64
65 if (path)
66 {
67 const regmatch_t *msender =
68 &match[lax ? PREX_MBOX_FROM_LAX_MATCH_ENVSENDER : PREX_MBOX_FROM_MATCH_ENVSENDER];
69 const size_t dsize = MIN(pathlen, mutt_regmatch_len(msender) + 1);
70 mutt_str_copy(path, s + mutt_regmatch_start(msender), dsize);
71 }
72
73 if (tp)
74 {
75 // clang-format off
76 const regmatch_t *mmonth = &match[lax ? PREX_MBOX_FROM_LAX_MATCH_MONTH : PREX_MBOX_FROM_MATCH_MONTH];
77 const regmatch_t *mday = &match[lax ? PREX_MBOX_FROM_LAX_MATCH_DAY : PREX_MBOX_FROM_MATCH_DAY];
78 const regmatch_t *mtime = &match[lax ? PREX_MBOX_FROM_LAX_MATCH_TIME : PREX_MBOX_FROM_MATCH_TIME];
79 const regmatch_t *myear = &match[lax ? PREX_MBOX_FROM_LAX_MATCH_YEAR : PREX_MBOX_FROM_MATCH_YEAR];
80 // clang-format on
81
82 struct tm tm = { 0 };
83 tm.tm_isdst = -1;
84 tm.tm_mon = mutt_date_check_month(s + mutt_regmatch_start(mmonth));
85 sscanf(s + mutt_regmatch_start(mday), " %d", &tm.tm_mday);
86 sscanf(s + mutt_regmatch_start(mtime), "%d:%d:%d", &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
87 int year = 0;
88 sscanf(s + mutt_regmatch_start(myear), "%d", &year);
89 if (year > 1900)
90 tm.tm_year = year - 1900;
91 else if (year < 70)
92 tm.tm_year = year + 100;
93 else
94 tm.tm_year = year;
95 *tp = mutt_date_make_time(&tm, false);
96 }
97
98 return true;
99 }
100