I had some time again this past weekend to work on contiguous UIDs and spent it on a patch (to the 2_2 branch; I’ve yet to test trunk) which ensures that whenever dbmail does a lookup on the messages table using message_idnr it also contrains the query by mailbox_idnr.
That is necessary to make (mailbox_idnr,message_idnr) the primary key. I’m running with this patch now, and have had no problems with it. I also did some testing with the schema change and IMAP at least worked perfectly. There was, however, a small problem with injection — once the schema is changed querying currval('dbmail_message_idnr_seq') to find the new messages’ uid won’t work. Either messages still must have a serial column or I have to come up with another way to find out what uid the trigger assigned to the newly injected messages row. Since only IMAP really needs the contiguous uids, I suspect the way forward is to have both the current message_idnr column and an imap_uid column, keep message_idnr as the primary key, add an unique constraint on (mailbox_idnr, imap_uid) and have imapd use the imap_uid column instead of the message_idnr column. In any case, this patch adds the additional contraint to the queries which didn’t already have it — some already did — but doesn’t otherwise change the behavior as seen by users. Also, I only use smtp and imapd, so only those are actually tested. -JimC
diff --git a/check_dbmail_misc.c b/check_dbmail_misc.c index 2682170..3e80b38 100644 --- a/check_dbmail_misc.c +++ b/check_dbmail_misc.c @@ -229,8 +229,8 @@ START_TEST(test_create_unique_id) { char *a = g_new0(char, 64); char *b = g_new0(char, 64); - create_unique_id(a,0); - create_unique_id(b,0); + create_unique_id(a,0,0); + create_unique_id(b,0,0); fail_unless(strlen(a)==32, "create_unique_id produced incorrect string length [%s]", a); fail_unless(strlen(b)==32, "create_unique_id produced incorrect string length [%s]", b); fail_unless(!MATCH(a,b),"create_unique_id shouldn't produce identical output"); diff --git a/db.c b/db.c index e32f629..786b356 100644 --- a/db.c +++ b/db.c @@ -325,7 +325,7 @@ int db_rollback_savepoint_transaction(const char* name) return DM_SUCCESS; } -int db_get_physmessage_id(u64_t message_idnr, u64_t * physmessage_id) +int db_get_physmessage_id(u64_t mailbox_idnr, u64_t message_idnr, u64_t * physmessage_id) { char query[DEF_QUERYSIZE]; memset(query,0,DEF_QUERYSIZE); @@ -335,7 +335,7 @@ int db_get_physmessage_id(u64_t message_idnr, u64_t * physmessage_id) snprintf(query, DEF_QUERYSIZE, "SELECT physmessage_id FROM %smessages " - "WHERE message_idnr = %llu", DBPFX, message_idnr); + "WHERE mailbox_idnr = %llu AND message_idnr = %llu", DBPFX, mailbox_idnr, message_idnr); if (db_query(query) == -1) { TRACE(TRACE_ERROR, "error getting physmessage_id"); @@ -1052,6 +1052,7 @@ int db_get_reply_body(u64_t user_idnr, char **reply_body) return DM_SUCCESS; } +/* Cannot really have this w/ per-mailbox uids.... */ u64_t db_get_mailbox_from_message(u64_t message_idnr) { u64_t mailbox_idnr; @@ -1079,7 +1080,7 @@ u64_t db_get_mailbox_from_message(u64_t message_idnr) return mailbox_idnr; } -u64_t db_get_useridnr(u64_t message_idnr) +u64_t db_get_useridnr(u64_t mailbox_idnr, u64_t message_idnr) { const char *query_result; u64_t user_idnr; @@ -1090,8 +1091,9 @@ u64_t db_get_useridnr(u64_t message_idnr) snprintf(query, DEF_QUERYSIZE, "SELECT %smailboxes.owner_idnr FROM %smailboxes, %smessages " "WHERE %smailboxes.mailbox_idnr = %smessages.mailbox_idnr " + "AND %smessages.mailbox_idnr = %llu " "AND %smessages.message_idnr = %llu", DBPFX,DBPFX,DBPFX, - DBPFX,DBPFX,DBPFX,message_idnr); + DBPFX,DBPFX,DBPFX,mailbox_idnr,DBPFX,message_idnr); if (db_query(query) == -1) { /* query failed */ TRACE(TRACE_ERROR, "query failed" ); @@ -1147,7 +1149,7 @@ int db_insert_physmessage(u64_t * physmessage_id) return db_insert_physmessage_with_internal_date(NULL, physmessage_id); } -int db_message_set_unique_id(u64_t message_idnr, const char *unique_id) +int db_message_set_unique_id(u64_t mailbox_idnr, u64_t message_idnr, const char *unique_id) { char query[DEF_QUERYSIZE]; memset(query,0,DEF_QUERYSIZE); @@ -1156,11 +1158,11 @@ int db_message_set_unique_id(u64_t message_idnr, const char *unique_id) snprintf(query, DEF_QUERYSIZE, "UPDATE %smessages SET unique_id = '%s', status = %d " - "WHERE message_idnr = %llu", DBPFX, unique_id, MESSAGE_STATUS_NEW, - message_idnr); + "WHERE mailbox_idnr = %llu AND message_idnr = %llu", DBPFX, + unique_id, MESSAGE_STATUS_NEW, mailbox_idnr, message_idnr); if (db_query(query) == DM_EQUERY) { - TRACE(TRACE_ERROR, "setting unique id for message [%llu] failed", - message_idnr); + TRACE(TRACE_ERROR, "setting unique id for mailbox [%llu] message [%llu] failed", + mailbox_idnr, message_idnr); return DM_EQUERY; } return DM_SUCCESS; @@ -1186,27 +1188,27 @@ int db_physmessage_set_sizes(u64_t physmessage_id, u64_t message_size, return DM_SUCCESS; } -int db_update_message(u64_t message_idnr, const char *unique_id, +int db_update_message(u64_t mailbox_idnr, u64_t message_idnr, const char *unique_id, u64_t message_size, u64_t rfc_size) { assert(unique_id); u64_t physmessage_id = 0; - if (db_message_set_unique_id(message_idnr, unique_id)) + if (db_message_set_unique_id(mailbox_idnr, message_idnr, unique_id)) return DM_EQUERY; /* update the fields in the physmessage table */ - if (db_get_physmessage_id(message_idnr, &physmessage_id)) + if (db_get_physmessage_id(mailbox_idnr, message_idnr, &physmessage_id)) return DM_EQUERY; if (db_physmessage_set_sizes(physmessage_id, message_size, rfc_size)) return DM_EQUERY; - if (user_quotum_inc(db_get_useridnr(message_idnr), message_size)) { + if (user_quotum_inc(db_get_useridnr(mailbox_idnr, message_idnr), message_size)) { TRACE(TRACE_ERROR, "error calculating quotum " "used for user [%llu]. Database might be " "inconsistent. Run dbmail-util.", - db_get_useridnr(message_idnr)); + db_get_useridnr(mailbox_idnr, message_idnr)); return DM_EQUERY; } return DM_SUCCESS; @@ -1263,7 +1265,7 @@ int db_insert_message_block_physmessage(const char *block, } int db_insert_message_block(const char *block, u64_t block_size, - u64_t message_idnr, u64_t * messageblk_idnr, unsigned is_header) + u64_t mailbox_idnr, u64_t message_idnr, u64_t * messageblk_idnr, unsigned is_header) { u64_t physmessage_id; @@ -1274,7 +1276,7 @@ int db_insert_message_block(const char *block, u64_t block_size, return DM_EQUERY; } - if (db_get_physmessage_id(message_idnr, &physmessage_id) == DM_EQUERY) { + if (db_get_physmessage_id(mailbox_idnr, message_idnr, &physmessage_id) == DM_EQUERY) { TRACE(TRACE_ERROR, "error getting physmessage_id"); return DM_EQUERY; } @@ -1565,7 +1567,7 @@ int db_icheck_physmessages(gboolean cleanup) int db_icheck_messages(struct dm_list *lost_list) { - u64_t message_idnr; + static box_uid_t box_uid = { .mailbox = 0, .uid = 0 }; int i, n; char query[DEF_QUERYSIZE]; memset(query,0,DEF_QUERYSIZE); @@ -1574,7 +1576,7 @@ int db_icheck_messages(struct dm_list *lost_list) dm_list_init(lost_list); snprintf(query, DEF_QUERYSIZE, - "SELECT msg.message_idnr FROM %smessages msg " + "SELECT msg.mailbox_idnr, msg.message_idnr FROM %smessages msg " "LEFT JOIN %smailboxes mbx ON " "msg.mailbox_idnr=mbx.mailbox_idnr " "WHERE mbx.mailbox_idnr IS NULL",DBPFX,DBPFX); @@ -1592,11 +1594,14 @@ int db_icheck_messages(struct dm_list *lost_list) } for (i = 0; i < n; i++) { - if (!(message_idnr = db_get_result_u64(i, 0))) + if (!(box_uid.mailbox = db_get_result_u64(i, 0))) continue; - TRACE(TRACE_INFO, "found lost message id [%llu]", message_idnr); - if (!dm_list_nodeadd(lost_list, &message_idnr, sizeof(u64_t))) { + if (!(box_uid.uid = db_get_result_u64(i, 1))) + continue; + + TRACE(TRACE_INFO, "found lost message id [%llu/%llu]", box_uid.mailbox, box_uid.uid); + if (!dm_list_nodeadd(lost_list, &box_uid, sizeof(box_uid_t))) { TRACE(TRACE_ERROR, "could not add message to list"); dm_list_free(&lost_list->start); db_free_result(); @@ -1699,7 +1704,7 @@ int db_icheck_null_physmessages(struct dm_list *lost_list) int db_icheck_null_messages(struct dm_list *lost_list) { - u64_t message_idnr; + static box_uid_t box_uid = { .mailbox = 0, .uid = 0 }; int i, n; char query[DEF_QUERYSIZE]; memset(query,0,DEF_QUERYSIZE); @@ -1708,7 +1713,7 @@ int db_icheck_null_messages(struct dm_list *lost_list) dm_list_init(lost_list); snprintf(query, DEF_QUERYSIZE, - "SELECT msg.message_idnr FROM %smessages msg " + "SELECT msg.mailbox_idnr, msg.message_idnr FROM %smessages msg " "LEFT JOIN %sphysmessage pm ON " "msg.physmessage_id = pm.id WHERE pm.id is NULL",DBPFX,DBPFX); @@ -1725,11 +1730,14 @@ int db_icheck_null_messages(struct dm_list *lost_list) } for (i = 0; i < n; i++) { - if (!(message_idnr = db_get_result_u64(i, 0))) + if (!(box_uid.mailbox = db_get_result_u64(i, 0))) + continue; + + if (!(box_uid.uid = db_get_result_u64(i, 1))) continue; - TRACE(TRACE_INFO, "found empty message id [%llu]", message_idnr); - if (!dm_list_nodeadd(lost_list, &message_idnr, sizeof(u64_t))) { + TRACE(TRACE_INFO, "found empty mailbox id [ %llu] message id [%llu]", box_uid.mailbox, box_uid.uid); + if (!dm_list_nodeadd(lost_list, &box_uid, sizeof(box_uid_t))) { TRACE(TRACE_ERROR, "could not add message to list"); dm_list_free(&lost_list->start); db_free_result(); @@ -2011,13 +2019,13 @@ int db_icheck_envelope(GList **lost) } -int db_set_message_status(u64_t message_idnr, MessageStatus_t status) +int db_set_message_status(u64_t mailbox_idnr, u64_t message_idnr, MessageStatus_t status) { char query[DEF_QUERYSIZE]; memset(query,0,DEF_QUERYSIZE); - snprintf(query, DEF_QUERYSIZE, "UPDATE %smessages SET status = %d WHERE message_idnr = %llu", - DBPFX, status, message_idnr); + snprintf(query, DEF_QUERYSIZE, "UPDATE %smessages SET status = %d WHERE mailbox_idnr = %llu AND message_idnr = %llu", + DBPFX, status, mailbox_idnr, message_idnr); return db_query(query); } @@ -2057,7 +2065,7 @@ int db_delete_physmessage(u64_t physmessage_id) return DM_EGENERAL; } -int db_delete_message(u64_t message_idnr) +int db_delete_message(u64_t mailbox_idnr, u64_t message_idnr) { u64_t physmessage_id; int rows; @@ -2065,25 +2073,25 @@ int db_delete_message(u64_t message_idnr) memset(query,0,DEF_QUERYSIZE); - if (db_get_physmessage_id(message_idnr, &physmessage_id) == DM_EQUERY) + if (db_get_physmessage_id(mailbox_idnr, message_idnr, &physmessage_id) == DM_EQUERY) return DM_EQUERY; /* now delete the message from the message table */ snprintf(query, DEF_QUERYSIZE, "DELETE FROM %smessages " - "WHERE message_idnr = %llu", - DBPFX, message_idnr); + "WHERE mailbox_idnr = %llu AND message_idnr = %llu", + DBPFX, mailbox_idnr, message_idnr); if (db_query(query) == DM_EQUERY) { - TRACE(TRACE_ERROR,"error deleting message [%llu]", message_idnr); + TRACE(TRACE_ERROR,"error deleting mailbox [%llu] message [%llu]", mailbox_idnr, message_idnr); return DM_EQUERY; } /* find other messages pointing to the same physmessage entry */ - snprintf(query, DEF_QUERYSIZE, "SELECT message_idnr FROM %smessages " + snprintf(query, DEF_QUERYSIZE, "SELECT mailbox_idnr, message_idnr FROM %smessages " "WHERE physmessage_id = %llu",DBPFX, physmessage_id); if (db_query(query) == -1) { - TRACE(TRACE_ERROR, "error finding physmessage for message [%llu]", message_idnr); + TRACE(TRACE_ERROR, "error finding physmessage for mailbox [%llu] message [%llu]", mailbox_idnr, message_idnr); return DM_EQUERY; } @@ -2148,7 +2156,7 @@ static int mailbox_empty(u64_t mailbox_idnr) db_free_result(); /* delete every message in the mailbox */ for (i = 0; i < n; i++) { - if (db_delete_message(message_idnrs[i]) == -1) { + if (db_delete_message(mailbox_idnr, message_idnrs[i]) == -1) { g_free(message_idnrs); return DM_EQUERY; } @@ -2208,7 +2216,7 @@ int db_delete_mailbox(u64_t mailbox_idnr, int only_empty, return DM_SUCCESS; } -int db_send_message_lines(void *fstream, u64_t message_idnr, long lines, int no_end_dot) +int db_send_message_lines(void *fstream, u64_t mailbox_idnr, u64_t message_idnr, long lines, int no_end_dot) { struct DbmailMessage *msg; @@ -2221,7 +2229,7 @@ int db_send_message_lines(void *fstream, u64_t message_idnr, long lines, int no_ TRACE(TRACE_DEBUG, "request for [%ld] lines", lines); /* first find the physmessage_id */ - if (db_get_physmessage_id(message_idnr, &physmessage_id) != DM_SUCCESS) + if (db_get_physmessage_id(mailbox_idnr, message_idnr, &physmessage_id) != DM_SUCCESS) return DM_EGENERAL; TRACE(TRACE_DEBUG, "sending [%ld] lines from message [%llu]", @@ -2285,6 +2293,8 @@ int db_createsession(u64_t user_idnr, PopSession_t * session_ptr) g_return_val_if_fail(mailbox_idnr > 0, DM_EQUERY); + session_ptr->mailbox_idnr = mailbox_idnr; + /* query is < MESSAGE_STATUS_DELETE because we don't want deleted * messages */ @@ -2385,14 +2395,19 @@ int db_update_pop(PopSession_t * session_ptr) user_idnr = db_get_useridnr(((struct message *) tmpelement->data)-> + mailbox, + ((struct message *) + tmpelement->data)-> realmessageid); /* yes they need an update, do the query */ snprintf(query, DEF_QUERYSIZE, "UPDATE %smessages set status=%d WHERE " - "message_idnr=%llu AND status < %d",DBPFX, + "mailbox_idnr=%llu AND message_idnr=%llu AND status < %d",DBPFX, ((struct message *) tmpelement->data)->virtual_messagestatus, + ((struct message *) + tmpelement->data)->mailbox, ((struct message *) tmpelement->data)-> realmessageid, MESSAGE_STATUS_DELETE); @@ -2462,6 +2477,7 @@ int db_deleted_purge(u64_t * affected_rows) char query[DEF_QUERYSIZE]; memset(query,0,DEF_QUERYSIZE); + u64_t *mailbox_idnrs; u64_t *message_idnrs; assert(affected_rows != NULL); @@ -2469,12 +2485,12 @@ int db_deleted_purge(u64_t * affected_rows) /* first we're deleting all the messageblks */ snprintf(query, DEF_QUERYSIZE, - "SELECT message_idnr FROM %smessages WHERE status=%d",DBPFX, + "SELECT mailbox_idnr, message_idnr FROM %smessages WHERE status=%d",DBPFX, MESSAGE_STATUS_PURGE); TRACE(TRACE_DEBUG, "executing query [%s]", query); if (db_query(query) == -1) { - TRACE(TRACE_ERROR, "Cound not fetch message ID numbers"); + TRACE(TRACE_ERROR, "Cound not fetch mailbox/message ID number tuples"); return DM_EQUERY; } @@ -2485,21 +2501,26 @@ int db_deleted_purge(u64_t * affected_rows) return DM_SUCCESS; } + mailbox_idnrs = g_new0(u64_t, *affected_rows); message_idnrs = g_new0(u64_t, *affected_rows); /* delete each message */ - for (i = 0; i < *affected_rows; i++) - message_idnrs[i] = db_get_result_u64(i, 0); - + for (i = 0; i < *affected_rows; i++) { + mailbox_idnrs[i] = db_get_result_u64(i, 0); + message_idnrs[i] = db_get_result_u64(i, 1); + } + db_free_result(); for (i = 0; i < *affected_rows; i++) { - if (db_delete_message(message_idnrs[i]) == -1) { - TRACE(TRACE_ERROR, "error deleting message"); + if (db_delete_message(mailbox_idnrs[i], message_idnrs[i]) == -1) { + TRACE(TRACE_ERROR, "error deleting mailbox [%llu] message [%llu]", + mailbox_idnrs[i], message_idnrs[i]); g_free(message_idnrs); return DM_EQUERY; } } g_free(message_idnrs); + g_free(mailbox_idnrs); return DM_EGENERAL; } @@ -2558,8 +2579,8 @@ int db_imap_append_msg(const char *msgdata, u64_t datalen UNUSED, } dbmail_message_store(message); - result = db_copymsg(message->id, mailbox_idnr, user_idnr, msg_idnr); - db_delete_message(message->id); + result = db_copymsg(message->mailbox, message->id, mailbox_idnr, user_idnr, msg_idnr); + db_delete_message(mailbox_idnr, message->id); dbmail_message_free(message); switch (result) { @@ -2580,7 +2601,7 @@ int db_imap_append_msg(const char *msgdata, u64_t datalen UNUSED, TRACE(TRACE_MESSAGE, "message id=%llu is inserted", *msg_idnr); - return db_set_message_status(*msg_idnr, MESSAGE_STATUS_SEEN); + return db_set_message_status(mailbox_idnr, *msg_idnr, MESSAGE_STATUS_SEEN); } int db_findmailbox(const char *fq_name, u64_t owner_idnr, u64_t * mailbox_idnr) @@ -3767,7 +3788,7 @@ int db_mailbox_has_message_id(u64_t mailbox_idnr, const char *messageid) } -static u64_t message_get_size(u64_t message_idnr) +static u64_t message_get_size(u64_t mailbox_idnr, u64_t message_idnr) { u64_t size = 0; char query[DEF_QUERYSIZE]; @@ -3777,7 +3798,7 @@ static u64_t message_get_size(u64_t message_idnr) snprintf(query, DEF_QUERYSIZE, "SELECT pm.messagesize FROM %sphysmessage pm, %smessages msg " "WHERE pm.id = msg.physmessage_id " - "AND message_idnr = %llu",DBPFX,DBPFX, message_idnr); + "AND mailbox_idnr = %llu AND message_idnr = %llu",DBPFX,DBPFX, mailbox_idnr, message_idnr); if (db_query(query)) return size; /* err */ @@ -3789,8 +3810,8 @@ static u64_t message_get_size(u64_t message_idnr) return size; } -int db_copymsg(u64_t msg_idnr, u64_t mailbox_to, u64_t user_idnr, - u64_t * newmsg_idnr) +int db_copymsg(u64_t mailbox_from, u64_t msg_idnr, u64_t mailbox_to, + u64_t user_idnr, u64_t * newmsg_idnr) { u64_t msgsize; char unique_id[UID_SIZE]; @@ -3799,9 +3820,9 @@ int db_copymsg(u64_t msg_idnr, u64_t mailbox_to, u64_t user_idnr, /* Get the size of the message to be copied. */ - if (! (msgsize = message_get_size(msg_idnr))) { + if (! (msgsize = message_get_size(mailbox_from, msg_idnr))) { TRACE(TRACE_ERROR, "error getting message size for " - "message [%llu]", msg_idnr); + "mailbox [%llu] message [%llu]", mailbox_from, msg_idnr); return DM_EQUERY; } @@ -3816,7 +3837,7 @@ int db_copymsg(u64_t msg_idnr, u64_t mailbox_to, u64_t user_idnr, return -2; } - create_unique_id(unique_id, msg_idnr); + create_unique_id(unique_id, mailbox_to, msg_idnr); /* Copy the message table entry of the message. */ snprintf(query, DEF_QUERYSIZE, @@ -3826,8 +3847,8 @@ int db_copymsg(u64_t msg_idnr, u64_t mailbox_to, u64_t user_idnr, "SELECT %llu, " "physmessage_id, seen_flag, answered_flag, deleted_flag, " "flagged_flag, recent_flag, draft_flag, '%s', status " - "FROM %smessages WHERE message_idnr = %llu",DBPFX, - mailbox_to, unique_id,DBPFX, msg_idnr); + "FROM %smessages WHERE mailbox_idnr = %llu AND message_idnr = %llu", + DBPFX, mailbox_to, unique_id, DBPFX, mailbox_from, msg_idnr); if (db_query(query) == -1) { TRACE(TRACE_ERROR, "error copying message"); diff --git a/db.h b/db.h index b5fdd6d..ea31c49 100644 --- a/db.h +++ b/db.h @@ -302,18 +302,19 @@ int db_rollback_savepoint_transaction(const char*); /* shared implementattion from hereon */ /** - * \brief get the physmessage_id from a message_idnr + * \brief get the physmessage_id from a mailbox_idnr, message_idnr tuple + * \param mailbox_idnr * \param message_idnr * \param physmessage_id will hold physmessage_id on return. Must hold a valid * pointer on call. * \return * - -1 on error * - 0 if a physmessage_id was found - * - 1 if no message with this message_idnr found + * - 1 if no message with this mailbox_idnr, message_idnr tuple was found * \attention function will fail and halt program if physmessage_id is * NULL on call. */ -int db_get_physmessage_id(u64_t message_idnr, /[EMAIL PROTECTED]@*/ u64_t * physmessage_id); +int db_get_physmessage_id(u64_t mailbox_idnr, u64_t message_idnr, /[EMAIL PROTECTED]@*/ u64_t * physmessage_id); /** * \brief return number of bytes used by user identified by userid @@ -502,13 +503,14 @@ int db_get_reply_body(u64_t user_idnr, char **body); /** * \brief get user idnr of a message. + * \param mailbox_idnr idnr of message * \param message_idnr idnr of message * \return * - -1 on failure * - 0 if message is located in a shared mailbox. * - user_idnr otherwise */ -u64_t db_get_useridnr(u64_t message_idnr); +u64_t db_get_useridnr(u64_t mailbox_idnr, u64_t message_idnr); /** * \brief insert a new physmessage. This inserts only an new record in the @@ -536,6 +538,7 @@ int db_insert_physmessage_with_internal_date(timestring_t internal_date, /** * \brief update unique_id, message_size and rfc_size of * a message identified by message_idnr + * \param mailbox_idnr * \param message_idnr * \param unique_id unique id of message * \param message_size size of message @@ -544,17 +547,18 @@ int db_insert_physmessage_with_internal_date(timestring_t internal_date, * - -1 on database error * - 0 on success */ -int db_update_message(u64_t message_idnr, const char *unique_id, +int db_update_message(u64_t mailbox_idnr, u64_t message_idnr, const char *unique_id, u64_t message_size, u64_t rfc_size); /** * \brief set unique id of a message + * \param mailbox_idnr * \param message_idnr * \param unique_id unique id of message * \return * - -1 on database error * - 0 on success */ -int db_message_set_unique_id(u64_t message_idnr, const char *unique_id); +int db_message_set_unique_id(u64_t mailbox_idnr, u64_t message_idnr, const char *unique_id); /** * \brief set messagesize and rfcsize of a message @@ -588,6 +592,7 @@ int db_insert_message_block_physmessage(const char *block, * \brief insert a message block into the message block table * \param block the message block (which is a string) * \param block_size length of the block +* \param mailbox_idnr mailbox of the message the block belongs to * \param message_idnr id of the message the block belongs to * \param messageblock_idnr will hold id of messageblock after call. Should * be a valid pointer on call. @@ -596,6 +601,7 @@ int db_insert_message_block_physmessage(const char *block, * - 0 otherwise */ int db_insert_message_block(const char *block, u64_t block_size, + u64_t mailbox_idnr, u64_t message_idnr, /[EMAIL PROTECTED]@*/ u64_t * messageblock_idnr, unsigned is_header); @@ -751,11 +757,12 @@ int db_icheck_envelope(GList **lost); int db_set_envelope(GList *lost); /** * \brief set status of a message + * \param mailbox_idnr * \param message_idnr * \param status new status of message * \return result of db_query() */ -int db_set_message_status(u64_t message_idnr, MessageStatus_t status); +int db_set_message_status(u64_t mailbox_idnr, u64_t message_idnr, MessageStatus_t status); /** * \brief delete a message block @@ -774,12 +781,13 @@ int db_delete_physmessage(u64_t physmessage_id); /** * \brief delete a message + * \param mailbox_idnr * \param message_idnr * \return * - -1 on error * - 1 on success */ -int db_delete_message(u64_t message_idnr); +int db_delete_message(u64_t mailbox_idnr, u64_t message_idnr); /** * \brief delete a mailbox. @@ -799,6 +807,7 @@ int db_delete_mailbox(u64_t mailbox_idnr, int only_empty, /** * \brief write lines of message to fstream. Always write full headers. * \param fstream the stream to write to + * \param mailbox_idnr mailbox of message to write * \param message_idnr idrn of message to write * \param lines number of lines to write. If <PRE>lines == -2</PRE>, then * the whole message (excluding the header) is written. @@ -810,7 +819,7 @@ int db_delete_mailbox(u64_t mailbox_idnr, int only_empty, * - 0 on failure * - 1 on success */ -int db_send_message_lines(void *fstream, u64_t message_idnr, +int db_send_message_lines(void *fstream, u64_t mailbox_idnr, u64_t message_idnr, long lines, int no_end_dot); /** * \brief create a new POP3 session. (was createsession() in dbmysql.c) @@ -1093,6 +1102,7 @@ int db_removemsg(u64_t user_idnr, u64_t mailbox_idnr); int db_movemsg(u64_t mailbox_to, u64_t mailbox_from); /** * \brief copy a message to a mailbox + * \param mailbox_from mailbox to copy from * \param msg_idnr * \param mailbox_to mailbox to copy to * \param user_idnr user to copy the messages for. @@ -1101,7 +1111,7 @@ int db_movemsg(u64_t mailbox_to, u64_t mailbox_from); * - -1 on failure * - 0 on success */ -int db_copymsg(u64_t msg_idnr, u64_t mailbox_to, +int db_copymsg(u64_t mailbox_from, u64_t msg_idnr, u64_t mailbox_to, u64_t user_idnr, u64_t * newmsg_idnr); /** diff --git a/dbmail-imapsession.c b/dbmail-imapsession.c index 3051336..6eb6943 100644 --- a/dbmail-imapsession.c +++ b/dbmail-imapsession.c @@ -362,7 +362,7 @@ static u64_t _imap_cache_update(struct ImapSession *self, message_filter_t filte cached_msg.dmsg = NULL; } - cached_msg.dmsg = db_init_fetch(self->msg_idnr, DBMAIL_MESSAGE_FILTER_FULL); + cached_msg.dmsg = db_init_fetch(self->mailbox->id, self->msg_idnr, DBMAIL_MESSAGE_FILTER_FULL); buf = dbmail_message_to_string(cached_msg.dmsg); outcnt = _imap_cache_set_dump(buf,IMAP_CACHE_MEMDUMP); @@ -2076,12 +2076,15 @@ int dbmail_imap_session_mailbox_close(struct ImapSession *self) return 0; } -static int imap_session_update_recent(GList *recent) +static int imap_session_update_recent(struct DbmailMailbox *mailbox, GList *recent) { GList *slices, *topslices; char query[DEF_QUERYSIZE]; memset(query,0,DEF_QUERYSIZE); + if (mailbox == NULL) + return 0; + if (recent == NULL) return 0; @@ -2091,8 +2094,8 @@ static int imap_session_update_recent(GList *recent) db_begin_transaction(); while (slices) { snprintf(query, DEF_QUERYSIZE, "UPDATE %smessages SET recent_flag = 0 " - "WHERE message_idnr IN (%s) AND recent_flag = 1", - DBPFX, (gchar *)slices->data); + "WHERE mailbox_idnr = %llu AND message_idnr IN (%s) AND recent_flag = 1", + DBPFX, mailbox->id, (gchar *)slices->data); if (db_query(query) == -1) { db_rollback_transaction(); return (-1); @@ -2109,7 +2112,7 @@ static int imap_session_update_recent(GList *recent) int dbmail_imap_session_mailbox_update_recent(struct ImapSession *self) { - imap_session_update_recent(self->recent); + imap_session_update_recent(self->mailbox, self->recent); g_list_destroy(self->recent); self->recent = NULL; diff --git a/dbmail-mailbox.c b/dbmail-mailbox.c index b22f96f..ab03456 100644 --- a/dbmail-mailbox.c +++ b/dbmail-mailbox.c @@ -320,10 +320,10 @@ int dbmail_mailbox_dump(struct DbmailMailbox *self, FILE *file) g_string_printf(q,"SELECT is_header,messageblk,%s FROM %smessageblks b " "JOIN %sphysmessage p ON b.physmessage_id = p.id " "JOIN %smessages m USING (physmessage_id) " - "WHERE message_idnr IN (%s) " + "WHERE mailbox_idnr = %llu AND message_idnr IN (%s) " "ORDER BY messageblk_idnr ", date2char, - DBPFX, DBPFX, DBPFX, + DBPFX, DBPFX, DBPFX, self->id, (char *)slice->data); if (db_query(q->str) == -1) { diff --git a/dbmail-message.c b/dbmail-message.c index f55a71b..d967a2a 100644 --- a/dbmail-message.c +++ b/dbmail-message.c @@ -788,7 +788,7 @@ int dbmail_message_store(struct DbmailMessage *self) break; } - create_unique_id(unique_id, user_idnr); + create_unique_id(unique_id, user_idnr, user_idnr); /* create a message record */ if(_message_insert(self, user_idnr, DBMAIL_TEMPMBOX, unique_id) < 0) return -1; @@ -806,7 +806,7 @@ int dbmail_message_store(struct DbmailMessage *self) hdrs = dbmail_message_hdrs_to_string(self); hdrs_size = (u64_t)dbmail_message_get_hdrs_size(self, FALSE); - if(db_insert_message_block(hdrs, hdrs_size, self->id, &messageblk_idnr,1) < 0) { + if(db_insert_message_block(hdrs, hdrs_size, self->mailbox, self->id, &messageblk_idnr,1) < 0) { g_free(hdrs); return -1; } @@ -815,14 +815,14 @@ int dbmail_message_store(struct DbmailMessage *self) /* store body in several blocks (if needed */ body = dbmail_message_body_to_string(self); body_size = (u64_t)dbmail_message_get_body_size(self, FALSE); - if (store_message_in_blocks(body, body_size, self->id) < 0) { + if (store_message_in_blocks(body, body_size, self->mailbox, self->id) < 0) { g_free(body); return -1; } g_free(body); rfcsize = (u64_t)dbmail_message_get_rfcsize(self); - if (db_update_message(self->id, unique_id, (hdrs_size + body_size), rfcsize) < 0) + if (db_update_message(self->mailbox, self->id, unique_id, (hdrs_size + body_size), rfcsize) < 0) return -1; /* store message headers */ @@ -885,6 +885,7 @@ int _message_insert(struct DbmailMessage *self, return -1; } + self->mailbox = mailboxid; self->id = db_insert_result("message_idnr"); return 1; } @@ -1360,13 +1361,13 @@ struct DbmailMessage * dbmail_message_construct(struct DbmailMessage *self, /* old stuff moved here from dbmsgbuf.c */ -struct DbmailMessage * db_init_fetch(u64_t msg_idnr, int filter) +struct DbmailMessage * db_init_fetch(u64_t mailbox_idnr, u64_t msg_idnr, int filter) { struct DbmailMessage *msg; int result; u64_t physid = 0; - if ((result = db_get_physmessage_id(msg_idnr, &physid)) != DM_SUCCESS) + if ((result = db_get_physmessage_id(mailbox_idnr, msg_idnr, &physid)) != DM_SUCCESS) return NULL; msg = dbmail_message_new(); if (! (msg = dbmail_message_retrieve(msg, physid, filter))) diff --git a/dbmail-message.h b/dbmail-message.h index 979c105..7240ad5 100644 --- a/dbmail-message.h +++ b/dbmail-message.h @@ -61,6 +61,7 @@ typedef enum DBMAIL_STREAM_TYPE { } dbmail_stream_t; struct DbmailMessage { + u64_t mailbox; u64_t id; u64_t physid; time_t internal_date; @@ -172,7 +173,7 @@ char * g_mime_object_get_body(const GMimeObject *object); * - 1 on success */ -struct DbmailMessage * db_init_fetch(u64_t msg_idnr, int filter); +struct DbmailMessage * db_init_fetch(u64_t mailbox_idnr, u64_t msg_idnr, int filter); #define db_init_fetch_headers(x) db_init_fetch(x,DBMAIL_MESSAGE_FILTER_HEAD) #define db_init_fetch_message(x) db_init_fetch(x,DBMAIL_MESSAGE_FILTER_FULL) diff --git a/dbmailtypes.h b/dbmailtypes.h index d26265b..9b64d97 100644 --- a/dbmailtypes.h +++ b/dbmailtypes.h @@ -138,6 +138,7 @@ typedef struct { /** all virtual_ definitions are session specific * when a RSET occurs all will be set to the real values */ struct message { + u64_t mailbox; /**< mailbox idnr */ u64_t msize; /**< message size */ u64_t messageid; /**< messageid (from database) */ u64_t realmessageid; @@ -183,8 +184,9 @@ typedef struct { char *apop_stamp; /**< timestamp for APOP */ u64_t useridnr; /**< Used by timsieved */ + u64_t mailbox_idnr; - u64_t totalsize;/**< total size of messages */ + u64_t totalsize; /**< total size of messages */ u64_t virtual_totalsize; u64_t totalmessages; /**< number of messages */ u64_t virtual_totalmessages; @@ -515,5 +517,9 @@ typedef enum { IMAP_FLAG_RECENT } imap_flag_t; +typedef struct box_uid { + u64_t mailbox; + u64_t uid; +} box_uid_t; #endif diff --git a/export.c b/export.c index b81e454..e01942f 100644 --- a/export.c +++ b/export.c @@ -141,7 +141,7 @@ static int mailbox_dump(u64_t mailbox_idnr, const char *dumpfile, // Set deleted status on each message // Following this, dbmail-util -p sets purge status if (delete_after_dump & 2) { - if (db_set_message_status(*(u64_t *)ids->data, MESSAGE_STATUS_DELETE)) { + if (db_set_message_status(mailbox_idnr, *(u64_t *)ids->data, MESSAGE_STATUS_DELETE)) { qerrorf("Error setting status for message [%llu]\n", *(u64_t *)ids->data); result = -1; } diff --git a/imapcommands.c b/imapcommands.c index de05907..79e5cba 100644 --- a/imapcommands.c +++ b/imapcommands.c @@ -1692,7 +1692,7 @@ static gboolean _do_copy(u64_t *id, gpointer UNUSED value, struct ImapSession *s u64_t newid; int result; - result = db_copymsg(*id, cmd->mailbox_id, ud->userid, &newid); + result = db_copymsg(self->mailbox->id, *id, cmd->mailbox_id, ud->userid, &newid); if (result == -1) { dbmail_imap_session_printf(self, "* BYE internal dbase error\r\n"); db_rollback_transaction(); diff --git a/maintenance.c b/maintenance.c index c3459e3..68027b6 100644 --- a/maintenance.c +++ b/maintenance.c @@ -461,12 +461,14 @@ int do_dangling_aliases(void) return result; } +/* FIXME: lostlist needs to be of pairs of ints rather than of ints */ +/* figure out how to recover the individual pairs */ int do_null_messages(void) { time_t start, stop; struct dm_list lostlist; struct element *el; - u64_t id; + u64_t mailbox, id; if (no_to_all) { qprintf("\nChecking DBMAIL for NULL messages...\n"); @@ -494,11 +496,12 @@ int do_null_messages(void) if (lostlist.total_nodes > 0) { el = lostlist.start; while (el) { - id = *((u64_t *) el->data); - if (db_set_message_status(id, MESSAGE_STATUS_ERROR) < 0) - qerrorf("Warning: could not set status on message [%llu]. Check log.\n", id); + mailbox = ((box_uid_t *) el->data)->mailbox; + id = ((box_uid_t *) el->data)->uid; + if (db_set_message_status(mailbox, id, MESSAGE_STATUS_ERROR) < 0) + qerrorf("Warning: could not set status on mailbox [%llu] message [%llu]. Check log.\n", mailbox, id); else - qverbosef("[%llu] set to MESSAGE_STATUS_ERROR)\n", id); + qverbosef("[%llu/%llu] set to MESSAGE_STATUS_ERROR)\n", mailbox, id); el = el->nextnode; } @@ -551,7 +554,7 @@ int do_check_integrity(void) struct element *el; const char *action; int count = 0; - u64_t id; + u64_t mailbox, id; if (yes_to_all) action = "Repairing"; @@ -664,12 +667,13 @@ int do_check_integrity(void) if (lostlist.total_nodes > 0) { el = lostlist.start; while (el) { - id = *((u64_t *) el->data); + mailbox = ((box_uid_t *) el->data)->mailbox; + id = ((box_uid_t *) el->data)->uid; if (no_to_all) { qerrorf("%llu ", id); } else if (yes_to_all) { - if (db_delete_message(id) < 0) + if (db_delete_message(mailbox,id) < 0) qerrorf ("Warning: could not delete message #%llu. Check log.\n", id); diff --git a/misc.c b/misc.c index efc3bcc..0ec5282 100644 --- a/misc.c +++ b/misc.c @@ -95,17 +95,18 @@ int drop_privileges(char *newuser, char *newgroup) return 0; } -void create_unique_id(char *target, u64_t message_idnr) +void create_unique_id(char *target, u64_t mailbox_idnr, u64_t message_idnr) { - char *a_message_idnr, *a_rand; + char *a_mailbox_idnr, *a_message_idnr, *a_rand; char *md5_str; + a_mailbox_idnr = g_strdup_printf("%llu",mailbox_idnr); a_message_idnr = g_strdup_printf("%llu",message_idnr); a_rand = g_strdup_printf("%d",g_random_int()); if (message_idnr != 0) - snprintf(target, UID_SIZE, "%s:%s", - a_message_idnr, a_rand); + snprintf(target, UID_SIZE, "%s:%s:%s", + a_mailbox_idnr, a_message_idnr, a_rand); else snprintf(target, UID_SIZE, "%s", a_rand); md5_str = dm_md5((unsigned char *)target); diff --git a/misc.h b/misc.h index 5993a6f..51827d6 100644 --- a/misc.h +++ b/misc.h @@ -40,9 +40,10 @@ int drop_privileges(char *newuser, char *newgroup); /** * \brief create a unique id for a message (used for pop, stored per message) * \param target target string. Length should be UID_SIZE + * \param message_idnr mailbox_idnr of message * \param message_idnr message_idnr of message */ -void create_unique_id(/[EMAIL PROTECTED]@*/ char *target, u64_t message_idnr); +void create_unique_id(/[EMAIL PROTECTED]@*/ char *target, u64_t mailbox_idnr, u64_t message_idnr); /** * \brief create a timestring with the current time. diff --git a/pipe.c b/pipe.c index 63b4a23..8e9ffe2 100644 --- a/pipe.c +++ b/pipe.c @@ -157,7 +157,7 @@ static int send_mail(struct DbmailMessage *message, if (preoutput) fprintf(mailpipe, "%s\n", preoutput); // This function will dot-stuff the message. - db_send_message_lines(mailpipe, message->id, -2, 1); + db_send_message_lines(mailpipe, message->mailbox, message->id, -2, 1); break; case SENDMESSAGE: message_string = dbmail_message_to_string(message); @@ -462,7 +462,7 @@ static int execute_auto_ran(struct DbmailMessage *message, u64_t useridnr) int store_message_in_blocks(const char *message, u64_t message_size, - u64_t msgidnr) + u64_t mailbox, u64_t msgidnr) { u64_t tmp_messageblk_idnr; u64_t rest_size = message_size; @@ -478,7 +478,7 @@ int store_message_in_blocks(const char *message, u64_t message_size, 0 : rest_size - READ_BLOCK_SIZE); TRACE(TRACE_DEBUG, "inserting message [%s]", &message[offset]); if (db_insert_message_block(&message[offset], - block_size, msgidnr, + block_size, mailbox, msgidnr, &tmp_messageblk_idnr,0) < 0) { TRACE(TRACE_ERROR, "db_insert_message_block() failed"); return -1; @@ -528,7 +528,7 @@ int insert_messages(struct DbmailMessage *message, struct dm_list *dsnusers) { u64_t bodysize, rfcsize; - u64_t tmpid; + u64_t tmpbox, tmpid; struct element *element; u64_t msgsize; @@ -553,7 +553,9 @@ int insert_messages(struct DbmailMessage *message, if (db_commit_transaction() < 0) return -1; - tmpid = message->id; // for later removal + /* for later removal */ + tmpbox = message->mailbox; + tmpid = message->id; bodysize = (u64_t)dbmail_message_get_body_size(message, FALSE); rfcsize = (u64_t)dbmail_message_get_rfcsize(message); @@ -662,7 +664,7 @@ int insert_messages(struct DbmailMessage *message, /* Always delete the temporary message, even if the delivery failed. * It is the MTA's job to requeue or bounce the message, * and our job to keep a tidy database ;-) */ - if (db_delete_message(tmpid) < 0) + if (db_delete_message(tmpbox, tmpid) < 0) TRACE(TRACE_ERROR, "failed to delete temporary message [%llu]", message->id); TRACE(TRACE_DEBUG, "temporary message deleted from database. Done."); @@ -715,7 +717,8 @@ int send_alert(u64_t user_idnr, char *subject, char *body) // Pre-insert the message and get a new_message->id dbmail_message_store(new_message); - u64_t tmpid = new_message->id; + u64_t tmpbox = new_message->mailbox; + u64_t tmpid = new_message->id; if (sort_deliver_to_mailbox(new_message, user_idnr, "INBOX", BOX_BRUTEFORCE, msgflags) != DSN_CLASS_OK) { @@ -723,7 +726,7 @@ int send_alert(u64_t user_idnr, char *subject, char *body) } g_free(to); - db_delete_message(tmpid); + db_delete_message(tmpbox, tmpid); dbmail_message_free(new_message); return 0; diff --git a/pipe.h b/pipe.h index f433f88..e1cb9b7 100644 --- a/pipe.h +++ b/pipe.h @@ -41,6 +41,7 @@ int insert_messages(struct DbmailMessage *message, struct dm_list *dsnusers); */ int store_message_in_blocks(const char* message, u64_t message_size, + u64_t mailbox, u64_t msgidnr); int send_vacation(struct DbmailMessage *message, diff --git a/pop3.c b/pop3.c index 1b94adf..27b4483 100644 --- a/pop3.c +++ b/pop3.c @@ -92,7 +92,7 @@ int pop3_handle_connection(clientinfo_t * ci) /* create an unique timestamp + processid for APOP authentication */ session.apop_stamp = g_new0(char,APOP_STAMP_SIZE); - create_unique_id(unique_id, 0); + create_unique_id(unique_id, 0, 0); snprintf(session.apop_stamp, APOP_STAMP_SIZE, "<[EMAIL PROTECTED]>", unique_id, myhostname); if (ci->tx) { @@ -509,7 +509,7 @@ int pop3(clientinfo_t *ci, char *buffer, PopSession_t * session) if (msg->messageid == strtoull(value, NULL, 10) && msg->virtual_messagestatus < MESSAGE_STATUS_DELETE) { /* message is not deleted */ msg->virtual_messagestatus = MESSAGE_STATUS_SEEN; ci_write((FILE *) stream, "+OK %llu octets\r\n", msg->msize); - return db_send_message_lines((void *) stream, msg->realmessageid, -2, 0); + return db_send_message_lines((void *) stream, session->mailbox_idnr, msg->realmessageid, -2, 0); } tmpelement = tmpelement->nextnode; } @@ -769,7 +769,7 @@ int pop3(clientinfo_t *ci, char *buffer, PopSession_t * session) msg = (struct message *) tmpelement->data; if (msg->messageid == top_messageid && msg->virtual_messagestatus < MESSAGE_STATUS_DELETE) { /* message is not deleted */ ci_write((FILE *) stream, "+OK %llu lines of message %llu\r\n", top_lines, top_messageid); - return db_send_message_lines(stream, msg->realmessageid, top_lines, 0); + return db_send_message_lines(stream, session->mailbox_idnr, msg->realmessageid, top_lines, 0); } tmpelement = tmpelement->nextnode; } diff --git a/sort.c b/sort.c index 8359e9e..e954bac 100644 --- a/sort.c +++ b/sort.c @@ -182,7 +182,7 @@ dsn_class_t sort_deliver_to_mailbox(struct DbmailMessage *message, } // Ok, we have the ACL right, time to deliver the message. - switch (db_copymsg(message->id, mboxidnr, useridnr, &newmsgidnr)) { + switch (db_copymsg(message->mailbox, message->id, mboxidnr, useridnr, &newmsgidnr)) { case -2: TRACE(TRACE_DEBUG, "error copying message to user [%llu]," "maxmail exceeded", useridnr); @@ -192,14 +192,15 @@ dsn_class_t sort_deliver_to_mailbox(struct DbmailMessage *message, useridnr); return DSN_CLASS_TEMP; default: - TRACE(TRACE_MESSAGE, "message id=%llu, size=%zd is inserted", - newmsgidnr, msgsize); + TRACE(TRACE_MESSAGE, "message id=%llu, size=%zd is inserted to mailbox id=%llu", + newmsgidnr, msgsize, mboxidnr); if (msgflags) { - TRACE(TRACE_MESSAGE, "message id=%llu, setting imap flags", - newmsgidnr); + TRACE(TRACE_MESSAGE, "mbox id=%llu, message id=%llu, setting imap flags", + mboxidnr, newmsgidnr); db_set_msgflag(newmsgidnr, mboxidnr, msgflags, IMAPFA_ADD); } message->id = newmsgidnr; + message->mailbox = mboxidnr; return DSN_CLASS_OK; } }
-- James Cloos <[EMAIL PROTECTED]> OpenPGP: 1024D/ED7DAEA6
_______________________________________________ Dbmail-dev mailing list Dbmail-dev@dbmail.org http://twister.fastxs.net/mailman/listinfo/dbmail-dev