1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 * Copyright (C) 1997 Daniel Risacher
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 */
18
19 /*
20 * GUMP - Gimp Useless Mail Plugin
21 * (or Gump Useless Mail Plugin if you prefer)
22 *
23 * by Adrian Likins <adrian@gimp.org>
24 * MIME encapsulation by Reagan Blundell <reagan@emails.net>
25 *
26 * As always: The utility of this plugin is left as an exercise for
27 * the reader
28 *
29 */
30
31 #include "config.h"
32
33 #include <string.h>
34
35 #ifdef SENDMAIL
36 #include <sys/types.h>
37 #include <sys/wait.h>
38 #endif
39
40 #include <glib/gstdio.h>
41
42 #include <libgimp/gimp.h>
43 #include <libgimp/gimpui.h>
44
45 #include "libgimp/stdplugins-intl.h"
46
47 #define BUFFER_SIZE 256
48
49 #define PLUG_IN_PROC "plug-in-mail-image"
50 #define PLUG_IN_BINARY "mail"
51 #define PLUG_IN_ROLE "gimp-mail"
52
53 typedef struct
54 {
55 gchar filename[BUFFER_SIZE];
56 gchar receipt[BUFFER_SIZE];
57 gchar from[BUFFER_SIZE];
58 gchar subject[BUFFER_SIZE];
59 gchar comment[BUFFER_SIZE];
60 } m_info;
61
62
63 static void query (void);
64 static void run (const gchar *name,
65 gint nparams,
66 const GimpParam *param,
67 gint *nreturn_vals,
68 GimpParam **return_vals);
69
70 static GimpPDBStatusType send_image (const gchar *filename,
71 gint32 image_ID,
72 gint32 drawable_ID,
73 gint32 run_mode);
74
75 static gboolean send_dialog (void);
76 static void mail_entry_callback (GtkWidget *widget,
77 gchar *data);
78 static gboolean valid_file (const gchar *filename);
79 static gchar * find_extension (const gchar *filename);
80
81 #ifdef SENDMAIL
82 static void mesg_body_callback (GtkTextBuffer *buffer,
83 gpointer data);
84
85 static gchar * sendmail_content_type (const gchar *filename);
86 static void sendmail_create_headers (FILE *mailpipe);
87 static gboolean sendmail_to64 (const gchar *filename,
88 FILE *outfile,
89 GError **error);
90 static FILE * sendmail_pipe (gchar **cmd,
91 GPid *pid);
92 #endif
93
94
95 const GimpPlugInInfo PLUG_IN_INFO =
96 {
97 NULL, /* init_proc */
98 NULL, /* quit_proc */
99 query, /* query_proc */
100 run, /* run_proc */
101 };
102
103 static m_info mail_info =
104 {
105 "", "", "", "", ""
106 };
107
108 static gchar *mesg_body = NULL;
109
110
MAIN()111 MAIN ()
112
113 static void
114 query (void)
115 {
116 gchar *email_bin;
117
118 static const GimpParamDef args[] =
119 {
120 { GIMP_PDB_INT32, "run-mode", "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
121 { GIMP_PDB_IMAGE, "image", "Input image" },
122 { GIMP_PDB_DRAWABLE, "drawable", "Drawable to save" },
123 { GIMP_PDB_STRING, "filename", "The name of the file to save the image in" },
124 { GIMP_PDB_STRING, "to-address", "The email address to send to" },
125 { GIMP_PDB_STRING, "from-address", "The email address for the From: field" },
126 { GIMP_PDB_STRING, "subject", "The subject" },
127 { GIMP_PDB_STRING, "comment", "The Comment" },
128 { GIMP_PDB_INT32, "encapsulation", "ignored" }
129 };
130
131 /* Check if xdg-email or sendmail is installed.
132 * TODO: allow setting the location of the executable in preferences.
133 */
134 #ifdef SENDMAIL
135 if (strlen (SENDMAIL) == 0)
136 {
137 email_bin = g_find_program_in_path ("sendmail");
138 }
139 else
140 {
141 /* If a directory has been set at build time, we assume that sendmail
142 * can only be in this directory. */
143 email_bin = g_build_filename (SENDMAIL, "sendmail", NULL);
144 if (! g_file_test (email_bin, G_FILE_TEST_IS_EXECUTABLE))
145 {
146 g_free (email_bin);
147 email_bin = NULL;
148 }
149 }
150 #else
151 email_bin = g_find_program_in_path ("xdg-email");
152 #endif
153
154 if (email_bin == NULL)
155 return;
156
157 gimp_install_procedure (PLUG_IN_PROC,
158 N_("Send the image by email"),
159 #ifdef SENDMAIL
160 "Sendmail is used to send emails and must be properly configured.",
161 #else /* xdg-email */
162 "The preferred email composer is used to send emails and must be properly configured.",
163 #endif
164 "Adrian Likins, Reagan Blundell",
165 "Adrian Likins, Reagan Blundell, Daniel Risacher, "
166 "Spencer Kimball and Peter Mattis",
167 "1995-1997",
168 N_("Send by E_mail..."),
169 "*",
170 GIMP_PLUGIN,
171 G_N_ELEMENTS (args), 0,
172 args, NULL);
173
174 gimp_plugin_menu_register (PLUG_IN_PROC, "<Image>/File/Send");
175 gimp_plugin_icon_register (PLUG_IN_PROC, GIMP_ICON_TYPE_ICON_NAME,
176 (const guint8 *) GIMP_ICON_EDIT);
177
178 g_free (email_bin);
179 }
180
181 static void
run(const gchar * name,gint nparams,const GimpParam * param,gint * nreturn_vals,GimpParam ** return_vals)182 run (const gchar *name,
183 gint nparams,
184 const GimpParam *param,
185 gint *nreturn_vals,
186 GimpParam **return_vals)
187 {
188 static GimpParam values[2];
189 GimpRunMode run_mode;
190 GimpPDBStatusType status = GIMP_PDB_SUCCESS;
191 gint32 image_ID;
192 gint32 drawable_ID;
193
194 INIT_I18N ();
195
196 run_mode = param[0].data.d_int32;
197 image_ID = param[1].data.d_image;
198 drawable_ID = param[2].data.d_drawable;
199
200 *nreturn_vals = 1;
201 *return_vals = values;
202
203 values[0].type = GIMP_PDB_STATUS;
204 values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
205
206 if (strcmp (name, PLUG_IN_PROC) == 0)
207 {
208 switch (run_mode)
209 {
210 case GIMP_RUN_INTERACTIVE:
211 gimp_get_data (PLUG_IN_PROC, &mail_info);
212 {
213 gchar *filename = gimp_image_get_filename (image_ID);
214
215 if (filename)
216 {
217 gchar *basename = g_filename_display_basename (filename);
218
219 g_strlcpy (mail_info.filename, basename, BUFFER_SIZE);
220 g_free (basename);
221 g_free (filename);
222 }
223 }
224
225 if (! send_dialog ())
226 status = GIMP_PDB_CANCEL;
227 break;
228
229 case GIMP_RUN_NONINTERACTIVE:
230 /* Make sure all the arguments are there! */
231 if (nparams < 8)
232 {
233 status = GIMP_PDB_CALLING_ERROR;
234 }
235 else
236 {
237 g_strlcpy (mail_info.filename,
238 param[3].data.d_string, BUFFER_SIZE);
239 g_strlcpy (mail_info.receipt,
240 param[4].data.d_string, BUFFER_SIZE);
241 g_strlcpy (mail_info.from,
242 param[5].data.d_string, BUFFER_SIZE);
243 g_strlcpy (mail_info.subject,
244 param[6].data.d_string, BUFFER_SIZE);
245 g_strlcpy (mail_info.comment,
246 param[7].data.d_string, BUFFER_SIZE);
247 }
248 break;
249
250 case GIMP_RUN_WITH_LAST_VALS:
251 gimp_get_data (PLUG_IN_PROC, &mail_info);
252 break;
253
254 default:
255 break;
256 }
257
258 if (status == GIMP_PDB_SUCCESS)
259 {
260 status = send_image (mail_info.filename,
261 image_ID,
262 drawable_ID,
263 run_mode);
264
265 if (status == GIMP_PDB_SUCCESS)
266 {
267 if (mesg_body)
268 g_strlcpy (mail_info.comment, mesg_body, BUFFER_SIZE);
269
270 gimp_set_data (PLUG_IN_PROC, &mail_info, sizeof (m_info));
271 }
272 }
273 }
274 else
275 {
276 status = GIMP_PDB_CALLING_ERROR;
277 }
278
279 values[0].data.d_status = status;
280 }
281
282 static GimpPDBStatusType
send_image(const gchar * filename,gint32 image_ID,gint32 drawable_ID,gint32 run_mode)283 send_image (const gchar *filename,
284 gint32 image_ID,
285 gint32 drawable_ID,
286 gint32 run_mode)
287 {
288 GimpPDBStatusType status = GIMP_PDB_SUCCESS;
289 gchar *ext;
290 gchar *tmpname;
291 #ifndef SENDMAIL /* xdg-email */
292 gchar *mailcmd[9];
293 gchar *filepath = NULL;
294 GFile *tmp_dir = NULL;
295 GFileEnumerator *enumerator;
296 gint i;
297 #else /* SENDMAIL */
298 gchar *mailcmd[3];
299 GPid mailpid;
300 FILE *mailpipe = NULL;
301 #endif
302 GError *error = NULL;
303
304 ext = find_extension (filename);
305
306 if (ext == NULL)
307 return GIMP_PDB_CALLING_ERROR;
308
309 /* get a temp name with the right extension and save into it. */
310 tmpname = gimp_temp_name (ext + 1);
311
312 if (! (gimp_file_save (run_mode,
313 image_ID,
314 drawable_ID,
315 tmpname,
316 tmpname) && valid_file (tmpname)))
317 {
318 goto error;
319 }
320
321 #ifndef SENDMAIL /* xdg-email */
322 /* From xdg-email doc:
323 * "Some e-mail applications require the file to remain present
324 * after xdg-email returns."
325 * As a consequence, the file cannot be removed at the end of the
326 * function. We actually have no way to ever know *when* the file can
327 * be removed since the caller could leave the email window opened for
328 * hours. Yet we still want to clean sometimes and not have temporary
329 * images piling up.
330 * So I use a known directory that we control under $GIMP_DIRECTORY/tmp/,
331 * and clean it out each time the plugin runs. This means that *if* you
332 * are in the above case (your email client requires the file to stay
333 * alive), * you cannot run twice the plugin at the same time.
334 */
335 tmp_dir = gimp_directory_file ("tmp", PLUG_IN_PROC, NULL);
336
337 if (g_mkdir_with_parents (gimp_file_get_utf8_name (tmp_dir),
338 S_IRUSR | S_IWUSR | S_IXUSR) == -1)
339 {
340 g_message ("Temporary directory %s could not be created.",
341 gimp_file_get_utf8_name (tmp_dir));
342 g_error_free (error);
343 goto error;
344 }
345
346 enumerator = g_file_enumerate_children (tmp_dir,
347 G_FILE_ATTRIBUTE_STANDARD_TYPE,
348 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
349 NULL, NULL);
350 if (enumerator)
351 {
352 GFileInfo *info;
353
354 while ((info = g_file_enumerator_next_file (enumerator,
355 NULL, NULL)))
356 {
357 if (g_file_info_get_file_type (info) == G_FILE_TYPE_REGULAR)
358 {
359 GFile *file = g_file_enumerator_get_child (enumerator, info);
360 g_file_delete (file, NULL, NULL);
361 g_object_unref (file);
362 }
363
364 g_object_unref (info);
365 }
366
367 g_object_unref (enumerator);
368 }
369
370 filepath = g_build_filename (gimp_file_get_utf8_name (tmp_dir),
371 mail_info.filename, NULL);
372 g_rename (tmpname, filepath);
373
374 mailcmd[0] = g_strdup ("xdg-email");
375 mailcmd[1] = "--attach";
376 mailcmd[2] = filepath;
377 i = 3;
378 if (strlen (mail_info.subject) > 0)
379 {
380 mailcmd[i++] = "--subject";
381 mailcmd[i++] = mail_info.subject;
382 }
383 if (strlen (mail_info.comment) > 0)
384 {
385 mailcmd[i++] = "--body";
386 mailcmd[i++] = mail_info.comment;
387 }
388 if (strlen (mail_info.receipt) > 0)
389 {
390 mailcmd[i++] = mail_info.receipt;
391 }
392 mailcmd[i] = NULL;
393
394 if (! g_spawn_async (NULL, mailcmd, NULL,
395 G_SPAWN_SEARCH_PATH,
396 NULL, NULL, NULL, &error))
397 {
398 g_message ("%s", error->message);
399 g_error_free (error);
400 goto error;
401 }
402
403 #else /* SENDMAIL */
404 /* construct the "sendmail user@location" line */
405 if (strlen (SENDMAIL) == 0)
406 mailcmd[0] = g_strdup ("sendmail");
407 else
408 mailcmd[0] = g_build_filename (SENDMAIL, "sendmail", NULL);
409
410 mailcmd[1] = mail_info.receipt;
411 mailcmd[2] = NULL;
412
413 /* create a pipe to sendmail */
414 mailpipe = sendmail_pipe (mailcmd, &mailpid);
415
416 if (mailpipe == NULL)
417 return GIMP_PDB_EXECUTION_ERROR;
418
419 sendmail_create_headers (mailpipe);
420
421 fflush (mailpipe);
422
423 if (! sendmail_to64 (tmpname, mailpipe, &error))
424 {
425 g_message ("%s", error->message);
426 g_error_free (error);
427 goto error;
428 }
429
430 fprintf (mailpipe, "\n--GUMP-MIME-boundary--\n");
431 #endif
432
433 goto cleanup;
434
435 error:
436 /* stop sendmail from doing anything */
437 #ifdef SENDMAIL
438 kill (mailpid, SIGINT);
439 #endif
440 status = GIMP_PDB_EXECUTION_ERROR;
441
442 cleanup:
443 /* close out the sendmail process */
444 #ifdef SENDMAIL
445 if (mailpipe)
446 {
447 fclose (mailpipe);
448 waitpid (mailpid, NULL, 0);
449 g_spawn_close_pid (mailpid);
450 }
451
452 /* delete the tmpfile that was generated */
453 g_unlink (tmpname);
454 #else
455 if (tmp_dir)
456 g_object_unref (tmp_dir);
457 if (filepath)
458 g_free (filepath);
459 #endif
460
461 g_free (mailcmd[0]);
462 g_free (tmpname);
463
464 return status;
465 }
466
467
468 static gboolean
send_dialog(void)469 send_dialog (void)
470 {
471 GtkWidget *dlg;
472 GtkWidget *main_vbox;
473 GtkWidget *entry;
474 GtkWidget *table;
475 #ifdef SENDMAIL
476 GtkWidget *scrolled_window;
477 GtkWidget *text_view;
478 GtkTextBuffer *text_buffer;
479 #endif
480 gchar *gump_from;
481 gint row = 0;
482 gboolean run;
483
484 gimp_ui_init (PLUG_IN_BINARY, FALSE);
485
486 /* check gimprc for a preferred "From:" address */
487 gump_from = gimp_gimprc_query ("gump-from");
488
489 if (gump_from)
490 {
491 g_strlcpy (mail_info.from, gump_from, BUFFER_SIZE);
492 g_free (gump_from);
493 }
494
495 dlg = gimp_dialog_new (_("Send by Email"), PLUG_IN_ROLE,
496 NULL, 0,
497 gimp_standard_help_func, PLUG_IN_PROC,
498
499 _("_Cancel"), GTK_RESPONSE_CANCEL,
500 _("_Send"), GTK_RESPONSE_OK,
501
502 NULL);
503
504 gtk_dialog_set_alternative_button_order (GTK_DIALOG (dlg),
505 GTK_RESPONSE_OK,
506 GTK_RESPONSE_CANCEL,
507 -1);
508
509 gimp_window_set_transient (GTK_WINDOW (dlg));
510
511 main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
512 gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
513 gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))),
514 main_vbox, TRUE, TRUE, 0);
515 gtk_widget_show (main_vbox);
516
517 /* table */
518 table = gtk_table_new (5, 2, FALSE);
519 gtk_box_pack_start (GTK_BOX (main_vbox), table, FALSE, FALSE, 0);
520 gtk_widget_show (table);
521
522 gtk_table_set_row_spacings (GTK_TABLE (table), 6);
523 gtk_table_set_row_spacing (GTK_TABLE (table), 0, 12);
524 gtk_table_set_col_spacings (GTK_TABLE (table), 6);
525
526 /* Filename entry */
527 entry = gtk_entry_new ();
528 gtk_widget_set_size_request (entry, 200, -1);
529 gtk_entry_set_max_length (GTK_ENTRY (entry), BUFFER_SIZE - 1);
530 gtk_entry_set_text (GTK_ENTRY (entry), mail_info.filename);
531 gimp_table_attach_aligned (GTK_TABLE (table), 0, row++,
532 _("_Filename:"), 0.0, 0.5,
533 entry, 1, FALSE);
534 g_signal_connect (entry, "changed",
535 G_CALLBACK (mail_entry_callback),
536 mail_info.filename);
537 gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
538
539 #ifdef SENDMAIL
540 /* To entry */
541 entry = gtk_entry_new ();
542 gtk_widget_set_size_request (entry, 200, -1);
543 gtk_entry_set_max_length (GTK_ENTRY (entry), BUFFER_SIZE - 1);
544 gtk_entry_set_text (GTK_ENTRY (entry), mail_info.receipt);
545 gimp_table_attach_aligned (GTK_TABLE (table), 0, row++,
546 C_("email-address", "_To:"), 0.0, 0.5,
547 entry, 1, FALSE);
548 g_signal_connect (entry, "changed",
549 G_CALLBACK (mail_entry_callback),
550 mail_info.receipt);
551
552 gtk_widget_grab_focus (entry);
553
554 /* From entry */
555 entry = gtk_entry_new ();
556 gtk_widget_set_size_request (entry, 200, -1);
557 gtk_entry_set_max_length (GTK_ENTRY (entry), BUFFER_SIZE - 1);
558 gtk_entry_set_text (GTK_ENTRY (entry), mail_info.from);
559 gimp_table_attach_aligned (GTK_TABLE (table), 0, row++,
560 C_("email-address", "_From:"), 0.0, 0.5,
561 entry, 1, FALSE);
562 g_signal_connect (entry, "changed",
563 G_CALLBACK (mail_entry_callback),
564 mail_info.from);
565
566 /* Subject entry */
567 entry = gtk_entry_new ();
568 gtk_widget_set_size_request (entry, 200, -1);
569 gtk_entry_set_max_length (GTK_ENTRY (entry), BUFFER_SIZE - 1);
570 gtk_entry_set_text (GTK_ENTRY (entry), mail_info.subject);
571 gimp_table_attach_aligned (GTK_TABLE (table), 0, row++,
572 _("S_ubject:"), 0.0, 0.5,
573 entry, 1, FALSE);
574 g_signal_connect (entry, "changed",
575 G_CALLBACK (mail_entry_callback),
576 mail_info.subject);
577
578 /* Body */
579 scrolled_window = gtk_scrolled_window_new (NULL, NULL);
580 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
581 GTK_SHADOW_IN);
582 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
583 GTK_POLICY_AUTOMATIC,
584 GTK_POLICY_AUTOMATIC);
585 gtk_box_pack_start (GTK_BOX (main_vbox), scrolled_window, TRUE, TRUE, 0);
586 gtk_widget_show (scrolled_window);
587
588 text_buffer = gtk_text_buffer_new (NULL);
589
590 g_signal_connect (text_buffer, "changed",
591 G_CALLBACK (mesg_body_callback),
592 NULL);
593
594 gtk_text_buffer_set_text (text_buffer, mail_info.comment, -1);
595
596 text_view = gtk_text_view_new_with_buffer (text_buffer);
597 g_object_unref (text_buffer);
598
599 gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (text_view), GTK_WRAP_WORD);
600 gtk_container_add (GTK_CONTAINER (scrolled_window), text_view);
601 gtk_widget_show (text_view);
602 #endif
603
604 gtk_widget_show (dlg);
605
606 run = (gimp_dialog_run (GIMP_DIALOG (dlg)) == GTK_RESPONSE_OK);
607
608 gtk_widget_destroy (dlg);
609
610 return run;
611 }
612
613 static gboolean
valid_file(const gchar * filename)614 valid_file (const gchar *filename)
615 {
616 GStatBuf buf;
617
618 return g_stat (filename, &buf) == 0 && buf.st_size > 0;
619 }
620
621 static gchar *
find_extension(const gchar * filename)622 find_extension (const gchar *filename)
623 {
624 gchar *filename_copy;
625 gchar *ext;
626
627 /* we never free this copy - aren't we evil! */
628 filename_copy = g_strdup (filename);
629
630 /* find the extension, boy! */
631 ext = strrchr (filename_copy, '.');
632
633 while (TRUE)
634 {
635 if (!ext || ext[1] == '\0' || strchr (ext, G_DIR_SEPARATOR))
636 {
637 g_message (_("some sort of error with the file extension "
638 "or lack thereof"));
639
640 return NULL;
641 }
642
643 if (0 != g_ascii_strcasecmp (ext, ".gz") &&
644 0 != g_ascii_strcasecmp (ext, ".bz2"))
645 {
646 return ext;
647 }
648 else
649 {
650 /* we found something, loop back, and look again */
651 *ext = 0;
652 ext = strrchr (filename_copy, '.');
653 }
654 }
655
656 g_free (filename_copy);
657
658 return ext;
659 }
660
661 static void
mail_entry_callback(GtkWidget * widget,gchar * data)662 mail_entry_callback (GtkWidget *widget,
663 gchar *data)
664 {
665 g_strlcpy (data, gtk_entry_get_text (GTK_ENTRY (widget)), BUFFER_SIZE);
666 }
667
668 #ifdef SENDMAIL
669 static void
mesg_body_callback(GtkTextBuffer * buffer,gpointer data)670 mesg_body_callback (GtkTextBuffer *buffer,
671 gpointer data)
672 {
673 GtkTextIter start_iter;
674 GtkTextIter end_iter;
675
676 gtk_text_buffer_get_bounds (buffer, &start_iter, &end_iter);
677
678 g_free (mesg_body);
679 mesg_body = gtk_text_buffer_get_text (buffer, &start_iter, &end_iter, FALSE);
680 }
681
682 static gchar *
sendmail_content_type(const gchar * filename)683 sendmail_content_type (const gchar *filename)
684 {
685 /* This function returns a MIME Content-type: value based on the
686 filename it is given. */
687 const gchar *type_mappings[20] =
688 {
689 "gif" , "image/gif",
690 "jpg" , "image/jpeg",
691 "jpeg", "image/jpeg",
692 "tif" , "image/tiff",
693 "tiff", "image/tiff",
694 "png" , "image/png",
695 "g3" , "image/g3fax",
696 "ps" , "application/postscript",
697 "eps" , "application/postscript",
698 NULL, NULL
699 };
700
701 gchar *ext;
702 gint i;
703
704 ext = find_extension (filename);
705
706 if (!ext)
707 {
708 return g_strdup ("application/octet-stream");
709 }
710
711 i = 0;
712 ext += 1;
713
714 while (type_mappings[i])
715 {
716 if (g_ascii_strcasecmp (ext, type_mappings[i]) == 0)
717 {
718 return g_strdup (type_mappings[i + 1]);
719 }
720
721 i += 2;
722 }
723
724 return g_strdup_printf ("image/x-%s", ext);
725 }
726
727 static void
sendmail_create_headers(FILE * mailpipe)728 sendmail_create_headers (FILE *mailpipe)
729 {
730 /* create all the mail header stuff. Feel free to add your own */
731 /* It is advisable to leave the X-Mailer header though, as */
732 /* there is a possibility of a Gimp mail scanner/reader in the */
733 /* future. It will probabaly need that header. */
734
735 fprintf (mailpipe, "To: %s \n", mail_info.receipt);
736 fprintf (mailpipe, "Subject: %s \n", mail_info.subject);
737 if (strlen (mail_info.from) > 0)
738 fprintf (mailpipe, "From: %s \n", mail_info.from);
739
740 fprintf (mailpipe, "X-Mailer: GIMP Useless Mail plug-in %s\n", GIMP_VERSION);
741
742 fprintf (mailpipe, "MIME-Version: 1.0\n");
743 fprintf (mailpipe, "Content-type: multipart/mixed; "
744 "boundary=GUMP-MIME-boundary\n");
745
746 fprintf (mailpipe, "\n\n");
747
748 fprintf (mailpipe, "--GUMP-MIME-boundary\n");
749 fprintf (mailpipe, "Content-type: text/plain; charset=UTF-8\n\n");
750
751 if (mesg_body)
752 fprintf (mailpipe, "%s", mesg_body);
753
754 fprintf (mailpipe, "\n\n");
755
756 {
757 gchar *content = sendmail_content_type (mail_info.filename);
758
759 fprintf (mailpipe, "--GUMP-MIME-boundary\n");
760 fprintf (mailpipe, "Content-type: %s\n", content);
761 fprintf (mailpipe, "Content-transfer-encoding: base64\n");
762 fprintf (mailpipe, "Content-disposition: attachment; filename=\"%s\"\n",
763 mail_info.filename);
764 fprintf (mailpipe, "Content-description: %s\n\n", mail_info.filename);
765
766 g_free (content);
767 }
768 }
769
770 static gboolean
sendmail_to64(const gchar * filename,FILE * outfile,GError ** error)771 sendmail_to64 (const gchar *filename,
772 FILE *outfile,
773 GError **error)
774 {
775 GMappedFile *infile;
776 const guchar *in;
777 gchar out[2048];
778 gint state = 0;
779 gint save = 0;
780 gsize len;
781 gsize bytes;
782 gsize c;
783
784 infile = g_mapped_file_new (filename, FALSE, error);
785 if (! infile)
786 return FALSE;
787
788 in = (const guchar *) g_mapped_file_get_contents (infile);
789 len = g_mapped_file_get_length (infile);
790
791 for (c = 0; c < len;)
792 {
793 gsize step = MIN (1024, len - c);
794
795 bytes = g_base64_encode_step (in + c, step, TRUE, out, &state, &save);
796 fwrite (out, 1, bytes, outfile);
797
798 c += step;
799 }
800
801 bytes = g_base64_encode_close (TRUE, out, &state, &save);
802 fwrite (out, 1, bytes, outfile);
803
804 g_mapped_file_unref (infile);
805
806 return TRUE;
807 }
808
809 static FILE *
sendmail_pipe(gchar ** cmd,GPid * pid)810 sendmail_pipe (gchar **cmd,
811 GPid *pid)
812 {
813 gint fd;
814 GError *err = NULL;
815
816 if (! g_spawn_async_with_pipes (NULL, cmd, NULL,
817 G_SPAWN_DO_NOT_REAP_CHILD |
818 G_SPAWN_SEARCH_PATH,
819 NULL, NULL, pid, &fd, NULL, NULL, &err))
820 {
821 g_message (_("Could not start sendmail (%s)"), err->message);
822 g_error_free (err);
823
824 *pid = -1;
825 return NULL;
826 }
827
828 return fdopen (fd, "wb");
829 }
830 #endif
831