Commit 7dcee33a 7dcee33a0ee8923108dbdfa024d1c7bc1e7d2800 by Sergey Poznyakoff

mh: improve mhn store mode.

* mh/mhn.c (options): Add --build as an alias to --compose.
(options): Likewise.
(store_destination): New enum.
(mhn_store_command): Support all variants of mhn-store-* components.
Return store_destination type.
(store_handler): Rewrite accordingly.
(main): Consistently use mh_expand_name to expand the value of
input_file.
* mh/tests/mhn.at: New file.
* mh/tests/Makefile.am (TESTSUITE_AT): Add mhn.at.
* mh/tests/testsuite.at: Include mhn.at.
1 parent 2ad19f56
......@@ -39,7 +39,11 @@ static struct argp_option options[] = {
{N_("MIME editing options"), 0, NULL, OPTION_DOC, NULL, GRID},
{"compose", ARG_COMPOSE, N_("BOOL"), OPTION_ARG_OPTIONAL,
N_("compose the MIME message (default)"), GRID+1},
{"nocompose", ARG_NOCOMPOSE, NULL, OPTION_HIDDEN, "", GRID+1},
{"build", 0, NULL, OPTION_ALIAS,
NULL, GRID+1 },
{"nocompose", ARG_NOCOMPOSE, NULL, OPTION_HIDDEN, NULL, GRID+1},
{"nobuild", ARG_NOCOMPOSE, NULL, OPTION_HIDDEN|OPTION_ALIAS,
NULL, GRID+1},
#undef GRID
#define GRID 20
{N_("Listing options"), 0, NULL, OPTION_DOC, NULL, GRID},
......@@ -97,6 +101,7 @@ static struct argp_option options[] = {
struct mh_option mh_option[] = {
{ "file", MH_OPT_ARG, "filename" },
{ "compose" },
{ "build" },
{ "list", MH_OPT_BOOL },
{ "headers", MH_OPT_BOOL },
{ "realsize", MH_OPT_BOOL },
......@@ -801,18 +806,71 @@ mhn_show_command (mu_message_t msg, msg_part_t part, int *flags,
return (char*) str;
}
char *
mhn_store_command (mu_message_t msg, msg_part_t part, char *name)
enum store_destination
{
store_to_folder,
store_to_folder_msg,
store_to_file,
store_to_command,
store_to_stdout
};
enum store_destination
mhn_store_command (mu_message_t msg, msg_part_t part, const char *name,
char **return_string)
{
const char *p, *str, *tmp;
char *typestr, *type, *subtype, *typeargs;
struct obstack stk;
mu_header_t hdr;
enum store_destination dest;
mu_message_get_header (msg, &hdr);
_get_content_type (hdr, &typestr, &typeargs);
split_content (typestr, &type, &subtype);
str = _mhn_profile_get ("store", type, subtype, "%m%P.%s");
str = _mhn_profile_get ("store", type, subtype, NULL);
if (!str)
{
/* FIXME:
[If the mhn-store component] isn't found, mhn will check to see if
the content is application/octet-stream with parameter "type=tar".
If so, mhn will choose an appropriate filename.
*/
if (mu_c_strcasecmp (type, "message") == 0)
{
/* If the content is not application/octet-stream, then mhn
will check to see if the content is a message. If so, mhn
will use the value "+". */
*return_string = xstrdup (mh_current_folder ());
return store_to_folder_msg;
}
else
str = "%m%P.%s";
}
switch (str[0])
{
case '+':
if (str[1])
*return_string = xstrdup (str);
else
*return_string = xstrdup (mh_current_folder ());
return store_to_folder;
case '-':
*return_string = NULL;
return store_to_stdout;
case '|':
dest = store_to_command;
str = mu_str_skip_class (str + 1, MU_CTYPE_SPACE);
break;
default:
dest = store_to_file;
}
/* Expand macro-notations:
%m message number
......@@ -880,12 +938,12 @@ mhn_store_command (mu_message_t msg, msg_part_t part, char *name)
str = obstack_finish (&stk);
p = mu_str_skip_class (str, MU_CTYPE_SPACE);
if (!*p)
str = NULL;
*return_string = NULL;
else
str = xstrdup (p);
*return_string = xstrdup (p);
obstack_free (&stk, NULL);
return (char*) str;
return dest;
}
......@@ -1539,13 +1597,14 @@ int
store_handler (mu_message_t msg, msg_part_t part, char *type, char *encoding,
void *data)
{
char *prefix = data;
const char *prefix = data;
char *name = NULL;
char *tmp;
char *partstr;
int ismime;
int rc;
mu_stream_t out;
const char *dir = mh_global_profile_get ("mhn-storage", NULL);
enum store_destination dest = store_to_file;
if (mu_message_is_multipart (msg, &ismime) == 0 && ismime)
return 0;
......@@ -1559,6 +1618,7 @@ store_handler (mu_message_t msg, msg_part_t part, char *type, char *encoding,
{
name = normalize_path (dir, val);
free (val);
dest = store_to_file;
}
else if (rc != MU_ERR_NOENT)
{
......@@ -1571,36 +1631,81 @@ store_handler (mu_message_t msg, msg_part_t part, char *type, char *encoding,
}
if (!name)
dest = mhn_store_command (msg, part, prefix, &name);
partstr = msg_part_format (part);
/* Set prefix for diagnostic purposes */
if (!prefix)
prefix = mu_umaxtostr (0, msg_part_subpart (part, 0));
out = NULL;
rc = 0;
switch (dest)
{
char *fname = mhn_store_command (msg, part, prefix);
if (dir)
name = mh_safe_make_file_name (dir, fname);
else
name = fname;
case store_to_folder_msg:
case store_to_folder:
{
mu_mailbox_t mbox = mh_open_folder (name, 1);
size_t uid;
mu_mailbox_uidnext (mbox, &uid);
printf (_("storing message %s part %s to folder %s as message %lu\n"),
prefix, partstr, name, (unsigned long) uid);
if (dest == store_to_folder_msg)
{
mu_body_t body;
mu_stream_t str;
mu_message_t tmpmsg;
rc = mu_message_get_body (msg, &body);
if (rc)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_message_get_body",
NULL, rc);
break;
}
rc = mu_body_get_streamref (body, &str);
if (rc)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_body_get_stream",
NULL, rc);
break;
}
rc = mu_stream_to_message (str, &tmpmsg);
mu_stream_unref (str);
if (rc)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_stream_to_message",
NULL, rc);
break;
}
tmp = msg_part_format (part);
if (prefix)
printf (_("storing message %s part %s as file %s\n"),
prefix,
tmp,
name);
rc = mu_mailbox_append_message (mbox, tmpmsg);
mu_message_destroy (&tmpmsg, mu_message_get_owner (tmpmsg));
}
else
rc = mu_mailbox_append_message (mbox, msg);
if (rc)
mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_append_message", NULL,
rc);
mu_mailbox_close (mbox);
mu_mailbox_destroy (&mbox);
}
break;
case store_to_file:
printf (_("storing message %s part %s as file %s\n"),
mu_umaxtostr (0, msg_part_subpart (part, 0)),
tmp,
name);
free (tmp);
prefix, partstr, name);
if (!(mode_options & OPT_QUIET) && access (name, R_OK) == 0)
{
char *p;
int rc;
int ok;
mu_asprintf (&p, _("File %s already exists. Rewrite"), name);
rc = mh_getyn (p);
ok = mh_getyn (p);
free (p);
if (!rc)
if (!ok)
{
free (name);
return 0;
......@@ -1610,18 +1715,42 @@ store_handler (mu_message_t msg, msg_part_t part, char *type, char *encoding,
rc = mu_file_stream_create (&out, name, MU_STREAM_WRITE|MU_STREAM_CREAT);
if (rc)
{
mu_error (_("cannot create output stream (file %s): %s"),
name, mu_strerror (rc));
free (name);
return rc;
break;
case store_to_command:
/* FIXME: Change to homedir, reflect this in the message below.
Chdir should better be implemented within mu_prog_stream_create
Example message:
storing msg 4 part 1 using command (cd /home/gray; less)
*/
printf (_("storing msg %s part %s using command %s\n"),
prefix, partstr, name);
rc = mu_prog_stream_create (&out, name, MU_STREAM_WRITE);
if (rc)
mu_diag_funcall (MU_DIAG_ERROR, "mu_prog_stream_create", NULL, rc);
break;
case store_to_stdout:
printf (_("storing msg %s part %s to stdout\n"),
prefix, partstr);
rc = mu_stdio_stream_create (&out, MU_STDOUT_FD, 0);
if (rc)
mu_diag_funcall (MU_DIAG_ERROR, "mu_stdio_stream_create", NULL, rc);
break;
}
show_internal (msg, part, encoding, out);
if (out)
{
show_internal (msg, part, encoding, out);
mu_stream_destroy (&out);
}
free (name);
free (partstr);
return 0;
return rc;
}
void
......@@ -2663,7 +2792,9 @@ main (int argc, char **argv)
mu_error (_("extra arguments"));
return 1;
}
message = mh_file_to_message (mu_folder_directory (), input_file);
input_file = mh_expand_name (mu_folder_directory (),
argc == 1 ? argv[0] : "draft", 0);
message = mh_file_to_message (NULL, input_file);
if (!message)
return 1;
}
......@@ -2674,8 +2805,9 @@ main (int argc, char **argv)
mu_error (_("extra arguments"));
return 1;
}
input_file = argc == 1 ? argv[0] : "draft";
message = mh_file_to_message (mu_folder_directory (), input_file);
input_file = mh_expand_name (mu_folder_directory (),
argc == 1 ? argv[0] : "draft", 0);
message = mh_file_to_message (NULL, input_file);
if (!message)
return 1;
}
......@@ -2688,9 +2820,6 @@ main (int argc, char **argv)
switch (mode)
{
case mode_compose:
/* Prepare filename for diagnostic purposes */
if (input_file[0] != '/')
input_file = mh_safe_make_file_name (mu_folder_directory (), input_file);
rc = mhn_compose ();
break;
......
......@@ -49,6 +49,7 @@ TESTSUITE_AT = \
install-mh.at\
mark.at\
mhl.at\
mhn.at\
mhparam.at\
mhpath.at\
mhseq.at\
......
# This file is part of GNU Mailutils. -*- Autotest -*-
# Copyright (C) 2010 Free Software Foundation, Inc.
#
# GNU Mailutils is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 3, or (at
# your option) any later version.
#
# GNU Mailutils is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>.
m4_pushdef([MH_KEYWORDS],[mhn])
dnl -------------------------------------------------------------------
dnl 1. List mode
dnl -------------------------------------------------------------------
MH_CHECK([mhn -list],[mhn00 mhn-list],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
mhn +inbox -list all
],
[0],
[ msg part type/subtype size description
1 text/plain 937
2 text/plain 215
3 multipart/mixed 2K
1 text/plain 230 How doth
2 application/octet-stream 462 Father William Part I
4 multipart/mixed 3K
1 text/plain 341 Father William Part I
2 multipart/mixed 3K
2.1 application/octet-stream 479 Father William Part II
2.2 multipart/mixed 2K
2.2.1 application/octet-stream 483 Father William Part III
2.2.2 application/octet-stream 495 Father William Part IV
5 multipart/mixed 355
1 text/plain 0 Empty part
2 text/plain 1 Single line part
])
MH_CHECK([mhn -list -realsize],[mhn01 mhn-list-realsize],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
mhn +inbox -list -realsize all
],
[0],
[ msg part type/subtype size description
1 text/plain 937
2 text/plain 215
3 multipart/mixed 2K
1 text/plain 230 How doth
2 application/octet-stream 341 Father William Part I
4 multipart/mixed 3K
1 text/plain 341 Father William Part I
2 multipart/mixed 3K
2.1 application/octet-stream 352 Father William Part II
2.2 multipart/mixed 2K
2.2.1 application/octet-stream 357 Father William Part III
2.2.2 application/octet-stream 366 Father William Part IV
5 multipart/mixed 355
1 text/plain 0 Empty part
2 text/plain 1 Single line part
])
dnl -------------------------------------------------------------------
dnl 2. Store mode
dnl -------------------------------------------------------------------
MH_CHECK([mhn -store],[mhn02 mhn-store],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
mhn +inbox -store 4 || exit $?
for file in 4.1.plain 4.2.1.octet-stream 4.2.2.1.octet-stream 4.2.2.2.octet-stream
do
echo == $file ==
cat $file
done
],
[0],
[storing message 4 part 1 as file 4.1.plain
storing message 4 part 2.1 as file 4.2.1.octet-stream
storing message 4 part 2.2.1 as file 4.2.2.1.octet-stream
storing message 4 part 2.2.2 as file 4.2.2.2.octet-stream
== 4.1.plain ==
`You are old, Father William,' the young man said,
`And your hair has become very white;
And yet you incessantly stand on your head--
Do you think, at your age, it is right?'
`In my youth,' Father William replied to his son,
`I feared it might injure the brain;
But, now that I'm perfectly sure I have none,
Why, I do it again and again.'
== 4.2.1.octet-stream ==
`You are old,' said the youth, `as I mentioned before,
And have grown most uncommonly fat;
Yet you turned a back-somersault in at the door--
Pray, what is the reason of that?'
`In my youth,' said the sage, as he shook his grey locks,
`I kept all my limbs very supple
By the use of this ointment--one shilling the box--
Allow me to sell you a couple?'
== 4.2.2.1.octet-stream ==
`You are old,' said the youth, `and your jaws are too weak
For anything tougher than suet;
Yet you finished the goose, with the bones and the beak--
Pray how did you manage to do it?'
`In my youth,' said his father, `I took to the law,
And argued each case with my wife;
And the muscular strength, which it gave to my jaw,
Has lasted the rest of my life.'
== 4.2.2.2.octet-stream ==
`You are old,' said the youth, `one would hardly suppose
That your eye was as steady as ever;
Yet you balanced an eel on the end of your nose--
What made you so awfully clever?'
`I have answered three questions, and that is enough,'
Said his father; `don't give yourself airs!
Do you think I can listen all day to such stuff?
Be off, or I'll kick you down stairs!'
])
m4_popdef[MH_KEYWORDS])
# End of mhn.at
......@@ -63,3 +63,4 @@ m4_include([burst.at])
m4_include([comp.at])
m4_include([forw.at])
m4_include([repl.at])
m4_include([mhn.at])
......