Updates from Sam Roberts.
Showing
3 changed files
with
350 additions
and
68 deletions
... | @@ -33,28 +33,54 @@ | ... | @@ -33,28 +33,54 @@ |
33 | 33 | ||
34 | /* Get email address from rfc822 address. */ | 34 | /* Get email address from rfc822 address. */ |
35 | int | 35 | int |
36 | address_create (address_t *a, const char *p) | 36 | address_create (address_t *a, const char *s) |
37 | { | 37 | { |
38 | /* 'paddress' must exist, and can't already have been initialized | 38 | /* 'paddress' must exist, and can't already have been initialized |
39 | */ | 39 | */ |
40 | int status; | 40 | int status; |
41 | char *s; /* FIXME: Remove when done, see below */ | 41 | const char *e; |
42 | const char *save; | ||
43 | char *fb; | ||
42 | 44 | ||
43 | if (!a) | 45 | if (!a) |
44 | return EINVAL; | 46 | return EINVAL; |
45 | 47 | ||
46 | *a = NULL; | 48 | *a = NULL; |
49 | save = s; | ||
50 | e = &s[strlen (s)]; | ||
51 | fb = calloc (1, 1); | ||
47 | 52 | ||
48 | /* FIXME: parse822 does not seem to like '\n' in the field body | 53 | /* We need to unfold the string. Do the same thing as parse822_field_body() |
49 | take care of it here until the proper fix. */ | 54 | but we have to be more flexible in allowing bare '\n' as CRLF. */ |
50 | s = strdup (p); | 55 | for (;;) |
51 | { | 56 | { |
52 | char *nl = s; | 57 | const char *eol = s; |
53 | while ((nl = strchr (nl, '\n'))) | 58 | size_t len = strlen (fb); |
54 | *nl++ = ' '; | 59 | while (eol != e) |
60 | { | ||
61 | /* if (eol[0] == '\r' && (eol+1) != e && eol[1] == '\n') */ | ||
62 | if (*eol == '\n') | ||
63 | break; | ||
64 | ++eol; | ||
65 | } | ||
66 | |||
67 | fb = realloc (fb, len + (eol - s) + 1); | ||
68 | memcpy (fb + len , s, eol - s); | ||
69 | fb[len + (eol - s)] = '\0'; | ||
70 | |||
71 | s = eol; | ||
72 | s += 2; | ||
73 | |||
74 | if (s == e) | ||
75 | break; /* no more, so we're done */ | ||
76 | |||
77 | /* check if next line is a continuation line */ | ||
78 | if (*s != ' ' && *s != '\t') | ||
79 | break; | ||
55 | } | 80 | } |
56 | 81 | ||
57 | status = parse822_address_list (a, (char*) s); | 82 | status = parse822_address_list (a, (char*) fb); |
83 | free (fb); | ||
58 | if (status == 0) | 84 | if (status == 0) |
59 | { | 85 | { |
60 | /* And address-list may contain 0 addresses but parse correctly. | 86 | /* And address-list may contain 0 addresses but parse correctly. |
... | @@ -62,15 +88,13 @@ address_create (address_t *a, const char *p) | ... | @@ -62,15 +88,13 @@ address_create (address_t *a, const char *p) |
62 | if (!*a) | 88 | if (!*a) |
63 | return ENOENT; | 89 | return ENOENT; |
64 | 90 | ||
65 | (*a)->addr = strdup (s); | 91 | (*a)->addr = strdup (save); |
66 | if (!(*a)->addr) | 92 | if (!(*a)->addr) |
67 | { | 93 | { |
68 | address_destroy (a); | 94 | address_destroy (a); |
69 | return ENOMEM; | 95 | return ENOMEM; |
70 | } | 96 | } |
71 | } | 97 | } |
72 | /* FIXME: part of the hack/fix above remove when done. */ | ||
73 | free (s); | ||
74 | return status; | 98 | return status; |
75 | } | 99 | } |
76 | 100 | ... | ... |
... | @@ -23,6 +23,8 @@ | ... | @@ -23,6 +23,8 @@ |
23 | #include <stdlib.h> | 23 | #include <stdlib.h> |
24 | #include <errno.h> | 24 | #include <errno.h> |
25 | #include <stdio.h> | 25 | #include <stdio.h> |
26 | #include <pwd.h> | ||
27 | #include <unistd.h> | ||
26 | 28 | ||
27 | #ifdef HAVE_PATHS_H | 29 | #ifdef HAVE_PATHS_H |
28 | # include <paths.h> | 30 | # include <paths.h> |
... | @@ -35,52 +37,268 @@ | ... | @@ -35,52 +37,268 @@ |
35 | # define _PATH_MAILDIR "/usr/spool/mail" | 37 | # define _PATH_MAILDIR "/usr/spool/mail" |
36 | #endif | 38 | #endif |
37 | 39 | ||
38 | int | 40 | /* Is this a security risk? */ |
39 | mailbox_create_default (mailbox_t *pmbox, const char *mail) | 41 | #define USE_ENVIRON 1 |
42 | |||
43 | static char * tilde_expansion __P ((const char *)); | ||
44 | static char * plus_equal_expansion __P ((const char *)); | ||
45 | static char * get_cwd __P ((void)); | ||
46 | static char * get_full_path __P ((const char *)); | ||
47 | static const char * get_homedir __P ((const char *)); | ||
48 | |||
49 | /* Do + and = expansion to ~/Mail, if necessary. */ | ||
50 | static char * | ||
51 | plus_equal_expansion (const char *file) | ||
40 | { | 52 | { |
41 | const char *user = NULL; | 53 | char *p = NULL; |
54 | if (file && (*file == '+' || *file == '=')) | ||
55 | { | ||
56 | char *folder; | ||
57 | /* Skip '+' or '='. */ | ||
58 | file++; | ||
59 | folder = tilde_expansion ("~/Mail"); | ||
60 | if (folder) | ||
61 | { | ||
62 | p = malloc (strlen (folder) + 1 + strlen (file) + 1); | ||
63 | if (p) | ||
64 | sprintf(p, "%s/%s", folder, file); | ||
65 | free (folder); | ||
66 | } | ||
67 | } | ||
42 | 68 | ||
43 | if (pmbox == NULL) | 69 | if (!p) |
44 | return EINVAL; | 70 | p = strdup (file); |
71 | return p; | ||
72 | } | ||
45 | 73 | ||
46 | if (mail == NULL) | 74 | static const char * |
47 | mail = getenv ("MAIL"); | 75 | get_homedir (const char *user) |
76 | { | ||
77 | const char *homedir = NULL; | ||
78 | struct passwd *pw = NULL; | ||
79 | if (user) | ||
80 | { | ||
81 | pw = getpwnam (user); | ||
82 | if (pw) | ||
83 | homedir = pw->pw_dir; | ||
84 | } | ||
85 | else | ||
86 | { | ||
87 | #ifdef USE_ENVIRON | ||
88 | /* NOTE: Should we honor ${HOME}? */ | ||
89 | homedir = getenv ("HOME"); | ||
90 | if (homedir == NULL) | ||
91 | { | ||
92 | pw = getpwuid (getuid ()); | ||
93 | if (pw) | ||
94 | homedir = pw->pw_dir; | ||
95 | } | ||
96 | #else | ||
97 | pw = getpwuid (getuid ()); | ||
98 | if (pw) | ||
99 | homedir = pw->pw_dir; | ||
100 | #endif | ||
101 | } | ||
102 | return homedir; | ||
103 | } | ||
48 | 104 | ||
49 | if (mail) | 105 | /* Do ~ , if necessary. We do not use $HOME. */ |
106 | static char * | ||
107 | tilde_expansion (const char *file) | ||
108 | { | ||
109 | char *p = NULL; | ||
110 | const char *homedir = NULL; | ||
111 | const char delim = '/'; /* Not portable. */ | ||
112 | |||
113 | if (file && *file == '~') | ||
114 | { | ||
115 | /* Skip the tilde. */ | ||
116 | file++; | ||
117 | |||
118 | /* This means we have ~ or ~/something. */ | ||
119 | if (*file == delim || *file == '\0') | ||
50 | { | 120 | { |
51 | /* Is it a fullpath ? */ | 121 | homedir = get_homedir (NULL); |
52 | if (mail[0] != '/') | 122 | if (homedir) |
53 | { | 123 | { |
54 | /* Is it a URL ? */ | 124 | p = calloc (strlen (homedir) + strlen (file) + 1, 1); |
55 | if (strchr (mail, ':') == NULL) | 125 | if (p) |
56 | { | 126 | { |
57 | /* A user name. */ | 127 | strcpy (p, homedir); |
58 | user = mail; | 128 | strcat (p, file); |
59 | mail = NULL; | ||
60 | } | 129 | } |
61 | } | 130 | } |
62 | } | 131 | } |
132 | /* Means we have ~user or ~user/something. */ | ||
133 | else | ||
134 | { | ||
135 | const char *s = file; | ||
63 | 136 | ||
64 | if (mail == NULL) | 137 | /* Move to the first delim. */ |
138 | while (*s && *s != delim) s++; | ||
139 | |||
140 | /* Get the username homedir. */ | ||
141 | { | ||
142 | char *name; | ||
143 | name = calloc (s - file + 1, 1); | ||
144 | if (name) | ||
145 | { | ||
146 | memcpy (name, file, s - file); | ||
147 | name [s - file] = '\0'; | ||
148 | } | ||
149 | homedir = get_homedir (name); | ||
150 | free (name); | ||
151 | } | ||
152 | |||
153 | if (homedir) | ||
154 | { | ||
155 | p = calloc (strlen (homedir) + strlen (s) + 1, 1); | ||
156 | if (p) | ||
157 | { | ||
158 | strcpy (p, homedir); | ||
159 | strcat (p, s); | ||
160 | } | ||
161 | } | ||
162 | } | ||
163 | } | ||
164 | |||
165 | if (!p) | ||
166 | p = strdup (file); | ||
167 | return p; | ||
168 | } | ||
169 | |||
170 | static char * | ||
171 | get_cwd () | ||
172 | { | ||
173 | char *ret; | ||
174 | unsigned path_max; | ||
175 | char buf[128]; | ||
176 | |||
177 | errno = 0; | ||
178 | ret = getcwd (buf, sizeof (buf)); | ||
179 | if (ret != NULL) | ||
180 | return strdup (buf); | ||
181 | |||
182 | if (errno != ERANGE) | ||
183 | return NULL; | ||
184 | |||
185 | path_max = 128; | ||
186 | path_max += 2; /* The getcwd docs say to do this. */ | ||
187 | |||
188 | for (;;) | ||
189 | { | ||
190 | char *cwd = (char *) malloc (path_max); | ||
191 | |||
192 | errno = 0; | ||
193 | ret = getcwd (cwd, path_max); | ||
194 | if (ret != NULL) | ||
195 | return ret; | ||
196 | if (errno != ERANGE) | ||
65 | { | 197 | { |
198 | int save_errno = errno; | ||
199 | free (cwd); | ||
200 | errno = save_errno; | ||
201 | return NULL; | ||
202 | } | ||
203 | |||
204 | free (cwd); | ||
205 | |||
206 | path_max += path_max / 16; | ||
207 | path_max += 32; | ||
208 | } | ||
209 | /* oops? */ | ||
210 | return NULL; | ||
211 | } | ||
212 | |||
213 | static char * | ||
214 | get_full_path (const char *file) | ||
215 | { | ||
216 | char *p = NULL; | ||
217 | |||
218 | if (!file) | ||
219 | p = get_cwd (); | ||
220 | else if (*file != '/') | ||
221 | { | ||
222 | char *cwd = get_cwd (); | ||
223 | if (cwd) | ||
224 | { | ||
225 | p = calloc (strlen (cwd) + 1 + strlen (file) + 1, 1); | ||
226 | if (p) | ||
227 | sprintf (p, "%s/%s", cwd, file); | ||
228 | free (cwd); | ||
229 | } | ||
230 | } | ||
231 | |||
232 | if (!p) | ||
233 | p = strdup (file); | ||
234 | return p; | ||
235 | } | ||
236 | |||
237 | /* We are trying to be smart about the location of the mail. | ||
238 | mailbox_create() is not doing this. | ||
239 | ~/file --> /home/user/file | ||
240 | ~user/file --> /home/user/file | ||
241 | +file --> /home/user/Mail/file | ||
242 | =file --> /home/user/Mail/file | ||
243 | */ | ||
244 | int | ||
245 | mailbox_create_default (mailbox_t *pmbox, const char *mail) | ||
246 | { | ||
247 | char *mbox = NULL; | ||
66 | int status; | 248 | int status; |
249 | |||
250 | /* Sanity. */ | ||
251 | if (pmbox == NULL) | ||
252 | return EINVAL; | ||
253 | |||
254 | /* Other utilities may not understand GNU mailutils url namespace, so | ||
255 | use FOLDER instead, to not confuse others by using MAIL. */ | ||
256 | if (mail == NULL) | ||
257 | mail = getenv ("FOLDER"); | ||
258 | |||
259 | /* Fallback to wellknown environment. */ | ||
260 | if (mail == NULL) | ||
261 | mail = getenv ("MAIL"); | ||
262 | |||
263 | /* FIXME: This is weak, it would be better to check | ||
264 | for all the known schemes to detect presence of URLs. */ | ||
265 | if (mail && *mail && strchr (mail, ':') == NULL) | ||
266 | { | ||
67 | char *mail0; | 267 | char *mail0; |
68 | if (user == NULL) | 268 | char *mail2; |
269 | |||
270 | mail0 = tilde_expansion (mail); | ||
271 | mail2 = plus_equal_expansion (mail0); | ||
272 | free (mail0); | ||
273 | mbox = get_full_path (mail2); | ||
274 | free (mail2); | ||
275 | } | ||
276 | |||
277 | /* Search the spooldir. */ | ||
278 | if (mbox == NULL) | ||
69 | { | 279 | { |
280 | const char *user = NULL; | ||
281 | #ifdef USE_ENVIRON | ||
70 | user = (getenv ("LOGNAME")) ? getenv ("LOGNAME") : getenv ("USER"); | 282 | user = (getenv ("LOGNAME")) ? getenv ("LOGNAME") : getenv ("USER"); |
283 | #endif | ||
71 | if (user == NULL) | 284 | if (user == NULL) |
72 | { | 285 | { |
286 | struct passwd *pw; | ||
287 | pw = getpwuid (getuid ()); | ||
288 | if (pw) | ||
289 | user = pw->pw_name; | ||
290 | else | ||
291 | { | ||
73 | mu_error ("Who am I ?\n"); | 292 | mu_error ("Who am I ?\n"); |
74 | return EINVAL; | 293 | return EINVAL; |
75 | } | 294 | } |
76 | } | 295 | } |
77 | mail0 = malloc (strlen (user) + strlen (_PATH_MAILDIR) + 2); | 296 | mbox = malloc (strlen (user) + strlen (_PATH_MAILDIR) + 2); |
78 | if (mail0 == NULL) | 297 | if (mbox == NULL) |
79 | return ENOMEM; | 298 | return ENOMEM; |
80 | sprintf (mail0, "%s/%s", _PATH_MAILDIR, user); | 299 | sprintf (mbox, "%s/%s", _PATH_MAILDIR, user); |
81 | status = mailbox_create (pmbox, mail0); | ||
82 | free (mail0); | ||
83 | return status; | ||
84 | } | 300 | } |
85 | return mailbox_create (pmbox, mail); | 301 | status = mailbox_create (pmbox, mbox); |
302 | free (mbox); | ||
303 | return status; | ||
86 | } | 304 | } | ... | ... |
... | @@ -211,12 +211,53 @@ int parse822_is_smtp_q(char c) | ... | @@ -211,12 +211,53 @@ int parse822_is_smtp_q(char c) |
211 | 211 | ||
212 | /***** From RFC 822, 3.3 Lexical Tokens *****/ | 212 | /***** From RFC 822, 3.3 Lexical Tokens *****/ |
213 | 213 | ||
214 | int parse822_skip_ws(const char** p, const char* e) | 214 | int parse822_skip_crlf(const char** p, const char* e) |
215 | { | 215 | { |
216 | while((*p != e) && parse822_is_lwsp_char(**p)) { | 216 | const char* s = *p; |
217 | *p += 1; | 217 | if( |
218 | (&s[1] < e) && | ||
219 | s[0] == '\r' && | ||
220 | s[1] == '\n' | ||
221 | ) | ||
222 | { | ||
223 | *p += 2; | ||
224 | |||
225 | return EOK; | ||
218 | } | 226 | } |
227 | return EPARSE; | ||
228 | } | ||
229 | int parse822_skip_lwsp_char(const char** p, const char* e) | ||
230 | { | ||
231 | if(*p < e && parse822_is_lwsp_char(**p)) { | ||
232 | *p += 1; | ||
219 | return EOK; | 233 | return EOK; |
234 | } | ||
235 | return EPARSE; | ||
236 | } | ||
237 | int parse822_skip_lwsp(const char** p, const char* e) | ||
238 | { | ||
239 | /* | ||
240 | * linear-white-space = 1*([CRLF] LWSP-char) | ||
241 | */ | ||
242 | int space = 0; | ||
243 | |||
244 | while(*p != e) { | ||
245 | const char* save = *p; | ||
246 | |||
247 | if(parse822_skip_lwsp_char(p, e) == EOK) { | ||
248 | space = 1; | ||
249 | continue; | ||
250 | } | ||
251 | if(parse822_skip_crlf(p, e) == EOK) { | ||
252 | if(parse822_skip_lwsp_char(p, e) == EOK) { | ||
253 | continue; | ||
254 | } | ||
255 | *p = save; | ||
256 | return EPARSE; | ||
257 | } | ||
258 | break; | ||
259 | } | ||
260 | return space ? EOK : EPARSE; | ||
220 | } | 261 | } |
221 | 262 | ||
222 | int parse822_skip_comments(const char** p, const char* e) | 263 | int parse822_skip_comments(const char** p, const char* e) |
... | @@ -258,7 +299,7 @@ int parse822_digits(const char** p, const char* e, | ... | @@ -258,7 +299,7 @@ int parse822_digits(const char** p, const char* e, |
258 | 299 | ||
259 | int parse822_special(const char** p, const char* e, char c) | 300 | int parse822_special(const char** p, const char* e, char c) |
260 | { | 301 | { |
261 | parse822_skip_ws(p, e); /* not comments, they start with a special... */ | 302 | parse822_skip_lwsp(p, e); /* not comments, they start with a special... */ |
262 | 303 | ||
263 | if((*p != e) && **p == c) { | 304 | if((*p != e) && **p == c) { |
264 | *p += 1; | 305 | *p += 1; |
... | @@ -694,7 +735,7 @@ int parse822_mail_box(const char** p, const char* e, address_t* a) | ... | @@ -694,7 +735,7 @@ int parse822_mail_box(const char** p, const char* e, address_t* a) |
694 | 735 | ||
695 | /* -> addr-spec */ | 736 | /* -> addr-spec */ |
696 | if((rc = parse822_addr_spec(p, e, a)) == EOK) { | 737 | if((rc = parse822_addr_spec(p, e, a)) == EOK) { |
697 | parse822_skip_ws(p, e); | 738 | parse822_skip_lwsp(p, e); |
698 | 739 | ||
699 | /* yuck. */ | 740 | /* yuck. */ |
700 | if((rc = parse822_comment(p, e, &(*a)->personal)) == EPARSE) { | 741 | if((rc = parse822_comment(p, e, &(*a)->personal)) == EPARSE) { |
... | @@ -1087,20 +1128,18 @@ int parse822_domain_literal(const char** p, const char* e, char** domain_literal | ... | @@ -1087,20 +1128,18 @@ int parse822_domain_literal(const char** p, const char* e, char** domain_literal |
1087 | return rc; | 1128 | return rc; |
1088 | } | 1129 | } |
1089 | 1130 | ||
1090 | #if 0 | ||
1091 | |||
1092 | /***** From RFC 822, 3.2 Header Field Definitions *****/ | 1131 | /***** From RFC 822, 3.2 Header Field Definitions *****/ |
1093 | 1132 | ||
1094 | int parse822_field_name(const char** p, const char* e, char** fieldname) | 1133 | int parse822_field_name(const char** p, const char* e, char** fieldname) |
1095 | { | 1134 | { |
1096 | /* field-name = 1*<any char, excluding ctlS, space, and ":"> ":" */ | 1135 | /* field-name = 1*<any char, excluding ctlS, space, and ":"> ":" */ |
1097 | 1136 | ||
1098 | Ptr save = p; | 1137 | const char *save = *p; |
1099 | 1138 | ||
1100 | Rope fn; | 1139 | char *fn = NULL; |
1101 | 1140 | ||
1102 | while(*p != e) { | 1141 | while(*p != e) { |
1103 | char c = *p; | 1142 | char c = **p; |
1104 | 1143 | ||
1105 | if(!parse822_is_char(c)) | 1144 | if(!parse822_is_char(c)) |
1106 | break; | 1145 | break; |
... | @@ -1112,66 +1151,67 @@ int parse822_field_name(const char** p, const char* e, char** fieldname) | ... | @@ -1112,66 +1151,67 @@ int parse822_field_name(const char** p, const char* e, char** fieldname) |
1112 | if(c == ':') | 1151 | if(c == ':') |
1113 | break; | 1152 | break; |
1114 | 1153 | ||
1115 | fn.append(c); | 1154 | str_append_char(&fn, c); |
1116 | *p += 1; | 1155 | *p += 1; |
1117 | } | 1156 | } |
1118 | /* must be at least one char in the field name */ | 1157 | /* must be at least one char in the field name */ |
1119 | if(fn.empty()) { | 1158 | if(!fn) { |
1120 | p = save; | 1159 | *p = save; |
1121 | return 0; | 1160 | return EPARSE; |
1122 | } | 1161 | } |
1123 | parse822_skip_comments(p, e); | 1162 | parse822_skip_comments(p, e); |
1124 | 1163 | ||
1125 | if(!parse822_special(p, e, ':')) { | 1164 | if(!parse822_special(p, e, ':')) { |
1126 | p = save; | 1165 | *p = save; |
1127 | return 0; | 1166 | if (fn) |
1167 | free (fn); | ||
1168 | return EPARSE; | ||
1128 | } | 1169 | } |
1129 | 1170 | ||
1130 | fieldname = fn; | 1171 | *fieldname = fn; |
1131 | 1172 | ||
1132 | return 1; | 1173 | return EOK; |
1133 | } | 1174 | } |
1134 | 1175 | ||
1135 | int parse822_field_body(const char** p, const char* e, Rope& fieldbody) | 1176 | int parse822_field_body(const char **p, const char *e, char** fieldbody) |
1136 | { | 1177 | { |
1137 | /* field-body = *text [CRLF lwsp-char field-body] */ | 1178 | /* field-body = *text [CRLF lwsp-char field-body] */ |
1138 | 1179 | ||
1139 | Ptr save = p; | 1180 | /*const char *save = *p; */ |
1140 | 1181 | ||
1141 | Rope fb; | 1182 | char *fb = NULL; |
1142 | 1183 | ||
1143 | for(;;) | 1184 | for(;;) |
1144 | { | 1185 | { |
1145 | Ptr eol = p; | 1186 | const char *eol = *p; |
1146 | while(eol != e) { | 1187 | while(eol != e) { |
1147 | char c = *eol; | 1188 | /*char c = *eol; */ |
1148 | if(eol[0] == '\r' && (eol+1) != e && eol[1] == '\n') | 1189 | if(eol[0] == '\r' && (eol+1) != e && eol[1] == '\n') |
1149 | break; | 1190 | break; |
1150 | ++eol; | 1191 | ++eol; |
1151 | } | 1192 | } |
1152 | fb.append(p, eol); | 1193 | str_append_range(&fb, *p, eol); |
1153 | p = eol; | 1194 | *p = eol; |
1154 | if(eol == e) | 1195 | if(eol == e) |
1155 | break; /* no more, so we're done */ | 1196 | break; /* no more, so we're done */ |
1156 | 1197 | ||
1157 | assert(p[0] == '\r'); | 1198 | /*assert(p[0] == '\r'); */ |
1158 | assert(p[1] == '\n'); | 1199 | /*assert(p[1] == '\n'); */ |
1159 | 1200 | ||
1160 | p += 2; | 1201 | *p += 2; |
1161 | 1202 | ||
1162 | if(*p == e) | 1203 | if(*p == e) |
1163 | break; /* no more, so we're done */ | 1204 | break; /* no more, so we're done */ |
1164 | 1205 | ||
1165 | /* check if next line is a continuation line */ | 1206 | /* check if next line is a continuation line */ |
1166 | if(*p != ' ' && *p != '\t') | 1207 | if(**p != ' ' && **p != '\t') |
1167 | break; | 1208 | break; |
1168 | } | 1209 | } |
1169 | 1210 | ||
1170 | fieldbody = fb; | 1211 | *fieldbody = fb; |
1171 | 1212 | ||
1172 | return 1; | 1213 | return EOK; |
1173 | } | 1214 | } |
1174 | #endif | ||
1175 | 1215 | ||
1176 | /***** RFC 822 Quoting Functions *****/ | 1216 | /***** RFC 822 Quoting Functions *****/ |
1177 | 1217 | ... | ... |
-
Please register or sign in to post a comment