diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2005-11-29 17:40:43 +0000 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2005-11-29 17:40:43 +0000 |
commit | 3ff591fe0535e285d893fff02042ef0ed54a49df (patch) | |
tree | 65b09aa0774b48f3a0730f6b9f782d86012d7e48 | |
parent | 03237b3a2709ccf219afca2c8fdc1e6952ce1dfc (diff) | |
download | mailutils-3ff591fe0535e285d893fff02042ef0ed54a49df.tar.gz mailutils-3ff591fe0535e285d893fff02042ef0ed54a49df.tar.bz2 |
Add burst.c
-rw-r--r-- | mh/Makefile.am | 2 | ||||
-rw-r--r-- | mh/burst.c | 433 |
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; +} + + + |