External-editor support, better maildir guessing



Hi!

Here's my next patch, features:

- External editor support
- Mutt-like external editor support (edit the headers with the
  external editor too). (Checkbox)
- Try whether $HOME/mail, $HOME/Mail or $HOME/nsmail exist and default
  to $HOME/mail if none of them exists. (The balsa startup wizard now
		guesses all my settings correctly :)

Notes:
 - The external editor support is not very heavily tested, might have
   bugs..
 - I have used the identity icon for 'edit with external editor'.
   We need a more appropriate icon. 

Time to shut down my computer :) Merry christmas to all! 

Jelmer

-- 
Jelmer Vernooij <jelmer@nl.linux.org> - http://nl.linux.org/~jelmer/
Development And Underdevelopment: http://library.thinkquest.org/C0110231/
Listening to Garbage: Cherry Lips
 16:58:15 up 8 days, 41 min, 11 users,  load average: 0.60, 0.50, 0.33
Index: src/balsa-app.h
===================================================================
RCS file: /cvs/gnome/balsa/src/balsa-app.h,v
retrieving revision 1.163
diff -u -r1.163 balsa-app.h
--- src/balsa-app.h	2001/12/05 22:49:11	1.163
+++ src/balsa-app.h	2001/12/25 16:08:23
@@ -272,6 +272,10 @@
     gboolean previewpane;
     gboolean debug;
 
+    /* external editor */
+    gchar *extern_editor_command;
+    gboolean extern_editor_mutt_like;
+
     /* arp --- string to prefix "replied to" messages. */
     gchar *quote_str;
 
Index: src/pref-manager.c
===================================================================
RCS file: /cvs/gnome/balsa/src/pref-manager.c,v
retrieving revision 1.185
diff -u -r1.185 pref-manager.c
--- src/pref-manager.c	2001/12/08 15:04:20	1.185
+++ src/pref-manager.c	2001/12/25 16:08:29
@@ -103,6 +103,10 @@
     GtkWidget *debug_message_menu;
     GtkWidget *fatal_message_menu;
 
+    /* External editor preferences */
+    GtkWidget *extern_editor_command;
+    GtkWidget *extern_editor_mutt_like;
+
     /* arp */
     GtkWidget *quote_str;
 
@@ -408,6 +412,14 @@
     gtk_signal_connect(GTK_OBJECT(pui->forward_attached), "toggled",
 		       GTK_SIGNAL_FUNC(properties_modified_cb), property_box);
 
+    /* external editor */
+    gtk_signal_connect(GTK_OBJECT(pui->extern_editor_command), "changed",
+    		       GTK_SIGNAL_FUNC(properties_modified_cb),
+    		       property_box);
+    gtk_signal_connect(GTK_OBJECT(pui->extern_editor_mutt_like), "toggled",
+    		       GTK_SIGNAL_FUNC(properties_modified_cb),
+    		       property_box);
+		
     /* arp */
     gtk_signal_connect(GTK_OBJECT(pui->quote_str), "changed",
 		       GTK_SIGNAL_FUNC(properties_modified_cb),
@@ -649,6 +661,13 @@
 	gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON
 					 (pui->close_mailbox_minutes));
 
+    /* external editor */
+    g_free(balsa_app.extern_editor_command);
+    balsa_app.extern_editor_command = 
+    	g_strdup(gtk_entry_get_text(GTK_ENTRY(pui->extern_editor_command)));
+    	
+    balsa_app.extern_editor_mutt_like = GTK_TOGGLE_BUTTON(pui->extern_editor_mutt_like)->active;
+
     /* arp */
     g_free(balsa_app.quote_str);
     balsa_app.quote_str =
@@ -901,6 +920,11 @@
     gtk_widget_set_sensitive(pui->send_rfc2646_format_flowed,
 			     GTK_TOGGLE_BUTTON(pui->wordwrap)->active);
 
+    /* external editor */
+    gtk_entry_set_text(GTK_ENTRY(pui->extern_editor_command), balsa_app.extern_editor_command);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pui->extern_editor_mutt_like),
+    balsa_app.extern_editor_mutt_like);
+
     /* arp */
     gtk_entry_set_text(GTK_ENTRY(pui->quote_str), balsa_app.quote_str);
     entry_widget = gnome_entry_gtk_entry(GNOME_ENTRY(pui->quote_pattern));
@@ -1627,10 +1651,14 @@
 
 	vbox2 = vbox_in_container(frame2);
 
-    table2 = GTK_TABLE(gtk_table_new(3, 2, FALSE));
+    table2 = GTK_TABLE(gtk_table_new(5, 2, FALSE));
     gtk_container_add(GTK_CONTAINER(vbox2), GTK_WIDGET(table2));
     gtk_container_set_border_width(GTK_CONTAINER(table2), 2);
-    pui->quote_str = attach_entry(_("Reply prefix:"), 4, table2);
+    pui->extern_editor_command = attach_entry(_("External editor command:"), 4, table2);
+    pui->extern_editor_mutt_like = 
+    	gtk_check_button_new_with_label(_("External editor mutt-like"));
+    gtk_box_pack_start(GTK_BOX(vbox2), pui->extern_editor_mutt_like, FALSE, TRUE, 0);
+    pui->quote_str = attach_entry(_("Reply prefix:"), 5, table2);
 
     pui->autoquote =
         gtk_check_button_new_with_label(_("Automatically quote original "
Index: src/save-restore.c
===================================================================
RCS file: /cvs/gnome/balsa/src/save-restore.c,v
retrieving revision 1.223
diff -u -r1.223 save-restore.c
--- src/save-restore.c	2001/12/05 22:49:12	1.223
+++ src/save-restore.c	2001/12/25 16:08:30
@@ -731,6 +731,10 @@
     /* Compose window ... */
     gnome_config_push_prefix(BALSA_CONFIG_PREFIX "Compose/");
 
+    g_free(balsa_app.extern_editor_command);
+    balsa_app.extern_editor_command = gnome_config_get_string("ExternEditorCommand=gnome-edit %s");
+    balsa_app.extern_editor_mutt_like = gnome_config_get_bool("ExternEditorMuttLike=false");
+
     g_free(balsa_app.quote_str);
     balsa_app.quote_str = gnome_config_get_string("QuoteString=> ");
     g_free(balsa_app.compose_headers);
@@ -974,6 +978,8 @@
 
     gnome_config_set_string("ComposeHeaders", balsa_app.compose_headers);
     gnome_config_set_bool("RequestDispositionNotification", balsa_app.req_dispnotify);
+    gnome_config_set_string("ExternEditorCommand", balsa_app.extern_editor_command);
+    gnome_config_set_bool("ExternEditorMuttLike", balsa_app.extern_editor_mutt_like);
     gnome_config_set_string("QuoteString", balsa_app.quote_str);
 
     gnome_config_pop_prefix();
Index: src/sendmsg-window.c
===================================================================
RCS file: /cvs/gnome/balsa/src/sendmsg-window.c,v
retrieving revision 1.330
diff -u -r1.330 sendmsg-window.c
--- src/sendmsg-window.c	2001/12/19 13:16:37	1.330
+++ src/sendmsg-window.c	2001/12/25 16:08:34
@@ -48,6 +48,7 @@
 #endif
 
 #include <sys/stat.h>		/* for check_if_regular_file() */
+#include <sys/wait.h>
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
@@ -75,6 +76,12 @@
 
 #define GNOME_MIME_BUG_WORKAROUND 1
 
+typedef struct {
+	pid_t pid_editor;
+	gchar *filename;
+	BalsaSendmsg *msg;
+}balsa_edit_with_gnome_data ;
+
 static gchar *read_signature(BalsaSendmsg *msg);
 static gint include_file_cb(GtkWidget *, BalsaSendmsg *);
 static gint send_message_cb(GtkWidget *, BalsaSendmsg *);
@@ -246,6 +253,12 @@
                            N_("Select the Identity to use for the message"),
                            change_identity_dialog_cb,
                            BALSA_PIXMAP_MENU_IDENTITY),
+	GNOMEUIINFO_SEPARATOR,
+#define EDIT_MENU_EDIT_GNOME 17
+	GNOMEUIINFO_ITEM_STOCK(N_("_Edit with Gnome-Editor"),
+						   N_("Edit the current message with the default Gnome editor"),
+						   edit_with_gnome,
+						   BALSA_PIXMAP_MENU_IDENTITY), /*FIXME: Other icon */
     GNOMEUIINFO_END
 };
 
@@ -663,136 +676,247 @@
 	update_msg_identity(msg, ident);
 }
 
-/*
-	Drop down list identity update
-*/
 
+/* Edit the current file with an external editor.
+ *
+ * We fork the twice current process, so we get:
+ *
+ * - Old (parent )process (this needs to continue because we don't want 
+ *   balsa to 'hang' until the editor exits
+ * - New (child) process (forks and waits for child to finish)
+ * - New (grandchild) process (executes editor)
+ */
+void
+edit_with_gnome(GtkWidget* widget, BalsaSendmsg* msg)
+{
+	gchar *filename = tmpnam(NULL);
+	gchar *command;
+	gchar **cmdline;
+	balsa_edit_with_gnome_data *data = g_malloc(sizeof(balsa_edit_with_gnome_data));
+	pid_t pid, pid_ext;
+	FILE *tmp = fopen(filename, "w+");
+
+	if(balsa_app.extern_editor_mutt_like){
+	gchar *from = gtk_entry_get_text(GTK_ENTRY(msg->from[1])),
+	*to = gtk_entry_get_text(GTK_ENTRY(msg->to[1])),
+	*reply_to =
+		gtk_entry_get_text(GTK_ENTRY(msg->reply_to[1])), *cc =
+		gtk_entry_get_text(GTK_ENTRY(msg->cc[1])),
+	*bcc = gtk_entry_get_text(GTK_ENTRY(msg->bcc[1])),
+	*subject = gtk_entry_get_text(GTK_ENTRY(msg->subject[1])),
+	*comments = gtk_entry_get_text(GTK_ENTRY(msg->comments[1]));
+	
+	/* Write all the headers */
+	fprintf(tmp, "From: %s\n"
+			"To: %s\n"
+			"Cc: %s\n"
+			"Bcc: %s\n"
+			"Subject: %s\n"
+			"Reply-To: %s\n"
+			"Comments: %s\n\n\n",
+			from,to,cc,bcc,subject,reply_to,comments);
+	}
+	gtk_widget_set_sensitive(msg->text, FALSE);
+	fputs(gtk_editable_get_chars(GTK_EDITABLE(msg->text), 0,
+				gtk_text_get_length(GTK_TEXT
+					(msg->text))),tmp);
+	fclose(tmp);
+	if ((pid = fork()) < 0) {
+		perror ("fork");
+		return; 
+	} 
+	if (pid == 0) {
+		setpgrp();
+		command = g_malloc(strlen(filename) + 30);
+		g_snprintf(command, strlen(filename)+30, balsa_app.extern_editor_command, filename); 
+		cmdline = g_strsplit (command, " ", 1024); 
+		execvp (cmdline[0], cmdline); 
+		perror ("execvp"); 
+		g_strfreev (cmdline); 
+		g_free(command);
+		exit(127);
+	}
+	/* Return immediately. We don't want balsa to 'hang' */
+	data->pid_editor = pid;
+	data->filename = g_strdup(filename);
+	data->msg = msg;
+	gtk_idle_add((GtkFunction) edit_with_gnome_check, data);
+}
+
+static gboolean edit_with_gnome_check(gpointer data){
+	FILE *tmp;
+	balsa_edit_with_gnome_data *data_real = (balsa_edit_with_gnome_data *)data;
+	pid_t pid;
+	gint curposition;
+	gchar line[81]; /* FIXME:All lines should wrap at this line */
+	/* Editor not ready */
+	pid = waitpid (data_real->pid_editor, NULL, WNOHANG);
+	if(pid == -1){
+		perror("waitpid");
+		return TRUE;
+	}else if(pid == 0)return TRUE;
+	tmp = fopen(data_real->filename, "r");
+	if(tmp == NULL){
+		perror("fopen");
+		return TRUE;
+	}
+	if(balsa_app.extern_editor_mutt_like){
+	while(!feof(tmp)){
+		fgets(line, 80, tmp);
+		if(line[strlen(line)-1] == '\n')line[strlen(line)-1] = '\0';
+		if(!strncmp(line, "To: ", 4))gtk_entry_set_text(GTK_ENTRY(data_real->msg->to[1]), line+4);
+		else if(!strncmp(line, "From: ", 6))gtk_entry_set_text(GTK_ENTRY(data_real->msg->from[1]), line+6);
+		else if(!strncmp(line, "Reply-To: ", 10))gtk_entry_set_text(GTK_ENTRY(data_real->msg->reply_to[1]), line+10);
+		else if(!strncmp(line, "Bcc: ", 5))gtk_entry_set_text(GTK_ENTRY(data_real->msg->bcc[1]), line+5);
+		else if(!strncmp(line, "Cc: ", 4))gtk_entry_set_text(GTK_ENTRY(data_real->msg->cc[1]), line+4);
+		else if(!strncmp(line, "Comments: ", 10))gtk_entry_set_text(GTK_ENTRY(data_real->msg->comments[1]), line+10);
+		else if(!strncmp(line, "Subject: ", 9))gtk_entry_set_text(GTK_ENTRY(data_real->msg->subject[1]), line+9);
+		else break;
+	}
+	}
+	gtk_editable_delete_text(GTK_EDITABLE(data_real->msg->text),0,-1);
+	curposition = 0;
+	while(!feof(tmp)){
+		fgets(line, 80, tmp);
+		gtk_editable_insert_text(GTK_EDITABLE(data_real->msg->text),line, strlen(line), &curposition);
+	}
+	g_free(data_real->filename);
+	fclose(tmp);
+	unlink(data_real->filename);
+	gtk_widget_set_sensitive(data_real->msg->text, TRUE);
+	g_free(data);
+	return FALSE;
+}
 
+/*
+   Drop down list identity update
+   */
 
-static void
+	static void
 update_msg_identity(BalsaSendmsg* msg, LibBalsaIdentity* ident)
 {
-    gchar* tmpstr=libbalsa_address_to_gchar(ident->address, 0);
-    
-    /* change entries to reflect new identity */
-        gtk_entry_set_text(GTK_ENTRY(msg->from[1]), tmpstr);
-        g_free(tmpstr);
+	gchar* tmpstr=libbalsa_address_to_gchar(ident->address, 0);
 
-    gtk_entry_set_text(GTK_ENTRY(msg->reply_to[1]), ident->replyto);
-    
-    gtk_entry_set_text(GTK_ENTRY(msg->bcc[1]), ident->bcc);
-    
-    /* change the subject to use the reply/forward strings */
+	/* change entries to reflect new identity */
+	gtk_entry_set_text(GTK_ENTRY(msg->from[1]), tmpstr);
+	g_free(tmpstr);
+
+	gtk_entry_set_text(GTK_ENTRY(msg->reply_to[1]), ident->replyto);
 
-    /* remove/add the signature depending on the new settings, change
-     * the signature if path changed */
+	gtk_entry_set_text(GTK_ENTRY(msg->bcc[1]), ident->bcc);
 
-    /* update the current messages identity */
+	/* change the subject to use the reply/forward strings */
+
+	/* remove/add the signature depending on the new settings, change
+	 * the signature if path changed */
+
+	/* update the current messages identity */
 	msg->ident=ident;
 }
 
 
-static void
+	static void
 sw_size_alloc_cb(GtkWidget * window, GtkAllocation * alloc)
 {
-    balsa_app.sw_height = alloc->height;
-    balsa_app.sw_width = alloc->width;
+	balsa_app.sw_height = alloc->height;
+	balsa_app.sw_width = alloc->width;
 }
 
 
 
 /* remove_attachment - right mouse button callback */
-static void
+	static void
 remove_attachment(GtkWidget * widget, GnomeIconList * ilist)
 {
-    gint num = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(ilist),
-						   "selectednumbertoremove"));
-    gnome_icon_list_remove(ilist, num);
-    gtk_object_remove_data(GTK_OBJECT(ilist), "selectednumbertoremove");
+	gint num = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(ilist),
+				"selectednumbertoremove"));
+	gnome_icon_list_remove(ilist, num);
+	gtk_object_remove_data(GTK_OBJECT(ilist), "selectednumbertoremove");
 }
 
 
 /* ask if an attachment shall be message/external-body */
 static void
 extbody_dialog_delete(GtkWidget *dialog, GdkEvent *event, 
-		      gpointer user_data)
+		gpointer user_data)
 {
-    GnomeIconList *ilist = 
-	GNOME_ICON_LIST(gtk_object_get_user_data (GTK_OBJECT (dialog)));
-    gtk_object_remove_data(GTK_OBJECT(ilist), "selectednumbertoextbody");
-    gtk_widget_hide (dialog);
-    gtk_object_destroy(GTK_OBJECT(dialog));
+	GnomeIconList *ilist = 
+		GNOME_ICON_LIST(gtk_object_get_user_data (GTK_OBJECT (dialog)));
+	gtk_object_remove_data(GTK_OBJECT(ilist), "selectednumbertoextbody");
+	gtk_widget_hide (dialog);
+	gtk_object_destroy(GTK_OBJECT(dialog));
 }
 
-static void
+	static void
 no_change_to_extbody(GtkWidget *widget, gpointer user_data)
 {
-    GtkWidget *dialog = GTK_WIDGET(user_data);
-    GnomeIconList *ilist;
+	GtkWidget *dialog = GTK_WIDGET(user_data);
+	GnomeIconList *ilist;
 
-    ilist = 
-	GNOME_ICON_LIST(gtk_object_get_user_data (GTK_OBJECT (dialog)));
-    gtk_object_remove_data(GTK_OBJECT(ilist), "selectednumbertoextbody");
-    gtk_widget_hide (dialog);
-    gtk_object_destroy(GTK_OBJECT(dialog));
+	ilist = 
+		GNOME_ICON_LIST(gtk_object_get_user_data (GTK_OBJECT (dialog)));
+	gtk_object_remove_data(GTK_OBJECT(ilist), "selectednumbertoextbody");
+	gtk_widget_hide (dialog);
+	gtk_object_destroy(GTK_OBJECT(dialog));
 }
 
 
 static void
 add_extbody_attachment(GnomeIconList *ilist, 
-		       const gchar *name, const gchar *mime_type,
-		       gboolean delete_on_destroy, gboolean is_url) {
-    gchar *pix;
-    gchar *label;
-    attachment_t *attach;
-    gint pos;
+		const gchar *name, const gchar *mime_type,
+		gboolean delete_on_destroy, gboolean is_url) {
+	gchar *pix;
+	gchar *label;
+	attachment_t *attach;
+	gint pos;
 
-    g_return_if_fail(name != NULL); 
-    
-    attach = g_malloc(sizeof(attachment_t));
-    if (is_url) 
-	attach->filename = g_strdup_printf("URL %s", name);
-    else
-	attach->filename = g_strdup(name);
-    attach->force_mime_type = mime_type != NULL ? g_strdup(mime_type) : NULL;
-    attach->delete_on_destroy = delete_on_destroy;
-    attach->as_extbody = TRUE;
-
-    pix = libbalsa_icon_finder("message/external-body", attach->filename);
-    label = g_strdup_printf ("%s (%s)", attach->filename, 
-			     "message/external-body");
-    pos = gnome_icon_list_append(ilist, pix, label);
-    gnome_icon_list_set_icon_data_full(ilist, pos, attach, destroy_attachment);
-    g_free(pix);
-    g_free(label);
+	g_return_if_fail(name != NULL); 
+
+	attach = g_malloc(sizeof(attachment_t));
+	if (is_url) 
+		attach->filename = g_strdup_printf("URL %s", name);
+	else
+		attach->filename = g_strdup(name);
+	attach->force_mime_type = mime_type != NULL ? g_strdup(mime_type) : NULL;
+	attach->delete_on_destroy = delete_on_destroy;
+	attach->as_extbody = TRUE;
+
+	pix = libbalsa_icon_finder("message/external-body", attach->filename);
+	label = g_strdup_printf ("%s (%s)", attach->filename, 
+			"message/external-body");
+	pos = gnome_icon_list_append(ilist, pix, label);
+	gnome_icon_list_set_icon_data_full(ilist, pos, attach, destroy_attachment);
+	g_free(pix);
+	g_free(label);
 }
 
 
 /* send attachment as external body - right mouse button callback */
-static void
+	static void
 extbody_attachment(GtkWidget * widget, gpointer user_data)
 {
-    GtkWidget *dialog = GTK_WIDGET(user_data);
-    GnomeIconList *ilist;
-    gint num;
-    attachment_t *oldattach;
-
-    ilist = 
-	GNOME_ICON_LIST(gtk_object_get_user_data (GTK_OBJECT (dialog)));
-    num = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(ilist),
-					      "selectednumbertoextbody"));
-    oldattach = 
-	(attachment_t *)gnome_icon_list_get_icon_data(ilist, num);
-    g_return_if_fail(oldattach);
-    gtk_object_remove_data(GTK_OBJECT(ilist), "selectednumbertoextbody");
-    gtk_widget_hide (dialog);
-    gtk_object_destroy(GTK_OBJECT(dialog));
-
-    /* remove the selected element and replace it */
-    gnome_icon_list_freeze(ilist);
-    add_extbody_attachment(ilist, oldattach->filename, 
-			   oldattach->force_mime_type, 
-			   oldattach->delete_on_destroy, FALSE);
+	GtkWidget *dialog = GTK_WIDGET(user_data);
+	GnomeIconList *ilist;
+	gint num;
+	attachment_t *oldattach;
+
+	ilist = 
+		GNOME_ICON_LIST(gtk_object_get_user_data (GTK_OBJECT (dialog)));
+	num = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(ilist),
+				"selectednumbertoextbody"));
+	oldattach = 
+		(attachment_t *)gnome_icon_list_get_icon_data(ilist, num);
+	g_return_if_fail(oldattach);
+	gtk_object_remove_data(GTK_OBJECT(ilist), "selectednumbertoextbody");
+	gtk_widget_hide (dialog);
+	gtk_object_destroy(GTK_OBJECT(dialog));
+
+	/* remove the selected element and replace it */
+	gnome_icon_list_freeze(ilist);
+	add_extbody_attachment(ilist, oldattach->filename, 
+			oldattach->force_mime_type, 
+			oldattach->delete_on_destroy, FALSE);
     gnome_icon_list_remove(ilist, num);
     gnome_icon_list_thaw(ilist);
     
@@ -1571,12 +1695,12 @@
 
     /* add the spell check widget to the notebook last */
     gtk_notebook_append_page(GTK_NOTEBOOK(nb), GTK_WIDGET(sc),
-			     gtk_label_new("Spell Check"));
+			     gtk_label_new(_("Spell Check")));
     spell_check_page = gtk_notebook_page_num(GTK_NOTEBOOK(nb), sc);
 
     /* add the mail headers table to the notebook first */
     gtk_notebook_append_page(GTK_NOTEBOOK(nb), GTK_WIDGET(table),
-			     gtk_label_new("Mail Headers"));
+			     gtk_label_new(_("Mail Headers")));
     mail_headers_page = gtk_notebook_page_num(GTK_NOTEBOOK(nb), table);
 
     gtk_notebook_set_page(GTK_NOTEBOOK(nb), mail_headers_page);
Index: src/sendmsg-window.h
===================================================================
RCS file: /cvs/gnome/balsa/src/sendmsg-window.h,v
retrieving revision 1.44
diff -u -r1.44 sendmsg-window.h
--- src/sendmsg-window.h	2001/11/12 22:15:12	1.44
+++ src/sendmsg-window.h	2001/12/25 16:08:35
@@ -79,7 +79,8 @@
 			gchar *forced_mime_type);
 
     typedef void (*field_setter)(BalsaSendmsg *d, const gchar*, const gchar*);
-
+	void edit_with_gnome(GtkWidget *, BalsaSendmsg *);
+	static gboolean edit_with_gnome_check(gpointer);
     void sendmsg_window_process_url(const char *url, field_setter func,
 				    void *data);
     BalsaSendmsg *sendmsg_window_new_from_list(GtkWidget * w,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]