Copied atexit() code from fakesmtp.c to fakepop.c so that its
[mmh] / sbr / escape_addresses.c
1 /*
2  * escape_addresses.c -- Escape address components, hopefully per RFC 5322.
3  *
4  * This code is Copyright (c) 2012, by the authors of nmh.  See the
5  * COPYRIGHT file in the root directory of the nmh distribution for
6  * complete copyright information.
7  */
8
9 #include <sys/types.h>
10 #include <h/utils.h>
11 #include <string.h>
12 #include <stdlib.h>
13
14 static void
15 escape_component (char *name, size_t namesize, char *chars);
16
17
18 void
19 escape_display_name (char *name, size_t namesize) {
20   char *specials = "\"(),.:;<>@[\\]";
21   escape_component (name, namesize, specials);
22 }
23
24
25 void
26 escape_local_part (char *name, size_t namesize) {
27   /* wsp (whitespace) is horizontal tab or space, according to
28      RFC 5234. */
29   char *specials_less_dot_plus_wsp = "   \"(),:;<>@[\\]";
30   escape_component (name, namesize, specials_less_dot_plus_wsp);
31 }
32
33
34 /* Escape an address component, hopefully per RFC 5322.  Assumes
35    one-byte characters.  The char array pointed to by the name
36    argument is modified in place.  Its size is specified by the
37    namesize argument.  The need_escape argument is a string of
38    characters that require that name be escaped. */
39 void
40 escape_component (char *name, size_t namesize, char *chars_to_escape) {
41     /* If name contains any chars_to_escape:
42        1) enclose it in ""
43        2) escape any embedded "
44      */
45     if (strpbrk(name, chars_to_escape)) {
46         char *destp, *srcp;
47         /* Maximum space requirement would be if each character had
48            to be escaped, plus enclosing double quotes, plus null termintor.
49            E.g., 2 characters, "", would require 7, "\"\""0, where that 0
50            is '\0'. */
51         char *tmp = mh_xmalloc (2*strlen(name) + 3);
52
53         for (destp = tmp, srcp = name; *srcp; ++srcp) {
54             if (srcp == name) {
55                 /* Insert initial double quote, if needed. */
56                 if (*srcp != '"') {
57                     *destp++ = '"';
58                 }
59             } else {
60                 /* Escape embedded, unescaped double quote. */
61                 if (*srcp == '"' && *(srcp+1) != '\0' && *(srcp-1) != '\\') {
62                     *destp++ = '\\';
63                 }
64             }
65
66             *destp++ = *srcp;
67
68             /* End of name. */
69             if (*(srcp+1) == '\0') {
70                 /* Insert final double quote, if needed. */
71                 if (*srcp != '"') {
72                     *destp++ = '"';
73                 }
74
75                 *destp++ = '\0';
76             }
77         }
78
79         if (strcmp (tmp, "\"")) {
80             /* assert (strlen(tmp) + 1 == destp - tmp); */
81             size_t len = destp - tmp;
82             strncpy (name, tmp, len <= namesize  ?  len  :  namesize);
83         } else {
84             /* Handle just " as special case here instead of above. */
85             strncpy (name, "\"\\\"\"", namesize);
86         }
87
88         name[namesize - 1] = '\0';
89
90         free (tmp);
91     }
92 }