Commit af202127 af20212718728b315449ff35685772302883fc3d by Sergey Poznyakoff

Fix operation of mail -t; some other minor fixes

* mail/escape.c (parse_headers): Moved to send.c
(check_headers): New function.
(escape_continue): Use check_headers.
* mail/mail.c (read_recipients): New variable.
The -t option sets read_recipients and editheaders
* mail/mail.h (parse_headers): New proto.
* mail/send.c: Special handling for -t option.
(parse_headers): New function.
* movemail/movemail.c (onerror statement): Accept a list as
argument.

* doc/texinfo/mailutils.texi: Update.
* doc/texinfo/programs.texi: Update.
1 parent edb05144
......@@ -236,7 +236,6 @@ Reading Mail
@command{movemail} --- Moves Mail from the User Maildrop to the Local File
* Movemail Configuration::
* Movemail Options:: Description of the Available Options
* Ownership:: Setting Destination Mailbox Ownership
* Summary:: Short Movemail Invocation Summary
......
......@@ -2742,7 +2742,7 @@ is being sent, etc.
@item trace6
When used together with @samp{prot}, displays security-sensitive
information (such as passwords, user keys, etc). in plaintext. By
default, such information is replaced with asteriscs to reduce the
default, such information is replaced with asterisks to reduce the
possibility of security compromise.
@item trace7
When used together with @samp{prot}, displays the @dfn{payload}
......@@ -2795,10 +2795,10 @@ configuration file statements:
@multitable @columnfractions 0.3 0.6
@headitem Statement @tab Reference
@item debug @tab @xref{Debug Statement}.
@item tls @tab @xref{TLS Statement}.
@item mailbox @tab @xref{Mailbox Statement}.
@item locking @tab @xref{Locking Statement}.
@item debug @tab @xref{debug statement}.
@item tls @tab @xref{tls statement}.
@item mailbox @tab @xref{mailbox statement}.
@item locking @tab @xref{locking statement}.
@end multitable
@subheading @command{frm}
......@@ -2907,10 +2907,9 @@ contents of the user system mailbox. The @option{--file} (@option{-f})
command line option allows to specify another mailbox name. For more
detail, see @ref{Reading Mail}.
In contrast to other GNU Mailutils programs, @command{mail} does not
use the Mailutils configuration file. Instead, it uses the traditional
@samp{mailrc}-style configuration. @xref{Mail Configuration Files},
for a detailed description of its format.
In addition to the Mailutils configuration file, @command{mail} loads
the traditional @samp{mailrc}-style configuration files. @xref{Mail
Configuration Files}, for a detailed description of their format.
@menu
* Invoking Mail:: Command Line Options.
......@@ -2934,49 +2933,72 @@ General usage of @command{mail} program is:
If [@var{address}...] part is present, @command{mail} switches to
mail sending mode, otherwise it operates in mail reading mode.
The program uses following option groups: @FIXME-xref{mailbox}.
@command{Mail} understands following command line options:
@command{Mail} understands the following command line options:
@table @option
@item -e
@itemx --exist
Return true if the mailbox contains some messages. Return false
otherwise.
This is useful for writing shell scripts.
@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.
@item -a @var{header}:@var{value}
@itemx --append=@var{header}:@var{value}
Append the given header to the composed message.
@item --content-type=@var{type}
This options sets the content type to be used by all subsequent
@option{--attach} options.
@item -E @var{command}
@itemx --exec=@var{command}
Execute @var{command} before opening the mailbox. Any number of
@option{--exec} options can be given. The commands will be executed
after sourcing configuration files (@pxref{Mail Configuration Files}),
but before opening the mailbox.
@item -f
@itemx --file
Operate on the mailbox given by the first non-optional command line
argument. If there is no such argument, read messages from the
user's @file{mbox} file. @xref{Reading Mail}, for more details about
using this option.
@item -e
@itemx --exist
Return true if the mailbox contains some messages. Return false
otherwise.
This is useful for writing shell scripts.
@item --encoding=@var{enc}
Sets content transfer encoding for use by the subsequent
@option{--attach} options.
@item -F
@itemx --byname
Record outgoing messages in a file named after the first recipient.
The name is the login-name portion of the address found first on the
@samp{To:} line in the mail header. This option sets the @samp{byname}
variable, which see (@pxref{byname}).
@item -f
@itemx --file
Operate on the mailbox given by the first non-optional command line
argument. If there is no such argument, read messages from the
user's @file{mbox} file. @xref{Reading Mail}, for more details about
using this option.
@item -H
@itemx --headers
Print header summary to stdout and exit.
@item -i
@itemx --ignore
Ignore interrupts.
@item -m @var{path}
@itemx --mail-spool=@var{path}
Set path to the mailspool directory
@item -n
@itemx --norc
Do not read the system-wide mailrc file. @xref{Mail Configuration Files}.
Ignore interrupts when composing the message.
@item -N
@itemx --nosum
Do not display initial header summary.
@item -n
@itemx --norc
Do not read the system-wide mailrc file. @xref{Mail Configuration
Files}.
@item -p
@itemx --print
@itemx --read
......@@ -2990,18 +3012,26 @@ quit
@end example
@noindent
except that @command{mail --print} does not change status of the messages.
@item -r @var{address}
@itemx --return-address=@var{address}
Sets the return email address for outgoing mail. @xref{return-address}.
@item -q
@itemx --quit
Cause interrupts to terminate program.
@item -r @var{address}
@itemx --return-address=@var{address}
Sets the return email address for outgoing mail.
@xref{return-address}.
@item -s @var{subj}
@itemx --subject=@var{subj}
Send a message with a Subject of @var{subj}. Valid only in sending mode.
Send a message with a Subject of @var{subj}. Valid only in sending
mode.
@item -t
@itemx --to
Switch to sending mode.
Read recipients from the message header. Ignore addresses listed in
the command line.
@item -u @var{user}
@itemx --user=@var{user}
Operate on @var{user}'s mailbox. This is equivalent to:
......@@ -3013,16 +3043,11 @@ mail -f/@var{spool_path}/@var{user}
@noindent
with @var{spool_path} being the full path to your mailspool directory
@*(@file{/var/spool/mail} or @file{/var/mail} on most systems).
@item -?
@itemx --help
Display a help message.
@item --usage
Display a short usage summary.
@item -V
@itemx --version
Print program version and exit.
@end table
The program also understands the common mailutils options
(@pxref{Common Options}.
@node Specifying Messages
@subsection How to Specify Message Sets
......@@ -3136,6 +3161,7 @@ The actual escape character may be changed by setting the value of
* Modifying the Headers::
* Enclosing Another Message::
* Adding a File to the Message::
* Attaching a File to the Message::
* Printing And Saving the Message::
* Signing the Message::
* Printing Another Message::
......@@ -3194,6 +3220,7 @@ the headers as well.
@node Modifying the Headers
@subsubsection Modifying the Headers: ~h, ~t, ~c, ~b, ~s
@cindex ~t, mail escape
To add new addresses to the list of message recipients, use @samp{~t}
command, e.g.:
......@@ -3201,15 +3228,19 @@ command, e.g.:
~t name1@@domain.net name2
@end example
@cindex ~c, mail escape
@cindex ~b, mail escape
To add addresses to @code{Cc} or @code{Bcc}, use @samp{~c} or @samp{~b}
escapes respectively.
@cindex ~s, mail escape
To change the @code{Subject} header, use @samp{~s} escape, e.g.:
@example
~s "Re: your message"
@end example
@cindex ~h, mail escape
Finally, to edit all headers, type @samp{~h} escape. This will present
you with the values of @code{To}, @code{Cc}, @code{Bcc}, and
@code{Subject} headers allowing to edit them with normal text editing
......@@ -3235,6 +3266,8 @@ prepended to each line enclosed.
@node Adding a File to the Message
@subsubsection Adding a File to the Message: ~r and ~d
@cindex ~r, mail escape
@cindex ~<, mail escape
To append the contents of file @var{filename} to the message, type
@example
......@@ -3248,12 +3281,56 @@ or
@end example
@noindent
@cindex ~d, mail escape
The @samp{~d} escape is a shorthand for
@example
~r dead.letter
@end example
@node Attaching a File to the Message
@subsubsection Attaching a File to the Message
@cindex ~+, mail escape
The @samp{~+} escape attaches a file to the message. It takes one to
three arguments. The first argument supplies the name of the file to
attach:
@example
~+ myfile.txt
@end example
The file will be attached with default content-type
@samp{application/octet-stream}, and encoding @samp{base64}
(these can be altered by the @option{--content-type} and
@option{--encoding} command line options, correspondingly).
Optional second argument defines the content type to be used instead
of the default one. Optional third argument defines the encoding,
e.g.:
@example
~+ myfile.html text/html base64
@end example
@cindex ~l, mail escape
To list the files attached so far, use the @samp{~l} escape:
@example
~l
1 myfile.html text/html base64
@end example
Each line of the listing contains the ordinal number of the attachment,
the name of the file, content-type and transfer encoding used.
@cindex ~^, mail escape
The @samp{~^} escape removes attachments. Its argument is the number
of the attachment to remove, e.g.:
@example
~^ 1
@end example
@node Printing And Saving the Message
@subsubsection Printing And Saving the Message
@kyindex ~p, mail escape
......@@ -4692,7 +4769,7 @@ The program is started with the @option{--print} (@option{-p}) command
line option (@pxref{Invoking Mail}).
@item read
The progran operates in read mode. This is the default.
The program operates in read mode. This is the default.
@item send
The program operates in send mode. This means it was given one or more
......@@ -4992,7 +5069,7 @@ variables. Also, if the user is trying to set an unknown variable,
@*Type: Boolean.
@*Default: False.
If this variable is set, the listing ouput by @command{set} contains short
If this variable is set, the listing output by @command{set} contains short
descriptions before each variable. @xref{Setting and Unsetting the Variables}.
@kwindex verbose
......@@ -5021,8 +5098,9 @@ X-Mailer: mail (GNU Mailutils @value{VERSION})
@node Mail Configuration Files
@subsection Personal and System-wide Configuration Files
Upon startup, @command{mail} reads the contents of the two command files:
the system-wide configuration file, and the user's configuration
After processing the usual Mailutils configuration files
(@pxref{configuration}), @command{mail} reads the contents of the two
command files: the system-wide command file, and the user's command
file. Each line read from these files is processed like a usual
@command{mail} command.
......@@ -5040,7 +5118,6 @@ package via @option{--with-mail-rc} option. It defaults to
@node messages
@section @command{messages} --- Count the Number of Messages in a Mailbox
@pindex messages
@UNREVISED
@command{Messages} prints on standard output the number of messages
contained in each folder specified in command line. If no folders
......@@ -5055,18 +5132,19 @@ Number of messages in @var{folder}: @var{number}
where @var{folder} represents the folder name, @var{number} represents
the number of messages.
Following configuration file statements affect the behaviour of
The following configuration file statements affect the behaviour of
@command{messages}:
@multitable @columnfractions 0.3 0.6
@headitem Statement @tab Reference
@item debug @tab @xref{Debug Statement}.
@item tls @tab @xref{TLS Statement}.
@item mailbox @tab @xref{Mailbox Statement}.
@item locking @tab @xref{Locking Statement}.
@item debug @tab @xref{debug statement}.
@item tls @tab @xref{tls statement}.
@item mailbox @tab @xref{mailbox statement}.
@item locking @tab @xref{locking statement}.
@end multitable
The program accepts following command line options:
In addition to the common mailutils options (@pxref{Common Options}),
the program accepts the following command line options:
@table @option
@item -q
......@@ -5074,22 +5152,12 @@ The program accepts following command line options:
@itemx -s
@itemx --silent
Be quiet. Display only number of messages per mailbox, without leading text.
@item -?
@itemx --help
Output help message and exit.
@item --usage
Output short usage summary and exit.
@item -V
@itemx --version
Output program version and exit.
@end table
@page
@node movemail
@section @command{movemail} --- Moves Mail from the User Maildrop to the Local File
@pindex movemail
@UNREVISED
The purpose of @command{movemail}, as its name implies, is to move mail
from one location to another. For example, the following invocation:
......@@ -5100,11 +5168,10 @@ movemail /var/mail/smith INBOX
@noindent
moves messages from file @file{/var/mail/smith} to file @file{INBOX}.
You will probably never have to run this program manually. It is
intended as a replacement for @command{movemail} from GNU Emacs. The
@command{movemail} program is run by Emacs @code{Rmail}
module. @xref{Rmail,,,emacs,Reading Mail with Rmail}, for detailed
description of @code{Rmail} interface.
The program was initially intended as a replacement for
@command{movemail} from GNU Emacs. The @command{movemail} program is
run by Emacs @code{Rmail} module. @xref{Rmail,,,emacs,Reading Mail
with Rmail}, for detailed description of @code{Rmail} interface.
Mailutils version of @command{movemail} is fully
backward-compatible with its Emacs predecessor, so it should run
......@@ -5113,18 +5180,21 @@ starting from 22.1 contain improved @code{Rmail} interface and
are able to take advantage of all new features mailutils
@command{movemail} provides.
Apart from that use, @command{movemail} proved to be a useful tool for
incorporating mail from remote mailboxes into the local one. See
@uref{http://mailutils.org/wiki/Fetching_Mail_with_Movemail, Fetching
Mail with Movemail}, for a detailed discussion with usage recipes.
@menu
* Movemail Configuration::
* Movemail Options:: Description of the Available Options
* Ownership:: Setting Destination Mailbox Ownership
* Summary:: Short Movemail Invocation Summary
@end menu
@node Movemail Configuration
@subsection Movemail Configuration
@UNREVISED
Following configuration file statements affect the behavior of
@cindex movemail, configuration
The following configuration file statements affect the behavior of
@command{movemail}:
@deffn {Movemail Config} preserve @var{bool}
......@@ -5139,7 +5209,7 @@ If @var{bool} is @samp{true}, reverse message sorting order.
If @var{bool} is @samp{true}, output information used by Emacs rmail interface.
@end deffn
@deffn {Movemail Config} ignore-erros @var{bool}
@deffn {Movemail Config} ignore-errors @var{bool}
Continue moving messages after errors. By default,
@command{mailfromd} exits immediately if it cannot copy a message.
@end deffn
......@@ -5149,6 +5219,7 @@ Set program identifier, i.e. a string which will prefix all
diagnostic messages issued by the program. By default, program
name is used.
@anchor{movemail-program-id}
The @var{fmt} is a format string that may contain references to the
following variables (@pxref{Variables}):
......@@ -5224,101 +5295,145 @@ Make destination mailbox owned by @var{user}.
@end table
@end deffn
@multitable @columnfractions 0.3 0.6
@headitem Statement @tab Reference
@item debug @tab @xref{Debug Statement}.
@item tls @tab @xref{TLS Statement}.
@item mailbox @tab @xref{Mailbox Statement}.
@item locking @tab @xref{Locking Statement}.
@item pam @tab @xref{PAM Statement}.
@item sql @tab @xref{SQL Statement}.
@item virtdomain @tab @xref{Virtdomain Statement}.
@item radius @tab @xref{Radius Statement}.
@item ldap @tab @xref{LDAP Statement}.
@item auth @tab @xref{Auth Statement}.
@end multitable
@deffn {Movemail Config} max-messages @var{count}
Defines upper limit on the number of moved messages. Movemail will
stop after transferring @var{count} messages.
@node Movemail Options
@subsection Movemail Options
@UNREVISED
By default, the number of messages is not limited.
@end deffn
This subsection discusses @command{movemail} options from the point of
view of an Emacs @code{Rmail} user.
@anchor{movemail-onerror}
@deffn {Movemail Config} onerror @var{actions}
Defines what to do if an error occurs when transferring a message.
@var{actions} is a list of one or more of the following keywords:
To set various options to @command{movemail} from @code{Rmail}, use
@code{rmail-movemail-flags} variable, or @samp{Rmail Movemail Flags}
section from the menu.
@table @asis
@item abort
Abort the transfer and terminate the program. This is the default
action.
Some POP servers return messages in reversed order. To fix the
order, use @option{-p} option or its synonym @option{--reverse}.
@item skip
Skip to the next message.
If the remote server supports @acronym{TLS} encryption, use
@option{--tls} to instruct @command{movemail} to initiate encrypted
connection.
@item delete
Delete the affected message.
@item count
Count this message as processed.
@end table
Each keyword can be prefixed with @samp{no} to reverse its meaning.
@end deffn
The following standard Mailutils statements are supported:
@multitable @columnfractions 0.3 0.6
@headitem Statement @tab Reference
@item debug @tab @xref{debug statement}.
@item tls @tab @xref{tls statement}.
@item mailbox @tab @xref{mailbox statement}.
@item locking @tab @xref{locking statement}.
@item pam @tab @xref{pam statement}.
@item sql @tab @xref{sql statement}.
@item virtdomain @tab @xref{virtdomain statement}.
@item radius @tab @xref{radius statement}.
@item ldap @tab @xref{ldap statement}.
@item auth @tab @xref{auth statement}.
@end multitable
@node Ownership
@subsection Setting Destination Mailbox Ownership
@UNREVISED
@node Summary
@subsection Movemail Usage Summary
@example
movemail [@var{option}...] @var{inbox} @var{destfile} [@var{remote-password}]
movemail [@var{option}...] @var{inbox} @var{destfile} [@var{password}]
@end example
The first argument, @var{inbox}, is the @acronym{url} (@FIXME-pxref{URL}) of
The first argument, @var{inbox}, is the @acronym{url} (@pxref{Mailbox}) of
the source mailbox. The second argument, @var{destfile}, traditionally
means destination file, i.e. the UNIX mailbox to copy messages
to. However, mailutils @command{movemail} extends the meaning of this
parameter. You may actually specify any valid @acronym{URL} as
parameter. You may actually specify any valid @acronym{url} as
@var{destfile} parameter.@footnote{Rmail does not use this
feature}. Finally, optional third argument is a traditional way of
specifying user passwords for remote (@acronym{POP} or @acronym{IMAP})
mailboxes.
feature}.
For compatibility with older implementations of @command{movemail},
the @var{source} argument can also have the form:
@example
po:@var{username}[:@var{pop-server}]
@end example
@noindent
where @var{pop-server} is the IP address or hostname of a POP3 server
to connect to and @var{username} is the name of the user on that
server. The password is then supplied by the third argument.
Following is the summary of available command line options:
It is equivalent to the following URL:
@example
pop://@var{username}[:@var{password}]@@@var{pop-server}
@end example
In fact, whenever @var{source} refers to a remote mailbox, the
@var{password} argument can be used to pass the password. However,
the safer @dfn{ticket} method is of course preferred.
Options are one or more of the following:
@table @option
@item --emacs
Output information used by Emacs rmail interface
Output information used by Emacs @code{rmail} interface.
@item --ignore-errors
Continue moving messages after an error occurs.
Try to continue after errors.
@item --max-messages=@var{count}
Process at most @var{count} messages.
@item --notify
Enable biff notification.
@item --onerror=@var{kw}[,@var{kw}...]
What to do on errors. @xref{movemail-onerror, onerror statement}, for
a description of @var{kw}.
@item -P @var{modelist}
@itemx --owner=@var{modelist}
Control mailbox ownership. @var{modelist} is a comma-separated list
of one or more ownership change methods.
@xref{mailbox-ownership-methods}, for a description of available
methods.
This option is useful only when running @command{movemail} as root.
@item -p
@itemx --preserve
@itemx --keep-messages
Preserve the source mailbox
Don't remove transferred messages from the source mailbox.
@item --program-id=@var{fmt}
Set program identifier for diagnostic purposes. See @ref{Movemail
Configuration,program-id}, for a detailed discussion of this feature.
Set program identifier for diagnostics (default: the program name).
@xref{movemail-program-id}, for a description of its argument.
@item -r
@itemx --reverse
Reverse the sorting order
@item --tls[=@var{bool}]
Enable (default) or disable TLS support
Reverse the order of retrieved messages.
@item -u
@item --uidl
@itemx --uidl
Use UIDLs to avoid downloading the same message twice.
@item -P @var{method-list}
@itemx --owner=@var{method-list}
Define list of methods for setting ownership of the destination
mailbox. @xref{mailbox-ownership-methods}, for a description of
@var{method-list}. This option is useful only when running
@command{movemail} as root.
@item -v
@item --verbose
@itemx --verbose
Increase verbosity level.
@end table
The common options are also understood (@pxref{Common Options}).
@page
@node readmsg
@section @command{readmsg} --- Extract Messages from a Folder
......@@ -5398,6 +5513,8 @@ A whitespace or coma separated list of header names to show per message.
Default is @option{--weedlist="From Subject Date To CC Apparently-"}.
@end table
See also @ref{Common Options}.
@node Conf-readmsg
@subsection Configuration of @command{readmsg}.
......@@ -7997,7 +8114,7 @@ run:
mailutils filter --list
@end example
Filters are applied in the order of their appearence, from left to
Filters are applied in the order of their appearance, from left to
right and operate in encode mode. The plus sign has the same meaning
as pipe in shell. The default mode can be changed using the
@option{--decode} (@option{-d}) and @option{--encode} (@option{-e}) options.
......@@ -8050,7 +8167,7 @@ configuration file processing.
@node mailutils acl
@subsection mailutils acl
The @command{mailutils acl} command tests Mailutils Access Control Lists. By
default it reads ACL from the Mailutils configiration file section
default it reads ACL from the Mailutils configuration file section
@samp{acl}. The command takes a list of IP addresses as its
arguments, applies the ACL to each of them in turn and prints the result.
......@@ -8166,7 +8283,7 @@ smtp://bar@@gnu.org: /home/@var{user}/.mu-tickets:2: smtp://bar:***@@gnu.org
@end example
As you see, even in that case the tool hides the actual password part
by replacing it with three asteriscs. If you are working in a secure
by replacing it with three asterisks. If you are working in a secure
environment, you can tell @command{mu wicket} to show passwords as
well, by supplying the @option{-v} option twice.
......@@ -8395,7 +8512,7 @@ As of version @value{VERSION}, @command{mailutils dbm} supports two formats
for dumping DBM databases. Both formats are line-oriented. Comments
are introduced with a sharp (@samp{#}) sign in the column 0 of a line,
followed by at least one white space character (space or tab). Sharp
sign followed by a colon (@samp{#:}) introduces a @dfn{paragmatic
sign followed by a colon (@samp{#:}) introduces a @dfn{pragmatic
comment}, which carries some additional information to the loader.
@anchor{dump version 0.0}
......
......@@ -37,119 +37,26 @@ dump_headers (mu_stream_t out, compose_env_t *env)
mu_stream_destroy (&stream);
}
#define STATE_INIT 0
#define STATE_READ 1
#define STATE_BODY 2
static int
parse_headers (mu_stream_t input, compose_env_t *env)
check_headers (mu_stream_t input, compose_env_t *env)
{
int status;
mu_header_t header;
char *name = NULL;
char *value = NULL;
int state = STATE_INIT;
char *buf = NULL;
size_t size = 0, n;
int errcnt = 0, line = 0;
char *p;
if ((status = mu_header_create (&header, NULL, 0)) != 0)
{
mu_error (_("Cannot create header: %s"), mu_strerror (status));
return 1;
}
mu_stream_seek (input, 0, MU_SEEK_SET, NULL);
while (state != STATE_BODY &&
errcnt == 0 &&
mu_stream_getline (input, &buf, &size, &n) == 0 && n > 0)
switch (parse_headers (input, env))
{
mu_rtrim_class (buf, MU_CTYPE_SPACE);
line++;
switch (state)
{
case STATE_INIT:
if (!buf[0] || mu_isspace (buf[0]))
continue;
else
state = STATE_READ;
/*FALLTHRU*/
case STATE_READ:
if (buf[0] == 0)
state = STATE_BODY;
else if (mu_isspace (buf[0]))
{
/* A continuation line */
if (name)
{
char *p = NULL;
mu_asprintf (&p, "%s\n%s", value, buf);
free (value);
value = p;
}
else
{
mu_error (_("%d: not a header line"), line);
errcnt++;
}
}
else
{
char *p;
if (name)
{
mu_header_set_value (header, name, value[0] ? value : NULL, 0);
free (name);
free (value);
name = value = NULL;
}
p = strchr (buf, ':');
if (p)
{
*p++ = 0;
while (*p && mu_isspace (*p))
p++;
value = mu_strdup (p);
name = mu_strdup (buf);
}
else
{
mu_error (_("%d: not a header line"), line);
errcnt++;
}
}
break;
}
case parse_headers_ok:
return 0;
case parse_headers_fatal:
return -1;
case parse_headers_error:
break;
}
free (buf);
if (name)
{
mu_header_set_value (header, name, value, 0);
free (name);
free (value);
}
if (errcnt)
{
char *p;
mu_header_destroy (&header);
p = ml_readline (_("Edit again?"));
if (mu_true_answer_p (p) == 1)
return -1;
else
return 1;
}
mu_header_destroy (&env->header);
env->header = header;
return 0;
}
p = ml_readline (_("Edit again?"));
return mu_true_answer_p (p);
}
static void
escape_continue (void)
{
......@@ -386,7 +293,7 @@ escape_run_editor (char *ed, int argc, char **argv, compose_env_t *env)
return rc;
}
}
while ((rc = parse_headers (tempstream, env)) < 0);
while (check_headers (tempstream, env));
}
else
{
......
......@@ -23,6 +23,7 @@
mu_mailbox_t mbox; /* Mailbox being operated upon */
size_t total; /* Total number of messages in the mailbox */
int interactive; /* Is the session interactive */
int read_recipients; /* Read recipients from the message (mail -t) */
static mu_list_t command_list;/* List of commands to be executed after parsing
command line */
......@@ -72,6 +73,8 @@ cli_command_option (struct mu_parseopt *po, struct mu_option *opt,
break;
case 't':
read_recipients = 1;
util_cache_command (&command_list, "set editheaders");
util_cache_command (&command_list, "setq mode=send");
break;
......@@ -186,7 +189,7 @@ static struct mu_option mail_options[] = {
mu_c_string, NULL, cli_subject },
{ "to", 't', NULL, MU_OPTION_DEFAULT,
N_("precede message by a list of addresses"),
N_("read recipients from the message header"),
mu_c_string, NULL, cli_command_option },
{ "user", 'u', N_("USER"), MU_OPTION_DEFAULT,
......@@ -227,7 +230,7 @@ static struct mu_cli_setup cli = {
options,
NULL,
N_("GNU mail -- process mail messages.\n"
"If -f or --file is given, mail operates on the mailbox named "
"If -f or --file is given, mail operates on the mailbox named "
"by the first argument, or the user's mbox, if no argument given."),
N_("[address...]"),
alt_args,
......@@ -421,6 +424,12 @@ main (int argc, char **argv)
/* argument parsing */
mu_cli (argc, argv, &cli, mail_capa, NULL, &argc, &argv);
if (read_recipients)
{
argv += argc;
argc = 0;
}
if ((hint & (HINT_SEND_MODE|HINT_FILE_OPTION)) ==
(HINT_SEND_MODE|HINT_FILE_OPTION))
{
......
......@@ -288,6 +288,15 @@ extern int escape_attach (int argc, char **argv, compose_env_t *env);
extern int escape_remove_attachment (int argc, char **argv,
compose_env_t *env);
enum
{
parse_headers_ok,
parse_headers_error,
parse_headers_fatal
};
extern int parse_headers (mu_stream_t input, compose_env_t *env);
/* Cursor */
extern void set_cursor (unsigned value);
extern size_t get_cursor (void);
......
......@@ -488,8 +488,42 @@ mail_send (int argc, char **argv)
compose_init (&env);
if (argc < 2)
compose_header_set (&env, MU_HEADER_TO, ml_readline_with_intr ("To: "),
COMPOSE_REPLACE);
{
if (interactive)
compose_header_set (&env, MU_HEADER_TO, ml_readline_with_intr ("To: "),
COMPOSE_REPLACE);
else if (!mailvar_get (NULL, "editheaders", mailvar_type_boolean, 0))
{
if (parse_headers (mu_strin, &env) != parse_headers_ok)
{
mu_error ("%s", _("Errors parsing message"));
exit (EXIT_FAILURE);
}
if (add_header_list)
{
mu_iterator_t itr;
mu_list_get_iterator (add_header_list, &itr);
for (mu_iterator_first (itr); !mu_iterator_is_done (itr);
mu_iterator_next (itr))
{
struct add_header *hp;
int mode;
if (mu_iterator_current (itr, (void**) &hp))
break;
mode = hp->mode;
if (mu_header_sget_value (env.header, hp->name, NULL) == 0)
mode = COMPOSE_REPLACE;
compose_header_set (&env, hp->name, hp->value, hp->mode);
}
mu_iterator_destroy (&itr);
}
}
else
{
mu_error ("%s", _("No recipients specified"));
exit (EXIT_FAILURE);
}
}
else
{
while (--argc)
......@@ -511,27 +545,137 @@ mail_send (int argc, char **argv)
}
}
if (mailvar_get (NULL, "mailx", mailvar_type_boolean, 0))
read_cc_bcc (&env);
if (mailvar_get (NULL, "asksub", mailvar_type_boolean, 0) == 0)
compose_header_set (&env, MU_HEADER_SUBJECT,
ml_readline_with_intr ("Subject: "), COMPOSE_REPLACE);
if (interactive)
{
if (mailvar_get (NULL, "mailx", mailvar_type_boolean, 0))
read_cc_bcc (&env);
if (mailvar_get (NULL, "asksub", mailvar_type_boolean, 0) == 0)
compose_header_set (&env, MU_HEADER_SUBJECT,
ml_readline_with_intr ("Subject: "),
COMPOSE_REPLACE);
}
status = mail_send0 (&env, save_to);
compose_destroy (&env);
return status;
}
int
parse_headers (mu_stream_t input, compose_env_t *env)
{
int status;
mu_header_t header;
char *name = NULL;
char *value = NULL;
enum { STATE_INIT, STATE_READ, STATE_BODY } state = STATE_INIT;
char *buf = NULL;
size_t size = 0, n;
int errcnt = 0, line = 0;
if ((status = mu_header_create (&header, NULL, 0)) != 0)
{
mu_error (_("Cannot create header: %s"), mu_strerror (status));
return parse_headers_fatal;
}
while (state != STATE_BODY &&
errcnt == 0 &&
mu_stream_getline (input, &buf, &size, &n) == 0 && n > 0)
{
mu_rtrim_class (buf, MU_CTYPE_SPACE);
line++;
switch (state)
{
case STATE_INIT:
if (!buf[0] || mu_isspace (buf[0]))
continue;
else
state = STATE_READ;
/*FALLTHRU*/
case STATE_READ:
if (buf[0] == 0)
state = STATE_BODY;
else if (mu_isspace (buf[0]))
{
/* A continuation line */
if (name)
{
char *p = NULL;
mu_asprintf (&p, "%s\n%s", value, buf);
free (value);
value = p;
}
else
{
mu_error (_("%d: not a header line"), line);
errcnt++;
}
}
else
{
char *p;
if (name)
{
mu_header_set_value (header, name, value[0] ? value : NULL, 0);
free (name);
free (value);
name = value = NULL;
}
p = strchr (buf, ':');
if (p)
{
*p++ = 0;
while (*p && mu_isspace (*p))
p++;
value = mu_strdup (p);
name = mu_strdup (buf);
}
else
{
mu_error (_("%d: not a header line"), line);
errcnt++;
}
}
break;
default:
abort ();
}
}
free (buf);
if (name)
{
mu_header_set_value (header, name, value, 0);
free (name);
free (value);
}
if (errcnt)
{
mu_header_destroy (&header);
return parse_headers_error;
}
mu_header_destroy (&env->header);
env->header = header;
return parse_headers_ok;
}
void
compose_init (compose_env_t * env)
compose_init (compose_env_t *env)
{
memset (env, 0, sizeof (*env));
mu_list_foreach (add_header_list, seed_headers, env);
}
int
compose_header_set (compose_env_t * env, const char *name,
compose_header_set (compose_env_t *env, const char *name,
const char *value, int mode)
{
int status;
......@@ -601,7 +745,7 @@ compose_header_set (compose_env_t * env, const char *name,
}
char *
compose_header_get (compose_env_t * env, char *name, char *defval)
compose_header_get (compose_env_t *env, char *name, char *defval)
{
char *p;
......
......@@ -226,8 +226,8 @@ static const struct mail_escape_entry mail_escape_table[] = {
{"!", "!", "![shell-command]", escape_shell },
{":", ":", ":[mail-command]", escape_command },
{"-", "-", "-[mail-command]", escape_command },
{"+", "+", "+[name [content-type [encoding]]]", escape_attach },
{"^", "^", "^[N]", escape_remove_attachment },
{"+", "+", "+name [content-type [encoding]]", escape_attach },
{"^", "^", "^N", escape_remove_attachment },
{"?", "?", "?", escape_help },
{"A", "A", "A", escape_sign },
{"a", "a", "a", escape_sign },
......
......@@ -194,51 +194,54 @@ set_mailbox_ownership_list (char const *str)
}
static int
set_onerror_action (char const *str)
set_onerror_action (void *item, void *data)
{
struct mu_wordsplit ws;
static struct mu_kwd onerror_kw[] = {
{ "skip", ONERROR_SKIP },
{ "delete", ONERROR_DELETE },
{ "count", ONERROR_COUNT },
{ NULL }
};
int i, flag;
char *str = item;
if (strcmp (str, "abort") == 0)
onerror_flags = 0;
else
{
onerror_flags = 0;
return 0;
}
ws.ws_delim = ",";
if (mu_wordsplit (str, &ws,
MU_WRDSF_NOVAR | MU_WRDSF_NOCMD |
MU_WRDSF_DELIM | MU_WRDSF_WS))
{
mu_error (_("cannot split argument: %s"), mu_wordsplit_strerror (&ws));
return 1;
}
for (i = 0; i < ws.ws_wordc; i++)
{
int clr = 0;
char *name = ws.ws_wordv[i];
if (strncmp (name, "no", 2) == 0)
static struct mu_kwd onerror_kw[] = {
{ "skip", ONERROR_SKIP },
{ "delete", ONERROR_DELETE },
{ "count", ONERROR_COUNT },
{ NULL }
};
int flag, clr = 0;
if (strncmp (str, "no", 2) == 0)
{
clr = 1;
name += 2;
str += 2;
}
if (mu_kwd_xlat_name (onerror_kw, str, &flag))
{
mu_error (_("unknown keyword: %s"), str);
return 1;
}
if (mu_kwd_xlat_name (onerror_kw, name, &flag))
mu_error (_("unknown keyword: %s"), ws.ws_wordv[i]);
if (clr)
onerror_flags &= ~flag;
else
onerror_flags |= flag;
}
mu_wordsplit_free (&ws);
return 0;
}
static int
set_onerror_actions (char const *str)
{
mu_list_t list;
int rc;
mu_list_create (&list);
mu_list_set_destroy_item (list, mu_list_free_item);
mu_string_split (str, ",", list);
rc = mu_list_foreach (list, set_onerror_action, NULL);
mu_list_destroy (&list);
return rc;
}
static void
cli_mailbox_ownership (struct mu_parseopt *po, struct mu_option *opt,
char const *arg)
......@@ -250,7 +253,7 @@ cli_mailbox_ownership (struct mu_parseopt *po, struct mu_option *opt,
static void
cli_onerror (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
{
if (set_onerror_action (arg))
if (set_onerror_actions (arg))
exit (po->po_exit_error);
}
......@@ -327,9 +330,20 @@ cb_mailbox_ownership (void *data, mu_config_value_t *val)
static int
cb_onerror (void *data, mu_config_value_t *val)
{
if (mu_cfg_assert_value_type (val, MU_CFG_STRING))
return 1;
return set_onerror_action (val->v.string);
switch (val->type)
{
case MU_CFG_LIST:
mu_list_foreach (val->v.list, set_onerror_action, NULL);
break;
case MU_CFG_STRING:
set_onerror_actions (val->v.string);
break;
default:
mu_error ("%s", _("too many arguments"));
}
return 0;
}
struct mu_cfg_param movemail_cfg_param[] = {
......@@ -360,12 +374,12 @@ struct mu_cfg_param movemail_cfg_param[] = {
{ "ignore-errors", mu_c_bool, &ignore_errors, 0, NULL,
N_("Continue after an error.") },
{ "onerror", mu_cfg_callback, NULL, 0, cb_onerror,
N_("What to do after an error. Argument is a comma-separated list of:\n"
N_("What to do after an error. Argument is a list of:\n"
" abort - terminate the program (the default)\n"
" skip - skip to the next message\n"
" delete - delete this one and to the next message\n"
" count - count this message as processed\n"
"Each keyword can be prefixed with \"no\" to reverse its meaning\n"
"Setting onerror=abort reverts to the default behavior."),
"Each keyword can be prefixed with \"no\" to reverse its meaning."),
N_("arg: list") },
{ NULL }
};
......