[Evolution-hackers] mboxtool
- From: Jeffrey Stedfast <fejj novell com>
- To: evolution-hackers <evolution-hackers gnome org>
- Subject: [Evolution-hackers] mboxtool
- Date: Thu, 08 May 2008 15:20:48 -0400
Not necessarily Evolution-specific, but I've had reason to 'fix' my
mailboxes a number of times in the past year and so I've written this
little tool.
gcc -o mboxtool mboxtool.c `pkg-config --cflags --libs gmime-2.0`
Enjoy.
Jeff
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* Authors: Jeffrey Stedfast <fejj novell com>
*
* Copyright 2008 Novell, Inc. (www.novell.com)
*
* This program 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 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <gmime/gmime.h>
enum {
RESORT = (1 << 0),
REMDUP = (1 << 1),
REUID = (1 << 2),
REPLACE = (1 << 3),
};
typedef struct {
char *msg_id;
off_t msg_start;
off_t msg_uid;
time_t msg_date;
char *msg_key;
int msg_dup;
} MsgInfo;
static int
datecmp (const void *a, const void *b)
{
MsgInfo *mia = (MsgInfo *) *((void **) a);
MsgInfo *mib = (MsgInfo *) *((void **) b);
return mia->msg_date - mib->msg_date;
}
static void
xev_cb (GMimeParser *parser, const char *header, const char *value, off_t offset, off_t *save)
{
*save = offset;
}
static int
sort_mbox (GMimeStream *istream, GMimeStream *ostream, GMimeStream *dstream, guint32 flags)
{
GHashTable *msgid_hash = NULL;
GMimeMessage *message;
GMimeStream *stream;
GMimeParser *parser;
GPtrArray *summary;
MsgInfo *info;
int tz_offset;
off_t offset;
char *from;
int rv = 0;
guint32 i;
if (flags & REMDUP)
msgid_hash = g_hash_table_new (g_str_hash, g_str_equal);
summary = g_ptr_array_new ();
parser = g_mime_parser_new ();
g_mime_parser_init_with_stream (parser, istream);
g_mime_parser_set_header_regex (parser, "^X-Evolution$", (GMimeParserHeaderRegexFunc) xev_cb, &offset);
g_mime_parser_set_scan_from (parser, TRUE);
while (!g_mime_parser_eos (parser)) {
offset = -1;
if (!(message = g_mime_parser_construct_message (parser)))
continue;
info = g_new (MsgInfo, 1);
info->msg_id = g_strdup (g_mime_message_get_message_id (message));
info->msg_start = g_mime_parser_get_from_offset (parser);
info->msg_uid = offset > info->msg_start ? (offset - info->msg_start) +
(summary->len > 0 ? 1 : 0) : -1;
g_mime_message_get_date (message, &info->msg_date, &tz_offset);
info->msg_date -= tz_offset;
info->msg_key = g_strdup_printf ("<%s>", info->msg_id);
info->msg_dup = (flags & REMDUP) && g_hash_table_lookup (msgid_hash, info->msg_key);
g_ptr_array_add (summary, info);
if ((flags & REMDUP) && !info->msg_dup)
g_hash_table_insert (msgid_hash, info->msg_key, info);
g_object_unref (message);
}
g_object_unref (parser);
if (msgid_hash != NULL)
g_hash_table_destroy (msgid_hash);
if (flags & RESORT)
qsort (summary->pdata, summary->len, sizeof (void *), datecmp);
for (i = 0; i < summary->len; i++) {
info = summary->pdata[i];
if ((rv = g_mime_stream_seek (istream, info->msg_start, GMIME_STREAM_SEEK_SET)) == -1)
break;
parser = g_mime_parser_new ();
g_mime_parser_init_with_stream (parser, istream);
g_mime_parser_set_scan_from (parser, TRUE);
message = g_mime_parser_construct_message (parser);
from = g_mime_parser_get_from (parser);
g_object_unref (parser);
if (info->msg_dup)
stream = dstream;
else
stream = ostream;
if (stream == NULL) {
g_free (from);
goto next;
}
offset = g_mime_stream_tell (stream);
if (offset > 0 && (rv = g_mime_stream_write (stream, "\n", 1)) == -1) {
g_object_unref (message);
g_free (from);
break;
}
if ((rv = g_mime_stream_write_string (stream, from)) == -1) {
g_object_unref (message);
g_free (from);
break;
}
g_free (from);
if ((rv = g_mime_stream_write (stream, "\n", 1)) == -1) {
g_object_unref (message);
break;
}
if ((rv = g_mime_object_write_to_stream ((GMimeObject *) message, stream)) == -1) {
g_object_unref (message);
break;
}
g_object_unref (message);
if ((flags & REUID) && offset != -1 && info->msg_uid != -1) {
if ((rv = g_mime_stream_seek (stream, offset + info->msg_uid, GMIME_STREAM_SEEK_SET)) == -1)
break;
if ((rv = g_mime_stream_printf (stream, "X-Evolution: %08x-", i + 1)) == -1)
break;
if ((rv = g_mime_stream_seek (stream, 0, GMIME_STREAM_SEEK_END)) == -1)
break;
}
next:
g_free (info->msg_key);
g_free (info->msg_id);
g_free (info);
}
for ( ; i < summary->len; i++) {
info = summary->pdata[i];
g_free (info->msg_key);
g_free (info->msg_id);
g_free (info);
}
g_ptr_array_free (summary, TRUE);
return rv;
}
static void
usage (const char *argv0)
{
const char *name;
if (!(name = strrchr (argv0, '/')))
name = argv0;
else
name++;
printf ("Usage: %s [OPTIONS...] inbox outbox\n\n", name);
printf ("Options:\n");
printf (" --sort Sort the mbox by date received\n");
printf (" --dups Remove duplicates\n");
printf (" --reuid Reassign uids in ascending order\n");
printf (" --replace Replace the mbox specified as 'inbox'\n");
printf ("\n");
printf ("Reads the mbox specified as inbox and rewrites it to\n");
printf ("the mbox specified as outbox after having performed the\n");
printf ("requested operations.\n\n");
fflush (stdout);
}
int main (int argc, char **argv)
{
GMimeStream *istream, *ostream, *dstream = NULL;
const char *inbox = NULL, *outbox = NULL;
char *replace = NULL;
guint32 flags = 0;
char *filename;
int fd, i;
if (argc < 3) {
usage (argv[0]);
return 0;
}
for (i = 1; i < argc; i++) {
if (!strcmp (argv[i], "--sort")) {
flags |= RESORT;
} else if (!strcmp (argv[i], "--dups")) {
flags |= REMDUP;
} else if (!strcmp (argv[i], "--reuid")) {
flags |= REUID;
} else if (!strcmp (argv[i], "--replace")) {
flags |= REPLACE;
} else if (strncmp (argv[i], "--", 2) != 0) {
if (inbox == NULL) {
inbox = argv[i];
} else {
outbox = argv[i];
break;
}
} else {
fprintf (stderr, "invalid option: %s\n", argv[i]);
return -1;
}
}
if (!inbox) {
fprintf (stderr, "no inbox specified\n");
return -1;
}
if (flags & REPLACE) {
if ((outbox = strrchr (inbox, '/')))
replace = g_strdup_printf ("%.*s/.%s", outbox - inbox, inbox, outbox + 1);
else
replace = g_strdup_printf (".%s", inbox);
outbox = replace;
}
if (!outbox) {
fprintf (stderr, "no outbox specified\n");
g_free (replace);
return -1;
}
g_mime_init (0);
if ((fd = open (inbox, O_RDONLY)) == -1) {
perror ("failed to open inbox");
g_free (replace);
return -1;
}
istream = g_mime_stream_fs_new (fd);
if ((fd = open (outbox, O_CREAT | O_TRUNC | O_EXCL | O_WRONLY, 0644)) == -1) {
perror ("failed to open outbox");
g_object_unref (istream);
g_free (replace);
return -1;
}
ostream = g_mime_stream_fs_new (fd);
if ((flags & (REPLACE | REMDUP)) == REMDUP) {
filename = g_strdup_printf ("%s.dups", outbox);
if ((fd = open (filename, O_CREAT | O_TRUNC | O_EXCL | O_WRONLY, 0644)) == -1) {
perror ("failed to open dup outbox");
g_object_unref (istream);
g_object_unref (ostream);
g_free (filename);
return -1;
}
g_free (filename);
dstream = g_mime_stream_fs_new (fd);
}
if (sort_mbox (istream, ostream, dstream, flags) == -1 ||
g_mime_stream_flush (ostream) == -1) {
perror ("failed to fix mbox");
g_object_unref (istream);
g_object_unref (ostream);
if (dstream)
g_object_unref (dstream);
unlink (replace);
g_free (replace);
return -1;
}
if (dstream) {
g_mime_stream_flush (dstream);
g_object_unref (dstream);
}
g_object_unref (istream);
g_object_unref (ostream);
if (flags & REPLACE) {
if (rename (replace, inbox) != -1) {
char *meta;
meta = g_strdup_printf ("%s.ev-summary-meta", inbox);
unlink (meta);
g_free (meta);
meta = g_strdup_printf ("%s.ev-summary", inbox);
unlink (meta);
g_free (meta);
meta = g_strdup_printf ("%s.ibex.index.data", inbox);
unlink (meta);
g_free (meta);
meta = g_strdup_printf ("%s.ibex.index", inbox);
unlink (meta);
g_free (meta);
}
}
g_free (replace);
return 0;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]