diff options
-rw-r--r-- | ChangeLog | 11 | ||||
-rw-r--r-- | camel/providers/MH/camel-mh-folder.c | 266 | ||||
-rw-r--r-- | tests/ui-tests/store_listing.c | 96 | ||||
-rw-r--r-- | tests/ui-tests/store_listing.glade | 6 |
4 files changed, 342 insertions, 37 deletions
@@ -1,3 +1,14 @@ +1999-08-16 bertrand <Bertrand.Guiheneuf@aful.org> + + * tests/ui-tests/store_listing.c: + Now has a popup menu on mailbox tree to allow + easier tests. Implemented the copy stuff. + Works well for the MH provider :))) + + * camel/providers/MH/camel-mh-folder.c (_copy_message_to): + Test MH provider fast copy implemented. + + 1999-08-15 bertrand <Bertrand.Guiheneuf@aful.org> * camel/camel-folder.c (camel_folder_expunge): diff --git a/camel/providers/MH/camel-mh-folder.c b/camel/providers/MH/camel-mh-folder.c index 049ad905ab..9bb2f36c82 100644 --- a/camel/providers/MH/camel-mh-folder.c +++ b/camel/providers/MH/camel-mh-folder.c @@ -22,6 +22,7 @@ */ #include <config.h> #include <sys/stat.h> +#include <sys/param.h> #include <unistd.h> #include <sys/types.h> #include <fcntl.h> @@ -42,6 +43,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); @@ -460,6 +462,7 @@ _get_message (CamelFolder *folder, gint number) message->message_number = number; gtk_object_set_data_full (GTK_OBJECT (message), "fullpath", g_strdup (message_file_name), _filename_free); + #warning Set flags and all this stuff here } g_free (message_file_name); @@ -508,29 +511,22 @@ _get_message_count (CamelFolder *folder) - -static gint -_append_message (CamelFolder *folder, CamelMimeMessage *message) +static gboolean +_find_next_free_message_file (CamelFolder *folder, gint *new_msg_number, gchar **new_msg_filename) { CamelMhFolder *mh_folder = CAMEL_MH_FOLDER(folder); const gchar *directory_path; struct dirent *dir_entry; DIR *dir_handle; - guint last_max_message_number = 0; - guint current_message_number; - guint new_message_number; - gchar *new_message_filename; - CamelStream *output_stream; - gboolean error; + gint last_max_message_number = 0; + gint current_message_number; - CAMEL_LOG_FULL_DEBUG ("Entering CamelMhFolder::append_message\n"); - g_assert(folder); directory_path = mh_folder->directory_path; - if (!directory_path) return -1; + if (!directory_path) return FALSE; - if (!camel_folder_exists (folder)) return 0; + if (!camel_folder_exists (folder)) return FALSE; dir_handle = opendir (directory_path); @@ -548,27 +544,42 @@ _append_message (CamelFolder *folder, CamelMimeMessage *message) dir_entry = readdir (dir_handle); } closedir (dir_handle); + + *new_msg_number = last_max_message_number + 1; + *new_msg_filename = g_strdup_printf ("%s/%d", directory_path, *new_msg_number); + CAMEL_LOG_FULL_DEBUG ("CamelMhFolder::find_next_free_message_file new message path is %s\n", + *new_msg_filename); + return TRUE; + + +} +static gint +_append_message (CamelFolder *folder, CamelMimeMessage *message) +{ + guint new_msg_number; + gchar *new_msg_filename; + CamelStream *output_stream; + gboolean error; - new_message_number = last_max_message_number + 1; - new_message_filename = g_strdup_printf ("%s/%d", directory_path, new_message_number); - CAMEL_LOG_FULL_DEBUG ("CamelMhFolder::append_message new message path is %s\n", - new_message_filename); + CAMEL_LOG_FULL_DEBUG ("Entering CamelMhFolder::append_message\n"); + if (!_find_next_free_message_file (folder, &new_msg_number, &new_msg_filename)) + return -1; - output_stream = camel_stream_fs_new_with_name (new_message_filename, CAMEL_STREAM_FS_WRITE); + output_stream = camel_stream_fs_new_with_name (new_msg_filename, CAMEL_STREAM_FS_WRITE); if (output_stream != NULL) { camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message), output_stream); camel_stream_close (output_stream); } else { CAMEL_LOG_WARNING ("CamelMhFolder::append_message could not open %s for writing\n", - new_message_filename); + new_msg_filename); CAMEL_LOG_FULL_DEBUG (" Full error text is : %s\n", strerror(errno)); error = TRUE; } - g_free (new_message_filename); + g_free (new_msg_filename); CAMEL_LOG_FULL_DEBUG ("Leaving CamelMhFolder::append_message\n"); if (error) return -1; - else return new_message_number; + else return new_msg_number; } @@ -623,13 +634,216 @@ _expunge (CamelFolder *folder) static void _copy_message_to (CamelFolder *folder, CamelMimeMessage *message, CamelFolder *dest_folder) { - gchar *filename; - gchar *dest_filename; + gchar *src_msg_filename; + guint dest_msg_number; + gchar *dest_msg_filename; if (IS_CAMEL_MH_FOLDER (dest_folder)) { - /*g_assert (message->parent_folder == folder);*/ - /* don't have time to finish that today */ - parent_class->copy_message_to (folder, message, dest_folder); + /*g_return_if_fail (message->parent_folder == folder);*/ + + if (!_find_next_free_message_file (dest_folder, &dest_msg_number, &dest_msg_filename)) + return; + src_msg_filename = gtk_object_get_data (GTK_OBJECT (message), "fullpath"); + CAMEL_LOG_FULL_DEBUG ("CamelMhFolder::copy_to copy file %s to %s\n", src_msg_filename, dest_msg_filename); + copy_reg (src_msg_filename, dest_msg_filename); + } else parent_class->copy_message_to (folder, message, dest_folder); } + + + + +/************************************************************************/ + +/*** Took directly from GNU fileutils-4.0 ***/ +/* Copyright (C) 89, 90, 91, 95, 96, 97, 1998 Free Software Foundation. */ +/* This may be rwritten soon. -Bertrand */ + + +/* Write LEN bytes at PTR to descriptor DESC, retrying if interrupted. + Return LEN upon success, write's (negative) error code otherwise. */ +int +full_write (int desc, const char *ptr, size_t len) +{ + int total_written; + + total_written = 0; + while (len > 0) + { + int written = write (desc, ptr, len); + if (written < 0) + { + if (errno == EINTR) + continue; + return written; + } + total_written += written; + ptr += written; + len -= written; + } + return total_written; +} + + + + +static int +copy_reg (const char *src_path, const char *dst_path) +{ + char *buf; + int buf_size; + int dest_desc; + int source_desc; + int n_read; + struct stat sb; + char *cp; + int *ip; + int return_val = 0; + off_t n_read_total = 0; + int last_write_made_hole = 0; + int make_holes = TRUE; + + source_desc = open (src_path, O_RDONLY); + if (source_desc < 0) + { + /* If SRC_PATH doesn't exist, then chances are good that the + user did something like this `cp --backup foo foo': and foo + existed to start with, but copy_internal renamed DST_PATH + with the backup suffix, thus also renaming SRC_PATH. */ + if (errno == ENOENT) + error (0, 0, "`%s' and `%s' are the same file", + src_path, dst_path); + else + error (0, errno, "%s", src_path); + + return -1; + } + + /* Create the new regular file with small permissions initially, + to not create a security hole. */ + + dest_desc = open (dst_path, O_WRONLY | O_CREAT | O_TRUNC, 0600); + if (dest_desc < 0) + { + error (0, errno, "cannot create regular file `%s'", dst_path); + return_val = -1; + goto ret2; + } + + /* Find out the optimal buffer size. */ + + if (fstat (dest_desc, &sb)) + { + error (0, errno, "%s", dst_path); + return_val = -1; + goto ret; + } + + buf_size = 8192; + + + + /* Make a buffer with space for a sentinel at the end. */ + + buf = (char *) alloca (buf_size + sizeof (int)); + + for (;;) + { + n_read = read (source_desc, buf, buf_size); + if (n_read < 0) + { + if (errno == EINTR) + continue; + error (0, errno, "%s", src_path); + return_val = -1; + goto ret; + } + if (n_read == 0) + break; + + n_read_total += n_read; + + ip = 0; + if (make_holes) + { + buf[n_read] = 1; /* Sentinel to stop loop. */ + + /* Find first nonzero *word*, or the word with the sentinel. */ + + ip = (int *) buf; + while (*ip++ == 0) + ; + + /* Find the first nonzero *byte*, or the sentinel. */ + + cp = (char *) (ip - 1); + while (*cp++ == 0) + ; + + /* If we found the sentinel, the whole input block was zero, + and we can make a hole. */ + + if (cp > buf + n_read) + { + /* Make a hole. */ + if (lseek (dest_desc, (off_t) n_read, SEEK_CUR) < 0L) + { + error (0, errno, "%s", dst_path); + return_val = -1; + goto ret; + } + last_write_made_hole = 1; + } + else + /* Clear to indicate that a normal write is needed. */ + ip = 0; + } + if (ip == 0) + { + if (full_write (dest_desc, buf, n_read) < 0) + { + error (0, errno, "%s", dst_path); + return_val = -1; + goto ret; + } + last_write_made_hole = 0; + } + } + + /* If the file ends with a `hole', something needs to be written at + the end. Otherwise the kernel would truncate the file at the end + of the last write operation. */ + + if (last_write_made_hole) + { +#if HAVE_FTRUNCATE + /* Write a null character and truncate it again. */ + if (full_write (dest_desc, "", 1) < 0 + || ftruncate (dest_desc, n_read_total) < 0) +#else + /* Seek backwards one character and write a null. */ + if (lseek (dest_desc, (off_t) -1, SEEK_CUR) < 0L + || full_write (dest_desc, "", 1) < 0) +#endif + { + error (0, errno, "%s", dst_path); + return_val = -1; + } + } + +ret: + if (close (dest_desc) < 0) + { + error (0, errno, "%s", dst_path); + return_val = -1; + } +ret2: + if (close (source_desc) < 0) + { + error (0, errno, "%s", src_path); + return_val = -1; + } + + return return_val; +} diff --git a/tests/ui-tests/store_listing.c b/tests/ui-tests/store_listing.c index 377c17baf7..526bd3c9f7 100644 --- a/tests/ui-tests/store_listing.c +++ b/tests/ui-tests/store_listing.c @@ -17,28 +17,95 @@ static GladeXML *xml; static CamelSession *_session; - +static CamelFolder *currently_selected_folder = NULL; static void add_mail_store (const gchar *store_url); static void show_folder_messages (CamelFolder *folder); -void -mailbox_row_selected (GtkCTree *ctree, GList *node, gint column, gpointer user_data) + +static void +_destroy_menu (gpointer data) { - GtkCTreeNode *mailbox_node = GTK_CTREE_NODE (node); + gtk_widget_destroy (GTK_WIDGET (data)); +} + +static void +_copy_message (GtkWidget *widget, gpointer data) +{ + CamelFolder *dest_folder = CAMEL_FOLDER (data); + GtkWidget *message_clist; + gint current_row; + GList *selected; + gint selected_row; + + CamelMimeMessage *message; + + printf ("Selected \"copy to folder\" with destination folder %s\n", camel_folder_get_name (dest_folder)); + message_clist = glade_xml_get_widget (xml, "message-clist"); + selected = GTK_CLIST (message_clist)->selection; + while (selected) { + selected_row = GPOINTER_TO_INT (selected->data); + message = CAMEL_MIME_MESSAGE (gtk_clist_get_row_data (GTK_CLIST (message_clist), selected_row)); + camel_folder_copy_message_to (currently_selected_folder, message, dest_folder); + selected = selected->next; + } + +} + +static GnomeUIInfo mailbox_popup_menu[] = { + GNOMEUIINFO_ITEM_STOCK ("_Copy selected message here", NULL, _copy_message, GNOME_STOCK_MENU_NEW), + GNOMEUIINFO_END +}; + +static void +_show_mailbox_context_menu (CamelFolder *folder) { + GtkWidget *menu; + GtkCTree *mailbox_and_store_tree; + + mailbox_and_store_tree = GTK_CTREE (glade_xml_get_widget (xml, "store-and-mailbox-tree")); + menu = gtk_object_get_data (GTK_OBJECT (mailbox_and_store_tree), "mailbox_popup_menu"); + if (!menu) { + menu = gnome_popup_menu_new (mailbox_popup_menu); + gtk_object_set_data_full (GTK_OBJECT (mailbox_and_store_tree), "mailbox_popup_menu", menu, _destroy_menu); + } + + gnome_popup_menu_do_popup (menu, NULL, NULL, NULL, folder); + + +} +static gboolean +mailbox_button_clicked_on_row (gint button, gint row) +{ + GtkCTreeNode *mailbox_node; CamelFolder *folder; + GtkCTree *mailbox_and_store_tree; const gchar *mailbox_name; + + mailbox_and_store_tree = GTK_CTREE (glade_xml_get_widget (xml, "store-and-mailbox-tree")); - folder = gtk_ctree_node_get_row_data (ctree, mailbox_node); + mailbox_node = gtk_ctree_node_nth (mailbox_and_store_tree, row); + + folder = gtk_ctree_node_get_row_data (mailbox_and_store_tree, mailbox_node); if (folder && IS_CAMEL_FOLDER (folder)) { + mailbox_name = camel_folder_get_name (folder); - printf ("Mailbox name : %s\n", mailbox_name); - show_folder_messages (folder); + printf ("mailbox %s clicked with button %d\n", mailbox_name, button); + switch (button) { + case 1: + currently_selected_folder = folder; + show_folder_messages (folder); + break; + case 2: + break; + case 3: + _show_mailbox_context_menu (folder); + } + return TRUE; } else { printf ("Node is a store\n"); + return FALSE; } - } @@ -271,7 +338,20 @@ on_message_delete_activate (GtkWidget *widget, void *data) delete_selected_messages(); } +gboolean +on_store_and_mailbox_tree_button_press_event (GtkWidget *widget, GdkEventButton *event, void *data) +{ + gint row; + GtkCList *clist = GTK_CLIST (widget); + if (!gtk_clist_get_selection_info (clist, event->x, event->y, &row, NULL)) + return FALSE; + if (!mailbox_button_clicked_on_row (event->button, row)) + return FALSE; + + return TRUE; + +} /* ----- init */ int diff --git a/tests/ui-tests/store_listing.glade b/tests/ui-tests/store_listing.glade index 34acf37e6f..d551c90dbb 100644 --- a/tests/ui-tests/store_listing.glade +++ b/tests/ui-tests/store_listing.glade @@ -255,9 +255,9 @@ <width>150</width> <can_focus>True</can_focus> <signal> - <name>tree_select_row</name> - <handler>mailbox_row_selected</handler> - <last_modification_time>Tue, 10 Aug 1999 16:25:40 GMT</last_modification_time> + <name>button_press_event</name> + <handler>on_store_and_mailbox_tree_button_press_event</handler> + <last_modification_time>Mon, 16 Aug 1999 13:06:15 GMT</last_modification_time> </signal> <columns>1</columns> <column_widths>80</column_widths> |