* mailbox/parse822.c, include/mailutils/parse822.h: now can
quote the local-part of and addr-spec, and a string.
Showing
2 changed files
with
91 additions
and
10 deletions
... | @@ -37,9 +37,8 @@ extern "C" { | ... | @@ -37,9 +37,8 @@ extern "C" { |
37 | #endif | 37 | #endif |
38 | 38 | ||
39 | /** | 39 | /** |
40 | * Reads an RFC822 defined lexical token from an input. If some of | 40 | * Reads an RFC822 defined lexical token from an input. All names are |
41 | * the names seem strange, they are taken from the names as defined | 41 | * as close as possible to those used in the extended BNF of the RFC. |
42 | * in the extended BNF of the RFC. | ||
43 | */ | 42 | */ |
44 | 43 | ||
45 | /* From RFC 822, 3.3 Lexical Tokens */ | 44 | /* From RFC 822, 3.3 Lexical Tokens */ |
... | @@ -69,6 +68,7 @@ extern int parse822_word __P ((const char** p, const char* e, char** w | ... | @@ -69,6 +68,7 @@ extern int parse822_word __P ((const char** p, const char* e, char** w |
69 | extern int parse822_phrase __P ((const char** p, const char* e, char** phrase)); | 68 | extern int parse822_phrase __P ((const char** p, const char* e, char** phrase)); |
70 | extern int parse822_d_text __P ((const char** p, const char* e, char** dtext)); | 69 | extern int parse822_d_text __P ((const char** p, const char* e, char** dtext)); |
71 | 70 | ||
71 | |||
72 | /* From RFC 822, 6.1 Address Specification Syntax */ | 72 | /* From RFC 822, 6.1 Address Specification Syntax */ |
73 | 73 | ||
74 | extern int parse822_address_list __P ((address_t* a, const char* s)); | 74 | extern int parse822_address_list __P ((address_t* a, const char* s)); |
... | @@ -84,6 +84,16 @@ extern int parse822_sub_domain __P ((const char** p, const char* e, char** s | ... | @@ -84,6 +84,16 @@ extern int parse822_sub_domain __P ((const char** p, const char* e, char** s |
84 | extern int parse822_domain_ref __P ((const char** p, const char* e, char** domain_ref)); | 84 | extern int parse822_domain_ref __P ((const char** p, const char* e, char** domain_ref)); |
85 | extern int parse822_domain_literal __P ((const char** p, const char* e, char** domain_literal)); | 85 | extern int parse822_domain_literal __P ((const char** p, const char* e, char** domain_literal)); |
86 | 86 | ||
87 | /* RFC 822 Quoting Functions | ||
88 | * Various elements must be quoted if then contain non-safe characters. What | ||
89 | * characters are allowed depend on the element. The following functions will | ||
90 | * allocate a quoted version of the raw element, it may not actually be | ||
91 | * quoted if no unsafe characters were in the raw string. | ||
92 | */ | ||
93 | |||
94 | extern int parse822_quote_string __P ((char** quoted, const char* raw)); | ||
95 | extern int parse822_quote_local_part __P ((char** quoted, const char* raw)); | ||
96 | |||
87 | #ifdef __cplusplus | 97 | #ifdef __cplusplus |
88 | } | 98 | } |
89 | #endif | 99 | #endif | ... | ... |
... | @@ -198,12 +198,7 @@ int parse822_is_smtp_q(char c) | ... | @@ -198,12 +198,7 @@ int parse822_is_smtp_q(char c) |
198 | && c != '\n'; | 198 | && c != '\n'; |
199 | } | 199 | } |
200 | 200 | ||
201 | /* | 201 | /***** From RFC 822, 3.3 Lexical Tokens *****/ |
202 | * Lexical Analysis - these tokens are all from RFC822, | ||
203 | * section 3.3, Lexical Tokens, though not all tokens are | ||
204 | * implemented. The names match those used int the extended | ||
205 | * BNF of the RFC where possible. | ||
206 | */ | ||
207 | 202 | ||
208 | int parse822_skip_ws(const char** p, const char* e) | 203 | int parse822_skip_ws(const char** p, const char* e) |
209 | { | 204 | { |
... | @@ -483,6 +478,8 @@ int parse822_phrase(const char** p, const char* e, char** phrase) | ... | @@ -483,6 +478,8 @@ int parse822_phrase(const char** p, const char* e, char** phrase) |
483 | return rc; | 478 | return rc; |
484 | } | 479 | } |
485 | 480 | ||
481 | /***** From RFC 822, 6.1 Address Specification Syntax *****/ | ||
482 | |||
486 | static address_t new_mb(void) { | 483 | static address_t new_mb(void) { |
487 | return calloc(1, sizeof(struct _address)); | 484 | return calloc(1, sizeof(struct _address)); |
488 | } | 485 | } |
... | @@ -505,7 +502,7 @@ static int fill_mb( | ... | @@ -505,7 +502,7 @@ static int fill_mb( |
505 | /* this is wrong, local must be quoted */ | 502 | /* this is wrong, local must be quoted */ |
506 | do { | 503 | do { |
507 | /* loop exists only to break out of */ | 504 | /* loop exists only to break out of */ |
508 | if((rc = str_append(&(*a)->email, local))) | 505 | if((rc = parse822_quote_local_part(&(*a)->email, local))) |
509 | break; | 506 | break; |
510 | if((rc = str_append(&(*a)->email, "@"))) | 507 | if((rc = str_append(&(*a)->email, "@"))) |
511 | break; | 508 | break; |
... | @@ -1032,6 +1029,9 @@ int parse822_domain_literal(const char** p, const char* e, char** domain_literal | ... | @@ -1032,6 +1029,9 @@ int parse822_domain_literal(const char** p, const char* e, char** domain_literal |
1032 | } | 1029 | } |
1033 | 1030 | ||
1034 | #if 0 | 1031 | #if 0 |
1032 | |||
1033 | /***** From RFC 822, 3.2 Header Field Definitions *****/ | ||
1034 | |||
1035 | int parse822_field_name(const char** p, const char* e, char** fieldname) | 1035 | int parse822_field_name(const char** p, const char* e, char** fieldname) |
1036 | { | 1036 | { |
1037 | /* field-name = 1*<any char, excluding ctlS, space, and ":"> ":" */ | 1037 | /* field-name = 1*<any char, excluding ctlS, space, and ":"> ":" */ |
... | @@ -1114,3 +1114,74 @@ int parse822_field_body(const char** p, const char* e, Rope& fieldbody) | ... | @@ -1114,3 +1114,74 @@ int parse822_field_body(const char** p, const char* e, Rope& fieldbody) |
1114 | } | 1114 | } |
1115 | #endif | 1115 | #endif |
1116 | 1116 | ||
1117 | /***** RFC 822 Quoting Functions *****/ | ||
1118 | |||
1119 | int parse822_quote_string(char** quoted, const char* raw) | ||
1120 | { | ||
1121 | /* quoted-string = <"> *(qtext/quoted-pair) <"> | ||
1122 | * | ||
1123 | * So double quote the string, and back quote anything that | ||
1124 | * isn't qtext. | ||
1125 | */ | ||
1126 | |||
1127 | int rc = EOK; | ||
1128 | const char* s; | ||
1129 | |||
1130 | if(!raw || !quoted || *quoted) { | ||
1131 | return EINVAL; | ||
1132 | } | ||
1133 | |||
1134 | s = raw; | ||
1135 | |||
1136 | rc = str_append_char(quoted, '"'); | ||
1137 | |||
1138 | while(!rc && *s) { | ||
1139 | if(!parse822_is_q_text(*s)) { | ||
1140 | rc = str_append_char(quoted, '\\'); | ||
1141 | } | ||
1142 | |||
1143 | if(!rc) { | ||
1144 | rc = str_append_char(quoted, *s); | ||
1145 | } | ||
1146 | ++s; | ||
1147 | } | ||
1148 | |||
1149 | if(!rc) { | ||
1150 | rc = str_append_char(quoted, '"'); | ||
1151 | } | ||
1152 | |||
1153 | if(rc) { | ||
1154 | str_free(quoted); | ||
1155 | } | ||
1156 | return rc; | ||
1157 | } | ||
1158 | |||
1159 | int parse822_quote_local_part(char** quoted, const char* raw) | ||
1160 | { | ||
1161 | /* local-part = word * ("." word) | ||
1162 | * word = atom / quoted-string | ||
1163 | * | ||
1164 | * So, if any character isn't a "." or an atom character, we quote | ||
1165 | * the whole thing as a string, for simplicity, otherwise just | ||
1166 | * copy it. | ||
1167 | */ | ||
1168 | |||
1169 | const char* s = 0; | ||
1170 | |||
1171 | if(!raw || !quoted || *quoted) { | ||
1172 | return EINVAL; | ||
1173 | } | ||
1174 | s = raw; | ||
1175 | |||
1176 | while(*s) { | ||
1177 | if(*s != '.' && !parse822_is_atom_char(*s)) { | ||
1178 | return parse822_quote_string(quoted, raw); | ||
1179 | } | ||
1180 | ++s; | ||
1181 | } | ||
1182 | |||
1183 | /* if we don't have to quote it, just copy it over */ | ||
1184 | |||
1185 | return str_append(quoted, raw); | ||
1186 | } | ||
1187 | ... | ... |
-
Please register or sign in to post a comment