diff options
Diffstat (limited to 'mail/mail-local.c')
-rw-r--r-- | mail/mail-local.c | 1529 |
1 files changed, 0 insertions, 1529 deletions
diff --git a/mail/mail-local.c b/mail/mail-local.c deleted file mode 100644 index e71a3315c2..0000000000 --- a/mail/mail-local.c +++ /dev/null @@ -1,1529 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* mail-local.c: Local mailbox support. */ - -/* - * Authors: - * Michael Zucchi <NotZed@ximian.com> - * Peter Williams <peterw@ximian.com> - * Ettore Perazzoli <ettore@ximian.com> - * Dan Winship <danw@ximian.com> - * - * Copyright 2000 Ximian, Inc. (www.ximian.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * 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 <string.h> -#include <unistd.h> -#include <errno.h> - -#include <libxml/xmlmemory.h> -#include <glade/glade.h> - -#include "e-util/e-path.h" -#include <gal/widgets/e-gui-utils.h> -#include <gal/util/e-xml-utils.h> - -#include "Evolution.h" -#include "evolution-storage.h" -#include "evolution-shell-component.h" -#include "evolution-storage-listener.h" - -#include "camel/camel.h" -#include "camel/camel-vtrash-folder.h" - -#include "mail.h" -#include "mail-local.h" -#include "mail-tools.h" -#include "mail-mt.h" -#include "mail-folder-cache.h" -#include "mail-vfolder.h" -#include "mail-ops.h" - -#define d(x) - -/* sigh, required for passing around to some functions */ -static GNOME_Evolution_Storage local_corba_storage = CORBA_OBJECT_NIL; - -/* ** MailLocalStore ** (protos) ************************************************** */ - -#define MAIL_LOCAL_STORE_TYPE (mail_local_store_get_type ()) -#define MAIL_LOCAL_STORE(obj) (CAMEL_CHECK_CAST((obj), MAIL_LOCAL_STORE_TYPE, MailLocalStore)) -#define MAIL_LOCAL_STORE_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), MAIL_LOCAL_STORE_TYPE, MailLocalStoreClass)) -#define MAIL_IS_LOCAL_STORE(o) (CAMEL_CHECK_TYPE((o), MAIL_LOCAL_STORE_TYPE)) - -typedef struct { - CamelStore parent_object; - - /* stores CamelFolderInfo's of the folders we're supposed to know about, by uri */ - GHashTable *folder_infos; - GMutex *folder_info_lock; - -} MailLocalStore; - -typedef struct { - CamelStoreClass parent_class; -} MailLocalStoreClass; - -static CamelType mail_local_store_get_type (void); - -static MailLocalStore *global_local_store; - -/* ** MailLocalFolder ** (protos) ************************************************* */ - -#define MAIL_LOCAL_FOLDER_TYPE (mail_local_folder_get_type ()) -#define MAIL_LOCAL_FOLDER(obj) (CAMEL_CHECK_CAST((obj), MAIL_LOCAL_FOLDER_TYPE, MailLocalFolder)) -#define MAIL_LOCAL_FOLDER_CLASS(k) (CAMEL_CHECK_CLASS_CAST ((k), MAIL_LOCAL_FOLDER_TYPE, MailLocalFolderClass)) -#define MAIL_IS_LOCAL_FOLDER(o) (CAMEL_CHECK_TYPE((o), MAIL_LOCAL_FOLDER_TYPE)) - -#define LOCAL_STORE_LOCK(folder) (g_mutex_lock (((MailLocalStore *)folder)->folder_info_lock)) -#define LOCAL_STORE_UNLOCK(folder) (g_mutex_unlock (((MailLocalStore *)folder)->folder_info_lock)) - -struct _local_meta { - char *path; /* path of metainfo */ - - char *format; /* format of mailbox */ - char *name; /* name of actual mbox */ - int indexed; /* is body indexed? */ -}; - -typedef struct { - CamelFolder parent_object; - - CamelFolder *real_folder; - CamelStore *real_store; - - char *description; - char *real_path; - - struct _local_meta *meta; - - GMutex *real_folder_lock; /* no way to use the CamelFolder's lock, so... */ -} MailLocalFolder; - -typedef struct { - CamelFolderClass parent_class; -} MailLocalFolderClass; - -static CamelType mail_local_folder_get_type (void); - -#ifdef ENABLE_THREADS -#define LOCAL_FOLDER_LOCK(folder) (g_mutex_lock (((MailLocalFolder *)folder)->real_folder_lock)) -#define LOCAL_FOLDER_UNLOCK(folder) (g_mutex_unlock (((MailLocalFolder *)folder)->real_folder_lock)) -#else -#define LOCAL_FOLDER_LOCK(folder) -#define LOCAL_FOLDER_UNLOCK(folder) -#endif - -/* ** MailLocalFolder ************************************************************* */ - -static struct _local_meta * -load_metainfo(const char *path) -{ - xmlDocPtr doc; - xmlNodePtr node; - struct _local_meta *meta; - - d(printf("Loading folder metainfo from : %s\n", path)); - - meta = g_malloc0(sizeof(*meta)); - meta->path = g_strdup(path); - - doc = xmlParseFile(path); - if (doc == NULL) - goto dodefault; - - node = doc->children; - if (strcmp(node->name, "folderinfo")) - goto dodefault; - - node = node->children; - while (node) { - if (!strcmp(node->name, "folder")) { - char *index, *txt; - - txt = xmlGetProp(node, "type"); - meta->format = g_strdup(txt?txt:"mbox"); - xmlFree(txt); - - txt = xmlGetProp(node, "name"); - meta->name = g_strdup(txt?txt:"mbox"); - xmlFree(txt); - - index = xmlGetProp(node, "index"); - if (index) { - meta->indexed = atoi(index); - xmlFree(index); - } else - meta->indexed = TRUE; - - } - node = node->next; - } - xmlFreeDoc(doc); - return meta; - - dodefault: - meta->format = g_strdup("mbox"); /* defaults */ - meta->name = g_strdup("mbox"); - meta->indexed = TRUE; - xmlFreeDoc(doc); - return meta; -} - -static void -free_metainfo(struct _local_meta *meta) -{ - g_free(meta->path); - g_free(meta->format); - g_free(meta->name); - g_free(meta); -} - -static gboolean -save_metainfo (struct _local_meta *meta) -{ - xmlDocPtr doc; - xmlNodePtr root, node; - int ret; - - d(printf("Saving folder metainfo to : %s\n", meta->path)); - - doc = xmlNewDoc("1.0"); - root = xmlNewDocNode(doc, NULL, "folderinfo", NULL); - xmlDocSetRootElement(doc, root); - - node = xmlNewChild(root, NULL, "folder", NULL); - xmlSetProp(node, "type", meta->format); - xmlSetProp(node, "name", meta->name); - xmlSetProp(node, "index", meta->indexed?"1":"0"); - - ret = e_xml_save_file (meta->path, doc); - - xmlFreeDoc (doc); - - return ret == -1 ? FALSE : TRUE; -} - -static CamelFolderClass *mlf_parent_class = NULL; - -/* forward a bunch of functions to the real folder. This pretty - * much sucks but I haven't found a better way of doing it. - */ - -/* We need to do it without having locked our folder, otherwise - we can get sync hangs with vfolders/trash */ -static void -mlf_refresh_info(CamelFolder *folder, CamelException *ex) -{ - MailLocalFolder *mlf = MAIL_LOCAL_FOLDER(folder); - CamelFolder *f; - - LOCAL_FOLDER_LOCK(mlf); - f = mlf->real_folder; - camel_object_ref(f); - LOCAL_FOLDER_UNLOCK(mlf); - - camel_folder_refresh_info(f, ex); - camel_object_unref(f); -} - -static void -mlf_sync(CamelFolder *folder, gboolean expunge, CamelException *ex) -{ - MailLocalFolder *mlf = MAIL_LOCAL_FOLDER(folder); - CamelFolder *f; - - LOCAL_FOLDER_LOCK(mlf); - f = mlf->real_folder; - camel_object_ref(f); - LOCAL_FOLDER_UNLOCK(mlf); - - camel_folder_sync(f, expunge, ex); - camel_object_unref(f); -} - -static void -mlf_expunge(CamelFolder *folder, CamelException *ex) -{ - MailLocalFolder *mlf = MAIL_LOCAL_FOLDER(folder); - CamelFolder *f; - - LOCAL_FOLDER_LOCK(mlf); - f = mlf->real_folder; - camel_object_ref(f); - LOCAL_FOLDER_UNLOCK(mlf); - - camel_folder_expunge(f, ex); - camel_object_unref(f); -} - -static void -mlf_append_message(CamelFolder *folder, CamelMimeMessage *message, const CamelMessageInfo *info, char **appended_uid, CamelException *ex) -{ - MailLocalFolder *mlf = MAIL_LOCAL_FOLDER(folder); - CamelFolder *f; - - LOCAL_FOLDER_LOCK(mlf); - f = mlf->real_folder; - camel_object_ref(f); - LOCAL_FOLDER_UNLOCK(mlf); - - camel_folder_append_message(f, message, info, appended_uid, ex); - camel_object_unref(f); -} - -static CamelMimeMessage * -mlf_get_message(CamelFolder *folder, const char *uid, CamelException *ex) -{ - MailLocalFolder *mlf = MAIL_LOCAL_FOLDER(folder); - CamelMimeMessage *ret; - CamelFolder *f; - - LOCAL_FOLDER_LOCK(mlf); - f = mlf->real_folder; - camel_object_ref(f); - LOCAL_FOLDER_UNLOCK(mlf); - - ret = camel_folder_get_message(f, uid, ex); - camel_object_unref(f); - - return ret; -} - -static GPtrArray * -mlf_search_by_expression(CamelFolder *folder, const char *expression, CamelException *ex) -{ - MailLocalFolder *mlf = MAIL_LOCAL_FOLDER (folder); - GPtrArray *ret; - CamelFolder *f; - - LOCAL_FOLDER_LOCK(mlf); - f = mlf->real_folder; - camel_object_ref(f); - LOCAL_FOLDER_UNLOCK(mlf); - - ret = camel_folder_search_by_expression(f, expression, ex); - camel_object_unref(f); - - return ret; -} - -static GPtrArray * -mlf_search_by_uids(CamelFolder *folder, const char *expression, GPtrArray *uids, CamelException *ex) -{ - MailLocalFolder *mlf = MAIL_LOCAL_FOLDER (folder); - GPtrArray *ret; - CamelFolder *f; - - LOCAL_FOLDER_LOCK(mlf); - f = mlf->real_folder; - camel_object_ref(f); - LOCAL_FOLDER_UNLOCK(mlf); - - ret = camel_folder_search_by_uids(f, expression, uids, ex); - camel_object_unref(f); - - return ret; -} - -static void -mlf_search_free(CamelFolder *folder, GPtrArray *result) -{ - MailLocalFolder *mlf = MAIL_LOCAL_FOLDER(folder); - CamelFolder *f; - - LOCAL_FOLDER_LOCK(mlf); - f = mlf->real_folder; - camel_object_ref(f); - LOCAL_FOLDER_UNLOCK(mlf); - - camel_folder_search_free(f, result); - camel_object_unref(f); -} - -static void -mlf_set_message_flags(CamelFolder *folder, const char *uid, guint32 flags, guint32 set) -{ - MailLocalFolder *mlf = MAIL_LOCAL_FOLDER(folder); - CamelFolder *f; - - LOCAL_FOLDER_LOCK(mlf); - f = mlf->real_folder; - camel_object_ref(f); - LOCAL_FOLDER_UNLOCK(mlf); - - camel_folder_set_message_flags(mlf->real_folder, uid, flags, set); - camel_object_unref(f); -} - -static void -mlf_set_message_user_flag(CamelFolder *folder, const char *uid, const char *name, gboolean value) -{ - MailLocalFolder *mlf = MAIL_LOCAL_FOLDER(folder); - CamelFolder *f; - - LOCAL_FOLDER_LOCK(mlf); - f = mlf->real_folder; - camel_object_ref(f); - LOCAL_FOLDER_UNLOCK(mlf); - - camel_folder_set_message_user_flag(mlf->real_folder, uid, name, value); - camel_object_unref(f); -} - -static void -mlf_set_message_user_tag(CamelFolder *folder, const char *uid, const char *name, const char *value) -{ - MailLocalFolder *mlf = MAIL_LOCAL_FOLDER(folder); - CamelFolder *f; - - LOCAL_FOLDER_LOCK(mlf); - f = mlf->real_folder; - camel_object_ref(f); - LOCAL_FOLDER_UNLOCK(mlf); - - camel_folder_set_message_user_tag(mlf->real_folder, uid, name, value); - camel_object_unref(f); -} - -/* Internal store-rename call, update our strings */ -static void -mlf_rename(CamelFolder *folder, const char *new) -{ - MailLocalFolder *mlf = (MailLocalFolder *)folder; - - /* first, proxy it down */ - if (mlf->real_folder) { - char *mbox = g_strdup_printf("%s/%s", new, mlf->meta->name); - - d(printf("renaming real folder to %s\n", mbox)); - - camel_folder_rename(mlf->real_folder, mbox); - g_free(mbox); - } - - /* Then do our stuff */ - g_free(mlf->real_path); - mlf->real_path = g_strdup(new); - - g_free(mlf->meta->path); - mlf->meta->path = g_strdup_printf("%s/%s/local-metadata.xml", ((CamelService *)folder->parent_store)->url->path, new); - - /* Then pass it up */ - ((CamelFolderClass *)mlf_parent_class)->rename(folder, new); -} - -/* and, conversely, forward the real folder's signals. */ - -static void -mlf_proxy_message_changed(CamelObject *real_folder, gpointer event_data, gpointer user_data) -{ - camel_object_trigger_event(user_data, "message_changed", event_data); -} - -static void -mlf_proxy_folder_changed(CamelObject *real_folder, gpointer event_data, gpointer user_data) -{ - camel_object_trigger_event(user_data, "folder_changed", event_data); -} - -static void -mlf_unset_folder (MailLocalFolder *mlf) -{ - CamelFolder *folder = (CamelFolder *)mlf; - - g_assert(mlf->real_folder); - - camel_object_unhook_event(mlf->real_folder, - "message_changed", - mlf_proxy_message_changed, - mlf); - camel_object_unhook_event(mlf->real_folder, - "folder_changed", - mlf_proxy_folder_changed, - mlf); - - camel_object_unref(folder->summary); - folder->summary = NULL; - camel_object_unref(mlf->real_folder); - mlf->real_folder = NULL; - camel_object_unref(mlf->real_store); - mlf->real_store = NULL; - - folder->permanent_flags = 0; - folder->folder_flags = 0; -} - -static gboolean -mlf_set_folder(MailLocalFolder *mlf, guint32 flags, CamelException *ex) -{ - CamelFolder *folder = (CamelFolder *)mlf; - char *uri, *mbox; - - g_assert(mlf->real_folder == NULL); - - uri = g_strdup_printf("%s:%s", mlf->meta->format, ((CamelService *)folder->parent_store)->url->path); - - d(printf("opening real store: %s\n", uri)); - mlf->real_store = camel_session_get_store(session, uri, ex); - g_free(uri); - if (mlf->real_store == NULL) - return FALSE; - - if (mlf->meta->indexed) - flags |= CAMEL_STORE_FOLDER_BODY_INDEX; - - /* mlf->real_folder = camel_store_get_folder(mlf->real_store, mlf->meta->name, flags, ex); */ - mbox = g_strdup_printf("%s/%s", mlf->real_path, mlf->meta->name); - d(printf("Opening mbox on real path: %s\n", mbox)); - mlf->real_folder = camel_store_get_folder(mlf->real_store, mbox, flags, ex); - g_free(mbox); - if (mlf->real_folder == NULL) - return FALSE; - - if (mlf->real_folder->folder_flags & CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY) { - folder->summary = mlf->real_folder->summary; - camel_object_ref(mlf->real_folder->summary); - } - - folder->permanent_flags = mlf->real_folder->permanent_flags; - folder->folder_flags = mlf->real_folder->folder_flags; - - camel_object_hook_event(mlf->real_folder, "message_changed", mlf_proxy_message_changed, mlf); - camel_object_hook_event(mlf->real_folder, "folder_changed", mlf_proxy_folder_changed, mlf); - - return TRUE; -} - -static int -mlf_getv(CamelObject *object, CamelException *ex, CamelArgGetV *args) -{ - CamelFolder *folder = (CamelFolder *)object; - MailLocalFolder *mlf = (MailLocalFolder *)object; - int i, count=args->argc; - guint32 tag; - - for (i=0;i<args->argc;i++) { - CamelArgGet *arg = &args->argv[i]; - - tag = arg->tag; - - switch (tag & CAMEL_ARG_TAG) { - /* CamelObject args */ - case CAMEL_OBJECT_ARG_DESCRIPTION: - if (mlf->description == NULL) { - int pathlen; - - /* string to describe a local folder as the location of a message */ - pathlen = strlen(evolution_dir) + strlen("local") + 1; - if (strlen(folder->full_name) > pathlen) - mlf->description = g_strdup_printf(_("Local folders/%s"), folder->full_name+pathlen); - else - mlf->description = g_strdup_printf(_("Local folders/%s"), folder->name); - } - *arg->ca_str = mlf->description; - break; - default: - count--; - continue; - } - - arg->tag = (tag & CAMEL_ARG_TYPE) | CAMEL_ARG_IGNORE; - } - - if (count) - return ((CamelObjectClass *)mlf_parent_class)->getv(object, ex, args); - - return 0; -} - -static void -mlf_class_init (CamelObjectClass *camel_object_class) -{ - CamelFolderClass *camel_folder_class = CAMEL_FOLDER_CLASS (camel_object_class); - - /* override all the functions subclassed in providers/local/ */ - - camel_folder_class->refresh_info = mlf_refresh_info; - camel_folder_class->sync = mlf_sync; - camel_folder_class->expunge = mlf_expunge; - camel_folder_class->append_message = mlf_append_message; - camel_folder_class->get_message = mlf_get_message; - camel_folder_class->search_free = mlf_search_free; - - camel_folder_class->search_by_expression = mlf_search_by_expression; - camel_folder_class->search_by_uids = mlf_search_by_uids; - camel_folder_class->set_message_flags = mlf_set_message_flags; - camel_folder_class->set_message_user_flag = mlf_set_message_user_flag; - camel_folder_class->set_message_user_tag = mlf_set_message_user_tag; - - camel_folder_class->rename = mlf_rename; - - camel_object_class->getv = mlf_getv; -} - -static void -mlf_init (CamelObject *obj, CamelObjectClass *klass) -{ - MailLocalFolder *mlf = MAIL_LOCAL_FOLDER (obj); - -#ifdef ENABLE_THREADS - mlf->real_folder_lock = g_mutex_new(); -#endif -} - -static void -mlf_finalize (CamelObject *obj) -{ - MailLocalFolder *mlf = MAIL_LOCAL_FOLDER (obj); - - if (mlf->real_folder) - mlf_unset_folder(mlf); - - free_metainfo(mlf->meta); - - g_free (mlf->real_path); - -#ifdef ENABLE_THREADS - g_mutex_free (mlf->real_folder_lock); -#endif -} - -static CamelType -mail_local_folder_get_type (void) -{ - static CamelType mail_local_folder_type = CAMEL_INVALID_TYPE; - - if (mail_local_folder_type == CAMEL_INVALID_TYPE) { - mail_local_folder_type = camel_type_register(CAMEL_FOLDER_TYPE, - "MailLocalFolder", - sizeof (MailLocalFolder), - sizeof (MailLocalFolderClass), - mlf_class_init, - NULL, - mlf_init, - mlf_finalize); - mlf_parent_class = (CamelFolderClass *)CAMEL_FOLDER_TYPE; - } - - return mail_local_folder_type; -} - -static MailLocalFolder * -mail_local_folder_construct(MailLocalFolder *mlf, MailLocalStore *parent_store, const char *full_name, CamelException *ex) -{ - char *metapath, *name; - - name = g_path_get_basename (full_name); - d(printf ("constructing local folder: full = %s, name = %s\n", full_name, name)); - camel_folder_construct (CAMEL_FOLDER (mlf), CAMEL_STORE (parent_store), full_name, name); - g_free (name); - - mlf->real_path = g_strdup (((CamelFolder *) mlf)->full_name); - - metapath = g_strdup_printf ("%s/%s/local-metadata.xml", ((CamelService *) parent_store)->url->path, full_name); - mlf->meta = load_metainfo (metapath); - g_free (metapath); - - return mlf; -} - -static gboolean -mail_local_folder_reconfigure (MailLocalFolder *mlf, const char *new_format, int index_body, CamelException *ex) -{ - CamelStore *fromstore = NULL; - CamelFolder *fromfolder = NULL; - char *oldformat = NULL; - char *store_uri; - GPtrArray *uids; - int real_folder_frozen = FALSE; - int format_change, index_changed; - char *tmpname = NULL; - char *mbox = NULL; - - format_change = strcmp(mlf->meta->format, new_format) != 0; - index_changed = mlf->meta->indexed != index_body; - - if (format_change == FALSE && index_changed == FALSE) - return TRUE; - - camel_operation_start(NULL, _("Reconfiguring folder")); - - /* first things first */ - g_assert (ex); - LOCAL_FOLDER_LOCK (mlf); - - /* first, 'close' the old folder */ - if (mlf->real_folder) { - camel_folder_sync(mlf->real_folder, FALSE, ex); - if (camel_exception_is_set (ex)) - goto cleanup; - mlf_unset_folder(mlf); - } - - /* only indexed change, just re-open with new flags */ - if (!format_change) { - mlf->meta->indexed = index_body; - mlf_set_folder(mlf, CAMEL_STORE_FOLDER_CREATE, ex); - save_metainfo(mlf->meta); - goto cleanup; - } - - store_uri = g_strdup_printf("%s:%s", mlf->meta->format, ((CamelService *)((CamelFolder *)mlf)->parent_store)->url->path); - fromstore = camel_session_get_store(session, store_uri, ex); - g_free(store_uri); - if (fromstore == NULL) - goto cleanup; - - oldformat = mlf->meta->format; - mlf->meta->format = g_strdup(new_format); - - /* rename the old mbox and open it again, without indexing */ - tmpname = g_strdup_printf ("%s/%s_reconfig", mlf->real_path, mlf->meta->name); - mbox = g_strdup_printf("%s/%s", mlf->real_path, mlf->meta->name); - d(printf("renaming %s to %s, and opening it\n", mbox, tmpname)); - - camel_store_rename_folder(fromstore, mbox, tmpname, ex); - if (camel_exception_is_set(ex)) - goto cleanup; - - /* we dont need to set the create flag ... or need an index if it has one */ - fromfolder = camel_store_get_folder(fromstore, tmpname, 0, ex); - if (fromfolder == NULL || camel_exception_is_set(ex)) { - /* try and recover ... */ - camel_exception_clear(ex); - camel_store_rename_folder(fromstore, tmpname, mbox, ex); - goto cleanup; - } - - /* create a new mbox */ - d(printf("Creating the destination mbox\n")); - - if (!mlf_set_folder(mlf, CAMEL_STORE_FOLDER_CREATE, ex)) { - d(printf("cannot open destination folder\n")); - /* try and recover ... */ - camel_exception_clear(ex); - camel_store_rename_folder(fromstore, tmpname, mbox, ex); - goto cleanup; - } - - real_folder_frozen = TRUE; - camel_folder_freeze(mlf->real_folder); - - uids = camel_folder_get_uids(fromfolder); - camel_folder_transfer_messages_to(fromfolder, uids, mlf->real_folder, NULL, TRUE, ex); - camel_folder_free_uids(fromfolder, uids); - if (camel_exception_is_set(ex)) - goto cleanup; - - camel_folder_expunge(fromfolder, ex); - - d(printf("delete old mbox ...\n")); - camel_object_unref(fromfolder); - fromfolder = NULL; - camel_store_delete_folder(fromstore, tmpname, ex); - - /* switch format */ - g_free(oldformat); - oldformat = NULL; - if (save_metainfo(mlf->meta) == FALSE) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Cannot save folder metainfo; " - "you may find you can't\n" - "open this folder anymore: %s: %s"), - mlf->meta->path, strerror(errno)); - } - - cleanup: - if (oldformat) { - g_free(mlf->meta->format); - mlf->meta->format = oldformat; - } - if (mlf->real_folder == NULL) - mlf_set_folder (mlf, CAMEL_STORE_FOLDER_CREATE, ex); - if (fromfolder) - camel_object_unref(fromfolder); - if (fromstore) - camel_object_unref(fromstore); - - g_free(tmpname); - g_free(mbox); - - LOCAL_FOLDER_UNLOCK (mlf); - - if (real_folder_frozen) - camel_folder_thaw(mlf->real_folder); - - camel_operation_end(NULL); - - return !camel_exception_is_set(ex); -} - -/* ******************************************************************************** */ - -static CamelObjectClass *local_store_parent_class = NULL; - -static CamelFolder * -mls_get_folder(CamelStore *store, const char *folder_name, guint32 flags, CamelException *ex) -{ - MailLocalStore *local_store = MAIL_LOCAL_STORE (store); - MailLocalFolder *folder; - - d(printf("--LOCAL-- get_folder: %s\n", folder_name)); - - folder = (MailLocalFolder *)camel_object_new(MAIL_LOCAL_FOLDER_TYPE); - folder = mail_local_folder_construct(folder, local_store, folder_name, ex); - if (folder == NULL) - return NULL; - - if (!mlf_set_folder(folder, flags, ex)) { - camel_object_unref(folder); - return NULL; - } - - if (flags & CAMEL_STORE_FOLDER_CREATE) { - if (save_metainfo(folder->meta) == FALSE) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Cannot save folder metainfo to %s: %s"), - folder->meta->path, g_strerror(errno)); - camel_object_unref(folder); - return NULL; - } - } - - return (CamelFolder *)folder; -} - -static void -mls_delete_folder(CamelStore *store, const char *folder_name, CamelException *ex) -{ - CamelStore *real_store; - char *metapath, *uri, *mbox; - CamelException local_ex; - struct _local_meta *meta; - - d(printf("Deleting folder: %s %s\n", ((CamelService *)store)->url->path, folder_name)); - - camel_exception_init(&local_ex); - - /* find the real store for this folder, and proxy the call */ - metapath = g_strdup_printf("%s%s/local-metadata.xml", ((CamelService *)store)->url->path, folder_name); - meta = load_metainfo(metapath); - uri = g_strdup_printf("%s:%s", meta->format, ((CamelService *)store)->url->path); - real_store = (CamelStore *)camel_session_get_service(session, uri, CAMEL_PROVIDER_STORE, ex); - g_free(uri); - if (real_store == NULL) { - g_free(metapath); - free_metainfo(meta); - camel_object_unref(real_store); - return; - } - - mbox = g_strdup_printf("%s/%s", folder_name, meta->name); - camel_store_delete_folder(real_store, mbox, &local_ex); - g_free(mbox); - if (camel_exception_is_set(&local_ex)) { - camel_exception_xfer(ex, &local_ex); - g_free(metapath); - free_metainfo(meta); - camel_object_unref(real_store); - return; - } - - camel_object_unref((CamelObject *)real_store); - - free_metainfo(meta); - - if (unlink(metapath) == -1) { - camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, - _("Cannot delete folder metadata %s: %s"), - metapath, g_strerror(errno)); - } - - g_free(metapath); -} - -static void -mls_rename_folder(CamelStore *store, const char *old_name, const char *new_name, CamelException *ex) -{ - CamelStore *real_store; - /*MailLocalStore *mls = (MailLocalStore *)store;*/ - char *uri; - /*CamelException local_ex;*/ - struct _local_meta *meta; - char *oldname, *newname; - char *oldmeta, *newmeta; - struct stat st; - - /* folder:rename() updates all our in-memory data to match */ - - /* FIXME: Need to lock the subfolder that matches this if its open - Then rename it and unlock it when done */ - - d(printf("Renaming folder from '%s' to '%s'\n", old_name, new_name)); - - oldmeta = g_strdup_printf("%s%s/local-metadata.xml", ((CamelService *)store)->url->path, old_name); - newmeta = g_strdup_printf("%s%s/local-metadata.xml", ((CamelService *)store)->url->path, new_name); - - meta = load_metainfo(oldmeta); - uri = g_strdup_printf("%s:%s", meta->format, ((CamelService *)store)->url->path); - real_store = (CamelStore *)camel_session_get_service(session, uri, CAMEL_PROVIDER_STORE, ex); - g_free(uri); - if (real_store == NULL) { - g_free(newmeta); - g_free(oldmeta); - free_metainfo(meta); - return; - } - - oldname = g_strdup_printf("%s/%s", old_name, meta->name); - newname = g_strdup_printf("%s/%s", new_name, meta->name); - - camel_store_rename_folder(real_store, oldname, newname, ex); - if (!camel_exception_is_set(ex)) { - /* If this fails? Well, doesn't really matter but 'fail' anyway */ - if (stat(oldmeta, &st) == 0 - && rename(oldmeta, newmeta) == -1) { - camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, - _("Could not rename folder %s to %s: %s"), - old_name, new_name, strerror(errno)); - } else { - /* So .. .the shell does a remove/add now the rename worked, so we dont - have to do this. However totally broken that idea might be */ -#if 0 - CamelFolderInfo *info; - const char *tmp; - char *olduri, *newuri; - - olduri = g_strdup_printf("%s:%s%s", ((CamelService *)store)->url->protocol, ((CamelService *)store)->url->path, old_name); - newuri = g_strdup_printf("%s:%s%s", ((CamelService *)store)->url->protocol, ((CamelService *)store)->url->path, new_name); - info = g_hash_table_lookup(mls->folder_infos, olduri); - if (info) { - CamelRenameInfo reninfo; - - g_free(info->url); - g_free(info->full_name); - g_free(info->name); - g_free(info->path); - info->url = newuri; - info->full_name = g_strdup(new_name); - info->path = g_strdup_printf("/%s", new_name); - tmp = strchr(new_name, '/'); - if (tmp == NULL) - tmp = new_name; - info->name = g_strdup(tmp); - g_hash_table_insert(mls->folder_infos, info->url, info); - - reninfo.new = info; - reninfo.old_base = (char *)old_name; - - camel_object_trigger_event(store, "folder_renamed", &reninfo); - } else { - g_free(newuri); - g_warning("Cannot find existing folder '%s' in table?\n", olduri); - } - - g_free(olduri); -#endif - } - } - - g_free(newname); - g_free(oldname); - - camel_object_unref(real_store); - - free_metainfo(meta); - - g_free(newmeta); - g_free(oldmeta); -} - -static char * -mls_get_name (CamelService *service, gboolean brief) -{ - if (brief) - return g_strdup("local"); - - return g_strdup("Local mail folders"); -} - -static void -mls_init (MailLocalStore *mls, MailLocalStoreClass *mlsclass) -{ - mls->folder_infos = g_hash_table_new(g_str_hash, g_str_equal); - mls->folder_info_lock = g_mutex_new(); -} - -static void -free_info(void *key, void *value, void *data) -{ - CamelFolderInfo *info = value; - - camel_folder_info_free (info); -} - -static void -mls_finalise(MailLocalStore *mls) -{ - g_hash_table_foreach(mls->folder_infos, (GHFunc)free_info, NULL); - g_hash_table_destroy(mls->folder_infos); - g_mutex_free(mls->folder_info_lock); -} - -static void -mls_class_init (CamelObjectClass *camel_object_class) -{ - CamelStoreClass *camel_store_class = CAMEL_STORE_CLASS(camel_object_class); - CamelServiceClass *camel_service_class = CAMEL_SERVICE_CLASS(camel_object_class); - - /* virtual method overload -- the bare minimum */ - camel_service_class->get_name = mls_get_name; - camel_store_class->get_folder = mls_get_folder; - camel_store_class->delete_folder = mls_delete_folder; - camel_store_class->rename_folder = mls_rename_folder; - - local_store_parent_class = camel_type_get_global_classfuncs (CAMEL_STORE_TYPE); -} - -static CamelType -mail_local_store_get_type (void) -{ - static CamelType mail_local_store_type = CAMEL_INVALID_TYPE; - - if (mail_local_store_type == CAMEL_INVALID_TYPE) { - mail_local_store_type = camel_type_register ( - CAMEL_STORE_TYPE, "MailLocalStore", - sizeof (MailLocalStore), - sizeof (MailLocalStoreClass), - (CamelObjectClassInitFunc) mls_class_init, - NULL, - (CamelObjectInitFunc) mls_init, - (CamelObjectFinalizeFunc) mls_finalise); - } - - return mail_local_store_type; -} - -static void mail_local_store_add_folder(MailLocalStore *mls, const char *uri, const char *path, const char *name) -{ - CamelFolderInfo *info = NULL; - CamelURL *url; - - d(printf("Shell adding folder: '%s' path = '%s'\n", uri, path)); - - url = camel_url_new(uri, NULL); - if (url == NULL) { - g_warning("Shell trying to add invalid folder url: %s", uri); - return; - } - if (url->path == NULL || url->path[0] == 0) { - g_warning("Shell trying to add invalid folder url: %s", uri); - camel_url_free(url); - return; - } - - LOCAL_STORE_LOCK(mls); - - if (g_hash_table_lookup(mls->folder_infos, uri)) { - g_warning("Shell trying to add a folder I already have!"); - } else { - info = g_malloc0(sizeof(*info)); - info->url = g_strdup(uri); - info->full_name = g_strdup(url->path+1); - info->name = g_strdup(name); - info->unread_message_count = -1; - info->path = g_strdup (path); - g_hash_table_insert(mls->folder_infos, info->url, info); - } - - LOCAL_STORE_UNLOCK(mls); - - camel_url_free(url); - - if (info) { - /* FIXME: should copy info, so we dont get a removed while we're using it? */ - camel_object_trigger_event(mls, "folder_created", info); - - /* this is just so the folder is opened at least once to setup the folder - counts etc in the display. Joy eh? The result is discarded. */ - mail_get_folder (uri, CAMEL_STORE_FOLDER_CREATE, NULL, NULL, mail_thread_queued_slow); - } -} - -struct _search_info { - const char *path; - CamelFolderInfo *info; -}; - -static void -remove_find_path(char *uri, CamelFolderInfo *info, struct _search_info *data) -{ - if (!strcmp(info->path, data->path)) - data->info = info; -} - -static void mail_local_store_remove_folder(MailLocalStore *mls, const char *path) -{ - struct _search_info data = { path, NULL }; - - d(printf("shell removing folder? '%s'\n", path)); - - /* we're keyed on uri, not path, so have to search for it manually */ - - LOCAL_STORE_LOCK(mls); - g_hash_table_foreach(mls->folder_infos, (GHFunc)remove_find_path, &data); - if (data.info) - g_hash_table_remove(mls->folder_infos, data.info->url); - LOCAL_STORE_UNLOCK(mls); - - if (data.info) { - camel_object_trigger_event(mls, "folder_deleted", data.info); - - g_free(data.info->url); - g_free(data.info->full_name); - g_free(data.info->name); - g_free(data.info); - } -} - -/* ** Local Provider ************************************************************** */ - -static CamelProvider local_provider = { - "file", "Local mail", "Local mailbox file", "mail", - CAMEL_PROVIDER_IS_STORAGE | CAMEL_PROVIDER_IS_EXTERNAL, - CAMEL_URL_NEED_PATH, - /* ... */ -}; - -/* There's only one "file:" store. */ -static guint -non_hash (gconstpointer key) -{ - return 0; -} - -static gint -non_equal (gconstpointer ap, gconstpointer bp) -{ - const CamelURL *a = ap, *b = bp; - - return strcmp(a->protocol, "file") == 0 - && strcmp(a->protocol, b->protocol) == 0; -} - -static void -mail_local_provider_init (void) -{ - /* Register with Camel to handle file: URLs */ - local_provider.object_types[CAMEL_PROVIDER_STORE] = MAIL_LOCAL_STORE_TYPE; - - local_provider.url_hash = non_hash; - local_provider.url_equal = non_equal; - camel_session_register_provider (session, &local_provider); -} - -/* ** Local Storage Listener ****************************************************** */ - -static void -local_storage_destroyed_cb (EvolutionStorageListener *storage_listener, - void *data) -{ - CORBA_Environment ev; - - CORBA_exception_init (&ev); - bonobo_object_release_unref (data, &ev); - CORBA_exception_free (&ev); -} - - -static void -local_storage_new_folder_cb (EvolutionStorageListener *storage_listener, - const char *path, - const GNOME_Evolution_Folder *folder, - void *data) -{ - d(printf("Local folder new:\n")); - d(printf(" path = '%s'\n uri = '%s'\n display = '%s'\n", - path, folder->physicalUri, folder->displayName)); - - /* We dont actually add the trash to our local folders list, get_trash is handled - outside our internal folder list */ - - if (strcmp(folder->type, "mail") == 0) { - mail_local_store_add_folder(global_local_store, folder->physicalUri, path, folder->displayName); - } else if (strcmp(folder->type, "vtrash") == 0) { - CamelFolderInfo info; - CamelURL *url; - - url = camel_url_new(folder->physicalUri, NULL); - if (url == NULL) { - g_warning("Shell trying to add invalid folder url: %s", folder->physicalUri); - return; - } - if (url->path == NULL || url->path[0] == 0) { - g_warning("Shell trying to add invalid folder url: %s", folder->physicalUri); - camel_url_free(url); - return; - } - - memset(&info, 0, sizeof(info)); - info.full_name = CAMEL_VTRASH_NAME; - info.name = folder->displayName; - info.url = g_strdup_printf("vtrash:%s", folder->physicalUri); - info.unread_message_count = 0; - info.path = (char *)path; - - camel_object_trigger_event(global_local_store, "folder_created", &info); - g_free(info.url); - camel_url_free(url); - } -} - - -static void -local_storage_removed_folder_cb (EvolutionStorageListener *storage_listener, - const char *path, - void *data) -{ - d(printf("Local folder remove:\n")); - d(printf(" path = '%s'\n", path)); - - mail_local_store_remove_folder(global_local_store, path); -} - -static void -storage_listener_startup (EvolutionShellClient *shellclient) -{ - EvolutionStorageListener *local_storage_listener; - GNOME_Evolution_StorageListener corba_local_storage_listener; - GNOME_Evolution_Storage corba_storage; - CORBA_Environment ev; - - d(printf("---- CALLING STORAGE LISTENER STARTUP ---\n")); - - local_corba_storage = corba_storage = evolution_shell_client_get_local_storage (shellclient); - if (corba_storage == CORBA_OBJECT_NIL) { - g_warning ("No local storage available from shell client!"); - return; - } - - /* setup to record this store's changes */ - mail_note_store((CamelStore *)global_local_store, NULL, local_corba_storage, NULL, NULL); - - local_storage_listener = evolution_storage_listener_new (); - corba_local_storage_listener = evolution_storage_listener_corba_objref ( - local_storage_listener); - - /* FIXME: is this supposed to be destroy? */ - g_signal_connect(local_storage_listener, - "destroyed", - G_CALLBACK (local_storage_destroyed_cb), - corba_storage); - g_signal_connect(local_storage_listener, - "new_folder", - G_CALLBACK (local_storage_new_folder_cb), - corba_storage); - g_signal_connect(local_storage_listener, - "removed_folder", - G_CALLBACK (local_storage_removed_folder_cb), - corba_storage); - - CORBA_exception_init (&ev); - GNOME_Evolution_Storage_addListener (corba_storage, - corba_local_storage_listener, &ev); - if (ev._major != CORBA_NO_EXCEPTION) { - g_warning ("Cannot add a listener to the Local Storage."); - CORBA_exception_free (&ev); - return; - } - CORBA_exception_free (&ev); -} - -/* ** The rest ******************************************************************** */ - -void -mail_local_storage_startup (EvolutionShellClient *shellclient, const char *evolution_path) -{ - mail_local_provider_init (); - - global_local_store = MAIL_LOCAL_STORE(camel_session_get_service (session, "file:/", CAMEL_PROVIDER_STORE, NULL)); - - if (!global_local_store) { - g_warning ("No local store!"); - return; - } - - storage_listener_startup (shellclient); -} - - -/*---------------------------------------------------------------------- - * Local folder reconfiguration stuff - *----------------------------------------------------------------------*/ - -/* - open new - copy old->new - close old - rename old oldsave - rename new old - open oldsave - delete oldsave - - close old - rename oldtmp - open new - open oldtmp - copy oldtmp new - close oldtmp - close oldnew - -*/ - -/* we should have our own progress bar for this */ - -struct _reconfigure_msg { - struct _mail_msg msg; - - char *uri; - CamelFolder *folder; - - char *newtype; - unsigned int index_body:1; - GtkWidget *frame; - GtkWidget *apply; - GtkWidget *cancel; - GtkWidget *check_index_body; - GtkOptionMenu *optionlist; - - void (*done)(const char *uri, CamelFolder *folder, void*data); - void *done_data; -}; - -/* hash table of folders that the user has a reconfig-folder dialog for */ -static GHashTable *reconfigure_folder_hash = NULL; - -static char * -reconfigure_folder_describe (struct _mail_msg *mm, int done) -{ - struct _reconfigure_msg *m = (struct _reconfigure_msg *)mm; - - return g_strdup_printf (_("Changing folder \"%s\" to \"%s\" format"), - camel_folder_get_full_name (m->folder), - m->newtype); -} - -static void -reconfigure_folder_reconfigure (struct _mail_msg *mm) -{ - struct _reconfigure_msg *m = (struct _reconfigure_msg *)mm; - - d(printf("reconfiguring folder: %s to type %s\n", m->uri, m->newtype)); - - mail_local_folder_reconfigure (MAIL_LOCAL_FOLDER (m->folder), m->newtype, m->index_body, &mm->ex); -} - -static void -reconfigure_folder_reconfigured (struct _mail_msg *mm) -{ - struct _reconfigure_msg *m = (struct _reconfigure_msg *)mm; - GtkWidget *dialog; - /*char *uri;*/ - - if (camel_exception_is_set (&mm->ex)) { - dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, - GTK_BUTTONS_OK, "%s", - _("If you can no longer open this mailbox, then\n" - "you may need to repair it manually.")); - gtk_dialog_run (GTK_DIALOG (dialog)); - } - - if (m->done) - m->done(m->uri, m->folder, m->done_data); -} - -static void -reconfigure_folder_free (struct _mail_msg *mm) -{ - struct _reconfigure_msg *m = (struct _reconfigure_msg *)mm; - - /* remove this folder from our hash since we are done with it */ - g_hash_table_remove (reconfigure_folder_hash, m->folder); - if (g_hash_table_size (reconfigure_folder_hash) == 0) { - /* additional cleanup */ - g_hash_table_destroy (reconfigure_folder_hash); - reconfigure_folder_hash = NULL; - } - - if (m->folder) - camel_object_unref (m->folder); - g_free(m->uri); - g_free (m->newtype); -} - -static struct _mail_msg_op reconfigure_folder_op = { - reconfigure_folder_describe, - reconfigure_folder_reconfigure, - reconfigure_folder_reconfigured, - reconfigure_folder_free, -}; - -static void -reconfigure_response(GtkDialog *dialog, int button, struct _reconfigure_msg *m) -{ - switch(button) { - case GTK_RESPONSE_OK: { - GtkWidget *menu, *item; - - menu = gtk_option_menu_get_menu(m->optionlist); - item = gtk_menu_get_active(GTK_MENU(menu)); - m->newtype = g_strdup(g_object_get_data ((GObject *)item, "type")); - m->index_body = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(m->check_index_body)); - - gtk_widget_set_sensitive (m->frame, FALSE); - gtk_widget_set_sensitive (m->apply, FALSE); - gtk_widget_set_sensitive (m->cancel, FALSE); - - e_thread_put (mail_thread_queued, (EMsg *)m); - break; } - case GTK_RESPONSE_CANCEL: - default: - if (m->done) - m->done(m->uri, NULL, m->done_data); - mail_msg_free ((struct _mail_msg *)m); - break; - } - - gtk_widget_destroy((GtkWidget *)dialog); -} - -static void -reconfigure_got_folder(char *uri, CamelFolder *folder, void *data) -{ - GladeXML *gui; - GtkDialog *gd; - struct _reconfigure_msg *m = data; - char *title; - GList *p; - GtkWidget *menu; - char *currentformat; - int index=0, history=0; - - if (folder == NULL - || !MAIL_IS_LOCAL_FOLDER (folder)) { - g_warning ("Trying to reconfigure nonexistant folder"); - /* error display ? */ - if (m->done) - m->done(uri, NULL, m->done_data); - mail_msg_free((struct _mail_msg *)m); - return; - } - - if (!reconfigure_folder_hash) - reconfigure_folder_hash = g_hash_table_new (NULL, NULL); - - if ((gd = g_hash_table_lookup (reconfigure_folder_hash, folder))) { - gdk_window_raise (GTK_WIDGET (gd)->window); - if (m->done) - m->done(uri, NULL, m->done_data); - mail_msg_free((struct _mail_msg *)m); - return; - } - - gui = glade_xml_new (EVOLUTION_GLADEDIR "/local-config.glade", "dialog_format", NULL); - gd = (GtkDialog *)glade_xml_get_widget (gui, "dialog_format"); - - title = g_strdup_printf (_("Reconfigure /%s"), - camel_folder_get_full_name (folder)); - gtk_window_set_title (GTK_WINDOW (gd), title); - g_free (title); - - m->uri = g_strdup(uri); - m->frame = glade_xml_get_widget (gui, "frame_format"); - m->apply = glade_xml_get_widget (gui, "apply_format"); - m->cancel = glade_xml_get_widget (gui, "cancel_format"); - m->optionlist = (GtkOptionMenu *)glade_xml_get_widget (gui, "option_format"); - m->check_index_body = glade_xml_get_widget (gui, "check_index_body"); - m->newtype = NULL; - m->folder = folder; - camel_object_ref(folder); - - /* dynamically create the folder type list from camel */ - /* we assume the list is static and never freed */ - currentformat = MAIL_LOCAL_FOLDER (folder)->meta->format; - p = camel_session_list_providers (session, TRUE); - menu = gtk_menu_new (); - while (p) { - CamelProvider *cp = p->data; - - /* we only want local providers */ - if (cp->flags & CAMEL_PROVIDER_IS_LOCAL) { - GtkWidget *item; - char *label; - - if (!strcmp (cp->protocol, currentformat)) - history = index; - - label = g_strdup_printf("%s (%s)", cp->protocol, _(cp->name)); - item = gtk_menu_item_new_with_label (label); - g_free (label); - g_object_set_data ((GObject *) item, "type", cp->protocol); - gtk_widget_show (item); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - index++; - } - p = p->next; - } - gtk_option_menu_remove_menu (GTK_OPTION_MENU (m->optionlist)); - gtk_option_menu_set_menu (GTK_OPTION_MENU(m->optionlist), menu); - gtk_option_menu_set_history(GTK_OPTION_MENU(m->optionlist), history); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m->check_index_body), MAIL_LOCAL_FOLDER (folder)->meta->indexed); - - gtk_label_set_text ((GtkLabel *)glade_xml_get_widget (gui, "label_format"), - MAIL_LOCAL_FOLDER (folder)->meta->format); - - g_signal_connect(gd, "response", G_CALLBACK(reconfigure_response), m); - g_object_unref(gui); - - g_hash_table_insert (reconfigure_folder_hash, (gpointer) folder, (gpointer) gd); - - gtk_widget_show((GtkWidget *)gd); -} - -void -mail_local_reconfigure_folder(const char *uri, void (*done)(const char *uri, CamelFolder *folder, void *data), void *done_data) -{ - struct _reconfigure_msg *m; - - if (strncmp(uri, "file:", 5) != 0) { - e_notice (NULL, GTK_MESSAGE_WARNING, - _("You cannot change the format of a non-local folder.")); - if (done) - done(uri, NULL, done_data); - return; - } - - m = mail_msg_new (&reconfigure_folder_op, NULL, sizeof (*m)); - m->done = done; - m->done_data = done_data; - - mail_get_folder(uri, 0, reconfigure_got_folder, m, mail_thread_new); -} |