Essentially rewritten.
mailbox_open_default() supports the following naming schemes: % --> system mailbox for the real uid %user --> system mailbox for the given user ~/file --> /home/user/file ~user/file --> /home/user/file +file --> /home/user/Mail/file =file --> /home/user/Mail/file
Showing
1 changed file
with
192 additions
and
186 deletions
... | @@ -34,38 +34,53 @@ | ... | @@ -34,38 +34,53 @@ |
34 | #include <mailutils/mutil.h> | 34 | #include <mailutils/mutil.h> |
35 | #include <mailutils/error.h> | 35 | #include <mailutils/error.h> |
36 | 36 | ||
37 | char *mu_path_maildir = MU_PATH_MAILDIR; | ||
38 | |||
37 | /* Is this a security risk? */ | 39 | /* Is this a security risk? */ |
38 | #define USE_ENVIRON 1 | 40 | #define USE_ENVIRON 1 |
39 | 41 | ||
40 | static char * tilde_expansion __P ((const char *)); | 42 | static int |
41 | static char * plus_equal_expansion __P ((const char *)); | 43 | split_shortcut (const char *file, const char pfx[], char **user, char **rest) |
42 | static char * get_cwd __P ((void)); | ||
43 | static char * get_full_path __P ((const char *)); | ||
44 | static const char * get_homedir __P ((const char *)); | ||
45 | |||
46 | /* Do + and = expansion to ~/Mail, if necessary. */ | ||
47 | static char * | ||
48 | plus_equal_expansion (const char *file) | ||
49 | { | 44 | { |
50 | char *p = NULL; | 45 | *user = NULL; |
51 | if (file && (*file == '+' || *file == '=')) | 46 | *rest = NULL; |
47 | |||
48 | if (!strchr (pfx, file[0])) | ||
49 | return 0; | ||
50 | |||
51 | if (*++file == 0) | ||
52 | return 0; | ||
53 | else | ||
52 | { | 54 | { |
53 | char *folder; | 55 | char *p = strchr (file, '/'); |
54 | /* Skip '+' or '='. */ | 56 | int len; |
55 | file++; | 57 | if (p) |
56 | folder = tilde_expansion ("~/Mail"); | 58 | len = p - file + 1; |
57 | if (folder) | 59 | else |
58 | { | 60 | len = strlen (file) + 1; |
59 | p = malloc (strlen (folder) + 1 + strlen (file) + 1); | 61 | |
60 | if (p) | 62 | *user = calloc (1, len); |
61 | sprintf(p, "%s/%s", folder, file); | 63 | if (!*user) |
62 | free (folder); | 64 | return ENOMEM; |
63 | } | 65 | |
66 | memcpy (*user, file, len); | ||
67 | (*user)[len-1] = 0; | ||
68 | file += len-1; | ||
69 | if (file[0] == '/') | ||
70 | file++; | ||
64 | } | 71 | } |
65 | 72 | ||
66 | if (!p) | 73 | if (file[0]) |
67 | p = strdup (file); | 74 | { |
68 | return p; | 75 | *rest = strdup (file); |
76 | if (!*rest) | ||
77 | { | ||
78 | free (*user); | ||
79 | return ENOMEM; | ||
80 | } | ||
81 | } | ||
82 | |||
83 | return 0; | ||
69 | } | 84 | } |
70 | 85 | ||
71 | static const char * | 86 | static const char * |
... | @@ -77,7 +92,7 @@ get_homedir (const char *user) | ... | @@ -77,7 +92,7 @@ get_homedir (const char *user) |
77 | { | 92 | { |
78 | pw = mu_getpwnam (user); | 93 | pw = mu_getpwnam (user); |
79 | if (pw) | 94 | if (pw) |
80 | homedir = pw->pw_dir; | 95 | homedir = pw->pw_dir; |
81 | } | 96 | } |
82 | else | 97 | else |
83 | { | 98 | { |
... | @@ -85,164 +100,163 @@ get_homedir (const char *user) | ... | @@ -85,164 +100,163 @@ get_homedir (const char *user) |
85 | /* NOTE: Should we honor ${HOME}? */ | 100 | /* NOTE: Should we honor ${HOME}? */ |
86 | homedir = getenv ("HOME"); | 101 | homedir = getenv ("HOME"); |
87 | if (homedir == NULL) | 102 | if (homedir == NULL) |
88 | { | 103 | { |
89 | pw = mu_getpwuid (getuid ()); | 104 | pw = mu_getpwuid (getuid ()); |
90 | if (pw) | 105 | if (pw) |
91 | homedir = pw->pw_dir; | 106 | homedir = pw->pw_dir; |
92 | } | 107 | } |
93 | #else | 108 | #else |
94 | pw = mu_getpwuid (getuid ()); | 109 | pw = mu_getpwuid (getuid ()); |
95 | if (pw) | 110 | if (pw) |
96 | homedir = pw->pw_dir; | 111 | homedir = pw->pw_dir; |
97 | #endif | 112 | #endif |
98 | } | 113 | } |
99 | return homedir; | 114 | return homedir; |
100 | } | 115 | } |
101 | 116 | ||
102 | /* Do ~ , if necessary. We do not use $HOME. */ | 117 | static int |
103 | static char * | 118 | user_mailbox_name (const char *user, char **mailbox_name) |
104 | tilde_expansion (const char *file) | ||
105 | { | 119 | { |
106 | char *p = NULL; | 120 | #ifdef USE_ENVIRON |
107 | const char *homedir = NULL; | 121 | if (!user) |
108 | const char delim = '/'; /* Not portable. */ | 122 | user = (getenv ("LOGNAME")) ? getenv ("LOGNAME") : getenv ("USER"); |
109 | 123 | #endif | |
110 | if (file && *file == '~') | 124 | if (user == NULL) |
111 | { | 125 | { |
112 | /* Skip the tilde. */ | 126 | struct passwd *pw; |
113 | file++; | 127 | pw = mu_getpwuid (getuid ()); |
114 | 128 | if (pw) | |
115 | /* This means we have ~ or ~/something. */ | 129 | user = pw->pw_name; |
116 | if (*file == delim || *file == '\0') | ||
117 | { | ||
118 | homedir = get_homedir (NULL); | ||
119 | if (homedir) | ||
120 | { | ||
121 | p = calloc (strlen (homedir) + strlen (file) + 1, 1); | ||
122 | if (p) | ||
123 | { | ||
124 | strcpy (p, homedir); | ||
125 | strcat (p, file); | ||
126 | } | ||
127 | } | ||
128 | } | ||
129 | /* Means we have ~user or ~user/something. */ | ||
130 | else | 130 | else |
131 | { | 131 | { |
132 | const char *s = file; | 132 | mu_error ("Who am I ?\n"); |
133 | 133 | return EINVAL; | |
134 | /* Move to the first delim. */ | ||
135 | while (*s && *s != delim) s++; | ||
136 | |||
137 | /* Get the username homedir. */ | ||
138 | { | ||
139 | char *name; | ||
140 | name = calloc (s - file + 1, 1); | ||
141 | if (name) | ||
142 | { | ||
143 | memcpy (name, file, s - file); | ||
144 | name [s - file] = '\0'; | ||
145 | } | ||
146 | homedir = get_homedir (name); | ||
147 | free (name); | ||
148 | } | ||
149 | |||
150 | if (homedir) | ||
151 | { | ||
152 | p = calloc (strlen (homedir) + strlen (s) + 1, 1); | ||
153 | if (p) | ||
154 | { | ||
155 | strcpy (p, homedir); | ||
156 | strcat (p, s); | ||
157 | } | ||
158 | } | ||
159 | } | 134 | } |
160 | } | 135 | } |
161 | 136 | *mailbox_name = malloc (strlen (user) + strlen (mu_path_maildir) + 2); | |
162 | if (!p) | 137 | if (*mailbox_name == NULL) |
163 | p = strdup (file); | 138 | return ENOMEM; |
164 | return p; | 139 | sprintf (*mailbox_name, "%s%s", mu_path_maildir, user); |
140 | return 0; | ||
165 | } | 141 | } |
166 | 142 | ||
167 | static char * | 143 | #define MPREFIX "Mail" |
168 | get_cwd () | ||
169 | { | ||
170 | char *ret; | ||
171 | unsigned path_max; | ||
172 | char buf[128]; | ||
173 | |||
174 | errno = 0; | ||
175 | ret = getcwd (buf, sizeof (buf)); | ||
176 | if (ret != NULL) | ||
177 | return strdup (buf); | ||
178 | 144 | ||
179 | if (errno != ERANGE) | 145 | static int |
180 | return NULL; | 146 | plus_expand (const char *file, char **buf) |
181 | 147 | { | |
182 | path_max = 128; | 148 | char *user = NULL; |
183 | path_max += 2; /* The getcwd docs say to do this. */ | 149 | char *path = NULL; |
184 | 150 | const char *home; | |
185 | for (;;) | 151 | int status, len; |
152 | |||
153 | if ((status = split_shortcut (file, "+=", &user, &path))) | ||
154 | return status; | ||
155 | |||
156 | if (!path) | ||
186 | { | 157 | { |
187 | char *cwd = (char *) malloc (path_max); | 158 | free (user); |
159 | return ENOENT; | ||
160 | } | ||
161 | |||
162 | home = get_homedir (user); | ||
163 | if (!home) | ||
164 | { | ||
165 | free (user); | ||
166 | free (path); | ||
167 | return ENOENT; | ||
168 | } | ||
188 | 169 | ||
189 | errno = 0; | 170 | len = strlen (home) + sizeof (MPREFIX) + strlen (path) + 3; |
190 | ret = getcwd (cwd, path_max); | 171 | *buf = malloc (len); |
191 | if (ret != NULL) | 172 | sprintf (*buf, "%s/%s/%s", home, MPREFIX, path); |
192 | return ret; | 173 | (*buf)[len-1] = 0; |
193 | if (errno != ERANGE) | 174 | free (user); |
194 | { | 175 | free (path); |
195 | int save_errno = errno; | 176 | return 0; |
196 | free (cwd); | 177 | } |
197 | errno = save_errno; | ||
198 | return NULL; | ||
199 | } | ||
200 | 178 | ||
201 | free (cwd); | 179 | /* Do ~ , if necessary. We do not use $HOME. */ |
180 | static int | ||
181 | tilde_expand (const char *file, char **buf) | ||
182 | { | ||
183 | char *user = NULL; | ||
184 | char *path = NULL; | ||
185 | const char *home; | ||
186 | int status; | ||
187 | int len; | ||
188 | |||
189 | if ((status = split_shortcut (file, "~", &user, &path))) | ||
190 | return status; | ||
191 | |||
192 | if (!user) | ||
193 | return ENOENT; | ||
194 | if (!path) | ||
195 | { | ||
196 | free (user); | ||
197 | return ENOENT; | ||
198 | } | ||
199 | |||
200 | home = get_homedir (user); | ||
201 | if (!home) | ||
202 | { | ||
203 | free (user); | ||
204 | free (path); | ||
205 | return ENOENT; | ||
206 | } | ||
202 | 207 | ||
203 | path_max += path_max / 16; | 208 | free (user); /* not needed anymore */ |
204 | path_max += 32; | 209 | |
210 | len = strlen (home) + strlen (path) + 2; | ||
211 | *buf = malloc (len); | ||
212 | if (*buf) | ||
213 | { | ||
214 | sprintf (*buf, "%s/%s", home, path); | ||
215 | (*buf)[len-1] = 0; | ||
205 | } | 216 | } |
206 | /* oops? */ | 217 | |
207 | return NULL; | 218 | free (path); |
219 | free (user); | ||
220 | return *buf ? 0 : ENOMEM; | ||
208 | } | 221 | } |
209 | 222 | ||
210 | static char * | 223 | static int |
211 | get_full_path (const char *file) | 224 | percent_expand (const char *file, char **mbox) |
212 | { | 225 | { |
213 | char *p = NULL; | 226 | char *user = NULL; |
227 | char *path = NULL; | ||
228 | int status; | ||
229 | |||
230 | if ((status = split_shortcut (file, "%", &user, &path))) | ||
231 | return status; | ||
214 | 232 | ||
215 | if (!file) | 233 | if (path) |
216 | p = get_cwd (); | ||
217 | else if (*file != '/') | ||
218 | { | 234 | { |
219 | char *cwd = get_cwd (); | 235 | free (user); |
220 | if (cwd) | 236 | free (path); |
221 | { | 237 | return ENOENT; |
222 | p = calloc (strlen (cwd) + 1 + strlen (file) + 1, 1); | ||
223 | if (p) | ||
224 | sprintf (p, "%s/%s", cwd, file); | ||
225 | free (cwd); | ||
226 | } | ||
227 | } | 238 | } |
228 | 239 | ||
229 | if (!p) | 240 | status = user_mailbox_name (user, mbox); |
230 | p = strdup (file); | 241 | free (user); |
231 | return p; | 242 | return status; |
232 | } | 243 | } |
233 | 244 | ||
234 | /* We are trying to be smart about the location of the mail. | 245 | /* We are trying to be smart about the location of the mail. |
235 | mailbox_create() is not doing this. | 246 | mailbox_create() is not doing this. |
236 | ~/file --> /home/user/file | 247 | % --> system mailbox for the real uid |
237 | ~user/file --> /home/user/file | 248 | %user --> system mailbox for the given user |
238 | +file --> /home/user/Mail/file | 249 | ~/file --> /home/user/file |
239 | =file --> /home/user/Mail/file | 250 | ~user/file --> /home/user/file |
251 | +file --> /home/user/Mail/file | ||
252 | =file --> /home/user/Mail/file | ||
240 | */ | 253 | */ |
241 | int | 254 | int |
242 | mailbox_create_default (mailbox_t *pmbox, const char *mail) | 255 | mailbox_create_default (mailbox_t *pmbox, const char *mail) |
243 | { | 256 | { |
244 | char *mbox = NULL; | 257 | char *mbox = NULL; |
245 | int status; | 258 | char *tmp_mbox = NULL; |
259 | int status = 0; | ||
246 | 260 | ||
247 | /* Sanity. */ | 261 | /* Sanity. */ |
248 | if (pmbox == NULL) | 262 | if (pmbox == NULL) |
... | @@ -251,52 +265,44 @@ mailbox_create_default (mailbox_t *pmbox, const char *mail) | ... | @@ -251,52 +265,44 @@ mailbox_create_default (mailbox_t *pmbox, const char *mail) |
251 | /* Other utilities may not understand GNU mailutils url namespace, so | 265 | /* Other utilities may not understand GNU mailutils url namespace, so |
252 | use FOLDER instead, to not confuse others by using MAIL. */ | 266 | use FOLDER instead, to not confuse others by using MAIL. */ |
253 | if (mail == NULL || *mail == '\0') | 267 | if (mail == NULL || *mail == '\0') |
254 | mail = getenv ("FOLDER"); | 268 | { |
269 | mail = getenv ("FOLDER"); | ||
255 | 270 | ||
256 | /* Fallback to wellknown environment. */ | 271 | /* Fallback to wellknown environment. */ |
257 | if (mail == NULL) | 272 | if (!mail) |
258 | mail = getenv ("MAIL"); | 273 | mail = getenv ("MAIL"); |
259 | 274 | ||
260 | /* FIXME: This is weak, it would be better to check | 275 | if (!mail) |
261 | for all the known schemes to detect presence of URLs. */ | 276 | { |
262 | if (mail && *mail && strchr (mail, ':') == NULL) | 277 | if (status = user_mailbox_name (NULL, &tmp_mbox)) |
263 | { | 278 | return status; |
264 | char *mail0; | 279 | mail = tmp_mbox; |
265 | char *mail2; | 280 | } |
266 | |||
267 | mail0 = tilde_expansion (mail); | ||
268 | mail2 = plus_equal_expansion (mail0); | ||
269 | free (mail0); | ||
270 | mbox = get_full_path (mail2); | ||
271 | free (mail2); | ||
272 | } | 281 | } |
273 | else if (mail) | ||
274 | mbox = strdup (mail); | ||
275 | 282 | ||
276 | /* Search the spooldir. */ | 283 | switch (mail[0]) |
277 | if (mbox == NULL) | ||
278 | { | 284 | { |
279 | const char *user = NULL; | 285 | case '%': |
280 | #ifdef USE_ENVIRON | 286 | status = percent_expand (mail, &mbox); |
281 | user = (getenv ("LOGNAME")) ? getenv ("LOGNAME") : getenv ("USER"); | 287 | break; |
282 | #endif | 288 | case '~': |
283 | if (user == NULL) | 289 | status = tilde_expand (mail, &mbox); |
284 | { | 290 | break; |
285 | struct passwd *pw; | 291 | case '+': |
286 | pw = mu_getpwuid (getuid ()); | 292 | case '=': |
287 | if (pw) | 293 | status = plus_expand (mail, &mbox); |
288 | user = pw->pw_name; | 294 | break; |
289 | else | 295 | default: |
290 | { | 296 | mbox = strdup (mail); |
291 | mu_error ("Who am I ?\n"); | 297 | break; |
292 | return EINVAL; | ||
293 | } | ||
294 | } | ||
295 | mbox = malloc (strlen (user) + strlen (MU_PATH_MAILDIR) + 2); | ||
296 | if (mbox == NULL) | ||
297 | return ENOMEM; | ||
298 | sprintf (mbox, "%s%s", MU_PATH_MAILDIR, user); | ||
299 | } | 298 | } |
299 | |||
300 | if (tmp_mbox) | ||
301 | free (tmp_mbox); | ||
302 | |||
303 | if (status) | ||
304 | return status; | ||
305 | |||
300 | status = mailbox_create (pmbox, mbox); | 306 | status = mailbox_create (pmbox, mbox); |
301 | free (mbox); | 307 | free (mbox); |
302 | return status; | 308 | return status; | ... | ... |
-
Please register or sign in to post a comment