Index: imap/Makefile.in =================================================================== RCS file: /cvs/src/cyrus/imap/Makefile.in,v retrieving revision 1.191 diff -u -d -r1.191 Makefile.in --- imap/Makefile.in 18 Oct 2007 18:48:02 -0000 1.191 +++ imap/Makefile.in 24 Dec 2007 12:09:08 -0000 @@ -117,7 +117,7 @@ fud smmapd reconstruct quota mbpath ipurge cyr_dbtool cyr_synclog \ cyrdump chk_cyrus cvt_cyrusdb deliver ctl_mboxlist \ ctl_deliver ctl_cyrusdb squatter mbexamine cyr_expire arbitron \ - unexpunge @IMAP_PROGS@ + unexpunge calc_guids @IMAP_PROGS@ BUILTSOURCES = imap_err.c imap_err.h pushstats.c pushstats.h \ lmtpstats.c lmtpstats.h xversion.h mupdate_err.c mupdate_err.h \ @@ -351,6 +351,9 @@ sync_reset sync_reset.o sync_support.o sync_commit.o \ libimap.a mutex_fake.o $(DEPLIBS) $(LIBS) +calc_guids: calc_guids.o libimap.a mutex_fake.o $(DEPLIBS) + $(CC) $(LDFLAGS) -o calc_guids calc_guids.o libimap.a mutex_fake.o $(DEPLIBS) $(LIBS) + ### Other Misc Targets clean: Index: imap/calc_guids.c =================================================================== RCS file: imap/calc_guids.c diff -N imap/calc_guids.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ imap/calc_guids.c 24 Dec 2007 12:09:08 -0000 @@ -0,0 +1,279 @@ +#include + +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "global.h" +#include "assert.h" +#include "mboxlist.h" +#include "exitcodes.h" +#include "imap_err.h" +#include "mailbox.h" +#include "xmalloc.h" +#include "acl.h" +#include "seen.h" +#include "mboxname.h" +#include "map.h" +#include "imapd.h" +#include "message.h" +#include "message_guid.h" + +/* global state */ +const int config_need_data = 0; + +extern char *optarg; +extern int optind; + +/* Stuff to make index.c link */ +int imapd_exists; +struct protstream *imapd_out = NULL; +struct auth_state *imapd_authstate = NULL; +char *imapd_userid = NULL; + +void printastring(const char *s __attribute__((unused))) +{ + fatal("not implemented", EC_SOFTWARE); +} + +void printstring(const char *s __attribute__((unused))) +{ + fatal("not implemented", EC_SOFTWARE); +} + +/* end stuff to make index.c link */ + +static int verbose = 0; +static int zero = 0; + +static void shut_down(int code) __attribute__((noreturn)); +static void shut_down(int code) +{ + seen_done(); + quotadb_close(); + quotadb_done(); + mboxlist_close(); + mboxlist_done(); + cyrus_done(); + exit(code); +} + +static int usage(const char *name) +{ + fprintf(stderr, + "usage: %s [-C ] [-v] user...\n", name); + + exit(EC_USAGE); +} + +void fatal(const char* s, int code) +{ + fprintf(stderr, "calc_guids: %s\n", s); + exit(code); +} + +/* ====================================================================== */ + +static int +calc_single_folder(char *name, + int matchlen __attribute__((unused)), + int maycreate __attribute__((unused)), + void *rock __attribute__((unused))) +{ + char msgfname[MAILBOX_FNAME_LEN+1]; + enum enum_value config_guidmode = config_getenum(IMAPOPT_GUID_MODE); + struct body *body = NULL; + struct mailbox m; + int r = 0; + unsigned long msgno; + struct index_record record; + FILE *msgfile; + struct stat sbuf; + + if (verbose > 1) + printf(" %s\n", name); + + memset(&m, 0, sizeof(struct mailbox)); + r = mailbox_open_header(name, 0, &m); + if (!r) r = mailbox_open_index(&m); + if (r) { + syslog(LOG_NOTICE, "error opening %s: %s\n", name, error_message(r)); + return(IMAP_IOERROR); + } + + if (chdir(m.path) == -1) { + r = IMAP_IOERROR; + goto bail; + } + + if ((r=mailbox_lock_header(&m))) { + syslog(LOG_NOTICE, + "error locking header for %s: %s\n", name, error_message(r)); + goto bail; + } + + if ((r=mailbox_lock_index(&m))) { + syslog(LOG_NOTICE, + "error locking index for %s: %s\n", name, error_message(r)); + goto bail; + } + + for (msgno = 1 ; msgno <= m.exists ; msgno++) { + if ((r=mailbox_read_index_record(&m, msgno, &record))) { + syslog(LOG_NOTICE, + "error reading index for %s, msgno %lu: %s\n", + name, msgno, error_message(r)); + goto bail; + } + message_guid_set_null(&record.guid); + + mailbox_message_get_fname(&m, record.uid, msgfname, sizeof(msgfname)); + msgfile = fopen(msgfname, "r"); + if (!msgfile) { + syslog(LOG_ERR, + "fopen() failed for '%s' [error=%d] -- skipping.\n", + msgfname, errno); + } else if ((fstat(fileno(msgfile), &sbuf) == -1) || + (sbuf.st_size == 0)) { + syslog(LOG_ERR, "ignoring empty file: %s\n", msgfname); + fclose(msgfile); + } else if (!zero && config_guidmode) { + r = message_parse_file(msgfile, NULL, NULL, &body); + if (r) { + syslog(LOG_ERR, + "message_parse_file() unable to parse: %s\n", + msgfname); + } else if (body) { + message_extract_guid(&record.guid, body); + message_free_body(body); + } + fclose(msgfile); + } + + if ((r=mailbox_write_index_record(&m, msgno, &record, 0))) { + syslog(LOG_NOTICE, + "error writing index for %s, msgno %lu: %s\n", + name, msgno, error_message(r)); + goto bail; + } + } + + mailbox_unlock_index(&m); + mailbox_unlock_header(&m); + + bail: + mailbox_close(&m); + return(r); +} + +/* ====================================================================== */ + +static int +do_user(char *user, struct namespace *namespacep) +{ + char buf[MAX_MAILBOX_PATH]; + int r = 0; + + if (verbose > 0) + printf("Calc_Guids: %s\n", user); + + syslog(LOG_NOTICE, "Starting GUID calc for %s", user); + + imapd_userid = user; + imapd_authstate = auth_newstate(imapd_userid); + + /* Count inbox */ + snprintf(buf, sizeof(buf)-1, "user.%s", user); + r = calc_single_folder(buf, 0, 0, NULL); + if (r) return(r); + + /* And then all folders */ + snprintf(buf, sizeof(buf)-1, "user.%s.*", user); + r = (namespacep->mboxlist_findall)(namespacep, buf, 1, + imapd_userid, imapd_authstate, + calc_single_folder, NULL); + return(r); +} + +/* ====================================================================== */ + +int +main(int argc, char **argv) +{ + int opt; + char *alt_config = NULL; + int r = 0; + int i; + struct namespace guid_namespace; + + if(geteuid() == 0) + fatal("must run as the Cyrus user", EC_USAGE); + + setbuf(stdout, NULL); + + while ((opt = getopt(argc, argv, "C:vz")) != EOF) { + switch (opt) { + case 'C': /* alt config file */ + alt_config = optarg; + break; + + case 'v': /* verbose */ + verbose++; + break; + + case 'z': + zero++; + break; + + default: + usage("calc_guids"); + } + } + + /* Set up default bounds if no command line options provided */ + + cyrus_init(alt_config, "calc_guids", 0); + + syslog(LOG_NOTICE, "Calculating GUIDS"); + + /* Set namespace -- force standard (internal) */ + if ((r = mboxname_init_namespace(&guid_namespace, 1)) != 0) { + fatal(error_message(r), EC_CONFIG); + } + + mboxlist_init(0); + mboxlist_open(NULL); + mailbox_initialize(); + + quotadb_init(0); + quotadb_open(NULL); + + signals_set_shutdown(&shut_down); + signals_add_handlers(0); + + if (optind == argc) { + fprintf(stderr, "please specify user to calc_guids\n"); + exit(EC_USAGE); + } + + for (i = optind; i < argc; i++) { + if (do_user(argv[i], &guid_namespace)) { + syslog(LOG_NOTICE, "Error calculating GUIDs in %s: %m", argv[i]); + shut_down(1); + } + } + syslog(LOG_NOTICE, "Done calculating GUIDs"); + shut_down(0); +} Index: imap/message.c =================================================================== RCS file: /cvs/src/cyrus/imap/message.c,v retrieving revision 1.110 diff -u -d -r1.110 message.c --- imap/message.c 1 Oct 2007 18:36:00 -0000 1.110 +++ imap/message.c 24 Dec 2007 12:09:09 -0000 @@ -560,6 +560,12 @@ return 0; } +void +message_extract_guid(struct message_guid *guid, struct body *body) +{ + message_guid_copy(guid, &body->guid); +} + /* * Parse a body-part */ Index: imap/message.h =================================================================== RCS file: /cvs/src/cyrus/imap/message.h,v retrieving revision 1.9 diff -u -d -r1.9 message.h --- imap/message.h 13 Sep 2007 17:35:15 -0000 1.9 +++ imap/message.h 24 Dec 2007 12:09:09 -0000 @@ -96,6 +96,8 @@ int cache_fd, struct index_record *message_index, struct body *body)); +extern void message_extract_guid P((struct message_guid *guid, + struct body *body)); extern void message_free_body P((struct body *body)); #endif /* INCLUDED_MESSAGE_H */ Index: man/Makefile.in =================================================================== RCS file: /cvs/src/cyrus/man/Makefile.in,v retrieving revision 1.39 diff -u -d -r1.39 Makefile.in --- man/Makefile.in 18 Oct 2007 18:14:48 -0000 1.39 +++ man/Makefile.in 24 Dec 2007 12:09:09 -0000 @@ -69,7 +69,7 @@ $(srcdir)/nntpd.8 $(srcdir)/fetchnews.8 $(srcdir)/smmapd.8 \ $(srcdir)/sync_client.8 $(srcdir)/sync_server.8 $(srcdir)/sync_reset.8 \ $(srcdir)/unexpunge.8 $(srcdir)/make_md5.8 $(srcdir)/cyr_dbtool.8 \ - $(srcdir)/cyr_synclog.8 $(srcdir)/make_sha1.8 + $(srcdir)/cyr_synclog.8 $(srcdir)/make_sha1.8 $(srcdir)/calc_guids.8 all: $(MAN1) $(MAN3) $(MAN5) $(MAN8) Index: man/calc_guids.8 =================================================================== RCS file: man/calc_guids.8 diff -N man/calc_guids.8 --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ man/calc_guids.8 24 Dec 2007 12:09:09 -0000 @@ -0,0 +1,46 @@ +.\" $Cambridge: hermes/src/cyrus-imapd/man/calc_guids.8,v 1.1 2007/12/23 18:08:08 dpc22 Exp $ +.\" -*- nroff -*- +.TH CALC_UUIDS HERMES 8 +.SH NAME +calc_guids \- Calculate all message GUIDs for named account +.SH SYNOPSIS +.B calc_guids +[ +.B \-C +.I config-file +] +[ +.B \-v +] +[ +.B \-v +] +[ +.B \-z +] +.IR userid ... +.SH DESCRIPTION + +.I Each message text in the Cyrus mailstore has a 20 byte Globally +Unique Unique identifier (GUID), which is the SHA1 digest of the static +message text. GUIDs allows us to optimise various replication operations +and maintain the single instance store when copying messages between a +master system and its replica. + +This utility allows us to calculate the GUIDs on a replica system as part +of the upgrade from the old 96 bit UUID system. +.SH OPTIONS +.TP +.BI \-C " config-file" +Read configuration options from \fIconfig-file\fR. +.TP +.BI \-v +Verbose mode. +.TP +.BI \-z +Reset (zero) GUIDs to the NULL value. +.SH FILES +.TP +.B /etc/imapd.conf +.SH AUTHORS +David Carter (dpc22@cam.ac.uk)