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 <cr33...@gmail.com>
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 u...@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@lists.XCF.Berkeley.EDU
https://lists.XCF.Berkeley.EDU/mailman/listinfo/gimp-developer

Reply via email to