static int get_messages_list(mailsession * session, struct mailmessage_list ** result) { int r; char key[PATH_MAX]; struct mail_cache_db * maildb; struct db_session_state_data * data; int res; carray * msglist; unsigned int i; carray * msgtab; struct mailmessage_list * driver_msglist; data = get_data(session); r = mail_cache_db_open_lock(data->db_filename, &maildb); if (r < 0) { res = MAIL_ERROR_FILE; goto err; } r = db_get_message_list(maildb, &msglist); if (r != MAIL_NO_ERROR) { res = r; goto close_db; } msgtab = carray_new(16); if (msgtab == NULL) { res = MAIL_ERROR_MEMORY; goto close_db; } for(i = 0 ; i < carray_count(msglist) ; i ++) { uint32_t msg_num; uint32_t * pmsg_num; mailmessage * msg; size_t size; pmsg_num = carray_get(msglist, i); msg_num = * pmsg_num; free(pmsg_num); carray_set(msglist, i, NULL); snprintf(key, sizeof(key), "%lu", (unsigned long) msg_num); r = mail_cache_db_get_size(maildb, key, strlen(key), &size); if (r < 0) { continue; } msg = mailmessage_new(); if (msg == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } r = mailmessage_init(msg, session, db_message_driver, msg_num, size); if (r != MAIL_NO_ERROR) { mailmessage_free(msg); res = r; goto free_list; } r = carray_add(msgtab, msg, NULL); if (r < 0) { mailmessage_free(msg); res = MAIL_ERROR_MEMORY; goto free_list; } } carray_free(msglist); driver_msglist = mailmessage_list_new(msgtab); if (driver_msglist == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } mail_cache_db_close_unlock(data->db_filename, maildb); * result = driver_msglist; return MAIL_NO_ERROR; free_list: for(i = 0 ; i < carray_count(msgtab) ; i ++) { mailmessage * msg; msg = carray_get(msgtab, i); mailmessage_free(msg); } carray_free(msgtab); for(i = 0 ; i < carray_count(msglist) ; i ++) { uint32_t * msg; msg = carray_get(msglist, i); if (msg != NULL) free(msg); } carray_free(msglist); close_db: mail_cache_db_close_unlock(data->db_filename, maildb); err: return res; }
static int nntpdriver_cached_get_envelopes_list(mailsession * session, struct mailmessage_list * env_list) { int r; unsigned int i; struct nntp_cached_session_state_data * cached_data; uint32_t first; uint32_t last; struct nntp_session_state_data * ancestor_data; char filename_env[PATH_MAX]; char filename_flags[PATH_MAX]; struct mail_cache_db * cache_db_env; struct mail_cache_db * cache_db_flags; MMAPString * mmapstr; int res; char cache_dir[PATH_MAX]; cached_data = get_cached_data(session); ancestor_data = get_ancestor_data(session); nntp_flags_store_process(cached_data->nntp_flags_directory, ancestor_data->nntp_group_name, cached_data->nntp_flags_store); if (ancestor_data->nntp_group_name == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } /* read articles sequence */ read_article_seq(session, &first, &last); mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto err; } snprintf(filename_env, PATH_MAX, "%s/%s/%s", cached_data->nntp_cache_directory, ancestor_data->nntp_group_name, ENV_NAME); r = mail_cache_db_open_lock(filename_env, &cache_db_env); if (r < 0) { res = MAIL_ERROR_FILE; goto free_mmapstr; } snprintf(filename_flags, PATH_MAX, "%s/%s/%s", cached_data->nntp_flags_directory, ancestor_data->nntp_group_name, FLAGS_NAME); /* fill with cached */ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { mailmessage * msg; struct mailimf_fields * fields; msg = carray_get(env_list->msg_tab, i); if ((msg->msg_index < first) || (msg->msg_index > last)) continue; if (msg->msg_fields == NULL) { r = get_cached_envelope(cache_db_env, mmapstr, session, msg->msg_index, &fields); if (r == MAIL_NO_ERROR) { msg->msg_fields = fields; msg->msg_cached = TRUE; } } } mail_cache_db_close_unlock(filename_env, cache_db_env); r = mailsession_get_envelopes_list(get_ancestor(session), env_list); if (r != MAIL_NO_ERROR) { res = r; goto free_mmapstr; } r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); if (r < 0) { res = MAIL_ERROR_FILE; goto free_mmapstr; } /* add flags */ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { mailmessage * msg; msg = carray_get(env_list->msg_tab, i); if (msg->msg_flags == NULL) { struct mail_flags * flags; r = nntpdriver_get_cached_flags(cache_db_flags, mmapstr, msg->msg_index, &flags); if (r == MAIL_NO_ERROR) { msg->msg_flags = flags; } else { msg->msg_flags = mail_flags_new_empty(); if (msg->msg_fields == NULL) { msg->msg_flags->fl_flags |= MAIL_FLAG_CANCELLED; mailmessage_check(msg); } } } } mail_cache_db_close_unlock(filename_flags, cache_db_flags); r = mail_cache_db_open_lock(filename_env, &cache_db_env); if (r < 0) { res = MAIL_ERROR_FILE; goto free_mmapstr; } r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); if (r < 0) { res = MAIL_ERROR_FILE; goto close_db_env; } /* must write cache */ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { mailmessage * msg; msg = carray_get(env_list->msg_tab, i); if (msg->msg_fields != NULL) { if (!msg->msg_cached) { r = write_cached_envelope(cache_db_env, mmapstr, session, msg->msg_index, msg->msg_fields); } } if (msg->msg_flags != NULL) { r = nntpdriver_write_cached_flags(cache_db_flags, mmapstr, msg->msg_index, msg->msg_flags); } } first = 0; last = 0; if (carray_count(env_list->msg_tab) > 0) { mailmessage * msg; msg = carray_get(env_list->msg_tab, 0); first = msg->msg_index; msg = carray_get(env_list->msg_tab, carray_count(env_list->msg_tab) - 1); last = msg->msg_index; } /* write articles sequence */ write_article_seq(session, first, last); /* flush cache */ maildriver_cache_clean_up(cache_db_env, cache_db_flags, env_list); /* remove cache files */ snprintf(cache_dir, PATH_MAX, "%s/%s", cached_data->nntp_cache_directory, ancestor_data->nntp_group_name); mail_cache_db_close_unlock(filename_flags, cache_db_flags); mail_cache_db_close_unlock(filename_env, cache_db_env); mmap_string_free(mmapstr); maildriver_message_cache_clean_up(cache_dir, env_list, get_uid_from_filename); return MAIL_NO_ERROR; close_db_env: mail_cache_db_close_unlock(filename_env, cache_db_env); free_mmapstr: mmap_string_free(mmapstr); err: return res; }
static int mail_build_thread_none(char * default_from, struct mailmessage_list * env_list, struct mailmessage_tree ** result, int (* comp_func)(struct mailmessage_tree **, struct mailmessage_tree **)) { unsigned int i; carray * rootlist; struct mailmessage_tree * root; int res; int r; root = mailmessage_tree_new(NULL, (time_t) -1, NULL); if (root == NULL) { res = MAIL_ERROR_MEMORY; goto err; } rootlist = root->node_children; for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { mailmessage * msg; struct mailmessage_tree * env_tree; char * base_subject; time_t date; msg = carray_get(env_list->msg_tab, i); if (msg == NULL) continue; if (msg->msg_fields != NULL) { date = get_date(msg); env_tree = mailmessage_tree_new(NULL, date, msg); if (env_tree == NULL) { res = MAIL_ERROR_MEMORY; goto free; } /* set parent */ env_tree->node_parent = root; r = carray_add(rootlist, env_tree, NULL); if (r < 0) { mailmessage_tree_free(env_tree); res = MAIL_ERROR_MEMORY; goto free; } r = get_extracted_subject(default_from, env_tree, &base_subject); switch (r) { case MAIL_NO_ERROR: env_tree->node_base_subject = base_subject; break; case MAIL_ERROR_SUBJECT_NOT_FOUND: break; default: res = r; goto free; } } } if (comp_func == NULL) comp_func = mailthread_tree_timecomp; r = mail_thread_sort(root, comp_func, FALSE); if (r != MAIL_NO_ERROR) { res = r; goto free; } * result = root; return MAIL_NO_ERROR; free: mailmessage_tree_free_recursive(root); err: return res; }
static int append_message_flags(mailsession * session, const char * message, size_t size, struct mail_flags * flags) { carray * msglist; unsigned int i; uint32_t * msg; uint32_t num; char key_value[PATH_MAX]; MMAPString * mmapstr; struct mail_cache_db * maildb; struct db_session_state_data * data; size_t cur_token; struct mailimf_fields * fields; int r; int res; data = get_data(session); r = mail_cache_db_open_lock(data->db_filename, &maildb); if (r < 0) { res = MAIL_ERROR_FILE; goto err; } num = 0; r = db_get_next_msg_number(maildb, &num); if (r != MAIL_NO_ERROR) { res = r; goto err; } r = db_get_message_list(maildb, &msglist); if (r != MAIL_NO_ERROR) { res = r; goto close_db; } msg = malloc(sizeof(* msg)); if (msg == NULL) { res = MAIL_ERROR_MEMORY; goto free_msglist; } * msg = num; r = carray_add(msglist, msg, NULL); if (r < 0) { res = MAIL_ERROR_MEMORY; free(msg); goto free_msglist; } r = db_set_message_list(maildb, msglist); if (r != MAIL_NO_ERROR) { res = r; goto free_msglist; } /* free msglist */ for(i = 0 ; i < carray_count(msglist) ; i ++) { msg = carray_get(msglist, i); free(msg); } carray_free(msglist); snprintf(key_value, sizeof(key_value), "%lu", (unsigned long) num); r = mail_cache_db_put(maildb, key_value, strlen(key_value), message, size); if (r < 0) { res = MAIL_ERROR_FILE; goto close_db; } /* write envelope */ cur_token = 0; r = mailimf_envelope_fields_parse(message, size, &cur_token, &fields); if (r != MAILIMF_NO_ERROR) { res = MAIL_ERROR_PARSE; goto close_db; } mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto close_db; } cur_token = 0; r = mailimf_cache_fields_write(mmapstr, &cur_token, fields); if (r != MAIL_NO_ERROR) { res = r; mmap_string_free(mmapstr); goto close_db; } snprintf(key_value, sizeof(key_value), "%lu-envelope", (unsigned long) num); r = mail_cache_db_put(maildb, key_value, strlen(key_value), mmapstr->str, mmapstr->len); mmap_string_free(mmapstr); mailimf_fields_free(fields); /* write flags */ if (flags != NULL) { snprintf(key_value, sizeof(key_value), "%lu-flags", (unsigned long) num); mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto close_db; } r = generic_cache_flags_write(maildb, mmapstr, key_value, flags); mmap_string_free(mmapstr); if (r != MAIL_NO_ERROR) { res = MAIL_ERROR_FILE; goto close_db; } } mail_cache_db_close_unlock(data->db_filename, maildb); return MAIL_NO_ERROR; free_msglist: for(i = 0 ; i < carray_count(msglist) ; i ++) { msg = carray_get(msglist, i); free(msg); } carray_free(msglist); close_db: mail_cache_db_close_unlock(data->db_filename, maildb); err: return res; }
static int pop3driver_cached_status_folder(mailsession * session, const char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen) { int res; struct pop3_cached_session_state_data * cached_data; char filename_flags[PATH_MAX]; struct mail_cache_db * cache_db_flags; MMAPString * mmapstr; unsigned int i; int r; carray * msg_tab; mailpop3 * pop3; uint32_t recent; uint32_t unseen; recent = 0; unseen = 0; pop3 = get_pop3_session(session); cached_data = get_cached_data(session); pop3_flags_store_process(cached_data->pop3_flags_directory, cached_data->pop3_flags_store); snprintf(filename_flags, PATH_MAX, "%s/%s", cached_data->pop3_flags_directory, FLAGS_NAME); r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); if (r < 0) { res = MAIL_ERROR_FILE; goto err; } mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto close_db_flags; } r = mailpop3_list(pop3, &msg_tab); if (r != MAILPOP3_NO_ERROR) { res = pop3driver_pop3_error_to_mail_error(r); goto free_mmapstr; } for(i = 0 ; i < carray_count(msg_tab) ; i++) { struct mailpop3_msg_info * pop3_info; struct mail_flags * flags; pop3_info = carray_get(msg_tab, i); if (pop3_info == NULL) continue; if (pop3_info->msg_deleted) continue; r = pop3driver_get_cached_flags(cache_db_flags, mmapstr, session, pop3_info->msg_index, &flags); if (r != MAIL_NO_ERROR) { recent ++; unseen ++; continue; } if ((flags->fl_flags & MAIL_FLAG_NEW) != 0) { recent ++; } if ((flags->fl_flags & MAIL_FLAG_SEEN) == 0) { unseen ++; } mail_flags_free(flags); } mmap_string_free(mmapstr); mail_cache_db_close_unlock(filename_flags, cache_db_flags); * result_messages = carray_count(msg_tab) - pop3->pop3_deleted_count; * result_recent = recent; * result_unseen = unseen; return MAIL_NO_ERROR; free_mmapstr: mmap_string_free(mmapstr); close_db_flags: mail_cache_db_close_unlock(filename_flags, cache_db_flags); err: return res; }
int maildriver_generic_search_messages(mailsession * session, char * charset, struct mail_search_key * key, struct mail_search_result ** result) { int header; clist * list; struct mail_search_result * search_result; int r; struct mailmessage_list * env_list; int res; unsigned int i; header = is_search_header_only(key); r = mailsession_get_messages_list(session, &env_list); if (r != MAIL_NO_ERROR) return r; list = NULL; for(i = 0 ; i < carray_count(env_list->tab) ; i ++) { char * message; size_t length; struct mail_info * info; uint32_t flags; struct mailimf_fields * fields; size_t cur_token; info = carray_get(env_list->tab, i); if (!header) { r = mailsession_fetch_message(session, info->indx, &message, &length); if (r != MAIL_NO_ERROR) { res = r; goto free_list; } cur_token = 0; r = mailimf_optional_fields_parse(message, length, &cur_token, &fields); if (r != MAILIMF_NO_ERROR) { res = MAIL_ERROR_PARSE; goto free_list; } } else { char * msg_header; int r; size_t cur_token; size_t header_len; r = mailsession_fetch_message_header(session, info->indx, &msg_header, &header_len); if (r != MAIL_NO_ERROR) { res = r; goto free_list; } message = NULL; cur_token = 0; r = mailimf_optional_fields_parse(msg_header, header_len, &cur_token, &fields); if (r != MAILIMF_NO_ERROR) { res = MAIL_ERROR_PARSE; goto free_list; } mailsession_fetch_result_free(session, msg_header); } r = mailsession_get_message_flags(session, info->indx, &flags); if (r != MAIL_NO_ERROR) { res = r; goto free_list; } if (match_messages(message, info->size, fields, flags, charset, key)) { uint32_t * pnum; pnum = malloc(sizeof(* pnum)); if (pnum == NULL) { if (message != NULL) mailsession_fetch_result_free(session, message); res = MAIL_ERROR_MEMORY; goto free_list; } * pnum = info->indx; r = clist_append(list, pnum); if (r < 0) { free(pnum); if (message != NULL) mailsession_fetch_result_free(session, message); res = MAIL_ERROR_MEMORY; goto free_list; } } if (message != NULL) mailsession_fetch_result_free(session, message); } search_result = mail_search_result_new(list); if (search_result == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } * result = search_result; return MAIL_NO_ERROR; free_list: clist_foreach(list, (clist_func) free, NULL); clist_free(list); mailmessage_list_free(env_list); return res; }
static int mailmbox_expunge_to_file_no_lock(char * dest_filename, int dest_fd, struct mailmbox_folder * folder, size_t * result_size) { int r; int res; size_t cur_offset; char * dest; size_t size; unsigned int i; size = 0; for(i = 0 ; i < carray_count(folder->mb_tab) ; i ++) { struct mailmbox_msg_info * info; info = carray_get(folder->mb_tab, i); if (!info->msg_deleted) { size += info->msg_size + info->msg_padding; if (!folder->mb_no_uid) { if (!info->msg_written_uid) { uint32_t uid; #ifdef CRLF_BADNESS size += strlen(UID_HEADER " \r\n"); #else size += strlen(UID_HEADER " \n"); #endif uid = info->msg_uid; while (uid >= 10) { uid /= 10; size ++; } size ++; } } } } r = ftruncate(dest_fd, size); if (r < 0) { res = MAILMBOX_ERROR_FILE; goto err; } dest = (char *) mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, dest_fd, 0); if (dest == (char *)MAP_FAILED) { res = MAILMBOX_ERROR_FILE; goto err; } cur_offset = 0; for(i = 0 ; i < carray_count(folder->mb_tab) ; i ++) { struct mailmbox_msg_info * info; info = carray_get(folder->mb_tab, i); if (!info->msg_deleted) { memcpy(dest + cur_offset, folder->mb_mapping + info->msg_start, info->msg_headers_len + info->msg_start_len); cur_offset += info->msg_headers_len + info->msg_start_len; if (!folder->mb_no_uid) { if (!info->msg_written_uid) { size_t numlen; memcpy(dest + cur_offset, UID_HEADER " ", strlen(UID_HEADER " ")); cur_offset += strlen(UID_HEADER " "); #ifdef CRLF_BADNESS numlen = snprintf(dest + cur_offset, size - cur_offset, "%i\r\n", info->msg_uid); #else numlen = snprintf(dest + cur_offset, size - cur_offset, "%i\n", info->msg_uid); #endif cur_offset += numlen; } } memcpy(dest + cur_offset, folder->mb_mapping + info->msg_headers + info->msg_headers_len, info->msg_size - (info->msg_start_len + info->msg_headers_len) + info->msg_padding); cur_offset += info->msg_size - (info->msg_start_len + info->msg_headers_len) + info->msg_padding; } } fflush(stdout); msync(dest, size, MS_SYNC); munmap(dest, size); * result_size = size; return MAILMBOX_NO_ERROR; err: return res; }
static int get_envelopes_list(mailsession * session, struct mailmessage_list * env_list) { int r; struct maildir * md; unsigned int i; int res; check_folder(session); md = get_maildir_session(session); if (md == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } r = maildir_update(md); if (r != MAILDIR_NO_ERROR) { res = maildirdriver_maildir_error_to_mail_error(r); goto err; } r = maildriver_generic_get_envelopes_list(session, env_list); if (r != MAIL_NO_ERROR) { res = r; goto err; } for(i = 0 ; i < carray_count(env_list->msg_tab) ; i++) { struct maildir_msg * md_msg; mailmessage * msg; uint32_t driver_flags; clist * ext; chashdatum key; chashdatum value; msg = carray_get(env_list->msg_tab, i); key.data = msg->msg_uid; key.len = strlen(msg->msg_uid); r = chash_get(md->mdir_msg_hash, &key, &value); if (r < 0) continue; md_msg = value.data; driver_flags = maildirdriver_maildir_flags_to_flags(md_msg->msg_flags); if (msg->msg_flags == NULL) { ext = clist_new(); if (ext == NULL) { res = MAIL_ERROR_MEMORY; continue; } msg->msg_flags = mail_flags_new(driver_flags, ext); if (msg->msg_flags == NULL) { clist_free(ext); res = MAIL_ERROR_MEMORY; continue; } if ((md_msg->msg_flags & MAILDIR_FLAG_NEW) != 0) { mail_flags_store_set(get_data(session)->md_flags_store, msg); } } else { msg->msg_flags->fl_flags &= MAIL_FLAG_FORWARDED; msg->msg_flags->fl_flags |= driver_flags; } } return MAIL_NO_ERROR; err: return res; }
int nntp_get_messages_list(mailsession * nntp_session, mailsession * session, mailmessage_driver * driver, struct mailmessage_list ** result) { carray * tab; struct mailmessage_list * env_list; uint32_t i; int res; int r; struct nntp_session_state_data * data; struct newsnntp_group_info * group_info; uint32_t max; unsigned int cur; data = session_get_data(nntp_session); if (data->nntp_group_name == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } r = nntpdriver_select_folder(nntp_session, data->nntp_group_name); if (r != MAIL_NO_ERROR) { res = r; goto err; } group_info = data->nntp_group_info; if (group_info == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } max = group_info->grp_first; if (data->nntp_max_articles != 0) { if (group_info->grp_last - data->nntp_max_articles + 1 > max) max = group_info->grp_last - data->nntp_max_articles + 1; } tab = carray_new(128); if (tab == NULL) { res = MAIL_ERROR_MEMORY; goto err; } for(i = max ; i <= group_info->grp_last ; i++) { mailmessage * msg; msg = mailmessage_new(); if (msg == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } r = mailmessage_init(msg, session, driver, i, 0); if (r != MAIL_NO_ERROR) { mailmessage_free(msg); res = r; goto free_list; } r = carray_add(tab, msg, NULL); if (r < 0) { mailmessage_free(msg); res = MAIL_ERROR_MEMORY; goto free_list; } } env_list = mailmessage_list_new(tab); if (env_list == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } * result = env_list; return MAIL_NO_ERROR; free_list: for(cur = 0 ; cur < carray_count(tab) ; cur ++) mailmessage_free(carray_get(tab, cur)); carray_free(tab); err: return res; }
int mailmbox_copy_msg_list(struct mailmbox_folder * dest_folder, struct mailmbox_folder * src_folder, carray * tab) { int r; int res; carray * append_tab; unsigned int i; r = mailmbox_validate_read_lock(src_folder); if (r != MAILMBOX_NO_ERROR) { res = r; goto err; } append_tab = carray_new(carray_count(tab)); if (append_tab == NULL) { res = MAILMBOX_ERROR_MEMORY; goto src_unlock; } for(i = 0 ; i < carray_count(tab) ; i ++) { struct mailmbox_append_info * append_info; char * data; size_t len; uint32_t uid; uid = * ((uint32_t *) carray_get(tab, i)); r = mailmbox_fetch_msg_no_lock(src_folder, uid, &data, &len); if (r != MAILMBOX_NO_ERROR) { res = r; goto free_list; } append_info = mailmbox_append_info_new(data, len); if (append_info == NULL) { res = MAILMBOX_ERROR_MEMORY; goto free_list; } r = carray_add(append_tab, append_info, NULL); if (r < 0) { mailmbox_append_info_free(append_info); res = MAILMBOX_ERROR_MEMORY; goto free_list; } } r = mailmbox_append_message_list(dest_folder, append_tab); if (r != MAILMBOX_NO_ERROR) { res = r; goto src_unlock; } for(i = 0 ; i < carray_count(append_tab) ; i ++) { struct mailmbox_append_info * append_info; append_info = carray_get(append_tab, i); mailmbox_append_info_free(append_info); } carray_free(append_tab); mailmbox_read_unlock(src_folder); return MAILMBOX_NO_ERROR; free_list: for(i = 0 ; i < carray_count(append_tab) ; i ++) { struct mailmbox_append_info * append_info; append_info = carray_get(append_tab, i); mailmbox_append_info_free(append_info); } carray_free(append_tab); src_unlock: mailmbox_read_unlock(src_folder); err: return res; }
struct newsfeed_item * newsfeed_get_item(struct newsfeed * feed, unsigned int n) { return carray_get(feed->feed_item_list, n); }
static int mail_build_thread_references(char * default_from, struct mailmessage_list * env_list, struct mailmessage_tree ** result, int use_subject, int (* comp_func)(struct mailmessage_tree **, struct mailmessage_tree **)) { int r; int res; chash * msg_id_hash; unsigned int cur; struct mailmessage_tree * root; carray * rootlist; carray * msg_list; unsigned int i; chash * subject_hash; msg_id_hash = chash_new(128, CHASH_COPYNONE); if (msg_id_hash == NULL) { res = MAIL_ERROR_MEMORY; goto err; } root = mailmessage_tree_new(NULL, (time_t) -1, NULL); if (root == NULL) { res = MAIL_ERROR_MEMORY; goto free_hash; } rootlist = root->node_children; msg_list = carray_new(128); if (msg_list == NULL) { res = MAIL_ERROR_MEMORY; goto free_root; } /* collect message-ID */ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { mailmessage * msg; char * msgid; struct mailmessage_tree * env_tree; chashdatum hashkey; chashdatum hashdata; chashdatum hashold; time_t date; msg = carray_get(env_list->msg_tab, i); if (msg == NULL) continue; if (msg->msg_fields != NULL) { msgid = get_msg_id(msg); if (msgid == NULL) { msgid = mailimf_get_message_id(); } else { hashkey.data = msgid; hashkey.len = strlen(msgid); if (chash_get(msg_id_hash, &hashkey, &hashdata) == 0) msgid = mailimf_get_message_id(); else msgid = strdup(msgid); } if (msgid == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } date = get_date(msg); env_tree = mailmessage_tree_new(msgid, date, msg); if (env_tree == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } r = carray_add(msg_list, env_tree, NULL); if (r < 0) { mailmessage_tree_free(env_tree); res = MAIL_ERROR_MEMORY; goto free_list; } hashkey.data = msgid; hashkey.len = strlen(msgid); hashdata.data = env_tree; hashdata.len = 0; r = chash_set(msg_id_hash, &hashkey, &hashdata, &hashold); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free_list; } } } /* (1) for all messages */ for(cur = 0 ; cur < carray_count(msg_list) ; cur ++) { struct mailmessage_tree * env_tree; mailmessage * msg; clist * ref; env_tree = carray_get(msg_list, cur); msg = env_tree->node_msg; ref = NULL; if (msg != NULL) { ref = get_ref(msg); if (ref == NULL) ref = get_in_reply_to(msg); } /* (A) Using the Message IDs in the message's references, link the corresponding messages (those whose Message-ID header line contains the given reference Message ID) together as parent/child. */ if (ref != NULL) { /* try to start a tree */ clistiter * cur_ref; chashdatum hashkey; chashdatum hashdata; chashdatum hashold; struct mailmessage_tree * env_cur_tree; struct mailmessage_tree * last_env_cur_tree; env_cur_tree = NULL; for(cur_ref = clist_begin(ref) ; cur_ref != NULL ; cur_ref = clist_next(cur_ref)) { char * msgid; last_env_cur_tree = env_cur_tree; msgid = clist_content(cur_ref); hashkey.data = msgid; hashkey.len = strlen(msgid); r = chash_get(msg_id_hash, &hashkey, &hashdata); if (r < 0) { /* not found, create a dummy message */ msgid = strdup(msgid); if (msgid == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } env_cur_tree = mailmessage_tree_new(msgid, (time_t) -1, NULL); if (env_cur_tree == NULL) { free(msgid); res = MAIL_ERROR_MEMORY; goto free_list; } r = carray_add(msg_list, env_cur_tree, NULL); if (r < 0) { mailmessage_tree_free(env_cur_tree); res = MAIL_ERROR_MEMORY; goto free_list; } hashkey.data = msgid; hashkey.len = strlen(msgid); hashdata.data = env_cur_tree; hashdata.len = 0; r = chash_set(msg_id_hash, &hashkey, &hashdata, &hashold); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free_list; } } else { env_cur_tree = hashdata.data; } if (last_env_cur_tree != NULL) { if (env_cur_tree->node_parent == NULL) { /* make it one child */ if (env_cur_tree != last_env_cur_tree) { if (!is_descendant(env_cur_tree, last_env_cur_tree)) { /* set parent */ env_cur_tree->node_parent = last_env_cur_tree; r = carray_add(last_env_cur_tree->node_children, env_cur_tree, NULL); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free_list; } } } } } } /* (B) Create a parent/child link between the last reference (or NIL if there are no references) and the current message. If the current message already has a parent, it is probably the result of a truncated References header line, so break the current parent/child link before creating the new correct one. */ last_env_cur_tree = env_cur_tree; if (last_env_cur_tree != NULL) { if (env_tree->node_parent == NULL) { if (last_env_cur_tree != env_tree) { if (!is_descendant(env_tree, last_env_cur_tree)) { /* set parent */ env_tree->node_parent = last_env_cur_tree; r = carray_add(last_env_cur_tree->node_children, env_tree, NULL); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free_list; } } } } } } } chash_free(msg_id_hash); msg_id_hash = NULL; /* (2) Gather together all of the messages that have no parents and make them all children (siblings of one another) of a dummy parent (the "root"). */ for(cur = 0 ; cur < carray_count(msg_list) ; cur ++) { struct mailmessage_tree * env_tree; env_tree = carray_get(msg_list, cur); if (env_tree->node_parent == NULL) { r = carray_add(rootlist, env_tree, NULL); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free_list; } /* set parent */ env_tree->node_parent = root; } } carray_free(msg_list); msg_list = NULL; /* (3) Prune dummy messages from the thread tree. */ cur = 0; while (cur < carray_count(rootlist)) { r = delete_dummy(rootlist, rootlist, cur, &cur); if (r != MAIL_NO_ERROR) { res = r; goto free_list; } } /* (4) Sort the messages under the root (top-level siblings only) by sent date. */ r = mail_thread_sort(root, mailthread_tree_timecomp, FALSE); if (r != MAIL_NO_ERROR) { res = r; goto free_list; } if (use_subject) { /* (5) Gather together messages under the root that have the same extracted subject text. (A) Create a table for associating extracted subjects with messages. */ subject_hash = chash_new(128, CHASH_COPYVALUE); if (subject_hash == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } /* (B) Populate the subject table with one message per extracted subject. For each child of the root: */ for(cur = 0 ; cur < carray_count(rootlist) ; cur ++) { struct mailmessage_tree * env_tree; chashdatum key; chashdatum data; char * base_subject; env_tree = carray_get(rootlist, cur); /* (i) Find the subject of this thread by extracting the base subject from the current message, or its first child if the current message is a dummy. */ r = get_thread_subject(default_from, env_tree, &base_subject); /* (ii) If the extracted subject is empty, skip this message. */ if (r == MAIL_ERROR_SUBJECT_NOT_FOUND) { /* no subject found */ continue; } else if (r == MAIL_NO_ERROR) { if (* base_subject == '\0') { /* subject empty */ free(base_subject); continue; } else { /* do nothing */ } } else { res = r; goto free_subject_hash; } env_tree->node_base_subject = base_subject; /* (iii) Lookup the message associated with this extracted subject in the table. */ key.data = base_subject; key.len = strlen(base_subject); r = chash_get(subject_hash, &key, &data); if (r < 0) { /* (iv) If there is no message in the table with this subject, add the current message and the extracted subject to the subject table. */ data.data = &cur; data.len = sizeof(cur); r = chash_set(subject_hash, &key, &data, NULL); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free_subject_hash; } } else { /* Otherwise, replace the message in the table with the current message if the message in the table is not a dummy AND either of the following criteria are true: The current message is a dummy, OR The message in the table is a reply or forward (its original subject contains a subj-refwd part and/or a "(fwd)" subj-trailer) and the current message is not. */ struct mailmessage_tree * msg_in_table; unsigned int * iter_in_table; int replace; iter_in_table = data.data; msg_in_table = carray_get(rootlist, cur); replace = FALSE; /* message is dummy if info is NULL */ if (msg_in_table->node_msg != NULL) { if (env_tree->node_msg == NULL) replace = TRUE; else { if (env_tree->node_is_reply && !env_tree->node_is_reply) replace = TRUE; } } if (replace) { data.data = &cur; data.len = sizeof(cur); r = chash_set(subject_hash, &key, &data, NULL); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free_subject_hash; } } } } /* (C) Merge threads with the same subject. For each child of the root: */ cur = 0; while (cur < carray_count(rootlist)) { struct mailmessage_tree * env_tree; chashdatum key; chashdatum data; struct mailmessage_tree * main_tree; unsigned int * main_cur; env_tree = carray_get(rootlist, cur); if (env_tree == NULL) goto next_msg; /* (i) Find the subject of this thread as in step 4.B.i above. */ /* already done in tree->node_base_subject */ /* (ii) If the extracted subject is empty, skip this message. */ if (env_tree->node_base_subject == NULL) goto next_msg; if (* env_tree->node_base_subject == '\0') goto next_msg; /* (iii) Lookup the message associated with this extracted subject in the table. */ key.data = env_tree->node_base_subject; key.len = strlen(env_tree->node_base_subject); r = chash_get(subject_hash, &key, &data); if (r < 0) goto next_msg; /* (iv) If the message in the table is the current message, skip this message. */ main_cur = data.data; if (* main_cur == cur) goto next_msg; /* Otherwise, merge the current message with the one in the table using the following rules: */ main_tree = carray_get(rootlist, * main_cur); /* If both messages are dummies, append the current message's children to the children of the message in the table (the children of both messages become siblings), and then delete the current message. */ if ((env_tree->node_msg == NULL) && (main_tree->node_msg == NULL)) { unsigned int old_size; old_size = carray_count(main_tree->node_children); r = carray_set_size(main_tree->node_children, old_size + carray_count(env_tree->node_children)); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free_subject_hash; } for(i = 0 ; i < carray_count(env_tree->node_children) ; i ++) { struct mailmessage_tree * child; child = carray_get(env_tree->node_children, i); carray_set(main_tree->node_children, old_size + i, child); /* set parent */ child->node_parent = main_tree; } carray_set_size(env_tree->node_children, 0); /* this is the only case where children can be NULL, this is before freeing it */ mailmessage_tree_free(env_tree); carray_delete_fast(rootlist, cur); } /* If the message in the table is a dummy and the current message is not, make the current message a child of the message in the table (a sibling of it's children). */ else if (main_tree->node_msg == NULL) { r = carray_add(main_tree->node_children, env_tree, NULL); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free_subject_hash; } /* set parent */ env_tree->node_parent = main_tree; carray_delete_fast(rootlist, cur); } /* If the current message is a reply or forward and the message in the table is not, make the current message a child of the message in the table (a sibling of it's children). */ else if (env_tree->node_is_reply && !main_tree->node_is_reply) { r = carray_add(main_tree->node_children, env_tree, NULL); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free_subject_hash; } /* set parent */ env_tree->node_parent = main_tree; carray_delete_fast(rootlist, cur); } /* Otherwise, create a new dummy message and make both the current message and the message in the table children of the dummy. Then replace the message in the table with the dummy message. Note: Subject comparisons are case-insensitive, as described under "Internationalization Considerations." */ else { struct mailmessage_tree * new_main_tree; char * base_subject; unsigned int last; new_main_tree = mailmessage_tree_new(NULL, (time_t) -1, NULL); if (new_main_tree == NULL) { res = MAIL_ERROR_MEMORY; goto free_subject_hash; } /* main_tree->node_base_subject is never NULL */ base_subject = strdup(main_tree->node_base_subject); if (base_subject == NULL) { mailmessage_tree_free(new_main_tree); res = MAIL_ERROR_MEMORY; goto free_subject_hash; } new_main_tree->node_base_subject = base_subject; r = carray_add(rootlist, new_main_tree, &last); if (r < 0) { mailmessage_tree_free(new_main_tree); res = MAIL_ERROR_MEMORY; goto free_subject_hash; } r = carray_add(new_main_tree->node_children, main_tree, NULL); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free_subject_hash; } /* set parent */ main_tree->node_parent = new_main_tree; carray_delete_fast(rootlist, * main_cur); r = carray_add(new_main_tree->node_children, env_tree, NULL); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free_subject_hash; } /* set parent */ env_tree->node_parent = new_main_tree; carray_delete_fast(rootlist, cur); data.data = &last; data.len = sizeof(last); r = chash_set(subject_hash, &key, &data, NULL); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free_subject_hash; } } continue; next_msg: cur ++; continue; } i = 0; for(cur = 0 ; cur < carray_count(rootlist) ; cur ++) { struct mailmessage_tree * env_tree; env_tree = carray_get(rootlist, cur); if (env_tree == NULL) continue; carray_set(rootlist, i, env_tree); i ++; } carray_set_size(rootlist, i); chash_free(subject_hash); } /* (6) Traverse the messages under the root and sort each set of siblings by sent date. Traverse the messages in such a way that the "youngest" set of siblings are sorted first, and the "oldest" set of siblings are sorted last (grandchildren are sorted before children, etc). In the case of an exact match on sent date or if either of the Date: headers used in a comparison can not be parsed, use the order in which the messages appear in the mailbox (that is, by sequence number) to determine the order. In the case of a dummy message (which can only occur with top-level siblings), use its first child for sorting. */ #if 0 if (comp_func != NULL) { r = mail_thread_sort(root, comp_func, TRUE); if (r != MAIL_NO_ERROR) { res = r; goto free_list; } } #endif if (comp_func == NULL) comp_func = mailthread_tree_timecomp; r = mail_thread_sort(root, comp_func, TRUE); if (r != MAIL_NO_ERROR) { res = r; goto free_list; } * result = root; return MAIL_NO_ERROR; free_subject_hash: chash_free(subject_hash); free_list: if (msg_list != NULL) { for(i = 0 ; i < carray_count(msg_list) ; i ++) mailmessage_tree_free(carray_get(msg_list, i)); carray_free(msg_list); } free_root: mailmessage_tree_free_recursive(root); free_hash: if (msg_id_hash != NULL) chash_free(msg_id_hash); err: return res; }
static int delete_dummy(carray * rootlist, carray * sibling_list, unsigned int cur, unsigned int * pnext) { struct mailmessage_tree * env_tree; int res; int r; unsigned int cur_child; unsigned int next; env_tree = carray_get(sibling_list, cur); cur_child = 0; while (cur_child < carray_count(env_tree->node_children)) { delete_dummy(rootlist, env_tree->node_children, cur_child, &cur_child); } if (env_tree->node_msg == NULL) { if (carray_count(env_tree->node_children) == 0) { /* If it is a dummy message with NO children, delete it. */ mailmessage_tree_free(env_tree); carray_delete(sibling_list, cur); next = cur; } else { /* If it is a dummy message with children, delete it, but promote its children to the current level. */ /* Do not promote the children if doing so would make them children of the root, unless there is only one child. */ cur_child = 0; if ((sibling_list != rootlist) || (carray_count(env_tree->node_children) == 1)) { while (cur_child < carray_count(env_tree->node_children)) { struct mailmessage_tree * child; child = carray_get(env_tree->node_children, cur_child); r = carray_add(sibling_list, child, NULL); if (r < 0) { res = MAIL_ERROR_MEMORY; goto err; } /* set new parent of the children */ child->node_parent = env_tree->node_parent; carray_delete(env_tree->node_children, cur_child); } mailmessage_tree_free(env_tree); carray_delete(sibling_list, cur); next = cur; } else next = cur + 1; } } else next = cur + 1; * pnext = next; return MAIL_NO_ERROR; err: return res; }
/* * Computes the phase-correlation of two images using FFT. * * INPUT: * `a` and `b`: the images to correlate. They must be the same size. * `c`: where to put the result * `h` and `w`: the dimensions of `a`, `b`, and `c` * The dimensions could be less than the smallest dimension for partial processing. * * RETURN VALUE: * None. * * OUTPUT: * Saved in `c` * * SIDE EFFECTS: * Saves the result of the correlation in `c` */ inline void phcorr2d(CArray *a, CArray *b, CArray *c) { unsigned int i, j; double normfactor; assert((a->rows == b->rows) && (b->rows == c->rows)); assert((a->cols == b->cols) && (b->cols == c->cols)); /* Multiply F(a) by the complex conjugate of F(b) * as per the Cross-Correlation theorem: * https://ccrma.stanford.edu/~jos/log/Correlation_Theorem.html * http://en.wikipedia.org/wiki/Fourier_transform#Cross-correlation_theorem * Divide by |F(a)F(b)| to get phase correlation as defined in * http://iopscience.iop.org/0004-637X/706/2/1605/fulltext/ * */ for(i = 0; i < a->rows; ++i) { for(j = 0; j < a->cols; ++j) { creal_set(carray_get(c, i, j), creal(carray_get(a, i, j)) * creal(carray_get(b, i, j)) + cimag(carray_get(a, i, j)) * cimag(carray_get(b, i, j))); cimag_set(carray_get(c, i, j), cimag(carray_get(a, i, j)) * creal(carray_get(b, i, j)) - cimag(carray_get(b, i, j)) * creal(carray_get(a, i, j))); normfactor = sqrt(creal(carray_get(c, i, j)) * creal(carray_get(c, i, j)) + cimag(carray_get(c, i, j)) * cimag(carray_get(c, i, j))) + EPSILON; creal_set(carray_get(c, i, j), creal(carray_get(c, i, j)) / normfactor); cimag_set(carray_get(c, i, j), cimag(carray_get(c, i, j)) / normfactor); assert(creal(carray_get(a, i, j)) == creal(carray_get(a, i, j))); assert(creal(carray_get(c, i, j)) == creal(carray_get(c, i, j))); } } }
int mailmbox_append_message_list_no_lock(struct mailmbox_folder * folder, carray * append_tab) { size_t extra_size; int r; char from_line[MAX_FROM_LINE_SIZE] = DEFAULT_FROM_LINE; struct tm time_info; time_t date; int res; size_t old_size; char * str; unsigned int i; size_t from_size; size_t left; size_t crlf_count; if (folder->mb_read_only) { res = MAILMBOX_ERROR_READONLY; goto err; } date = time(NULL); from_size = strlen(DEFAULT_FROM_LINE); if (localtime_r(&date, &time_info) != NULL) #ifdef CRLF_BADNESS from_size = strftime(from_line, MAX_FROM_LINE_SIZE, "From - %c\r\n", &time_info); #else from_size = strftime(from_line, MAX_FROM_LINE_SIZE, "From - %c\n", &time_info); #endif extra_size = 0; for(i = 0 ; i < carray_count(append_tab) ; i ++) { struct mailmbox_append_info * info; info = carray_get(append_tab, i); extra_size += from_size; extra_size += get_fixed_message_size(info->ai_message, info->ai_size, folder->mb_max_uid + i + 1, folder->mb_no_uid); #ifdef CRLF_BADNESS extra_size += 2; /* CR LF */ #else extra_size += 1; /* CR LF */ #endif info->ai_uid = folder->mb_max_uid + i + 1; } left = folder->mb_mapping_size; crlf_count = 0; while (left >= 1) { if (folder->mb_mapping[left - 1] == '\n') { crlf_count ++; left --; } #ifdef CRLF_BADNESS else if (folder->mb_mapping[left - 1] == '\r') { left --; } #endif else break; if (crlf_count == 2) break; } old_size = folder->mb_mapping_size; mailmbox_unmap(folder); if (old_size != 0) { if (crlf_count != 2) #ifdef CRLF_BADNESS extra_size += (2 - crlf_count) * 2; #else /* Need the number of LFs, not CRLFs */ extra_size += (2 - crlf_count) * 1; #endif } r = ftruncate(folder->mb_fd, extra_size + old_size); if (r < 0) { mailmbox_map(folder); res = MAILMBOX_ERROR_FILE; goto err; } r = mailmbox_map(folder); if (r < 0) { r = ftruncate(folder->mb_fd, old_size); return MAILMBOX_ERROR_FILE; } str = folder->mb_mapping + old_size; if (old_size != 0) { for(i = 0 ; i < 2 - crlf_count ; i ++) { #ifdef CRLF_BADNESS * str = '\r'; str ++; #endif * str = '\n'; str ++; } } for(i = 0 ; i < carray_count(append_tab) ; i ++) { struct mailmbox_append_info * info; info = carray_get(append_tab, i); memcpy(str, from_line, from_size); str += strlen(from_line); str = write_fixed_message(str, info->ai_message, info->ai_size, folder->mb_max_uid + i + 1, folder->mb_no_uid); #ifdef CRLF_BADNESS * str = '\r'; str ++; #endif * str = '\n'; str ++; } folder->mb_max_uid += carray_count(append_tab); return MAILMBOX_NO_ERROR; err: return res; }
static int nntpdriver_get_envelopes_list(mailsession * session, struct mailmessage_list * env_list) { newsnntp * nntp; int r; struct nntp_session_state_data * data; clist * list; int done; clistiter * cur; uint32_t first_seq; unsigned int i; nntp = get_nntp_session(session); data = get_data(session); if (data->nntp_group_info == NULL) return MAIL_ERROR_BAD_STATE; first_seq = data->nntp_group_info->grp_first; if (carray_count(env_list->msg_tab) > 0) { mailmessage * msg; msg = carray_get(env_list->msg_tab, 0); first_seq = msg->msg_index; } if (carray_count(env_list->msg_tab) > 0) { i = carray_count(env_list->msg_tab) - 1; while (1) { mailmessage * msg; msg = carray_get(env_list->msg_tab, i); if (msg->msg_fields != NULL) { first_seq = msg->msg_index + 1; break; } if (i == 0) break; i --; } } if (first_seq > data->nntp_group_info->grp_last) { list = NULL; } else { done = FALSE; do { r = newsnntp_xover_range(nntp, first_seq, data->nntp_group_info->grp_last, &list); switch (r) { case NEWSNNTP_ERROR_REQUEST_AUTHORIZATION_USERNAME: r = nntpdriver_authenticate_user(session); if (r != MAIL_NO_ERROR) return r; break; case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD: r = nntpdriver_authenticate_password(session); if (r != MAIL_NO_ERROR) return r; break; case NEWSNNTP_NO_ERROR: done = TRUE; break; default: return nntpdriver_nntp_error_to_mail_error(r); } } while (!done); } #if 0 i = 0; j = 0; if (list != NULL) { for(cur = clist_begin(list) ; cur != NULL ; cur = clist_next(cur)) { struct newsnntp_xover_resp_item * item; struct mailimf_fields * fields; item = clist_content(cur); while (i < carray_count(env_list->msg_tab)) { mailmessage * info; info = carray_get(env_list->msg_tab, i); if (item->ovr_article == info->msg_index) { if (info->fields == NULL) { r = xover_resp_to_fields(item, &fields); if (r == MAIL_NO_ERROR) { info->fields = fields; } info->size = item->ovr_size; carray_set(env_list->msg_tab, j, info); j ++; i ++; break; } else { carray_set(env_list->msg_tab, j, info); j ++; } } else { if (info->fields != NULL) { carray_set(env_list->msg_tab, j, info); j ++; } else { if (info->flags != NULL) { info->flags->flags &= ~MAIL_FLAG_NEW; info->flags->flags |= MAIL_FLAG_SEEN | MAIL_FLAG_DELETED; mailmessage_check(info); } mailmessage_free(info); carray_set(env_list->msg_tab, i, NULL); } } i ++; } } } while (i < carray_count(env_list->msg_tab)) { mailmessage * info; info = carray_get(env_list->msg_tab, i); if (info->fields != NULL) { carray_set(env_list->msg_tab, j, info); j ++; } else { if (info->flags != NULL) { info->flags->flags &= ~MAIL_FLAG_NEW; info->flags->flags |= MAIL_FLAG_SEEN | MAIL_FLAG_DELETED; mailmessage_check(info); } mailmessage_free(info); carray_set(env_list->msg_tab, i, NULL); } i ++; } r = carray_set_size(env_list->msg_tab, j); if (r < 0) { if (list != NULL) newsnntp_xover_resp_list_free(list); return MAIL_ERROR_MEMORY; } #endif i = 0; if (list != NULL) { for(cur = clist_begin(list) ; cur != NULL ; cur = clist_next(cur)) { struct newsnntp_xover_resp_item * item; struct mailimf_fields * fields; item = clist_content(cur); while (i < carray_count(env_list->msg_tab)) { mailmessage * info; info = carray_get(env_list->msg_tab, i); if (item->ovr_article == info->msg_index) { if (info->msg_fields == NULL) { fields = NULL; r = xover_resp_to_fields(item, &fields); if (r == MAIL_NO_ERROR) { info->msg_fields = fields; } info->msg_size = item->ovr_size; i ++; break; } } #if 0 else if ((info->fields == NULL) && (info->flags != NULL)) { info->flags->flags &= ~MAIL_FLAG_NEW; info->flags->flags |= MAIL_FLAG_CANCELLED; mailmessage_check(info); } #endif i ++; } } } #if 0 while (i < env_list->msg_tab->len) { mailmessage * info; info = carray_get(env_list->msg_tab, i); if ((info->fields == NULL) && (info->flags != NULL)) { info->flags->flags &= ~MAIL_FLAG_NEW; info->flags->flags |= MAIL_FLAG_CANCELLED; mailmessage_check(info); } i ++; } #endif if (list != NULL) newsnntp_xover_resp_list_free(list); return MAIL_NO_ERROR; }
static int db_get_message_list(struct mail_cache_db * maildb, carray ** p_msglist) { carray * msglist; void * serialized; size_t serialized_len; int r; char key_value[PATH_MAX]; int res; unsigned int i; msglist = carray_new(16); if (msglist == NULL) { res = MAIL_ERROR_MEMORY; goto err; } snprintf(key_value, sizeof(key_value), "message-list"); r = mail_cache_db_get(maildb, key_value, strlen(key_value), &serialized, &serialized_len); if (r >= 0) { MMAPString * mmapstr; size_t cur_token; /* collect message list */ mmapstr = mmap_string_new_len(serialized, serialized_len); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto free_msglist; } cur_token = 0; do { uint32_t num; uint32_t * msg; r = mailimf_cache_int_read(mmapstr, &cur_token, &num); if (r != MAIL_NO_ERROR) break; msg = malloc(sizeof(* msg)); if (msg == NULL) { res = MAIL_ERROR_MEMORY; mmap_string_free(mmapstr); goto free_msglist; } * msg = num; r = carray_add(msglist, msg, NULL); if (r < 0) { res = MAIL_ERROR_MEMORY; free(msg); mmap_string_free(mmapstr); goto free_msglist; } } while (1); mmap_string_free(mmapstr); } * p_msglist = msglist; return MAIL_NO_ERROR; free_msglist: for(i = 0 ; i < carray_count(msglist) ; i ++) { uint32_t * msg; msg = carray_get(msglist, i); free(msg); } carray_free(msglist); err: return res; }
static int folder_update_msg_list(struct folder_ref_info * ref_info, struct mailmessage_list ** p_new_msg_list, struct mailmessage_list ** p_lost_msg_list) { int r; int res; struct mailmessage_list * new_env_list; unsigned int i; carray * lost_msg_tab; struct mailmessage_list * lost_msg_list; unsigned int free_start_index; chashiter * iter; unsigned int lost_count; r = mailfolder_get_messages_list(ref_info->folder, &new_env_list); if (r != MAIL_NO_ERROR) { res = r; goto err; } for(iter = chash_begin(ref_info->msg_hash) ; iter != NULL ; iter = chash_next(ref_info->msg_hash, iter)) { struct message_ref_elt * msg_ref; chashdatum data; chash_value(iter, &data); msg_ref = data.data; msg_ref->lost = 1; } lost_count = chash_count(ref_info->msg_hash); for(i = 0 ; i < carray_count(new_env_list->msg_tab) ; i ++) { mailmessage * msg; mailmessage * old_msg; msg = carray_get(new_env_list->msg_tab, i); if (msg->msg_uid == NULL) continue; old_msg = folder_info_get_msg_by_uid(ref_info, msg->msg_uid); if (old_msg != NULL) { struct message_ref_elt * msg_ref; /* replace old message */ old_msg->msg_index = msg->msg_index; carray_set(new_env_list->msg_tab, i, old_msg); mailmessage_free(msg); msg_ref = folder_info_get_msg_ref(ref_info, old_msg); msg_ref->lost = 0; lost_count --; } else { /* set new message */ r = folder_message_add(ref_info, msg); if (r != MAIL_NO_ERROR) { free_start_index = i; res = r; goto free_remaining; } } } /* build the table of lost messages */ lost_msg_tab = carray_new(lost_count); if (lost_msg_tab == NULL) { res = MAIL_ERROR_MEMORY; goto free_env_list; } carray_set_size(lost_msg_tab, lost_count); i = 0; for(iter = chash_begin(ref_info->msg_hash) ; iter != NULL ; iter = chash_next(ref_info->msg_hash, iter)) { struct message_ref_elt * msg_ref; chashdatum key; chashdatum value; mailmessage * msg; chash_key(iter, &key); memcpy(&msg, key.data, sizeof(msg)); chash_value(iter, &value); msg_ref = value.data; if (msg_ref->lost) { carray_set(lost_msg_tab, i, msg); i ++; } } lost_msg_list = mailmessage_list_new(lost_msg_tab); if (lost_msg_list == NULL) { res = MAIL_ERROR_MEMORY; goto free_lost_msg_tab; } /* reference messages */ for(i = 0 ; i < carray_count(new_env_list->msg_tab) ; i ++) { mailmessage * msg; msg = carray_get(new_env_list->msg_tab, i); folder_message_ref(ref_info, msg); } * p_new_msg_list = new_env_list; * p_lost_msg_list = lost_msg_list; return MAIL_NO_ERROR; free_lost_msg_tab: carray_free(lost_msg_tab); free_env_list: for(i = 0 ; i < carray_count(new_env_list->msg_tab) ; i ++) { mailmessage * msg; struct message_ref_elt * msg_ref; msg = carray_get(new_env_list->msg_tab, i); msg_ref = folder_info_get_msg_ref(ref_info, msg); if (msg_ref != NULL) { if (msg_ref->ref_count == 0) folder_message_remove(ref_info, msg); } } carray_set_size(new_env_list->msg_tab, 0); mailmessage_list_free(new_env_list); goto err; free_remaining: for(i = 0 ; i < carray_count(new_env_list->msg_tab) ; i ++) { mailmessage * msg; struct message_ref_elt * msg_ref; msg = carray_get(new_env_list->msg_tab, i); msg_ref = folder_info_get_msg_ref(ref_info, msg); if (msg_ref != NULL) { if (msg_ref->ref_count == 0) folder_message_remove(ref_info, msg); } } for(i = free_start_index ; i < carray_count(new_env_list->msg_tab) ; i ++) { mailmessage * msg; msg = carray_get(new_env_list->msg_tab, i); mailmessage_free(msg); } carray_set_size(new_env_list->msg_tab, 0); mailmessage_list_free(new_env_list); err: return res; }
static int expunge_folder(mailsession * session) { int r; char key_value[PATH_MAX]; struct mail_cache_db * maildb; carray * msglist; unsigned int i; struct db_session_state_data * data; int res; chash * msg_table; MMAPString * mmapstr; data = get_data(session); flags_store_process(session); r = mail_cache_db_open_lock(data->db_filename, &maildb); if (r < 0) { res = MAIL_ERROR_FILE; goto err; } r = db_get_message_list(maildb, &msglist); if (r != MAIL_NO_ERROR) { res = r; goto close_db; } msg_table = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY); if (msg_table == NULL) { res = MAIL_ERROR_MEMORY; goto free_msglist; } mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto free_msgtable; } i = 0; while (i < carray_count(msglist)) { uint32_t num; uint32_t * msg; chashdatum key; chashdatum value; struct mail_flags * flags; int deleted; msg = carray_get(msglist, i); num = * msg; deleted = 0; snprintf(key_value, sizeof(key_value), "%lu-flags", (unsigned long) num); r = generic_cache_flags_read(maildb, mmapstr, key_value, &flags); if (r == MAIL_NO_ERROR) { if ((flags->fl_flags & MAIL_FLAG_DELETED) != 0) deleted = 1; } if (!deleted) { snprintf(key_value, sizeof(key_value), "%lu", (unsigned long) num); key.data = key_value; key.len = strlen(key_value); chash_set(msg_table, &key, &value, NULL); snprintf(key_value, sizeof(key_value), "%lu-envelope", (unsigned long) num); key.data = key_value; key.len = strlen(key_value); chash_set(msg_table, &key, &value, NULL); snprintf(key_value, sizeof(key_value), "%lu-flags", (unsigned long) num); key.data = key_value; key.len = strlen(key_value); chash_set(msg_table, &key, &value, NULL); i ++; } else { free(msg); carray_delete(msglist, i); } } mmap_string_free(mmapstr); r = mail_cache_db_clean_up(maildb, msg_table); chash_free(msg_table); r = db_set_message_list(maildb, msglist); for(i = 0 ; i < carray_count(msglist) ; i ++) { uint32_t * msg; msg = carray_get(msglist, i); free(msg); } carray_free(msglist); mail_cache_db_close_unlock(data->db_filename, maildb); return MAIL_NO_ERROR; free_msgtable: chash_free(msg_table); free_msglist: for(i = 0 ; i < carray_count(msglist) ; i ++) { uint32_t * msg; msg = carray_get(msglist, i); free(msg); } close_db: mail_cache_db_close_unlock(data->db_filename, maildb); err: return res; }
static int pop3driver_cached_get_envelopes_list(mailsession * session, struct mailmessage_list * env_list) { int r; unsigned int i; struct pop3_cached_session_state_data * cached_data; char filename_env[PATH_MAX]; char filename_flags[PATH_MAX]; struct mail_cache_db * cache_db_env; struct mail_cache_db * cache_db_flags; MMAPString * mmapstr; int res; cached_data = get_cached_data(session); pop3_flags_store_process(cached_data->pop3_flags_directory, cached_data->pop3_flags_store); snprintf(filename_env, PATH_MAX, "%s/%s", cached_data->pop3_cache_directory, ENV_NAME); mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto err; } r = mail_cache_db_open_lock(filename_env, &cache_db_env); if (r < 0) { res = MAIL_ERROR_FILE; goto free_mmapstr; } snprintf(filename_flags, PATH_MAX, "%s/%s", cached_data->pop3_flags_directory, FLAGS_NAME); r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); if (r < 0) { res = MAIL_ERROR_FILE; goto close_db_env; } /* fill with cached */ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { mailmessage * msg; struct mailimf_fields * fields; struct mail_flags * flags; msg = carray_get(env_list->msg_tab, i); if (msg->msg_fields == NULL) { r = get_cached_envelope(cache_db_env, mmapstr, session, msg->msg_index, &fields); if (r == MAIL_NO_ERROR) { msg->msg_cached = TRUE; msg->msg_fields = fields; } } if (msg->msg_flags == NULL) { r = pop3driver_get_cached_flags(cache_db_flags, mmapstr, session, msg->msg_index, &flags); if (r == MAIL_NO_ERROR) { msg->msg_flags = flags; } } } mail_cache_db_close_unlock(filename_flags, cache_db_flags); mail_cache_db_close_unlock(filename_env, cache_db_env); r = maildriver_generic_get_envelopes_list(session, env_list); if (r != MAIL_NO_ERROR) { res = r; goto free_mmapstr; } /* add flags */ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { mailmessage * msg; msg = carray_get(env_list->msg_tab, i); if (msg->msg_flags == NULL) msg->msg_flags = mail_flags_new_empty(); } r = mail_cache_db_open_lock(filename_env, &cache_db_env); if (r < 0) { res = MAIL_ERROR_FILE; goto free_mmapstr; } r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); if (r < 0) { res = MAIL_ERROR_FILE; goto close_db_env; } /* must write cache */ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { mailmessage * msg; msg = carray_get(env_list->msg_tab, i); if (msg->msg_fields != NULL) { if (!msg->msg_cached) { r = write_cached_envelope(cache_db_env, mmapstr, session, msg->msg_index, msg->msg_fields); } } if (msg->msg_flags != NULL) { r = pop3driver_write_cached_flags(cache_db_flags, mmapstr, msg->msg_uid, msg->msg_flags); } } /* flush cache */ maildriver_cache_clean_up(cache_db_env, cache_db_flags, env_list); mail_cache_db_close_unlock(filename_flags, cache_db_flags); mail_cache_db_close_unlock(filename_env, cache_db_env); mmap_string_free(mmapstr); /* remove cache files */ maildriver_message_cache_clean_up(cached_data->pop3_cache_directory, env_list, get_uid_from_filename); return MAIL_NO_ERROR; close_db_env: mail_cache_db_close_unlock(filename_env, cache_db_env); free_mmapstr: mmap_string_free(mmapstr); err: return res; }
static int status_folder(mailsession * session, const char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen) { struct mail_cache_db * maildb; char key_value[PATH_MAX]; MMAPString * mmapstr; uint32_t messages; uint32_t recent; uint32_t unseen; struct db_session_state_data * data; int r; int res; carray * msglist; unsigned int i; data = get_data(session); flags_store_process(session); r = mail_cache_db_open_lock(data->db_filename, &maildb); if (r < 0) { res = MAIL_ERROR_FILE; goto err; } r = db_get_message_list(maildb, &msglist); if (r != MAIL_NO_ERROR) { res = r; goto close_db; } mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } messages = 0; recent = 0; unseen = 0; for(i = 0 ; i < carray_count(msglist) ; i ++) { uint32_t num; uint32_t * msg; struct mail_flags * flags; msg = carray_get(msglist, i); num = * msg; free(msg); carray_set(msglist, i, NULL); messages ++; snprintf(key_value, sizeof(key_value), "%lu-flags", (unsigned long) num); r = generic_cache_flags_read(maildb, mmapstr, key_value, &flags); if (r == MAIL_NO_ERROR) { if ((flags->fl_flags & MAIL_FLAG_NEW) != 0) { recent ++; } if ((flags->fl_flags & MAIL_FLAG_SEEN) == 0) { unseen ++; } mail_flags_free(flags); } } mmap_string_free(mmapstr); carray_free(msglist); mail_cache_db_close_unlock(data->db_filename, maildb); * result_messages = messages; * result_unseen = unseen; * result_recent = recent; return MAIL_NO_ERROR; free_list: for(i = 0 ; i < carray_count(msglist) ; i ++) { uint32_t * msg; msg = carray_get(msglist, i); if (msg != NULL) free(msg); } carray_free(msglist); close_db: mail_cache_db_close_unlock(data->db_filename, maildb); err: return res; }
int maildriver_cache_clean_up(struct mail_cache_db * cache_db_env, struct mail_cache_db * cache_db_flags, struct mailmessage_list * env_list) { chash * hash_exist; int res; int r; char keyname[PATH_MAX]; unsigned int i; /* flush cache */ hash_exist = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYALL); if (hash_exist == NULL) { res = MAIL_ERROR_MEMORY; goto err; } for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { mailmessage * msg; chashdatum key; chashdatum value; msg = carray_get(env_list->msg_tab, i); value.data = NULL; value.len = 0; if (cache_db_env != NULL) { snprintf(keyname, PATH_MAX, "%s-envelope", msg->msg_uid); key.data = keyname; key.len = strlen(keyname); r = chash_set(hash_exist, &key, &value, NULL); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free; } } if (cache_db_flags != NULL) { snprintf(keyname, PATH_MAX, "%s-flags", msg->msg_uid); key.data = keyname; key.len = strlen(keyname); r = chash_set(hash_exist, &key, &value, NULL); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free; } } } /* clean up */ if (cache_db_env != NULL) mail_cache_db_clean_up(cache_db_env, hash_exist); if (cache_db_flags != NULL) mail_cache_db_clean_up(cache_db_flags, hash_exist); chash_free(hash_exist); return MAIL_NO_ERROR; free: chash_free(hash_exist); err: return res; }
static int mail_build_thread_orderedsubject(char * default_from, struct mailmessage_list * env_list, struct mailmessage_tree ** result, int (* comp_func)(struct mailmessage_tree **, struct mailmessage_tree **)) { unsigned int i; carray * rootlist; unsigned int cur; struct mailmessage_tree * root; int res; int r; struct mailmessage_tree * current_thread; root = mailmessage_tree_new(NULL, (time_t) -1, NULL); if (root == NULL) { res = MAIL_ERROR_MEMORY; goto err; } rootlist = root->node_children; /* The ORDEREDSUBJECT threading algorithm is also referred to as "poor man's threading." */ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { mailmessage * msg; struct mailmessage_tree * env_tree; char * base_subject; time_t date; msg = carray_get(env_list->msg_tab, i); if (msg == NULL) continue; if (msg->msg_fields != NULL) { date = get_date(msg); env_tree = mailmessage_tree_new(NULL, date, msg); if (env_tree == NULL) { res = MAIL_ERROR_MEMORY; goto free; } /* set parent */ env_tree->node_parent = root; r = carray_add(rootlist, env_tree, NULL); if (r < 0) { mailmessage_tree_free(env_tree); res = MAIL_ERROR_MEMORY; goto free; } r = get_extracted_subject(default_from, env_tree, &base_subject); switch (r) { case MAIL_NO_ERROR: env_tree->node_base_subject = base_subject; break; case MAIL_ERROR_SUBJECT_NOT_FOUND: break; default: res = r; goto free; } } } /* The searched messages are sorted by subject and then by the sent date. */ r = mail_thread_sort(root, tree_subj_time_comp, FALSE); if (r != MAIL_NO_ERROR) { res = r; goto free; } /* The messages are then split into separate threads, with each thread containing messages with the same extracted subject text. */ current_thread = NULL; cur = 0; while (cur < carray_count(rootlist)) { struct mailmessage_tree * cur_env_tree; cur_env_tree = carray_get(rootlist, cur); if (current_thread == NULL) { current_thread = cur_env_tree; cur ++; continue; } if ((cur_env_tree->node_base_subject == NULL) || (current_thread->node_base_subject == NULL)) { current_thread = cur_env_tree; cur ++; continue; } if (strcmp(cur_env_tree->node_base_subject, current_thread->node_base_subject) == 0) { /* set parent */ cur_env_tree->node_parent = current_thread; r = carray_add(current_thread->node_children, cur_env_tree, NULL); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free; } carray_delete(rootlist, cur); } else cur ++; current_thread = cur_env_tree; } /* Finally, the threads are sorted by the sent date of the first message in the thread. Note that each message in a thread is a child (as opposed to a sibling) of the previous message. */ #if 0 if (comp_func != NULL) { r = mail_thread_sort(root, comp_func, FALSE); if (r != MAIL_NO_ERROR) { res = r; goto free; } } #endif if (comp_func == NULL) comp_func = mailthread_tree_timecomp; r = mail_thread_sort(root, comp_func, FALSE); if (r != MAIL_NO_ERROR) { res = r; goto free; } * result = root; return MAIL_NO_ERROR; free: mailmessage_tree_free_recursive(root); err: return res; }