void MailboxState_remap(T M) { GList *ids = NULL; uint64_t *uid, *msn = NULL, rows = 1; MessageInfo *msginfo; MailboxState_uid_msn_new(M); ids = g_tree_keys(M->msginfo); ids = g_list_first(ids); while (ids) { uid = (uint64_t *)ids->data; msginfo = g_tree_lookup(M->msginfo, uid); if (msginfo->status < MESSAGE_STATUS_DELETE) { msn = g_new0(uint64_t,1); *msn = msginfo->msn = rows++; g_tree_insert(M->ids, uid, msn); g_tree_insert(M->msn, msn, uid); } if (! g_list_next(ids)) break; ids = g_list_next(ids); } g_list_free(g_list_first(ids)); }
int MailboxState_flush_recent(T M) { GList *recent; if ((!M) || (M && MailboxState_getPermission(M) != IMAPPERM_READWRITE)) return DM_SUCCESS; if (! g_tree_nnodes(M->recent_queue)) return DM_SUCCESS; TRACE(TRACE_DEBUG,"flush [%d] recent messages", g_tree_nnodes(M->recent_queue)); recent = g_tree_keys(M->recent_queue); if (recent) { long long int changed = 0; uint64_t seq = MailboxState_getSeq(M); changed = _update_recent(g_list_slices_u64(recent,100), seq+1); if (changed) db_mailbox_seq_update(MailboxState_getId(M), 0); } g_list_free(g_list_first(recent)); g_tree_foreach(M->recent_queue, (GTraverseFunc)_free_recent_queue, M); g_tree_destroy(M->recent_queue); M->recent_queue = g_tree_new((GCompareFunc)ucmp); return 0; }
char * MailboxState_flags(T M) { char *s = NULL; GString *string = g_string_new("\\Seen \\Answered \\Deleted \\Flagged \\Draft"); assert(M); if (M->keywords) { GList *k = g_tree_keys(M->keywords); GString *keywords = g_list_join(k," "); g_string_append_printf(string, " %s", keywords->str); g_string_free(keywords,TRUE); g_list_free(g_list_first(k)); } s = string->str; g_string_free(string, FALSE); return g_strchomp(s); }
//--------------------------------------------------------------------------------------// void Http_getMailboxes(T R) { const char *mailbox = Request_getId(R); TRACE(TRACE_DEBUG,"mailbox [%s]", mailbox); char *endptr = NULL; struct evbuffer *buf; uint64_t id = 0; if (! mailbox) { Request_error(R, HTTP_SERVUNAVAIL, "Server error"); return; } if (! (id = strtoull(mailbox, &endptr, 10))) { Request_error(R, HTTP_NOTFOUND, "Not found"); return; } TRACE(TRACE_DEBUG,"mailbox id [%lu]", id); buf = evbuffer_new(); Request_setContentType(R,"application/json; charset=utf-8"); if (Request_getMethod(R) == NULL) { /* * retrieve mailbox meta-data * C < GET /mailboxes/876 * * or * * append a new message * C < POST /mailboxes/876 */ const char *msg; uint64_t msg_id = 0; MailboxState_T b = MailboxState_new(id); unsigned exists = MailboxState_getExists(b); if ((msg = evhttp_find_header(Request_getPOST(R),"message"))) { if (! db_append_msg(msg, MailboxState_getId(b), MailboxState_getOwner(b), NULL, &msg_id, TRUE)) exists++; } evbuffer_add_printf(buf, "{\"mailboxes\": {\n"); evbuffer_add_printf(buf, " \"%lu\":{\"name\":\"%s\",\"exists\":%d}", MailboxState_getId(b), MailboxState_getName(b), exists); evbuffer_add_printf(buf, "\n}}\n"); MailboxState_free(&b); } else if (MATCH(Request_getMethod(R),"messages")) { /* * list messages in mailbox * C < GET /mailboxes/876/messages */ MailboxState_T b = MailboxState_new(id); GTree *msns = MailboxState_getMsn(b); GList *ids = g_tree_keys(msns); GTree *msginfo = MailboxState_getMsginfo(b); evbuffer_add_printf(buf, "{\"messages\": {\n"); while (ids && ids->data) { uint64_t *msn = (uint64_t *)ids->data; uint64_t *uid = (uint64_t *)g_tree_lookup(msns, msn); MessageInfo *info = (MessageInfo *)g_tree_lookup(msginfo, uid); evbuffer_add_printf(buf, " \"%lu\":{\"size\":%lu}", *uid, info->rfcsize); if (! g_list_next(ids)) break; ids = g_list_next(ids); evbuffer_add_printf(buf,",\n"); } evbuffer_add_printf(buf, "\n}}\n"); if (ids) g_list_free(g_list_first(ids)); MailboxState_free(&b); } if (EVBUFFER_LENGTH(buf)) Request_send(R, HTTP_OK, "OK", buf); else Request_error(R, HTTP_SERVUNAVAIL, "Server error"); evbuffer_free(buf); }
GTree * MailboxState_get_set(MailboxState_T M, const char *set, gboolean uid) { GTree *inset, *a, *b; GList *sets = NULL; GString *t; uint64_t lo = 0, hi = 0; gboolean error = FALSE; if (uid) inset = MailboxState_getIds(M); else inset = MailboxState_getMsn(M); a = g_tree_new_full((GCompareDataFunc)ucmpdata,NULL, (GDestroyNotify)uint64_free, (GDestroyNotify)uint64_free); b = g_tree_new_full((GCompareDataFunc)ucmpdata,NULL, (GDestroyNotify)uint64_free, (GDestroyNotify)uint64_free); if (! uid) { lo = 1; hi = MailboxState_getExists(M); } else { GList *ids = g_tree_keys(inset); if (ids) { ids = g_list_last(ids); hi = *((uint64_t *)ids->data); ids = g_list_first(ids); lo = *((uint64_t *)ids->data); g_list_free(g_list_first(ids)); } } t = g_string_new(set); sets = g_string_split(t,","); g_string_free(t,TRUE); sets = g_list_first(sets); while(sets) { uint64_t l = 0, r = 0; char *rest = (char *)sets->data; if (strlen(rest) < 1) break; if (g_tree_nnodes(inset) == 0) { // empty box if (rest[0] == '*') { uint64_t *k = mempool_pop(small_pool, sizeof(uint64_t)); uint64_t *v = mempool_pop(small_pool, sizeof(uint64_t)); *k = 1; *v = MailboxState_getUidnext(M); g_tree_insert(b, k, v); } else { if (! (l = dm_strtoull(sets->data, &rest, 10))) { error = TRUE; break; } if (rest[0]) { if (rest[0] != ':') { error = TRUE; break; } rest++; if ((rest[0] != '*') && (! dm_strtoull(rest, NULL, 10))) { error = TRUE; break; } } uint64_t *k = mempool_pop(small_pool, sizeof(uint64_t)); uint64_t *v = mempool_pop(small_pool, sizeof(uint64_t)); *k = 1; *v = MailboxState_getUidnext(M); g_tree_insert(b, k, v); } } else { if (rest[0] == '*') { l = hi; r = l; if (strlen(rest) > 1) rest++; } else { if (! (l = dm_strtoull(sets->data,&rest,10))) { error = TRUE; break; } if (l == 0xffffffff) l = hi; // outlook l = max(l,lo); r = l; } if (rest[0]==':') { if (strlen(rest)>1) rest++; if (rest[0] == '*') r = hi; else { if (! (r = dm_strtoull(rest,NULL,10))) { error = TRUE; break; } if (r == 0xffffffff) r = hi; // outlook } if (!r) break; } if (! (l && r)) break; find_range(inset, min(l,r), max(l,r), a, uid); if (g_tree_merge(b,a,IST_SUBSEARCH_OR)) { error = TRUE; TRACE(TRACE_ERR, "cannot compare null trees"); break; } } if (! g_list_next(sets)) break; sets = g_list_next(sets); } g_list_destroy(sets); if (a) g_tree_destroy(a); if (error) { g_tree_destroy(b); b = NULL; TRACE(TRACE_DEBUG, "return NULL"); } return b; }
static int mailbox_dump(u64_t mailbox_idnr, const char *dumpfile, const char *search, int delete_after_dump) { FILE *ostream; DbmailMailbox *mb = NULL; ImapSession *s = NULL; int result = 0; /* * For dbmail the usual filesystem semantics don't really * apply. Mailboxes can contain other mailboxes as well as * messages. For now however, this is solved by appending * the mailboxname with .mbox * * TODO: facilitate maildir type exports */ mb = dbmail_mailbox_new(mailbox_idnr); if (search) { s = dbmail_imap_session_new(); s->ci = client_init(NULL); if (! (imap4_tokenizer_main(s, search))) { qerrorf("error parsing search string"); dbmail_imap_session_delete(&s); dbmail_mailbox_free(mb); return 1; } if (dbmail_mailbox_build_imap_search(mb, s->args, &(s->args_idx), SEARCH_UNORDERED) < 0) { qerrorf("invalid search string"); dbmail_imap_session_delete(&s); dbmail_mailbox_free(mb); return 1; } dbmail_mailbox_search(mb); dbmail_imap_session_delete(&s); } if (strcmp(dumpfile, "-") == 0) { ostream = stdout; } else if (! (ostream = fopen(dumpfile, "a"))) { int err = errno; qerrorf("opening [%s] failed [%s]\n", dumpfile, strerror(err)); result = -1; goto cleanup; } if (dbmail_mailbox_dump(mb, ostream) < 0) { qerrorf("Export failed\n"); result = -1; goto cleanup; } if (delete_after_dump) { int deleted_flag[IMAP_NFLAGS]; memset(deleted_flag, 0, IMAP_NFLAGS * sizeof(int)); deleted_flag[IMAP_FLAG_DELETED] = 1; GList *ids = g_tree_keys(MailboxState_getIds(mb->mbstate)); while (ids) { // Flag the selected messages \\Deleted // Following this, dbmail-util -d sets deleted status if (delete_after_dump & 1) { if (db_set_msgflag(*(u64_t *)ids->data, deleted_flag, NULL, IMAPFA_ADD, NULL) < 0) { qerrorf("Error setting flags for message [%llu]\n", *(u64_t *)ids->data); result = -1; } } // 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)) { qerrorf("Error setting status for message [%llu]\n", *(u64_t *)ids->data); result = -1; } } if (!g_list_next(ids)) break; ids = g_list_next(ids); } g_list_free(g_list_first(ids)); } cleanup: if (mb) dbmail_mailbox_free(mb); if ((ostream) && (ostream != stdout)) fclose(ostream); return result; }