+2003-10-21 [hoa] 0.9.6claws38
+
+ * src/Makefile.am
+ * src/carray.[ch] * NEW *
+ * src/chash.[ch] * NEW *
+ * src/folder.c
+ * src/maillock.[ch] * NEW *
+ * src/mailmbox.[ch] * NEW *
+ * src/mailmbox_folder.[ch] * NEW *
+ * src/mailmbox_parse.[ch] * NEW *
+ * src/mailmbox_types.[ch] * NEW *
+ implementation of mbox folder with unique message numbers
+
+ made use of libEtPan! implementation of mbox for lower-layer.
+
2003-10-20 [alfons] 0.9.6claws37
* src/noticeview.c
MICRO_VERSION=6
INTERFACE_AGE=0
BINARY_AGE=0
-EXTRA_VERSION=37
+EXTRA_VERSION=38
if test $EXTRA_VERSION -eq 0; then
VERSION=${MAJOR_VERSION}.${MINOR_VERSION}.${MICRO_VERSION}claws
else
addrquery.c \
addrselect.c \
alertpanel.c \
+ carray.c \
+ chash.c \
codeconv.c \
compose.c \
crash.c \
ldapserver.c \
ldaputil.c \
ldif.c \
+ maillock.c \
main.c \
mainwindow.c \
manual.c \
matcher_parser_lex.l \
matcher_parser_parse.y \
mbox.c \
- mbox_folder.c \
+ mailmbox_folder.c \
+ mailmbox.c \
+ mailmbox_parse.c \
+ mailmbox_types.c \
message_search.c \
messageview.c \
mh.c \
addrquery.h \
addrselect.h \
alertpanel.h \
+ carray.h \
+ chash.h \
codeconv.h \
compose.h \
crash.h \
ldapserver.h \
ldaputil.h \
ldif.h \
+ maillock.h \
main.h \
mainwindow.h \
manual.h \
matcher_parser.h \
matcher_parser_lex.h \
matcher_parser_parse.h \
- mbox_folder.h \
mbox.h \
+ mailmbox_folder.h \
+ mailmbox.h \
+ mailmbox_parse.h \
+ mailmbox_types.h \
message_search.h \
messageview.h \
mh.h \
--- /dev/null
+
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * carray - Implements simple dynamic pointer arrays
+ *
+ * Copyright (c) 1999-2000, Gaël Roualland <gael.roualland@iname.com>
+ * interface changes - 2002 - 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 REGENTS 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 REGENTS 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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "carray.h"
+
+carray * carray_new(uint32_t initsize) {
+ carray * array;
+
+ array = (carray *) malloc(sizeof(carray));
+ if (!array) return NULL;
+
+ array->len = 0;
+ array->max = initsize;
+ array->array = (void **) malloc(sizeof(void *) * initsize);
+ if (!array->array) {
+ free(array);
+ return NULL;
+ }
+ return array;
+}
+
+int carray_add(carray * array, void * data, uint32_t * index) {
+ int r;
+
+ r = carray_set_size(array, array->len + 1);
+ if (r < 0)
+ return r;
+
+ array->array[array->len - 1] = data;
+ if (index != NULL)
+ * index = array->len - 1;
+
+ return 0;
+}
+
+int carray_set_size(carray * array, uint32_t new_size)
+{
+ if (new_size > array->max) {
+ uint32_t n = array->max * 2;
+ void * new;
+
+ while (n <= new_size)
+ n *= 2;
+
+ new = (void **) realloc(array->array, sizeof(void *) * n);
+ if (!new)
+ return -1;
+ array->array = new;
+ array->max = n;
+ }
+ array->len = new_size;
+
+ return 0;
+}
+
+int carray_delete_fast(carray * array, uint32_t indx) {
+ if (indx >= array->len)
+ return -1;
+
+ array->array[indx] = NULL;
+
+ return 0;
+}
+
+int carray_delete(carray * array, uint32_t indx) {
+ if (indx >= array->len)
+ return -1;
+
+ if (indx != --array->len)
+ array->array[indx] = array->array[array->len];
+ return 0;
+}
+
+int carray_delete_slow(carray * array, uint32_t indx) {
+ if (indx >= array->len)
+ return -1;
+
+ if (indx != --array->len)
+ memmove(array->array + indx, array->array + indx + 1,
+ (array->len - indx) * sizeof(void *));
+ return 0;
+}
+
+#ifdef NO_MACROS
+void ** carray_data(carray * array) {
+ return array->array;
+}
+
+uint32_t carray_count(carray * array) {
+ return array->len;
+}
+
+void * carray_get(carray * array, uint32_t indx) {
+ return array->array[indx];
+}
+
+void carray_set(carray * array, uint32_t indx, void * value) {
+ array->array[indx] = value;
+}
+#endif
+
+void carray_free(carray * array) {
+ free(array->array);
+ free(array);
+}
--- /dev/null
+
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * carray - Implements simple dynamic pointer arrays
+ *
+ * Copyright (c) 1999-2000, Gaël Roualland <gael.roualland@iname.com>
+ * interface changes - 2002 - 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 REGENTS 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 REGENTS 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.
+ */
+
+#ifndef CARRAY_H
+#define CARRAY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <inttypes.h>
+
+struct carray_s {
+ void ** array;
+ uint32_t len;
+ uint32_t max;
+};
+
+typedef struct carray_s carray;
+
+/* Creates a new array of pointers, with initsize preallocated cells */
+carray * carray_new(uint32_t initsize);
+
+/* Adds the pointer to data in the array.
+ Returns the index of the pointer in the array or -1 on error */
+int carray_add(carray * array, void * data, uint32_t * index);
+
+int carray_set_size(carray * array, uint32_t new_size);
+
+/* Removes the cell at this index position. Returns TRUE on success.
+ Order of elements in the array IS changed. */
+int carray_delete(carray * array, uint32_t indx);
+
+/* Removes the cell at this index position. Returns TRUE on success.
+ Order of elements in the array IS not changed. */
+int carray_delete_slow(carray * array, uint32_t indx);
+
+/* remove without decreasing the size of the array */
+int carray_delete_fast(carray * array, uint32_t indx);
+
+/* Some of the following routines can be implemented as macros to
+ be faster. If you don't want it, define NO_MACROS */
+#ifdef NO_MACROS
+
+/* Returns the array itself */
+void ** carray_data(carray);
+
+/* Returns the number of elements in the array */
+int carray_count(carray);
+
+/* Returns the contents of one cell */
+void * carray_get(carray array, int indx);
+
+/* Sets the contents of one cell */
+void carray_set(carray array, int indx, void * value);
+
+#else
+#define carray_data(a) (a->array)
+#define carray_count(a) (a->len)
+#define carray_get(a, indx) (a->array[indx])
+#define carray_set(a, indx, v) do { a->array[indx]=v; } while(0)
+#endif
+
+void carray_free(carray * array);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * chash - Implements generic hash tables.
+ *
+ * Copyright (c) 1999-2000, Gaël Roualland <gael.roualland@iname.com>
+ * interface changes - 2002 - 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 REGENTS 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 REGENTS 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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "chash.h"
+
+/* This defines the maximum (average) number of entries per bucket.
+ The hash is resized everytime inserting an entry makes the
+ average go over that value. */
+#define CHASH_MAXDEPTH 3
+
+static inline unsigned int chash_func(const char * key, int len) {
+ register unsigned int c = 0, t;
+ register const char * k = key;
+
+ while (len--) {
+ c += (c << 4) + *k++;
+ if ((t = c & 0xF0000000)) {
+ c ^= t >> 24;
+ c ^= t;
+ }
+ }
+ return c;
+}
+
+static inline char * chash_dup(const char * data, int len)
+{
+ char * r;
+
+ r = (char *) malloc(len * sizeof(char));
+ if (!r)
+ return NULL;
+ memcpy(r, data, len * sizeof(char));
+ return r;
+}
+
+chash * chash_new(int size, int flags)
+{
+ chash * h;
+
+ h = (chash *) malloc(sizeof(chash));
+ if (h == NULL)
+ return NULL;
+
+ h->count = 0;
+ h->cells = (struct chashcell **) calloc(size, sizeof(struct chashcell *));
+ if (h->cells == NULL) {
+ free(h);
+ return NULL;
+ }
+ h->size = size;
+ h->copykey = flags & CHASH_COPYKEY;
+ h->copyvalue = flags & CHASH_COPYVALUE;
+
+ return h;
+}
+
+int chash_get(chash * hash,
+ chashdatum * key, chashdatum * result)
+{
+ unsigned int func;
+ chashiter * iter;
+
+ func = chash_func(key->data, key->len);
+
+ /* look for the key in existing cells */
+ iter = hash->cells[func % hash->size];
+ while (iter) {
+ if (iter->key.len == key->len && iter->func == func
+ && !memcmp(iter->key.data, key->data, key->len)) {
+ * result = iter->value; /* found */
+
+ return 0;
+ }
+ iter = iter->next;
+ }
+
+ return -1;
+}
+
+int chash_set(chash * hash,
+ chashdatum * key,
+ chashdatum * value,
+ chashdatum * oldvalue)
+{
+ unsigned int func, indx;
+ chashiter * iter, * cell;
+ int r;
+
+ if (hash->count > hash->size * CHASH_MAXDEPTH) {
+ r = chash_resize(hash, (hash->count / CHASH_MAXDEPTH) * 2 + 1);
+ if (r < 0)
+ goto err;
+ }
+
+ func = chash_func(key->data, key->len);
+ indx = func % hash->size;
+
+ /* look for the key in existing cells */
+ iter = hash->cells[indx];
+ while (iter) {
+ if (iter->key.len == key->len && iter->func == func
+ && !memcmp(iter->key.data, key->data, key->len)) {
+ /* found, replacing entry */
+ if (hash->copyvalue) {
+ char * data;
+
+ data = chash_dup(value->data, value->len);
+ if (data == NULL)
+ goto err;
+
+ free(iter->value.data);
+ iter->value.data = data;
+ iter->value.len = value->len;
+ } else {
+ if (oldvalue != NULL) {
+ oldvalue->data = iter->value.data;
+ oldvalue->len = iter->value.len;
+ }
+ iter->value.data = value->data;
+ iter->value.len = value->len;
+ }
+ if (!hash->copykey)
+ iter->key.data = key->data;
+
+ if (oldvalue != NULL) {
+ oldvalue->data = value->data;
+ oldvalue->len = value->len;
+ }
+
+ return 0;
+ }
+ iter = iter->next;
+ }
+
+ if (oldvalue != NULL) {
+ oldvalue->data = NULL;
+ oldvalue->len = 0;
+ }
+
+ /* not found, adding entry */
+ cell = (struct chashcell *) malloc(sizeof(struct chashcell));
+ if (cell == NULL)
+ goto err;
+
+ if (hash->copykey) {
+ cell->key.data = chash_dup(key->data, key->len);
+ if (cell->key.data == NULL)
+ goto free;
+ }
+ else
+ cell->key.data = key->data;
+
+ cell->key.len = key->len;
+ if (hash->copyvalue) {
+ cell->value.data = chash_dup(value->data, value->len);
+ if (cell->value.data == NULL)
+ goto free_key_data;
+ }
+ else
+ cell->value.data = value->data;
+
+ cell->value.len = value->len;
+ cell->func = func;
+ cell->next = hash->cells[indx];
+ hash->cells[indx] = cell;
+ hash->count++;
+
+ return 0;
+
+ free_key_data:
+ if (hash->copykey)
+ free(cell->key.data);
+ free:
+ free(cell);
+ err:
+ return -1;
+}
+
+int chash_delete(chash * hash, chashdatum * key, chashdatum * oldvalue)
+{
+ /* chashdatum result = { NULL, TRUE }; */
+ unsigned int func, indx;
+ chashiter * iter, * old;
+
+ /*
+ if (!keylen)
+ keylen = strlen(key) + 1;
+ */
+
+ func = chash_func(key->data, key->len);
+ indx = func % hash->size;
+
+ /* look for the key in existing cells */
+ old = NULL;
+ iter = hash->cells[indx];
+ while (iter) {
+ if (iter->key.len == key->len && iter->func == func
+ && !memcmp(iter->key.data, key->data, key->len)) {
+ /* found, deleting */
+ if (old)
+ old->next = iter->next;
+ else
+ hash->cells[indx] = iter->next;
+ if (hash->copykey)
+ free(iter->key.data);
+ if (hash->copyvalue)
+ free(iter->value.data);
+ else {
+ if (oldvalue != NULL) {
+ oldvalue->data = iter->value.data;
+ oldvalue->len = iter->value.len;
+ }
+ }
+ free(iter);
+ hash->count--;
+ return 0;
+ }
+ old = iter;
+ iter = iter->next;
+ }
+
+ return -1; /* not found */
+}
+
+void chash_free(chash * hash) {
+ int indx;
+ chashiter * iter, * next;
+
+ /* browse the hash table */
+ for(indx = 0; indx < hash->size; indx++) {
+ iter = hash->cells[indx];
+ while (iter) {
+ next = iter->next;
+ if (hash->copykey)
+ free(iter->key.data);
+ if (hash->copyvalue)
+ free(iter->value.data);
+ free(iter);
+ iter = next;
+ }
+ }
+ free(hash->cells);
+ free(hash);
+}
+
+void chash_clear(chash * hash) {
+ int indx;
+ chashiter * iter, * next;
+
+ /* browse the hash table */
+ for(indx = 0; indx < hash->size; indx++) {
+ iter = hash->cells[indx];
+ while (iter) {
+ next = iter->next;
+ if (hash->copykey)
+ free(iter->key.data);
+ if (hash->copyvalue)
+ free(iter->value.data);
+ free(iter);
+ iter = next;
+ }
+ }
+ memset(hash->cells, 0, hash->size * sizeof(* hash->cells));
+ hash->count = 0;
+}
+
+chashiter * chash_begin(chash * hash) {
+ chashiter * iter;
+ int indx = 0;
+
+ iter = hash->cells[0];
+ while(!iter) {
+ indx++;
+ if (indx >= hash->size)
+ return NULL;
+ iter = hash->cells[indx];
+ }
+ return iter;
+}
+
+chashiter * chash_next(chash * hash, chashiter * iter) {
+ int indx;
+
+ if (!iter)
+ return NULL;
+
+ indx = iter->func % hash->size;
+ iter = iter->next;
+
+ while(!iter) {
+ indx++;
+ if (indx >= hash->size)
+ return NULL;
+ iter = hash->cells[indx];
+ }
+ return iter;
+}
+
+int chash_resize(chash * hash, int size)
+{
+ struct chashcell ** cells;
+ int indx, nindx;
+ chashiter * iter, * next;
+
+ if (hash->size == size)
+ return 0;
+
+ cells = (struct chashcell **) calloc(size, sizeof(struct chashcell *));
+ if (!cells)
+ return -1;
+
+ /* browse initial hash and copy items in second hash */
+ for(indx = 0; indx < hash->size; indx++) {
+ iter = hash->cells[indx];
+ while (iter) {
+ next = iter->next;
+ nindx = iter->func % size;
+ iter->next = cells[nindx];
+ cells[nindx] = iter;
+ iter = next;
+ }
+ }
+ free(hash->cells);
+ hash->size = size;
+ hash->cells = cells;
+
+ return 0;
+}
+
+#ifdef NO_MACROS
+int chash_count(chash * hash) {
+ return hash->count;
+}
+
+int chash_size(chash * hash) {
+ return hash->size;
+}
+
+void chash_value(chashiter * iter, chashdatum * result) {
+ * result = iter->value;
+}
+
+void chash_key(chashiter * iter, chashdatum * result) {
+ * result = iter->key;
+}
+#endif
--- /dev/null
+
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * chash - Implements generic hash tables.
+ *
+ * Copyright (c) 1999-2000, Gaël Roualland <gael.roualland@iname.com>
+ * interface changes - 2002 - 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 REGENTS 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 REGENTS 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.
+ */
+
+#ifndef CHASH_H
+#define CHASH_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ char * data;
+ int len;
+} chashdatum;
+
+struct chash {
+ int size, count, copyvalue, copykey;
+ struct chashcell ** cells;
+};
+
+typedef struct chash chash;
+
+struct chashcell {
+ unsigned int func;
+ chashdatum key;
+ chashdatum value;
+ struct chashcell * next;
+};
+
+typedef struct chashcell chashiter;
+
+#define CHASH_COPYNONE 0
+#define CHASH_COPYKEY 1
+#define CHASH_COPYVALUE 2
+#define CHASH_COPYALL (CHASH_COPYKEY | CHASH_COPYVALUE)
+
+#define CHASH_DEFAULTSIZE 13
+
+/* Allocates a new (empty) hash using this initial size and the given flags,
+ specifying which data should be copied in the hash.
+ CHASH_COPYNONE : Keys/Values are not copied.
+ CHASH_COPYKEY : Keys are dupped and freed as needed in the hash.
+ CHASH_COPYVALUE : Values are dupped and freed as needed in the hash.
+ CHASH_COPYALL : Both keys and values are dupped in the hash.
+ */
+chash * chash_new(int size, int flags);
+
+/* Frees a hash */
+void chash_free(chash * hash);
+
+/* Removes all elements from a hash */
+void chash_clear(chash * hash);
+
+/* Adds an entry in the hash table.
+ Length can be 0 if key/value are strings.
+ If an entry already exists for this key, it is replaced, and its value
+ is returned. Otherwise, the data pointer will be NULL and the length
+ field be set to TRUE or FALSe to indicate success or failure. */
+int chash_set(chash * hash,
+ chashdatum * key,
+ chashdatum * value,
+ chashdatum * oldvalue);
+
+/* Retrieves the data associated to the key if it is found in the hash table.
+ The data pointer and the length will be NULL if not found*/
+int chash_get(chash * hash,
+ chashdatum * key, chashdatum * result);
+
+/* Removes the entry associated to this key if it is found in the hash table,
+ and returns its contents if not dupped (otherwise, pointer will be NULL
+ and len TRUE). If entry is not found both pointer and len will be NULL. */
+int chash_delete(chash * hash,
+ chashdatum * key,
+ chashdatum * oldvalue);
+
+/* Resizes the hash table to the passed size. */
+int chash_resize(chash * hash, int size);
+
+/* Returns an iterator to the first non-empty entry of the hash table */
+chashiter * chash_begin(chash * hash);
+
+/* Returns the next non-empty entry of the hash table */
+chashiter * chash_next(chash * hash, chashiter * iter);
+
+/* Some of the following routines can be implemented as macros to
+ be faster. If you don't want it, define NO_MACROS */
+#ifdef NO_MACROS
+/* Returns the size of the hash table */
+int chash_size(chash * hash);
+
+/* Returns the number of entries in the hash table */
+int chash_count(chash * hash);
+
+/* Returns the key part of the entry pointed by the iterator */
+void chash_key(chashiter * iter, chashdatum * result);
+
+/* Returns the value part of the entry pointed by the iterator */
+void chash_value(chashiter * iter, chashdatum * result);
+
+#else
+static inline int chash_size(chash * hash)
+{
+ return hash->size;
+}
+
+static inline int chash_count(chash * hash)
+{
+ return hash->count;
+}
+
+static inline void chash_key(chashiter * iter, chashdatum * result)
+{
+ * result = iter->key;
+}
+
+static inline void chash_value(chashiter * iter, chashdatum * result)
+{
+ * result = iter->value;
+}
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
#include "imap.h"
#include "news.h"
#include "mh.h"
-#include "mbox_folder.h"
+#include "mailmbox_folder.h"
#include "utils.h"
#include "xml.h"
#include "codeconv.h"
folder_register_class(mh_get_class());
folder_register_class(imap_get_class());
folder_register_class(news_get_class());
- folder_register_class(mbox_get_class());
+ folder_register_class(mailmbox_get_class());
}
GSList *folder_get_class_list(void)
--- /dev/null
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2002 - 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 REGENTS 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 REGENTS 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 "maillock.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <time.h>
+
+/* ********************************************************************** */
+
+/* lock primitives */
+
+/* the lock code is modified from the dot lock file code from mail.local.c */
+
+/*
+ SENDMAIL LICENSE
+
+The following license terms and conditions apply, unless a different
+license is obtained from Sendmail, Inc., 6425 Christie Ave, Fourth Floor,
+Emeryville, CA 94608, or by electronic mail at license@sendmail.com.
+
+License Terms:
+
+Use, Modification and Redistribution (including distribution of any
+modified or derived work) in source and binary forms is permitted only if
+each of the following conditions is met:
+
+1. Redistributions qualify as "freeware" or "Open Source Software" under
+ one of the following terms:
+
+ (a) Redistributions are made at no charge beyond the reasonable cost of
+ materials and delivery.
+
+ (b) Redistributions are accompanied by a copy of the Source Code or by an
+ irrevocable offer to provide a copy of the Source Code for up to three
+ years at the cost of materials and delivery. Such redistributions
+ must allow further use, modification, and redistribution of the Source
+ Code under substantially the same terms as this license. For the
+ purposes of redistribution "Source Code" means the complete compilable
+ and linkable source code of sendmail including all modifications.
+
+2. Redistributions of source code must retain the copyright notices as they
+ appear in each source code file, these license terms, and the
+ disclaimer/limitation of liability set forth as paragraph 6 below.
+
+3. Redistributions in binary form must reproduce the Copyright Notice,
+ these license terms, and the disclaimer/limitation of liability set
+ forth as paragraph 6 below, in the documentation and/or other materials
+ provided with the distribution. For the purposes of binary distribution
+ the "Copyright Notice" refers to the following language:
+ "Copyright (c) 1998-2002 Sendmail, Inc. All rights reserved."
+
+4. Neither the name of Sendmail, Inc. nor the University of California nor
+ the names of their contributors may be used to endorse or promote
+ products derived from this software without specific prior written
+ permission. The name "sendmail" is a trademark of Sendmail, Inc.
+
+5. All redistributions must comply with the conditions imposed by the
+ University of California on certain embedded code, whose copyright
+ notice and conditions for redistribution are as follows:
+
+ (a) Copyright (c) 1988, 1993 The Regents of the University of
+ California. All rights reserved.
+
+ (b) Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ (i) Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ (ii) 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.
+
+ (iii) Neither the name of the University nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+6. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY
+ SENDMAIL, INC. 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 SENDMAIL, INC., THE REGENTS OF THE UNIVERSITY OF
+ CALIFORNIA 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 DAMAGES.
+*/
+
+/*
+ TODO : lock, prefer fcntl() over flock()
+ AND use dotlock code above
+*/
+
+#define LOCKTO_RM 300 /* timeout for stale lockfile removal */
+#define LOCKTO_GLOB 400 /* global timeout for lockfile creation */
+
+static int lock_common(char * filename, int fd, short locktype)
+{
+ char lockfilename[PATH_MAX];
+ struct flock lock;
+ /* dot lock file */
+ int statfailed = 0;
+ time_t start;
+ int r;
+ int res;
+
+ lock.l_start = 0;
+ lock.l_len = 0;
+ lock.l_pid = getpid();
+ lock.l_type = locktype;
+ lock.l_whence = SEEK_SET;
+
+ r = fcntl(fd, F_SETLKW, &lock);
+ if (r < 0) {
+ /* WARNING POSIX lock could not be applied */
+ }
+
+ /* dot lock file */
+
+ if (strlen(filename) + 6 > PATH_MAX) {
+ res = -1;
+ goto unlock;
+ }
+
+ snprintf(lockfilename, PATH_MAX, "%s.lock", filename);
+
+ time(&start);
+ while (1) {
+ int fd;
+ struct stat st;
+ time_t now;
+
+ /* global timeout */
+ time(&now);
+ if (now > start + LOCKTO_GLOB) {
+ res = -1;
+ goto unlock;
+ }
+
+ fd = open(lockfilename, O_WRONLY|O_EXCL|O_CREAT, 0);
+ if (fd >= 0) {
+ /* defeat lock checking programs which test pid */
+ write(fd, "0", 2);
+ close(fd);
+ break;
+ }
+
+ if (stat(lockfilename, &st) < 0) {
+ if (statfailed++ > 5) {
+ res = -1;
+ goto unlock;
+ }
+ continue;
+ }
+ statfailed = 0;
+ time(&now);
+
+ if (now < st.st_ctime + LOCKTO_RM)
+ continue;
+
+ /* try to remove stale lockfile */
+ if (unlink(lockfilename) < 0) {
+ res = -1;
+ goto unlock;
+ }
+
+ sleep(5);
+ }
+
+ return 0;
+
+ unlock:
+ lock.l_start = 0;
+ lock.l_len = 0;
+ lock.l_pid = getpid();
+ lock.l_type = F_UNLCK;
+ lock.l_whence = SEEK_SET;
+
+ r = fcntl(fd, F_SETLK, &lock);
+ if (r < 0) {
+ /* WARNING POSIX lock could not be applied */
+ }
+ err:
+ return res;
+}
+
+static int unlock_common(char * filename, int fd)
+{
+ char lockfilename[PATH_MAX];
+ struct flock lock;
+ int r;
+
+ if (strlen(filename) + 6 > PATH_MAX)
+ return -1;
+
+ snprintf(lockfilename, PATH_MAX, "%s.lock", filename);
+
+ unlink(lockfilename);
+
+ lock.l_start = 0;
+ lock.l_len = 0;
+ lock.l_pid = getpid();
+ lock.l_type = F_UNLCK;
+ lock.l_whence = SEEK_SET;
+
+ r = fcntl(fd, F_SETLK, &lock);
+ if (r < 0) {
+ /* WARNING POSIX lock could not be applied */
+ }
+
+ return 0;
+}
+
+int maillock_read_lock(char * filename, int fd)
+{
+ return lock_common(filename, fd, F_RDLCK);
+}
+
+int maillock_read_unlock(char * filename, int fd)
+{
+ return unlock_common(filename, fd);
+}
+
+int maillock_write_lock(char * filename, int fd)
+{
+ return lock_common(filename, fd, F_WRLCK);
+}
+
+int maillock_write_unlock(char * filename, int fd)
+{
+ return unlock_common(filename, fd);
+}
--- /dev/null
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2002 - 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 REGENTS 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 REGENTS 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$
+ */
+
+#ifndef MAILLOCK_H
+
+#define MAILLOCK_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int maillock_read_lock(char * filename, int fd);
+int maillock_read_unlock(char * filename, int fd);
+int maillock_write_lock(char * filename, int fd);
+int maillock_write_unlock(char * filename, int fd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2002 - 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 REGENTS 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 REGENTS 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 "mailmbox.h"
+
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+
+#include "mailmbox_parse.h"
+#include "maillock.h"
+
+/*
+ http://www.qmail.org/qmail-manual-html/man5/mbox.html
+ RFC 2076
+*/
+
+#define TMPDIR "/tmp"
+
+/* mbox is a file with a corresponding filename */
+
+#define UID_HEADER "X-LibEtPan-UID:"
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+int mailmbox_write_lock(struct mailmbox_folder * folder)
+{
+ int r;
+
+ if (folder->read_only)
+ return MAILMBOX_ERROR_READONLY;
+
+ r = maillock_write_lock(folder->filename, folder->fd);
+ if (r == 0)
+ return MAILMBOX_NO_ERROR;
+ else
+ return MAILMBOX_ERROR_FILE;
+}
+
+int mailmbox_write_unlock(struct mailmbox_folder * folder)
+{
+ int r;
+
+ r = maillock_write_unlock(folder->filename, folder->fd);
+ if (r == 0)
+ return MAILMBOX_NO_ERROR;
+ else
+ return MAILMBOX_ERROR_FILE;
+}
+
+int mailmbox_read_lock(struct mailmbox_folder * folder)
+{
+ int r;
+
+ r = maillock_read_lock(folder->filename, folder->fd);
+ if (r == 0)
+ return MAILMBOX_NO_ERROR;
+ else
+ return MAILMBOX_ERROR_FILE;
+}
+
+int mailmbox_read_unlock(struct mailmbox_folder * folder)
+{
+ int r;
+
+ r = maillock_read_unlock(folder->filename, folder->fd);
+ if (r == 0)
+ return MAILMBOX_NO_ERROR;
+ else
+ return MAILMBOX_ERROR_FILE;
+}
+
+
+/*
+ map the file into memory.
+ the file must be locked.
+*/
+
+int mailmbox_map(struct mailmbox_folder * folder)
+{
+ char * str;
+ struct stat buf;
+ int res;
+ int r;
+
+ r = stat(folder->filename, &buf);
+ if (r < 0) {
+ res = MAILMBOX_ERROR_FILE;
+ goto err;
+ }
+
+ if (folder->read_only)
+ str = (char *) mmap(0, buf.st_size, PROT_READ,
+ MAP_PRIVATE, folder->fd, 0);
+ else
+ str = (char *) mmap(0, buf.st_size, PROT_READ | PROT_WRITE,
+ MAP_SHARED, folder->fd, 0);
+ if (str == MAP_FAILED) {
+ res = MAILMBOX_ERROR_FILE;
+ goto err;
+ }
+
+ folder->mapping = str;
+ folder->mapping_size = buf.st_size;
+
+ return MAILMBOX_NO_ERROR;
+
+ err:
+ return res;
+}
+
+/*
+ unmap the file
+*/
+
+void mailmbox_unmap(struct mailmbox_folder * folder)
+{
+ munmap(folder->mapping, folder->mapping_size);
+ folder->mapping = NULL;
+ folder->mapping_size = 0;
+}
+
+void mailmbox_sync(struct mailmbox_folder * folder)
+{
+ msync(folder->mapping, folder->mapping_size, MS_SYNC);
+}
+
+void mailmbox_timestamp(struct mailmbox_folder * folder)
+{
+ int r;
+ struct stat buf;
+
+ r = stat(folder->filename, &buf);
+ if (r < 0)
+ folder->mtime = (time_t) -1;
+ else
+ folder->mtime = buf.st_mtime;
+}
+
+/*
+ open the file
+*/
+
+int mailmbox_open(struct mailmbox_folder * folder)
+{
+ int fd;
+ int read_only;
+
+ if (!folder->read_only) {
+ read_only = FALSE;
+ fd = open(folder->filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
+ }
+
+ if (folder->read_only || (fd < 0)) {
+ read_only = TRUE;
+ fd = open(folder->filename, O_RDONLY);
+ if (fd < 0)
+ return MAILMBOX_ERROR_FILE_NOT_FOUND;
+ }
+
+ folder->fd = fd;
+ folder->read_only = read_only;
+
+ return MAILMBOX_NO_ERROR;
+}
+
+/*
+ close the file
+*/
+
+void mailmbox_close(struct mailmbox_folder * folder)
+{
+ close(folder->fd);
+ folder->fd = -1;
+}
+
+
+static int mailmbox_validate_lock(struct mailmbox_folder * folder,
+ int (* custom_lock)(struct mailmbox_folder *),
+ int (* custom_unlock)(struct mailmbox_folder *))
+{
+ struct stat buf;
+ int res;
+ int r;
+
+ r = stat(folder->filename, &buf);
+ if (r < 0) {
+ buf.st_mtime = (time_t) -1;
+ }
+
+ if ((buf.st_mtime != folder->mtime) ||
+ ((size_t) buf.st_size != folder->mapping_size)) {
+ int r;
+
+ mailmbox_unmap(folder);
+ mailmbox_close(folder);
+
+ r = mailmbox_open(folder);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = custom_lock(folder);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailmbox_map(folder);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto err_unlock;
+ }
+
+ r = mailmbox_parse(folder);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto err_unlock;
+ }
+
+ folder->mtime = buf.st_mtime;
+
+ return MAILMBOX_NO_ERROR;
+ }
+ else {
+ r = custom_lock(folder);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+ }
+
+ return MAILMBOX_NO_ERROR;
+
+ err_unlock:
+ custom_unlock(folder);
+ err:
+ return res;
+}
+
+
+int mailmbox_validate_write_lock(struct mailmbox_folder * folder)
+{
+ return mailmbox_validate_lock(folder,
+ mailmbox_write_lock,
+ mailmbox_write_unlock);
+}
+
+
+int mailmbox_validate_read_lock(struct mailmbox_folder * folder)
+{
+ return mailmbox_validate_lock(folder,
+ mailmbox_read_lock,
+ mailmbox_read_unlock);
+}
+
+
+/* ********************************************************************** */
+/* append messages */
+
+#define MAX_FROM_LINE_SIZE 256
+
+static inline size_t get_line(char * line, size_t length,
+ char ** pnext_line, size_t * pcount)
+{
+ size_t count;
+
+ count = 0;
+
+ while (1) {
+ if (length == 0)
+ break;
+
+ if (* line == '\r') {
+ line ++;
+
+ count ++;
+ length --;
+
+ if (* line == '\n') {
+ line ++;
+
+ count ++;
+ length --;
+
+ break;
+ }
+ }
+ else if (* line == '\n') {
+ line ++;
+
+ count ++;
+ length --;
+
+ break;
+ }
+ else {
+ line ++;
+ length --;
+ count ++;
+ }
+ }
+
+ * pnext_line = line;
+ * pcount = count;
+
+ return count;
+}
+
+/*
+ TODO : should strip \r\n if any
+ see also in write_fixed_line
+*/
+
+static inline size_t get_fixed_line_size(char * line, size_t length,
+ char ** pnext_line, size_t * pcount,
+ size_t * pfixed_count)
+{
+ size_t count;
+ char * next_line;
+ size_t fixed_count;
+
+ if (!get_line(line, length, &next_line, &count))
+ return 0;
+
+ fixed_count = count;
+ if (count >= 5) {
+ if (line[0] == 'F') {
+ if (strncmp(line, "From ", 5) == 0)
+ fixed_count ++;
+ }
+ }
+
+ * pnext_line = next_line;
+ * pcount = count;
+ * pfixed_count = fixed_count;
+
+ return count;
+}
+
+static size_t get_fixed_message_size(char * message, size_t size,
+ uint32_t uid, int force_no_uid)
+{
+ size_t fixed_size;
+ size_t cur_token;
+ size_t left;
+ char * next;
+ char * cur;
+ int end;
+ int r;
+ uint32_t tmp_uid;
+
+ cur_token = 0;
+
+ fixed_size = 0;
+
+ /* headers */
+
+ end = FALSE;
+ while (!end) {
+ size_t begin;
+ int ignore;
+
+ ignore = FALSE;
+ begin = cur_token;
+ if (cur_token + strlen(UID_HEADER) <= size) {
+ if (message[cur_token] == 'X') {
+ if (strncasecmp(message + cur_token, UID_HEADER,
+ strlen(UID_HEADER)) == 0) {
+ ignore = TRUE;
+ }
+ }
+ }
+
+ r = mailimf_ignore_field_parse(message, size, &cur_token);
+ switch (r) {
+ case MAILIMF_NO_ERROR:
+ if (!ignore)
+ fixed_size += cur_token - begin;
+ break;
+ case MAILIMF_ERROR_PARSE:
+ default:
+ end = TRUE;
+ break;
+ }
+ }
+
+ if (!force_no_uid) {
+ /* UID header */
+
+ fixed_size += strlen(UID_HEADER " \r\n");
+
+ tmp_uid = uid;
+ while (tmp_uid >= 10) {
+ tmp_uid /= 10;
+ fixed_size ++;
+ }
+ fixed_size ++;
+ }
+
+ /* body */
+
+ left = size - cur_token;
+ next = message + cur_token;
+ while (left > 0) {
+ size_t count;
+ size_t fixed_count;
+
+ cur = next;
+
+ if (!get_fixed_line_size(cur, left, &next, &count, &fixed_count))
+ break;
+
+ fixed_size += fixed_count;
+ left -= count;
+ }
+
+ return fixed_size;
+}
+
+static inline char * write_fixed_line(char * str,
+ char * line, size_t length,
+ char ** pnext_line, size_t * pcount)
+{
+ size_t count;
+ char * next_line;
+
+ if (!get_line(line, length, &next_line, &count))
+ return str;
+
+ if (count >= 5) {
+ if (line[0] == 'F') {
+ if (strncmp(line, "From ", 5) == 0) {
+ * str = '>';
+ str ++;
+ }
+ }
+ }
+
+ memcpy(str, line, count);
+
+ * pnext_line = next_line;
+ * pcount = count;
+ str += count;
+
+ return str;
+}
+
+static char * write_fixed_message(char * str,
+ char * message, size_t size,
+ uint32_t uid, int force_no_uid)
+{
+ size_t fixed_size;
+ size_t cur_token;
+ size_t left;
+ int end;
+ int r;
+ char * cur_src;
+ size_t numlen;
+
+ cur_token = 0;
+
+ fixed_size = 0;
+
+ /* headers */
+
+ end = FALSE;
+ while (!end) {
+ size_t begin;
+ int ignore;
+
+ ignore = FALSE;
+ begin = cur_token;
+ if (cur_token + strlen(UID_HEADER) <= size) {
+ if (message[cur_token] == 'X') {
+ if (strncasecmp(message + cur_token, UID_HEADER,
+ strlen(UID_HEADER)) == 0) {
+ ignore = TRUE;
+ }
+ }
+ }
+
+ r = mailimf_ignore_field_parse(message, size, &cur_token);
+ switch (r) {
+ case MAILIMF_NO_ERROR:
+ if (!ignore) {
+ memcpy(str, message + begin, cur_token - begin);
+ str += cur_token - begin;
+ }
+ break;
+ case MAILIMF_ERROR_PARSE:
+ default:
+ end = TRUE;
+ break;
+ }
+ }
+
+ if (!force_no_uid) {
+ /* UID header */
+
+ memcpy(str, UID_HEADER " ", strlen(UID_HEADER " "));
+ str += strlen(UID_HEADER " ");
+ numlen = snprintf(str, 20, "%i\r\n", uid);
+ str += numlen;
+ }
+
+ /* body */
+
+ cur_src = message + cur_token;
+ left = size - cur_token;
+ while (left > 0) {
+ size_t count;
+ char * next;
+
+ str = write_fixed_line(str, cur_src, left, &next, &count);
+
+ cur_src = next;
+ left -= count;
+ }
+
+ return str;
+}
+
+#define DEFAULT_FROM_LINE "From - Wed Jun 30 21:49:08 1993\n"
+
+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;
+ uint32_t i;
+ size_t from_size;
+ size_t maxuid;
+ size_t left;
+ size_t crlf_count;
+
+ if (folder->read_only) {
+ res = MAILMBOX_ERROR_READONLY;
+ goto err;
+ }
+
+ date = time(NULL);
+ from_size = strlen(DEFAULT_FROM_LINE);
+ if (localtime_r(&date, &time_info) != NULL)
+ from_size = strftime(from_line, MAX_FROM_LINE_SIZE, "From - %c\n", &time_info);
+
+ maxuid = /* */ folder->max_uid;
+
+ extra_size = 0;
+ for(i = 0 ; i < append_tab->len ; i ++) {
+ struct mailmbox_append_info * info;
+
+ info = carray_get(append_tab, i);
+ extra_size += from_size;
+ extra_size += get_fixed_message_size(info->message, info->size,
+ folder->max_uid + i + 1,
+ folder->no_uid);
+ extra_size += 2; /* CR LF */
+ }
+
+ left = folder->mapping_size;
+ crlf_count = 0;
+ while (left >= 1) {
+ if (folder->mapping[left - 1] == '\n') {
+ crlf_count ++;
+ left --;
+ }
+ else if (folder->mapping[left - 1] == '\r') {
+ left --;
+ }
+ else
+ break;
+
+ if (crlf_count == 2)
+ break;
+ }
+
+ old_size = folder->mapping_size;
+ mailmbox_unmap(folder);
+
+ if (old_size != 0) {
+ if (crlf_count != 2)
+ extra_size += (2 - crlf_count) * 2;
+ }
+
+ r = ftruncate(folder->fd, extra_size + old_size);
+ if (r < 0) {
+ mailmbox_map(folder);
+ res = MAILMBOX_ERROR_FILE;
+ goto err;
+ }
+
+ r = mailmbox_map(folder);
+ if (r < 0) {
+ ftruncate(folder->fd, old_size);
+ return MAILMBOX_ERROR_FILE;
+ }
+
+ str = folder->mapping + old_size;
+
+ if (old_size != 0) {
+ for(i = 0 ; i < 2 - crlf_count ; i ++) {
+ * str = '\r';
+ str ++;
+ * str = '\n';
+ str ++;
+ }
+ }
+
+ for(i = 0 ; i < append_tab->len ; 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->message, info->size,
+ folder->max_uid + i + 1,
+ folder->no_uid);
+
+ * str = '\r';
+ str ++;
+ * str = '\n';
+ str ++;
+ }
+
+ folder->max_uid += append_tab->len;
+
+ return MAILMBOX_NO_ERROR;
+
+ err:
+ return res;
+}
+
+int
+mailmbox_append_message_list(struct mailmbox_folder * folder,
+ carray * append_tab)
+{
+ int r;
+ int res;
+ size_t cur_token;
+
+ r = mailmbox_validate_write_lock(folder);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailmbox_expunge_no_lock(folder);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto unlock;
+ }
+
+ cur_token = folder->mapping_size;
+
+ r = mailmbox_append_message_list_no_lock(folder, append_tab);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto unlock;
+ }
+
+ mailmbox_sync(folder);
+
+ r = mailmbox_parse_additionnal(folder, &cur_token);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto unlock;
+ }
+
+ mailmbox_timestamp(folder);
+
+ mailmbox_write_unlock(folder);
+
+ return MAILMBOX_NO_ERROR;
+
+ unlock:
+ mailmbox_write_unlock(folder);
+ err:
+ return res;
+}
+
+int
+mailmbox_append_message(struct mailmbox_folder * folder,
+ char * data, size_t len)
+{
+ carray * tab;
+ struct mailmbox_append_info * append_info;
+ int res;
+ int r;
+
+ tab = carray_new(1);
+ if (tab == NULL) {
+ res = MAILMBOX_ERROR_MEMORY;
+ goto err;
+ }
+
+ append_info = mailmbox_append_info_new(data, len);
+ if (append_info == NULL) {
+ res = MAILMBOX_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ r = carray_add(tab, append_info, NULL);
+ if (r < 0) {
+ res = MAILMBOX_ERROR_MEMORY;
+ goto free_append_info;
+ }
+
+ r = mailmbox_append_message_list(folder, tab);
+
+ mailmbox_append_info_free(append_info);
+ carray_free(tab);
+
+ return r;
+
+ free_append_info:
+ mailmbox_append_info_free(append_info);
+ free_list:
+ carray_free(tab);
+ err:
+ return res;
+}
+
+/* ********************************************************************** */
+
+int mailmbox_fetch_msg_no_lock(struct mailmbox_folder * folder,
+ uint32_t num, char ** result,
+ size_t * result_len)
+{
+ struct mailmbox_msg_info * info;
+ int res;
+ chashdatum key;
+ chashdatum data;
+ int r;
+
+ key.data = (char *) #
+ key.len = sizeof(num);
+
+ r = chash_get(folder->hash, &key, &data);
+ if (r < 0) {
+ res = MAILMBOX_ERROR_MSG_NOT_FOUND;
+ goto err;
+ }
+
+ info = (struct mailmbox_msg_info *) data.data;
+
+ if (info->deleted) {
+ res = MAILMBOX_ERROR_MSG_NOT_FOUND;
+ goto err;
+ }
+
+ * result = folder->mapping + info->headers;
+ * result_len = info->size - info->start_len;
+
+ return MAILMBOX_NO_ERROR;
+
+ err:
+ return res;
+}
+
+int mailmbox_fetch_msg_headers_no_lock(struct mailmbox_folder * folder,
+ uint32_t num, char ** result,
+ size_t * result_len)
+{
+ struct mailmbox_msg_info * info;
+ int res;
+ chashdatum key;
+ chashdatum data;
+ int r;
+
+ key.data = (char *) #
+ key.len = sizeof(num);
+
+ r = chash_get(folder->hash, &key, &data);
+ if (r < 0) {
+ res = MAILMBOX_ERROR_MSG_NOT_FOUND;
+ goto err;
+ }
+
+ info = (struct mailmbox_msg_info *) data.data;
+
+ if (info->deleted) {
+ res = MAILMBOX_ERROR_MSG_NOT_FOUND;
+ goto err;
+ }
+
+ * result = folder->mapping + info->headers;
+ * result_len = info->headers_len;
+
+ return MAILMBOX_NO_ERROR;
+
+ err:
+ return res;
+}
+
+int mailmbox_fetch_msg(struct mailmbox_folder * folder,
+ uint32_t num, char ** result,
+ size_t * result_len)
+{
+ int res;
+ char * data;
+ size_t len;
+ int r;
+ size_t fixed_size;
+ char * end;
+ char * new_data;
+
+ r = mailmbox_validate_read_lock(folder);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailmbox_fetch_msg_no_lock(folder, num, &data, &len);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto unlock;
+ }
+
+ /* size with no uid */
+ fixed_size = get_fixed_message_size(data, len, 0, 1 /* force no uid */);
+
+ new_data = malloc(fixed_size + 1);
+ if (new_data == NULL) {
+ res = MAILMBOX_ERROR_MEMORY;
+ goto unlock;
+ }
+
+ end = write_fixed_message(new_data, data, len, 0, 1 /* force no uid */);
+ * end = '\0';
+
+ * result = new_data;
+ * result_len = fixed_size;
+
+ mailmbox_read_unlock(folder);
+
+ return MAILMBOX_NO_ERROR;
+
+ unlock:
+ mailmbox_read_unlock(folder);
+ err:
+ return res;
+}
+
+int mailmbox_fetch_msg_headers(struct mailmbox_folder * folder,
+ uint32_t num, char ** result,
+ size_t * result_len)
+{
+ int res;
+ char * data;
+ size_t len;
+ int r;
+ size_t fixed_size;
+ char * end;
+ char * new_data;
+
+ r = mailmbox_validate_read_lock(folder);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailmbox_fetch_msg_headers_no_lock(folder, num, &data, &len);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto unlock;
+ }
+
+ /* size with no uid */
+ fixed_size = get_fixed_message_size(data, len, 0, 1 /* force no uid */);
+
+ new_data = malloc(fixed_size + 1);
+ if (new_data == NULL) {
+ res = MAILMBOX_ERROR_MEMORY;
+ goto unlock;
+ }
+
+ end = write_fixed_message(new_data, data, len, 0, 1 /* force no uid */);
+ * end = '\0';
+
+ * result = new_data;
+ * result_len = fixed_size;
+
+ mailmbox_read_unlock(folder);
+
+ return MAILMBOX_NO_ERROR;
+
+ unlock:
+ mailmbox_read_unlock(folder);
+ err:
+ return res;
+}
+
+void mailmbox_fetch_result_free(char * msg)
+{
+ free(msg);
+}
+
+
+int mailmbox_copy_msg_list(struct mailmbox_folder * dest_folder,
+ struct mailmbox_folder * src_folder,
+ carray * tab)
+{
+ int r;
+ int res;
+ carray * append_tab;
+ uint32_t i;
+
+ r = mailmbox_validate_read_lock(src_folder);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ append_tab = carray_new(tab->len);
+ if (append_tab == NULL) {
+ res = MAILMBOX_ERROR_MEMORY;
+ goto src_unlock;
+ }
+
+ for(i = 0 ; i < tab->len ; 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 < append_tab->len ; 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 < append_tab->len ; 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;
+}
+
+int mailmbox_copy_msg(struct mailmbox_folder * dest_folder,
+ struct mailmbox_folder * src_folder,
+ uint32_t uid)
+{
+ carray * tab;
+ int res;
+ uint32_t * puid;
+ int r;
+
+ tab = carray_new(1);
+ if (tab == NULL) {
+ res = MAILMBOX_ERROR_MEMORY;
+ goto err;
+ }
+
+ puid = malloc(sizeof(* puid));
+ if (puid == NULL) {
+ res = MAILMBOX_ERROR_MEMORY;
+ goto free_array;
+ }
+ * puid = uid;
+
+ r = mailmbox_copy_msg_list(dest_folder, src_folder, tab);
+ res = r;
+
+ free(puid);
+ free_array:
+ carray_free(tab);
+ err:
+ 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;
+ unsigned long i;
+ size_t cur_offset;
+ char * dest;
+ size_t size;
+
+ size = 0;
+ for(i = 0 ; i < folder->tab->len ; i ++) {
+ struct mailmbox_msg_info * info;
+
+ info = carray_get(folder->tab, i);
+
+ if (!info->deleted) {
+ size += info->size + info->padding;
+
+ if (!folder->no_uid) {
+ if (!info->written_uid) {
+ uint32_t uid;
+
+ size += strlen(UID_HEADER " \r\n");
+
+ uid = info->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 == MAP_FAILED) {
+ res = MAILMBOX_ERROR_FILE;
+ goto err;
+ }
+
+ cur_offset = 0;
+ for(i = 0 ; i < folder->tab->len ; i ++) {
+ struct mailmbox_msg_info * info;
+
+ info = carray_get(folder->tab, i);
+
+ if (!info->deleted) {
+ memcpy(dest + cur_offset, folder->mapping + info->start,
+ info->headers_len + info->start_len);
+ cur_offset += info->headers_len + info->start_len;
+
+ if (!folder->no_uid) {
+ if (!info->written_uid) {
+ size_t numlen;
+
+ memcpy(dest + cur_offset, UID_HEADER " ", strlen(UID_HEADER " "));
+ cur_offset += strlen(UID_HEADER " ");
+ numlen = snprintf(dest + cur_offset, size - cur_offset,
+ "%i\r\n", info->uid);
+ cur_offset += numlen;
+ }
+ }
+
+ memcpy(dest + cur_offset,
+ folder->mapping + info->headers + info->headers_len,
+ info->size - (info->start_len + info->headers_len)
+ + info->padding);
+
+ cur_offset += info->size - (info->start_len + info->headers_len)
+ + info->padding;
+ }
+ }
+ fflush(stdout);
+
+ munmap(dest, size);
+
+ * result_size = size;
+
+ return MAILMBOX_NO_ERROR;
+
+ err:
+ return res;
+}
+
+int mailmbox_expunge_no_lock(struct mailmbox_folder * folder)
+{
+ char tmpfile[PATH_MAX];
+ int r;
+ int res;
+ int dest_fd;
+ size_t size;
+
+ if (folder->read_only)
+ return MAILMBOX_ERROR_READONLY;
+
+ if (((folder->written_uid >= folder->max_uid) || folder->no_uid) &&
+ (!folder->changed)) {
+ /* no need to expunge */
+ return MAILMBOX_NO_ERROR;
+ }
+
+ snprintf(tmpfile, PATH_MAX, "%sXXXXXX", folder->filename);
+ dest_fd = mkstemp(tmpfile);
+
+ if (dest_fd < 0) {
+ res = MAILMBOX_ERROR_FILE;
+ goto unlink;
+ }
+
+ r = mailmbox_expunge_to_file_no_lock(tmpfile, dest_fd,
+ folder, &size);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto unlink;
+ }
+
+ close(dest_fd);
+
+ r = rename(tmpfile, folder->filename);
+ if (r < 0) {
+ res = r;
+ goto err;
+ }
+
+ mailmbox_unmap(folder);
+ mailmbox_close(folder);
+
+ r = mailmbox_open(folder);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailmbox_map(folder);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailmbox_parse(folder);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ mailmbox_timestamp(folder);
+
+ folder->changed = FALSE;
+ folder->deleted_count = 0;
+
+ return MAILMBOX_NO_ERROR;
+
+ unlink:
+ close(dest_fd);
+ unlink(tmpfile);
+ err:
+ return res;
+}
+
+int mailmbox_expunge(struct mailmbox_folder * folder)
+{
+ int r;
+ int res;
+
+ r = mailmbox_validate_write_lock(folder);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailmbox_expunge_no_lock(folder);
+ res = r;
+
+ mailmbox_write_unlock(folder);
+ err:
+ return res;
+}
+
+int mailmbox_delete_msg(struct mailmbox_folder * folder, uint32_t uid)
+{
+ struct mailmbox_msg_info * info;
+ int res;
+ chashdatum key;
+ chashdatum data;
+ int r;
+
+ if (folder->read_only) {
+ res = MAILMBOX_ERROR_READONLY;
+ goto err;
+ }
+
+ key.data = (char *) &uid;
+ key.len = sizeof(uid);
+
+ r = chash_get(folder->hash, &key, &data);
+ if (r < 0) {
+ res = MAILMBOX_ERROR_MSG_NOT_FOUND;
+ goto err;
+ }
+
+ info = (struct mailmbox_msg_info *) data.data;
+
+ if (info->deleted) {
+ res = MAILMBOX_ERROR_MSG_NOT_FOUND;
+ goto err;
+ }
+
+ info->deleted = TRUE;
+ folder->changed = TRUE;
+ folder->deleted_count ++;
+
+ return MAILMBOX_NO_ERROR;
+
+ err:
+ return res;
+}
+
+
+/*
+ INIT of MBOX
+
+ - open file
+ - map the file
+
+ - lock the file
+
+ - parse memory
+
+ - unlock the file
+*/
+
+int mailmbox_init(char * filename,
+ int force_readonly,
+ int force_no_uid,
+ uint32_t default_written_uid,
+ struct mailmbox_folder ** result_folder)
+{
+ struct mailmbox_folder * folder;
+ int r;
+ int res;
+
+ folder = mailmbox_folder_new(filename);
+ if (folder == NULL) {
+ res = MAILMBOX_ERROR_MEMORY;
+ goto err;
+ }
+ folder->no_uid = force_no_uid;
+ folder->read_only = force_readonly;
+ folder->written_uid = default_written_uid;
+
+ folder->changed = FALSE;
+ folder->deleted_count = 0;
+
+ r = mailmbox_open(folder);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+
+ r = mailmbox_map(folder);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto close;
+ }
+
+ r = mailmbox_validate_read_lock(folder);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto unmap;
+ }
+
+ mailmbox_read_unlock(folder);
+
+ * result_folder = folder;
+
+ return MAILMBOX_NO_ERROR;
+
+ unmap:
+ mailmbox_unmap(folder);
+ close:
+ mailmbox_close(folder);
+ free:
+ mailmbox_folder_free(folder);
+ err:
+ return res;
+}
+
+
+/*
+ when MBOX is DONE
+
+ - check for changes
+
+ - unmap the file
+ - close file
+*/
+
+void mailmbox_done(struct mailmbox_folder * folder)
+{
+ if (!folder->read_only)
+ mailmbox_expunge(folder);
+
+ mailmbox_unmap(folder);
+ mailmbox_close(folder);
+
+ mailmbox_folder_free(folder);
+}
--- /dev/null
+#ifndef MAILMBOX_H
+
+#define MAILMBOX_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "mailmbox_types.h"
+
+int
+mailmbox_append_message_list(struct mailmbox_folder * folder,
+ carray * append_tab);
+
+int
+mailmbox_append_message(struct mailmbox_folder * folder,
+ char * data, size_t len);
+
+int mailmbox_fetch_msg(struct mailmbox_folder * folder,
+ uint32_t num, char ** result,
+ size_t * result_len);
+
+int mailmbox_fetch_msg_headers(struct mailmbox_folder * folder,
+ uint32_t num, char ** result,
+ size_t * result_len);
+
+void mailmbox_fetch_result_free(char * msg);
+
+int mailmbox_copy_msg_list(struct mailmbox_folder * dest_folder,
+ struct mailmbox_folder * src_folder,
+ carray * tab);
+
+int mailmbox_copy_msg(struct mailmbox_folder * dest_folder,
+ struct mailmbox_folder * src_folder,
+ uint32_t uid);
+
+int mailmbox_expunge(struct mailmbox_folder * folder);
+
+int mailmbox_delete_msg(struct mailmbox_folder * folder, uint32_t uid);
+
+int mailmbox_init(char * filename,
+ int force_readonly,
+ int force_no_uid,
+ uint32_t default_written_uid,
+ struct mailmbox_folder ** result_folder);
+
+void mailmbox_done(struct mailmbox_folder * folder);
+
+/* low-level access primitives */
+
+int mailmbox_write_lock(struct mailmbox_folder * folder);
+
+int mailmbox_write_unlock(struct mailmbox_folder * folder);
+
+int mailmbox_read_lock(struct mailmbox_folder * folder);
+
+int mailmbox_read_unlock(struct mailmbox_folder * folder);
+
+
+/* memory map */
+
+int mailmbox_map(struct mailmbox_folder * folder);
+
+void mailmbox_unmap(struct mailmbox_folder * folder);
+
+void mailmbox_sync(struct mailmbox_folder * folder);
+
+
+/* open & close file */
+
+int mailmbox_open(struct mailmbox_folder * folder);
+
+void mailmbox_close(struct mailmbox_folder * folder);
+
+
+/* validate cache */
+
+#if 0
+int mailmbox_validate_cache(struct mailmbox_folder * folder);
+#endif
+
+int mailmbox_validate_write_lock(struct mailmbox_folder * folder);
+
+int mailmbox_validate_read_lock(struct mailmbox_folder * folder);
+
+
+/* fetch message */
+
+int mailmbox_fetch_msg_no_lock(struct mailmbox_folder * folder,
+ uint32_t num, char ** result,
+ size_t * result_len);
+
+int mailmbox_fetch_msg_headers_no_lock(struct mailmbox_folder * folder,
+ uint32_t num, char ** result,
+ size_t * result_len);
+
+/* append message */
+
+int
+mailmbox_append_message_list_no_lock(struct mailmbox_folder * folder,
+ carray * append_tab);
+
+int mailmbox_expunge_no_lock(struct mailmbox_folder * folder);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2003 Hiroyuki Yamamoto
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "defs.h"
+
+#include <glib.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+#undef MEASURE_TIME
+
+#ifdef MEASURE_TIME
+# include <sys/time.h>
+#endif
+
+#include "intl.h"
+#include "folder.h"
+#include "procmsg.h"
+#include "procheader.h"
+#include "utils.h"
+#include "mailmbox.h"
+#include "mailmbox_folder.h"
+#include "mailmbox_parse.h"
+
+static Folder *s_mailmbox_folder_new(const gchar *name, const gchar *path);
+
+static void mailmbox_folder_destroy(Folder *folder);
+
+static FolderItem *mailmbox_folder_item_new(Folder *folder);
+
+static void mailmbox_folder_item_destroy(Folder *folder, FolderItem *_item);
+
+static gchar *mailmbox_item_get_path(Folder *folder, FolderItem *item);
+
+static gint mailmbox_get_num_list(Folder *folder, FolderItem *item,
+ GSList **list, gboolean *old_uids_valid);
+
+static MsgInfo *mailmbox_get_msginfo(Folder *folder,
+ FolderItem *item, gint num);
+
+static GSList *mailmbox_get_msginfos(Folder *folder, FolderItem *item,
+ GSList *msgnum_list);
+
+static gchar *s_mailmbox_fetch_msg(Folder *folder, FolderItem *item, gint num);
+
+static gint mailmbox_add_msg(Folder *folder, FolderItem *dest,
+ const gchar *file, MsgFlags *flags);
+
+static gint mailmbox_add_msgs(Folder *folder, FolderItem *dest,
+ GSList *file_list,
+ GRelation *relation);
+
+static gint s_mailmbox_copy_msg(Folder *folder,
+ FolderItem *dest, MsgInfo *msginfo);
+
+static gint mailmbox_copy_msgs(Folder *folder, FolderItem *dest,
+ MsgInfoList *msglist, GRelation *relation);
+
+static gint mailmbox_remove_msg(Folder *folder, FolderItem *item, gint num);
+
+static gint mailmbox_remove_all_msg(Folder *folder, FolderItem *item);
+
+static FolderItem *mailmbox_create_folder(Folder *folder, FolderItem *parent,
+ const gchar *name);
+
+static gboolean mailmbox_scan_required(Folder *folder, FolderItem *_item);
+
+static gint mailmbox_rename_folder(Folder *folder,
+ FolderItem *item, const gchar *name);
+
+static gint mailmbox_remove_folder(Folder *folder, FolderItem *item);
+
+static gint mailmbox_create_tree(Folder *folder);
+
+static FolderClass mailmbox_class =
+{
+ F_MBOX,
+ "mbox",
+ "MBOX",
+
+ /* Folder functions */
+ s_mailmbox_folder_new,
+ mailmbox_folder_destroy,
+ NULL, /* mailmbox_scan_tree, */
+ mailmbox_create_tree,
+
+ /* FolderItem functions */
+ mailmbox_folder_item_new,
+ mailmbox_folder_item_destroy,
+ mailmbox_item_get_path,
+ mailmbox_create_folder,
+ mailmbox_rename_folder,
+ mailmbox_remove_folder,
+ NULL,
+ mailmbox_get_num_list,
+ NULL,
+ NULL,
+ NULL,
+ mailmbox_scan_required,
+
+ /* Message functions */
+ mailmbox_get_msginfo,
+ mailmbox_get_msginfos,
+ s_mailmbox_fetch_msg,
+ mailmbox_add_msg,
+ mailmbox_add_msgs,
+ s_mailmbox_copy_msg,
+ mailmbox_copy_msgs,
+ mailmbox_remove_msg,
+ mailmbox_remove_all_msg,
+ NULL,
+ NULL,
+};
+
+FolderClass *mailmbox_get_class(void)
+{
+ return &mailmbox_class;
+}
+
+
+static void mailmbox_folder_init(Folder *folder,
+ const gchar *name, const gchar *path)
+{
+ folder_local_folder_init(folder, name, path);
+}
+
+static Folder *s_mailmbox_folder_new(const gchar *name, const gchar *path)
+{
+ Folder *folder;
+
+ folder = (Folder *)g_new0(MBOXFolder, 1);
+ folder->klass = &mailmbox_class;
+ mailmbox_folder_init(folder, name, path);
+
+ return folder;
+}
+
+static void mailmbox_folder_destroy(Folder *folder)
+{
+ folder_local_folder_destroy(LOCAL_FOLDER(folder));
+}
+
+typedef struct _MBOXFolderItem MBOXFolderItem;
+struct _MBOXFolderItem
+{
+ FolderItem item;
+ uint32_t old_max_uid;
+ struct mailmbox_folder * mbox;
+};
+
+static FolderItem *mailmbox_folder_item_new(Folder *folder)
+{
+ MBOXFolderItem *item;
+
+ item = g_new0(MBOXFolderItem, 1);
+ item->mbox = NULL;
+ item->old_max_uid = 0;
+
+ return (FolderItem *)item;
+}
+
+#define MAX_UID_FILE "max-uid"
+
+void read_max_uid_value(FolderItem *item, uint32_t * pmax_uid)
+{
+ gchar * path;
+ gchar * file;
+ FILE * f;
+ uint32_t max_uid;
+ size_t r;
+
+ path = folder_item_get_path(item);
+ file = g_strconcat(path, G_DIR_SEPARATOR_S, MAX_UID_FILE, NULL);
+ g_free(path);
+
+ f = fopen(file, "r");
+ g_free(file);
+ if (f == NULL)
+ return;
+ r = fread(&max_uid, sizeof(max_uid), 1, f);
+ if (r == 0) {
+ fclose(f);
+ return;
+ }
+
+ fclose(f);
+
+ * pmax_uid = max_uid;
+}
+
+void write_max_uid_value(FolderItem *item, uint32_t max_uid)
+{
+ gchar * path;
+ gchar * file;
+ FILE * f;
+ size_t r;
+
+ path = folder_item_get_path(item);
+ file = g_strconcat(path, G_DIR_SEPARATOR_S, MAX_UID_FILE, NULL);
+ g_free(path);
+
+ f = fopen(file, "w");
+ g_free(file);
+ if (f == NULL)
+ return;
+ r = fwrite(&max_uid, sizeof(max_uid), 1, f);
+ if (r == 0) {
+ fclose(f);
+ return;
+ }
+
+ fclose(f);
+}
+
+static void mailmbox_folder_item_destroy(Folder *folder, FolderItem *_item)
+{
+ MBOXFolderItem *item = (MBOXFolderItem *)_item;
+
+ g_return_if_fail(item != NULL);
+
+ if (item->mbox != NULL) {
+ write_max_uid_value(_item, item->mbox->written_uid);
+ mailmbox_done(item->mbox);
+ }
+ g_free(_item);
+}
+
+static void mailmbox_folder_create_parent(const gchar * path)
+{
+ if (!is_file_exist(path)) {
+ gchar * new_path;
+
+ new_path = g_dirname(path);
+ if (new_path[strlen(new_path) - 1] == G_DIR_SEPARATOR)
+ new_path[strlen(new_path) - 1] = '\0';
+
+ if (!is_dir_exist(new_path))
+ make_dir_hier(new_path);
+ g_free(new_path);
+
+ }
+}
+
+static gchar * mailmbox_folder_get_path(Folder *folder, FolderItem *item)
+{
+ gchar *folder_path;
+ gchar *path;
+
+ g_return_val_if_fail(item != NULL, NULL);
+
+ if (item->path && item->path[0] == G_DIR_SEPARATOR) {
+ mailmbox_folder_create_parent(item->path);
+ return g_strdup(item->path);
+ }
+
+ folder_path = g_strdup(LOCAL_FOLDER(item->folder)->rootpath);
+ g_return_val_if_fail(folder_path != NULL, NULL);
+
+ if (folder_path[0] == G_DIR_SEPARATOR) {
+ if (item->path) {
+ path = g_strconcat(folder_path, G_DIR_SEPARATOR_S,
+ item->path, NULL);
+ }
+ else
+ path = g_strdup(folder_path);
+ } else {
+ if (item->path)
+ path = g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S,
+ folder_path, G_DIR_SEPARATOR_S,
+ item->path, NULL);
+ else
+ path = g_strconcat(get_home_dir(), G_DIR_SEPARATOR_S,
+ folder_path, NULL);
+ }
+
+ g_free(folder_path);
+
+ mailmbox_folder_create_parent(path);
+
+ return path;
+}
+
+static int mailmbox_item_sync(FolderItem *_item, int validate_uid)
+{
+ MBOXFolderItem *item = (MBOXFolderItem *)_item;
+ int r;
+
+ if (item->mbox == NULL) {
+ uint32_t written_uid;
+ gchar * path;
+
+ written_uid = 0;
+ read_max_uid_value(_item, &written_uid);
+ path = mailmbox_folder_get_path(_item->folder, _item);
+ r = mailmbox_init(path, 0, 0, written_uid, &item->mbox);
+ g_free(path);
+ if (r != MAILMBOX_NO_ERROR)
+ return -1;
+ }
+
+ if (!validate_uid) {
+ r = mailmbox_validate_read_lock(item->mbox);
+ if (r != MAILMBOX_NO_ERROR) {
+ goto err;
+ }
+
+ mailmbox_read_unlock(item->mbox);
+ }
+ else {
+ r = mailmbox_validate_write_lock(item->mbox);
+ if (r != MAILMBOX_NO_ERROR) {
+ goto err;
+ }
+
+ if (item->mbox->written_uid < item->mbox->max_uid) {
+ r = mailmbox_expunge_no_lock(item->mbox);
+ if (r != MAILMBOX_NO_ERROR)
+ goto unlock;
+ }
+ mailmbox_write_unlock(item->mbox);
+ }
+
+ return 0;
+
+ unlock:
+ mailmbox_write_unlock(item->mbox);
+ err:
+ return -1;
+}
+
+static struct mailmbox_folder * get_mbox(FolderItem *_item, int validate_uid)
+{
+ MBOXFolderItem *item = (MBOXFolderItem *)_item;
+
+ mailmbox_item_sync(_item, validate_uid);
+
+ return item->mbox;
+}
+
+static gint mailmbox_get_num_list(Folder *folder, FolderItem *item,
+ GSList **list, gboolean *old_uids_valid)
+{
+ gint nummsgs = 0;
+ uint32_t i;
+ struct mailmbox_folder * mbox;
+
+ g_return_val_if_fail(item != NULL, -1);
+
+ debug_print("mbox_get_last_num(): Scanning %s ...\n", item->path);
+
+ *old_uids_valid = TRUE;
+
+ mbox = get_mbox(item, 1);
+ if (mbox == NULL)
+ return -1;
+
+ for(i = 0 ; i < carray_count(mbox->tab) ; i ++) {
+ struct mailmbox_msg_info * msg;
+
+ msg = carray_get(mbox->tab, i);
+ if (msg != NULL) {
+ *list = g_slist_prepend(*list,
+ GINT_TO_POINTER(msg->uid));
+ nummsgs ++;
+ }
+ }
+
+ return nummsgs;
+}
+
+static gchar *s_mailmbox_fetch_msg(Folder *folder, FolderItem *item, gint num)
+{
+ gchar *path;
+ gchar *file;
+ int r;
+ struct mailmbox_folder * mbox;
+ char * data;
+ size_t len;
+ FILE * f;
+ mode_t old_mask;
+
+ g_return_val_if_fail(item != NULL, NULL);
+ g_return_val_if_fail(num > 0, NULL);
+
+ mbox = get_mbox(item, 0);
+ if (mbox == NULL)
+ return NULL;
+
+ path = folder_item_get_path(item);
+ file = g_strconcat(path, G_DIR_SEPARATOR_S, itos(num), NULL);
+ g_free(path);
+ if (is_file_exist(file)) {
+ return file;
+ }
+
+ r = mailmbox_fetch_msg(mbox, num, &data, &len);
+ if (r != MAILMBOX_NO_ERROR)
+ goto free;
+
+ fprintf(stderr, file);
+ old_mask = umask(0077);
+ f = fopen(file, "w");
+ umask(old_mask);
+ if (f == NULL)
+ goto free_data;
+
+ r = fwrite(data, 1, len, f);
+ if (r == 0)
+ goto close;
+
+ fclose(f);
+ free(data);
+
+ return file;
+
+ close:
+ fclose(f);
+ unlink(file);
+ free_data:
+ free(data);
+ free:
+ free(file);
+ err:
+ return NULL;
+}
+
+static MsgInfo *mailmbox_parse_msg(uint32_t uid,
+ char * data, size_t len, FolderItem *item)
+{
+ MsgInfo *msginfo;
+ MsgFlags flags;
+
+ flags.perm_flags = MSG_NEW|MSG_UNREAD;
+ flags.tmp_flags = 0;
+
+ g_return_val_if_fail(item != NULL, NULL);
+ g_return_val_if_fail(data != NULL, NULL);
+
+ if (item->stype == F_QUEUE) {
+ MSG_SET_TMP_FLAGS(flags, MSG_QUEUED);
+ } else if (item->stype == F_DRAFT) {
+ MSG_SET_TMP_FLAGS(flags, MSG_DRAFT);
+ }
+
+ msginfo = procheader_parse_str(data, flags, FALSE, FALSE);
+ if (!msginfo) return NULL;
+
+ msginfo->msgnum = uid;
+ msginfo->folder = item;
+
+ return msginfo;
+}
+
+static MsgInfo *mailmbox_get_msginfo(Folder *folder,
+ FolderItem *item, gint num)
+{
+ MsgInfo *msginfo;
+ int r;
+ char * data;
+ size_t len;
+ struct mailmbox_folder * mbox;
+
+ g_return_val_if_fail(item != NULL, NULL);
+ g_return_val_if_fail(num > 0, NULL);
+
+ mbox = get_mbox(item, 0);
+ if (mbox == NULL)
+ goto err;
+
+ r = mailmbox_validate_read_lock(mbox);
+ if (r != MAILMBOX_NO_ERROR)
+ goto err;
+
+ r = mailmbox_fetch_msg_headers_no_lock(mbox, num, &data, &len);
+ if (r != MAILMBOX_NO_ERROR)
+ goto unlock;
+
+ msginfo = mailmbox_parse_msg(num, data, len, item);
+ if (!msginfo)
+ goto unlock;
+
+ msginfo->msgnum = num;
+
+ mailmbox_read_unlock(mbox);
+
+ return msginfo;
+
+ unlock:
+ mailmbox_read_unlock(mbox);
+ err:
+ return NULL;
+}
+
+static GSList *mailmbox_get_msginfos(Folder *folder, FolderItem *item,
+ GSList *msgnum_list)
+{
+ int r;
+ GSList * cur;
+ GSList * ret;
+ struct mailmbox_folder * mbox;
+
+ g_return_val_if_fail(item != NULL, NULL);
+
+ mbox = get_mbox(item, 0);
+ if (mbox == NULL)
+ goto err;
+
+ r = mailmbox_validate_read_lock(mbox);
+ if (r != MAILMBOX_NO_ERROR)
+ goto err;
+
+ ret = NULL;
+
+ for (cur = msgnum_list ; cur != NULL ; cur = g_slist_next(cur)) {
+ char * data;
+ size_t len;
+ gint num;
+ MsgInfo *msginfo;
+
+ num = GPOINTER_TO_INT(cur->data);
+
+ r = mailmbox_fetch_msg_headers_no_lock(mbox, num, &data, &len);
+ if (r != MAILMBOX_NO_ERROR)
+ continue;
+
+ msginfo = mailmbox_parse_msg(num, data, len, item);
+ if (!msginfo)
+ continue;
+
+ msginfo->msgnum = num;
+
+ ret = g_slist_append(ret, msginfo);
+ }
+
+ mailmbox_read_unlock(mbox);
+
+ return ret;
+
+ unlock:
+ mailmbox_read_unlock(mbox);
+ err:
+ return NULL;
+}
+
+/* ok */
+
+static gint mailmbox_add_msg(Folder *folder, FolderItem *dest,
+ const gchar *file, MsgFlags *flags)
+{
+ gint ret;
+ GSList file_list;
+ MsgFileInfo fileinfo;
+
+ g_return_val_if_fail(file != NULL, -1);
+
+ fileinfo.msginfo = NULL;
+ fileinfo.file = (gchar *)file;
+ fileinfo.flags = flags;
+ file_list.data = &fileinfo;
+ file_list.next = NULL;
+
+ ret = mailmbox_add_msgs(folder, dest, &file_list, NULL);
+ return ret;
+}
+
+/* ok */
+
+static gint mailmbox_add_msgs(Folder *folder, FolderItem *dest,
+ GSList *file_list,
+ GRelation *relation)
+{
+ gchar *destfile;
+ GSList *cur;
+ gint last_num;
+ struct mailmbox_folder * mbox;
+ carray * append_list;
+ struct mailmbox_append_info append_info;
+ int r;
+
+ g_return_val_if_fail(dest != NULL, -1);
+ g_return_val_if_fail(file_list != NULL, -1);
+
+ mbox = get_mbox(dest, 0);
+ if (mbox == NULL)
+ return -1;
+
+ r = mailmbox_validate_write_lock(mbox);
+ if (r != MAILMBOX_NO_ERROR)
+ return -1;
+
+ r = mailmbox_expunge_no_lock(mbox);
+ if (r != MAILMBOX_NO_ERROR)
+ goto unlock;
+
+ last_num = -1;
+
+ append_list = carray_new(1);
+ if (append_list == NULL)
+ goto unlock;
+
+ r = carray_set_size(append_list, 1);
+ if (r < 0)
+ goto free;
+
+ carray_set(append_list, 0, &append_info);
+
+ for (cur = file_list; cur != NULL; cur = cur->next) {
+ int fd;
+ struct stat stat_info;
+ char * data;
+ size_t len;
+ struct mailmbox_msg_info * msg;
+ size_t cur_token;
+ MsgFileInfo *fileinfo;
+
+ fileinfo = (MsgFileInfo *)cur->data;
+
+ fd = open(fileinfo->file, O_RDONLY);
+ if (fd == -1)
+ goto err;
+
+ r = fstat(fd, &stat_info);
+ if (r < 0)
+ goto close;
+
+ len = stat_info.st_size;
+ data = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (data == MAP_FAILED)
+ goto close;
+
+ append_info.message = data;
+ append_info.size = len;
+
+ cur_token = mbox->mapping_size;
+
+ r = mailmbox_append_message_list_no_lock(mbox, append_list);
+ if (r != MAILMBOX_NO_ERROR)
+ goto unmap;
+
+ munmap(data, len);
+ close(fd);
+
+ mailmbox_sync(mbox);
+
+ r = mailmbox_parse_additionnal(mbox, &cur_token);
+ if (r != MAILMBOX_NO_ERROR)
+ goto unlock;
+
+ msg = carray_get(mbox->tab, carray_count(mbox->tab) - 1);
+
+ if (relation != NULL)
+ g_relation_insert(relation, fileinfo,
+ GINT_TO_POINTER(msg->uid));
+
+ last_num = msg->uid;
+
+ continue;
+
+ unmap:
+ munmap(data, len);
+ close:
+ close(fd);
+ err:
+ continue;
+ }
+
+ carray_free(append_list);
+ mailmbox_write_unlock(mbox);
+
+ return last_num;
+
+ free:
+ carray_free(append_list);
+ unlock:
+ mailmbox_write_unlock(mbox);
+return -1;
+}
+
+static gint s_mailmbox_copy_msg(Folder *folder,
+ FolderItem *dest, MsgInfo *msginfo)
+{
+ GSList msglist;
+
+ g_return_val_if_fail(msginfo != NULL, -1);
+
+ msglist.data = msginfo;
+ msglist.next = NULL;
+
+ return mailmbox_copy_msgs(folder, dest, &msglist, NULL);
+}
+
+static gint mailmbox_copy_msgs(Folder *folder, FolderItem *dest,
+ MsgInfoList *msglist, GRelation *relation)
+{
+ MsgInfo *msginfo;
+ GSList *file_list;
+ gint ret;
+
+ g_return_val_if_fail(folder != NULL, -1);
+ g_return_val_if_fail(dest != NULL, -1);
+ g_return_val_if_fail(msglist != NULL, -1);
+
+ msginfo = (MsgInfo *)msglist->data;
+ g_return_val_if_fail(msginfo->folder != NULL, -1);
+
+ file_list = procmsg_get_message_file_list(msglist);
+ g_return_val_if_fail(file_list != NULL, -1);
+
+ ret = mailmbox_add_msgs(folder, dest, file_list, relation);
+
+ procmsg_message_file_list_free(file_list);
+
+ return ret;
+}
+
+
+static gint mailmbox_remove_msg(Folder *folder, FolderItem *item, gint num)
+{
+ struct mailmbox_folder * mbox;
+ int r;
+
+ g_return_val_if_fail(item != NULL, -1);
+
+ mbox = get_mbox(item, 0);
+ if (mbox == NULL)
+ return -1;
+
+ r = mailmbox_delete_msg(mbox, num);
+ if (r != MAILMBOX_NO_ERROR)
+ return -1;
+
+ return 0;
+}
+
+static gint mailmbox_remove_all_msg(Folder *folder, FolderItem *item)
+{
+ struct mailmbox_folder * mbox;
+ int r;
+ uint32_t i;
+
+ g_return_val_if_fail(item != NULL, -1);
+
+ mbox = get_mbox(item, 0);
+ if (mbox == NULL)
+ return -1;
+
+ for(i = 0 ; i < carray_count(mbox->tab) ; i ++) {
+ struct mailmbox_msg_info * msg;
+
+ msg = carray_get(mbox->tab, i);
+ if (msg == NULL)
+ continue;
+
+ r = mailmbox_delete_msg(mbox, msg->uid);
+ if (r != MAILMBOX_NO_ERROR)
+ continue;
+ }
+
+ return 0;
+}
+
+
+static gchar * mailmbox_get_new_path(FolderItem * parent, gchar * name)
+{
+ gchar * path;
+
+ if (strchr(name, G_DIR_SEPARATOR) == NULL) {
+ if (parent->path != NULL)
+ path = g_strconcat(parent->path, ".sbd", G_DIR_SEPARATOR_S, name, NULL);
+ else
+ path = g_strdup(name);
+ }
+ else
+ path = g_strdup(name);
+
+ return path;
+}
+
+static gchar * mailmbox_get_folderitem_name(gchar * name)
+{
+ gchar * foldername;
+
+ foldername = g_strdup(g_basename(name));
+
+ return foldername;
+}
+
+static FolderItem *mailmbox_create_folder(Folder *folder, FolderItem *parent,
+ const gchar *name)
+{
+ gchar * path;
+ FolderItem *new_item;
+ gchar * foldername;
+
+ g_return_val_if_fail(folder != NULL, NULL);
+ g_return_val_if_fail(parent != NULL, NULL);
+ g_return_val_if_fail(name != NULL, NULL);
+
+ path = mailmbox_get_new_path(parent, (gchar *) name);
+
+ foldername = mailmbox_get_folderitem_name((gchar *) name);
+
+ new_item = folder_item_new(folder, foldername, path);
+ folder_item_append(parent, new_item);
+
+ if (!strcmp(name, "inbox")) {
+ new_item->stype = F_INBOX;
+ new_item->folder->inbox = new_item;
+ } else if (!strcmp(name, "outbox")) {
+ new_item->stype = F_OUTBOX;
+ new_item->folder->outbox = new_item;
+ } else if (!strcmp(name, "draft")) {
+ new_item->stype = F_DRAFT;
+ new_item->folder->draft = new_item;
+ } else if (!strcmp(name, "queue")) {
+ new_item->stype = F_QUEUE;
+ new_item->folder->queue = new_item;
+ } else if (!strcmp(name, "trash")) {
+ new_item->stype = F_TRASH;
+ new_item->folder->trash = new_item;
+ }
+
+ g_free(foldername);
+ g_free(path);
+
+ return new_item;
+}
+
+
+
+static gboolean mailmbox_scan_required(Folder *folder, FolderItem *_item)
+{
+ struct mailmbox_folder * mbox;
+ MBOXFolderItem *item = (MBOXFolderItem *)_item;
+ int scan_required;
+
+ g_return_val_if_fail(folder != NULL, FALSE);
+ g_return_val_if_fail(item != NULL, FALSE);
+
+ if (item->item.path == NULL)
+ return FALSE;
+
+ mbox = get_mbox(_item, 0);
+ if (mbox == NULL)
+ return FALSE;
+
+ scan_required = (item->old_max_uid != item->mbox->max_uid);
+
+ item->old_max_uid = item->mbox->max_uid;
+
+ return scan_required;
+}
+
+
+static gint mailmbox_rename_folder(Folder *folder,
+ FolderItem *item, const gchar *name)
+{
+ gchar * path;
+ gchar * foldername;
+
+ g_return_val_if_fail(folder != NULL, -1);
+ g_return_val_if_fail(item != NULL, -1);
+ g_return_val_if_fail(item->path != NULL, -1);
+ g_return_val_if_fail(name != NULL, -1);
+
+ path = mailmbox_get_new_path(item->parent, (gchar *) name);
+ foldername = mailmbox_get_folderitem_name((gchar *) name);
+
+ if (rename(item->path, path) == -1) {
+ g_free(foldername);
+ g_free(path);
+ g_warning("Cannot rename folder item");
+
+ return -1;
+ }
+ else {
+ g_free(item->name);
+ g_free(item->path);
+ item->path = path;
+ item->name = foldername;
+
+ return 0;
+ }
+}
+
+static gint mailmbox_remove_folder(Folder *folder, FolderItem *item)
+{
+ g_return_val_if_fail(folder != NULL, -1);
+ g_return_val_if_fail(item != NULL, -1);
+ g_return_val_if_fail(item->path != NULL, -1);
+
+ folder_item_remove(item);
+ return 0;
+}
+
+#define MAKE_DIR_IF_NOT_EXIST(dir) \
+{ \
+ if (!is_dir_exist(dir)) { \
+ if (is_file_exist(dir)) { \
+ g_warning("File `%s' already exists.\n" \
+ "Can't create folder.", dir); \
+ return -1; \
+ } \
+ if (mkdir(dir, S_IRWXU) < 0) { \
+ FILE_OP_ERROR(dir, "mkdir"); \
+ return -1; \
+ } \
+ if (chmod(dir, S_IRWXU) < 0) \
+ FILE_OP_ERROR(dir, "chmod"); \
+ } \
+}
+
+static gint mailmbox_create_tree(Folder *folder)
+{
+ gchar *rootpath;
+
+ g_return_val_if_fail(folder != NULL, -1);
+
+ CHDIR_RETURN_VAL_IF_FAIL(get_home_dir(), -1);
+ rootpath = LOCAL_FOLDER(folder)->rootpath;
+ MAKE_DIR_IF_NOT_EXIST(rootpath);
+ CHDIR_RETURN_VAL_IF_FAIL(rootpath, -1);
+
+ return 0;
+}
+
+#undef MAKE_DIR_IF_NOT_EXIST
+
+
+static char * quote_mailbox(char * mb)
+{
+ char path[PATH_MAX];
+ char * str;
+ size_t remaining;
+ char * p;
+
+ remaining = sizeof(path) - 1;
+ p = path;
+
+ while (* mb != 0) {
+ char hex[3];
+
+ if (((* mb >= 'a') && (* mb <= 'z')) ||
+ ((* mb >= 'A') && (* mb <= 'Z')) ||
+ ((* mb >= '0') && (* mb <= '9'))) {
+ if (remaining < 1)
+ return NULL;
+ * p = * mb;
+ p ++;
+ remaining --;
+ }
+ else {
+ if (remaining < 3)
+ return NULL;
+ * p = '%';
+ p ++;
+ snprintf(p, 3, "%02x", (unsigned char) (* mb));
+ p += 2;
+ }
+ mb ++;
+ }
+
+ * p = 0;
+
+ str = strdup(path);
+ if (str == NULL)
+ return NULL;
+
+ return str;
+}
+
+static gchar *mailmbox_item_get_path(Folder *folder, FolderItem *item)
+{
+ gchar *itempath, *path;
+ gchar * folderpath;
+
+ if (item->path == NULL)
+ return NULL;
+
+ if (folder->name == NULL)
+ return NULL;
+
+ folderpath = quote_mailbox(folder->name);
+ if (folderpath == NULL)
+ return NULL;
+ itempath = quote_mailbox(item->path);
+ if (itempath == NULL) {
+ free(folderpath);
+ return NULL;
+ }
+ path = g_strconcat(get_mbox_cache_dir(),
+ G_DIR_SEPARATOR_S, folderpath,
+ G_DIR_SEPARATOR_S, itempath, NULL);
+ free(itempath);
+ free(folderpath);
+
+ return path;
+}
--- /dev/null
+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 1999-2003 Hiroyuki Yamamoto
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __MAILMBOX_FOLDER_H__
+#define __MAILMBOX_FOLDER_H__
+
+#include <glib.h>
+
+#include "folder.h"
+
+typedef struct _MBOXFolder MBOXFolder;
+
+#define MBOX_FOLDER(obj) ((MBOXFolder *)obj)
+
+struct _MBOXFolder
+{
+ LocalFolder lfolder;
+};
+
+FolderClass *mailmbox_get_class (void);
+
+#endif /* __MH_H__ */
--- /dev/null
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2002 - 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 REGENTS 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 REGENTS 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 "mailmbox_parse.h"
+
+#include "mailmbox.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define UID_HEADER "X-LibEtPan-UID:"
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+enum {
+ UNSTRUCTURED_START,
+ UNSTRUCTURED_CR,
+ UNSTRUCTURED_LF,
+ UNSTRUCTURED_WSP,
+ UNSTRUCTURED_OUT
+};
+
+/* begin extracted from imf/mailimf.c */
+
+static int mailimf_char_parse(char * message, size_t length,
+ size_t * index, char token)
+{
+ size_t cur_token;
+
+ cur_token = * index;
+
+ if (cur_token >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ if (message[cur_token] == token) {
+ cur_token ++;
+ * index = cur_token;
+ return MAILIMF_NO_ERROR;
+ }
+ else
+ return MAILIMF_ERROR_PARSE;
+}
+
+int mailimf_crlf_parse(char * message, size_t length, size_t * index)
+{
+ size_t cur_token;
+ int r;
+
+ cur_token = * index;
+
+ r = mailimf_char_parse(message, length, &cur_token, '\r');
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE))
+ return r;
+
+ r = mailimf_char_parse(message, length, &cur_token, '\n');
+ if (r != MAILIMF_NO_ERROR)
+ return r;
+
+ * index = cur_token;
+ return MAILIMF_NO_ERROR;
+}
+
+
+int mailimf_ignore_field_parse(char * message, size_t length,
+ size_t * index)
+{
+ int has_field;
+ size_t cur_token;
+ int state;
+ size_t terminal;
+
+ has_field = FALSE;
+ cur_token = * index;
+
+ terminal = cur_token;
+ state = UNSTRUCTURED_START;
+
+ /* check if this is not a beginning CRLF */
+
+ if (cur_token >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ switch (message[cur_token]) {
+ case '\r':
+ return MAILIMF_ERROR_PARSE;
+ case '\n':
+ return MAILIMF_ERROR_PARSE;
+ }
+
+ while (state != UNSTRUCTURED_OUT) {
+
+ switch(state) {
+ case UNSTRUCTURED_START:
+ if (cur_token >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ switch(message[cur_token]) {
+ case '\r':
+ state = UNSTRUCTURED_CR;
+ break;
+ case '\n':
+ state = UNSTRUCTURED_LF;
+ break;
+ case ':':
+ has_field = TRUE;
+ state = UNSTRUCTURED_START;
+ break;
+ default:
+ state = UNSTRUCTURED_START;
+ break;
+ }
+ break;
+ case UNSTRUCTURED_CR:
+ if (cur_token >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ switch(message[cur_token]) {
+ case '\n':
+ state = UNSTRUCTURED_LF;
+ break;
+ case ':':
+ has_field = TRUE;
+ state = UNSTRUCTURED_START;
+ break;
+ default:
+ state = UNSTRUCTURED_START;
+ break;
+ }
+ break;
+ case UNSTRUCTURED_LF:
+ if (cur_token >= length) {
+ terminal = cur_token;
+ state = UNSTRUCTURED_OUT;
+ break;
+ }
+
+ switch(message[cur_token]) {
+ case '\t':
+ case ' ':
+ state = UNSTRUCTURED_WSP;
+ break;
+ default:
+ terminal = cur_token;
+ state = UNSTRUCTURED_OUT;
+ break;
+ }
+ break;
+ case UNSTRUCTURED_WSP:
+ if (cur_token >= length)
+ return MAILIMF_ERROR_PARSE;
+
+ switch(message[cur_token]) {
+ case '\r':
+ state = UNSTRUCTURED_CR;
+ break;
+ case '\n':
+ state = UNSTRUCTURED_LF;
+ break;
+ case ':':
+ has_field = TRUE;
+ state = UNSTRUCTURED_START;
+ break;
+ default:
+ state = UNSTRUCTURED_START;
+ break;
+ }
+ break;
+ }
+
+ cur_token ++;
+ }
+
+ if (!has_field)
+ return MAILIMF_ERROR_PARSE;
+
+ * index = terminal;
+
+ return MAILIMF_NO_ERROR;
+}
+
+/* end - extracted from imf/mailimf.c */
+
+static inline int
+mailmbox_fields_parse(char * str, size_t length,
+ size_t * index,
+ uint32_t * puid,
+ size_t * phlen)
+{
+ size_t cur_token;
+ int r;
+ size_t hlen;
+ size_t uid;
+ int end;
+
+ cur_token = * index;
+
+ end = FALSE;
+ uid = 0;
+ while (!end) {
+ size_t begin;
+
+ begin = cur_token;
+
+ r = mailimf_ignore_field_parse(str, length, &cur_token);
+ switch (r) {
+ case MAILIMF_NO_ERROR:
+ if (str[begin] == 'X') {
+
+ if (strncasecmp(str + begin, UID_HEADER, strlen(UID_HEADER)) == 0) {
+ begin += strlen(UID_HEADER);
+
+ while (str[begin] == ' ')
+ begin ++;
+
+ uid = strtoul(str + begin, NULL, 10);
+ }
+ }
+
+ break;
+ case MAILIMF_ERROR_PARSE:
+ default:
+ end = TRUE;
+ break;
+ }
+ }
+
+ hlen = cur_token - * index;
+
+ * phlen = hlen;
+ * puid = uid;
+ * index = cur_token;
+
+ return MAILMBOX_NO_ERROR;
+}
+
+enum {
+ IN_MAIL,
+ FIRST_CR,
+ FIRST_LF,
+ SECOND_CR,
+ SECOND_LF,
+ PARSING_F,
+ PARSING_R,
+ PARSING_O,
+ PARSING_M,
+ OUT_MAIL
+};
+
+
+
+
+static inline int
+mailmbox_single_parse(char * str, size_t length,
+ size_t * index,
+ size_t * pstart,
+ size_t * pstart_len,
+ size_t * pheaders,
+ size_t * pheaders_len,
+ size_t * pbody,
+ size_t * pbody_len,
+ size_t * psize,
+ size_t * ppadding,
+ uint32_t * puid)
+{
+ size_t cur_token;
+ size_t start;
+ size_t start_len;
+ size_t headers;
+ size_t headers_len;
+ size_t body;
+ size_t end;
+ size_t next;
+ size_t message_length;
+ uint32_t uid;
+ int r;
+#if 0
+ int in_mail_data;
+#endif
+#if 0
+ size_t begin;
+#endif
+
+ int state;
+
+ cur_token = * index;
+
+ if (cur_token >= length)
+ return MAILMBOX_ERROR_PARSE;
+
+ start = cur_token;
+ start_len = 0;
+ headers = cur_token;
+
+ if (cur_token + 5 < length) {
+ if (strncmp(str + cur_token, "From ", 5) == 0) {
+ cur_token += 5;
+ while (str[cur_token] != '\n') {
+ cur_token ++;
+ if (cur_token >= length)
+ break;
+ }
+ if (cur_token < length) {
+ cur_token ++;
+ headers = cur_token;
+ start_len = headers - start;
+ }
+ }
+ }
+
+ next = length;
+
+ r = mailmbox_fields_parse(str, length, &cur_token,
+ &uid, &headers_len);
+ if (r != MAILMBOX_NO_ERROR)
+ return r;
+
+ /* save position */
+#if 0
+ begin = cur_token;
+#endif
+
+ mailimf_crlf_parse(str, length, &cur_token);
+
+#if 0
+ if (str[cur_token] == 'F') {
+ printf("start !\n");
+ printf("%50.50s\n", str + cur_token);
+ getchar();
+ }
+#endif
+
+ body = cur_token;
+
+ /* restore position */
+ /* cur_token = begin; */
+
+ state = FIRST_LF;
+
+ end = length;
+
+#if 0
+ in_mail_data = 0;
+#endif
+ while (state != OUT_MAIL) {
+
+ if (cur_token >= length) {
+ if (state == IN_MAIL)
+ end = length;
+ next = length;
+ break;
+ }
+
+ switch(state) {
+ case IN_MAIL:
+ switch(str[cur_token]) {
+ case '\r':
+ state = FIRST_CR;
+ break;
+ case '\n':
+ state = FIRST_LF;
+ break;
+ case 'F':
+ if (cur_token == body) {
+ end = cur_token;
+ next = cur_token;
+ state = PARSING_F;
+ }
+ break;
+#if 0
+ default:
+ in_mail_data = 1;
+ break;
+#endif
+ }
+ break;
+
+ case FIRST_CR:
+ end = cur_token;
+ switch(str[cur_token]) {
+ case '\r':
+ state = SECOND_CR;
+ break;
+ case '\n':
+ state = FIRST_LF;
+ break;
+ default:
+ state = IN_MAIL;
+#if 0
+ in_mail_data = 1;
+#endif
+ break;
+ }
+ break;
+
+ case FIRST_LF:
+ end = cur_token;
+ switch(str[cur_token]) {
+ case '\r':
+ state = SECOND_CR;
+ break;
+ case '\n':
+ state = SECOND_LF;
+ break;
+ default:
+ state = IN_MAIL;
+#if 0
+ in_mail_data = 1;
+#endif
+ break;
+ }
+ break;
+
+ case SECOND_CR:
+ switch(str[cur_token]) {
+ case '\r':
+ end = cur_token;
+ break;
+ case '\n':
+ state = SECOND_LF;
+ break;
+ case 'F':
+ next = cur_token;
+ state = PARSING_F;
+ break;
+ default:
+ state = IN_MAIL;
+#if 0
+ in_mail_data = 1;
+#endif
+ break;
+ }
+ break;
+
+ case SECOND_LF:
+ switch(str[cur_token]) {
+ case '\r':
+ state = SECOND_CR;
+ break;
+ case '\n':
+ end = cur_token;
+ break;
+ case 'F':
+ next = cur_token;
+ state = PARSING_F;
+ break;
+ default:
+ state = IN_MAIL;
+#if 0
+ in_mail_data = 1;
+#endif
+ break;
+ }
+ break;
+
+ case PARSING_F:
+ switch(str[cur_token]) {
+ case 'r':
+ state = PARSING_R;
+ break;
+ default:
+ state = IN_MAIL;
+#if 0
+ in_mail_data = 1;
+#endif
+ break;
+ }
+ break;
+
+ case PARSING_R:
+ switch(str[cur_token]) {
+ case 'o':
+ state = PARSING_O;
+ break;
+ default:
+ state = IN_MAIL;
+#if 0
+ in_mail_data = 1;
+#endif
+ break;
+ }
+ break;
+
+ case PARSING_O:
+ switch(str[cur_token]) {
+ case 'm':
+ state = PARSING_M;
+ break;
+ default:
+ state = IN_MAIL;
+#if 0
+ in_mail_data = 1;
+#endif
+ break;
+ }
+ break;
+
+ case PARSING_M:
+ switch(str[cur_token]) {
+ case ' ':
+ state = OUT_MAIL;
+ break;
+ default:
+ state = IN_MAIL;
+ break;
+ }
+ break;
+ }
+
+ cur_token ++;
+ }
+
+ message_length = end - start;
+
+ * pstart = start;
+ * pstart_len = start_len;
+ * pheaders = headers;
+ * pheaders_len = headers_len;
+ * pbody = body;
+ * pbody_len = end - body;
+ * psize = message_length;
+ * ppadding = next - end;
+ * puid = uid;
+
+ * index = next;
+
+ return MAILMBOX_NO_ERROR;
+}
+
+
+int
+mailmbox_parse_additionnal(struct mailmbox_folder * folder,
+ size_t * index)
+{
+ size_t cur_token;
+
+ size_t start;
+ size_t start_len;
+ size_t headers;
+ size_t headers_len;
+ size_t body;
+ size_t body_len;
+ size_t size;
+ size_t padding;
+ uint32_t uid;
+ int r;
+ int res;
+
+ uint32_t max_uid;
+ uint32_t first_index;
+ uint32_t i;
+ uint32_t j;
+
+ cur_token = * index;
+
+ /* remove temporary UID that we will parse */
+
+ first_index = folder->tab->len;
+
+ for(i = 0 ; i < folder->tab->len ; i++) {
+ struct mailmbox_msg_info * info;
+
+ info = carray_get(folder->tab, i);
+
+ if (info->start < cur_token) {
+ continue;
+ }
+
+ if (!info->written_uid) {
+ chashdatum key;
+
+ key.data = (char *) &info->uid;
+ key.len = sizeof(info->uid);
+
+ chash_delete(folder->hash, &key, NULL);
+ carray_delete_fast(folder->tab, i);
+ mailmbox_msg_info_free(info);
+ if (i < first_index)
+ first_index = i;
+ }
+ }
+
+ /* make a sequence in the table */
+
+ max_uid = folder->written_uid;
+
+ i = 0;
+ j = 0;
+ while (i < folder->tab->len) {
+ struct mailmbox_msg_info * info;
+
+ info = carray_get(folder->tab, i);
+ if (info != NULL) {
+ carray_set(folder->tab, j, info);
+
+ if (info->uid > max_uid)
+ max_uid = info->uid;
+
+ info->index = j;
+ j ++;
+ }
+ i ++;
+ }
+ carray_set_size(folder->tab, j);
+
+ /* parse content */
+
+ first_index = j;
+
+ while (1) {
+ struct mailmbox_msg_info * info;
+ chashdatum key;
+ chashdatum data;
+
+ r = mailmbox_single_parse(folder->mapping, folder->mapping_size,
+ &cur_token,
+ &start, &start_len,
+ &headers, &headers_len,
+ &body, &body_len,
+ &size, &padding, &uid);
+ if (r == MAILMBOX_NO_ERROR) {
+ /* do nothing */
+ }
+ else if (r == MAILMBOX_ERROR_PARSE)
+ break;
+ else {
+ res = r;
+ goto err;
+ }
+
+ key.data = (char *) &uid;
+ key.len = sizeof(uid);
+
+ r = chash_get(folder->hash, &key, &data);
+ if (r == 0) {
+ info = (struct mailmbox_msg_info *) data.data;
+
+ if (!info->written_uid) {
+ /* some new mail has been written and override an
+ existing temporary UID */
+
+ chash_delete(folder->hash, &key, NULL);
+ info->uid = 0;
+
+ if (info->index < first_index)
+ first_index = info->index;
+ }
+ else
+ uid = 0;
+ }
+
+ if (uid > max_uid)
+ max_uid = uid;
+
+ r = mailmbox_msg_info_update(folder,
+ start, start_len, headers, headers_len,
+ body, body_len, size, padding, uid);
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+ }
+
+ * index = cur_token;
+
+ folder->written_uid = max_uid;
+
+ /* attribute uid */
+
+ for(i = first_index ; i < folder->tab->len ; i ++) {
+ struct mailmbox_msg_info * info;
+ chashdatum key;
+ chashdatum data;
+
+ info = carray_get(folder->tab, i);
+
+ if (info->uid != 0) {
+ continue;
+ }
+
+ max_uid ++;
+ info->uid = max_uid;
+
+ key.data = (char *) &info->uid;
+ key.len = sizeof(info->uid);
+ data.data = (char *) info;
+ data.len = 0;
+
+ r = chash_set(folder->hash, &key, &data, NULL);
+ if (r < 0) {
+ res = MAILMBOX_ERROR_MEMORY;
+ goto err;
+ }
+ }
+
+ folder->max_uid = max_uid;
+
+ return MAILMBOX_NO_ERROR;
+
+ err:
+ return res;
+}
+
+static void flush_uid(struct mailmbox_folder * folder)
+{
+ uint32_t i;
+
+ for(i = 0 ; i < folder->tab->len ; i++) {
+ struct mailmbox_msg_info * info;
+
+ info = carray_get(folder->tab, i);
+ if (info != NULL)
+ mailmbox_msg_info_free(info);
+ }
+
+ chash_clear(folder->hash);
+ carray_set_size(folder->tab, 0);
+}
+
+int mailmbox_parse(struct mailmbox_folder * folder)
+{
+ int r;
+ int res;
+ size_t cur_token;
+
+ flush_uid(folder);
+
+ cur_token = 0;
+
+ r = mailmbox_parse_additionnal(folder, &cur_token);
+
+ if (r != MAILMBOX_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ return MAILMBOX_NO_ERROR;
+
+ err:
+ return res;
+}
--- /dev/null
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2002 - 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 REGENTS 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 REGENTS 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$
+ */
+
+#ifndef MAILMBOX_PARSE_H
+
+#define MAILMBOX_PARSE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "mailmbox_types.h"
+
+int mailmbox_parse(struct mailmbox_folder * folder);
+
+int
+mailmbox_parse_additionnal(struct mailmbox_folder * folder,
+ size_t * index);
+
+enum {
+ MAILIMF_NO_ERROR,
+ MAILIMF_ERROR_PARSE,
+};
+
+int mailimf_ignore_field_parse(char * message, size_t length,
+ size_t * index);
+
+int mailimf_crlf_parse(char * message, size_t length, size_t * index);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2002 - 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 REGENTS 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 REGENTS 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 "mailmbox_types.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/* *********************************************************************** */
+
+int mailmbox_msg_info_update(struct mailmbox_folder * folder,
+ size_t start, size_t start_len,
+ size_t headers, size_t headers_len,
+ size_t body, size_t body_len,
+ size_t size, size_t padding,
+ uint32_t uid)
+{
+ struct mailmbox_msg_info * info;
+ int res;
+ chashdatum key;
+ chashdatum data;
+ int r;
+
+ key.data = (char *) &uid;
+ key.len = sizeof(uid);
+ r = chash_get(folder->hash, &key, &data);
+ if (r < 0) {
+ uint32_t index;
+
+ info = mailmbox_msg_info_new(start, start_len, headers, headers_len,
+ body, body_len, size, padding, uid);
+ if (info == NULL) {
+ res = MAILMBOX_ERROR_MEMORY;
+ goto err;
+ }
+
+ r = carray_add(folder->tab, info, &index);
+ if (r < 0) {
+ mailmbox_msg_info_free(info);
+ res = MAILMBOX_ERROR_MEMORY;
+ goto err;
+ }
+
+ if (uid != 0) {
+ chashdatum key;
+ chashdatum data;
+
+ key.data = (char *) &uid;
+ key.len = sizeof(uid);
+ data.data = (char *) info;
+ data.len = 0;
+
+ r = chash_set(folder->hash, &key, &data, NULL);
+ if (r < 0) {
+ mailmbox_msg_info_free(info);
+ carray_delete(folder->tab, index);
+ res = MAILMBOX_ERROR_MEMORY;
+ goto err;
+ }
+ }
+
+ info->index = index;
+ }
+ else {
+ info = (struct mailmbox_msg_info *) data.data;
+
+ info->start = start;
+ info->start_len = start_len;
+ info->headers = headers;
+ info->headers_len = headers_len;
+ info->body = body;
+ info->body_len = body_len;
+ info->size = size;
+ info->padding = padding;
+ }
+
+ return MAILMBOX_NO_ERROR;
+
+ err:
+ return res;
+}
+
+
+struct mailmbox_msg_info *
+mailmbox_msg_info_new(size_t start, size_t start_len,
+ size_t headers, size_t headers_len,
+ size_t body, size_t body_len,
+ size_t size, size_t padding,
+ uint32_t uid)
+{
+ struct mailmbox_msg_info * info;
+
+ info = malloc(sizeof(* info));
+ if (info == NULL)
+ return NULL;
+
+ info->index = 0;
+ info->uid = uid;
+ if (uid != 0)
+ info->written_uid = TRUE;
+ else
+ info->written_uid = FALSE;
+ info->deleted = FALSE;
+
+ info->start = start;
+ info->start_len = start_len;
+
+ info->headers = headers;
+ info->headers_len = headers_len;
+
+ info->body = body;
+ info->body_len = body_len;
+
+ info->size = size;
+
+ info->padding = padding;
+
+ return info;
+}
+
+void mailmbox_msg_info_free(struct mailmbox_msg_info * info)
+{
+ free(info);
+}
+
+/* *********************************************************************** */
+
+#if 0
+struct mailmbox_msg_env *
+mailmbox_msg_env_new(uint32_t index, struct mailimf_fields * fields)
+{
+ struct mailmbox_msg_env * msg_env;
+
+ msg_env = alloc(struct mailmbox_msg_env, 1);
+ if (msg_env == NULL)
+ return NULL;
+
+ msg_env->index = index;
+ msg_env->fields = fields;
+
+ return msg_env;
+}
+
+void mailmbox_msg_env_free(struct mailmbox_msg_env * msg_env)
+{
+ if (msg_env->fields != NULL)
+ mailimf_fields_free(msg_env->fields);
+ free(msg_env);
+}
+#endif
+
+/* append info */
+
+struct mailmbox_append_info *
+mailmbox_append_info_new(char * message, size_t size)
+{
+ struct mailmbox_append_info * info;
+
+ info = malloc(sizeof(* info));
+ if (info == NULL)
+ return NULL;
+
+ info->message = message;
+ info->size = size;
+
+ return info;
+}
+
+void mailmbox_append_info_free(struct mailmbox_append_info * info)
+{
+ free(info);
+}
+
+#if 0
+struct mailmbox_append_info_list *
+mailmbox_append_info_list_new(clist * list)
+{
+ struct mailmbox_append_info_list * info_list;
+
+ info_list = alloc(struct mailmbox_append_info_list, 1);
+ if (info_list == NULL)
+ return NULL;
+
+ info_list->list = list;
+
+ return info_list;
+}
+
+void mailmbox_append_info_list_free(struct mailmbox_append_info_list *
+ info_list)
+{
+ clist_foreach(info_list->list, (clist_func) mailmbox_append_info_free, NULL);
+ free(info_list);
+}
+#endif
+
+struct mailmbox_folder * mailmbox_folder_new(char * filename)
+{
+ struct mailmbox_folder * folder;
+
+ folder = malloc(sizeof(* folder));
+ if (folder == NULL)
+ goto err;
+
+ strncpy(folder->filename, filename, PATH_MAX);
+
+ folder->mtime = (time_t) -1;
+
+ folder->fd = -1;
+ folder->read_only = TRUE;
+ folder->no_uid = TRUE;
+
+ folder->changed = FALSE;
+ folder->deleted_count = 0;
+
+ folder->mapping = NULL;
+ folder->mapping_size = 0;
+
+ folder->written_uid = 0;
+ folder->max_uid = 0;
+
+ folder->hash = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY);
+ if (folder->hash == NULL)
+ goto free;
+
+ folder->tab = carray_new(128);
+ if (folder->tab == NULL)
+ goto free_hash;
+
+ return folder;
+
+ free_hash:
+ chash_free(folder->hash);
+ free:
+ free(folder);
+ err:
+ return NULL;
+}
+
+void mailmbox_folder_free(struct mailmbox_folder * folder)
+{
+ uint32_t i;
+
+ for(i = 0 ; i < folder->tab->len ; i++) {
+ struct mailmbox_msg_info * info;
+
+ info = carray_get(folder->tab, i);
+ if (info != NULL)
+ mailmbox_msg_info_free(info);
+ }
+
+ carray_free(folder->tab);
+
+ chash_free(folder->hash);
+
+ free(folder);
+}
--- /dev/null
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2002 - 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 REGENTS 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 REGENTS 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$
+ */
+
+#ifndef MAILMBOX_TYPES_H
+
+#define MAILMBOX_TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <limits.h>
+
+#include "carray.h"
+#include "chash.h"
+
+enum {
+ MAILMBOX_NO_ERROR = 0,
+ MAILMBOX_ERROR_PARSE,
+ MAILMBOX_ERROR_INVAL,
+ MAILMBOX_ERROR_FILE_NOT_FOUND,
+ MAILMBOX_ERROR_MEMORY,
+ MAILMBOX_ERROR_TEMPORARY_FILE,
+ MAILMBOX_ERROR_FILE,
+ MAILMBOX_ERROR_MSG_NOT_FOUND,
+ MAILMBOX_ERROR_READONLY,
+};
+
+
+struct mailmbox_folder {
+ char filename[PATH_MAX];
+
+ time_t mtime;
+
+ int fd;
+ int read_only;
+ int no_uid;
+
+ int changed;
+ uint32_t deleted_count;
+
+ char * mapping;
+ size_t mapping_size;
+
+ uint32_t written_uid;
+ uint32_t max_uid;
+
+ chash * hash;
+ carray * tab;
+};
+
+struct mailmbox_folder * mailmbox_folder_new(char * filename);
+void mailmbox_folder_free(struct mailmbox_folder * folder);
+
+
+struct mailmbox_msg_info {
+ uint32_t index;
+ uint32_t uid;
+ int written_uid;
+ int deleted;
+
+ size_t start;
+ size_t start_len;
+
+ size_t headers;
+ size_t headers_len;
+
+ size_t body;
+ size_t body_len;
+
+ size_t size;
+
+ size_t padding;
+};
+
+
+int mailmbox_msg_info_update(struct mailmbox_folder * folder,
+ size_t start, size_t start_len,
+ size_t headers, size_t headers_len,
+ size_t body, size_t body_len,
+ size_t size, size_t padding,
+ uint32_t uid);
+
+struct mailmbox_msg_info *
+mailmbox_msg_info_new(size_t start, size_t start_len,
+ size_t headers, size_t headers_len,
+ size_t body, size_t body_len,
+ size_t size, size_t padding,
+ uint32_t uid);
+
+void mailmbox_msg_info_free(struct mailmbox_msg_info * info);
+
+#if 0
+struct mailmbox_msg_env {
+ uint32_t index;
+ struct mailimf_fields * fields;
+};
+
+struct mailmbox_msg_env *
+mailmbox_msg_env_new(uint32_t index, struct mailimf_fields * fields);
+
+void mailmbox_msg_env_free(struct mailmbox_msg_env * msg_env);
+#endif
+
+struct mailmbox_append_info {
+ char * message;
+ size_t size;
+};
+
+struct mailmbox_append_info *
+mailmbox_append_info_new(char * message, size_t size);
+
+void mailmbox_append_info_free(struct mailmbox_append_info * info);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif