/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999-2021 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 . */
/* MH inc command */
#include
#include "muscript.h"
static char prog_doc[] = N_("Incorporate new mail");
static char extra_doc[] = N_("Debug flags are:\n\
g - guile stack traces\n\
t - sieve trace (MU_SIEVE_DEBUG_TRACE)\n\
i - sieve instructions trace (MU_SIEVE_DEBUG_INSTR)\n\
l - sieve action logs");
static mh_format_t format;
static mh_fvm_t fvm;
static int width;
static mu_list_t input_file_list;
static char *audit_file;
static mu_stream_t audit_stream;
static int changecur = -1;
static int truncate_source = -1;
static int quiet = 0;
static int notify = 0;
static const char *append_folder;
static const char *move_to_mailbox;
static const char *script_file;
static const char *script_lang;
static char const *script_env[] = { "location=MUA", "phase=post", NULL };
static void
add_file (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
{
int rc;
if (!input_file_list)
{
rc = mu_list_create (&input_file_list);
if (rc)
{
mu_diag_funcall (MU_DIAG_ERROR,
"mu_list_create", "&input_file_list", rc);
exit (1);
}
}
rc = mu_list_append (input_file_list, mu_strdup (arg));
if (rc)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_list_append", arg, rc);
exit (1);
}
}
static void
set_debug (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
{
char *p;
if (mu_script_debug_flags (arg, &p))
{
mu_parseopt_error (po, _("invalid debug flag near %s"), p);
exit (po->po_exit_error);
}
}
static struct mu_option options[] = {
{ "file", 0, N_("FILE"), MU_OPTION_DEFAULT,
N_("incorporate mail from named file"),
mu_c_string, NULL, add_file },
{ "folder", 0, N_("FOLDER"), MU_OPTION_DEFAULT,
N_("specify folder to incorporate mail to"),
mu_c_string, &append_folder },
{ "audit", 0, N_("FILE"), MU_OPTION_DEFAULT,
N_("enable audit"),
mu_c_string, &audit_file },
{ "noaudit", 0, NULL, MU_OPTION_DEFAULT,
N_("disable audit"),
mu_c_string, &audit_file, mh_opt_clear_string },
{ "changecur", 0, NULL, MU_OPTION_DEFAULT,
N_("mark first incorporated message as current (default)"),
mu_c_bool, &changecur },
{ "form", 0, N_("FILE"), MU_OPTION_DEFAULT,
N_("read format from given file"),
mu_c_string, &format, mh_opt_parse_formfile },
{ "format", 0, N_("FORMAT"), MU_OPTION_DEFAULT,
N_("use this format string"),
mu_c_string, &format, mh_opt_parse_format },
{ "truncate", 0, NULL, MU_OPTION_DEFAULT,
N_("truncate source mailbox after incorporating (default)"),
mu_c_bool, &truncate_source },
{ "moveto", 0, N_("MAILBOX"), MU_OPTION_DEFAULT,
N_("move incorporated messages to MAILBOX instead of deleting them"),
mu_c_string, &move_to_mailbox },
{ "width", 0, N_("NUMBER"), MU_OPTION_DEFAULT,
N_("set output width"),
mu_c_int, &width },
{ "quiet", 0, NULL, MU_OPTION_DEFAULT,
N_("be quiet"),
mu_c_bool, &quiet },
{ "notify", 0, NULL, MU_OPTION_DEFAULT,
N_("enable biff notification"),
mu_c_bool, ¬ify },
{ "language", 0, N_("LANG"), MU_OPTION_DEFAULT,
N_("set language for the --script option"),
mu_c_string, &script_lang },
{ "script", 0, N_("FILE"), MU_OPTION_DEFAULT,
N_("filter incoming messages using script FILE"),
mu_c_string, &script_file },
{ "debug", 0, N_("FLAGS"), MU_OPTION_DEFAULT,
N_("enable debugging"),
mu_c_string, 0, set_debug },
MU_OPTION_END
};
void
list_message (mu_mailbox_t mbox, size_t msgno)
{
mu_message_t msg;
mu_mailbox_get_message (mbox, msgno, &msg);
mh_fvm_run (fvm, msg);
if (audit_stream)
{
mh_fvm_set_output (fvm, audit_stream);
mh_fvm_run (fvm, msg);
mh_fvm_set_output (fvm, mu_strout);
}
}
struct incdat
{
mu_mailbox_t output;
size_t lastmsg;
mu_script_t handler;
mu_script_descr_t descr;
};
static int
getparam (mu_url_t url, const char *param, const char **sval)
{
int rc = mu_url_sget_param (url, param, sval);
switch (rc)
{
case 0:
case MU_ERR_NOENT:
break;
default:
mu_diag_funcall (MU_DIAG_ERROR, "mu_url_sget_param", param, rc);
exit (1);
}
return rc;
}
static int
incmbx (void *item, void *data)
{
char *input_file = item;
struct incdat *dp = data;
mu_mailbox_t input = NULL;
size_t total, n;
int rc;
int f_truncate = truncate_source;
const char *f_move_to_mailbox = move_to_mailbox, *sval;
mu_url_t url;
if (mu_url_create (&url, input_file) == 0)
{
if (getparam (url, "truncate", &sval) == 0)
{
if (!sval)
f_truncate = 1;
else
f_truncate = is_true (sval);
}
if (getparam (url, "nomoveto", NULL) == 0)
f_move_to_mailbox = NULL;
else
getparam (url, "moveto", &f_move_to_mailbox);
mu_url_destroy (&url);
}
/* Select and open input mailbox */
if (input_file == NULL)
{
if ((rc = mu_mailbox_create_default (&input, NULL)) != 0)
{
mu_error (_("cannot create default mailbox: %s"),
mu_strerror (rc));
exit (1);
}
}
else if ((rc = mu_mailbox_create_default (&input, input_file)) != 0)
{
mu_error (_("cannot create mailbox %s: %s"),
input_file, mu_strerror (rc));
exit (1);
}
if ((rc = mu_mailbox_open (input, MU_STREAM_READ | (f_truncate ? MU_STREAM_WRITE : 0))) != 0)
{
mu_url_t url;
mu_mailbox_get_url (input, &url);
mu_error (_("cannot open mailbox %s: %s"),
mu_url_to_string (url),
mu_strerror (rc));
exit (1);
}
if ((rc = mu_mailbox_messages_count (input, &total)) != 0)
{
mu_error (_("cannot read input mailbox: %s"), mu_strerror (errno));
exit (1);
}
if ((rc = mu_mailbox_get_url (input, &url)) != 0)
{
mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_get_url", input_file, rc);
exit (1);
}
/* Open audit file, if specified */
if (audit_file)
audit_stream = mh_audit_open (audit_file, input);
for (n = 1; n <= total; n++)
{
mu_message_t imsg;
if ((rc = mu_mailbox_get_message (input, n, &imsg)) != 0)
{
mu_error (_("%lu: cannot get message: %s"),
(unsigned long) n, mu_strerror (rc));
continue;
}
if (dp->handler)
{
mu_attribute_t attr;
if (mu_script_process_msg (dp->handler, dp->descr, imsg))
{
mu_error (_("%lu: filter failed: %s"),
(unsigned long) n, mu_strerror (rc));
continue;
}
mu_message_get_attribute (imsg, &attr);
if (mu_attribute_is_deleted (attr))
continue;
}
if ((rc = mu_mailbox_append_message (dp->output, imsg)) != 0)
{
mu_error (_("%lu: error appending message: %s"),
(unsigned long) n, mu_strerror (rc));
continue;
}
if (n == 1 && changecur)
{
mu_message_t msg = NULL;
size_t cur;
mu_mailbox_get_message (dp->output, dp->lastmsg + 1, &msg);
mh_message_number (msg, &cur);
mh_mailbox_set_cur (dp->output, cur);
}
++dp->lastmsg;
if (!quiet)
list_message (dp->output, dp->lastmsg);
if (f_truncate)
{
mu_attribute_t attr;
mu_message_get_attribute (imsg, &attr);
mu_attribute_set_deleted (attr);
}
}
if (total && f_truncate)
{
if (f_move_to_mailbox)
{
mu_msgset_t msgset;
rc = mu_msgset_create (&msgset, input, MU_MSGSET_NUM);
if (rc)
mu_diag_funcall (MU_DIAG_ERROR, "mu_msgset_create", NULL, rc);
else
{
rc = mu_msgset_add_range (msgset, 1, total, MU_MSGSET_NUM);
if (rc)
mu_diag_funcall (MU_DIAG_ERROR, "mu_msgset_add_range",
NULL, rc);
else
{
rc = mu_mailbox_msgset_copy (input, msgset, f_move_to_mailbox,
MU_MAILBOX_COPY_CREAT);
if (rc)
{
mu_error (_("failed to move messages to %s: %s"),
f_move_to_mailbox, mu_strerror (rc));
f_truncate = 0;
}
}
mu_msgset_destroy (&msgset);
}
}
mu_mailbox_expunge (input);
}
if (audit_stream)
{
mh_audit_close (audit_stream);
mu_stream_destroy (&audit_stream);
}
mu_mailbox_close (input);
mu_mailbox_destroy (&input);
return 0;
}
int
main (int argc, char **argv)
{
struct incdat incdat;
int rc;
int f_truncate = 0;
int f_changecur = 0;
size_t lastseen;
const char *unseen_seq;
mh_getopt (&argc, &argv, options, 0, NULL, prog_doc, extra_doc);
if (!append_folder)
append_folder = mh_global_profile_get ("Inbox", "inbox");
if (argc)
{
mu_error (_("unrecognized arguments"));
exit (1);
}
mu_registrar_set_default_scheme ("mh");
/* Inc sets missing cur to 1 */
mh_mailbox_cur_default = 1;
if (!format && !quiet)
format = mh_scan_format ();
mh_fvm_create (&fvm, MH_FMT_FORCENL);
mh_fvm_set_format (fvm, format);
mh_fvm_set_width (fvm, width ? width : mh_width ());
mh_format_destroy (&format);
memset (&incdat, 0, sizeof (incdat));
incdat.output = mh_open_folder (append_folder,
MU_STREAM_READ|MU_STREAM_APPEND|MU_STREAM_CREAT);
if (script_file)
{
if (script_lang)
{
incdat.handler = mu_script_lang_handler (script_lang);
if (!incdat.handler)
{
mu_error (_("unknown or unsupported language: %s"),
script_lang);
exit (1);
}
}
else
{
incdat.handler = mu_script_suffix_handler (script_file);
if (!incdat.handler)
{
mu_error (_("unknown or unsupported language: %s"),
script_file);
exit (1);
}
}
rc = mu_script_init (incdat.handler, script_file, script_env,
&incdat.descr);
if (rc)
{
mu_error (_("script initialization failed: %s"),
mu_strerror (rc));
exit (1);
}
}
if (notify)
{
rc = mu_mailbox_set_notify (incdat.output, NULL);
if (rc)
mu_error (_("failed to set up notification: %s"),
mu_strerror (rc));
}
if ((rc = mu_mailbox_messages_count (incdat.output, &incdat.lastmsg)) != 0)
{
mu_error (_("cannot read output mailbox: %s"),
mu_strerror (errno));
exit (1);
}
lastseen = incdat.lastmsg + 1;
/* Fixup options */
if (!input_file_list)
f_truncate = f_changecur = 1;
if (truncate_source == -1)
truncate_source = f_truncate;
if (changecur == -1)
changecur = f_changecur;
if (!input_file_list)
incmbx (NULL, &incdat);
else
mu_list_foreach (input_file_list, incmbx, &incdat);
if (script_file)
mu_script_done (incdat.handler, incdat.descr);
unseen_seq = mh_global_profile_get ("Unseen-Sequence", NULL);
if (unseen_seq && lastseen < incdat.lastmsg)
{
mu_msgset_t unseen;
mu_msgset_create (&unseen, incdat.output, MU_MSGSET_UID);
mu_msgset_add_range (unseen, lastseen, incdat.lastmsg, MU_MSGSET_NUM);
mh_seq_add (incdat.output, unseen_seq, unseen, 0);
mu_msgset_free (unseen);
}
mh_global_save_state ();
mu_mailbox_close (incdat.output);
mu_mailbox_destroy (&incdat.output);
return 0;
}