implementation of mbox folder with unique messages numbers
authorHoà Viêt Dinh <dinh.viet.hoa@free.fr>
Tue, 21 Oct 2003 05:41:31 +0000 (05:41 +0000)
committerHoà Viêt Dinh <dinh.viet.hoa@free.fr>
Tue, 21 Oct 2003 05:41:31 +0000 (05:41 +0000)
18 files changed:
ChangeLog.claws
configure.ac
src/Makefile.am
src/carray.c [new file with mode: 0644]
src/carray.h [new file with mode: 0644]
src/chash.c [new file with mode: 0644]
src/chash.h [new file with mode: 0644]
src/folder.c
src/maillock.c [new file with mode: 0644]
src/maillock.h [new file with mode: 0644]
src/mailmbox.c [new file with mode: 0644]
src/mailmbox.h [new file with mode: 0644]
src/mailmbox_folder.c [new file with mode: 0644]
src/mailmbox_folder.h [new file with mode: 0644]
src/mailmbox_parse.c [new file with mode: 0644]
src/mailmbox_parse.h [new file with mode: 0644]
src/mailmbox_types.c [new file with mode: 0644]
src/mailmbox_types.h [new file with mode: 0644]

index 5897cd3..4bb1f56 100644 (file)
@@ -1,3 +1,18 @@
+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
index e09b2fd..f3b6be7 100644 (file)
@@ -11,7 +11,7 @@ MINOR_VERSION=9
 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
index f0cce84..8c51421 100644 (file)
@@ -18,6 +18,8 @@ sylpheed_SOURCES = \
        addrquery.c \
        addrselect.c \
        alertpanel.c \
+       carray.c \
+       chash.c \
        codeconv.c \
        compose.c \
        crash.c \
@@ -57,6 +59,7 @@ sylpheed_SOURCES = \
        ldapserver.c \
        ldaputil.c \
        ldif.c \
+       maillock.c \
        main.c \
        mainwindow.c \
        manual.c \
@@ -64,7 +67,10 @@ sylpheed_SOURCES = \
        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 \
@@ -141,6 +147,8 @@ sylpheedinclude_HEADERS = \
        addrquery.h \
        addrselect.h \
        alertpanel.h \
+       carray.h \
+       chash.h \
        codeconv.h \
        compose.h \
        crash.h \
@@ -180,6 +188,7 @@ sylpheedinclude_HEADERS = \
        ldapserver.h \
        ldaputil.h \
        ldif.h \
+       maillock.h \
        main.h \
        mainwindow.h \
        manual.h \
@@ -187,8 +196,11 @@ sylpheedinclude_HEADERS = \
        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 \
diff --git a/src/carray.c b/src/carray.c
new file mode 100644 (file)
index 0000000..8ce2fb2
--- /dev/null
@@ -0,0 +1,139 @@
+
+/*
+ * 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);
+}
diff --git a/src/carray.h b/src/carray.h
new file mode 100644 (file)
index 0000000..8200452
--- /dev/null
@@ -0,0 +1,102 @@
+
+/*
+ * 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
diff --git a/src/chash.c b/src/chash.c
new file mode 100644 (file)
index 0000000..d9f8d7d
--- /dev/null
@@ -0,0 +1,381 @@
+
+/*
+ * 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
diff --git a/src/chash.h b/src/chash.h
new file mode 100644 (file)
index 0000000..60c6e57
--- /dev/null
@@ -0,0 +1,159 @@
+
+/*
+ * 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
index 0f1eef0..c027d1e 100644 (file)
@@ -37,7 +37,7 @@
 #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"
@@ -81,7 +81,7 @@ void folder_system_init(void)
        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)
diff --git a/src/maillock.c b/src/maillock.c
new file mode 100644 (file)
index 0000000..d0d7273
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * 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);
+}
diff --git a/src/maillock.h b/src/maillock.h
new file mode 100644 (file)
index 0000000..5113559
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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
diff --git a/src/mailmbox.c b/src/mailmbox.c
new file mode 100644 (file)
index 0000000..3651e04
--- /dev/null
@@ -0,0 +1,1388 @@
+/*
+ * 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 *) &num;
+  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 *) &num;
+  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);
+}
diff --git a/src/mailmbox.h b/src/mailmbox.h
new file mode 100644 (file)
index 0000000..be4a0f0
--- /dev/null
@@ -0,0 +1,109 @@
+#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
diff --git a/src/mailmbox_folder.c b/src/mailmbox_folder.c
new file mode 100644 (file)
index 0000000..3dc5af9
--- /dev/null
@@ -0,0 +1,1025 @@
+/*
+ * 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;
+}
diff --git a/src/mailmbox_folder.h b/src/mailmbox_folder.h
new file mode 100644 (file)
index 0000000..ab137c7
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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__ */
diff --git a/src/mailmbox_parse.c b/src/mailmbox_parse.c
new file mode 100644 (file)
index 0000000..57c88b2
--- /dev/null
@@ -0,0 +1,780 @@
+/*
+ * 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;
+}
diff --git a/src/mailmbox_parse.h b/src/mailmbox_parse.h
new file mode 100644 (file)
index 0000000..6fc3897
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * 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
diff --git a/src/mailmbox_types.c b/src/mailmbox_types.c
new file mode 100644 (file)
index 0000000..fc79063
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * 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);
+}
diff --git a/src/mailmbox_types.h b/src/mailmbox_types.h
new file mode 100644 (file)
index 0000000..9032bed
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * 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