summaryrefslogtreecommitdiff
path: root/mail/mailvar.c
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2009-07-12 18:18:43 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2009-07-12 18:18:43 +0300
commit4f12cc0c9924afccb721ef418efe6e83c95c0cd1 (patch)
treed1c788e675d8fd01ae311fac840e4c97f06ead89 /mail/mailvar.c
parent0a7e59334332346755a05df5f85aafdba629d78d (diff)
downloadmailutils-4f12cc0c9924afccb721ef418efe6e83c95c0cd1.tar.gz
mailutils-4f12cc0c9924afccb721ef418efe6e83c95c0cd1.tar.bz2
Further improvements in `mail'.
* NEWS: Update. * mail/mail.h (MOPTF_UNSET): New constant. * mail/mailvar.c (MAILVAR_TYPEMASK): New define. (struct mailvar_symbol): Remove `type'. Add `handler'. The latter supplies special handling for certain variables. (mailvar_tab): Update accordingly. Implement "debug" variable. (mailvar_set): Enforce correct variable type in variable-strict mode. Handle MOPTF_UNSET flag. Remove kludgy special handling for some attributes, use sym->handler instead. (set_decode_fallback, set_replyregex) (set_screen, set_mailbox_debug_level, set_debug): New functions. (describe_symbol): Handle alternative symbol types. * mail/set.c: Use MOPTF_UNSET when unsetting the variable. * mail/source.c: Set correct locus. This allows to display locations along with error messages.
Diffstat (limited to 'mail/mailvar.c')
-rw-r--r--mail/mailvar.c402
1 files changed, 290 insertions, 112 deletions
diff --git a/mail/mailvar.c b/mail/mailvar.c
index 6550b398f..e4d7efc4a 100644
--- a/mail/mailvar.c
+++ b/mail/mailvar.c
@@ -20,160 +20,241 @@
#define MAILVAR_RDONLY 0x0002
#define MAILVAR_HIDDEN 0x0004
+#define MAILVAR_TYPEMASK(type) (1<<(8+(type)))
+
struct mailvar_symbol
{
struct mailvar_variable var;
- enum mailvar_type type;
int flags;
char *descr;
+ void (*handler) (struct mailvar_variable *);
};
mu_list_t mailvar_list = NULL;
+static void set_decode_fallback (struct mailvar_variable *);
+static void set_replyregex (struct mailvar_variable *);
+static void set_screen (struct mailvar_variable *);
+static void set_debug (struct mailvar_variable *);
+
struct mailvar_symbol mailvar_tab[] =
{
+ /* FIXME: */
+ { { "allnet", }, MAILVAR_HIDDEN },
+
/* For compatibility with other mailx implementations.
Never used, always true. */
- { { "append", }, mailvar_type_boolean, MAILVAR_RDONLY,
+ { { "append", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean) | MAILVAR_RDONLY,
N_("messages saved in mbox are appended to the end rather than prepended") },
- { { "appenddeadletter", }, mailvar_type_boolean, 0,
+ { { "appenddeadletter", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("append the contents of canceled letter to dead.letter file") },
- { { "askbcc", }, mailvar_type_boolean, 0,
+ { { "askbcc", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("prompt user for bcc before composing the message") },
- { { "askcc", }, mailvar_type_boolean, 0,
+ { { "askcc", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("prompt user for cc before composing the message") },
- { { "ask", }, mailvar_type_boolean, 0,
+ { { "ask", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("prompt user for subject before composing the message") },
- { { "asksub", }, mailvar_type_whatever, MAILVAR_ALIAS, NULL },
- { { "autoinc", }, mailvar_type_boolean, 0,
+ { { "asksub", }, MAILVAR_ALIAS, NULL },
+ { { "autoinc", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("automatically incorporate newly arrived messages")},
- { { "autoprint", }, mailvar_type_boolean, 0,
+ { { "autoprint", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("delete command behaves like dp") },
- { { "bang", }, mailvar_type_boolean, 0,
+ { { "bang", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("replace every occurrence of ! in arguments to the shell command"
" with the last executed command") },
- { { "charset", }, mailvar_type_string, 0,
+ { { "charset", },
+ MAILVAR_TYPEMASK (mailvar_type_string),
N_("output character set for decoded header fields") },
- { { "cmd", }, mailvar_type_string, 0,
+ { { "cmd", },
+ MAILVAR_TYPEMASK (mailvar_type_string),
N_("default shell command for pipe") },
- { { "columns", }, mailvar_type_number, 0,
+ { { "columns", },
+ MAILVAR_TYPEMASK (mailvar_type_number),
N_("number of columns on terminal screen") },
- { { "crt", }, mailvar_type_number, 0,
+ { { "crt", },
+ MAILVAR_TYPEMASK (mailvar_type_number) |
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("if numeric, sets the minimum number of output lines needed "
"to engage paging; if boolean, use the height of the terminal "
"screen to compute the threshold") },
- { { "datefield", }, mailvar_type_boolean, 0,
+ { { "datefield", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("get date from the `Date:' header, instead of the envelope") },
- { { "dot", }, mailvar_type_boolean, 0,
+ { { "debug", },
+ MAILVAR_TYPEMASK (mailvar_type_string) |
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
+ N_("set Mailutils debug level"),
+ set_debug },
+ { { "decode-fallback", },
+ MAILVAR_TYPEMASK (mailvar_type_string),
+ N_("how to represent characters that cannot be rendered using the "
+ "current character set"),
+ set_decode_fallback },
+ { { "dot", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("input message is terminated with a dot alone on a line") },
- { { "editheaders", }, mailvar_type_boolean, 0,
+ { { "editheaders", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("allow to edit message headers while composing") },
- { { "emptystart", }, mailvar_type_boolean, 0,
+ { { "emptystart", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("start interactive mode if the mailbox is empty") },
- { { "escape", }, mailvar_type_string, 0,
+ { { "escape", },
+ MAILVAR_TYPEMASK (mailvar_type_string),
N_("character denoting escapes") },
- { { "flipr", }, mailvar_type_boolean, 0,
+ { { "flipr", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("swap the meaning of reply and Reply commands") },
- { { "folder", }, mailvar_type_string, 0,
+ { { "folder", },
+ MAILVAR_TYPEMASK (mailvar_type_string),
N_("folder directory name") },
- { { "fromfield", }, mailvar_type_boolean, 0,
+ { { "fromfield", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("get sender address from the `From:' header, instead of "
"the envelope") },
- { { "gnu-last-command", }, mailvar_type_boolean, MAILVAR_RDONLY,
+ { { "gnu-last-command", },
+ MAILVAR_TYPEMASK (mailvar_type_string) | MAILVAR_RDONLY,
N_("last executed command line") },
- { { "header", }, mailvar_type_boolean, 0,
+ { { "header", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("run the `headers' command after entering interactive mode") },
- { { "hold", }, mailvar_type_boolean, 0,
+ { { "hold", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("hold the read or saved messages in the system mailbox") },
- { { "ignore", }, mailvar_type_boolean, 0,
+ { { "ignore", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("ignore keyboard interrupts when composing messages") },
- { { "ignoreeof", }, mailvar_type_boolean, 0,
+ { { "ignoreeof", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("typing the EOF character terminates the letter being composed") },
- { { "indentprefix", }, mailvar_type_string, 0,
+ { { "indentprefix", },
+ MAILVAR_TYPEMASK (mailvar_type_string),
N_("string used by the ~m escape for indenting quoted messages") },
- { { "inplacealiases", }, mailvar_type_boolean, 0,
+ { { "inplacealiases", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("expand aliases in the address header field "
"before entering send mode") },
/* For compatibility with other mailx implementations.
Never used, always true. */
- { { "keep", }, mailvar_type_boolean, MAILVAR_RDONLY,
+ { { "keep", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean) | MAILVAR_RDONLY,
N_("truncate the user's system mailbox when it is empty") },
- { { "keepsave", }, mailvar_type_boolean, 0,
+ { { "keepsave", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("keep saved messages in system mailbox too") },
- { { "mailx", }, mailvar_type_boolean, 0,
+ { { "mailx", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("enable mailx compatibility mode") },
- { { "metamail", }, mailvar_type_boolean, 0,
+ { { "metamail", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("interpret the content of message parts; if set to a string "
"specifies the name of the externam metamail command") },
- { { "metoo", }, mailvar_type_boolean, 0,
+ { { "metoo", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("do not remove sender addresses from the recipient list") },
- { { "mimenoask", }, mailvar_type_string, 0,
+ { { "mimenoask", },
+ MAILVAR_TYPEMASK (mailvar_type_string),
N_("a comma-separated list of MIME types for which "
"no confirmation is needed before running metamail interpreter") },
- { { "mode", }, mailvar_type_string, MAILVAR_RDONLY,
+ { { "mode", },
+ MAILVAR_TYPEMASK (mailvar_type_string) | MAILVAR_RDONLY,
N_("the name of current operation mode") },
- { { "nullbody", }, mailvar_type_boolean, 0,
+ { { "nullbody", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("accept messages with an empty body") },
- { { "nullbodymsg", }, mailvar_type_string, 0,
+ { { "nullbodymsg", },
+ MAILVAR_TYPEMASK (mailvar_type_string),
N_("display this text when sending a message with empty body") },
- { { "outfolder", }, mailvar_type_string, 0,
+ { { "outfolder", },
+ MAILVAR_TYPEMASK (mailvar_type_string),
N_("keep created files in this folder") },
- { { "page", }, mailvar_type_boolean, 0,
+ { { "page", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("pipe command terminates each message with a linefeed") },
- { { "prompt", }, mailvar_type_string, 0,
+ { { "prompt", },
+ MAILVAR_TYPEMASK (mailvar_type_string),
N_("command prompt sequence") },
- { { "quit", }, mailvar_type_boolean, 0,
+ { { "quit", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("keyboard interrupts terminate the program") },
- { { "rc", }, mailvar_type_boolean, 0,
+ { { "rc", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("read the system-wide configuration file upon startup") },
- { { "readonly", }, mailvar_type_boolean, 0,
+ { { "readonly", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("mailboxes are opened in readonly mode") },
- { { "record", }, mailvar_type_string, 0,
+ { { "record", },
+ MAILVAR_TYPEMASK (mailvar_type_string),
N_("save outgoing messages in this file") },
- { { "recursivealiases", }, mailvar_type_boolean, 0,
+ { { "recursivealiases", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("recursively expand aliases") },
- { { "regex", }, mailvar_type_boolean, 0,
+ { { "regex", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("use regular expressions in message specifications") },
- { { "replyprefix", }, mailvar_type_string, 0,
+ { { "replyprefix", },
+ MAILVAR_TYPEMASK (mailvar_type_string),
N_("prefix for the subject line of a reply message") },
- { { "replyregex", }, mailvar_type_string, 0,
- N_("regexp for recognizing subject lines of reply messages") },
- { { "save", }, mailvar_type_boolean, 0,
+ { { "replyregex", },
+ MAILVAR_TYPEMASK (mailvar_type_string),
+ N_("regexp for recognizing subject lines of reply messages"),
+ set_replyregex },
+ { { "save", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("stored aborted messages in the user's dead.file") },
- { { "screen", }, mailvar_type_number, 0,
- N_("number of lines on terminal screen") },
- { { "sendmail", }, mailvar_type_string, 0,
+ { { "screen", },
+ MAILVAR_TYPEMASK (mailvar_type_number),
+ N_("number of lines on terminal screen"),
+ set_screen },
+ { { "sendmail", },
+ MAILVAR_TYPEMASK (mailvar_type_string),
N_("URL of the mail transport agent") },
/* FIXME: Not yet used. */
- { { "sendwait", }, mailvar_type_boolean, MAILVAR_HIDDEN, NULL },
- { { "sign", }, mailvar_type_string, 0,
+ { { "sendwait", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean) | MAILVAR_HIDDEN, NULL },
+ { { "sign", },
+ MAILVAR_TYPEMASK (mailvar_type_string),
N_("signature for use with the ~a command") },
- { { "Sign", }, mailvar_type_string, 0,
+ { { "Sign", },
+ MAILVAR_TYPEMASK (mailvar_type_string),
N_("signature for use with the ~A command") },
- { { "showenvelope", }, mailvar_type_boolean, 0,
+ { { "showenvelope", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("`print' command includes the SMTP envelope in its output") },
- { { "showto", }, mailvar_type_boolean, 0,
+ { { "showto", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("if the message was sent by the user, print its recipient address "
"in the header summary") },
- { { "toplines", }, mailvar_type_number, 0,
+ { { "toplines", },
+ MAILVAR_TYPEMASK (mailvar_type_number),
N_("number of lines to be displayed by `top' or `Top'") },
- { { "verbose", }, mailvar_type_boolean, 0,
- N_("verbosely trace the process of message delivery") },
- { { "xmailer", }, mailvar_type_boolean, 0,
- N_("add the `X-Mailer' header to the outgoing messages") },
-
- { { "variable-pretty-print", }, mailvar_type_boolean, 0,
+ { { "variable-pretty-print", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("print variables with short descriptions") },
- { { "varpp", }, mailvar_type_whatever, MAILVAR_ALIAS },
- { { "variable-strict", }, mailvar_type_boolean, 0,
+ { { "varpp", }, MAILVAR_ALIAS },
+ { { "variable-strict", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("perform strict checking when setting options") },
- { { "varstrict", }, mailvar_type_whatever, MAILVAR_ALIAS },
+ { { "varstrict", }, MAILVAR_ALIAS },
+ { { "verbose", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
+ N_("verbosely trace the process of message delivery") },
+ { { "xmailer", },
+ MAILVAR_TYPEMASK (mailvar_type_boolean),
+ N_("add the `X-Mailer' header to the outgoing messages") },
/* These will be implemented later */
- { { "debug", }, mailvar_type_whatever, MAILVAR_HIDDEN, NULL },
- { { "onehop", }, mailvar_type_whatever, MAILVAR_HIDDEN, NULL },
+ { { "onehop", }, MAILVAR_HIDDEN, NULL },
- { { "quiet", }, mailvar_type_boolean, MAILVAR_HIDDEN,
+ { { "quiet", }, MAILVAR_TYPEMASK (mailvar_type_boolean) | MAILVAR_HIDDEN,
"suppresses the printing of the version when first invoked" },
{ { NULL }, }
@@ -381,12 +462,12 @@ mailvar_set (const char *variable, void *value, enum mailvar_type type,
int flags)
{
struct mailvar_variable *var;
+ const struct mailvar_symbol *sym = find_mailvar_symbol (variable);
+ int unset = flags & MOPTF_UNSET;
if (!(flags & MOPTF_QUIET)
&& mailvar_get (NULL, "variable-strict", mailvar_type_boolean, 0) == 0)
{
- const struct mailvar_symbol *sym = find_mailvar_symbol (variable);
-
if (!sym)
mu_diag_output (MU_DIAG_WARNING, _("setting unknown variable %s"),
variable);
@@ -396,64 +477,149 @@ mailvar_set (const char *variable, void *value, enum mailvar_type type,
variable);
return 1;
}
+ else if (!(sym->flags & MAILVAR_TYPEMASK (type))
+ && !unset)
+ {
+ mu_error (_("Wrong type for %s"), variable);
+ return 1;
+ }
}
- var = mailvar_find_variable (variable, 1);
+ var = mailvar_find_variable (variable, !unset);
if (!var || (var->set && !(flags & MOPTF_OVERWRITE)))
return 0;
mailvar_variable_reset (var);
-
- var->type = type;
- if (value)
+ if (!unset)
{
- var->set = 1;
- switch (type)
+ var->type = type;
+ if (value)
{
- case mailvar_type_number:
- var->value.number = *(int*)value;
- break;
+ var->set = 1;
+ switch (type)
+ {
+ case mailvar_type_number:
+ var->value.number = *(int*)value;
+ break;
- case mailvar_type_string:
- var->value.string = strdup (value);
- break;
+ case mailvar_type_string:
+ var->value.string = strdup (value);
+ break;
- case mailvar_type_boolean:
- var->value.bool = *(int*)value;
- break;
+ case mailvar_type_boolean:
+ var->value.bool = *(int*)value;
+ break;
- default:
- abort();
+ default:
+ abort();
+ }
}
}
/* Special handling for some variables */
- if (strcmp (variable, "replyregex") == 0)
- {
- int rc;
- char *err;
-
- if ((rc = mu_unre_set_regex (value, 0, &err)))
+ if (sym && sym->flags & MAILVAR_TYPEMASK (type) && sym->handler)
+ sym->handler (var);
+
+ return 0;
+}
+
+
+static void
+set_decode_fallback (struct mailvar_variable *var)
+{
+ if (mu_set_default_fallback (var->value.string))
+ mu_error (_("Incorrect value for decode-fallback"));
+}
+
+static void
+set_replyregex (struct mailvar_variable *var)
+{
+ int rc;
+ char *err;
+
+ if ((rc = mu_unre_set_regex (var->value.string, 0, &err)))
+ {
+ if (err)
+ mu_error ("%s: %s", mu_strerror (rc), err);
+ else
+ mu_error ("%s", mu_strerror (rc));
+ }
+}
+
+static void
+set_screen (struct mailvar_variable *var)
+{
+ page_invalidate (1);
+}
+
+static void
+set_mailbox_debug_level (mu_log_level_t level)
+{
+ if (mbox)
+ {
+ mu_debug_t mdbg;
+ mu_mailbox_get_debug (mbox, &mdbg);
+ mu_debug_set_level (mdbg, level);
+ }
+}
+
+#define DEFAULT_DEBUG_LEVEL \
+ (MU_DEBUG_INHERIT | MU_DEBUG_LEVEL_UPTO (MU_DEBUG_TRACE7))
+
+static void
+set_debug (struct mailvar_variable *var)
+{
+ int rc;
+ int argc;
+ char **argv;
+ int i;
+ mu_debug_t dbg;
+
+ mu_global_debug_clear_level (NULL);
+ set_mailbox_debug_level (0);
+
+ if (var->type == mailvar_type_boolean)
+ {
+ if (var->set)
{
- fprintf (stderr, "%s", mu_strerror (rc));
- if (err)
- {
- fprintf (stderr, "%s", err);
- free (err);
- }
- fprintf (stderr, "\n");
+ /* FIXME: What to set here?
+ mu_global_debug_set_level ("*", DEFAULT_DEBUG_LEVEL); */
+ set_mailbox_debug_level (DEFAULT_DEBUG_LEVEL);
}
+ return;
}
- else if (strcmp (variable, "decode-fallback") == 0)
+
+ mu_diag_get_debug (&dbg);
+
+ rc = mu_argcv_get (var->value.string, ";", NULL, &argc, &argv);
+ if (rc)
{
- if (mu_set_default_fallback (value))
- mu_error (_("Incorrect value for decode-fallback"));
+ mu_error (_("Cannot parse string: %s"), mu_strerror (rc));
+ return;
+ }
+
+ for (i = 0; i < argc; i++)
+ {
+ char *p;
+ mu_log_level_t level = MU_DEBUG_INHERIT;
+ char *object_name = argv[i];
+
+ for (p = object_name; *p && *p != '='; p++)
+ ;
+
+ if (*p == '=')
+ {
+ *p++ = 0;
+ mu_debug_level_from_string (p, &level, dbg);
+ }
+ else
+ level |= MU_DEBUG_LEVEL_UPTO (MU_DEBUG_PROT);
+
+ if (strcmp (object_name, "mailbox") == 0)
+ set_mailbox_debug_level (level);
+ mu_global_debug_set_level (object_name, level);
}
- else if (strcmp (variable, "screen") == 0)
- page_invalidate (1);
-
- return 0;
}
@@ -654,6 +820,7 @@ static void
describe_symbol (FILE *out, int width, const struct mailvar_symbol *sym)
{
int n;
+ int i, t;
const struct mailvar_symbol *ali;
n = fprintf (out, "%s", sym->var.name);
@@ -667,7 +834,18 @@ describe_symbol (FILE *out, int width, const struct mailvar_symbol *sym)
}
fputc ('\n', out);
- fprintf (out, _("Type: %s\n"), gettext (typestr[sym->type]));
+ fprintf (out, _("Type: "));
+ for (i = 0, t = 0; i < sizeof (typestr) / sizeof (typestr[0]); i++)
+ if (sym->flags & MAILVAR_TYPEMASK (i))
+ {
+ if (t++)
+ fprintf (out, " %s ", _("or"));
+ fprintf (out, "%s", gettext (typestr[i]));
+ }
+ if (!t)
+ fprintf (out, "%s", gettext (typestr[0]));
+ fputc ('\n', out);
+
fprintf (out, "%s", _("Current value: "));
mailvar_variable_format (out, &sym->var, _("[not set]"));

Return to:

Send suggestions and report system problems to the System administrator.