summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2017-01-13 14:45:09 +0200
committerSergey Poznyakoff <gray@gnu.org.ua>2017-01-14 00:08:52 +0200
commiteabddf8f5f18afddc13281a5fbaa562f75e76b5f (patch)
treef50191fdbba7ca5b7b7d297e6c0fa93e077f57fd
parent0c76b2b1a4325a8e96292161ee95523ecb6cbc14 (diff)
downloadmailutils-eabddf8f5f18afddc13281a5fbaa562f75e76b5f.tar.gz
mailutils-eabddf8f5f18afddc13281a5fbaa562f75e76b5f.tar.bz2
mail: new options to read attachments from file descriptors
* mail/mail.c (default_encoding,default_content_type) (content_name,content_filename): New statics. (cli_attach): Use the value of --content-name option as the content-type name parameter. The "-" argument instructs the program to read attachment from stdin (eqv --attach-fd=0) (cli_attach_fd): New function. (mail_options): New options: --content-name, --content-filename, --attach-fd * mail/mail.h (send_attach_file_default): Remove. (send_attach_file): New proto. * mail/send.c (atchinfo): New fields: id, name, source. (atchinfo_free): Update. (default_encoding,default_content_type): Remove globals. (send_attach_file): Rewrite. (send_attach_file_default): Remove. (escape_list_attachments): Print attachment identifier instead of the file name, which can be NULL. (saveatt): Use mu_attachment_create and mu_attachment_copy_from_stream. * NEWS: Update. * doc/texinfo/programs.texi: Document the new options.
-rw-r--r--NEWS50
-rw-r--r--doc/texinfo/programs.texi137
-rw-r--r--mail/mail.c54
-rw-r--r--mail/mail.h6
-rw-r--r--mail/send.c111
5 files changed, 321 insertions, 37 deletions
diff --git a/NEWS b/NEWS
index 90ac1884c..79d09c5fe 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
-GNU mailutils NEWS -- history of user-visible changes. 2016-12-17
+GNU mailutils NEWS -- history of user-visible changes. 2017-01-13
Copyright (C) 2002-2017 Free Software Foundation, Inc.
See the end of file for copying conditions.
@@ -7,6 +7,54 @@ Please send mailutils bug reports to <bug-mailutils@gnu.org>.
Version 3.1.90 (Git)
+* mail
+
+** Modifying attachment name and filename
+
+Two new options are provided for modifying attachment name (a.k.a
+description), and file name:
+
+ --content-name=STRING
+ Sets the attachment name (description). Technically speaking, it
+ is the "name" parameter in the Content-Type MIME header.
+
+ --content-filename=NAME
+ Sets the file name (the "filename" parameter in the
+ Content-Description MIME header of the outgoing message.
+
+Both options affect only the next `--attach' or `--attach-fd' option.
+
+* Constructing attachments from command line
+
+The new option `--attach-fd=N' instructs mail to read attachment from
+file descriptor N. By default, the attachments created using this
+option are unnamed, i.e. neither name parameter of the Content-Type
+header, nor the filename parameter of the Content-Disposition header
+are set. Use the --content-name and --content-filename options to
+change these.
+
+The option `--attach-fd=0' causes attachment to be read from the
+standard input. The option `--attach=-' has the same effect. For
+obvious reasons, the interactive mode is suppressed in this case.
+
+The `--attach-fd' option is useful when calling `mail' from another
+program.
+
+Example:
+
+Suppose that the 'mail' binary is opened at file descriptor 5 and
+the mail.c file is opened at descriptor 6, the following command
+line sends them as attachments:
+
+ mail --encoding=base64 \
+ --content-type=application/octet-stream \
+ --content-name="the mail(1) binary" --content-filename="mail" \
+ --attach-fd=5 \
+ --encoding=binary\
+ --content-type=text/plain --content-name="mail.c source file"\
+ --content-filename=mail.c --attach-fd=6 \
+ root@example.org
+
Version 3.1.1 - 2016-12-15
diff --git a/doc/texinfo/programs.texi b/doc/texinfo/programs.texi
index 3e3f98ed7..7d1a6ec52 100644
--- a/doc/texinfo/programs.texi
+++ b/doc/texinfo/programs.texi
@@ -2915,6 +2915,7 @@ Configuration Files}, for a detailed description of their format.
* Invoking Mail:: Command Line Options.
* Specifying Messages:: How to Specify Message Sets.
* Composing Mail:: Composing Mail.
+* Attachments:: Attaching Files.
* Reading Mail:: Reading Mail.
* Scripting:: Scripting.
* Mail Variables:: How to Alter the Behavior of @command{mail}.
@@ -2938,9 +2939,22 @@ mail sending mode, otherwise it operates in mail reading mode.
@table @option
@item -A @var{file}
@itemx --attach=@var{file}
-Attach @var{file} to the composed message. The encoding and content
-type are controlled by the @option{--encoding} and
-@option{--content-type} options, correspondingly.
+Attach @var{file} to the composed message. The encoding, content
+type, and content description are controlled by the
+@option{--encoding}, @option{--content-type}, and
+@option{--content-name} options, correspondingly.
+
+The option @option{--attach=-} instructs @command{mail} to read the
+file to be attached from the standard input. Interactive shell is
+disabled in this case.
+
+@item --attach-fd=@var{fd}
+Read attachment body from the file descriptor @var{fd}. The
+descriptor must be open for reading. This option is useful when
+calling @command{mail} from another program.
+
+See the options @option{--encoding}, @option{--content-type},
+@option{--content-name}, and @option{--content-filename}.
@item -a @var{header}:@var{value}
@itemx --append=@var{header}:@var{value}
@@ -2950,6 +2964,14 @@ Append the given header to the composed message.
This options sets the content type to be used by all subsequent
@option{--attach} options.
+@item --content-filename=@var{name}
+Set the @samp{filename} parameter in the @samp{Content-Disposition}
+header for the next @option{--attach-fd} option.
+
+@item --content-name=@var{text}
+Set the @samp{name} parameter (description) in the @samp{Content-Type}
+header for the next @option{--attach} or @option{--attach-fd} option.
+
@item -E @var{command}
@itemx --exec=@var{command}
Execute @var{command} before opening the mailbox. Any number of
@@ -3412,6 +3434,115 @@ the old contents of your message.
@c *********************************************************************
+@node Attachments
+@subsection Sending Attachments
+
+The simplest way to attach a file from command line is by using the
+@option{--attach} (@option{-A}) option. Its argument specifies the
+file to attach. For example, the following will attach the content
+of the file @file{archive.tar}:
+
+@example
+$ mail --attach=archive.tar
+@end example
+
+By default, the content type will be set to
+@samp{application/octet-stream}, and the attachment will be encoded
+using the @samp{base64} encoding. To change the content type, use the
+@option{--content-type} option. For example, to send an HTML
+attachment:
+
+@example
+$ mail --content-type=text/html --attach=in.html
+@end example
+
+The @option{--content-type} option affects all @option{--attach}
+options that follow it. To change the content type, simply add
+another @option{--content-type} option. For example, to send both
+the HTML file and the archive:
+
+@example
+$ mail --content-type=text/html --attach=in.html \
+ --content-type=application/x-tar --attach=archive.tar
+@end example
+
+Similarly, the encoding to use is set up by the @option{--encoding}
+option. As well as @option{--content-type}, this option affects all
+attachments supplied after it in the command line, until changed by
+the eventual next appearance of the same option. Extending the above
+example:
+
+@example
+$ mail --content-type=text/html --encoding=quoted-printable \
+ --attach=in.html \
+ --content-type=application/x-tar --encoding=base64 \
+ --attach=archive.tar
+@end example
+
+Each attachment can also be assigned a @dfn{description} and a
+@dfn{file name}. Normally, these are the same as the file name
+supplied with the @option{--attach} option. However, you can change
+either or both of them using the @option{--content-name} and
+@option{--content-filename}, correspondingly. Both of these options
+affect only the next @option{--attach} (or @option{--attach-fd}, see
+below) option.
+
+All the examples above will enter the usual interactive shell,
+allowing you to compose the body of the message. If that's not
+needed, the non-interactive use can be forced by redirecting
+@file{/dev/null} to the standard input, e.g.:
+
+@example
+$ mail --attach=archive.tar < /dev/null
+@end example
+
+This will normally produce a message saying:
+
+@example
+mail: Null message body; hope that's ok
+@end example
+
+To suppress this message, unset the @samp{nullbodymsg} variable,
+as shown in the example below:
+
+@example
+$ mail -E 'set nonullbodymsg' --attach=archive.tar < /dev/null
+@end example
+
+The option @option{--attach=-} forces @command{mail} to read the file
+to be attached from the standard input stream. This option implies
+disables the interactive mode and sets @samp{nonullbodymsg}
+implicitly, so that the above example can be rewritten as:
+
+@example
+$ mail --attach=- < archive.tar
+@end example
+
+Special option is provided to facilitate the use of @command{mail}
+in scripts. The @option{--attach-fd=@var{N}} instructs the program to
+read the data to be attached from the file descriptor @var{N}. The
+above example is equivalent to:
+
+@example
+$ mail --attach-fd=0 < archive.tar
+@end example
+
+Attachments created using this option have neither filename not
+description set, so normally the use of @option{--content-name} and/or
+@option{--content-filename} is advised.
+
+@example
+$ mail --subject 'mail(1)' \
+ --content-name="The mail(1) binary" --content-filename="mail" \
+ --attach-fd 5 \
+ --encoding=binary --content-type=text/plain \
+ --content-name="mail.c source file" --content-filename=mail.c \
+ --attach-fd 6 gray@@example.org 5</usr/bin/mail \
+ 6<mailutils/mail/mail.c
+@end example
+
+@c *********************************************************************
+
@node Reading Mail
@subsection Reading Mail
diff --git a/mail/mail.c b/mail/mail.c
index 71fd81280..ca3f08e19 100644
--- a/mail/mail.c
+++ b/mail/mail.c
@@ -35,6 +35,11 @@ const char *program_version = "mail (" PACKAGE_STRING ")";
int hint;
char *file;
char *user;
+
+char *default_encoding;
+char *default_content_type;
+char *content_name;
+char *content_filename;
static void
cli_f_option (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
@@ -134,9 +139,45 @@ cli_append (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
static void
cli_attach (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
{
+ int fd = -1;
+
hint |= HINT_SEND_MODE;
- if (send_attach_file_default (arg))
+ if (strcmp (arg, "-") == 0)
+ {
+ arg = NULL;
+ fd = 0;
+ }
+ if (send_attach_file (fd, arg, content_filename, content_name,
+ default_content_type, default_encoding))
exit (1);
+
+ free (content_name);
+ content_name = NULL;
+ free (content_filename);
+ content_filename = NULL;
+}
+
+static void
+cli_attach_fd (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
+{
+ int rc, fd;
+
+ hint |= HINT_SEND_MODE;
+ rc = mu_str_to_c (arg, mu_c_int, &fd, NULL);
+ if (rc)
+ {
+ mu_parseopt_error (po, _("%s: bad descriptor"), arg);
+ exit (po->po_exit_error);
+ }
+
+ if (send_attach_file (fd, NULL, content_filename, content_name,
+ default_content_type, default_encoding))
+ exit (1);
+
+ free (content_name);
+ content_name = NULL;
+ free (content_filename);
+ content_filename = NULL;
}
static struct mu_option mail_options[] = {
@@ -212,10 +253,21 @@ static struct mu_option mail_options[] = {
N_("set content type for subsequent --attach options"),
mu_c_string, &default_content_type },
+ { "content-name", 0, N_("NAME"), MU_OPTION_DEFAULT,
+ N_("set the Content-Type name parameter for the next --attach option"),
+ mu_c_string, &content_name },
+ { "content-filename", 0, N_("NAME"), MU_OPTION_DEFAULT,
+ N_("set the Content-Disposition filename parameter for the next --attach option"),
+ mu_c_string, &content_filename },
+
{ "attach", 'A', N_("FILE"), MU_OPTION_DEFAULT,
N_("attach FILE"),
mu_c_string, NULL, cli_attach },
+ { "attach-fd", 0, N_("FD"), MU_OPTION_DEFAULT,
+ N_("attach from file descriptor FD"),
+ mu_c_string, NULL, cli_attach_fd },
+
MU_OPTION_END
}, *options[] = { mail_options, NULL };
diff --git a/mail/mail.h b/mail/mail.h
index 7efc0be94..35a81d3a6 100644
--- a/mail/mail.h
+++ b/mail/mail.h
@@ -258,7 +258,11 @@ extern char *mail_expand_name (const char *name);
extern void send_append_header (char const *text);
extern void send_append_header2 (char const *name, char const *value, int mode);
-extern int send_attach_file_default (const char *name);
+extern int send_attach_file (int fd,
+ const char *filename,
+ const char *content_filename,
+ const char *content_name,
+ const char *content_type, const char *encoding);
extern int escape_check_args (int argc, char **argv, int minargs, int maxargs);
diff --git a/mail/send.c b/mail/send.c
index 1ab1c1881..8456ad854 100644
--- a/mail/send.c
+++ b/mail/send.c
@@ -134,55 +134,97 @@ mail_sendheader (int argc, char **argv)
/* Attachments */
struct atchinfo
{
+ char *id;
char *encoding;
char *content_type;
+ char *name;
char *filename;
+ mu_stream_t source;
};
static mu_list_t attlist;
-char *default_encoding;
-char *default_content_type;
-
static void
atchinfo_free (void *p)
{
struct atchinfo *ap = p;
+ free (ap->id);
free (ap->encoding);
free (ap->content_type);
+ free (ap->name);
free (ap->filename);
+ mu_stream_destroy (&ap->source);
free (ap);
}
int
-send_attach_file (const char *name,
+send_attach_file (int fd,
+ const char *realname,
+ const char *content_filename, const char *content_name,
const char *content_type, const char *encoding)
{
int rc;
struct stat st;
struct atchinfo *aptr;
mu_list_t list;
-
- if (stat (name, &st))
+ mu_stream_t stream = NULL;
+ char *id = NULL;
+
+ if (fd >= 0)
{
- if (errno == ENOENT)
+ rc = mu_fd_stream_create (&stream, NULL, fd, MU_STREAM_READ);
+ if (rc)
{
- mu_error (_("%s: file does not exist"), name);
+ mu_error (_("can't open descriptor %d: %s"), fd, mu_strerror (rc));
return 1;
}
- else
+ mu_asprintf (&id, "fd %d", fd);
+ if (fd == 0)
{
- mu_error (_("%s: cannot stat: %s"), name, mu_strerror (errno));
- return 1;
+ mu_stream_destroy (&mu_strin);
+ mu_nullstream_create (&mu_strin, MU_STREAM_READ);
+ mu_stream_ioctl (mu_strin, MU_IOCTL_NULLSTREAM,
+ MU_IOCTL_NULLSTREAM_SET_PATTERN, NULL);
+ util_do_command ("set nullbody nullbodymsg");
}
}
-
- if (!S_ISREG (st.st_mode))
+ else if (realname)
{
- mu_error (_("%s: not a regular file"), name);
- return 1;
- }
+ if (!content_filename)
+ content_filename = realname;
+ if (stat (realname, &st))
+ {
+ if (errno == ENOENT)
+ {
+ mu_error (_("%s: file does not exist"), realname);
+ return 1;
+ }
+ else
+ {
+ mu_error (_("%s: cannot stat: %s"), realname,
+ mu_strerror (errno));
+ return 1;
+ }
+ }
+
+ if (!S_ISREG (st.st_mode))
+ {
+ mu_error (_("%s: not a regular file"), realname);
+ return 1;
+ }
+ rc = mu_mapfile_stream_create (&stream, realname, MU_STREAM_READ);
+ if (rc)
+ {
+ mu_error (_("can't open file %s: %s"),
+ realname, mu_strerror (rc));
+ return 1;
+ }
+ mu_asprintf (&id, "\"%s\"", realname);
+ }
+ else
+ abort ();
+
if (!encoding)
encoding = "base64";
mu_filter_get_list (&list);
@@ -190,6 +232,8 @@ send_attach_file (const char *name,
if (rc)
{
mu_error (_("unsupported encoding: %s"), encoding);
+ free (id);
+ mu_stream_destroy (&stream);
return 1;
}
@@ -205,11 +249,13 @@ send_attach_file (const char *name,
}
aptr = mu_alloc (sizeof (*aptr));
+ aptr->id = id;
aptr->encoding = mu_strdup (encoding);
aptr->content_type = mu_strdup (content_type ?
- content_type :
- "application/octet-stream");
- aptr->filename = mu_strdup (name);
+ content_type : "application/octet-stream");
+ aptr->name = content_name ? mu_strdup (content_name) : NULL;
+ aptr->filename = content_filename ? mu_strdup (content_filename) : NULL;
+ aptr->source = stream;
rc = mu_list_append (attlist, aptr);
if (rc)
{
@@ -220,12 +266,6 @@ send_attach_file (const char *name,
}
int
-send_attach_file_default (const char *name)
-{
- return send_attach_file (name, default_content_type, default_encoding);
-}
-
-int
escape_list_attachments (int argc, char **argv, compose_env_t *env)
{
mu_iterator_t itr;
@@ -246,7 +286,7 @@ escape_list_attachments (int argc, char **argv, compose_env_t *env)
continue;
mu_printf ("%3d %-12s %-30s %-s\n",
- i, aptr->filename, aptr->content_type, aptr->encoding);
+ i, aptr->id, aptr->content_type, aptr->encoding);
}
mu_iterator_destroy (&itr);
@@ -266,7 +306,8 @@ escape_attach (int argc, char **argv, compose_env_t *env)
case 3:
content_type = argv[2];
case 2:
- return send_attach_file (argv[1], content_type, encoding);
+ return send_attach_file (-1, argv[1], argv[1], argv[1],
+ content_type, encoding);
default:
return escape_check_args (argc, argv, 2, 4);
}
@@ -309,12 +350,20 @@ saveatt (void *item, void *data)
int rc;
size_t nparts;
char *p;
-
- rc = mu_message_create_attachment (aptr->content_type, aptr->encoding,
- aptr->filename, &part);
+
+ rc = mu_attachment_create (&part, aptr->content_type, aptr->encoding,
+ aptr->name, aptr->filename);
+ if (rc)
+ {
+ mu_error (_("can't create attachment %s: %s"),
+ aptr->id, mu_strerror (rc));
+ return 1;
+ }
+
+ rc = mu_attachment_copy_from_stream (part, aptr->source, aptr->encoding);
if (rc)
{
- mu_error (_("cannot attach \"%s\": %s"), aptr->filename,
+ mu_error (_("cannot attach %s: %s"), aptr->filename,
mu_strerror (rc));
return 1;
}

Return to:

Send suggestions and report system problems to the System administrator.