summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org>2019-01-21 05:17:56 (GMT)
committer Sergey Poznyakoff <gray@gnu.org>2019-01-21 08:31:37 (GMT)
commitdb7165424199a473265eda5d35f2399e8816e92d (patch) (unidiff)
treec55a57f21f540c45b93f60543bca8bbb24b9bc3a
parent29a837b1126c701191affceb092afbb8de5d5ffc (diff)
downloadmailutils-db7165424199a473265eda5d35f2399e8816e92d.tar.gz
mailutils-db7165424199a473265eda5d35f2399e8816e92d.tar.bz2
Improve folder handling and expansion in mail. Add convenience functions to the library.
* configure.ac: Build libmailutils/wicket * libmailutils/Makefile.am: Likewise. * libmailutils/base/wicket.c: Move file wicket stuff to ... * libmailutils/wicket/file.c: ... here * libmailutils/wicket/noauth.c: New file. * libmailutils/wicket/Makefile.am: New file. * include/mailutils/auth.h (mu_noauth_ticket_create) (mu_noauth_wicket_create): New protos. * include/mailutils/folder.h (mu_folder_attach_ticket) (mu_folder_is_local): New protos. * include/mailutils/mailbox.h (mu_mailbox_attach_ticket): New proto. * include/mailutils/sys/folder.h (_mu_folder): Remove flags. Add new member: is_local. * libmailutils/mailbox/folder.c (mu_folder_create_from_record): Set is_local. (mu_folder_attach_ticket): New function. (mu_folder_is_local): New function. * libmailutils/mailbox/mbx_default.c (mu_mailbox_attach_ticket): New function. * libmailutils/url/create.c: Allow for trailing / in url. * libproto/imap/mbox.c (_imap_mbx_open): Do initial scan. (__imap_msg_get_stream): Initialize clos.size. * libproto/imap/tests/imapfolder.c: Attach ticket to the folder. * mail/cd.c (mail_cd): Expand directory name (~, %, + notations) prior to use. * mail/file.c (mail_file): Attach ticket to the mailbox. * mail/copy.c (append_to_mailbox): Likewise. * mail/mailline.c: Rewrite directory expansion. Implement fully functional folder expansion. * mail/util.c (util_folder_path) (util_outfolder_name): Rewrite using mu_mailbox_expand_name.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--configure.ac1
-rw-r--r--include/mailutils/auth.h3
-rw-r--r--include/mailutils/folder.h3
-rw-r--r--include/mailutils/mailbox.h2
-rw-r--r--include/mailutils/sys/folder.h5
-rw-r--r--libmailutils/Makefile.am5
-rw-r--r--libmailutils/base/wicket.c253
-rw-r--r--libmailutils/mailbox/folder.c49
-rw-r--r--libmailutils/mailbox/mbx_default.c43
-rw-r--r--libmailutils/url/create.c11
-rw-r--r--libmailutils/wicket/Makefile.am28
-rw-r--r--libmailutils/wicket/file.c266
-rw-r--r--libmailutils/wicket/noauth.c65
-rw-r--r--libproto/imap/mbox.c7
-rw-r--r--libproto/imap/tests/imapfolder.c1
-rw-r--r--mail/cd.c15
-rw-r--r--mail/copy.c1
-rw-r--r--mail/file.c24
-rw-r--r--mail/mailline.c353
-rw-r--r--mail/mailvar.c2
-rw-r--r--mail/util.c133
21 files changed, 771 insertions, 499 deletions
diff --git a/configure.ac b/configure.ac
index 8f44007..0ef4a23 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1520,6 +1520,7 @@ AC_CONFIG_FILES([
1520 libmailutils/stream/Makefile 1520 libmailutils/stream/Makefile
1521 libmailutils/stdstream/Makefile 1521 libmailutils/stdstream/Makefile
1522 libmailutils/url/Makefile 1522 libmailutils/url/Makefile
1523 libmailutils/wicket/Makefile
1523 libmailutils/Makefile 1524 libmailutils/Makefile
1524 messages/Makefile 1525 messages/Makefile
1525 mh/Makefile 1526 mh/Makefile
diff --git a/include/mailutils/auth.h b/include/mailutils/auth.h
index b4a650e..73fa98e 100644
--- a/include/mailutils/auth.h
+++ b/include/mailutils/auth.h
@@ -74,6 +74,9 @@ void *mu_wicket_get_data (mu_wicket_t wicket);
74int mu_wicket_set_get_ticket (mu_wicket_t wicket, 74int mu_wicket_set_get_ticket (mu_wicket_t wicket,
75 int (*_get_ticket) (mu_wicket_t, void *, 75 int (*_get_ticket) (mu_wicket_t, void *,
76 const char *, mu_ticket_t *)); 76 const char *, mu_ticket_t *));
77
78int mu_noauth_ticket_create (mu_ticket_t *pticket);
79int mu_noauth_wicket_create (mu_wicket_t *pwicket);
77int mu_file_wicket_create (mu_wicket_t *pwicket, const char *filename); 80int mu_file_wicket_create (mu_wicket_t *pwicket, const char *filename);
78 81
79struct mu_debug_locus; 82struct mu_debug_locus;
diff --git a/include/mailutils/folder.h b/include/mailutils/folder.h
index 2d71a0e..1232798 100644
--- a/include/mailutils/folder.h
+++ b/include/mailutils/folder.h
@@ -60,6 +60,9 @@ extern int mu_folder_enumerate (mu_folder_t, const char *,
60extern int mu_folder_lsub (mu_folder_t, const char *, const char *, 60extern int mu_folder_lsub (mu_folder_t, const char *, const char *,
61 mu_list_t *); 61 mu_list_t *);
62 62
63extern int mu_folder_attach_ticket (mu_folder_t folder);
64extern int mu_folder_is_local (mu_folder_t folder);
65
63 /* Match function */ 66 /* Match function */
64extern int mu_folder_set_match (mu_folder_t folder, mu_folder_match_fp pmatch); 67extern int mu_folder_set_match (mu_folder_t folder, mu_folder_match_fp pmatch);
65extern int mu_folder_get_match (mu_folder_t folder, 68extern int mu_folder_get_match (mu_folder_t folder,
diff --git a/include/mailutils/mailbox.h b/include/mailutils/mailbox.h
index 5c5f4c6..e54ae88 100644
--- a/include/mailutils/mailbox.h
+++ b/include/mailutils/mailbox.h
@@ -72,6 +72,8 @@ extern int mu_mailbox_expunge (mu_mailbox_t);
72extern int mu_mailbox_sync (mu_mailbox_t); 72extern int mu_mailbox_sync (mu_mailbox_t);
73extern int mu_mailbox_save_attributes (mu_mailbox_t) MU_DEPRECATED; 73extern int mu_mailbox_save_attributes (mu_mailbox_t) MU_DEPRECATED;
74 74
75extern int mu_mailbox_attach_ticket (mu_mailbox_t mbox);
76
75#define MU_UIDL_LENGTH 70 77#define MU_UIDL_LENGTH 70
76#define MU_UIDL_BUFFER_SIZE (MU_UIDL_LENGTH+1) 78#define MU_UIDL_BUFFER_SIZE (MU_UIDL_LENGTH+1)
77 79
diff --git a/include/mailutils/sys/folder.h b/include/mailutils/sys/folder.h
index c32835e..050a18f 100644
--- a/include/mailutils/sys/folder.h
+++ b/include/mailutils/sys/folder.h
@@ -28,9 +28,6 @@
28extern "C" { 28extern "C" {
29# endif 29# endif
30 30
31# define MU_FOLDER_LIST 0
32# define MU_FOLDER_ENUM 1
33
34struct _mu_folder 31struct _mu_folder
35{ 32{
36 /* Data */ 33 /* Data */
@@ -39,7 +36,7 @@ struct _mu_folder
39 mu_property_t property; 36 mu_property_t property;
40 mu_monitor_t monitor; 37 mu_monitor_t monitor;
41 mu_url_t url; 38 mu_url_t url;
42 int flags; 39 int is_local;
43 int ref; 40 int ref;
44 size_t uid; 41 size_t uid;
45 42
diff --git a/libmailutils/Makefile.am b/libmailutils/Makefile.am
index c940d9c..55b6238 100644
--- a/libmailutils/Makefile.am
+++ b/libmailutils/Makefile.am
@@ -18,7 +18,7 @@
18SUBDIRS = \ 18SUBDIRS = \
19 auth base address list sockaddr cidr cfg cli diag\ 19 auth base address list sockaddr cidr cfg cli diag\
20 filter locus mailbox mailer mime msgset opt server string stream stdstream\ 20 filter locus mailbox mailer mime msgset opt server string stream stdstream\
21 property url imapio datetime . tests 21 property url imapio datetime wicket . tests
22 22
23lib_LTLIBRARIES = libmailutils.la 23lib_LTLIBRARIES = libmailutils.la
24 24
@@ -49,7 +49,8 @@ libmailutils_la_LIBADD = \
49 string/libstring.la\ 49 string/libstring.la\
50 stream/libstream.la\ 50 stream/libstream.la\
51 stdstream/libstdstream.la\ 51 stdstream/libstdstream.la\
52 url/liburl.la 52 url/liburl.la\
53 wicket/libwicket.la
53 54
54libmailutils_la_LDFLAGS = -version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@ 55libmailutils_la_LDFLAGS = -version-info @VI_CURRENT@:@VI_REVISION@:@VI_AGE@
55 56
diff --git a/libmailutils/base/wicket.c b/libmailutils/base/wicket.c
index c60ddff..22cd2c1 100644
--- a/libmailutils/base/wicket.c
+++ b/libmailutils/base/wicket.c
@@ -19,24 +19,9 @@
19# include <config.h> 19# include <config.h>
20#endif 20#endif
21 21
22#include <errno.h>
23#include <sys/types.h>
24#include <sys/stat.h>
25#include <pwd.h>
26#include <string.h>
27#include <stdlib.h> 22#include <stdlib.h>
28#include <stdio.h>
29#include <unistd.h>
30#include <ctype.h>
31 23
32#include <mailutils/errno.h> 24#include <mailutils/errno.h>
33#include <mailutils/util.h>
34#include <mailutils/mu_auth.h>
35#include <mailutils/stream.h>
36#include <mailutils/cstr.h>
37#include <mailutils/nls.h>
38#include <mailutils/errno.h>
39
40#include <mailutils/sys/auth.h> 25#include <mailutils/sys/auth.h>
41#include <mailutils/sys/url.h> 26#include <mailutils/sys/url.h>
42 27
@@ -135,241 +120,3 @@ mu_wicket_set_get_ticket (mu_wicket_t wicket,
135 return 0; 120 return 0;
136} 121}
137 122
138
139/* A "file wicket" implementation */
140
141struct file_wicket
142{
143 char *filename;
144};
145
146static void
147_file_wicket_destroy (mu_wicket_t wicket)
148{
149 struct file_wicket *fw = mu_wicket_get_data (wicket);
150 free (fw->filename);
151 free (fw);
152}
153
154struct file_ticket
155{
156 char *filename;
157 char *user;
158 mu_url_t tickurl;
159};
160
161static void
162file_ticket_destroy (mu_ticket_t ticket)
163{
164 struct file_ticket *ft = mu_ticket_get_data (ticket);
165 if (ft)
166 {
167 free (ft->filename);
168 free (ft->user);
169 mu_url_destroy (&ft->tickurl);
170 free (ft);
171 }
172}
173
174int
175file_ticket_get_cred (mu_ticket_t ticket, mu_url_t url, const char *challenge,
176 char **pplain, mu_secret_t *psec)
177{
178 struct file_ticket *ft = mu_ticket_get_data (ticket);
179 int rc = 0;
180
181 if (!ft->tickurl)
182 {
183 rc = mu_wicket_file_match_url (ft->filename, url,
184 MU_URL_PARSE_ALL,
185 &ft->tickurl);
186 if (rc)
187 return rc;
188 }
189 if (pplain)
190 {
191 if (ft->user)
192 {
193 *pplain = strdup (ft->user);
194 if (!*pplain)
195 rc = ENOMEM;
196 }
197 else
198 rc = mu_url_aget_user (ft->tickurl, pplain);
199 }
200 else
201 rc = mu_url_get_secret (ft->tickurl, psec);
202 return rc;
203}
204
205static int
206_file_wicket_get_ticket (mu_wicket_t wicket, void *data,
207 const char *user, mu_ticket_t *pticket)
208{
209 int rc;
210 mu_ticket_t ticket;
211 struct file_wicket *fw = data;
212 struct file_ticket *ft = calloc (1, sizeof (*ft));
213 ft->filename = strdup (fw->filename);
214 if (!ft->filename)
215 {
216 free (ft);
217 return ENOMEM;
218 }
219 if (user)
220 {
221 ft->user = strdup (user);
222 if (!ft->user)
223 {
224 free (ft->filename);
225 free (ft);
226 return ENOMEM;
227 }
228 }
229 else
230 ft->user = NULL;
231
232 rc = mu_ticket_create (&ticket, NULL);
233 if (rc)
234 {
235 free (ft->filename);
236 free (ft->user);
237 free (ft);
238 return rc;
239 }
240
241 mu_ticket_set_destroy (ticket, file_ticket_destroy, NULL);
242 mu_ticket_set_data (ticket, ft, NULL);
243 mu_ticket_set_get_cred (ticket, file_ticket_get_cred, NULL);
244
245 *pticket = ticket;
246 return 0;
247}
248
249int
250mu_wicket_stream_match_url (mu_stream_t stream, struct mu_locus_point *loc,
251 mu_url_t url, int parse_flags,
252 mu_url_t *pticket_url)
253{
254 int rc;
255 mu_url_t u = NULL;
256 char *buf = NULL;
257 size_t bufsize = 0;
258 size_t len;
259 mu_url_t pret = NULL;
260 int weight = 0;
261 int line = loc->mu_line;
262
263 while ((rc = mu_stream_getline (stream, &buf, &bufsize, &len)) == 0
264 && len > 0)
265 {
266 char *p;
267 int err;
268 int n;
269
270 loc->mu_line++;
271 p = mu_str_stripws (buf);
272
273 /* Skip empty lines and comments. */
274 if (*p == 0 || *p == '#')
275 continue;
276
277 if ((err = mu_url_create_hint (&u, p, parse_flags, NULL)) != 0)
278 {
279 /* Skip erroneous entry */
280 mu_error (_("%s:%u: cannot create URL: %s"),
281 loc->mu_file, loc->mu_line, mu_strerror (err));
282 continue;
283 }
284
285 if (!mu_url_has_flag (u, MU_URL_USER|MU_URL_SECRET))
286 {
287 mu_error (_("%s:%u: URL is missing required parts"),
288 loc->mu_file, loc->mu_line);
289 mu_url_destroy (&u);
290 continue;
291 }
292
293 if (!mu_url_matches_ticket (u, url, &n))
294 {
295 mu_url_destroy (&u);
296 continue;
297 }
298
299 if (!pret || n < weight)
300 {
301 pret = u;
302 weight = n;
303 line = loc->mu_line;
304 if (weight == 0)
305 break;
306 }
307 }
308 free (buf);
309
310 if (rc == 0)
311 {
312 if (pret)
313 {
314 *pticket_url = pret;
315 loc->mu_line = line;
316 }
317 else
318 rc = MU_ERR_NOENT;
319 }
320
321 return rc;
322}
323
324int
325mu_wicket_file_match_url (const char *name, mu_url_t url,
326 int parse_flags,
327 mu_url_t *pticket_url)
328{
329 mu_stream_t stream;
330 int rc;
331 struct mu_locus_point loc;
332
333 rc = mu_file_stream_create (&stream, name, MU_STREAM_READ);
334 if (rc)
335 return rc;
336 loc.mu_file = (char*) name;
337 loc.mu_line = 0;
338 loc.mu_col = 0;
339 rc = mu_wicket_stream_match_url (stream, &loc, url, parse_flags,
340 pticket_url);
341 mu_stream_close (stream);
342 mu_stream_destroy (&stream);
343 return rc;
344}
345
346int
347mu_file_wicket_create (mu_wicket_t *pwicket, const char *filename)
348{
349 mu_wicket_t wicket;
350 int rc;
351 struct file_wicket *fw = calloc (1, sizeof (*fw));
352
353 if (!fw)
354 return ENOMEM;
355 fw->filename = strdup (filename);
356 if (!fw->filename)
357 {
358 free (fw);
359 return ENOMEM;
360 }
361
362 rc = mu_wicket_create (&wicket);
363 if (rc)
364 {
365 free (fw->filename);
366 free (fw);
367 return rc;
368 }
369 mu_wicket_set_data (wicket, fw);
370 mu_wicket_set_destroy (wicket, _file_wicket_destroy);
371 mu_wicket_set_get_ticket (wicket, _file_wicket_get_ticket);
372 *pwicket = wicket;
373 return 0;
374}
375
diff --git a/libmailutils/mailbox/folder.c b/libmailutils/mailbox/folder.c
index 64f997d..6773544 100644
--- a/libmailutils/mailbox/folder.c
+++ b/libmailutils/mailbox/folder.c
@@ -36,7 +36,7 @@
36#include <mailutils/property.h> 36#include <mailutils/property.h>
37#include <mailutils/mailbox.h> 37#include <mailutils/mailbox.h>
38#include <mailutils/imaputil.h> 38#include <mailutils/imaputil.h>
39 39#include <mailutils/util.h>
40#include <mailutils/sys/folder.h> 40#include <mailutils/sys/folder.h>
41 41
42/* Internal folder list. */ 42/* Internal folder list. */
@@ -121,6 +121,7 @@ mu_folder_create_from_record (mu_folder_t *pfolder, mu_url_t url,
121 if (folder != NULL) 121 if (folder != NULL)
122 { 122 {
123 folder->url = url; 123 folder->url = url;
124 folder->is_local = record->flags & MU_RECORD_LOCAL;
124 /* Initialize the internal foilder lock, now so the 125 /* Initialize the internal foilder lock, now so the
125 concrete folder could use it. */ 126 concrete folder could use it. */
126 status = mu_monitor_create (&folder->monitor, 0, folder); 127 status = mu_monitor_create (&folder->monitor, 0, folder);
@@ -170,6 +171,52 @@ mu_folder_create (mu_folder_t *pfolder, const char *name)
170 return rc; 171 return rc;
171} 172}
172 173
174int
175mu_folder_attach_ticket (mu_folder_t folder)
176{
177 mu_authority_t auth = NULL;
178 int rc = MU_ERR_NOENT;
179
180 if (mu_folder_get_authority (folder, &auth) == 0 && auth)
181 {
182 char *filename = mu_tilde_expansion (mu_ticket_file,
183 MU_HIERARCHY_DELIMITER, NULL);
184 mu_wicket_t wicket;
185
186 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_TRACE1,
187 ("Reading user ticket file %s", filename));
188 if ((rc = mu_file_wicket_create (&wicket, filename)) == 0)
189 {
190 mu_ticket_t ticket;
191
192 if ((rc = mu_wicket_get_ticket (wicket, NULL, &ticket)) == 0)
193 {
194 rc = mu_authority_set_ticket (auth, ticket);
195 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_TRACE1,
196 ("Retrieved and set ticket: %d", rc));
197 }
198 else
199 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
200 ("Error retrieving ticket: %s\n",
201 mu_strerror (rc)));
202 mu_wicket_destroy (&wicket);
203 }
204 else
205 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
206 ("Error creating wicket: %s\n", mu_strerror (rc)));
207 free (filename);
208 }
209 return rc;
210}
211
212int
213mu_folder_is_local (mu_folder_t folder)
214{
215 if (!folder)
216 return -1;
217 return folder->is_local;
218}
219
173/* The folder is destroy if it is the last reference. */ 220/* The folder is destroy if it is the last reference. */
174void 221void
175mu_folder_destroy (mu_folder_t *pfolder) 222mu_folder_destroy (mu_folder_t *pfolder)
diff --git a/libmailutils/mailbox/mbx_default.c b/libmailutils/mailbox/mbx_default.c
index 29890bf..bd9f876 100644
--- a/libmailutils/mailbox/mbx_default.c
+++ b/libmailutils/mailbox/mbx_default.c
@@ -344,44 +344,15 @@ percent_expand (const char *file, char **mbox)
344 return status; 344 return status;
345} 345}
346 346
347static void 347int
348attach_auth_ticket (mu_mailbox_t mbox) 348mu_mailbox_attach_ticket (mu_mailbox_t mbox)
349{ 349{
350 int rc;
350 mu_folder_t folder = NULL; 351 mu_folder_t folder = NULL;
351 mu_authority_t auth = NULL;
352 352
353 if (mu_mailbox_get_folder (mbox, &folder) == 0 353 if ((rc = mu_mailbox_get_folder (mbox, &folder)) == 0)
354 && mu_folder_get_authority (folder, &auth) == 0 354 rc = mu_folder_attach_ticket (folder);
355 && auth) 355 return rc;
356 {
357 char *filename = mu_tilde_expansion (mu_ticket_file,
358 MU_HIERARCHY_DELIMITER, NULL);
359 mu_wicket_t wicket;
360 int rc;
361
362 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_TRACE1,
363 ("Reading user ticket file %s", filename));
364 if ((rc = mu_file_wicket_create (&wicket, filename)) == 0)
365 {
366 mu_ticket_t ticket;
367
368 if ((rc = mu_wicket_get_ticket (wicket, NULL, &ticket)) == 0)
369 {
370 rc = mu_authority_set_ticket (auth, ticket);
371 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_TRACE1,
372 ("Retrieved and set ticket: %d", rc));
373 }
374 else
375 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
376 ("Error retrieving ticket: %s\n",
377 mu_strerror (rc)));
378 mu_wicket_destroy (&wicket);
379 }
380 else
381 mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR,
382 ("Error creating wicket: %s\n", mu_strerror (rc)));
383 free (filename);
384 }
385} 356}
386 357
387/* Expand mailbox name according to the following rules: 358/* Expand mailbox name according to the following rules:
@@ -490,7 +461,7 @@ mu_mailbox_create_default (mu_mailbox_t *pmbox, const char *mail)
490 status = mu_mailbox_create (pmbox, mboxname); 461 status = mu_mailbox_create (pmbox, mboxname);
491 free (mboxname); 462 free (mboxname);
492 if (status == 0) 463 if (status == 0)
493 attach_auth_ticket (*pmbox); 464 mu_mailbox_attach_ticket (*pmbox);
494 465
495 return status; 466 return status;
496} 467}
diff --git a/libmailutils/url/create.c b/libmailutils/url/create.c
index 124be32..3b19a4f 100644
--- a/libmailutils/url/create.c
+++ b/libmailutils/url/create.c
@@ -269,7 +269,16 @@ _mu_url_ctx_parse_host (struct mu_url_ctx *ctx, int has_host)
269 if (*ctx->cur == '/') 269 if (*ctx->cur == '/')
270 { 270 {
271 if (has_host) 271 if (has_host)
272 ctx->cur++; 272 {
273 ctx->cur++;
274 if (*ctx->cur == 0)
275 {
276 rc = str_assign (&url->path, "");
277 if (rc == 0)
278 url->flags |= MU_URL_PATH;
279 return rc;
280 }
281 }
273 return _mu_url_ctx_parse_path (ctx); 282 return _mu_url_ctx_parse_path (ctx);
274 } 283 }
275 284
diff --git a/libmailutils/wicket/Makefile.am b/libmailutils/wicket/Makefile.am
new file mode 100644
index 0000000..b7f3528
--- a/dev/null
+++ b/libmailutils/wicket/Makefile.am
@@ -0,0 +1,28 @@
1# GNU Mailutils -- a suite of utilities for electronic mail
2# Copyright (C) 2010-2019 Free Software Foundation, Inc.
3#
4# This library is free software; you can redistribute it and/or
5# modify it under the terms of the GNU Lesser General Public
6# License as published by the Free Software Foundation; either
7# version 3 of the License, or (at your option) any later version.
8#
9# This library is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12# Lesser General Public License for more details.
13#
14# You should have received a copy of the GNU Lesser General
15# Public License along with this library. If not, see
16# <http://www.gnu.org/licenses/>.
17
18noinst_LTLIBRARIES = libwicket.la
19libwicket_la_SOURCES = \
20 file.c\
21 noauth.c
22
23localedir = $(datadir)/locale
24AM_CPPFLAGS = \
25 @MU_LIB_COMMON_INCLUDES@ -I/libmailutils\
26 -DSYSCONFDIR=\"$(sysconfdir)\"\
27 -DSITE_VIRTUAL_PWDDIR=\"@SITE_VIRTUAL_PWDDIR@\"\
28 -DLOCALEDIR=\"$(localedir)\"
diff --git a/libmailutils/wicket/file.c b/libmailutils/wicket/file.c
new file mode 100644
index 0000000..73e7e65
--- a/dev/null
+++ b/libmailutils/wicket/file.c
@@ -0,0 +1,266 @@
1/* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999-2019 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library. If not, see
16 <http://www.gnu.org/licenses/>. */
17
18/* A "file wicket" implementation */
19
20#ifdef HAVE_CONFIG_H
21# include <config.h>
22#endif
23
24#include <stdlib.h>
25#include <mailutils/errno.h>
26#include <mailutils/error.h>
27#include <mailutils/auth.h>
28#include <mailutils/url.h>
29#include <mailutils/stream.h>
30#include <mailutils/cstr.h>
31#include <mailutils/nls.h>
32
33struct file_wicket
34{
35 char *filename;
36};
37
38static void
39_file_wicket_destroy (mu_wicket_t wicket)
40{
41 struct file_wicket *fw = mu_wicket_get_data (wicket);
42 free (fw->filename);
43 free (fw);
44}
45
46struct file_ticket
47{
48 char *filename;
49 char *user;
50 mu_url_t tickurl;
51};
52
53static void
54file_ticket_destroy (mu_ticket_t ticket)
55{
56 struct file_ticket *ft = mu_ticket_get_data (ticket);
57 if (ft)
58 {
59 free (ft->filename);
60 free (ft->user);
61 mu_url_destroy (&ft->tickurl);
62 free (ft);
63 }
64}
65
66int
67file_ticket_get_cred (mu_ticket_t ticket, mu_url_t url, const char *challenge,
68 char **pplain, mu_secret_t *psec)
69{
70 struct file_ticket *ft = mu_ticket_get_data (ticket);
71 int rc = 0;
72
73 if (!ft->tickurl)
74 {
75 rc = mu_wicket_file_match_url (ft->filename, url,
76 MU_URL_PARSE_ALL,
77 &ft->tickurl);
78 if (rc)
79 return rc;
80 }
81 if (pplain)
82 {
83 if (ft->user)
84 {
85 *pplain = strdup (ft->user);
86 if (!*pplain)
87 rc = ENOMEM;
88 }
89 else
90 rc = mu_url_aget_user (ft->tickurl, pplain);
91 }
92 else
93 rc = mu_url_get_secret (ft->tickurl, psec);
94 return rc;
95}
96
97static int
98_file_wicket_get_ticket (mu_wicket_t wicket, void *data,
99 const char *user, mu_ticket_t *pticket)
100{
101 int rc;
102 mu_ticket_t ticket;
103 struct file_wicket *fw = data;
104 struct file_ticket *ft = calloc (1, sizeof (*ft));
105 ft->filename = strdup (fw->filename);
106 if (!ft->filename)
107 {
108 free (ft);
109 return ENOMEM;
110 }
111 if (user)
112 {
113 ft->user = strdup (user);
114 if (!ft->user)
115 {
116 free (ft->filename);
117 free (ft);
118 return ENOMEM;
119 }
120 }
121 else
122 ft->user = NULL;
123
124 rc = mu_ticket_create (&ticket, NULL);
125 if (rc)
126 {
127 free (ft->filename);
128 free (ft->user);
129 free (ft);
130 return rc;
131 }
132
133 mu_ticket_set_destroy (ticket, file_ticket_destroy, NULL);
134 mu_ticket_set_data (ticket, ft, NULL);
135 mu_ticket_set_get_cred (ticket, file_ticket_get_cred, NULL);
136
137 *pticket = ticket;
138 return 0;
139}
140
141int
142mu_wicket_stream_match_url (mu_stream_t stream, struct mu_locus_point *loc,
143 mu_url_t url, int parse_flags,
144 mu_url_t *pticket_url)
145{
146 int rc;
147 mu_url_t u = NULL;
148 char *buf = NULL;
149 size_t bufsize = 0;
150 size_t len;
151 mu_url_t pret = NULL;
152 int weight = 0;
153 int line = loc->mu_line;
154
155 while ((rc = mu_stream_getline (stream, &buf, &bufsize, &len)) == 0
156 && len > 0)
157 {
158 char *p;
159 int err;
160 int n;
161
162 loc->mu_line++;
163 p = mu_str_stripws (buf);
164
165 /* Skip empty lines and comments. */
166 if (*p == 0 || *p == '#')
167 continue;
168
169 if ((err = mu_url_create_hint (&u, p, parse_flags, NULL)) != 0)
170 {
171 /* Skip erroneous entry */
172 mu_error (_("%s:%u: cannot create URL: %s"),
173 loc->mu_file, loc->mu_line, mu_strerror (err));
174 continue;
175 }
176
177 if (!mu_url_has_flag (u, MU_URL_USER|MU_URL_SECRET))
178 {
179 mu_error (_("%s:%u: URL is missing required parts"),
180 loc->mu_file, loc->mu_line);
181 mu_url_destroy (&u);
182 continue;
183 }
184
185 if (!mu_url_matches_ticket (u, url, &n))
186 {
187 mu_url_destroy (&u);
188 continue;
189 }
190
191 if (!pret || n < weight)
192 {
193 pret = u;
194 weight = n;
195 line = loc->mu_line;
196 if (weight == 0)
197 break;
198 }
199 }
200 free (buf);
201
202 if (rc == 0)
203 {
204 if (pret)
205 {
206 *pticket_url = pret;
207 loc->mu_line = line;
208 }
209 else
210 rc = MU_ERR_NOENT;
211 }
212
213 return rc;
214}
215
216int
217mu_wicket_file_match_url (const char *name, mu_url_t url,
218 int parse_flags,
219 mu_url_t *pticket_url)
220{
221 mu_stream_t stream;
222 int rc;
223 struct mu_locus_point loc;
224
225 rc = mu_file_stream_create (&stream, name, MU_STREAM_READ);
226 if (rc)
227 return rc;
228 loc.mu_file = (char*) name;
229 loc.mu_line = 0;
230 loc.mu_col = 0;
231 rc = mu_wicket_stream_match_url (stream, &loc, url, parse_flags,
232 pticket_url);
233 mu_stream_close (stream);
234 mu_stream_destroy (&stream);
235 return rc;
236}
237
238int
239mu_file_wicket_create (mu_wicket_t *pwicket, const char *filename)
240{
241 mu_wicket_t wicket;
242 int rc;
243 struct file_wicket *fw = calloc (1, sizeof (*fw));
244
245 if (!fw)
246 return ENOMEM;
247 fw->filename = strdup (filename);
248 if (!fw->filename)
249 {
250 free (fw);
251 return ENOMEM;
252 }
253
254 rc = mu_wicket_create (&wicket);
255 if (rc)
256 {
257 free (fw->filename);
258 free (fw);
259 return rc;
260 }
261 mu_wicket_set_data (wicket, fw);
262 mu_wicket_set_destroy (wicket, _file_wicket_destroy);
263 mu_wicket_set_get_ticket (wicket, _file_wicket_get_ticket);
264 *pwicket = wicket;
265 return 0;
266}
diff --git a/libmailutils/wicket/noauth.c b/libmailutils/wicket/noauth.c
new file mode 100644
index 0000000..2a4da10
--- a/dev/null
+++ b/libmailutils/wicket/noauth.c
@@ -0,0 +1,65 @@
1/* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999-2019 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library. If not, see
16 <http://www.gnu.org/licenses/>. */
17
18#ifdef HAVE_CONFIG_H
19# include <config.h>
20#endif
21
22#include <stdlib.h>
23#include <mailutils/errno.h>
24#include <mailutils/auth.h>
25
26static int
27noauth_ticket_get_cred (mu_ticket_t ticket, mu_url_t url, const char *challenge,
28 char **pplain, mu_secret_t *psec)
29{
30 return MU_ERR_AUTH_FAILURE;
31}
32
33int
34mu_noauth_ticket_create (mu_ticket_t *pticket)
35{
36 mu_ticket_t ticket;
37 int rc;
38
39 rc = mu_ticket_create (&ticket, NULL);
40 if (rc)
41 return rc;
42 mu_ticket_set_get_cred (ticket, noauth_ticket_get_cred, NULL);
43 *pticket = ticket;
44 return 0;
45}
46
47static int
48noauth_get_ticket (mu_wicket_t wicket, void *data,
49 const char *user, mu_ticket_t *pticket)
50{
51 return mu_noauth_ticket_create (pticket);
52}
53
54int
55mu_noauth_wicket_create (mu_wicket_t *pwicket)
56{
57 mu_wicket_t wicket;
58 int rc;
59
60 rc = mu_wicket_create (&wicket);
61 if (rc)
62 return rc;
63 mu_wicket_set_get_ticket (wicket, noauth_get_ticket);
64 return 0;
65}
diff --git a/libproto/imap/mbox.c b/libproto/imap/mbox.c
index 1442e62..fde568a 100644
--- a/libproto/imap/mbox.c
+++ b/libproto/imap/mbox.c
@@ -183,7 +183,8 @@ __imap_msg_get_stream (struct _mu_imap_message *imsg, size_t msgno,
183 183
184 clos.imsg = imsg; 184 clos.imsg = imsg;
185 clos.save_stream = imbx->cache; 185 clos.save_stream = imbx->cache;
186 186 clos.size = 0;
187
187 rc = mu_msgset_add_range (msgset, msgno, msgno, MU_MSGSET_NUM); 188 rc = mu_msgset_add_range (msgset, msgno, msgno, MU_MSGSET_NUM);
188 if (rc == 0) 189 if (rc == 0)
189 { 190 {
@@ -757,7 +758,9 @@ _imap_mbx_open (mu_mailbox_t mbox, int flags)
757 758
758 if (imbx->stats.flags & MU_IMAP_STAT_MESSAGE_COUNT) 759 if (imbx->stats.flags & MU_IMAP_STAT_MESSAGE_COUNT)
759 rc = _imap_realloc_messages (imbx, imbx->stats.message_count); 760 rc = _imap_realloc_messages (imbx, imbx->stats.message_count);
760 761
762 _imap_mbx_scan (mbox, 1, NULL);
763
761 return rc; 764 return rc;
762} 765}
763 766
diff --git a/libproto/imap/tests/imapfolder.c b/libproto/imap/tests/imapfolder.c
index 6f91b63..8d3f6ce 100644
--- a/libproto/imap/tests/imapfolder.c
+++ b/libproto/imap/tests/imapfolder.c
@@ -202,6 +202,7 @@ main (int argc, char **argv)
202 mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_create", fname, rc); 202 mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_create", fname, rc);
203 return 1; 203 return 1;
204 } 204 }
205 mu_folder_attach_ticket (folder);
205 206
206 rc = mu_folder_open (folder, MU_STREAM_READ); 207 rc = mu_folder_open (folder, MU_STREAM_READ);
207 if (rc) 208 if (rc)
diff --git a/mail/cd.c b/mail/cd.c
index cb71b4c..122a1af 100644
--- a/mail/cd.c
+++ b/mail/cd.c
@@ -24,7 +24,8 @@
24int 24int
25mail_cd (int argc, char **argv) 25mail_cd (int argc, char **argv)
26{ 26{
27 char *dir; 27 char *dir, *edir;
28 int rc;
28 29
29 if (argc > 2) 30 if (argc > 2)
30 return 1; 31 return 1;
@@ -33,10 +34,16 @@ mail_cd (int argc, char **argv)
33 else 34 else
34 dir = getenv ("HOME"); 35 dir = getenv ("HOME");
35 36
36 if (chdir (dir)) 37 rc = mu_mailbox_expand_name (dir, &edir);
38 if (rc)
37 { 39 {
38 mu_diag_funcall (MU_DIAG_ERROR, "chdir", dir, errno); 40 mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_expand_name", dir, rc);
39 return 1; 41 return 1;
40 } 42 }
41 return 0; 43
44 rc = chdir (edir);
45 if (rc)
46 mu_diag_funcall (MU_DIAG_ERROR, "chdir", edir, errno);
47 free (edir);
48 return rc;
42} 49}
diff --git a/mail/copy.c b/mail/copy.c
index 476b441..15deebe 100644
--- a/mail/copy.c
+++ b/mail/copy.c
@@ -45,6 +45,7 @@ append_to_mailbox (char const *filename, msgset_t *msglist, int mark,
45 mu_strerror (status)); 45 mu_strerror (status));
46 return 1; 46 return 1;
47 } 47 }
48 mu_mailbox_attach_ticket (mbx);
48 if ((status = mu_mailbox_open (mbx, MU_STREAM_WRITE | MU_STREAM_CREAT)) != 0) 49 if ((status = mu_mailbox_open (mbx, MU_STREAM_WRITE | MU_STREAM_CREAT)) != 0)
49 { 50 {
50 mu_error (_("Cannot open mailbox %s: %s"), filename, 51 mu_error (_("Cannot open mailbox %s: %s"), filename,
diff --git a/mail/file.c b/mail/file.c
index 517a6b7..bc94f13 100644
--- a/mail/file.c
+++ b/mail/file.c
@@ -30,7 +30,7 @@ mail_expand_name (const char *name)
30{ 30{
31 int status = 0; 31 int status = 0;
32 char *exp = NULL; 32 char *exp = NULL;
33 33
34 if (strcmp (name, "#") == 0) 34 if (strcmp (name, "#") == 0)
35 { 35 {
36 if (!prev_name) 36 if (!prev_name)
@@ -84,9 +84,18 @@ mail_file (int argc, char **argv)
84 84
85 if (!name) 85 if (!name)
86 return 1; 86 return 1;
87 87
88 if ((status = mu_mailbox_create (&newbox, name)) != 0 88 status = mu_mailbox_create (&newbox, name);
89 || (status = mu_mailbox_open (newbox, MU_STREAM_RDWR)) != 0) 89 if (status)
90 {
91 mu_error(_("Cannot create mailbox %s: %s"), name,
92 mu_strerror (status));
93 free (name);
94 return 1;
95 }
96 mu_mailbox_attach_ticket (newbox);
97
98 if ((status = mu_mailbox_open (newbox, MU_STREAM_RDWR)) != 0)
90 { 99 {
91 mu_mailbox_destroy (&newbox); 100 mu_mailbox_destroy (&newbox);
92 mu_error(_("Cannot open mailbox %s: %s"), name, mu_strerror (status)); 101 mu_error(_("Cannot open mailbox %s: %s"), name, mu_strerror (status));
@@ -96,7 +105,7 @@ mail_file (int argc, char **argv)
96 105
97 free (name); /* won't need it any more */ 106 free (name); /* won't need it any more */
98 page_invalidate (1); /* Invalidate current page map */ 107 page_invalidate (1); /* Invalidate current page map */
99 108
100 mu_mailbox_get_url (mbox, &url); 109 mu_mailbox_get_url (mbox, &url);
101 pname = mu_strdup (mu_url_to_string (url)); 110 pname = mu_strdup (mu_url_to_string (url));
102 if (mail_mbox_close ()) 111 if (mail_mbox_close ())
@@ -107,11 +116,11 @@ mail_file (int argc, char **argv)
107 mu_mailbox_destroy (&newbox); 116 mu_mailbox_destroy (&newbox);
108 return 1; 117 return 1;
109 } 118 }
110 119
111 if (prev_name) 120 if (prev_name)
112 free (prev_name); 121 free (prev_name);
113 prev_name = pname; 122 prev_name = pname;
114 123
115 mbox = newbox; 124 mbox = newbox;
116 mu_mailbox_messages_count (mbox, &total); 125 mu_mailbox_messages_count (mbox, &total);
117 set_cursor (1); 126 set_cursor (1);
@@ -128,4 +137,3 @@ mail_file (int argc, char **argv)
128 } 137 }
129 return 1; 138 return 1;
130} 139}
131
diff --git a/mail/mailline.c b/mail/mailline.c
index f1fa4b2..1574125 100644
--- a/mail/mailline.c
+++ b/mail/mailline.c
@@ -18,6 +18,7 @@
18#include <sys/stat.h> 18#include <sys/stat.h>
19#include <dirent.h> 19#include <dirent.h>
20#include <mailutils/folder.h> 20#include <mailutils/folder.h>
21#include <mailutils/auth.h>
21 22
22#ifdef WITH_READLINE 23#ifdef WITH_READLINE
23static char **ml_command_completion (char *cmd, int start, int end); 24static char **ml_command_completion (char *cmd, int start, int end);
@@ -209,7 +210,7 @@ ml_command_completion (char *cmd, int start, int end)
209 char **ret; 210 char **ret;
210 char *p; 211 char *p;
211 struct mu_wordsplit ws; 212 struct mu_wordsplit ws;
212 213
213 for (p = rl_line_buffer; p < rl_line_buffer + start && mu_isblank (*p); p++) 214 for (p = rl_line_buffer; p < rl_line_buffer + start && mu_isblank (*p); p++)
214 ; 215 ;
215 216
@@ -239,7 +240,7 @@ ml_command_completion (char *cmd, int start, int end)
239 point |= COMPL_WS; 240 point |= COMPL_WS;
240 if (mu_str_skip_class (p + end, MU_CTYPE_SPACE)[0] == 0) 241 if (mu_str_skip_class (p + end, MU_CTYPE_SPACE)[0] == 0)
241 point |= COMPL_LASTARG; 242 point |= COMPL_LASTARG;
242 243
243 ret = entry->command_completion (ws.ws_wordc, ws.ws_wordv, point); 244 ret = entry->command_completion (ws.ws_wordc, ws.ws_wordv, point);
244 } 245 }
245 else 246 else
@@ -295,7 +296,7 @@ ml_attempted_completion_over (void)
295 be returned by rl_completion_matches, i.e. their first entry is the 296 be returned by rl_completion_matches, i.e. their first entry is the
296 longest common prefix of the remaining entries, which are sorted 297 longest common prefix of the remaining entries, which are sorted
297 lexicographically. Array B is treated as case-insensitive. 298 lexicographically. Array B is treated as case-insensitive.
298 299
299 If either of the arrays is NULL, the other one is returned unchanged. 300 If either of the arrays is NULL, the other one is returned unchanged.
300 301
301 Otherwise, if A[0] begins with a lowercase letter, all items from B 302 Otherwise, if A[0] begins with a lowercase letter, all items from B
@@ -312,7 +313,7 @@ compl_concat (char **a, char **b)
312 size_t i, j, k, n = 0, an, bn; 313 size_t i, j, k, n = 0, an, bn;
313 char **ret; 314 char **ret;
314 int lwr = 0; 315 int lwr = 0;
315 316
316 if (a) 317 if (a)
317 { 318 {
318 lwr = mu_islower (a[0][0]); 319 lwr = mu_islower (a[0][0]);
@@ -321,21 +322,21 @@ compl_concat (char **a, char **b)
321 } 322 }
322 else 323 else
323 return b; 324 return b;
324 325
325 if (b) 326 if (b)
326 { 327 {
327 for (bn = 0; b[bn]; bn++) 328 for (bn = 0; b[bn]; bn++)
328 { 329 {
329 if (lwr) 330 if (lwr)
330 mu_strlower (b[bn]); 331 mu_strlower (b[bn]);
331 } 332 }
332 } 333 }
333 else 334 else
334 return a; 335 return a;
335 336
336 i = an == 1 ? 0 : 1; 337 i = an == 1 ? 0 : 1;
337 j = bn == 1 ? 0 : 1; 338 j = bn == 1 ? 0 : 1;
338 339
339 n = (an - i) + (bn - j) + 1; 340 n = (an - i) + (bn - j) + 1;
340 ret = mu_calloc (n + 1, sizeof (ret[0])); 341 ret = mu_calloc (n + 1, sizeof (ret[0]));
341 342
@@ -356,7 +357,7 @@ compl_concat (char **a, char **b)
356 free (a[0]); 357 free (a[0]);
357 if (j) 358 if (j)
358 free (b[0]); 359 free (b[0]);
359 360
360 k = 1; 361 k = 1;
361 while (k < n) 362 while (k < n)
362 { 363 {
@@ -377,7 +378,7 @@ compl_concat (char **a, char **b)
377 free (a); 378 free (a);
378 free (b); 379 free (b);
379 return ret; 380 return ret;
380} 381}
381 382
382static char *msgtype_generator (const char *text, int state); 383static char *msgtype_generator (const char *text, int state);
383static char *header_generator (const char *text, int state); 384static char *header_generator (const char *text, int state);
@@ -389,7 +390,7 @@ static char *header_generator (const char *text, int state);
389 In the latter case the MATCHES function generates expansions for the 390 In the latter case the MATCHES function generates expansions for the
390 last argument. It is used for such commands as write, where the last 391 last argument. It is used for such commands as write, where the last
391 object is a mailbox or pipe, where it is a command). 392 object is a mailbox or pipe, where it is a command).
392 393
393 CLOSURE supplies argument for MATCHES. It is ignored if MATCHES is NULL. 394 CLOSURE supplies argument for MATCHES. It is ignored if MATCHES is NULL.
394*/ 395*/
395static char ** 396static char **
@@ -399,7 +400,7 @@ msglist_closure_compl (int argc, char **argv, int point,
399{ 400{
400 char *text = (point & COMPL_WS) ? "" : argv[argc-1]; 401 char *text = (point & COMPL_WS) ? "" : argv[argc-1];
401 size_t len = strlen (text); 402 size_t len = strlen (text);
402 403
403 if (text[0] == ':') 404 if (text[0] == ':')
404 { 405 {
405 if (text[1] && (text[1] == '/' || text[2])) 406 if (text[1] && (text[1] == '/' || text[2]))
@@ -411,7 +412,7 @@ msglist_closure_compl (int argc, char **argv, int point,
411 ml_set_completion_append_character (' '); 412 ml_set_completion_append_character (' ');
412 return rl_completion_matches (text, msgtype_generator); 413 return rl_completion_matches (text, msgtype_generator);
413 } 414 }
414 415
415 ml_set_completion_append_character (0); 416 ml_set_completion_append_character (0);
416 if (len && text[len-1] == ':') 417 if (len && text[len-1] == ':')
417 { 418 {
@@ -450,111 +451,211 @@ command_compl (int argc, char **argv, int point)
450 return NULL; 451 return NULL;
451 return rl_completion_matches (argv[argc-1], ml_command_generator); 452 return rl_completion_matches (argv[argc-1], ml_command_generator);
452} 453}
454
455struct filegen
456{
457 mu_list_t list;
458 mu_iterator_t itr;
459 size_t pathlen;
460 char repl;
461 int flags;
462};
453 463
454/* Generate file list based on reference prefix TEXT, relative to PATH. 464static void
455 Remove PATHLEN leading characters from the returned names. Replace 465filegen_free (struct filegen *fg)
456 them with REPL unless it is 0. 466{
467 mu_iterator_destroy (&fg->itr);
468 mu_list_destroy (&fg->list);
469}
457 470
458 Select only those files that match given FLAGS (MU_FOLDER_ATTRIBUTE_* 471enum
459 constants). 472 {
473 any_folder,
474 local_folder
475 };
460 476
461 STATE is 0 for the first call, 1 otherwise. 477#define PATHLEN_AUTO ((size_t)-1)
462 */ 478
463static char * 479static int
464file_generator (const char *text, int state, 480filegen_init (struct filegen *fg,
465 char *path, size_t pathlen, 481 const char *text,
466 char repl, 482 const char *folder_path,
467 int flags) 483 int type,
484 size_t pathlen,
485 int repl,
486 int flags)
468{ 487{
469 static mu_list_t list; 488 char *pathref;
470 static mu_iterator_t itr; 489 char *wcard;
490 mu_folder_t folder;
491 size_t count, i, len;
492 mu_url_t url;
493 int rc;
471 494
472 if (!state) 495 pathref = mu_strdup (text);
473 { 496 len = strlen (pathref);
474 char *wcard; 497 for (i = len; i > 0; i--)
475 mu_folder_t folder; 498 if (pathref[i-1] == '/')
476 size_t count; 499 break;
500 wcard = mu_alloc (len - i + 2);
501 strcpy (wcard, pathref + i);
502 strcat (wcard, "%");
503 pathref[i] = 0;
477 504
478 wcard = mu_alloc (strlen (text) + 2); 505 rc = mu_folder_create (&folder, folder_path);
479 strcat (strcpy (wcard, text), "*"); 506 if (rc)
507 {
508 mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_create", folder_path, rc);
509 free (wcard);
510 free (pathref);
511 return -1;
512 }
480 513
481 if (mu_folder_create (&folder, path)) 514 if (!mu_folder_is_local (folder))
515 {
516 if (type == local_folder)
482 { 517 {
518 mu_error ("%s", _("folder must be set to a local folder"));
483 free (wcard); 519 free (wcard);
484 return NULL; 520 free (pathref);
521 return -1;
485 } 522 }
486 523
487 mu_folder_list (folder, path, wcard, 1, &list); 524 /* Set ticket for a remote folder */
525 rc = mu_folder_attach_ticket (folder);
526 if (rc)
527 {
528 mu_authority_t auth = NULL;
529
530 if (mu_folder_get_authority (folder, &auth) == 0 && auth)
531 {
532 mu_ticket_t tct;
533 mu_noauth_ticket_create (&tct);
534 rc = mu_authority_set_ticket (auth, tct);
535 if (rc)
536 mu_diag_funcall (MU_DIAG_ERROR, "mu_authority_set_ticket",
537 NULL, rc);
538 }
539 }
540 }
541
542 rc = mu_folder_open (folder, MU_STREAM_READ);
543 if (rc)
544 {
545 mu_diag_funcall (MU_DIAG_ERROR, "mu_folder_open", folder_path, rc);
488 free (wcard); 546 free (wcard);
547 free (pathref);
548 return -1;
549 }
550
551 if (mu_folder_get_url (folder, &url))
552 {
553 free (wcard);
554 free (pathref);
489 mu_folder_destroy (&folder); 555 mu_folder_destroy (&folder);
556 }
490 557
491 if (mu_list_count (list, &count) || count == 0) 558 if (pathlen == PATHLEN_AUTO)
492 { 559 {
493 mu_list_destroy (&list); 560 char const *urlpath;
494 return NULL; 561
495 } 562 mu_url_sget_path (url, &urlpath);
496 else if (count == 1) 563 fg->pathlen = strlen (urlpath);
497 ml_set_completion_append_character (0); 564 while (fg->pathlen > 0 && urlpath[fg->pathlen-1] == '/')
565 fg->pathlen--;
566 if (fg->pathlen == 1 && urlpath[0] == '/')
567 fg->pathlen = 0;
568 }
569 else
570 fg->pathlen = pathlen;
498 571
499 if (mu_list_get_iterator (list, &itr)) 572 mu_folder_list (folder, pathref, wcard, 1, &fg->list);
573 free (wcard);
574 free (pathref);
575 mu_folder_destroy (&folder);
576
577 if (mu_list_count (fg->list, &count) || count == 0)
578 {
579 mu_list_destroy (&fg->list);
580 return -1;
581 }
582 else if (count == 1)
583 {
584 if (flags & MU_FOLDER_ATTRIBUTE_DIRECTORY)
500 { 585 {
501 mu_list_destroy (&list); 586 struct mu_list_response *resp;
502 return NULL; 587 mu_list_head (fg->list, (void**)&resp);
588 if (resp->type & MU_FOLDER_ATTRIBUTE_DIRECTORY)
589 {
590 size_t len = strlen (resp->name);
591 resp->name = mu_realloc (resp->name, len + 2);
592 resp->name[len] = resp->separator;
593 resp->name[len+1] = 0;
594 }
503 } 595 }
504 mu_iterator_first (itr); 596 ml_set_completion_append_character (0);
505 } 597 }
506 598
507 while (!mu_iterator_is_done (itr)) 599 if (mu_list_get_iterator (fg->list, &fg->itr))
600 {
601 mu_list_destroy (&fg->list);
602 return -1;
603 }
604 mu_iterator_first (fg->itr);
605 fg->repl = repl;
606 fg->flags = flags;
607 return 0;
608}
609
610static char *
611filegen_next (struct filegen *fg)
612{
613 while (!mu_iterator_is_done (fg->itr))
508 { 614 {
509 struct mu_list_response *resp; 615 struct mu_list_response *resp;
510 mu_iterator_current (itr, (void**)&resp); 616 mu_iterator_current (fg->itr, (void**)&resp);
511 mu_iterator_next (itr); 617 mu_iterator_next (fg->itr);
512 if (resp->type & flags) 618 if (resp->type & fg->flags)
513 { 619 {
514 char *ret; 620 char *ret;
515 if (pathlen) 621 size_t len = strlen (resp->name + fg->pathlen);
516 { 622 char *ptr;
517 size_t len = strlen (resp->name + pathlen); 623
518 char *ptr; 624 ret = mu_alloc (len + (fg->repl ? 1 : 0) + 1);
519 625 ptr = ret;
520 ret = mu_alloc (len + (repl ? 1 : 0) + 1); 626 if (fg->repl)
521 ptr = ret; 627 *ptr++ = fg->repl;
522 if (repl) 628 memcpy (ptr, resp->name + fg->pathlen, len);
523 *ptr++ = repl; 629 ptr[len] = 0;
524 memcpy (ptr, resp->name + pathlen, len); 630 // if (resp->type & (fg->flags & MU_FOLDER_ATTRIBUTE_DIRECTORY))
525 ptr[len] = 0;
526 }
527 else
528 ret = mu_strdup (resp->name);
529 return ret; 631 return ret;
530 } 632 }
531 } 633 }
532 mu_iterator_destroy (&itr); 634 filegen_free (fg);
533 mu_list_destroy (&list);
534 return NULL; 635 return NULL;
535} 636}
536 637
537static char * 638static char *
538folder_generator (const char *text, int state) 639folder_generator (const char *text, int state)
539{ 640{
540 char *ret; 641 static struct filegen fg;
541 static size_t pathlen;
542 642
543 if (!state) 643 if (!state)
544 { 644 {
545 char *path = util_folder_path (""); 645 int rc;
646 char *path = util_folder_path ("+");
546 if (!path) 647 if (!path)
547 return NULL; 648 return NULL;
548 649
549 pathlen = strlen (path); 650 rc = filegen_init (&fg, text, path,
550 ret = file_generator (text, state, path, pathlen, '+', 651 any_folder,
551 MU_FOLDER_ATTRIBUTE_ALL); 652 PATHLEN_AUTO, '+',
653 MU_FOLDER_ATTRIBUTE_ALL);
552 free (path); 654 free (path);
655 if (rc)
656 return NULL;
553 } 657 }
554 else 658 return filegen_next (&fg);
555 ret = file_generator (text, state, NULL, pathlen, '+',
556 MU_FOLDER_ATTRIBUTE_ALL);
557 return ret;
558} 659}
559 660
560static char * 661static char *
@@ -562,7 +663,7 @@ msgtype_generator (const char *text, int state)
562{ 663{
563 /* Allowed message types, plus '/'. The latter can folow a colon, 664 /* Allowed message types, plus '/'. The latter can folow a colon,
564 meaning body lookup */ 665 meaning body lookup */
565 static char types[] = "dnorTtu/"; 666 static char types[] = "dnorTtu/";
566 static int i; 667 static int i;
567 char c; 668 char c;
568 669
@@ -659,7 +760,7 @@ char **
659file_compl (int argc, char **argv, int point) 760file_compl (int argc, char **argv, int point)
660{ 761{
661 char *text; 762 char *text;
662 763
663 if (point & COMPL_WS) 764 if (point & COMPL_WS)
664 { 765 {
665 ml_set_completion_append_character (0); 766 ml_set_completion_append_character (0);
@@ -679,12 +780,12 @@ file_compl (int argc, char **argv, int point)
679 case '&': 780 case '&':
680 ml_attempted_completion_over (); 781 ml_attempted_completion_over ();
681 break; 782 break;
682 783
683 default: 784 default:
684 /* Suppose it is a file name */ 785 /* Suppose it is a file name */
685 return rl_completion_matches (text, rl_filename_completion_function); 786 return rl_completion_matches (text, rl_filename_completion_function);
686 } 787 }
687 788
688 return NULL; 789 return NULL;
689} 790}
690 791
@@ -712,32 +813,45 @@ msglist_file_compl (int argc, char **argv, int point)
712static char * 813static char *
713dir_generator (const char *text, int state) 814dir_generator (const char *text, int state)
714{ 815{
715 char *ret; 816 static struct filegen fg;
716 static size_t pathlen;
717 static int repl;
718 817
719 if (!state) 818 if (!state)
720 { 819 {
721 char *path; 820 char *path;
821 char *p;
822 int rc;
823 char repl;
824 size_t pathlen;
825
722 switch (text[0]) 826 switch (text[0])
723 { 827 {
724 case '+': 828 case '+':
725 text++; 829 {
726 repl = '+'; 830 char *f;
727 path = util_folder_path (text); 831 repl = '+';
728 pathlen = strlen (path) - strlen (text); 832 f = util_folder_path ("+");
833 pathlen = strlen (f);
834 path = mu_make_file_name (f, text + 1);
835 free (f);
836 }
729 break; 837 break;
730 838
731 case '~': 839 case '~':
732 repl = '~'; 840 repl = '~';
733 if (text[1] == '/') 841 if (text[1] == '/')
734 { 842 {
735 path = mu_get_homedir (); 843 char *home = mu_get_homedir ();
736 text += 2; 844 pathlen = strlen (home);
737 pathlen = strlen (path); 845 path = mu_make_file_name (home, text + 2);
738 break; 846 free (home);
739 } 847 }
740 /* else FIXME! */ 848 else
849 {
850 ml_attempted_completion_over ();
851 return NULL;
852 /* FIXME: implement user-name completion */
853 }
854 break;
741 855
742 case '/': 856 case '/':
743 path = mu_strdup (text); 857 path = mu_strdup (text);
@@ -746,19 +860,36 @@ dir_generator (const char *text, int state)
746 break; 860 break;
747 861
748 default: 862 default:
749 path = mu_strdup ("./"); 863 {
750 pathlen = 2; 864 char *cwd = mu_getcwd ();
865 pathlen = strlen (cwd);
866 path = mu_make_file_name (cwd, text);
867 free (cwd);
868 }
751 repl = 0; 869 repl = 0;
752 } 870 }
753 871 p = strrchr (path, '/');
754 ret = file_generator (text, state, path, pathlen, repl, 872 if (*p)
755 MU_FOLDER_ATTRIBUTE_DIRECTORY); 873 {
756 free (path); 874 if (p[1])
875 *p++ = 0;
876 else
877 p = "";
878 rc = filegen_init (&fg, p, path[0] ? path : "/",
879 local_folder,
880 pathlen, repl,
881 MU_FOLDER_ATTRIBUTE_DIRECTORY);
882 }
883 else
884 {
885 ml_attempted_completion_over ();
886 rc = -1;
887 }
888 if (rc)
889 return NULL;
757 } 890 }
758 else 891
759 ret = file_generator (text, state, NULL, pathlen, repl, 892 return filegen_next (&fg);
760 MU_FOLDER_ATTRIBUTE_DIRECTORY);
761 return ret;
762} 893}
763 894
764char ** 895char **
@@ -801,20 +932,6 @@ alias_compl (int argc, char **argv, int point)
801} 932}
802 933
803static char * 934static char *
804mkfilename (const char *dir, const char *file)
805{
806 size_t len = strlen (dir) + 1 + strlen (file) + 1;
807 char *p = malloc (len);
808 if (p)
809 {
810 strcpy (p, dir);
811 strcat (p, "/");
812 strcat (p, file);
813 }
814 return p;
815}
816
817static char *
818exec_generator (const char *text, int state) 935exec_generator (const char *text, int state)
819{ 936{
820 static int prefix_len; 937 static int prefix_len;
@@ -877,7 +994,7 @@ exec_generator (const char *text, int state)
877 994
878 while ((ent = readdir (dp))) 995 while ((ent = readdir (dp)))
879 { 996 {
880 char *name = mkfilename (dir, ent->d_name); 997 char *name = mu_make_file_name (dir, ent->d_name);
881 if (name) 998 if (name)
882 { 999 {
883 int rc = access (name, X_OK); 1000 int rc = access (name, X_OK);
diff --git a/mail/mailvar.c b/mail/mailvar.c
index 206166c..5cdb7f1 100644
--- a/mail/mailvar.c
+++ b/mail/mailvar.c
@@ -289,7 +289,7 @@ struct mailvar_symbol mailvar_tab[] =
289 289
290 { { "quiet", }, MAILVAR_TYPEMASK (mailvar_type_boolean) | MAILVAR_HIDDEN, 290 { { "quiet", }, MAILVAR_TYPEMASK (mailvar_type_boolean) | MAILVAR_HIDDEN,
291 "suppresses the printing of the version when first invoked" }, 291 "suppresses the printing of the version when first invoked" },
292 292
293 { { NULL }, } 293 { { NULL }, }
294 }; 294 };
295 295
diff --git a/mail/util.c b/mail/util.c
index 0475e9e..f5471e7 100644
--- a/mail/util.c
+++ b/mail/util.c
@@ -42,7 +42,7 @@ util_do_command (const char *fmt, ...)
42 char *cmd = NULL; 42 char *cmd = NULL;
43 size_t size = 0; 43 size_t size = 0;
44 va_list ap; 44 va_list ap;
45 45
46 va_start (ap, fmt); 46 va_start (ap, fmt);
47 status = mu_vasnprintf (&cmd, &size, fmt, ap); 47 status = mu_vasnprintf (&cmd, &size, fmt, ap);
48 va_end (ap); 48 va_end (ap);
@@ -61,7 +61,7 @@ util_do_command (const char *fmt, ...)
61 if (cmd[0] == '\0') 61 if (cmd[0] == '\0')
62 { 62 {
63 free (cmd); 63 free (cmd);
64 64
65 /* Hitting return i.e. no command, is equivalent to next 65 /* Hitting return i.e. no command, is equivalent to next
66 according to the POSIX spec. Note, that this applies 66 according to the POSIX spec. Note, that this applies
67 to interactive state only. */ 67 to interactive state only. */
@@ -85,7 +85,7 @@ util_do_command (const char *fmt, ...)
85 85
86 argc = ws.ws_wordc; 86 argc = ws.ws_wordc;
87 argv = ws.ws_wordv + 1; 87 argv = ws.ws_wordv + 1;
88 88
89 /* Special case: a number alone implies "print" */ 89 /* Special case: a number alone implies "print" */
90 if (argc == 1 90 if (argc == 1
91 && ((strtoul (argv[0], &p, 10) > 0 && *p == 0) 91 && ((strtoul (argv[0], &p, 10) > 0 && *p == 0)
@@ -108,16 +108,16 @@ util_do_command (const char *fmt, ...)
108 { 108 {
109 /* argv[0] might be a traditional /bin/mail contracted form, e.g. 109 /* argv[0] might be a traditional /bin/mail contracted form, e.g.
110 `d*' or `p4'. */ 110 `d*' or `p4'. */
111 111
112 char *p; 112 char *p;
113 113
114 for (p = argv[0] + strlen (argv[0]) - 1; 114 for (p = argv[0] + strlen (argv[0]) - 1;
115 p > argv[0] && !mu_isalpha (*p); 115 p > argv[0] && !mu_isalpha (*p);
116 p--) 116 p--)
117 ; 117 ;
118 118
119 p++; 119 p++;
120 120
121 if (strlen (p)) 121 if (strlen (p))
122 { 122 {
123 /* Expand contracted form. That's what we have kept an extra 123 /* Expand contracted form. That's what we have kept an extra
@@ -131,10 +131,10 @@ util_do_command (const char *fmt, ...)
131 ws.ws_wordc++; 131 ws.ws_wordc++;
132 ws.ws_offs = 0; 132 ws.ws_offs = 0;
133 } 133 }
134 134
135 entry = mail_find_command (argv[0]); 135 entry = mail_find_command (argv[0]);
136 } 136 }
137 137
138 if (entry) 138 if (entry)
139 { 139 {
140 /* Make sure we are not in any if/else */ 140 /* Make sure we are not in any if/else */
@@ -183,12 +183,12 @@ util_foreach_msg (int argc, char **argv, int flags,
183} 183}
184 184
185size_t 185size_t
186util_range_msg (size_t low, size_t high, int flags, 186util_range_msg (size_t low, size_t high, int flags,
187 msg_handler_t func, void *data) 187 msg_handler_t func, void *data)
188{ 188{
189 msgset_t msgspec = { 0 }; 189 msgset_t msgspec = { 0 };
190 size_t count, expect_count; 190 size_t count, expect_count;
191 191
192 msgspec.next = NULL; 192 msgspec.next = NULL;
193 msgspec.npart = 0; 193 msgspec.npart = 0;
194 msgspec.msg_part = &low; 194 msgspec.msg_part = &low;
@@ -217,7 +217,7 @@ util_range_msg (size_t low, size_t high, int flags,
217 (unsigned long) low); 217 (unsigned long) low);
218 continue; 218 continue;
219 } 219 }
220 220
221 if (util_get_message (mbox, low, &mesg) == 0) 221 if (util_get_message (mbox, low, &mesg) == 0)
222 { 222 {
223 count ++; 223 count ++;
@@ -250,13 +250,13 @@ util_find_entry (void *table, size_t nmemb, size_t size, const char *cmd)
250 int i; 250 int i;
251 int len = strlen (cmd); 251 int len = strlen (cmd);
252 char *p; 252 char *p;
253 253
254 for (p = table, i = 0; i < nmemb; i++, p += size) 254 for (p = table, i = 0; i < nmemb; i++, p += size)
255 { 255 {
256 struct mail_command *cp = (struct mail_command *)p; 256 struct mail_command *cp = (struct mail_command *)p;
257 int ll = strlen (cp->longname); 257 int ll = strlen (cp->longname);
258 int sl = strlen (cp->shortname); 258 int sl = strlen (cp->shortname);
259 259
260 if (sl > ll && !strncmp (cp->shortname, cmd, sl)) 260 if (sl > ll && !strncmp (cp->shortname, cmd, sl))
261 return p; 261 return p;
262 else if (sl == len && !strcmp (cp->shortname, cmd)) 262 else if (sl == len && !strcmp (cp->shortname, cmd))
@@ -285,7 +285,7 @@ util_help (void *table, size_t nmemb, size_t size, const char *word)
285 continue; 285 continue;
286 mu_stream_printf (out, "%s\n", cp->synopsis); 286 mu_stream_printf (out, "%s\n", cp->synopsis);
287 } 287 }
288 288
289 mu_stream_unref (out); 289 mu_stream_unref (out);
290 290
291 return 0; 291 return 0;
@@ -313,7 +313,7 @@ util_command_list (void *table, size_t nmemb, size_t size)
313 char *p; 313 char *p;
314 int cols = util_screen_columns (); 314 int cols = util_screen_columns ();
315 int pos = 0; 315 int pos = 0;
316 316
317 for (p = table, i = 0; i < nmemb; i++, p += size) 317 for (p = table, i = 0; i < nmemb; i++, p += size)
318 { 318 {
319 const char *cmd; 319 const char *cmd;
@@ -335,7 +335,7 @@ util_command_list (void *table, size_t nmemb, size_t size)
335 mu_printf ("\n%s ", cmd); 335 mu_printf ("\n%s ", cmd);
336 } 336 }
337 else 337 else
338 mu_printf ("%s ", cmd); 338 mu_printf ("%s ", cmd);
339 } 339 }
340 mu_printf ("\n"); 340 mu_printf ("\n");
341 return 0; 341 return 0;
@@ -467,35 +467,21 @@ char *
467util_folder_path (const char *name) 467util_folder_path (const char *name)
468{ 468{
469 char *folder; 469 char *folder;
470 char *tmp; 470 int rc;
471 char *p; 471
472
473 if (mailvar_get (&folder, "folder", mailvar_type_string, 1)) 472 if (mailvar_get (&folder, "folder", mailvar_type_string, 1))
474 return NULL; 473 return NULL;
475 474
476 if (!name) 475 if (!name)
477 return NULL; 476 return NULL;
478 if (name[0] == '+') 477
479 name++; 478 rc = mu_mailbox_expand_name (name, &folder);
480 479 if (rc)
481 if (folder[0] != '/' && folder[0] != '~')
482 {
483 char *home = mu_get_homedir ();
484 tmp = mu_alloc (strlen (home) + 1 +
485 strlen (folder) + 1 +
486 strlen (name) + 1);
487 sprintf (tmp, "%s/%s/%s", home, folder, name);
488 }
489 else
490 { 480 {
491 tmp = mu_alloc (strlen (folder) + 1 + 481 mu_diag_funcall (MU_DIAG_ERROR, "mailbox_expand_name", name, rc);
492 strlen (name) + 1); 482 return NULL;
493 sprintf (tmp, "%s/%s", folder, name);
494 } 483 }
495 p = util_fullpath (tmp); 484 return folder;
496 free (tmp);
497
498 return p;
499} 485}
500 486
501char * 487char *
@@ -504,7 +490,7 @@ util_get_sender (int msgno, int strip)
504 mu_message_t msg = NULL; 490 mu_message_t msg = NULL;
505 mu_address_t addr = NULL; 491 mu_address_t addr = NULL;
506 char *buf = NULL, *p; 492 char *buf = NULL, *p;
507 493
508 mu_mailbox_get_message (mbox, msgno, &msg); 494 mu_mailbox_get_message (mbox, msgno, &msg);
509 addr = get_sender_address (msg); 495 addr = get_sender_address (msg);
510 if (!addr) 496 if (!addr)
@@ -659,34 +645,43 @@ char *
659util_outfolder_name (char *str) 645util_outfolder_name (char *str)
660{ 646{
661 char *outfolder; 647 char *outfolder;
648 char *exp;
649 int rc;
662 650
663 if (!str) 651 if (!str)
664 return NULL; 652 return NULL;
665 653
666 switch (*str) 654 switch (*str)
667 { 655 {
668 case '/': 656 case '/':
669 case '~': 657 case '~':
670 str = util_fullpath (str);
671 break;
672
673 case '+': 658 case '+':
674 str = util_folder_path (str); 659 rc = mu_mailbox_expand_name (str, &exp);
660 if (rc)
661 {
662 mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_expand_name", str, rc);
663 return NULL;
664 }
675 break; 665 break;
676 666
677 default: 667 default:
678 if (mailvar_get (&outfolder, "outfolder", mailvar_type_string, 0) == 0) 668 if (mailvar_get (&outfolder, "outfolder", mailvar_type_string, 0) == 0)
679 { 669 {
680 char *ns = NULL; 670 char *s = mu_make_file_name (outfolder, str);
681 mu_asprintf (&ns, "%s/%s", outfolder, str); 671 rc = mu_mailbox_expand_name (s, &exp);
682 str = util_fullpath (ns); 672 if (rc)
683 free (ns); 673 {
674 mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_expand_name", s, rc);
675 free (s);
676 return NULL;
677 }
678 free (s);
684 } 679 }
685 break; 680 break;
686 681
687 } 682 }
688 683
689 return mu_strdup (str); 684 return exp;
690} 685}
691 686
692/* Save an outgoing message. The SAVEFILE argument overrides the setting 687/* Save an outgoing message. The SAVEFILE argument overrides the setting
@@ -695,7 +690,7 @@ void
695util_save_outgoing (mu_message_t msg, char *savefile) 690util_save_outgoing (mu_message_t msg, char *savefile)
696{ 691{
697 char *record; 692 char *record;
698 693
699 if (mailvar_get (&record, "record", mailvar_type_string, 0) == 0) 694 if (mailvar_get (&record, "record", mailvar_type_string, 0) == 0)
700 { 695 {
701 int rc; 696 int rc;
@@ -725,7 +720,7 @@ util_save_outgoing (mu_message_t msg, char *savefile)
725 720
726 mu_mailbox_close (outbox); 721 mu_mailbox_close (outbox);
727 mu_mailbox_destroy (&outbox); 722 mu_mailbox_destroy (&outbox);
728 723
729 free (filename); 724 free (filename);
730 } 725 }
731} 726}
@@ -836,7 +831,7 @@ util_merge_addresses (char **addr_str, const char *value)
836 831
837 if ((rc = mu_address_create (&new_addr, value)) != 0) 832 if ((rc = mu_address_create (&new_addr, value)) != 0)
838 return rc; 833 return rc;
839 834
840 if ((rc = mu_address_create (&addr, *addr_str)) != 0) 835 if ((rc = mu_address_create (&addr, *addr_str)) != 0)
841 { 836 {
842 mu_address_destroy (&new_addr); 837 mu_address_destroy (&new_addr);
@@ -847,7 +842,7 @@ util_merge_addresses (char **addr_str, const char *value)
847 if (rc == 0) 842 if (rc == 0)
848 { 843 {
849 char *val; 844 char *val;
850 845
851 rc = mu_address_aget_printable (addr, &val); 846 rc = mu_address_aget_printable (addr, &val);
852 if (rc == 0) 847 if (rc == 0)
853 { 848 {
@@ -873,7 +868,7 @@ is_address_field (const char *name)
873 0 868 0
874 }; 869 };
875 char **p; 870 char **p;
876 871
877 for (p = address_fields; *p; p++) 872 for (p = address_fields; *p; p++)
878 if (mu_c_strcasecmp (*p, name) == 0) 873 if (mu_c_strcasecmp (*p, name) == 0)
879 return 1; 874 return 1;
@@ -886,32 +881,32 @@ util_header_expand (mu_header_t *phdr)
886 size_t i, nfields = 0; 881 size_t i, nfields = 0;
887 mu_header_t hdr; 882 mu_header_t hdr;
888 int errcnt = 0, rc; 883 int errcnt = 0, rc;
889 884
890 rc = mu_header_create (&hdr, "", 0); 885 rc = mu_header_create (&hdr, "", 0);
891 if (rc) 886 if (rc)
892 { 887 {
893 mu_error (_("Cannot create temporary header: %s"), mu_strerror (rc)); 888 mu_error (_("Cannot create temporary header: %s"), mu_strerror (rc));
894 return 1; 889 return 1;
895 } 890 }
896 891
897 mu_header_get_field_count (*phdr, &nfields); 892 mu_header_get_field_count (*phdr, &nfields);
898 for (i = 1; i <= nfields; i++) 893 for (i = 1; i <= nfields; i++)
899 { 894 {
900 const char *name, *value; 895 const char *name, *value;
901 896
902 if (mu_header_sget_field_name (*phdr, i, &name)) 897 if (mu_header_sget_field_name (*phdr, i, &name))
903 continue; 898 continue;
904 899
905 if (mu_header_sget_field_value (*phdr, i, &value)) 900 if (mu_header_sget_field_value (*phdr, i, &value))
906 continue; 901 continue;
907 902
908 if (is_address_field (name)) 903 if (is_address_field (name))
909 { 904 {
910 const char *s; 905 const char *s;
911 mu_address_t addr = NULL; 906 mu_address_t addr = NULL;
912 struct mu_wordsplit ws; 907 struct mu_wordsplit ws;
913 size_t j; 908 size_t j;
914 909
915 if (mu_header_sget_value (hdr, name, &s) == 0) 910 if (mu_header_sget_value (hdr, name, &s) == 0)
916 mu_address_create (&addr, s); 911 mu_address_create (&addr, s);
917 912
@@ -932,9 +927,9 @@ util_header_expand (mu_header_t *phdr)
932 const char *exp; 927 const char *exp;
933 mu_address_t new_addr; 928 mu_address_t new_addr;
934 char *p = ws.ws_wordv[j]; 929 char *p = ws.ws_wordv[j];
935 930
936 if (mailvar_is_true ("inplacealiases")) 931 if (mailvar_is_true ("inplacealiases"))
937 /* If inplacealiases was set, the value was already expanded */ 932 /* If inplacealiases was set, the value was already expanded */
938 exp = p; 933 exp = p;
939 else 934 else
940 exp = alias_expand (p); 935 exp = alias_expand (p);
@@ -949,15 +944,15 @@ util_header_expand (mu_header_t *phdr)
949 mu_error (_("Cannot parse address `%s': %s"), 944 mu_error (_("Cannot parse address `%s': %s"),
950 p, mu_strerror (rc)); 945 p, mu_strerror (rc));
951 } 946 }
952 947
953 mu_address_union (&addr, new_addr); 948 mu_address_union (&addr, new_addr);
954 mu_address_destroy (&new_addr); 949 mu_address_destroy (&new_addr);
955 } 950 }
956 951
957 if (addr) 952 if (addr)
958 { 953 {
959 const char *newvalue; 954 const char *newvalue;
960 955
961 rc = mu_address_sget_printable (addr, &newvalue); 956 rc = mu_address_sget_printable (addr, &newvalue);
962 if (rc == 0 && newvalue) 957 if (rc == 0 && newvalue)
963 mu_header_set_value (hdr, name, newvalue, 1); 958 mu_header_set_value (hdr, name, newvalue, 1);
@@ -989,7 +984,7 @@ util_get_message (mu_mailbox_t mbox, size_t msgno, mu_message_t *msg)
989 util_error_range (msgno); 984 util_error_range (msgno);
990 return MU_ERR_NOENT; 985 return MU_ERR_NOENT;
991 } 986 }
992 987
993 status = mu_mailbox_get_message (mbox, msgno, msg); 988 status = mu_mailbox_get_message (mbox, msgno, msg);
994 if (status) 989 if (status)
995 { 990 {
@@ -1060,7 +1055,7 @@ util_get_charset (void)
1060 char *tmp = getenv ("LC_ALL"); 1055 char *tmp = getenv ("LC_ALL");
1061 if (!tmp) 1056 if (!tmp)
1062 tmp = getenv ("LANG"); 1057 tmp = getenv ("LANG");
1063 1058
1064 if (tmp && mu_parse_lc_all (tmp, &lc_all, MU_LC_CSET) == 0) 1059 if (tmp && mu_parse_lc_all (tmp, &lc_all, MU_LC_CSET) == 0)
1065 { 1060 {
1066 charset = mu_strdup (lc_all.charset); 1061 charset = mu_strdup (lc_all.charset);
@@ -1089,7 +1084,7 @@ util_rfc2047_decode (char **value)
1089 1084
1090 rc = mu_rfc2047_decode (charset, *value, &tmp); 1085 rc = mu_rfc2047_decode (charset, *value, &tmp);
1091 free (charset); 1086 free (charset);
1092 1087
1093 if (rc) 1088 if (rc)
1094 { 1089 {
1095 if (mailvar_is_true ("verbose")) 1090 if (mailvar_is_true ("verbose"))
@@ -1124,7 +1119,7 @@ open_pager (size_t lines)
1124 const char *pager; 1119 const char *pager;
1125 unsigned pagelines = util_get_crt (); 1120 unsigned pagelines = util_get_crt ();
1126 mu_stream_t str; 1121 mu_stream_t str;
1127 1122
1128 if (pagelines && lines > pagelines && (pager = getenv ("PAGER"))) 1123 if (pagelines && lines > pagelines && (pager = getenv ("PAGER")))
1129 { 1124 {
1130 int rc = mu_command_stream_create (&str, pager, MU_STREAM_WRITE); 1125 int rc = mu_command_stream_create (&str, pager, MU_STREAM_WRITE);

Return to:

Send suggestions and report system problems to the System administrator.