From 9e549686b23b6dffdcbd09c9b10dc2cb795fbcdf Mon Sep 17 00:00:00 2001 From: zautrix Date: Fri, 18 Mar 2005 20:17:03 +0000 Subject: Initial revision --- (limited to 'libetpan/src/driver/tools/generic_cache.c') diff --git a/libetpan/src/driver/tools/generic_cache.c b/libetpan/src/driver/tools/generic_cache.c new file mode 100644 index 0000000..3ff6e43 --- a/dev/null +++ b/libetpan/src/driver/tools/generic_cache.c @@ -0,0 +1,729 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "generic_cache.h" + +#include "libetpan-config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "maildriver_types.h" +#include "imfcache.h" +#include "chash.h" +#include "mailmessage.h" +#include "mail_cache_db.h" + +int generic_cache_create_dir(char * dirname) +{ + struct stat buf; + int r; + + r = stat(dirname, &buf); + if (r != 0) { + r = mkdir(dirname, 0700); + + if (r < 0) + return MAIL_ERROR_FILE; + } + else { + if (!S_ISDIR(buf.st_mode)) + return MAIL_ERROR_FILE; + } + + return MAIL_NO_ERROR; +} + +int generic_cache_store(char * filename, char * content, size_t length) +{ + int fd; + char * str; + + fd = open(filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + if (fd == -1) + return MAIL_ERROR_FILE; + + if (ftruncate(fd, length) < 0) + return MAIL_ERROR_FILE; + + str = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (str == MAP_FAILED) + return MAIL_ERROR_FILE; + + memcpy(str, content, length); + msync(str, length, MS_SYNC); + munmap(str, length); + + close(fd); + + return MAIL_NO_ERROR; +} + +int generic_cache_read(char * filename, char ** result, size_t * result_len) +{ + int fd; + char * str; + struct stat buf; + MMAPString * mmapstr; + char * content; + int res; + + if (stat(filename, &buf) < 0) { + res = MAIL_ERROR_CACHE_MISS; + goto err; + } + + fd = open(filename, O_RDONLY); + if (fd == -1) { + res = MAIL_ERROR_CACHE_MISS; + goto err; + } + + str = mmap(NULL, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (str == MAP_FAILED) { + res = MAIL_ERROR_FILE; + goto close; + } + + mmapstr = mmap_string_new_len(str, buf.st_size); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto unmap; + } + + if (mmap_string_ref(mmapstr) < 0) { + res = MAIL_ERROR_MEMORY; + goto free; + } + + content = mmapstr->str; + + munmap(str, buf.st_size); + close(fd); + + * result = content; + * result_len = buf.st_size; + + return MAIL_NO_ERROR; + + free: + mmap_string_free(mmapstr); + unmap: + munmap(str, buf.st_size); + close: + close(fd); + err: + return res; +} + +static int flags_extension_read(MMAPString * mmapstr, size_t * index, + clist ** result) +{ + clist * list; + int r; + uint32_t count; + uint32_t i; + int res; + + r = mailimf_cache_int_read(mmapstr, index, &count); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + list = clist_new(); + if (list == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + for(i = 0 ; i < count ; i++) { + char * str; + + r = mailimf_cache_string_read(mmapstr, index, &str); + if (r != MAIL_NO_ERROR) { + res = r; + goto free_list; + } + + r = clist_append(list, str); + if (r < 0) { + free(str); + res = MAIL_ERROR_MEMORY; + goto free_list; + } + } + + * result = list; + + return MAIL_NO_ERROR; + + free_list: + clist_foreach(list, (clist_func) free, NULL); + clist_free(list); + err: + return res; +} + +static int generic_flags_read(MMAPString * mmapstr, size_t * index, + struct mail_flags ** result) +{ + clist * ext; + int r; + struct mail_flags * flags; + uint32_t value; + int res; + + r = mailimf_cache_int_read(mmapstr, index, &value); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + r = flags_extension_read(mmapstr, index, &ext); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + flags = mail_flags_new(value, ext); + if (flags == NULL) { + res = r; + goto free; + } + + * result = flags; + + return MAIL_NO_ERROR; + + free: + clist_foreach(ext, (clist_func) free, NULL); + clist_free(ext); + err: + return res; +} + +static int flags_extension_write(MMAPString * mmapstr, size_t * index, + clist * ext) +{ + int r; + clistiter * cur; + + r = mailimf_cache_int_write(mmapstr, index, clist_count(ext)); + if (r != MAIL_NO_ERROR) + return r; + + for(cur = clist_begin(ext) ; cur != NULL ; cur = clist_next(cur)) { + r = mailimf_cache_string_write(mmapstr, index, + clist_content(cur), strlen(clist_content(cur))); + if (r != MAIL_NO_ERROR) + return r; + } + + return MAIL_NO_ERROR; +} + +static int generic_flags_write(MMAPString * mmapstr, size_t * index, + struct mail_flags * flags) +{ + int r; + + r = mailimf_cache_int_write(mmapstr, index, + flags->fl_flags & ~MAIL_FLAG_NEW); + if (r != MAIL_NO_ERROR) + return r; + + r = flags_extension_write(mmapstr, index, + flags->fl_extension); + if (r != MAIL_NO_ERROR) + return r; + + return MAIL_NO_ERROR; +} + + + + +static struct mail_flags * mail_flags_dup(struct mail_flags * flags) +{ + clist * list; + struct mail_flags * new_flags; + int r; + clistiter * cur; + + list = clist_new(); + if (list == NULL) { + goto err; + } + + for(cur = clist_begin(flags->fl_extension) ; cur != NULL ; + cur = clist_next(cur)) { + char * ext; + + ext = strdup(clist_content(cur)); + if (ext == NULL) { + goto free; + } + + r = clist_append(list, ext); + if (r < 0) { + free(ext); + goto free; + } + } + + new_flags = mail_flags_new(flags->fl_flags, list); + if (new_flags == NULL) { + goto free; + } + + return new_flags; + + free: + clist_foreach(list, (clist_func) free, NULL); + clist_free(list); + err: + return NULL; +} + +static mailmessage * mailmessage_build(mailmessage * msg) +{ + mailmessage * new_msg; + + new_msg = malloc(sizeof(* new_msg)); + if (new_msg == NULL) + goto err; + + new_msg->msg_session = msg->msg_session; + new_msg->msg_driver = msg->msg_driver; + new_msg->msg_index = msg->msg_index; + if (msg->msg_uid == NULL) + new_msg->msg_uid = NULL; + else { + new_msg->msg_uid = strdup(msg->msg_uid); + if (new_msg->msg_uid == NULL) + goto free; + } + + new_msg->msg_cached = msg->msg_cached; + new_msg->msg_size = msg->msg_size; + new_msg->msg_fields = NULL; + new_msg->msg_flags = mail_flags_dup(msg->msg_flags); + if (new_msg->msg_flags == NULL) { + free(new_msg->msg_uid); + goto free; + } + + new_msg->msg_mime = NULL; + new_msg->msg_data = NULL; + + return new_msg; + + free: + free(new_msg); + err: + return NULL; +} + +struct mail_flags_store * mail_flags_store_new(void) +{ + struct mail_flags_store * flags_store; + + flags_store = malloc(sizeof(struct mail_flags_store)); + if (flags_store == NULL) + goto err; + + flags_store->fls_tab = carray_new(128); + if (flags_store->fls_tab == NULL) + goto free; + + flags_store->fls_hash = chash_new(128, CHASH_COPYALL); + if (flags_store->fls_hash == NULL) + goto free_tab; + + return flags_store; + + free_tab: + carray_free(flags_store->fls_tab); + free: + free(flags_store); + err: + return NULL; +} + +void mail_flags_store_clear(struct mail_flags_store * flags_store) +{ + unsigned int i; + + for(i = 0 ; i < carray_count(flags_store->fls_tab) ; i ++) { + chashdatum key; + mailmessage * msg; + + msg = carray_get(flags_store->fls_tab, i); + + key.data = &msg->msg_index; + key.len = sizeof(msg->msg_index); + chash_delete(flags_store->fls_hash, &key, NULL); + + mailmessage_free(msg); + } + carray_set_size(flags_store->fls_tab, 0); +} + +void mail_flags_store_free(struct mail_flags_store * flags_store) +{ + mail_flags_store_clear(flags_store); + chash_free(flags_store->fls_hash); + carray_free(flags_store->fls_tab); + free(flags_store); +} + +int mail_flags_store_set(struct mail_flags_store * flags_store, + mailmessage * msg) +{ + chashdatum key; + chashdatum value; + unsigned int index; + int res; + int r; + mailmessage * new_msg; + + if (msg->msg_flags == NULL) { + res = MAIL_NO_ERROR; + goto err; + } + + /* duplicate needed message info */ + new_msg = mailmessage_build(msg); + if (new_msg == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + key.data = &new_msg->msg_index; + key.len = sizeof(new_msg->msg_index); + + r = chash_get(flags_store->fls_hash, &key, &value); + if (r == 0) { + mailmessage * old_msg; + + index = * (unsigned int *) value.data; + old_msg = carray_get(flags_store->fls_tab, index); + mailmessage_free(old_msg); + } + else { + r = carray_set_size(flags_store->fls_tab, + carray_count(flags_store->fls_tab) + 1); + if (r != 0) { + res = MAIL_ERROR_MEMORY; + goto err; + } + index = carray_count(flags_store->fls_tab) - 1; + } + + carray_set(flags_store->fls_tab, index, new_msg); + + value.data = &index; + value.len = sizeof(index); + + r = chash_set(flags_store->fls_hash, &key, &value, NULL); + if (r < 0) { + carray_delete(flags_store->fls_tab, index); + res = MAIL_ERROR_MEMORY; + goto free; + } + + return MAIL_NO_ERROR; + + free: + mailmessage_free(new_msg); + err: + return res; +} + +static int msg_index_compare(mailmessage ** msg1, mailmessage ** msg2) +{ + return (* msg1)->msg_index - (* msg2)->msg_index; +} + +void mail_flags_store_sort(struct mail_flags_store * flags_store) +{ + qsort(carray_data(flags_store->fls_tab), + carray_count(flags_store->fls_tab), sizeof(mailmessage *), + (int (*)(const void *, const void *)) msg_index_compare); +} + +struct mail_flags * +mail_flags_store_get(struct mail_flags_store * flags_store, uint32_t index) +{ + struct mail_flags * flags; + chashdatum key; + chashdatum value; + int r; + unsigned int tab_index; + mailmessage * msg; + + key.data = &index; + key.len = sizeof(index); + + r = chash_get(flags_store->fls_hash, &key, &value); + + if (r < 0) + return NULL; + +#if 0 + flags = mail_flags_dup((struct mail_flags *) value.data); +#endif + tab_index = * (unsigned int *) value.data; + msg = carray_get(flags_store->fls_tab, tab_index); + if (msg->msg_flags == NULL) + return NULL; + + flags = mail_flags_dup(msg->msg_flags); + + return flags; +} + +int mail_flags_compare(struct mail_flags * flags1, struct mail_flags * flags2) +{ + clistiter * cur1; + + if (clist_count(flags1->fl_extension) != clist_count(flags2->fl_extension)) + return -1; + + for(cur1 = clist_begin(flags1->fl_extension) ; cur1 != NULL ; + cur1 = clist_next(cur1)) { + char * flag1; + clistiter * cur2; + int found; + + flag1 = clist_content(cur1); + + found = 0; + for(cur2 = clist_begin(flags2->fl_extension) ; cur2 != NULL ; + cur2 = clist_next(cur2)) { + char * flag2; + + flag2 = clist_content(cur2); + + if (strcasecmp(flag1, flag2) == 0) { + found = 1; + break; + } + } + + if (!found) + return -1; + } + + return flags1->fl_flags - flags2->fl_flags; +} + + +int generic_cache_fields_read(struct mail_cache_db * cache_db, + MMAPString * mmapstr, + char * keyname, struct mailimf_fields ** result) +{ + int r; + int res; + size_t cur_token; + struct mailimf_fields * fields; + void * data; + size_t data_len; + + r = mail_cache_db_get(cache_db, keyname, strlen(keyname), &data, &data_len); + if (r != 0) { + res = MAIL_ERROR_CACHE_MISS; + goto err; + } + + r = mail_serialize_clear(mmapstr, &cur_token); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + if (mmap_string_append_len(mmapstr, data, data_len) == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + r = mailimf_cache_fields_read(mmapstr, &cur_token, &fields); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + * result = fields; + + return MAIL_NO_ERROR; + + err: + return res; +} + +int generic_cache_fields_write(struct mail_cache_db * cache_db, + MMAPString * mmapstr, + char * keyname, struct mailimf_fields * fields) +{ + int r; + int res; + size_t cur_token; + + r = mail_serialize_clear(mmapstr, &cur_token); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_cache_fields_write(mmapstr, &cur_token, fields); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + r = mail_cache_db_put(cache_db, keyname, strlen(keyname), + mmapstr->str, mmapstr->len); + if (r != 0) { + res = MAIL_ERROR_FILE; + goto err; + } + + return MAIL_NO_ERROR; + + err: + return res; +} + +int generic_cache_flags_read(struct mail_cache_db * cache_db, + MMAPString * mmapstr, + char * keyname, struct mail_flags ** result) +{ + int r; + int res; + size_t cur_token; + struct mail_flags * flags; + void * data; + size_t data_len; + + r = mail_cache_db_get(cache_db, keyname, strlen(keyname), &data, &data_len); + if (r != 0) { + res = MAIL_ERROR_CACHE_MISS; + goto err; + } + + r = mail_serialize_clear(mmapstr, &cur_token); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + if (mmap_string_append_len(mmapstr, data, data_len) == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + r = generic_flags_read(mmapstr, &cur_token, &flags); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + * result = flags; + + return MAIL_NO_ERROR; + + err: + return res; +} + +int generic_cache_flags_write(struct mail_cache_db * cache_db, + MMAPString * mmapstr, + char * keyname, struct mail_flags * flags) +{ + int r; + int res; + size_t cur_token; + + r = mail_serialize_clear(mmapstr, &cur_token); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + r = generic_flags_write(mmapstr, &cur_token, flags); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + r = mail_cache_db_put(cache_db, keyname, strlen(keyname), + mmapstr->str, mmapstr->len); + if (r != 0) { + res = MAIL_ERROR_FILE; + goto err; + } + + return MAIL_NO_ERROR; + + err: + return res; +} + + +int generic_cache_delete(struct mail_cache_db * cache_db, + char * keyname) +{ + int r; + int res; + + r = mail_cache_db_del(cache_db, keyname, strlen(keyname)); + if (r != 0) { + res = MAIL_ERROR_FILE; + goto err; + } + + return MAIL_NO_ERROR; + + err: + return res; +} -- cgit v0.9.0.2