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