Commit a9a11cf9 a9a11cf95bbfad541ae242cffecb963065621fa1 by Alain Magloire

Updates from Sam Roberts.

1 parent 3e158c93
...@@ -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
......