OK, so I thought bug 596066 (https://bugzilla.gnome.org/show_bug.cgi?id=596066) might be easy enough for me, an admitted novice in C. However, I can not for the life of me figure out why my call to g_spawn_async throws a segfault every time. I would be most grateful if someone could point out the problem (I'm sure it's a newbie error on my part). This patch has known problems. Due to the new import/export structure (I think), it will only work on native .XCF files right now., and the file must be saved. There is some legacy code from the original sendmail plugin hanging around that isn't doing much. And the segfault of course :) And finally, xdg-email is broken, and needs to be patched in order for Evolution or Thunderbird to even accept attachments. You can grab the patch for xdg-email from launchpad (filed upstream also): https://bugs.launchpad.net/ubuntu/+source/xdg-utils/+bug/408350 The git patch is attached. Thanks! Chris PS - is there any reason to maintain backwards compatibility with the original mail plugin? The attached patch was a heavy-handed attack just to see if I could get it working with xdg-utils - I have not really settled on the best approach yet.
From 099cf07983d1dbc82510952b2a2bce798b7ef62f Mon Sep 17 00:00:00 2001 From: Chris Mohler <cr33dog@xxxxxxxxx> Date: Sat, 3 Oct 2009 21:10:35 -0500 Subject: [PATCH] Update mail plugin to use xdg-email This is a work-in-progress patch to use xdg-email instead of sendmail. There are known problems. --- plug-ins/common/mail.c | 501 +++--------------------------------------------- 1 files changed, 30 insertions(+), 471 deletions(-) diff --git a/plug-ins/common/mail.c b/plug-ins/common/mail.c index 8f5625a..19b8e71 100644 --- a/plug-ins/common/mail.c +++ b/plug-ins/common/mail.c @@ -102,8 +102,8 @@ static const guint8 mail_icon[] = }; -#ifndef SENDMAIL -#define SENDMAIL "/usr/lib/sendmail" +#ifndef XDGEMAIL +#define XDGEMAIL "/usr/bin/xdg-email" #endif #define BUFFER_SIZE 256 @@ -114,10 +114,6 @@ static const guint8 mail_icon[] = typedef struct { gchar filename[BUFFER_SIZE]; - gchar receipt[BUFFER_SIZE]; - gchar from[BUFFER_SIZE]; - gchar subject[BUFFER_SIZE]; - gchar comment[BUFFER_SIZE]; } m_info; @@ -128,26 +124,11 @@ static void run (const gchar *name, gint *nreturn_vals, GimpParam **return_vals); -static GimpPDBStatusType save_image (const gchar *filename, +static GimpPDBStatusType save_image (gchar *filename, gint32 image_ID, gint32 drawable_ID, gint32 run_mode); -static gboolean save_dialog (void); -static void mail_entry_callback (GtkWidget *widget, - gchar *data); -static void mesg_body_callback (GtkTextBuffer *buffer, - gpointer data); - -static gboolean valid_file (const gchar *filename); -static void create_headers (FILE *mailpipe); -static gchar * find_extension (const gchar *filename); -static gboolean to64 (const gchar *filename, - FILE *outfile, - GError **error); -static FILE * sendmail_pipe (gchar **cmd, - GPid *pid); - const GimpPlugInInfo PLUG_IN_INFO = { @@ -159,11 +140,9 @@ const GimpPlugInInfo PLUG_IN_INFO = static m_info mail_info = { - "", "", "", "", "" + "" }; -static gchar *mesg_body = NULL; - MAIN () @@ -176,16 +155,11 @@ query (void) { GIMP_PDB_IMAGE, "image", "Input image" }, { GIMP_PDB_DRAWABLE, "drawable", "Drawable to save" }, { GIMP_PDB_STRING, "filename", "The name of the file to save the image in" }, - { GIMP_PDB_STRING, "to-address", "The email address to send to" }, - { GIMP_PDB_STRING, "from-address", "The email address for the From: field" }, - { GIMP_PDB_STRING, "subject", "The subject" }, - { GIMP_PDB_STRING, "comment", "The Comment" }, - { GIMP_PDB_INT32, "encapsulation", "ignored" } }; gimp_install_procedure (PLUG_IN_PROC, N_("Send the image by email"), - "You need to have sendmail installed", + "You need to have xdg-utils installed", "Adrian Likins, Reagan Blundell", "Adrian Likins, Reagan Blundell, Daniel Risacher, " "Spencer Kimball and Peter Mattis", @@ -245,8 +219,6 @@ run (const gchar *name, } } - if (! save_dialog ()) - status = GIMP_PDB_CANCEL; break; case GIMP_RUN_NONINTERACTIVE: @@ -259,14 +231,6 @@ run (const gchar *name, { g_strlcpy (mail_info.filename, param[3].data.d_string, BUFFER_SIZE); - g_strlcpy (mail_info.receipt, - param[4].data.d_string, BUFFER_SIZE); - g_strlcpy (mail_info.from, - param[5].data.d_string, BUFFER_SIZE); - g_strlcpy (mail_info.subject, - param[6].data.d_string, BUFFER_SIZE); - g_strlcpy (mail_info.comment, - param[7].data.d_string, BUFFER_SIZE); } break; @@ -285,13 +249,6 @@ run (const gchar *name, drawable_ID, run_mode); - if (status == GIMP_PDB_SUCCESS) - { - if (mesg_body) - g_strlcpy (mail_info.comment, mesg_body, BUFFER_SIZE); - - gimp_set_data (PLUG_IN_PROC, &mail_info, sizeof (m_info)); - } } } else @@ -303,434 +260,36 @@ run (const gchar *name, } static GimpPDBStatusType -save_image (const gchar *filename, +save_image (gchar *filename, gint32 image_ID, gint32 drawable_ID, gint32 run_mode) { GimpPDBStatusType status = GIMP_PDB_SUCCESS; - gchar *ext; - gchar *tmpname; - gchar *mailcmd[3]; - GPid mailpid; - FILE *mailpipe; - GError *error = NULL; - - ext = find_extension (filename); - - if (ext == NULL) - return GIMP_PDB_CALLING_ERROR; - - /* get a temp name with the right extension and save into it. */ - tmpname = gimp_temp_name (ext + 1); - - /* construct the "sendmail user@location" line */ - mailcmd[0] = SENDMAIL; - mailcmd[1] = mail_info.receipt; - mailcmd[2] = NULL; - - /* create a pipe to sendmail */ - mailpipe = sendmail_pipe (mailcmd, &mailpid); - - if (mailpipe == NULL) - return GIMP_PDB_EXECUTION_ERROR; - - create_headers (mailpipe); - - fflush (mailpipe); - - if (! (gimp_file_save (run_mode, - image_ID, - drawable_ID, - tmpname, - tmpname) && valid_file (tmpname))) - { - goto error; - } - - if (! to64 (tmpname, mailpipe, &error)) - { - g_message ("%s", error->message); - g_error_free (error); - goto error; - } - - fprintf (mailpipe, "\n--GUMP-MIME-boundary--\n"); - - goto cleanup; - -error: - /* stop sendmail from doing anything */ - kill (mailpid, SIGINT); - status = GIMP_PDB_EXECUTION_ERROR; - -cleanup: - /* close out the sendmail process */ - fclose (mailpipe); - waitpid (mailpid, NULL, 0); - g_spawn_close_pid (mailpid); - - /* delete the tmpfile that was generated */ - g_unlink (tmpname); - g_free (tmpname); + gchar *xdgargs[sizeof (gchar)]; + gulong flags; + GPid childpid; + GError *spawnerr; + + /* pass the image to xdg-email */ + g_message("%s", filename); + flags=G_SPAWN_SEARCH_PATH|G_SPAWN_STDERR_TO_DEV_NULL; + + xdgargs[0] = XDGEMAIL; + xdgargs[1] = "--attach"; + xdgargs[2] = filename; + xdgargs[3] = NULL; + + if (!(g_spawn_async (NULL, xdgargs, NULL, flags, NULL, NULL, + &childpid, &spawnerr))) + { + g_message("%s", spawnerr->message); + } + + /* kill & close */ + //g_free (xdgargs[sizeof (gchar)]); + //g_spawn_close_pid(childpid); + //g_error_free(spawnerr); return status; } - - -static gboolean -save_dialog (void) -{ - GtkWidget *dlg; - GtkWidget *main_vbox; - GtkWidget *entry; - GtkWidget *table; - GtkWidget *scrolled_window; - GtkWidget *text_view; - GtkTextBuffer *text_buffer; - gchar *gump_from; - gint row = 0; - gboolean run; - - gimp_ui_init (PLUG_IN_BINARY, FALSE); - - /* check gimprc for a preferred "From:" address */ - gump_from = gimp_gimprc_query ("gump-from"); - - if (gump_from) - { - g_strlcpy (mail_info.from, gump_from, BUFFER_SIZE); - g_free (gump_from); - } - - dlg = gimp_dialog_new (_("Send by Email"), PLUG_IN_BINARY, - NULL, 0, - gimp_standard_help_func, PLUG_IN_PROC, - - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - _("_Send"), GTK_RESPONSE_OK, - - NULL); - - gtk_dialog_set_alternative_button_order (GTK_DIALOG (dlg), - GTK_RESPONSE_OK, - GTK_RESPONSE_CANCEL, - -1); - - gimp_window_set_transient (GTK_WINDOW (dlg)); - - main_vbox = gtk_vbox_new (FALSE, 12); - gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12); - gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), - main_vbox, TRUE, TRUE, 0); - gtk_widget_show (main_vbox); - - /* table */ - table = gtk_table_new (5, 2, FALSE); - gtk_box_pack_start (GTK_BOX (main_vbox), table, FALSE, FALSE, 0); - gtk_widget_show (table); - - gtk_table_set_row_spacings (GTK_TABLE (table), 6); - gtk_table_set_row_spacing (GTK_TABLE (table), 0, 12); - gtk_table_set_col_spacings (GTK_TABLE (table), 6); - - /* Filename entry */ - entry = gtk_entry_new (); - gtk_widget_set_size_request (entry, 200, -1); - gtk_entry_set_max_length (GTK_ENTRY (entry), BUFFER_SIZE - 1); - gtk_entry_set_text (GTK_ENTRY (entry), mail_info.filename); - gimp_table_attach_aligned (GTK_TABLE (table), 0, row++, - _("_Filename:"), 0.0, 0.5, - entry, 1, FALSE); - g_signal_connect (entry, "changed", - G_CALLBACK (mail_entry_callback), - mail_info.filename); - - /* To entry */ - entry = gtk_entry_new (); - gtk_widget_set_size_request (entry, 200, -1); - gtk_entry_set_max_length (GTK_ENTRY (entry), BUFFER_SIZE - 1); - gtk_entry_set_text (GTK_ENTRY (entry), mail_info.receipt); - gimp_table_attach_aligned (GTK_TABLE (table), 0, row++, - _("_To:"), 0.0, 0.5, - entry, 1, FALSE); - g_signal_connect (entry, "changed", - G_CALLBACK (mail_entry_callback), - mail_info.receipt); - - gtk_widget_grab_focus (entry); - - /* From entry */ - entry = gtk_entry_new (); - gtk_widget_set_size_request (entry, 200, -1); - gtk_entry_set_max_length (GTK_ENTRY (entry), BUFFER_SIZE - 1); - gtk_entry_set_text (GTK_ENTRY (entry), mail_info.from); - gimp_table_attach_aligned (GTK_TABLE (table), 0, row++, - _("_From:"), 0.0, 0.5, - entry, 1, FALSE); - g_signal_connect (entry, "changed", - G_CALLBACK (mail_entry_callback), - mail_info.from); - - /* Subject entry */ - entry = gtk_entry_new (); - gtk_widget_set_size_request (entry, 200, -1); - gtk_entry_set_max_length (GTK_ENTRY (entry), BUFFER_SIZE - 1); - gtk_entry_set_text (GTK_ENTRY (entry), mail_info.subject); - gimp_table_attach_aligned (GTK_TABLE (table), 0, row++, - _("S_ubject:"), 0.0, 0.5, - entry, 1, FALSE); - g_signal_connect (entry, "changed", - G_CALLBACK (mail_entry_callback), - mail_info.subject); - - /* Body */ - scrolled_window = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window), - GTK_SHADOW_IN); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_AUTOMATIC); - gtk_box_pack_start (GTK_BOX (main_vbox), scrolled_window, TRUE, TRUE, 0); - gtk_widget_show (scrolled_window); - - text_buffer = gtk_text_buffer_new (NULL); - - g_signal_connect (text_buffer, "changed", - G_CALLBACK (mesg_body_callback), - NULL); - - gtk_text_buffer_set_text (text_buffer, mail_info.comment, -1); - - text_view = gtk_text_view_new_with_buffer (text_buffer); - g_object_unref (text_buffer); - - gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text_view), GTK_WRAP_WORD); - gtk_container_add (GTK_CONTAINER (scrolled_window), text_view); - gtk_widget_show (text_view); - - gtk_widget_show (dlg); - - run = (gimp_dialog_run (GIMP_DIALOG (dlg)) == GTK_RESPONSE_OK); - - gtk_widget_destroy (dlg); - - return run; -} - -static gboolean -valid_file (const gchar *filename) -{ - struct stat buf; - - return g_stat (filename, &buf) == 0 && buf.st_size > 0; -} - -static gchar * -find_content_type (const gchar *filename) -{ - /* This function returns a MIME Content-type: value based on the - filename it is given. */ - const gchar *type_mappings[20] = - { - "gif" , "image/gif", - "jpg" , "image/jpeg", - "jpeg", "image/jpeg", - "tif" , "image/tiff", - "tiff", "image/tiff", - "png" , "image/png", - "g3" , "image/g3fax", - "ps" , "application/postscript", - "eps" , "application/postscript", - NULL, NULL - }; - - gchar *ext; - gint i; - - ext = find_extension (filename); - - if (!ext) - { - return g_strdup ("application/octet-stream"); - } - - i = 0; - ext += 1; - - while (type_mappings[i]) - { - if (g_ascii_strcasecmp (ext, type_mappings[i]) == 0) - { - return g_strdup (type_mappings[i + 1]); - } - - i += 2; - } - - return g_strdup_printf ("image/x-%s", ext); -} - -static gchar * -find_extension (const gchar *filename) -{ - gchar *filename_copy; - gchar *ext; - - /* we never free this copy - aren't we evil! */ - filename_copy = g_strdup (filename); - - /* find the extension, boy! */ - ext = strrchr (filename_copy, '.'); - - while (TRUE) - { - if (!ext || ext[1] == '\0' || strchr (ext, G_DIR_SEPARATOR)) - { - g_message (_("some sort of error with the file extension " - "or lack thereof")); - - return NULL; - } - - if (0 != g_ascii_strcasecmp (ext, ".gz") && - 0 != g_ascii_strcasecmp (ext, ".bz2")) - { - return ext; - } - else - { - /* we found somehting, loop back, and look again */ - *ext = 0; - ext = strrchr (filename_copy, '.'); - } - } - - return ext; -} - -static void -mail_entry_callback (GtkWidget *widget, - gchar *data) -{ - g_strlcpy (data, gtk_entry_get_text (GTK_ENTRY (widget)), BUFFER_SIZE); -} - -static void -mesg_body_callback (GtkTextBuffer *buffer, - gpointer data) -{ - GtkTextIter start_iter; - GtkTextIter end_iter; - - gtk_text_buffer_get_bounds (buffer, &start_iter, &end_iter); - - g_free (mesg_body); - mesg_body = gtk_text_buffer_get_text (buffer, &start_iter, &end_iter, FALSE); -} - -static void -create_headers (FILE *mailpipe) -{ - /* create all the mail header stuff. Feel free to add your own */ - /* It is advisable to leave the X-Mailer header though, as */ - /* there is a possibilty of a Gimp mail scanner/reader in the */ - /* future. It will probabaly need that header. */ - - fprintf (mailpipe, "To: %s \n", mail_info.receipt); - fprintf (mailpipe, "Subject: %s \n", mail_info.subject); - if (strlen (mail_info.from) > 0) - fprintf (mailpipe, "From: %s \n", mail_info.from); - - fprintf (mailpipe, "X-Mailer: GIMP Useless Mail Plug-In %s\n", GIMP_VERSION); - - fprintf (mailpipe, "MIME-Version: 1.0\n"); - fprintf (mailpipe, "Content-type: multipart/mixed; " - "boundary=GUMP-MIME-boundary\n"); - - fprintf (mailpipe, "\n\n"); - - fprintf (mailpipe, "--GUMP-MIME-boundary\n"); - fprintf (mailpipe, "Content-type: text/plain; charset=UTF-8\n\n"); - - if (mesg_body) - fprintf (mailpipe, "%s", mesg_body); - - fprintf (mailpipe, "\n\n"); - - { - gchar *content = find_content_type (mail_info.filename); - - fprintf (mailpipe, "--GUMP-MIME-boundary\n"); - fprintf (mailpipe, "Content-type: %s\n", content); - fprintf (mailpipe, "Content-transfer-encoding: base64\n"); - fprintf (mailpipe, "Content-disposition: attachment; filename=\"%s\"\n", - mail_info.filename); - fprintf (mailpipe, "Content-description: %s\n\n", mail_info.filename); - - g_free (content); - } -} - -static gboolean -to64 (const gchar *filename, - FILE *outfile, - GError **error) -{ - GMappedFile *infile; - const guchar *in; - gchar out[2048]; - gint state = 0; - gint save = 0; - gsize len; - gsize bytes; - gsize c; - - infile = g_mapped_file_new (filename, FALSE, error); - if (! infile) - return FALSE; - - in = (const guchar *) g_mapped_file_get_contents (infile); - len = g_mapped_file_get_length (infile); - - for (c = 0; c < len;) - { - gsize step = MIN (1024, len - c); - - bytes = g_base64_encode_step (in + c, step, TRUE, out, &state, &save); - fwrite (out, 1, bytes, outfile); - - c += step; - } - - bytes = g_base64_encode_close (TRUE, out, &state, &save); - fwrite (out, 1, bytes, outfile); - -#if GLIB_CHECK_VERSION(2, 21, 3) - g_mapped_file_unref (infile); -#else - g_mapped_file_free (infile); -#endif - - return TRUE; -} - -static FILE * -sendmail_pipe (gchar **cmd, - GPid *pid) -{ - gint fd; - GError *err = NULL; - - if (! g_spawn_async_with_pipes (NULL, cmd, NULL, G_SPAWN_DO_NOT_REAP_CHILD, - NULL, NULL, pid, &fd, NULL, NULL, &err)) - { - g_message (_("Could not start sendmail (%s)"), err->message); - g_error_free (err); - - *pid = -1; - return NULL; - } - - return fdopen (fd, "wb"); -} -- 1.6.0.4
_______________________________________________ Gimp-developer mailing list Gimp-developer@xxxxxxxxxxxxxxxxxxxxxx https://lists.XCF.Berkeley.EDU/mailman/listinfo/gimp-developer