From 80bec4b3e5de8044697f4acddd05947cbf68d8c4 Mon Sep 17 00:00:00 2001 From: Michael Zucci Date: Wed, 15 Nov 2000 05:44:25 +0000 Subject: Maildir lives. svn path=/trunk/; revision=6576 --- camel/providers/local/Makefile.am | 10 +- camel/providers/local/camel-local-provider.c | 24 +- camel/providers/local/camel-local-summary.c | 5 +- camel/providers/local/camel-maildir-folder.c | 227 +++++++++++++++ camel/providers/local/camel-maildir-folder.h | 59 ++++ camel/providers/local/camel-maildir-store.c | 164 +++++++++++ camel/providers/local/camel-maildir-store.h | 56 ++++ camel/providers/local/camel-maildir-summary.c | 396 ++++++++++++++++++++++++++ camel/providers/local/camel-maildir-summary.h | 63 ++++ camel/providers/local/camel-mh-folder.c | 7 +- camel/providers/local/camel-mh-folder.h | 5 +- camel/providers/local/camel-mh-store.h | 5 +- camel/providers/local/libcamellocal.urls | 1 + 13 files changed, 1005 insertions(+), 17 deletions(-) create mode 100644 camel/providers/local/camel-maildir-folder.c create mode 100644 camel/providers/local/camel-maildir-folder.h create mode 100644 camel/providers/local/camel-maildir-store.c create mode 100644 camel/providers/local/camel-maildir-store.h create mode 100644 camel/providers/local/camel-maildir-summary.c create mode 100644 camel/providers/local/camel-maildir-summary.h diff --git a/camel/providers/local/Makefile.am b/camel/providers/local/Makefile.am index 01a3072cb9..1f250b04cd 100644 --- a/camel/providers/local/Makefile.am +++ b/camel/providers/local/Makefile.am @@ -28,7 +28,10 @@ libcamellocal_la_SOURCES = \ camel-mh-summary.c \ camel-mbox-folder.c \ camel-mbox-store.c \ - camel-mbox-summary.c + camel-mbox-summary.c \ + camel-maildir-folder.c \ + camel-maildir-store.c \ + camel-maildir-summary.c libcamellocalinclude_HEADERS = \ camel-local-folder.h \ @@ -39,7 +42,10 @@ libcamellocalinclude_HEADERS = \ camel-mh-summary.h \ camel-mbox-folder.h \ camel-mbox-store.h \ - camel-mbox-summary.h + camel-mbox-summary.h \ + camel-maildir-folder.h \ + camel-maildir-store.h \ + camel-maildir-summary.h libcamellocal_la_LDFLAGS = -version-info 0:0:0 diff --git a/camel/providers/local/camel-local-provider.c b/camel/providers/local/camel-local-provider.c index f0beec0065..603a4a7bf9 100644 --- a/camel/providers/local/camel-local-provider.c +++ b/camel/providers/local/camel-local-provider.c @@ -20,6 +20,8 @@ * USA */ +#include + #include "config.h" #include "camel-provider.h" #include "camel-session.h" @@ -27,6 +29,7 @@ #include "camel-mh-store.h" #include "camel-mbox-store.h" +#include "camel-maildir-store.h" static CamelProvider mh_provider = { "mh", @@ -42,7 +45,18 @@ static CamelProvider mh_provider = { static CamelProvider mbox_provider = { "mbox", N_("UNIX mbox-format mail files (CamelLocal version)"), - N_("For storing local mai in standard mbox format"), + N_("For storing local mail in standard mbox format"), + "mail", + CAMEL_PROVIDER_IS_SOURCE | CAMEL_PROVIDER_IS_STORAGE, + CAMEL_URL_NEED_PATH, + { 0, 0 }, + NULL +}; + +static CamelProvider maildir_provider = { + "maildir", + N_("UNIX qmail maildir-format mail files (CamelLocal version)"), + N_("For storing local mail in qmail maildir directories"), "mail", CAMEL_PROVIDER_IS_SOURCE | CAMEL_PROVIDER_IS_STORAGE, CAMEL_URL_NEED_PATH, @@ -59,6 +73,10 @@ void camel_provider_module_init(CamelSession * session) camel_session_register_provider(session, &mh_provider); mbox_provider.object_types[CAMEL_PROVIDER_STORE] = camel_mbox_store_get_type(); - mbox_provider.service_cache = g_hash_table_new (camel_url_hash, camel_url_equal); - camel_session_register_provider (session, &mbox_provider); + mbox_provider.service_cache = g_hash_table_new(camel_url_hash, camel_url_equal); + camel_session_register_provider(session, &mbox_provider); + + maildir_provider.object_types[CAMEL_PROVIDER_STORE] = camel_maildir_store_get_type(); + maildir_provider.service_cache = g_hash_table_new(camel_url_hash, camel_url_equal); + camel_session_register_provider(session, &maildir_provider); } diff --git a/camel/providers/local/camel-local-summary.c b/camel/providers/local/camel-local-summary.c index 68c83404cc..ed33d9ffc2 100644 --- a/camel/providers/local/camel-local-summary.c +++ b/camel/providers/local/camel-local-summary.c @@ -248,7 +248,6 @@ static CamelMessageInfo * local_summary_add(CamelLocalSummary *cls, CamelMimeMessage *msg, const CamelMessageInfo *info, CamelFolderChangeInfo *ci, CamelException *ex) { CamelMessageInfo *mi; - CamelFolderSummary *s = (CamelFolderSummary *)cls; char *xev; d(printf("Adding message to summary\n")); @@ -431,7 +430,7 @@ message_info_new(CamelFolderSummary *s, struct _header_raw *h) static CamelMessageInfo * message_info_new_from_message(CamelFolderSummary *s, CamelMimeMessage *msg) { CamelMessageInfo *mi; - CamelLocalSummary *cls = (CamelLocalSummary *)s; + /*CamelLocalSummary *cls = (CamelLocalSummary *)s;*/ mi = ((CamelFolderSummaryClass *)camel_local_summary_parent)->message_info_new_from_message(s, msg); #if 0 @@ -461,7 +460,7 @@ static CamelMessageInfo * message_info_new_from_parser(CamelFolderSummary *s, CamelMimeParser *mp) { CamelMessageInfo *mi; - CamelLocalSummary *mbs = CAMEL_LOCAL_SUMMARY(s); + /*CamelLocalSummary *mbs = CAMEL_LOCAL_SUMMARY(s);*/ mi = ((CamelFolderSummaryClass *)camel_local_summary_parent)->message_info_new_from_parser(s, mp); if (mi) { diff --git a/camel/providers/local/camel-maildir-folder.c b/camel/providers/local/camel-maildir-folder.c new file mode 100644 index 0000000000..0cf3f23610 --- /dev/null +++ b/camel/providers/local/camel-maildir-folder.c @@ -0,0 +1,227 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*- + * + * Authors: Michael Zucchi + * + * Copyright (C) 1999, 2000 Helix Code Inc. + * + * 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 + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "camel-maildir-folder.h" +#include "camel-maildir-store.h" +#include "string-utils.h" +#include "camel-stream-fs.h" +#include "camel-maildir-summary.h" +#include "camel-data-wrapper.h" +#include "camel-mime-message.h" +#include "camel-exception.h" + +#define d(x) (printf("%s(%d): ", __FILE__, __LINE__),(x)) + +static CamelFolderClass *parent_class = NULL; + +/* Returns the class for a CamelMaildirFolder */ +#define CMAILDIRF_CLASS(so) CAMEL_MAILDIR_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so)) +#define CF_CLASS(so) CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so)) +#define CMAILDIRS_CLASS(so) CAMEL_STORE_CLASS (CAMEL_OBJECT_GET_CLASS(so)) + +static CamelLocalSummary *maildir_create_summary(const char *path, const char *folder, ibex *index); + +static void maildir_append_message(CamelFolder * folder, CamelMimeMessage * message, const CamelMessageInfo *info, CamelException * ex); +static CamelMimeMessage *maildir_get_message(CamelFolder * folder, const gchar * uid, CamelException * ex); + +static void maildir_finalize(CamelObject * object); + +static void camel_maildir_folder_class_init(CamelObjectClass * camel_maildir_folder_class) +{ + CamelFolderClass *camel_folder_class = CAMEL_FOLDER_CLASS(camel_maildir_folder_class); + CamelLocalFolderClass *lclass = (CamelLocalFolderClass *)camel_maildir_folder_class; + + parent_class = CAMEL_FOLDER_CLASS (camel_type_get_global_classfuncs(camel_folder_get_type())); + + /* virtual method definition */ + + /* virtual method overload */ + camel_folder_class->append_message = maildir_append_message; + camel_folder_class->get_message = maildir_get_message; + + lclass->create_summary = maildir_create_summary; +} + +static void maildir_init(gpointer object, gpointer klass) +{ + /*CamelFolder *folder = object; + CamelMaildirFolder *maildir_folder = object;*/ +} + +static void maildir_finalize(CamelObject * object) +{ + /*CamelMaildirFolder *maildir_folder = CAMEL_MAILDIR_FOLDER(object);*/ +} + +CamelType camel_maildir_folder_get_type(void) +{ + static CamelType camel_maildir_folder_type = CAMEL_INVALID_TYPE; + + if (camel_maildir_folder_type == CAMEL_INVALID_TYPE) { + camel_maildir_folder_type = camel_type_register(CAMEL_LOCAL_FOLDER_TYPE, "CamelMaildirFolder", + sizeof(CamelMaildirFolder), + sizeof(CamelMaildirFolderClass), + (CamelObjectClassInitFunc) camel_maildir_folder_class_init, + NULL, + (CamelObjectInitFunc) maildir_init, + (CamelObjectFinalizeFunc) maildir_finalize); + } + + return camel_maildir_folder_type; +} + +CamelFolder * +camel_maildir_folder_new(CamelStore *parent_store, const char *full_name, guint32 flags, CamelException *ex) +{ + CamelFolder *folder; + + d(printf("Creating maildir folder: %s\n", full_name)); + + folder = (CamelFolder *)camel_object_new(CAMEL_MAILDIR_FOLDER_TYPE); + folder = (CamelFolder *)camel_local_folder_construct((CamelLocalFolder *)folder, + parent_store, full_name, flags, ex); + + return folder; +} + +static CamelLocalSummary *maildir_create_summary(const char *path, const char *folder, ibex *index) +{ + return (CamelLocalSummary *)camel_maildir_summary_new(path, folder, index); +} + +static void maildir_append_message(CamelFolder * folder, CamelMimeMessage * message, const CamelMessageInfo *info, CamelException * ex) +{ + CamelMaildirFolder *maildir_folder = (CamelMaildirFolder *)folder; + CamelLocalFolder *lf = (CamelLocalFolder *)folder; + CamelStream *output_stream; + CamelMessageInfo *mi; + CamelMaildirMessageInfo *mdi; + char *name, *dest; + + /* FIXME: probably needs additional locking */ + + d(printf("Appending message\n")); + + /* add it to the summary/assign the uid, etc */ + mi = camel_local_summary_add(lf->summary, message, info, lf->changes, ex); + if (camel_exception_is_set(ex)) { + return; + } + + mdi = (CamelMaildirMessageInfo *)mi; + + g_assert(mdi->filename); + + d(printf("Appending message: uid is %s filename is %s\n", mi->uid, mdi->filename)); + + /* write it out to tmp, use the uid we got from the summary */ + name = g_strdup_printf("%s/tmp/%s", lf->folder_path, mi->uid); + output_stream = camel_stream_fs_new_with_name(name, O_WRONLY|O_CREAT, 0600); + if (output_stream == NULL) { + camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, + _("Cannot append message to maildir folder: %s: %s"), name, g_strerror(errno)); + g_free(name); + return; + } + + if (camel_data_wrapper_write_to_stream((CamelDataWrapper *)message, output_stream) == -1 + || camel_stream_close(output_stream) == -1) { + camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, + _("Cannot append message to maildir folder: %s: %s"), name, g_strerror(errno)); + camel_object_unref((CamelObject *)output_stream); + unlink(name); + g_free(name); + return; + } + + /* now move from tmp to cur (bypass new, does it matter?) */ + dest = g_strdup_printf("%s/cur/%s", lf->folder_path, mdi->filename); + if (rename(name, dest) == 1) { + camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, + _("Cannot append message to maildir folder: %s: %s"), name, g_strerror(errno)); + camel_object_unref((CamelObject *)output_stream); + unlink(name); + g_free(name); + g_free(dest); + return; + } + + g_free(dest); + g_free(name); + + camel_object_trigger_event((CamelObject *)folder, "folder_changed", ((CamelLocalFolder *)maildir_folder)->changes); + camel_folder_change_info_clear(((CamelLocalFolder *)maildir_folder)->changes); +} + +static CamelMimeMessage *maildir_get_message(CamelFolder * folder, const gchar * uid, CamelException * ex) +{ + CamelLocalFolder *lf = (CamelLocalFolder *)folder; + CamelStream *message_stream = NULL; + CamelMimeMessage *message = NULL; + CamelMessageInfo *info; + char *name; + CamelMaildirMessageInfo *mdi; + + d(printf("getting message: %s\n", uid)); + + /* get the message summary info */ + if ((info = camel_folder_summary_uid((CamelFolderSummary *)lf->summary, uid)) == NULL) { + camel_exception_setv(ex, CAMEL_EXCEPTION_FOLDER_INVALID_UID, _("Cannot get message: %s\n %s"), uid, _("No such message")); + return NULL; + } + + mdi = (CamelMaildirMessageInfo *)info; + + name = g_strdup_printf("%s/cur/%s", lf->folder_path, mdi->filename); + if ((message_stream = camel_stream_fs_new_with_name(name, O_RDONLY, 0)) == NULL) { + camel_exception_setv(ex, CAMEL_EXCEPTION_FOLDER_INVALID_UID, _("Cannot get message: %s\n %s"), + name, g_strerror(errno)); + g_free(name); + return NULL; + } + + message = camel_mime_message_new(); + if (camel_data_wrapper_construct_from_stream((CamelDataWrapper *)message, message_stream) == -1) { + camel_exception_setv(ex, CAMEL_EXCEPTION_FOLDER_INVALID_UID, _("Cannot get message: %s\n %s"), + name, _("Invalid message contents")); + g_free(name); + camel_object_unref((CamelObject *)message_stream); + camel_object_unref((CamelObject *)message); + return NULL; + + } + camel_object_unref((CamelObject *)message_stream); + g_free(name); + + return message; +} diff --git a/camel/providers/local/camel-maildir-folder.h b/camel/providers/local/camel-maildir-folder.h new file mode 100644 index 0000000000..5eb1a7cbbb --- /dev/null +++ b/camel/providers/local/camel-maildir-folder.h @@ -0,0 +1,59 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Authors: + * Michael Zucchi + * + * Copyright (C) 1999 Helix Code Inc. + * + * 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 CAMEL_MAILDIR_FOLDER_H +#define CAMEL_MAILDIR_FOLDER_H 1 + +#ifdef __cplusplus +extern "C" { +#pragma } +#endif /* __cplusplus } */ +#include "camel-local-folder.h" + +#define CAMEL_MAILDIR_FOLDER_TYPE (camel_maildir_folder_get_type ()) +#define CAMEL_MAILDIR_FOLDER(obj) (CAMEL_CHECK_CAST((obj), CAMEL_MAILDIR_FOLDER_TYPE, CamelMaildirFolder)) +#define CAMEL_MAILDIR_FOLDER_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_MAILDIR_FOLDER_TYPE, CamelMaildirFolderClass)) +#define IS_CAMEL_MAILDIR_FOLDER(o) (CAMEL_CHECK_TYPE((o), CAMEL_MAILDIR_FOLDER_TYPE)) + +typedef struct { + CamelLocalFolder parent_object; + +} CamelMaildirFolder; + +typedef struct { + CamelLocalFolderClass parent_class; + + /* Virtual methods */ + +} CamelMaildirFolderClass; + +/* public methods */ +CamelFolder *camel_maildir_folder_new(CamelStore *parent_store, const char *full_name, guint32 flags, CamelException *ex); + +/* Standard Camel function */ +CamelType camel_maildir_folder_get_type(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* CAMEL_MAILDIR_FOLDER_H */ diff --git a/camel/providers/local/camel-maildir-store.c b/camel/providers/local/camel-maildir-store.c new file mode 100644 index 0000000000..0601307449 --- /dev/null +++ b/camel/providers/local/camel-maildir-store.c @@ -0,0 +1,164 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2000 Helix Code, Inc. + * + * Authors: Michael Zucchi + * + * 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 + */ + +#include + +#include +#include +#include +#include + +#include "camel-maildir-store.h" +#include "camel-maildir-folder.h" +#include "camel-exception.h" +#include "camel-url.h" + +static CamelLocalStoreClass *parent_class = NULL; + +/* Returns the class for a CamelMaildirStore */ +#define CMAILDIRS_CLASS(so) CAMEL_MAILDIR_STORE_CLASS (CAMEL_OBJECT_GET_CLASS(so)) +#define CF_CLASS(so) CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so)) +#define CMAILDIRF_CLASS(so) CAMEL_MAILDIR_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so)) + +static CamelFolder *get_folder(CamelStore * store, const char *folder_name, guint32 flags, CamelException * ex); +static void delete_folder(CamelStore * store, const char *folder_name, CamelException * ex); + +static void camel_maildir_store_class_init(CamelObjectClass * camel_maildir_store_class) +{ + CamelStoreClass *camel_store_class = CAMEL_STORE_CLASS(camel_maildir_store_class); + /*CamelServiceClass *camel_service_class = CAMEL_SERVICE_CLASS(camel_maildir_store_class);*/ + + parent_class = (CamelLocalStoreClass *)camel_type_get_global_classfuncs(camel_folder_get_type()); + + /* virtual method overload, use defaults for most */ + camel_store_class->get_folder = get_folder; + camel_store_class->delete_folder = delete_folder; +} + +static void camel_maildir_store_init(CamelObject * object) +{ + CamelStore *store = CAMEL_STORE(object); + + /* maildir names are filenames, so they are case-sensitive. */ + store->folders = g_hash_table_new(g_str_hash, g_str_equal); +} + +CamelType camel_maildir_store_get_type(void) +{ + static CamelType camel_maildir_store_type = CAMEL_INVALID_TYPE; + + if (camel_maildir_store_type == CAMEL_INVALID_TYPE) { + camel_maildir_store_type = camel_type_register(CAMEL_LOCAL_STORE_TYPE, "CamelMaildirStore", + sizeof(CamelMaildirStore), + sizeof(CamelMaildirStoreClass), + (CamelObjectClassInitFunc) camel_maildir_store_class_init, + NULL, + (CamelObjectInitFunc) camel_maildir_store_init, + NULL); + } + + return camel_maildir_store_type; +} + +static CamelFolder *get_folder(CamelStore * store, const char *folder_name, guint32 flags, CamelException * ex) +{ + char *name, *tmp, *cur, *new; + struct stat st; + CamelFolder *folder = NULL; + + name = g_strdup_printf("%s%s", CAMEL_SERVICE(store)->url->path, folder_name); + tmp = g_strdup_printf("%s/tmp", name); + cur = g_strdup_printf("%s/cur", name); + new = g_strdup_printf("%s/new", name); + + if (stat(name, &st) == -1) { + if (errno != ENOENT) { + camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, + _("Could not open folder `%s':\n%s"), + folder_name, strerror(errno)); + } else if ((flags & CAMEL_STORE_FOLDER_CREATE) == 0) { + camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, + _("Folder `%s' does not exist."), folder_name); + } else { + printf("creating ...\n"); + + if (mkdir(name, 0700) != 0 + || mkdir(tmp, 0700) != 0 + || mkdir(cur, 0700) != 0 + || mkdir(new, 0700) != 0) { + camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, + _("Could not create folder `%s':\n%s"), + folder_name, strerror(errno)); + rmdir(tmp); + rmdir(cur); + rmdir(new); + rmdir(name); + } else { + printf("created ok?\n"); + folder = camel_maildir_folder_new(store, folder_name, flags, ex); + } + } + } else if (!S_ISDIR(st.st_mode) + || stat(tmp, &st) != 0 || !S_ISDIR(st.st_mode) + || stat(cur, &st) != 0 || !S_ISDIR(st.st_mode) + || stat(new, &st) != 0 || !S_ISDIR(st.st_mode)) { + camel_exception_setv(ex, CAMEL_EXCEPTION_STORE_NO_FOLDER, + _("`%s' is not a maildir directory."), name); + } else { + folder = camel_maildir_folder_new(store, folder_name, flags, ex); + } + + g_free(name); + g_free(tmp); + g_free(cur); + g_free(new); + + return folder; +} + +static void delete_folder(CamelStore * store, const char *folder_name, CamelException * ex) +{ + char *name, *tmp, *cur, *new; + + name = g_strdup_printf("%s%s", CAMEL_SERVICE(store)->url->path, folder_name); + tmp = g_strdup_printf("%s/tmp", name); + cur = g_strdup_printf("%s/cur", name); + new = g_strdup_printf("%s/new", name); + + /* remove subdirs first - will fail if not empty */ + if ((rmdir(tmp) == -1 && errno != ENOENT) + || (rmdir(new) == -1 && errno != ENOENT) + || (rmdir(cur) == -1 && errno != ENOENT) + || (rmdir(name) == -1 && errno != ENOENT)) { + camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, + _("Could not delete folder `%s': %s"), + folder_name, strerror(errno)); + } else { + /* and remove metadata */ + ((CamelStoreClass *)parent_class)->delete_folder(store, folder_name, ex); + } + + g_free(name); + g_free(tmp); + g_free(cur); + g_free(new); +} diff --git a/camel/providers/local/camel-maildir-store.h b/camel/providers/local/camel-maildir-store.h new file mode 100644 index 0000000000..3e4a907652 --- /dev/null +++ b/camel/providers/local/camel-maildir-store.h @@ -0,0 +1,56 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2000 Helix Code, Inc. + * + * Authors: Michael Zucchi + * + * 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 CAMEL_MAILDIR_STORE_H +#define CAMEL_MAILDIR_STORE_H 1 + +#ifdef __cplusplus +extern "C" { +#pragma } +#endif /* __cplusplus } */ + +#include "camel-local-store.h" + +#define CAMEL_MAILDIR_STORE_TYPE (camel_maildir_store_get_type ()) +#define CAMEL_MAILDIR_STORE(obj) (CAMEL_CHECK_CAST((obj), CAMEL_MAILDIR_STORE_TYPE, CamelMaildirStore)) +#define CAMEL_MAILDIR_STORE_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), CAMEL_MAILDIR_STORE_TYPE, CamelMaildirStoreClass)) +#define IS_CAMEL_MAILDIR_STORE(o) (CAMEL_CHECK_TYPE((o), CAMEL_MAILDIR_STORE_TYPE)) + +typedef struct { + CamelLocalStore parent_object; + +} CamelMaildirStore; + +typedef struct { + CamelLocalStoreClass parent_class; + +} CamelMaildirStoreClass; + +/* public methods */ + +/* Standard Camel function */ +CamelType camel_maildir_store_get_type(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* CAMEL_MAILDIR_STORE_H */ diff --git a/camel/providers/local/camel-maildir-summary.c b/camel/providers/local/camel-maildir-summary.c new file mode 100644 index 0000000000..cbe5a56f00 --- /dev/null +++ b/camel/providers/local/camel-maildir-summary.c @@ -0,0 +1,396 @@ +/* + * Copyright (C) 2000 Helix Code Inc. + * + * Authors: Not Zed + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "camel-maildir-summary.h" +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#define d(x) (printf("%s(%d): ", __FILE__, __LINE__),(x)) + +#define CAMEL_MAILDIR_SUMMARY_VERSION (0x2000) + +static CamelMessageInfo *message_info_new(CamelFolderSummary *, struct _header_raw *); + +static int maildir_summary_check(CamelLocalSummary *cls, CamelFolderChangeInfo *changeinfo, CamelException *ex); +static int maildir_summary_sync(CamelLocalSummary *cls, gboolean expunge, CamelFolderChangeInfo *changeinfo, CamelException *ex); +/*static int maildir_summary_add(CamelLocalSummary *cls, CamelMimeMessage *msg, CamelMessageInfo *info, CamelFolderChangeInfo *, CamelException *ex);*/ + +static char *maildir_summary_next_uid_string(CamelFolderSummary *s); + +static void camel_maildir_summary_class_init (CamelMaildirSummaryClass *class); +static void camel_maildir_summary_init (CamelMaildirSummary *gspaper); +static void camel_maildir_summary_finalise (CamelObject *obj); + +#define _PRIVATE(x) (((CamelMaildirSummary *)(x))->priv) + +struct _CamelMaildirSummaryPrivate { + char *current_file; + char *hostname; +}; + +static CamelLocalSummaryClass *parent_class; + +CamelType +camel_maildir_summary_get_type (void) +{ + static CamelType type = CAMEL_INVALID_TYPE; + + if (type == CAMEL_INVALID_TYPE) { + type = camel_type_register(camel_local_summary_get_type (), "CamelMaildirSummary", + sizeof(CamelMaildirSummary), + sizeof(CamelMaildirSummaryClass), + (CamelObjectClassInitFunc)camel_maildir_summary_class_init, + NULL, + (CamelObjectInitFunc)camel_maildir_summary_init, + (CamelObjectFinalizeFunc)camel_maildir_summary_finalise); + } + + return type; +} + +static void +camel_maildir_summary_class_init (CamelMaildirSummaryClass *class) +{ + CamelFolderSummaryClass *sklass = (CamelFolderSummaryClass *) class; + CamelLocalSummaryClass *lklass = (CamelLocalSummaryClass *)class; + + parent_class = (CamelLocalSummaryClass *)camel_type_get_global_classfuncs(camel_local_summary_get_type ()); + + /* override methods */ + sklass->message_info_new = message_info_new; + sklass->next_uid_string = maildir_summary_next_uid_string; + + lklass->check = maildir_summary_check; + lklass->sync = maildir_summary_sync; + /*lklass->add = maildir_summary_add;*/ +} + +static void +camel_maildir_summary_init (CamelMaildirSummary *o) +{ + struct _CamelFolderSummary *s = (CamelFolderSummary *) o; + char hostname[256]; + + o->priv = g_malloc0(sizeof(*o->priv)); + /* set unique file version */ + s->version += CAMEL_MAILDIR_SUMMARY_VERSION; + + if (gethostname(hostname, 256) == 0) { + o->priv->hostname = g_strdup(hostname); + } else { + o->priv->hostname = g_strdup("localhost"); + } +} + +static void +camel_maildir_summary_finalise(CamelObject *obj) +{ + CamelMaildirSummary *o = (CamelMaildirSummary *)obj; + + g_free(o->priv); +} + +/** + * camel_maildir_summary_new: + * + * Create a new CamelMaildirSummary object. + * + * Return value: A new #CamelMaildirSummary object. + **/ +CamelMaildirSummary *camel_maildir_summary_new (const char *filename, const char *maildirdir, ibex *index) +{ + CamelMaildirSummary *o = (CamelMaildirSummary *)camel_object_new(camel_maildir_summary_get_type ()); + + camel_local_summary_construct((CamelLocalSummary *)o, filename, maildirdir, index); + return o; +} + +static CamelMessageInfo *message_info_new(CamelFolderSummary * s, struct _header_raw *h) +{ + CamelMessageInfo *mi; + CamelMaildirSummary *mds = (CamelMaildirSummary *)s; + CamelMaildirMessageInfo *mdi; + + mi = ((CamelFolderSummaryClass *) parent_class)->message_info_new(s, h); + /* assign the uid and new filename */ + if (mi) { + mdi = (CamelMaildirMessageInfo *)mi; + + mi->uid = camel_folder_summary_next_uid_string(s); + + /* should store some status info in the filename, but we wont (yet) (fixme) */ + if (mds->priv->current_file) { + mdi->filename = g_strdup(mds->priv->current_file); + } else { + mdi->filename = g_strdup_printf("%s:2,", mi->uid); + } + } + + return mi; +} + +static char *maildir_summary_next_uid_string(CamelFolderSummary *s) +{ + CamelMaildirSummary *mds = (CamelMaildirSummary *)s; + /*CamelLocalSummary *cls = (CamelLocalSummary *)s;*/ + + /* current_file is more a current_filename, so map the filename to a uid */ + if (mds->priv->current_file) { + char *cln; + + cln = strchr(mds->priv->current_file, ':'); + if (cln) + return g_strndup(mds->priv->current_file, cln-mds->priv->current_file); + else + return g_strdup(mds->priv->current_file); + } else { + /* we use time.pid_count.hostname */ + return g_strdup_printf("%ld.%d_%u.%s", time(0), getpid(), camel_folder_summary_next_uid(s), mds->priv->hostname); + } +} + +static int camel_maildir_summary_add(CamelLocalSummary *cls, const char *name, int forceindex) +{ + CamelMaildirSummary *maildirs = (CamelMaildirSummary *)cls; + char *filename = g_strdup_printf("%s/cur/%s", cls->folder_path, name); + int fd; + CamelMimeParser *mp; + + d(printf("summarising: %s\n", name)); + + fd = open(filename, O_RDONLY); + if (fd == -1) { + g_warning("Cannot summarise/index: %s: %s", filename, strerror(errno)); + g_free(filename); + return -1; + } + mp = camel_mime_parser_new(); + camel_mime_parser_scan_from(mp, FALSE); + camel_mime_parser_init_with_fd(mp, fd); + if (cls->index && (forceindex || !ibex_contains_name(cls->index, (char *)name))) { + d(printf("forcing indexing of message content\n")); + camel_folder_summary_set_index((CamelFolderSummary *)maildirs, cls->index); + } else { + camel_folder_summary_set_index((CamelFolderSummary *)maildirs, NULL); + } + maildirs->priv->current_file = (char *)name; + camel_folder_summary_add_from_parser((CamelFolderSummary *)maildirs, mp); + camel_object_unref((CamelObject *)mp); + maildirs->priv->current_file = NULL; + camel_folder_summary_set_index((CamelFolderSummary *)maildirs, NULL); + g_free(filename); + return 0; +} + +static void +remove_summary(char *key, CamelMessageInfo *info, CamelLocalSummary *cls) +{ + d(printf("removing message %s from summary\n", key)); + if (cls->index) + ibex_unindex(cls->index, info->uid); + camel_folder_summary_remove((CamelFolderSummary *)cls, info); +} + +static int +maildir_summary_check(CamelLocalSummary *cls, CamelFolderChangeInfo *changes, CamelException *ex) +{ + DIR *dir; + struct dirent *d; + char *p; + CamelMessageInfo *info; + CamelMaildirMessageInfo *mdi; + CamelFolderSummary *s = (CamelFolderSummary *)cls; + GHashTable *left; + int i, count; + int forceindex; + char *new, *cur; + char *uid; + + new = g_strdup_printf("%s/new", cls->folder_path); + cur = g_strdup_printf("%s/cur", cls->folder_path); + + /* FIXME: Handle changeinfo */ + + d(printf("checking summary ...\n")); + + /* scan the directory, check for mail files not in the index, or index entries that + no longer exist */ + dir = opendir(cur); + if (dir == NULL) { + camel_exception_setv(ex, 1, "Cannot open maildir directory path: %s: %s", cls->folder_path, strerror(errno)); + g_free(cur); + g_free(new); + return -1; + } + + /* keeps track of all uid's that have not been processed */ + left = g_hash_table_new(g_str_hash, g_str_equal); + count = camel_folder_summary_count((CamelFolderSummary *)cls); + forceindex = count == 0; + for (i=0;iuid, info); + } + } + + while ( (d = readdir(dir)) ) { + /* FIXME: also run stat to check for regular file */ + p = d->d_name; + if (p[0] == '.') + continue; + + /* map the filename -> uid */ + uid = strchr(d->d_name, ':'); + if (uid) + uid = g_strndup(d->d_name, uid-d->d_name); + else + uid = g_strdup(d->d_name); + + info = camel_folder_summary_uid((CamelFolderSummary *)cls, uid); + if (info == NULL || (cls->index && (!ibex_contains_name(cls->index, uid)))) { + /* need to add this file to the summary */ + if (info != NULL) { + g_hash_table_remove(left, info->uid); + camel_folder_summary_remove((CamelFolderSummary *)cls, info); + } + camel_maildir_summary_add(cls, d->d_name, forceindex); + } else { + if (info) { + mdi = (CamelMaildirMessageInfo *)info; + /* TODO: only store the extension in the mdi->filename struct, not the whole lot */ + if (mdi->filename == NULL || strcmp(mdi->filename, d->d_name) != 0) { + g_free(mdi->filename); + mdi->filename = g_strdup(d->d_name); + } + } + g_hash_table_remove(left, info->uid); + } + g_free(uid); + } + closedir(dir); + g_hash_table_foreach(left, (GHFunc)remove_summary, cls); + g_hash_table_destroy(left); + + /* now, scan new for new messages, and copy them to cur, and so forth */ + dir = opendir(new); + if (dir != NULL) { + while ( (d = readdir(dir)) ) { + char *name, *newname, *destname, *destfilename; + char *src, *dest; + + name = d->d_name; + if (name[0] == '.') + continue; + + /* already in summary? shouldn't happen, but just incase ... */ + if (camel_folder_summary_uid((CamelFolderSummary *)cls, name)) + newname = destname = camel_folder_summary_next_uid_string(s); + else { + newname = NULL; + destname = name; + } + + /* copy this to the destination folder, use 'standard' semantics for maildir info field */ + src = g_strdup_printf("%s/%s", new, name); + destfilename = g_strdup_printf("%s:2,", destname); + dest = g_strdup_printf("%s/%s", cur, destfilename); + if (rename(src, dest) == 0) { + camel_maildir_summary_add(cls, destfilename, forceindex); + if (changes) + camel_folder_change_info_add_uid(changes, destname); + } else { + /* else? we should probably care about failures, but wont */ + g_warning("Failed to move new maildir message %s to cur %s", src, dest); + } + + /* c strings are painful to work with ... */ + g_free(destfilename); + g_free(newname); + g_free(src); + g_free(dest); + } + } + + g_free(new); + g_free(cur); + + /* FIXME: move this up a class? */ + + /* force a save of the index, just to make sure */ + /* note this could be expensive so possibly shouldn't be here + as such */ + if (cls->index) { + ibex_save(cls->index); + } + + return 0; +} + +/* sync the summary with the ondisk files. + It doesnt store the state in the file, the summary only, == MUCH faster */ +static int +maildir_summary_sync(CamelLocalSummary *cls, gboolean expunge, CamelFolderChangeInfo *changes, CamelException *ex) +{ + int count, i; + CamelMessageInfo *info; + CamelMaildirMessageInfo *mdi; + char *name; + + d(printf("summary_sync(expunge=%s)\n", expunge?"true":"false")); + + if (cls->index) { + ibex_save(cls->index); + } + if (!expunge) + return 0; + + count = camel_folder_summary_count((CamelFolderSummary *)cls); + for (i=count-1;i>=0;i--) { + info = camel_folder_summary_index((CamelFolderSummary *)cls, i); + if (info && info->flags & CAMEL_MESSAGE_DELETED) { + mdi = (CamelMaildirMessageInfo *)info; + name = g_strdup_printf("%s/cur/%s", cls->folder_path, mdi->filename); + d(printf("deleting %s\n", name)); + if (unlink(name) == 0 || errno==ENOENT) { + + /* FIXME: put this in folder_summary::remove()? */ + if (cls->index) + ibex_unindex(cls->index, info->uid); + + camel_folder_change_info_remove_uid(changes, info->uid); + camel_folder_summary_remove((CamelFolderSummary *)cls, info); + } + } + } + return 0; +} + diff --git a/camel/providers/local/camel-maildir-summary.h b/camel/providers/local/camel-maildir-summary.h new file mode 100644 index 0000000000..e1f00ac385 --- /dev/null +++ b/camel/providers/local/camel-maildir-summary.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2000 Helix Code Inc. + * + * Authors: Not Zed + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library 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 Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _CAMEL_MAILDIR_SUMMARY_H +#define _CAMEL_MAILDIR_SUMMARY_H + +#include "camel-local-summary.h" +#include +#include +#include + +#define CAMEL_MAILDIR_SUMMARY(obj) CAMEL_CHECK_CAST (obj, camel_maildir_summary_get_type (), CamelMaildirSummary) +#define CAMEL_MAILDIR_SUMMARY_CLASS(klass) CAMEL_CHECK_CLASS_CAST (klass, camel_maildir_summary_get_type (), CamelMaildirSummaryClass) +#define IS_CAMEL_MAILDIR_SUMMARY(obj) CAMEL_CHECK_TYPE (obj, camel_maildir_summary_get_type ()) + +typedef struct _CamelMaildirSummary CamelMaildirSummary; +typedef struct _CamelMaildirSummaryClass CamelMaildirSummaryClass; + +typedef struct _CamelMaildirMessageContentInfo { + CamelMessageContentInfo info; +} CamelMaildirMessageContentInfo; + +typedef struct _CamelMaildirMessageInfo { + CamelMessageInfo info; + + char *filename; /* maildir has this annoying status shit on the end of the filename, use this to get the real message id */ +} CamelMaildirMessageInfo; + +struct _CamelMaildirSummary { + CamelLocalSummary parent; + struct _CamelMaildirSummaryPrivate *priv; +}; + +struct _CamelMaildirSummaryClass { + CamelLocalSummaryClass parent_class; + + /* virtual methods */ + + /* signals */ +}; + +CamelType camel_maildir_summary_get_type (void); +CamelMaildirSummary *camel_maildir_summary_new (const char *filename, const char *maildirdir, ibex *index); + +#endif /* ! _CAMEL_MAILDIR_SUMMARY_H */ + diff --git a/camel/providers/local/camel-mh-folder.c b/camel/providers/local/camel-mh-folder.c index 64f9bbee81..c3b74dc3d6 100644 --- a/camel/providers/local/camel-mh-folder.c +++ b/camel/providers/local/camel-mh-folder.c @@ -149,14 +149,19 @@ static void mh_append_message(CamelFolder * folder, CamelMimeMessage * message, return; } - if (camel_data_wrapper_write_to_stream((CamelDataWrapper *)message, output_stream) == -1) { + if (camel_data_wrapper_write_to_stream((CamelDataWrapper *)message, output_stream) == -1 + || camel_stream_close(output_stream) == -1) { camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot append message to mh folder: %s: %s"), name, g_strerror(errno)); camel_object_unref((CamelObject *)output_stream); + unlink(name); g_free(name); return; } + /* close this? */ + camel_object_unref((CamelObject *)output_stream); + g_free(name); camel_object_trigger_event((CamelObject *)folder, "folder_changed", ((CamelLocalFolder *)mh_folder)->changes); diff --git a/camel/providers/local/camel-mh-folder.h b/camel/providers/local/camel-mh-folder.h index 4940230952..f9c30db6ca 100644 --- a/camel/providers/local/camel-mh-folder.h +++ b/camel/providers/local/camel-mh-folder.h @@ -1,7 +1,4 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-mh-folder.h : MH folder. */ - -/* +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Authors: * Michael Zucchi diff --git a/camel/providers/local/camel-mh-store.h b/camel/providers/local/camel-mh-store.h index 80c5ee0c28..937fe50d1c 100644 --- a/camel/providers/local/camel-mh-store.h +++ b/camel/providers/local/camel-mh-store.h @@ -1,7 +1,4 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* camel-mh-store.h : class for an mh store */ - -/* +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Copyright (C) 2000 Helix Code, Inc. * diff --git a/camel/providers/local/libcamellocal.urls b/camel/providers/local/libcamellocal.urls index 141aa7caf5..35a7049145 100644 --- a/camel/providers/local/libcamellocal.urls +++ b/camel/providers/local/libcamellocal.urls @@ -1,2 +1,3 @@ mh mbox +maildir -- cgit v1.2.3