Mercurial > dovecot > original-hg > dovecot-1.2
view src/lib-storage/index/index-messageset.c @ 988:8028c4dcf38f HEAD
mail-storage.h interface changes, affects pretty much everything.
FETCH, SEARCH, SORT and THREAD handling were pretty much moved from
lib-storage/ to imap/ so adding non-index storages would be much easier now.
Also POP3 server can now be easily implemented with lib-storage.
Not too well tested, and at least one major problem: partial fetching is
_slow_.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Mon, 20 Jan 2003 16:52:51 +0200 |
parents | 411006be3c66 |
children | b5ca53885d07 |
line wrap: on
line source
/* Copyright (C) 2002-2003 Timo Sirainen */ #include "lib.h" #include "mail-index.h" #include "mail-index-util.h" #include "mail-modifylog.h" #include "index-storage.h" #include "index-messageset.h" struct messageset_context { struct index_mailbox *ibox; struct mail_index *index; const struct modify_log_expunge *expunges; int expunges_found; struct messageset_mail mail; unsigned int messages_count; unsigned int num1, num2; const char *messageset, *p; int uidset; int first, ret; const char *error; }; static int uidset_init(struct messageset_context *ctx); static int seqset_init(struct messageset_context *ctx); struct messageset_context * index_messageset_init(struct index_mailbox *ibox, const char *messageset, int uidset) { struct messageset_context *ctx; i_assert(ibox->index->lock_type != MAIL_LOCK_UNLOCK); ctx = i_new(struct messageset_context, 1); ctx->ibox = ibox; ctx->index = ibox->index; ctx->messages_count = ibox->synced_messages_count; ctx->p = ctx->messageset = messageset; ctx->uidset = uidset; /* Reset index errors, we rely on it to check for failures */ index_reset_error(ctx->index); return ctx; } struct messageset_context * index_messageset_init_range(struct index_mailbox *ibox, unsigned int num1, unsigned int num2, int uidset) { struct messageset_context *ctx; ctx = index_messageset_init(ibox, NULL, uidset); ctx->num1 = num1; ctx->num2 = num2; return ctx; } int index_messageset_deinit(struct messageset_context *ctx) { int ret = ctx->ret; if (ret == 1 && ctx->expunges_found) { /* some of the messages weren't found */ ret = 0; } if (ret == -1) mail_storage_set_index_error(ctx->ibox); else if (ret == -2) { /* user error */ mail_storage_set_syntax_error(ctx->ibox->box.storage, "%s", ctx->error); } i_free(ctx); return ret; } static unsigned int get_next_number(const char **str) { unsigned int num; num = 0; while (**str != '\0') { if (**str < '0' || **str > '9') break; num = num*10 + (**str - '0'); (*str)++; } return num; } static int messageset_parse_next(struct messageset_context *ctx) { if (ctx->p == NULL) { /* num1..num2 already set. */ ctx->p = ""; return TRUE; } if (*ctx->p == '*') { /* last message */ ctx->num1 = (unsigned int)-1; ctx->p++; } else { ctx->num1 = get_next_number(&ctx->p); if (ctx->num1 == 0) { ctx->error = t_strconcat("Invalid messageset: ", ctx->messageset, NULL); return FALSE; } } if (*ctx->p != ':') ctx->num2 = ctx->num1; else { /* first:last range */ ctx->p++; if (*ctx->p == '*') { ctx->num2 = (unsigned int)-1; ctx->p++; } else { ctx->num2 = get_next_number(&ctx->p); if (ctx->num2 == 0) { ctx->error = t_strconcat("Invalid messageset: ", ctx->messageset, NULL); return FALSE; } } } if (*ctx->p == ',') ctx->p++; else if (*ctx->p != '\0') { ctx->error = t_strdup_printf("Unexpected char '%c' " "with messageset: %s", *ctx->p, ctx->messageset); return FALSE; } if (ctx->num1 > ctx->num2) { /* swap, as specified by latest IMAP4rev1 draft */ unsigned int temp = ctx->num1; ctx->num1 = ctx->num2; ctx->num2 = temp; } return TRUE; } static int uidset_init(struct messageset_context *ctx) { unsigned int expunges_before; if (ctx->num1 == (unsigned int)-1) { struct mail_index_record *rec; rec = ctx->index->lookup(ctx->index, ctx->messages_count); ctx->num1 = rec == NULL ? 0 : rec->uid; } if (ctx->num2 == (unsigned int)-1) ctx->num2 = ctx->index->header->next_uid-1; /* get list of expunged messages in our range. */ ctx->expunges = mail_modifylog_uid_get_expunges(ctx->index->modifylog, ctx->num1, ctx->num2, &expunges_before); if (ctx->expunges == NULL) return -1; if (ctx->expunges->uid1 != 0) ctx->expunges_found = TRUE; /* get the first message */ ctx->mail.rec = ctx->index->lookup_uid_range(ctx->index, ctx->num1, ctx->num2, &ctx->mail.idx_seq); if (ctx->mail.rec == NULL) { return ctx->index->get_last_error(ctx->index) == MAIL_INDEX_ERROR_NONE ? 1 : -1; } ctx->mail.client_seq = ctx->mail.idx_seq + expunges_before; return 0; } static int seqset_init(struct messageset_context *ctx) { unsigned int expunges_before; if (ctx->num1 == (unsigned int)-1) ctx->num1 = ctx->messages_count; if (ctx->num2 == (unsigned int)-1) ctx->num2 = ctx->messages_count; /* get list of expunged messages in our range. the expunges_before can be used to calculate the current real sequence position */ ctx->expunges = mail_modifylog_seq_get_expunges(ctx->index->modifylog, ctx->num1, ctx->num2, &expunges_before); if (ctx->expunges == NULL) return -1; i_assert(expunges_before < ctx->num1); if (ctx->expunges->uid1 != 0) ctx->expunges_found = TRUE; /* get the first non-expunged message. note that if all messages were expunged in the range, this points outside wanted range. */ ctx->mail.idx_seq = ctx->num1 - expunges_before; ctx->mail.rec = ctx->index->lookup(ctx->index, ctx->mail.idx_seq); if (ctx->mail.rec == NULL) { return ctx->index->get_last_error(ctx->index) == MAIL_INDEX_ERROR_NONE ? 1 : -1; } ctx->mail.client_seq = ctx->num1; return 0; } const struct messageset_mail * index_messageset_next(struct messageset_context *ctx) { struct messageset_mail *mail = &ctx->mail; int last; if (ctx->ret != 0) return NULL; if (!ctx->uidset) last = mail->rec == NULL || mail->client_seq >= ctx->num2; else last = mail->rec == NULL || mail->rec->uid >= ctx->num2; if (!last) { mail->rec = ctx->index->next(ctx->index, mail->rec); mail->client_seq++; mail->idx_seq++; } else { do { if (ctx->p != NULL && *ctx->p == '\0') { /* finished */ ctx->ret = 1; return NULL; } if (!messageset_parse_next(ctx)) { ctx->ret = -2; return NULL; } if (ctx->uidset) ctx->ret = uidset_init(ctx); else ctx->ret = seqset_init(ctx); } while (ctx->ret == 1); if (ctx->ret != 0) return NULL; } /* fix client_seq */ while (ctx->expunges->uid1 != 0 && ctx->expunges->uid1 < mail->rec->uid) { i_assert(ctx->expunges->uid2 < mail->rec->uid); mail->client_seq += ctx->expunges->seq_count; ctx->expunges++; } i_assert(!(ctx->expunges->uid1 <= mail->rec->uid && ctx->expunges->uid2 >= mail->rec->uid)); if (!ctx->uidset && mail->client_seq > ctx->num2) { /* finished this set - see if there's more */ return index_messageset_next(ctx); } return mail; }