From 4e4eb45bf69d539996b298a13bf650c5ebea7f16 Mon Sep 17 00:00:00 2001 From: bertrand Date: Sun, 5 Sep 1999 16:15:12 +0000 Subject: [PATCH] use folder summary instead of opening all messages. 1999-09-05 bertrand * tests/ui-tests/store_listing.c (show_folder_messages): use folder summary instead of opening all messages. * camel/providers/MH/camel-mh-folder.c (_create_summary): basic and highly non-efficient summary implementation. Should be seen as a proof of concept only. subfolder summary still has to be implemented. * camel/providers/maildir/camel-maildir-folder.c (_init_with_store): hasn't summary for the moment. * camel/providers/maildir/camel-maildir-folder.c cosmetic changes. svn path=/trunk/; revision=1178 --- ChangeLog | 16 + camel/camel-folder.c | 13 +- camel/camel-folder.h | 3 + camel/providers/MH/camel-mh-folder.c | 49 +- .../providers/maildir/camel-maildir-folder.c | 1082 +++++++++-------- tests/ui-tests/store_listing.c | 45 +- 6 files changed, 674 insertions(+), 534 deletions(-) diff --git a/ChangeLog b/ChangeLog index d7b0c6cd64..ed6cd1386e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +1999-09-05 bertrand + + * tests/ui-tests/store_listing.c (show_folder_messages): + use folder summary instead of opening all messages. + + * camel/providers/MH/camel-mh-folder.c (_create_summary): + basic and highly non-efficient summary implementation. + Should be seen as a proof of concept only. + subfolder summary still has to be implemented. + + * camel/providers/maildir/camel-maildir-folder.c (_init_with_store): + hasn't summary for the moment. + * camel/providers/maildir/camel-maildir-folder.c + cosmetic changes. + + 1999-09-04 bertrand * camel/providers/MH/camel-mh-folder.c (_create_summary): diff --git a/camel/camel-folder.c b/camel/camel-folder.c index 49c886dc98..1cd3b41dc6 100644 --- a/camel/camel-folder.c +++ b/camel/camel-folder.c @@ -167,6 +167,10 @@ _init_with_store (CamelFolder *folder, CamelStore *parent_store) if (folder->parent_store) gtk_object_unref (GTK_OBJECT (folder->parent_store)); folder->parent_store = parent_store; if (parent_store) gtk_object_ref (GTK_OBJECT (parent_store)); + folder->open_mode = FOLDER_OPEN_UNKNOWN; + folder->open_state = FOLDER_CLOSE; + folder->name = NULL; + folder->full_name = NULL; } @@ -187,6 +191,13 @@ _open (CamelFolder *folder, CamelFolderOpenMode mode) } +void camel_folder_open (CamelFolder *folder, CamelFolderOpenMode mode) +{ + CF_CLASS(folder)->open (folder, mode); +} + + + /** * _close:Close a folder. * @folder: @@ -972,7 +983,7 @@ camel_folder_has_summary_capability (CamelFolder *folder) } -const CamelFolderSummary * +CamelFolderSummary * camel_folder_get_summary (CamelFolder *folder) { return folder->summary; diff --git a/camel/camel-folder.h b/camel/camel-folder.h index 4554cb4b0c..0715396ca7 100644 --- a/camel/camel-folder.h +++ b/camel/camel-folder.h @@ -120,6 +120,7 @@ GtkType camel_folder_get_type (void); /* public methods */ CamelFolder *camel_folder_get_folder (CamelFolder *folder, gchar *folder_name); +void camel_folder_open (CamelFolder *folder, CamelFolderOpenMode mode); gboolean camel_folder_create (CamelFolder *folder); gboolean camel_folder_delete (CamelFolder *folder, gboolean recurse); gboolean camel_folder_delete_messages (CamelFolder *folder); @@ -138,7 +139,9 @@ gint camel_folder_get_message_count (CamelFolder *folder); gint camel_folder_append_message (CamelFolder *folder, CamelMimeMessage *message); const GList *camel_folder_list_permanent_flags (CamelFolder *folder); void camel_folder_copy_message_to (CamelFolder *folder, CamelMimeMessage *message, CamelFolder *dest_folder); + gboolean camel_folder_has_summary_capability (CamelFolder *folder); +CamelFolderSummary *camel_folder_get_summary (CamelFolder *folder); #ifdef __cplusplus diff --git a/camel/providers/MH/camel-mh-folder.c b/camel/providers/MH/camel-mh-folder.c index 300d8366d3..fa6661c722 100644 --- a/camel/providers/MH/camel-mh-folder.c +++ b/camel/providers/MH/camel-mh-folder.c @@ -37,6 +37,7 @@ #include "camel-stream-fs.h" #include "camel-stream-buffered-fs.h" #include "camel-folder-summary.h" +#include "gmime-utils.h" static CamelFolderClass *parent_class=NULL; @@ -46,7 +47,7 @@ static CamelFolderClass *parent_class=NULL; #define CF_CLASS(so) CAMEL_FOLDER_CLASS (GTK_OBJECT(so)->klass) #define CMHS_CLASS(so) CAMEL_STORE_CLASS (GTK_OBJECT(so)->klass) -static int copy_reg (const char *src_path, const char *dst_path); + static void _set_name(CamelFolder *folder, const gchar *name); static void _init_with_store (CamelFolder *folder, CamelStore *parent_store); static gboolean _exists (CamelFolder *folder); @@ -61,6 +62,9 @@ static void _expunge (CamelFolder *folder); static void _copy_message_to (CamelFolder *folder, CamelMimeMessage *message, CamelFolder *dest_folder); static void _open (CamelFolder *folder, CamelFolderOpenMode mode); + +/* some utility functions */ +static int copy_reg (const char *src_path, const char *dst_path); static gboolean _is_a_message_file (const gchar *file_name, const gchar *file_path); static void @@ -148,18 +152,51 @@ static void _create_summary (CamelFolder *folder) { CamelMhFolder *mh_folder = CAMEL_MH_FOLDER (folder); + CamelFolderSummary *summary = folder->summary; CamelMessageInfo *message_info; - CamelFolderSummary *subfolder_info; - + CamelFolderInfo *subfolder_info; + CamelStream *message_stream; GList *file_list = mh_folder->file_name_list; gchar *filename; + gchar *message_fullpath; + gchar *directory_path = mh_folder->directory_path; + GArray *header_array; + Rfc822Header *cur_header; + int i; + + summary = folder->summary; while (file_list) { filename = (gchar *)(file_list->data); message_info = g_new0 (CamelMessageInfo, 1); - message_info->subject = NULL; + message_fullpath = g_strdup_printf ("%s/%s", directory_path, filename); + message_stream = camel_stream_buffered_fs_new_with_name (message_fullpath, + CAMEL_STREAM_BUFFERED_FS_READ); + header_array = get_header_array_from_stream (message_stream); + gtk_object_unref (GTK_OBJECT (message_stream)); + + for (i=0; ilen; i++) { + cur_header = (Rfc822Header *)header_array->data + i; + if (!g_strcasecmp (cur_header->name, "subject")) { + message_info->subject = cur_header->value; + g_free (cur_header->name); + } else if (!g_strcasecmp (cur_header->name, "sender")) { + message_info->date = cur_header->value; + g_free (cur_header->name); + } else if (!g_strcasecmp (cur_header->name, "date")) { + message_info->date = cur_header->value; + g_free (cur_header->name); + } else { + g_free (cur_header->name); + g_free (cur_header->value); + } + } + g_array_free (header_array, TRUE); + + message_info->UID = NULL; + summary->message_info_list = g_list_append (summary->message_info_list, message_info); file_list = file_list->next; } } @@ -172,7 +209,8 @@ _open (CamelFolder *folder, CamelFolderOpenMode mode) CamelMhFolder *mh_folder = CAMEL_MH_FOLDER (folder); struct dirent *dir_entry; DIR *dir_handle; - + + if (folder->open_state == FOLDER_OPEN) return; @@ -194,6 +232,7 @@ _open (CamelFolder *folder, CamelFolderOpenMode mode) closedir (dir_handle); + _create_summary (folder); } /** diff --git a/camel/providers/maildir/camel-maildir-folder.c b/camel/providers/maildir/camel-maildir-folder.c index 489fd37009..9b663aa191 100644 --- a/camel/providers/maildir/camel-maildir-folder.c +++ b/camel/providers/maildir/camel-maildir-folder.c @@ -20,6 +20,13 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */ + +/* + * AUTHORS : Jukka Zitting + * + */ + + #include #include #include @@ -53,6 +60,561 @@ static CamelFolderClass *parent_class=NULL; #define GETMSG "CamelMaildirFolder::get_message" #define NUMMSGS "CamelMaildirFolder::get_message_count" + +static void _init_with_store (CamelFolder *folder, CamelStore *parent_store); +static void _set_name (CamelFolder *folder, const gchar *name); +static gboolean _exists (CamelFolder *folder); +static gboolean _create (CamelFolder *folder); +static gboolean _delete (CamelFolder *folder, gboolean recurse); +static gboolean _delete_messages (CamelFolder *folder); +static CamelMimeMessage *_get_message (CamelFolder *folder, gint number); +static gint _get_message_count (CamelFolder *folder); +static void _expunge (CamelFolder *folder); + +/* fs utility functions */ +static DIR * _xopendir (const gchar *path); +static gboolean _xstat (const gchar *path, struct stat *buf); +static gboolean _xmkdir (const gchar *path); +static gboolean _xlink (const gchar *from, const gchar *to); +static gboolean _xunlink (const gchar *path); +static gboolean _xrmdir (const gchar *path); +/* ** */ + +static void +camel_maildir_folder_class_init (CamelMaildirFolderClass *camel_maildir_folder_class) +{ + CamelFolderClass *camel_folder_class = + CAMEL_FOLDER_CLASS (camel_maildir_folder_class); + + parent_class = gtk_type_class (camel_folder_get_type ()); + + /* virtual method definition */ + /* virtual method overload */ + camel_folder_class->init_with_store = _init_with_store; + camel_folder_class->set_name = _set_name; + camel_folder_class->exists = _exists; + camel_folder_class->create = _create; + camel_folder_class->delete = _delete; + camel_folder_class->delete_messages = _delete_messages; + camel_folder_class->expunge = _expunge; + camel_folder_class->get_message = _get_message; + camel_folder_class->get_message_count = _get_message_count; +} + +GtkType +camel_maildir_folder_get_type (void) +{ + static GtkType camel_maildir_folder_type = 0; + + if (!camel_maildir_folder_type) { + GtkTypeInfo camel_maildir_folder_info = + { + "CamelMaildirFolder", + sizeof (CamelMaildirFolder), + sizeof (CamelMaildirFolderClass), + (GtkClassInitFunc) camel_maildir_folder_class_init, + (GtkObjectInitFunc) NULL, + /* reserved_1 */ NULL, + /* reserved_2 */ NULL, + (GtkClassInitFunc) NULL, + }; + + camel_maildir_folder_type = + gtk_type_unique (CAMEL_FOLDER_TYPE, &camel_maildir_folder_info); + } + + return camel_maildir_folder_type; +} + + + + + + +/** + * CamelMaildirFolder::init_with_store: initializes the folder object + * @folder: folder object to initialize + * @parent_store: parent store object of the folder + * + * Simply tells that the folder can contain messages but not subfolders. + * Perhaps we'll later implement subfolders too... + */ +static void +_init_with_store (CamelFolder *folder, + CamelStore *parent_store) +{ + CAMEL_LOG_FULL_DEBUG ("Entering CamelMaildirFolder::init_with_store\n"); + g_assert(folder); + g_assert(parent_store); + + /* call parent method */ + parent_class->init_with_store (folder, parent_store); + + folder->can_hold_messages = TRUE; + folder->can_hold_folders = FALSE; + folder->has_summary_capability = FALSE; + + CAMEL_LOG_FULL_DEBUG ("Leaving CamelMaildirFolder::init_with_store\n"); +} + +/** + * CamelMaildirFolder::set_name: sets the name of the folder + * @folder: folder object + * @name: name of the folder + * + * Sets the name of the folder object. The existence of a folder with + * the given name is not checked in this function. + */ +static void +_set_name (CamelFolder *folder, const gchar *name) +{ + CamelMaildirFolder *maildir_folder = CAMEL_MAILDIR_FOLDER (folder); + + CAMEL_LOG_FULL_DEBUG ("Entering CamelMaildirFolder::set_name\n"); + g_assert (folder); + g_assert (name); + g_assert (folder->parent_store); + + /* call default implementation */ + parent_class->set_name (folder, name); + + if (maildir_folder->directory_path) + g_free (maildir_folder->directory_path); + + maildir_folder->directory_path = g_strdup (name); + + CAMEL_LOG_FULL_DEBUG ("CamelMaildirFolder::set_name: " + "name set to %s\n", name); + CAMEL_LOG_FULL_DEBUG ("Leaving CamelMaildirFolder::set_name\n"); +} + +/** + * CamelMaildirFolder::exists: tests whether the named maildir exists + * @folder: folder object + * + * A created maildir folder object doesn't necessarily exist yet in the + * filesystem. This function checks whether the maildir exists. + * The structure of the maildir is stated in the maildir.5 manpage. + * + * maildir.5: + * A directory in maildir format has three subdirectories, + * all on the same filesystem: tmp, new, and cur. + * + * Return value: TRUE if the maildir exists, FALSE otherwise + */ +static gboolean +_exists (CamelFolder *folder) +{ + CamelMaildirFolder *maildir_folder = CAMEL_MAILDIR_FOLDER (folder); + static const gchar *dir[3] = { "new", "cur", "tmp" }; + gint i; + struct stat statbuf; + const gchar *maildir; + gchar *path; + gboolean rv = TRUE; + + CAMEL_LOG_FULL_DEBUG ("Entering CamelMaildirFolder::exists\n"); + g_assert (folder); + g_return_val_if_fail (maildir_folder->directory_path, FALSE); + + maildir = maildir_folder->directory_path; + + CAMEL_LOG_FULL_DEBUG ("CamelMailFolder::exists: checking maildir %s\n", + maildir); + + /* check whether the toplevel directory exists */ + rv = _xstat (maildir, &statbuf) && S_ISDIR (statbuf.st_mode); + + /* check whether the maildir subdirectories exist */ + for (i = 0; rv && i < 3; i++) { + path = g_strconcat (maildir, G_DIR_SEPARATOR_S, dir[i], NULL); + + rv = _xstat (path, &statbuf) && S_ISDIR (statbuf.st_mode); + + g_free (path); + } + + CAMEL_LOG_FULL_DEBUG ("CamelMaildirFolder::exists: %s\n", + (rv) ? "maildir found" : "maildir not found"); + CAMEL_LOG_FULL_DEBUG ("Leaving CamelMaildirFolder::exists\n"); + return rv; +} + +/** + * CamelMaildirFolder::create: creates the named maildir + * @folder: folder object + * + * A created maildir folder object doesn't necessarily exist yet in the + * filesystem. This function creates the maildir if it doesn't yet exist. + * The structure of the maildir is stated in the maildir.5 manpage. + * + * maildir.5: + * A directory in maildir format has three subdirectories, + * all on the same filesystem: tmp, new, and cur. + * + * Return value: TRUE if the maildir existed already or was created, + * FALSE otherwise + */ +static gboolean +_create (CamelFolder *folder) +{ + CamelMaildirFolder *maildir_folder = CAMEL_MAILDIR_FOLDER (folder); + static const gchar *dir[3] = { "new", "cur", "tmp" }; + gint i; + const gchar *maildir; + gchar *path; + gboolean rv = TRUE; + + CAMEL_LOG_FULL_DEBUG ("Entering CamelMaildirFolder::create\n"); + g_assert (folder); + + /* check whether the maildir already exists */ + if (camel_folder_exists (folder)) return TRUE; + + maildir = maildir_folder->directory_path; + + CAMEL_LOG_FULL_DEBUG ("CamelMailFolder::create: creating maildir %s\n", + maildir); + + /* create the toplevel directory */ + rv = _xmkdir (maildir); + + /* create the maildir subdirectories */ + for (i = 0; rv && i < 3; i++) { + path = g_strconcat (maildir, G_DIR_SEPARATOR_S, dir[i], NULL); + + rv = _xmkdir (path); + + g_free (path); + } + + CAMEL_LOG_FULL_DEBUG ("CamelMaildirFolder::create: %s\n", + rv ? "maildir created" : "an error occurred"); + CAMEL_LOG_FULL_DEBUG ("Leaving CamelMaildirFolder::create\n"); + return rv; +} + +/** + * CamelMaildirFolder::delete: delete the maildir folder + * @folder: the folder object + * @recurse: + * + * This function empties and deletes the maildir folder. The subdirectories + * "tmp", "cur", and "new" are removed first and then the toplevel maildir + * directory is deleted. All files from the directories are deleted as well, + * so you should be careful when using this function. If a subdirectory cannot + * be deleted, then the operation it is stopped. Thus if an error occurs, the + * maildir directory won't be removed, but it might no longer be a valid maildir. + */ +static gboolean +_delete (CamelFolder *folder, gboolean recurse) +{ + CamelMaildirFolder *maildir_folder = CAMEL_MAILDIR_FOLDER (folder); + static const gchar *dir[3] = { "new", "cur", "tmp" }; + gint i; + const gchar *maildir; + gchar *path; + gboolean rv = TRUE; + + CAMEL_LOG_FULL_DEBUG ("Entering CamelMaildirFolder::create\n"); + g_assert (folder); + + /* check whether the maildir already exists */ + if (!camel_folder_exists (folder)) return TRUE; + + maildir = maildir_folder->directory_path; + + CAMEL_LOG_FULL_DEBUG ("CamelMailFolder::delete: deleting maildir %s\n", + maildir); + + /* delete the maildir subdirectories */ + for (i = 0; rv && i < 3; i++) { + path = g_strconcat (maildir, G_DIR_SEPARATOR_S, dir[i], NULL); + + rv = _xrmdir (path); + + g_free (path); + } + + /* create the toplevel directory */ + if (rv) + rv = _xrmdir (maildir); + + CAMEL_LOG_FULL_DEBUG ("CamelMaildirFolder::delete: %s\n", + rv ? "maildir deleted" : "an error occurred"); + CAMEL_LOG_FULL_DEBUG ("Leaving CamelMaildirFolder::delete\n"); + return rv; +} + +/** + * CamelMaildirFolder::delete_messages: empty the maildir folder + * @folder: the folder object + * + * This function empties the maildir folder. All messages from the + * "cur" subdirectory are deleted. If a message cannot be deleted, then + * it is just skipped and the rest of the messages are still deleted. + * Files with names starting with a dot are skipped as described in the + * maildir.5 manpage. + * + * maildir.5: + * It is a good idea for readers to skip all filenames in new + * and cur starting with a dot. Other than this, readers + * should not attempt to parse filenames. + * + * Return value: FALSE on error and if some messages could not be deleted. + * TRUE otherwise. + */ +static gboolean +_delete_messages (CamelFolder *folder) +{ + CamelMaildirFolder *maildir_folder = CAMEL_MAILDIR_FOLDER (folder); + const gchar *maildir; + gchar *curdir, *file; + DIR *dir_handle; + struct dirent *dir_entry; + gboolean rv = TRUE; + + CAMEL_LOG_FULL_DEBUG ("Entering CamelMaildirFolder::delete_messages\n"); + g_assert (folder); + + /* call default implementation */ + parent_class->delete_messages (folder); + + /* Check if the folder didn't exist */ + if (!camel_folder_exists (folder)) return TRUE; + + maildir = maildir_folder->directory_path; + + CAMEL_LOG_FULL_DEBUG ("CamelMaildirFolder::delete_messages: " + "deleting messages from %s\n", maildir); + + /* delete messages from the maildir subdirectory "cur" */ + curdir = g_strconcat (maildir, G_DIR_SEPARATOR_S, "cur", NULL); + + dir_handle = _xopendir (curdir); + if (dir_handle) { + while ((dir_entry = readdir (dir_handle))) { + if (dir_entry->d_name[0] == '.') continue; + file = g_strconcat (curdir, G_DIR_SEPARATOR_S, + dir_entry->d_name, NULL); + + if (!_xunlink (file)) rv = FALSE; + + g_free (file); + } + closedir (dir_handle); + } else + rv = FALSE; + + g_free (curdir); + + CAMEL_LOG_FULL_DEBUG ("CamelMaildirFolder::delete_messages: %s\n", + rv ? "messages deleted" : "an error occurred"); + CAMEL_LOG_FULL_DEBUG ("Leaving CamelMaildirFolder::delete_messages\n"); + return rv; +} + +/** + * CamelMaildirFolder::get_message: get a message from maildir + * @folder: the folder object + * @number: number of the message within the folder + * + * Return value: the message, NULL on error + */ +static CamelMimeMessage * +_get_message (CamelFolder *folder, gint number) +{ + CamelMaildirFolder *maildir_folder = CAMEL_MAILDIR_FOLDER(folder); + DIR *dir_handle; + struct dirent *dir_entry; + CamelStream *stream; + CamelMimeMessage *message = NULL; + const gchar *maildir; + gchar *curdir, *file = NULL; + gint count = -1; + + CAMEL_LOG_FULL_DEBUG ("Entering CamelMaildirFolder::get_message\n"); + g_assert(folder); + + /* Check if the folder exists */ + if (!camel_folder_exists (folder)) return NULL; + + maildir = maildir_folder->directory_path; + + CAMEL_LOG_FULL_DEBUG ("CamelMaildirFolder::get_message: " + "getting message #%d from %s\n", number, maildir); + + /* Count until the desired message is reached */ + curdir = g_strconcat (maildir, G_DIR_SEPARATOR_S, "cur", NULL); + if ((dir_handle = _xopendir (curdir))) { + while ((count < number) && (dir_entry = readdir (dir_handle))) + if (dir_entry->d_name[0] != '.') count++; + + if (count == number) + file = g_strconcat (curdir, G_DIR_SEPARATOR_S, + dir_entry->d_name, NULL); + + closedir (dir_handle); + } + g_free (curdir); + if (!file) return NULL; + + /* Create the message object */ +#warning use session field here + message = camel_mime_message_new_with_session ((CamelSession *) NULL); + stream = camel_stream_fs_new_with_name (file, CAMEL_STREAM_FS_READ); + + if (!message || !stream) { + g_free (file); + if (stream) gtk_object_unref (GTK_OBJECT (stream)); + if (message) gtk_object_unref (GTK_OBJECT (message)); + return NULL; + } + + camel_data_wrapper_construct_from_stream (CAMEL_DATA_WRAPPER (message), + stream); + gtk_object_unref (GTK_OBJECT (stream)); + gtk_object_set_data_full (GTK_OBJECT (message), + "fullpath", file, g_free); + + CAMEL_LOG_FULL_DEBUG ("CamelMaildirFolder::get_message: " + "message %p created from %s\n", message, file); + CAMEL_LOG_FULL_DEBUG ("Leaving CamelMaildirFolder::get_message\n"); + return message; +} + +/** + * CamelMaildirFolder::get_message_count: count messages in maildir + * @folder: the folder object + * + * Returns the number of messages in the maildir folder. New messages + * are included in this count. + * + * Return value: number of messages in the maildir, -1 on error + */ +static gint +_get_message_count (CamelFolder *folder) +{ + CamelMaildirFolder *maildir_folder = CAMEL_MAILDIR_FOLDER(folder); + const gchar *maildir; + gchar *newdir, *curdir, *newfile, *curfile; + DIR *dir_handle; + struct dirent *dir_entry; + guint count = 0; + + CAMEL_LOG_FULL_DEBUG ("Entering " + "CamelMaildirFolder::get_message_count\n"); + g_assert(folder); + + /* check if the maildir exists */ + if (!camel_folder_exists (folder)) return -1; + + maildir = maildir_folder->directory_path; + + newdir = g_strconcat (maildir, G_DIR_SEPARATOR_S, "new", NULL); + curdir = g_strconcat (maildir, G_DIR_SEPARATOR_S, "cur", NULL); + + /* Check new messages */ + CAMEL_LOG_FULL_DEBUG ("CamelMaildirFolder::get_message_count: " + "getting new messages from %s\n", newdir); + if ((dir_handle = _xopendir (newdir))) { + while ((dir_entry = readdir (dir_handle))) { + if (dir_entry->d_name[0] == '.') continue; + newfile = g_strconcat (newdir, G_DIR_SEPARATOR_S, + dir_entry->d_name, NULL); + curfile = g_strconcat (curdir, G_DIR_SEPARATOR_S, + dir_entry->d_name, ":2,", NULL); + + if (_xlink (newfile, curfile)) _xunlink (newfile); + + g_free (curfile); + g_free (newfile); + } + closedir (dir_handle); + } + + /* Count messages */ + CAMEL_LOG_FULL_DEBUG ("CamelMaildirFolder::get_message_count: " + "counting messages in %s\n", curdir); + if ((dir_handle = _xopendir (curdir))) { + while ((dir_entry = readdir (dir_handle))) + if (dir_entry->d_name[0] != '.') count++; + closedir (dir_handle); + } + + g_free (curdir); + g_free (newdir); + + CAMEL_LOG_FULL_DEBUG ("CamelMaildirFolder::get_message_count: " + " found %d messages\n", count); + CAMEL_LOG_FULL_DEBUG ("Leaving " + "CamelMaildirFolder::get_message_count\n"); + return count; +} + + + + +/** + * CamelMaildirFolder::expunge: expunge messages marked as deleted + * @folder: the folder object + * + * Physically deletes the messages marked as deleted in the folder. + */ +static void +_expunge (CamelFolder *folder) +{ + CamelMimeMessage *message; + GList *node; + gchar *fullpath; + + CAMEL_LOG_FULL_DEBUG ("Entering CamelMaildirFolder::expunge\n"); + g_assert(folder); + + /* expunge messages marked for deletion */ + for (node = folder->message_list; node; node = g_list_next(node)) { + message = CAMEL_MIME_MESSAGE (node->data); + if (!message) { + CAMEL_LOG_WARNING ("CamelMaildirFolder::expunge: " + "null message in node %p\n", node); + continue; + } + + if (camel_mime_message_get_flag (message, "DELETED")) { + CAMEL_LOG_FULL_DEBUG ("CamelMaildirFolder::expunge: " + "expunging message #%d\n", + message->message_number); + + /* expunge the message */ + fullpath = gtk_object_get_data (GTK_OBJECT (message), + "fullpath"); + CAMEL_LOG_FULL_DEBUG ("CamelMaildirFolder::expunge: " + "message fullpath is %s\n", + fullpath); + + if (_xunlink (fullpath)) + message->expunged = TRUE; + } else { + CAMEL_LOG_FULL_DEBUG ("CamelMaildirFolder::expunge: " + "skipping message #%d\n", + message->message_number); + } + } + + CAMEL_LOG_FULL_DEBUG ("Leaving CamelMaildirFolder::expunge\n"); +} + + + + + + + +/* + * fs utility function + * + */ + static DIR * _xopendir (const gchar *path) { @@ -179,523 +741,5 @@ _xrmdir (const gchar *path) } } -/** - * CamelMaildirFolder::init_with_store: initializes the folder object - * @folder: folder object to initialize - * @parent_store: parent store object of the folder - * - * Simply tells that the folder can contain messages but not subfolders. - * Perhaps we'll later implement subfolders too... - */ -static void -camel_maildir_folder_init_with_store (CamelFolder *folder, - CamelStore *parent_store) -{ - CAMEL_LOG_FULL_DEBUG ("Entering CamelMaildirFolder::init_with_store\n"); - g_assert(folder); - g_assert(parent_store); - - /* call parent method */ - parent_class->init_with_store (folder, parent_store); - - folder->can_hold_messages = TRUE; - folder->can_hold_folders = FALSE; +/** *** **/ - CAMEL_LOG_FULL_DEBUG ("Leaving CamelMaildirFolder::init_with_store\n"); -} - -/** - * CamelMaildirFolder::set_name: sets the name of the folder - * @folder: folder object - * @name: name of the folder - * - * Sets the name of the folder object. The existence of a folder with - * the given name is not checked in this function. - */ -static void -camel_maildir_folder_set_name (CamelFolder *folder, const gchar *name) -{ - CamelMaildirFolder *maildir_folder = CAMEL_MAILDIR_FOLDER (folder); - - CAMEL_LOG_FULL_DEBUG ("Entering CamelMaildirFolder::set_name\n"); - g_assert (folder); - g_assert (name); - g_assert (folder->parent_store); - - /* call default implementation */ - parent_class->set_name (folder, name); - - if (maildir_folder->directory_path) - g_free (maildir_folder->directory_path); - - maildir_folder->directory_path = g_strdup (name); - - CAMEL_LOG_FULL_DEBUG ("CamelMaildirFolder::set_name: " - "name set to %s\n", name); - CAMEL_LOG_FULL_DEBUG ("Leaving CamelMaildirFolder::set_name\n"); -} - -/** - * CamelMaildirFolder::exists: tests whether the named maildir exists - * @folder: folder object - * - * A created maildir folder object doesn't necessarily exist yet in the - * filesystem. This function checks whether the maildir exists. - * The structure of the maildir is stated in the maildir.5 manpage. - * - * maildir.5: - * A directory in maildir format has three subdirectories, - * all on the same filesystem: tmp, new, and cur. - * - * Return value: TRUE if the maildir exists, FALSE otherwise - */ -static gboolean -camel_maildir_folder_exists (CamelFolder *folder) -{ - CamelMaildirFolder *maildir_folder = CAMEL_MAILDIR_FOLDER (folder); - static const gchar *dir[3] = { "new", "cur", "tmp" }; - gint i; - struct stat statbuf; - const gchar *maildir; - gchar *path; - gboolean rv = TRUE; - - CAMEL_LOG_FULL_DEBUG ("Entering CamelMaildirFolder::exists\n"); - g_assert (folder); - g_return_val_if_fail (maildir_folder->directory_path, FALSE); - - maildir = maildir_folder->directory_path; - - CAMEL_LOG_FULL_DEBUG ("CamelMailFolder::exists: checking maildir %s\n", - maildir); - - /* check whether the toplevel directory exists */ - rv = _xstat (maildir, &statbuf) && S_ISDIR (statbuf.st_mode); - - /* check whether the maildir subdirectories exist */ - for (i = 0; rv && i < 3; i++) { - path = g_strconcat (maildir, G_DIR_SEPARATOR_S, dir[i], NULL); - - rv = _xstat (path, &statbuf) && S_ISDIR (statbuf.st_mode); - - g_free (path); - } - - CAMEL_LOG_FULL_DEBUG ("CamelMaildirFolder::exists: %s\n", - (rv) ? "maildir found" : "maildir not found"); - CAMEL_LOG_FULL_DEBUG ("Leaving CamelMaildirFolder::exists\n"); - return rv; -} - -/** - * CamelMaildirFolder::create: creates the named maildir - * @folder: folder object - * - * A created maildir folder object doesn't necessarily exist yet in the - * filesystem. This function creates the maildir if it doesn't yet exist. - * The structure of the maildir is stated in the maildir.5 manpage. - * - * maildir.5: - * A directory in maildir format has three subdirectories, - * all on the same filesystem: tmp, new, and cur. - * - * Return value: TRUE if the maildir existed already or was created, - * FALSE otherwise - */ -static gboolean -camel_maildir_folder_create (CamelFolder *folder) -{ - CamelMaildirFolder *maildir_folder = CAMEL_MAILDIR_FOLDER (folder); - static const gchar *dir[3] = { "new", "cur", "tmp" }; - gint i; - const gchar *maildir; - gchar *path; - gboolean rv = TRUE; - - CAMEL_LOG_FULL_DEBUG ("Entering CamelMaildirFolder::create\n"); - g_assert (folder); - - /* check whether the maildir already exists */ - if (camel_folder_exists (folder)) return TRUE; - - maildir = maildir_folder->directory_path; - - CAMEL_LOG_FULL_DEBUG ("CamelMailFolder::create: creating maildir %s\n", - maildir); - - /* create the toplevel directory */ - rv = _xmkdir (maildir); - - /* create the maildir subdirectories */ - for (i = 0; rv && i < 3; i++) { - path = g_strconcat (maildir, G_DIR_SEPARATOR_S, dir[i], NULL); - - rv = _xmkdir (path); - - g_free (path); - } - - CAMEL_LOG_FULL_DEBUG ("CamelMaildirFolder::create: %s\n", - rv ? "maildir created" : "an error occurred"); - CAMEL_LOG_FULL_DEBUG ("Leaving CamelMaildirFolder::create\n"); - return rv; -} - -/** - * CamelMaildirFolder::delete: delete the maildir folder - * @folder: the folder object - * @recurse: - * - * This function empties and deletes the maildir folder. The subdirectories - * "tmp", "cur", and "new" are removed first and then the toplevel maildir - * directory is deleted. All files from the directories are deleted as well, - * so you should be careful when using this function. If a subdirectory cannot - * be deleted, then the operation it is stopped. Thus if an error occurs, the - * maildir directory won't be removed, but it might no longer be a valid maildir. - */ -static gboolean -camel_maildir_folder_delete (CamelFolder *folder, gboolean recurse) -{ - CamelMaildirFolder *maildir_folder = CAMEL_MAILDIR_FOLDER (folder); - static const gchar *dir[3] = { "new", "cur", "tmp" }; - gint i; - const gchar *maildir; - gchar *path; - gboolean rv = TRUE; - - CAMEL_LOG_FULL_DEBUG ("Entering CamelMaildirFolder::create\n"); - g_assert (folder); - - /* check whether the maildir already exists */ - if (!camel_folder_exists (folder)) return TRUE; - - maildir = maildir_folder->directory_path; - - CAMEL_LOG_FULL_DEBUG ("CamelMailFolder::delete: deleting maildir %s\n", - maildir); - - /* delete the maildir subdirectories */ - for (i = 0; rv && i < 3; i++) { - path = g_strconcat (maildir, G_DIR_SEPARATOR_S, dir[i], NULL); - - rv = _xrmdir (path); - - g_free (path); - } - - /* create the toplevel directory */ - if (rv) - rv = _xrmdir (maildir); - - CAMEL_LOG_FULL_DEBUG ("CamelMaildirFolder::delete: %s\n", - rv ? "maildir deleted" : "an error occurred"); - CAMEL_LOG_FULL_DEBUG ("Leaving CamelMaildirFolder::delete\n"); - return rv; -} - -/** - * CamelMaildirFolder::delete_messages: empty the maildir folder - * @folder: the folder object - * - * This function empties the maildir folder. All messages from the - * "cur" subdirectory are deleted. If a message cannot be deleted, then - * it is just skipped and the rest of the messages are still deleted. - * Files with names starting with a dot are skipped as described in the - * maildir.5 manpage. - * - * maildir.5: - * It is a good idea for readers to skip all filenames in new - * and cur starting with a dot. Other than this, readers - * should not attempt to parse filenames. - * - * Return value: FALSE on error and if some messages could not be deleted. - * TRUE otherwise. - */ -static gboolean -camel_maildir_folder_delete_messages (CamelFolder *folder) -{ - CamelMaildirFolder *maildir_folder = CAMEL_MAILDIR_FOLDER (folder); - const gchar *maildir; - gchar *curdir, *file; - DIR *dir_handle; - struct dirent *dir_entry; - gboolean rv = TRUE; - - CAMEL_LOG_FULL_DEBUG ("Entering CamelMaildirFolder::delete_messages\n"); - g_assert (folder); - - /* call default implementation */ - parent_class->delete_messages (folder); - - /* Check if the folder didn't exist */ - if (!camel_folder_exists (folder)) return TRUE; - - maildir = maildir_folder->directory_path; - - CAMEL_LOG_FULL_DEBUG ("CamelMaildirFolder::delete_messages: " - "deleting messages from %s\n", maildir); - - /* delete messages from the maildir subdirectory "cur" */ - curdir = g_strconcat (maildir, G_DIR_SEPARATOR_S, "cur", NULL); - - dir_handle = _xopendir (curdir); - if (dir_handle) { - while ((dir_entry = readdir (dir_handle))) { - if (dir_entry->d_name[0] == '.') continue; - file = g_strconcat (curdir, G_DIR_SEPARATOR_S, - dir_entry->d_name, NULL); - - if (!_xunlink (file)) rv = FALSE; - - g_free (file); - } - closedir (dir_handle); - } else - rv = FALSE; - - g_free (curdir); - - CAMEL_LOG_FULL_DEBUG ("CamelMaildirFolder::delete_messages: %s\n", - rv ? "messages deleted" : "an error occurred"); - CAMEL_LOG_FULL_DEBUG ("Leaving CamelMaildirFolder::delete_messages\n"); - return rv; -} - -/** - * CamelMaildirFolder::get_message: get a message from maildir - * @folder: the folder object - * @number: number of the message within the folder - * - * Return value: the message, NULL on error - */ -static CamelMimeMessage * -camel_maildir_folder_get_message (CamelFolder *folder, gint number) -{ - CamelMaildirFolder *maildir_folder = CAMEL_MAILDIR_FOLDER(folder); - DIR *dir_handle; - struct dirent *dir_entry; - CamelStream *stream; - CamelMimeMessage *message = NULL; - const gchar *maildir; - gchar *curdir, *file = NULL; - gint count = -1; - - CAMEL_LOG_FULL_DEBUG ("Entering CamelMaildirFolder::get_message\n"); - g_assert(folder); - - /* Check if the folder exists */ - if (!camel_folder_exists (folder)) return NULL; - - maildir = maildir_folder->directory_path; - - CAMEL_LOG_FULL_DEBUG ("CamelMaildirFolder::get_message: " - "getting message #%d from %s\n", number, maildir); - - /* Count until the desired message is reached */ - curdir = g_strconcat (maildir, G_DIR_SEPARATOR_S, "cur", NULL); - if ((dir_handle = _xopendir (curdir))) { - while ((count < number) && (dir_entry = readdir (dir_handle))) - if (dir_entry->d_name[0] != '.') count++; - - if (count == number) - file = g_strconcat (curdir, G_DIR_SEPARATOR_S, - dir_entry->d_name, NULL); - - closedir (dir_handle); - } - g_free (curdir); - if (!file) return NULL; - - /* Create the message object */ -#warning use session field here - message = camel_mime_message_new_with_session ((CamelSession *) NULL); - stream = camel_stream_fs_new_with_name (file, CAMEL_STREAM_FS_READ); - - if (!message || !stream) { - g_free (file); - if (stream) gtk_object_unref (GTK_OBJECT (stream)); - if (message) gtk_object_unref (GTK_OBJECT (message)); - return NULL; - } - - camel_data_wrapper_construct_from_stream (CAMEL_DATA_WRAPPER (message), - stream); - gtk_object_unref (GTK_OBJECT (stream)); - gtk_object_set_data_full (GTK_OBJECT (message), - "fullpath", file, g_free); - - CAMEL_LOG_FULL_DEBUG ("CamelMaildirFolder::get_message: " - "message %p created from %s\n", message, file); - CAMEL_LOG_FULL_DEBUG ("Leaving CamelMaildirFolder::get_message\n"); - return message; -} - -/** - * CamelMaildirFolder::get_message_count: count messages in maildir - * @folder: the folder object - * - * Returns the number of messages in the maildir folder. New messages - * are included in this count. - * - * Return value: number of messages in the maildir, -1 on error - */ -static gint -camel_maildir_folder_get_message_count (CamelFolder *folder) -{ - CamelMaildirFolder *maildir_folder = CAMEL_MAILDIR_FOLDER(folder); - const gchar *maildir; - gchar *newdir, *curdir, *newfile, *curfile; - DIR *dir_handle; - struct dirent *dir_entry; - guint count = 0; - - CAMEL_LOG_FULL_DEBUG ("Entering " - "CamelMaildirFolder::get_message_count\n"); - g_assert(folder); - - /* check if the maildir exists */ - if (!camel_folder_exists (folder)) return -1; - - maildir = maildir_folder->directory_path; - - newdir = g_strconcat (maildir, G_DIR_SEPARATOR_S, "new", NULL); - curdir = g_strconcat (maildir, G_DIR_SEPARATOR_S, "cur", NULL); - - /* Check new messages */ - CAMEL_LOG_FULL_DEBUG ("CamelMaildirFolder::get_message_count: " - "getting new messages from %s\n", newdir); - if ((dir_handle = _xopendir (newdir))) { - while ((dir_entry = readdir (dir_handle))) { - if (dir_entry->d_name[0] == '.') continue; - newfile = g_strconcat (newdir, G_DIR_SEPARATOR_S, - dir_entry->d_name, NULL); - curfile = g_strconcat (curdir, G_DIR_SEPARATOR_S, - dir_entry->d_name, ":2,", NULL); - - if (_xlink (newfile, curfile)) _xunlink (newfile); - - g_free (curfile); - g_free (newfile); - } - closedir (dir_handle); - } - - /* Count messages */ - CAMEL_LOG_FULL_DEBUG ("CamelMaildirFolder::get_message_count: " - "counting messages in %s\n", curdir); - if ((dir_handle = _xopendir (curdir))) { - while ((dir_entry = readdir (dir_handle))) - if (dir_entry->d_name[0] != '.') count++; - closedir (dir_handle); - } - - g_free (curdir); - g_free (newdir); - - CAMEL_LOG_FULL_DEBUG ("CamelMaildirFolder::get_message_count: " - " found %d messages\n", count); - CAMEL_LOG_FULL_DEBUG ("Leaving " - "CamelMaildirFolder::get_message_count\n"); - return count; -} - -/** - * CamelMaildirFolder::expunge: expunge messages marked as deleted - * @folder: the folder object - * - * Physically deletes the messages marked as deleted in the folder. - */ -static void -camel_maildir_folder_expunge (CamelFolder *folder) -{ - CamelMimeMessage *message; - GList *node; - gchar *fullpath; - - CAMEL_LOG_FULL_DEBUG ("Entering CamelMaildirFolder::expunge\n"); - g_assert(folder); - - /* expunge messages marked for deletion */ - for (node = folder->message_list; node; node = g_list_next(node)) { - message = CAMEL_MIME_MESSAGE (node->data); - if (!message) { - CAMEL_LOG_WARNING ("CamelMaildirFolder::expunge: " - "null message in node %p\n", node); - continue; - } - - if (camel_mime_message_get_flag (message, "DELETED")) { - CAMEL_LOG_FULL_DEBUG ("CamelMaildirFolder::expunge: " - "expunging message #%d\n", - message->message_number); - - /* expunge the message */ - fullpath = gtk_object_get_data (GTK_OBJECT (message), - "fullpath"); - CAMEL_LOG_FULL_DEBUG ("CamelMaildirFolder::expunge: " - "message fullpath is %s\n", - fullpath); - - if (_xunlink (fullpath)) - message->expunged = TRUE; - } else { - CAMEL_LOG_FULL_DEBUG ("CamelMaildirFolder::expunge: " - "skipping message #%d\n", - message->message_number); - } - } - - CAMEL_LOG_FULL_DEBUG ("Leaving CamelMaildirFolder::expunge\n"); -} - -static void -camel_maildir_folder_class_init ( - CamelMaildirFolderClass *camel_maildir_folder_class) -{ - CamelFolderClass *camel_folder_class = - CAMEL_FOLDER_CLASS (camel_maildir_folder_class); - - parent_class = gtk_type_class (camel_folder_get_type ()); - - /* virtual method definition */ - /* virtual method overload */ - camel_folder_class-> - init_with_store = camel_maildir_folder_init_with_store; - camel_folder_class->set_name = camel_maildir_folder_set_name; - camel_folder_class->exists = camel_maildir_folder_exists; - camel_folder_class->create = camel_maildir_folder_create; - camel_folder_class->delete = camel_maildir_folder_delete; - camel_folder_class-> - delete_messages = camel_maildir_folder_delete_messages; - camel_folder_class->expunge = camel_maildir_folder_expunge; - camel_folder_class-> - get_message = camel_maildir_folder_get_message; - camel_folder_class-> - get_message_count = camel_maildir_folder_get_message_count; -} - -GtkType -camel_maildir_folder_get_type (void) -{ - static GtkType camel_maildir_folder_type = 0; - - if (!camel_maildir_folder_type) { - GtkTypeInfo camel_maildir_folder_info = - { - "CamelMaildirFolder", - sizeof (CamelMaildirFolder), - sizeof (CamelMaildirFolderClass), - (GtkClassInitFunc) camel_maildir_folder_class_init, - (GtkObjectInitFunc) NULL, - /* reserved_1 */ NULL, - /* reserved_2 */ NULL, - (GtkClassInitFunc) NULL, - }; - - camel_maildir_folder_type = - gtk_type_unique (CAMEL_FOLDER_TYPE, - &camel_maildir_folder_info); - } - - return camel_maildir_folder_type; -} diff --git a/tests/ui-tests/store_listing.c b/tests/ui-tests/store_listing.c index 526bd3c9f7..ca69985221 100644 --- a/tests/ui-tests/store_listing.c +++ b/tests/ui-tests/store_listing.c @@ -14,6 +14,7 @@ #include "camel-mh-folder.h" #include "camel-mh-store.h" #include "camel.h" +#include "camel-folder-summary.h" static GladeXML *xml; static CamelSession *_session; @@ -132,19 +133,22 @@ show_folder_messages (CamelFolder *folder) const gchar *clist_row_text[3]; const char *sent_date, *subject, *sender; gint current_row; + CamelFolderSummary *summary; message_clist = glade_xml_get_widget (xml, "message-clist"); /* clear old message list */ gtk_clist_clear (GTK_CLIST (message_clist)); - + +#if 0 folder_message_count = camel_folder_get_message_count (folder); + for (i=0; idata; + clist_row_text [0] = msg_info->date; + clist_row_text [1] = msg_info->sender; + clist_row_text [2] = msg_info->subject; + printf ("New message : subject = %s\n", msg_info->subject); + current_row = gtk_clist_append (GTK_CLIST (message_clist), clist_row_text); + + message_info_list = message_info_list->next; + } + } else { + printf ("Folder does not have summary. Skipping\n"); + } +} /* add a mail store given by its URL */ @@ -200,10 +224,13 @@ add_mail_store (const gchar *store_url) /* normally, use get_root_folder */ root_folder = camel_store_get_folder (store, ""); + camel_folder_open (root_folder, FOLDER_OPEN_RW); subfolder_list = camel_folder_list_subfolders (root_folder); while (subfolder_list) { new_tree_text[0] = subfolder_list->data; new_folder = camel_store_get_folder (store, subfolder_list->data); + camel_folder_open (new_folder, FOLDER_OPEN_RW); + new_folder_node = gtk_ctree_insert_node (GTK_CTREE (mailbox_and_store_tree), new_store_node, NULL,