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