diff options
| author | David Bremner <david@tethera.net> | 2017-06-04 09:32:26 -0300 |
|---|---|---|
| committer | David Bremner <david@tethera.net> | 2017-08-01 21:17:47 -0400 |
| commit | 2f94b3090c03bb56b43c4adfb94f7eeb28a6bf18 (patch) | |
| tree | 25b72267996881e28efaa2bf064e1463ae39ba2d /lib/message-id.c | |
| parent | 95b52e85b2deae449b71794b0d74e6c677516e12 (diff) | |
lib: factor out message-id parsing to separate file.
This is really pure C string parsing, and doesn't need to be mixed in
with the Xapian/C++ layer. Although not strictly necessary, it also
makes it a bit more natural to call _parse_message_id from multiple
compilation units.
Diffstat (limited to 'lib/message-id.c')
| -rw-r--r-- | lib/message-id.c | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/lib/message-id.c b/lib/message-id.c new file mode 100644 index 00000000..d7541d50 --- /dev/null +++ b/lib/message-id.c @@ -0,0 +1,96 @@ +#include "notmuch-private.h" + +/* Advance 'str' past any whitespace or RFC 822 comments. A comment is + * a (potentially nested) parenthesized sequence with '\' used to + * escape any character (including parentheses). + * + * If the sequence to be skipped continues to the end of the string, + * then 'str' will be left pointing at the final terminating '\0' + * character. + */ +static void +skip_space_and_comments (const char **str) +{ + const char *s; + + s = *str; + while (*s && (isspace (*s) || *s == '(')) { + while (*s && isspace (*s)) + s++; + if (*s == '(') { + int nesting = 1; + s++; + while (*s && nesting) { + if (*s == '(') { + nesting++; + } else if (*s == ')') { + nesting--; + } else if (*s == '\\') { + if (*(s+1)) + s++; + } + s++; + } + } + } + + *str = s; +} + +char * +_notmuch_message_id_parse (void *ctx, const char *message_id, const char **next) +{ + const char *s, *end; + char *result; + + if (message_id == NULL || *message_id == '\0') + return NULL; + + s = message_id; + + skip_space_and_comments (&s); + + /* Skip any unstructured text as well. */ + while (*s && *s != '<') + s++; + + if (*s == '<') { + s++; + } else { + if (next) + *next = s; + return NULL; + } + + skip_space_and_comments (&s); + + end = s; + while (*end && *end != '>') + end++; + if (next) { + if (*end) + *next = end + 1; + else + *next = end; + } + + if (end > s && *end == '>') + end--; + if (end <= s) + return NULL; + + result = talloc_strndup (ctx, s, end - s + 1); + + /* Finally, collapse any whitespace that is within the message-id + * itself. */ + { + char *r; + int len; + + for (r = result, len = strlen (r); *r; r++, len--) + if (*r == ' ' || *r == '\t') + memmove (r, r+1, len); + } + + return result; +} |
