]> git.notmuchmail.org Git - notmuch/blob - lib/message-id.c
Merge tag '0.25.1'
[notmuch] / lib / message-id.c
1 #include "notmuch-private.h"
2
3 /* Advance 'str' past any whitespace or RFC 822 comments. A comment is
4  * a (potentially nested) parenthesized sequence with '\' used to
5  * escape any character (including parentheses).
6  *
7  * If the sequence to be skipped continues to the end of the string,
8  * then 'str' will be left pointing at the final terminating '\0'
9  * character.
10  */
11 static void
12 skip_space_and_comments (const char **str)
13 {
14     const char *s;
15
16     s = *str;
17     while (*s && (isspace (*s) || *s == '(')) {
18         while (*s && isspace (*s))
19             s++;
20         if (*s == '(') {
21             int nesting = 1;
22             s++;
23             while (*s && nesting) {
24                 if (*s == '(') {
25                     nesting++;
26                 } else if (*s == ')') {
27                     nesting--;
28                 } else if (*s == '\\') {
29                     if (*(s+1))
30                         s++;
31                 }
32                 s++;
33             }
34         }
35     }
36
37     *str = s;
38 }
39
40 char *
41 _notmuch_message_id_parse (void *ctx, const char *message_id, const char **next)
42 {
43     const char *s, *end;
44     char *result;
45
46     if (message_id == NULL || *message_id == '\0')
47         return NULL;
48
49     s = message_id;
50
51     skip_space_and_comments (&s);
52
53     /* Skip any unstructured text as well. */
54     while (*s && *s != '<')
55         s++;
56
57     if (*s == '<') {
58         s++;
59     } else {
60         if (next)
61             *next = s;
62         return NULL;
63     }
64
65     skip_space_and_comments (&s);
66
67     end = s;
68     while (*end && *end != '>')
69         end++;
70     if (next) {
71         if (*end)
72             *next = end + 1;
73         else
74             *next = end;
75     }
76
77     if (end > s && *end == '>')
78         end--;
79     if (end <= s)
80         return NULL;
81
82     result = talloc_strndup (ctx, s, end - s + 1);
83
84     /* Finally, collapse any whitespace that is within the message-id
85      * itself. */
86     {
87         char *r;
88         int len;
89
90         for (r = result, len = strlen (r); *r; r++, len--)
91             if (*r == ' ' || *r == '\t')
92                 memmove (r, r+1, len);
93     }
94
95     return result;
96 }