Postfix3.3.1
quote_822_local.c
[詳解]
1 /*++
2 /* NAME
3 /* quote_822_local 3
4 /* SUMMARY
5 /* quote local part of mailbox
6 /* SYNOPSIS
7 /* #include <quote_822_local.h>
8 /*
9 /* VSTRING *quote_822_local(dst, src)
10 /* VSTRING *dst;
11 /* const char *src;
12 /*
13 /* VSTRING *quote_822_local_flags(dst, src, flags)
14 /* VSTRING *dst;
15 /* const char *src;
16 /* int flags;
17 /*
18 /* VSTRING *unquote_822_local(dst, src)
19 /* VSTRING *dst;
20 /* const char *src;
21 /* DESCRIPTION
22 /* quote_822_local() quotes the local part of a mailbox and
23 /* returns a result that can be used in message headers as
24 /* specified by RFC 822 (actually, an 8-bit clean version of
25 /* RFC 822). It implements an 8-bit clean version of RFC 822.
26 /*
27 /* quote_822_local_flags() provides finer control.
28 /*
29 /* unquote_822_local() transforms the local part of a mailbox
30 /* address to unquoted (internal) form.
31 /*
32 /* Arguments:
33 /* .IP dst
34 /* The result.
35 /* .IP src
36 /* The input address.
37 /* .IP flags
38 /* Bit-wise OR of zero or more of the following.
39 /* .RS
40 /* .IP QUOTE_FLAG_8BITCLEAN
41 /* In violation with RFCs, treat 8-bit text as ordinary text.
42 /* .IP QUOTE_FLAG_EXPOSE_AT
43 /* In violation with RFCs, treat `@' as an ordinary character.
44 /* .IP QUOTE_FLAG_APPEND
45 /* Append to the result buffer, instead of overwriting it.
46 /* .IP QUOTE_FLAG_BARE_LOCALPART
47 /* The input is a localpart without @domain part.
48 /* .RE
49 /* STANDARDS
50 /* RFC 822 (ARPA Internet Text Messages)
51 /* BUGS
52 /* The code assumes that the domain is RFC 822 clean.
53 /* LICENSE
54 /* .ad
55 /* .fi
56 /* The Secure Mailer license must be distributed with this software.
57 /* AUTHOR(S)
58 /* Wietse Venema
59 /* IBM T.J. Watson Research
60 /* P.O. Box 704
61 /* Yorktown Heights, NY 10598, USA
62 /*
63 /* Wietse Venema
64 /* Google, Inc.
65 /* 111 8th Avenue
66 /* New York, NY 10011, USA
67 /*--*/
68 
69 /* System library. */
70 
71 #include <sys_defs.h>
72 #include <string.h>
73 #include <ctype.h>
74 
75 /* Utility library. */
76 
77 #include <vstring.h>
78 
79 /* Global library. */
80 
81 /* Application-specific. */
82 
83 #include "quote_822_local.h"
84 
85 /* Local stuff. */
86 
87 #define YES 1
88 #define NO 0
89 
90 /* is_822_dot_string - is this local-part an rfc 822 dot-string? */
91 
92 static int is_822_dot_string(const char *local_part, const char *end, int flags)
93 {
94  const char *cp;
95  int ch;
96 
97  /*
98  * Detect any deviations from a sequence of atoms separated by dots. We
99  * could use lookup tables to speed up some of the work, but hey, how
100  * large can a local-part be anyway?
101  *
102  * RFC 822 expects 7-bit data. Rather than quoting every 8-bit character
103  * (and still passing it on as 8-bit data) we leave 8-bit data alone.
104  */
105  if (local_part == end || local_part[0] == 0 || local_part[0] == '.')
106  return (NO);
107  for (cp = local_part; cp < end && (ch = *(unsigned char *) cp) != 0; cp++) {
108  if (ch == '.' && (cp + 1) < end && cp[1] == '.')
109  return (NO);
110  if (ch > 127 && !(flags & QUOTE_FLAG_8BITCLEAN))
111  return (NO);
112  if (ch == ' ')
113  return (NO);
114  if (ISCNTRL(ch))
115  return (NO);
116  if (ch == '(' || ch == ')'
117  || ch == '<' || ch == '>'
118  || (ch == '@' && !(flags & QUOTE_FLAG_EXPOSE_AT)) || ch == ','
119  || ch == ';' || ch == ':'
120  || ch == '\\' || ch == '"'
121  || ch == '[' || ch == ']')
122  return (NO);
123  }
124  if (cp[-1] == '.')
125  return (NO);
126  return (YES);
127 }
128 
129 /* make_822_quoted_string - make quoted-string from local-part */
130 
131 static VSTRING *make_822_quoted_string(VSTRING *dst, const char *local_part,
132  const char *end, int flags)
133 {
134  const char *cp;
135  int ch;
136 
137  /*
138  * Put quotes around the result, and prepend a backslash to characters
139  * that need quoting when they occur in a quoted-string.
140  */
141  VSTRING_ADDCH(dst, '"');
142  for (cp = local_part; cp < end && (ch = *(unsigned char *) cp) != 0; cp++) {
143  if ((ch > 127 && !(flags & QUOTE_FLAG_8BITCLEAN))
144  || ch == '"' || ch == '\\' || ch == '\r')
145  VSTRING_ADDCH(dst, '\\');
146  VSTRING_ADDCH(dst, ch);
147  }
148  VSTRING_ADDCH(dst, '"');
149  return (dst);
150 }
151 
152 /* quote_822_local_flags - quote local part of mailbox according to rfc 822 */
153 
154 VSTRING *quote_822_local_flags(VSTRING *dst, const char *mbox, int flags)
155 {
156  const char *start; /* first byte of localpart */
157  const char *end; /* first byte after localpart */
158  const char *colon;
159 
160  /*
161  * According to RFC 822, a local-part is a dot-string or a quoted-string.
162  * We first see if the local-part is a dot-string. If it is not, we turn
163  * it into a quoted-string. Anything else would be too painful. But
164  * first, skip over any source route that precedes the local-part.
165  */
166  if (mbox[0] == '@' && (colon = strchr(mbox, ':')) != 0)
167  start = colon + 1;
168  else
169  start = mbox;
170  if ((flags & QUOTE_FLAG_BARE_LOCALPART) != 0
171  || (end = strrchr(start, '@')) == 0)
172  end = start + strlen(start);
173  if ((flags & QUOTE_FLAG_APPEND) == 0)
174  VSTRING_RESET(dst);
175  if (is_822_dot_string(start, end, flags)) {
176  return (vstring_strcat(dst, mbox));
177  } else {
178  vstring_strncat(dst, mbox, start - mbox);
179  make_822_quoted_string(dst, start, end, flags & QUOTE_FLAG_8BITCLEAN);
180  return (vstring_strcat(dst, end));
181  }
182 }
183 
184 /* unquote_822_local - unquote local part of mailbox according to rfc 822 */
185 
186 VSTRING *unquote_822_local(VSTRING *dst, const char *mbox)
187 {
188  const char *start; /* first byte of localpart */
189  const char *colon;
190  const char *cp;
191  int in_quote = 0;
192  const char *bare_at_src;
193  int bare_at_dst_pos = -1;
194 
195  /* Don't unquote a routing prefix. Is this still possible? */
196  if (mbox[0] == '@' && (colon = strchr(mbox, ':')) != 0) {
197  start = colon + 1;
198  vstring_strncpy(dst, mbox, start - mbox);
199  } else {
200  start = mbox;
201  VSTRING_RESET(dst);
202  }
203  /* Locate the last unquoted '@'. */
204  for (cp = start; *cp; cp++) {
205  if (*cp == '"') {
206  in_quote = !in_quote;
207  continue;
208  } else if (*cp == '@') {
209  if (!in_quote) {
210  bare_at_dst_pos = VSTRING_LEN(dst);
211  bare_at_src = cp;
212  }
213  } else if (*cp == '\\') {
214  if (cp[1] == 0)
215  continue;
216  cp++;
217  }
218  VSTRING_ADDCH(dst, *cp);
219  }
220  /* Don't unquote text after the last unquoted '@'. */
221  if (bare_at_dst_pos >= 0) {
222  vstring_truncate(dst, bare_at_dst_pos);
223  vstring_strcat(dst, bare_at_src);
224  } else
225  VSTRING_TERMINATE(dst);
226  return (dst);
227 }
228 
229 #ifdef TEST
230 
231  /*
232  * Proof-of-concept test program. Read an unquoted address from stdin, and
233  * show the quoted and unquoted results.
234  */
235 #include <ctype.h>
236 #include <string.h>
237 
238 #include <msg.h>
239 #include <name_mask.h>
240 #include <stringops.h>
241 #include <vstream.h>
242 #include <vstring_vstream.h>
243 
244 #define STR vstring_str
245 
246 int main(int unused_argc, char **argv)
247 {
248  VSTRING *in = vstring_alloc(100);
249  VSTRING *out = vstring_alloc(100);
250  char *cmd;
251  char *bp;
252  int flags;
253 
254  while (vstring_fgets_nonl(in, VSTREAM_IN)) {
255  bp = STR(in);
256  if ((cmd = mystrtok(&bp, CHARS_SPACE)) != 0) {
257  while (ISSPACE(*bp))
258  bp++;
259  if (*bp == 0) {
260  msg_warn("missing argument");
261  } else if (strcmp(cmd, "quote") == 0) {
262  quote_822_local(out, bp);
263  vstream_printf("'%s' quoted '%s'\n", bp, STR(out));
264  } else if (strcmp(cmd, "quote_with_flags") == 0) {
265  if ((cmd = mystrtok(&bp, CHARS_SPACE)) == 0) {
266  msg_warn("missing flags");
267  continue;
268  }
269  while (ISSPACE(*bp))
270  bp++;
271  flags = quote_flags_from_string(cmd);
272  quote_822_local_flags(out, bp, flags);
273  vstream_printf("'%s' quoted flags=%s '%s'\n",
274  bp, quote_flags_to_string((VSTRING *) 0, flags), STR(out));
275  } else if (strcmp(cmd, "unquote") == 0) {
276  unquote_822_local(out, bp);
277  vstream_printf("'%s' unquoted '%s'\n", bp, STR(out));
278  } else {
279  msg_warn("unknown command: %s", cmd);
280  }
282  }
283  }
284  vstring_free(in);
285  vstring_free(out);
286  return (0);
287 }
288 
289 #endif
#define QUOTE_FLAG_8BITCLEAN
Definition: quote_flags.h:19
#define vstring_fgets_nonl(s, p)
const char * quote_flags_to_string(VSTRING *res_buf, int quote_flags_mask)
Definition: quote_flags.c:80
#define VSTREAM_OUT
Definition: vstream.h:67
int main(int argc, char **argv)
Definition: anvil.c:1010
VSTRING * vstring_strncat(VSTRING *vp, const char *src, ssize_t len)
Definition: vstring.c:471
VSTRING * unquote_822_local(VSTRING *dst, const char *mbox)
VSTRING * vstring_truncate(VSTRING *vp, ssize_t len)
Definition: vstring.c:415
#define VSTREAM_IN
Definition: vstream.h:66
char * mystrtok(char **src, const char *sep)
Definition: mystrtok.c:54
#define VSTRING_LEN(vp)
Definition: vstring.h:72
#define QUOTE_FLAG_EXPOSE_AT
Definition: quote_flags.h:20
#define VSTRING_TERMINATE(vp)
Definition: vstring.h:74
VSTRING * quote_822_local_flags(VSTRING *dst, const char *mbox, int flags)
#define VSTRING_ADDCH(vp, ch)
Definition: vstring.h:81
#define QUOTE_FLAG_BARE_LOCALPART
Definition: quote_flags.h:22
VSTREAM * vstream_printf(const char *fmt,...)
Definition: vstream.c:1335
#define VSTRING_RESET(vp)
Definition: vstring.h:77
#define STR(x)
Definition: anvil.c:518
void msg_warn(const char *fmt,...)
Definition: msg.c:215
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
#define CHARS_SPACE
Definition: sys_defs.h:1762
int quote_flags_from_string(const char *quote_flags_string)
Definition: quote_flags.c:71
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
#define ISCNTRL(c)
Definition: sys_defs.h:1747
#define quote_822_local(dst, src)
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
#define ISSPACE(c)
Definition: sys_defs.h:1753
#define YES
VSTRING * vstring_strncpy(VSTRING *vp, const char *src, ssize_t len)
Definition: vstring.c:445
#define QUOTE_FLAG_APPEND
Definition: quote_flags.h:21
#define NO
VSTRING * vstring_strcat(VSTRING *vp, const char *src)
Definition: vstring.c:459