summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2005-11-29 17:40:43 +0000
committerSergey Poznyakoff <gray@gnu.org.ua>2005-11-29 17:40:43 +0000
commit3ff591fe0535e285d893fff02042ef0ed54a49df (patch)
tree65b09aa0774b48f3a0730f6b9f782d86012d7e48
parent03237b3a2709ccf219afca2c8fdc1e6952ce1dfc (diff)
downloadmailutils-3ff591fe0535e285d893fff02042ef0ed54a49df.tar.gz
mailutils-3ff591fe0535e285d893fff02042ef0ed54a49df.tar.bz2
Add burst.c
-rw-r--r--mh/Makefile.am2
-rw-r--r--mh/burst.c433
2 files changed, 435 insertions, 0 deletions
diff --git a/mh/Makefile.am b/mh/Makefile.am
index c880bf553..fc2f219ae 100644
--- a/mh/Makefile.am
+++ b/mh/Makefile.am
@@ -22,6 +22,7 @@
PROGRAMS_MH = \
ali$(EXEEXT)\
anno$(EXEEXT)\
+ burst$(EXEEXT)\
comp$(EXEEXT)\
fmtcheck$(EXEEXT)\
folder$(EXEEXT)\
@@ -47,6 +48,7 @@ PROGRAMS_MH = \
EXTRA_PROGRAMS = \
ali\
anno\
+ burst\
comp\
fmtcheck\
folder\
diff --git a/mh/burst.c b/mh/burst.c
new file mode 100644
index 000000000..d7373110c
--- /dev/null
+++ b/mh/burst.c
@@ -0,0 +1,433 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2005 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 2, 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, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ MA 02110-1301 USA */
+
+/* MH burst command */
+
+#include <mh.h>
+#define obstack_chunk_alloc malloc
+#define obstack_chunk_free free
+#include <obstack.h>
+
+const char *program_version = "burst (" PACKAGE_STRING ")";
+/* TRANSLATORS: Please, preserve the vertical tabulation (^K character)
+ in this message */
+static char doc[] = N_("GNU MH burst\v\
+Options marked with `*' are not yet implemented.\n\
+Use -help to obtain the list of traditional MH options.");
+static char args_doc[] = "[msgs]";
+
+/* GNU options */
+static struct argp_option options[] = {
+ {"folder", ARG_FOLDER, N_("FOLDER"), 0,
+ N_("Specify folder to operate upon")},
+ {"inplace", ARG_INPLACE, N_("BOOL"), OPTION_ARG_OPTIONAL,
+ N_("Replace the source message with the table of contents, insert extracted messages after it") },
+ {"noinplace", ARG_NOINPLACE, 0, OPTION_HIDDEN, ""},
+ {"quiet", ARG_QUIET, N_("BOOL"), OPTION_ARG_OPTIONAL,
+ N_("Be quiet about the messages that are not in digest format") },
+ {"noquiet", ARG_NOQUIET, 0, OPTION_HIDDEN, ""},
+ {"verbose", ARG_VERBOSE, N_("BOOL"), OPTION_ARG_OPTIONAL,
+ N_("Verbosely list the actions taken") },
+ {"noverbose", ARG_NOVERBOSE, 0, OPTION_HIDDEN, ""},
+ {"recursive", ARG_RECURSIVE, N_("BOOL"), OPTION_ARG_OPTIONAL,
+ N_("Recursively expand MIME messages") },
+ {"norecursive", ARG_NORECURSIVE, 0, OPTION_HIDDEN, ""},
+ {"license", ARG_LICENSE, 0, 0,
+ N_("Display software license"), -1},
+ { NULL }
+};
+
+/* Traditional MH options */
+struct mh_option mh_option[] = {
+ {"inplace", 1, MH_OPT_BOOL },
+ {"quiet", 1, MH_OPT_BOOL },
+ {"verbose", 1, MH_OPT_BOOL },
+ {NULL}
+};
+
+/* Command line switches */
+int inplace;
+int quiet;
+int verbose;
+int recursive;
+
+#define VERBOSE(c) do { if (verbose) { printf c; putchar ('\n'); } } while (0)
+
+static int
+opt_handler (int key, char *arg, void *unused, struct argp_state *state)
+{
+ switch (key)
+ {
+ case ARG_FOLDER:
+ current_folder = arg;
+ break;
+
+ case ARG_INPLACE:
+ inplace = is_true (arg);
+ break;
+
+ case ARG_NOINPLACE:
+ inplace = 0;
+ break;
+
+ case ARG_LICENSE:
+ mh_license (argp_program_version);
+ break;
+
+ case ARG_VERBOSE:
+ verbose = is_true (arg);
+ break;
+
+ case ARG_NOVERBOSE:
+ verbose = 0;
+ break;
+
+ case ARG_RECURSIVE:
+ recursive = is_true (arg);
+ break;
+
+ case ARG_NORECURSIVE:
+ recursive = 0;
+ break;
+
+ case ARG_QUIET:
+ quiet = is_true (arg);
+ break;
+
+ case ARG_NOQUIET:
+ quiet = 0;
+ break;
+
+ default:
+ return 1;
+ }
+ return 0;
+}
+
+
+/* General-purpose data structures */
+struct burst_map
+{
+ int mime; /* Is mime? */
+ size_t msgno; /* Number of the original message */
+ /* Following numbers refer to tmpbox */
+ size_t first; /* Number of the first bursted message */
+ size_t count; /* Number of bursted messages */
+};
+
+
+/* Global data */
+struct burst_map map; /* Currently built map */
+struct burst_map *burst_map; /* Finished burst map */
+size_t burst_count; /* Number of items in burst_map */
+mu_mailbox_t tmpbox; /* Temporaty mailbox */
+struct obstack stk; /* Stack for building burst_map, etc. */
+
+static int burst_or_copy (mu_message_t msg, int recursive, int copy);
+
+
+/* MIME messages */
+int
+burst_mime (mu_message_t msg)
+{
+ size_t i, nparts;
+
+ mu_message_get_num_parts (msg, &nparts);
+
+ for (i = 1; i <= nparts; i++)
+ {
+ mu_message_t mpart;
+ if (mu_message_get_part (msg, i, &mpart) == 0)
+ {
+ if (!map.first)
+ mu_mailbox_uidnext (tmpbox, &map.first);
+ burst_or_copy (mpart, recursive, 1);
+ }
+ }
+ return 0;
+}
+
+
+int
+burst_or_copy (mu_message_t msg, int recursive, int copy)
+{
+ if (recursive)
+ {
+ int mime = 0;
+ mu_message_is_multipart (msg, &mime);
+
+ if (mime)
+ {
+ if (!map.first)
+ map.mime = 1;
+ return burst_mime (msg);
+ }
+ /* else if (is_digest (msg))
+ return burst_digest (msg) */
+ }
+
+ if (copy)
+ {
+ int rc;
+
+ if (map.mime)
+ {
+ mu_header_t hdr;
+ char *value = NULL;
+
+ mu_message_get_header (msg, &hdr);
+ if (mu_header_aget_value (hdr, MU_HEADER_CONTENT_TYPE, &value) == 0
+ && memcmp (value, "message/rfc822", 14) == 0)
+ {
+ mu_stream_t str;
+ mu_body_t body;
+
+ mu_message_get_body (msg, &body);
+ mu_body_get_stream (body, &str);
+
+ msg = mh_stream_to_message (str);
+ }
+ free (value);
+ }
+
+ rc = mu_mailbox_append_message (tmpbox, msg);
+ if (rc)
+ {
+ mh_error (_("cannot append message: %s"), mu_strerror (rc));
+ exit (1);
+ }
+ map.count++;
+ return 0;
+ }
+
+ return 1;
+}
+
+void
+burst (mu_mailbox_t mbox, mu_message_t msg, size_t num, void *data)
+{
+ memset (&map, 0, sizeof (map));
+ map.msgno = num;
+
+ if (burst_or_copy (msg, 1, 0) == 0)
+ {
+ if (inplace)
+ {
+ obstack_grow (&stk, &map, sizeof map);
+ burst_count++;
+ }
+ }
+ else if (!quiet)
+ mh_error (_("%lu: Not a digest message"), (unsigned long) num);
+}
+
+
+/* Inplace handling */
+
+void
+burst_rename (mh_msgset_t *ms, size_t lastuid)
+{
+ size_t i, j;
+
+ VERBOSE ((_("Renaming messages")));
+ j = burst_count - 1;
+ for (i = ms->count; i > 0; i--)
+ {
+ char *from;
+ char *to;
+
+ if (ms->list[i] == burst_map[j].msgno)
+ {
+ lastuid -= burst_map[j].count;
+ burst_map[j].msgno = lastuid;
+ j--;
+ }
+
+ asprintf (&from, "%lu", (unsigned long) ms->list[i]);
+ asprintf (&to, "%lu", (unsigned long) lastuid);
+ --lastuid;
+
+ if (rename (from, to))
+ {
+ mh_error (_("error renaming %s to %s: %s"),
+ from, to, mu_strerror (errno));
+ exit (1);
+ }
+ free (from);
+ free (to);
+ }
+}
+
+void
+msg_copy (size_t num, char *file)
+{
+ mu_message_t msg;
+ mu_attribute_t attr = NULL;
+ mu_stream_t istream, ostream;
+ int rc;
+ size_t n;
+ char buf[512];
+
+ if ((rc = mu_file_stream_create (&ostream,
+ file,
+ MU_STREAM_WRITE|MU_STREAM_CREAT)) != 0
+ || (rc = mu_stream_open (ostream)))
+ {
+ mh_error (_("Cannot open output file `%s': %s"),
+ file, mu_strerror (rc));
+ exit (1);
+ }
+
+ mu_mailbox_get_message (tmpbox, num, &msg);
+ mu_message_get_stream (msg, &istream);
+
+ while (rc == 0
+ && mu_stream_sequential_read (istream, buf, sizeof buf, &n) == 0
+ && n > 0)
+ /* FIXME: Implement RFC 934 FSA */
+ rc = mu_stream_sequential_write (ostream, buf, n);
+
+ mu_stream_close (ostream);
+ mu_stream_destroy (&ostream, mu_stream_get_owner (ostream));
+
+ /* Mark message as deleted */
+ mu_message_get_attribute (msg, &attr);
+ mu_attribute_set_deleted (attr);
+}
+
+void
+finalize_inplace (size_t lastuid)
+{
+ size_t i;
+
+ VERBOSE ((_("Moving bursted out messages in place")));
+
+ for (i = 0; i < burst_count; i++)
+ {
+ size_t j;
+
+ /* FIXME: toc handling */
+ for (j = 0; j < burst_map[i].count; j++)
+ {
+ char *to;
+
+ asprintf (&to, "%lu", (unsigned long) (burst_map[i].msgno + 1 + j));
+ msg_copy (burst_map[i].first + j, to);
+ }
+ }
+}
+
+int
+main (int argc, char **argv)
+{
+ int index, rc;
+ mu_mailbox_t mbox;
+ mh_msgset_t msgset;
+ char *tempfolder = mh_global_profile_get ("Temp-Folder", ".temp");
+
+ /* Native Language Support */
+ mu_init_nls ();
+
+ mu_argp_init (program_version, NULL);
+ mh_argp_parse (&argc, &argv, 0, options, mh_option, args_doc, doc,
+ opt_handler, NULL, &index);
+
+ argc -= index;
+ argv += index;
+
+ VERBOSE ((_("Opening folder `%s'"), current_folder));
+ mbox = mh_open_folder (current_folder, 0);
+ mh_msgset_parse (mbox, &msgset, argc, argv, "cur");
+
+ if (inplace)
+ {
+ size_t i, count;
+
+ VERBOSE ((_("Opening temporary folder `%s'"), tempfolder));
+ tmpbox = mh_open_folder (tempfolder, 1);
+ VERBOSE ((_("Cleaning up temporary folder")));
+ mu_mailbox_messages_count (tmpbox, &count);
+ for (i = 1; i <= count; i++)
+ {
+ mu_attribute_t attr = NULL;
+ mu_message_t msg = NULL;
+ mu_mailbox_get_message (tmpbox, i, &msg);
+ mu_message_get_attribute (msg, &attr);
+ mu_attribute_set_deleted (attr);
+ }
+ mu_mailbox_expunge (tmpbox);
+ obstack_init (&stk);
+ }
+ else
+ tmpbox = mbox;
+
+ rc = mh_iterate (mbox, &msgset, burst, NULL);
+ if (rc)
+ return rc;
+
+ if (inplace)
+ {
+ mu_url_t dst_url = NULL;
+ size_t i, next_uid, last_uid;
+ mh_msgset_t ms;
+ char *xargv[2];
+ char *dir;
+
+ burst_map = obstack_finish (&stk);
+
+ mu_mailbox_uidnext (mbox, &next_uid);
+ for (i = 0, last_uid = next_uid; i < burst_count; i++)
+ last_uid += burst_map[i].count;
+ VERBOSE ((_("Estimated last UID: %lu"), (unsigned long) last_uid));
+
+ asprintf (&xargv[0], "%lu-last",
+ (unsigned long) burst_map[0].msgno);
+ xargv[1] = NULL;
+ mh_msgset_parse (mbox, &ms, 1, xargv, NULL);
+ free (xargv[0]);
+
+ mu_mailbox_get_url (mbox, &dst_url);
+ dir = mu_url_to_string (dst_url);
+ VERBOSE ((_("changing to `%s'"), dir + 3));
+ if (chdir (dir+3))
+ {
+ mh_error (_("cannot change to `%s': %s"), dir, mu_strerror (errno));
+ exit (1);
+ }
+ mu_mailbox_close (mbox);
+
+ burst_rename (&ms, last_uid);
+ mh_msgset_free (&ms);
+
+ finalize_inplace (last_uid);
+
+ VERBOSE ((_("Expunging temporary folder")));
+ mu_mailbox_expunge (tmpbox);
+ mu_mailbox_close (tmpbox);
+ mu_mailbox_destroy (&tmpbox);
+ }
+ else
+ mu_mailbox_close (mbox);
+
+ mu_mailbox_destroy (&mbox);
+ VERBOSE ((_("Finished bursting")));
+ return rc;
+}
+
+
+

Return to:

Send suggestions and report system problems to the System administrator.