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