# Use short_md5 scheme in place of UUIDs allocated from master. # Only in cyrus-imapd-2.3.8: autom4te.cache diff -udr cyrus-imapd-2.3.8/imap/append.c cyrus-imapd/imap/append.c --- cyrus-imapd-2.3.8/imap/append.c 2007-02-05 18:41:45.000000000 +0000 +++ cyrus-imapd/imap/append.c 2007-05-08 18:03:43.000000000 +0100 @@ -408,6 +408,7 @@ char stagedir[MAX_MAILBOX_PATH+1], stagefile[MAX_MAILBOX_PATH+1]; FILE *f; int r; + enum enum_value config_uuidmode = config_getenum(IMAPOPT_UUID_MODE); assert(mailboxname != NULL); assert(stagep != NULL); @@ -416,9 +417,6 @@ stage->parts = xzmalloc(5 * (MAX_MAILBOX_PATH+1) * sizeof(char)); stage->partend = stage->parts + 5 * (MAX_MAILBOX_PATH+1) * sizeof(char); - /* Assign new, shared MessageID */ - message_uuid_assign(&stage->uuid); - snprintf(stage->fname, sizeof(stage->fname), "%d-%d-%d", (int) getpid(), (int) internaldate, msgnum); @@ -472,7 +470,7 @@ FILE *destfile; int i, r; int userflag, emptyflag; - + enum enum_value config_uuidmode = config_getenum(IMAPOPT_UUID_MODE); /* for staging */ char stagefile[MAX_MAILBOX_PATH+1]; int sflen; @@ -640,8 +638,6 @@ } } } - /* Copy Message UUID from stage */ - message_uuid_copy(&message_index.uuid, &stage->uuid); /* Write out index file entry */ r = mailbox_append_index(mailbox, &message_index, @@ -704,6 +700,7 @@ FILE *destfile; int i, r; int userflag, emptyflag; + enum enum_value config_uuidmode = config_getenum(IMAPOPT_UUID_MODE); assert(mailbox->format == MAILBOX_FORMAT_NORMAL); assert(size != 0); @@ -801,9 +798,6 @@ } } - /* Assign new Message-UUID */ - message_uuid_assign(&message_index.uuid); - /* Write out index file entry; if we abort later, it's not important */ r = mailbox_append_index(mailbox, &message_index, @@ -1003,9 +997,6 @@ addme(&as->seen_msgrange, &as->seen_alloced, message_index[msg].uid); } - - /* Assign messageID for this message */ - message_uuid_copy(&message_index[msg].uuid, ©msg[msg].uuid); } if (body) free(body); diff -udr cyrus-imapd-2.3.8/imap/imapd.c cyrus-imapd/imap/imapd.c --- cyrus-imapd-2.3.8/imap/imapd.c 2007-02-05 18:49:55.000000000 +0000 +++ cyrus-imapd/imap/imapd.c 2007-05-08 18:03:43.000000000 +0100 @@ -685,9 +685,6 @@ /* Create a protgroup for input from the client and selected backend */ protin = protgroup_new(2); - /* YYY Sanity checks possible here? */ - message_uuid_client_init(getenv("CYRUS_UUID_PREFIX")); - return 0; } diff -udr cyrus-imapd-2.3.8/imap/lmtpd.c cyrus-imapd/imap/lmtpd.c --- cyrus-imapd-2.3.8/imap/lmtpd.c 2007-02-05 18:41:47.000000000 +0000 +++ cyrus-imapd/imap/lmtpd.c 2007-05-08 18:03:43.000000000 +0100 @@ -226,9 +226,6 @@ snmp_connect(); /* ignore return code */ snmp_set_str(SERVER_NAME_VERSION, CYRUS_VERSION); - /* YYY Sanity checks possible here? */ - message_uuid_client_init(getenv("CYRUS_UUID_PREFIX")); - return 0; } diff -udr cyrus-imapd-2.3.8/imap/message.c cyrus-imapd/imap/message.c --- cyrus-imapd-2.3.8/imap/message.c 2007-02-05 18:41:47.000000000 +0000 +++ cyrus-imapd/imap/message.c 2007-05-08 18:03:43.000000000 +0100 @@ -75,6 +75,9 @@ #include "global.h" #include "retry.h" +#include "md5global.h" +#include "md5.h" + /* Message being parsed */ struct msg { const char *base; @@ -137,6 +140,9 @@ * Cached headers. Only filled in at top-level */ struct ibuf cacheheaders; + + /* MD5 UUID. Only filled in at top level */ + unsigned char msg_md5[16]; }; /* List of Content-type parameters */ @@ -425,6 +431,17 @@ return 0; } +/* Small utility routine to compute message MD5 sum */ +static void +message_md5_calculate(unsigned char md5[], /* 16 bytes */ + unsigned char *source, unsigned len) +{ + MD5_CTX ctx; + + MD5Init(&ctx); + MD5Update(&ctx, source, len); + MD5Final(md5, &ctx); +} /* * Parse the message at 'msg_base' of length 'msg_len' in 'mailbox'. @@ -436,6 +453,7 @@ struct body *body) { struct msg msg; + enum enum_value config_uuidmode = config_getenum(IMAPOPT_UUID_MODE); msg.base = msg_base; msg.len = msg_len; @@ -445,6 +463,11 @@ message_parse_body(&msg, MAILBOX_FORMAT_NORMAL, body, DEFAULT_CONTENT_TYPE, (struct boundary *)0); + if (config_uuidmode == IMAP_ENUM_UUID_MODE_SHORTMD5) { + message_md5_calculate(&body->msg_md5[0], + (unsigned char *)msg_base, msg_len); + } + return 0; } @@ -530,6 +553,7 @@ struct body *body; { int n; + enum enum_value config_uuidmode = config_getenum(IMAPOPT_UUID_MODE); message_index->sentdate = message_parse_date(body->date, 0); message_index->size = body->header_size + body->content_size; @@ -548,6 +572,13 @@ return IMAP_IOERROR; } + /* Copy in MD5 UUID unless UUID already assigned to the message + * (allows parent to decide which source of UUIDs to use) + */ + if ((config_uuidmode == IMAP_ENUM_UUID_MODE_SHORTMD5) && + message_uuid_isnull(&message_index->uuid)) { + message_uuid_shortmd5(&message_index->uuid, &body->msg_md5[0]); + } return 0; } diff -udr cyrus-imapd-2.3.8/imap/reconstruct.c cyrus-imapd/imap/reconstruct.c --- cyrus-imapd-2.3.8/imap/reconstruct.c 2007-02-05 18:41:48.000000000 +0000 +++ cyrus-imapd/imap/reconstruct.c 2007-05-08 18:03:43.000000000 +0100 @@ -993,6 +993,7 @@ } } + /* NB: message_crease_record will reconstruct MD5 UUID if NULL */ if (((r = message_parse_file(msgfile, NULL, NULL, &body)) != 0) || ((r = message_create_record(&mailbox, &message_index, body)) != 0)) { fclose(msgfile); diff -udr cyrus-imapd-2.3.8/lib/imapoptions cyrus-imapd/lib/imapoptions --- cyrus-imapd-2.3.8/lib/imapoptions 2007-02-07 18:58:07.000000000 +0000 +++ cyrus-imapd/lib/imapoptions 2007-05-08 18:03:43.000000000 +0100 @@ -929,11 +929,6 @@ and nntpd(8). The log {configdirectory}/sync/log is used by sync_client(8) for "rolling" replication. */ -{ "sync_machineid", -1, INT } -/* Machine ID of this server which must be unique within a cluster. - Any negative number, the default, will disable the use of UUIDs for - replication. */ - { "sync_password", NULL, STRING } /* The default password to use when authenticating to a sync server. */ @@ -1014,6 +1009,9 @@ mailbox hierarchy. The default is to use the netnews separator character '.'. */ +{ "uuid_mode", "none", ENUM("none", "shortmd5")} +/* The way to calculate UUIDs */ + { "virtdomains", "off", ENUM("off", "userid", "on") } /* Enable virtual domain support. If enabled, the user's domain will be determined by splitting a fully qualified userid at the last '@' diff -udr cyrus-imapd-2.3.8/lib/message_uuid.c cyrus-imapd/lib/message_uuid.c --- cyrus-imapd-2.3.8/lib/message_uuid.c 2006-11-30 17:11:22.000000000 +0000 +++ cyrus-imapd/lib/message_uuid.c 2007-05-08 18:03:43.000000000 +0100 @@ -58,229 +58,12 @@ * on first byte. Currently two UUID schemas defined: * * Schema 0 => NULL values. - * Schema 1 => UUIDs allocated by master process in 2^24 bit chunks. - */ - -static int schema = 0; - -/* Schema 1 Byte encoding is: - * - * Byte Offset Use - * - * 0 Current UUID schema (following is schema 1) - * 1 -> 8 64 bit prefix private to UUID schema. - * 9 -> 11 24 bit counter for UUID with child process - * (means max 16777216 messages per child process) - * - * Numbers stored big-endian. + * Schema 1 => (Obsolete) + * Schema 2 => First 11 bytes from MD5(msg body) */ -static struct { - unsigned char prefix[8]; /* 8 bytes used */ - unsigned long count; /* 3 bytes used */ -} schema_1; - -/* message_uuid_record() ************************************************* - * - * Decode public UUID into components for manipulation - * Returns: Cyrus error code, 0 on sucess - * - ************************************************************************/ - -static int -message_uuid_record(struct message_uuid *uuid) -{ - unsigned char *s = &uuid->value[0]; - int rc = 1; - - switch (s[0]) { - case 0: - schema = 0; - break; - case 1: - schema = 1; - memcpy(&schema_1.prefix[0], &s[1], 8); - schema_1.count = 0; - break; - default: - rc = 0; - break; - } - - return(rc); -} - -/* message_uuid_extract() ************************************************ - * - * Convert message_uuid_structure into public UID - * Returns: boolean success - * - ************************************************************************/ - -static int -message_uuid_extract(struct message_uuid *uuid) -{ - unsigned char *s = &uuid->value[0]; - int rc = 1; - - switch (schema) { - case 0: - message_uuid_set_null(uuid); - break; - case 1: - s[0] = 1; - - memcpy(&s[1], &schema_1.prefix[0], 8); - s[9] = ((schema_1.count & 0xff0000) >> 16); - s[10] = ((schema_1.count & 0x00ff00) >> 8); - s[11] = ((schema_1.count & 0x0000ff)); - break; - default: - syslog(LOG_ERR, "UUID: Unknown schema"); - message_uuid_set_null(uuid); - rc = 0; - break; - } - - return(rc); -} - /* ====================================================================== */ -/* message_uuid_client_init() ******************************************** - * - * Initialise private UUID system - * Returns: boolean success - ************************************************************************/ - -int -message_uuid_client_init(char *uuid_prefix) -{ - struct message_uuid tmp; - unsigned char *s = &tmp.value[0]; - unsigned long count, checksum; - - /* Record a NULL value in case of failure */ - message_uuid_set_null(&tmp); - message_uuid_record(&tmp); - - if (uuid_prefix == NULL) - return(1); - - if (!message_uuid_from_text(&tmp, uuid_prefix)) - return(0); - - /* Test and record UUID prefix in different schemas */ - switch (s[0]) { - case 0: - /* NOOP, used record NULL value */ - break; - case 1: - /* Compute 24 bit checksum from first 9 bytes */ - count = (s[0] << 16) + (s[1] << 8) + s[2]; - count += (s[3] << 16) + (s[4] << 8) + s[5]; - count += (s[6] << 16) + (s[7] << 8) + s[8]; - count &= 0x00ffffff; - - /* And retrieve checksum from last three bytes */ - checksum = (s[9] << 16) + (s[10] << 8) + s[11]; - - if (checksum != count) { - syslog(LOG_ERR, "UUID checksum mismatch for %s", uuid_prefix); - return(0); - } - - /* Clear checksum bytes */ - s[9] = 0; - s[10] = 0; - s[11] = 0; - - if (!message_uuid_record(&tmp)) - return(0); - break; - default: - syslog(LOG_ERR, - "Attempt to initialise invalid UUID prefix: %s", uuid_prefix); - return(0); - break; - } - - return(1); -} - -/* message_uuid_assign() ************************************************* - * - * Assign next UUID to preallocated structure - * Returns: Cyrus error code, 0 on sucess - * - ************************************************************************/ - -int -message_uuid_assign(struct message_uuid *uuid) -{ - int rc = 1; - - switch (schema) { - case 0: - message_uuid_set_null(uuid); - break; - case 1: - if (schema_1.count >= (256*256*256)) { - /* Allocation space (2^24 nodes) exhausted */ - message_uuid_set_null(uuid); - break; - } - - if (!message_uuid_extract(uuid)) { - message_uuid_set_null(uuid); - rc = 0; - break; - } - - schema_1.count++; - - break; - default: - message_uuid_set_null(uuid); - rc = 0; - break; - } - - return(rc); -} - -/* message_uuid_alloc() ************************************************** - * - * Allocate and assign next UUID using xmalloc. - * Returns: NULL Message-UUID if allocation exhaused. - * NULL => Internal error - * - ************************************************************************/ - -struct message_uuid * -message_uuid_alloc() -{ - struct message_uuid *current = xmalloc(sizeof(struct message_uuid)); - - if (!message_uuid_assign(current)) - return(NULL); - - return(current); -} - -/* message_uuid_free() *************************************************** - * - * Wrapper for free function. - * - ************************************************************************/ - -void -message_uuid_free(struct message_uuid **uuidp) -{ - free(*uuidp); - *uuidp = NULL; -} - /* message_uuid_copy() *************************************************** * * Copy UUID @@ -381,6 +164,19 @@ return(1); } +/* message_uuid_shortmd5() *********************************************** + * + * Generate schema 2 (shortmd5) UUID from message MD5 + * + ************************************************************************/ + +void +message_uuid_shortmd5(struct message_uuid *uuid, unsigned char *md5) +{ + uuid->value[0] = 2; + memcpy(&uuid->value[1], md5, 11); +} + /* Routines for manipulating packed values */ /* message_uuid_pack() *************************************************** diff -udr cyrus-imapd-2.3.8/lib/message_uuid.h cyrus-imapd/lib/message_uuid.h --- cyrus-imapd-2.3.8/lib/message_uuid.h 2006-11-30 17:11:22.000000000 +0000 +++ cyrus-imapd/lib/message_uuid.h 2007-05-08 18:03:43.000000000 +0100 @@ -10,26 +10,6 @@ }; int -message_uuid_client_init(char *uuid_prefix); - /* Initialise private UUID system - * (sets fields from message_uuid, clears uuid_suffix) */ - -int -message_uuid_assign(struct message_uuid *uuid); - /* Assign next UUID to preallocated structure */ - /* Returns: Cyrus error code, 0 on sucess */ - -struct message_uuid * -message_uuid_alloc(); - /* Allocate and assign next UUID using xmalloc */ - /* Returns NULL Message-UUID if allocation exhaused */ - /* NULL => alloc failed */ - -void -message_uuid_free(struct message_uuid **uuidp); - /* Free Message UUID structure */ - -int message_uuid_compare(struct message_uuid *uuid1, struct message_uuid *uuid2); /* Compare a pair of UUIDs: Returns 1 => match */ @@ -52,6 +32,10 @@ /* Routines for manipulating packed values */ +void +message_uuid_shortmd5(struct message_uuid *uuid, unsigned char *md5); + /* Generate UUID from message md5 */ + int message_uuid_pack(struct message_uuid *uuid, char *packed); /* Store Message UID as packed sequence (MESSAGE_UUID_PACKED_SIZE) diff -udr cyrus-imapd-2.3.8/master/Makefile.in cyrus-imapd/master/Makefile.in --- cyrus-imapd-2.3.8/master/Makefile.in 2006-11-30 17:11:23.000000000 +0000 +++ cyrus-imapd/master/Makefile.in 2007-05-08 18:03:43.000000000 +0100 @@ -86,8 +86,8 @@ $(CC) -c $(CPPFLAGS) $(DEFS) $(CFLAGS) \ $< -master: master.o masterconf.o message_uuid_master.o cyrusMasterMIB.o ../lib/lock_@WITH_LOCK@.o - $(CC) $(LDFLAGS) -o master master.o masterconf.o message_uuid_master.o cyrusMasterMIB.o ../lib/lock_@WITH_LOCK@.o $(LIBS) $(DEPLIBS) +master: master.o masterconf.o cyrusMasterMIB.o ../lib/lock_@WITH_LOCK@.o + $(CC) $(LDFLAGS) -o master master.o masterconf.o cyrusMasterMIB.o ../lib/lock_@WITH_LOCK@.o $(LIBS) $(DEPLIBS) clean: rm -f *.o *.a Makefile.bak $(PROGS) diff -udr cyrus-imapd-2.3.8/master/master.c cyrus-imapd/master/master.c --- cyrus-imapd-2.3.8/master/master.c 2006-11-30 17:11:23.000000000 +0000 +++ cyrus-imapd/master/master.c 2007-05-08 18:03:43.000000000 +0100 @@ -113,8 +113,6 @@ #include "xmalloc.h" -#include "message_uuid_master.h" - enum { become_cyrus_early = 1, child_table_size = 10000, @@ -124,7 +122,6 @@ static int verbose = 0; static int listen_queue_backlog = 32; static int pidfd = -1; -static int have_uuid = 0; const char *MASTER_CONFIG_FILENAME = DEFAULT_MASTER_CONFIG_FILENAME; @@ -601,7 +598,6 @@ struct centry *c; struct service * const s = &Services[si]; time_t now = time(NULL); - struct message_uuid uuid_prefix; char *uuid_prefix_text; static char uuid_env[100]; @@ -650,21 +646,6 @@ return; } - if (s->provide_uuid) { - if (!message_uuid_master_next_child(&uuid_prefix)) { - syslog(LOG_ERR, "Failed to generate UUID for %s", s->name); - message_uuid_set_null(&uuid_prefix); - } - - if (!message_uuid_master_checksum(&uuid_prefix)) { - syslog(LOG_ERR, "Failed to checksum UUID for %s", s->name); - message_uuid_set_null(&uuid_prefix); - } - - uuid_prefix_text = message_uuid_text(&uuid_prefix); - } else - uuid_prefix_text = NULL; - switch (p = fork()) { case -1: syslog(LOG_ERR, "can't fork process to run service %s: %m", s->name); @@ -708,13 +689,6 @@ snprintf(name_env2, sizeof(name_env2), "CYRUS_ID=%d", s->associate); putenv(name_env2); - /* add UUID prefix to environment */ - if (s->provide_uuid) { - snprintf(uuid_env, sizeof(uuid_env), "CYRUS_UUID_PREFIX=%s", - uuid_prefix_text); - putenv(uuid_env); - } - execv(path, s->exec); syslog(LOG_ERR, "couldn't exec %s: %m", path); exit(EX_OSERR); @@ -1347,7 +1321,6 @@ rlim_t maxfds = (rlim_t) masterconf_getint(e, "maxfds", 256); int reconfig = 0; int i, j; - int provide_uuid = have_uuid && masterconf_getswitch(e, "provide_uuid", 0); if(babysit && prefork == 0) prefork = 1; if(babysit && maxforkrate == 0) maxforkrate = 10; /* reasonable safety */ @@ -1427,7 +1400,6 @@ Services[i].maxforkrate = maxforkrate; Services[i].maxfds = maxfds; - Services[i].provide_uuid = provide_uuid; if (!strcmp(Services[i].proto, "tcp") || !strcmp(Services[i].proto, "tcp4") || @@ -1456,7 +1428,6 @@ Services[j].desired_workers = Services[i].desired_workers; Services[j].babysit = Services[i].babysit; Services[j].max_workers = Services[i].max_workers; - Services[j].provide_uuid = Services[i].provide_uuid; } } } @@ -1954,12 +1925,6 @@ } } - have_uuid = (config_getint(IMAPOPT_SYNC_MACHINEID) >= 0); - if (have_uuid && !message_uuid_master_init()) { - syslog(LOG_ERR, "Couldn't initialise UUID subsystem"); - exit(EX_OSERR); - } - /* init ctable janitor */ init_janitor(); @@ -2016,7 +1981,6 @@ Services[i].nactive = 0; Services[i].nconnections = 0; Services[i].associate = 0; - Services[i].provide_uuid = 0; if (Services[i].stat[0] > 0) close(Services[i].stat[0]); if (Services[i].stat[1] > 0) close(Services[i].stat[1]); diff -udr cyrus-imapd-2.3.8/master/master.h cyrus-imapd/master/master.h --- cyrus-imapd-2.3.8/master/master.h 2006-11-30 17:11:23.000000000 +0000 +++ cyrus-imapd/master/master.h 2007-05-08 18:03:43.000000000 +0100 @@ -15,7 +15,6 @@ char *proto; /* protocol to accept */ char *const *exec; /* command (with args) to execute */ int babysit; /* babysit this service? */ - int provide_uuid; /* Service assigns UUIDS */ /* multiple address family support */ int associate; /* are we primary or additional instance? */