mail.c 24 KB
Newer Older
Elliot Lee's avatar
Elliot Lee committed
1 2
/* The GIMP -- an image manipulation program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3
 * Copyright (C) 1997 Daniel Risacher
Elliot Lee's avatar
Elliot Lee committed
4 5 6 7 8 9 10 11 12 13 14 15 16
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Elliot Lee's avatar
Elliot Lee committed
18 19 20
 */

/*
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
 *   GUMP - Gimp Useless Mail Plugin (or Gump Useless Mail Plugin if you prefer)
 *          version about .85 I would say... give or take a few decimal points
 *
 *
 *   by Adrian Likins <adrian@gimp.org>
 *      MIME encapsulation by Reagan Blundell <reagan@emails.net>
 *
 *
 *
 *   Based heavily on gz.c by Daniel Risacher
 *
 *     Lets you choose to send a image to the mail from the file save as dialog.
 *      images are piped to uuencode and then to mail...
 *
 *
 *   This works fine for .99.10. I havent actually tried it in combination with
 *   the gz plugin, but it works with all other file types. I will eventually get
 *   around to making sure it works with gz.
 *
 *  To use: 1) image->File->mail image
 *          2) when the mail dialog popups up, fill it out. Only to: and filename are required
 *             note: the filename needs to a type that the image can be saved as. otherwise
 *                   you will just send an empty message.
 *          3) click ok and it should be on its way
 *
 *
 * NOTE: You probabaly need sendmail installed. If your sendmail is in an odd spot
 *       you can change the #define below. If you use qmail or other MTA's, and this
 *       works after changing the MAILER, let me know how well or what changes were
 *       needed.
 *
 * NOTE: Uuencode is needed. If it is in the path, it should work fine as is. Other-
 *       wise just change the UUENCODE.
 *
 *
56
 * TODO: 1) the aforementioned abilty to specify the
57 58 59 60 61
 *           uuencode filename                         *done*
 *       2) someway to do this without tmp files
 *              * wont happen anytime soon*
 *       3) MIME? *done*
 *       4) a pointlessly snazzier dialog
62
 *       5) make sure it works with gz
63
 *               * works for .xcfgz but not .xcf.gz *
64
 *       6) add an option to choose if mail get
65 66 67
 *          uuencode or not (or MIME'ed for that matter)
 *       7) realtime preview
 *       8) better entry for comments    *done*
68
 *       9) list of frequently used addreses
69 70
 *      10) openGL compliance
 *      11) better handling of filesave errors
71
 *
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
 *
 *  Version history
 *       .5  - 6/30/97 - inital relese
 *       .51 - 7/3/97  - fixed a few spelling errors and the like
 *       .65 - 7/4/97  - a fairly significant revision. changed it from a file
 *                       plugin to an image plugin.
 *                     - Changed some strcats into strcpy to be a bit more robust.
 *                     - added the abilty to specify the filename you want it sent as
 *                     - no more annoying hassles with the file saves as dialog
 *                     - plugin now registers itself as <image>/File/Mail image
 *       .7  - 9/12/97 - (RB) added support for MIME encapsulation
 *       .71 - 9/17/97 - (RB) included Base64 encoding functions from mpack
 *                       instead of using external program.
 *                     - General cleanup of the MIME handling code.
 *       .80 - 6/23/98 - Added a text box so you can compose real messages.
 *       .85 - 3/19/99 - Added a "From:" field. Made it check gimprc for a
88
 *                       "gump-from" token and use it. Also made "run with last
89 90 91
 *                        values" work.
 * As always: The utility of this plugin is left as an exercise for the reader
 *
Elliot Lee's avatar
Elliot Lee committed
92 93 94 95 96
 */

#define ENCAPSULATION_UUENCODE 0
#define ENCAPSULATION_MIME     1

97 98
#define BUFFER_SIZE            256

99 100
#include "config.h"

101 102 103 104 105 106 107 108
#ifndef SENDMAIL
#define SENDMAIL "/usr/lib/sendmail"
#endif

#ifndef UUENCODE
#define UUENCODE "uuencode"
#endif

Elliot Lee's avatar
Elliot Lee committed
109 110
#include <stdlib.h>
#include <stdio.h>
111
#include <sys/types.h>
Elliot Lee's avatar
Elliot Lee committed
112 113 114 115 116 117
#include <sys/param.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
118 119 120

#include <gtk/gtk.h>

121 122
#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>
Elliot Lee's avatar
Elliot Lee committed
123

124
#include "libgimp/stdplugins-intl.h"
Elliot Lee's avatar
Elliot Lee committed
125

126

127
static void   query (void);
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
static void   run   (const gchar      *name,
		     gint              nparams,
		     const GimpParam  *param,
		     gint             *nreturn_vals,
		     GimpParam       **return_vals);

static GimpPDBStatusType save_image (const gchar *filename,
			             gint32       image_ID,
			             gint32       drawable_ID,
				     gint32       run_mode);

static gint    save_dialog          (void);
static void    mail_entry_callback  (GtkWidget     *widget,
                                     gpointer       data);
static void    mesg_body_callback   (GtkTextBuffer *buffer,
                                     gpointer       data);

static gint    valid_file     (const gchar *filename);
static void    create_headers (FILE        *mailpipe);
static gchar * find_extension (const gchar *filename);
static gint    to64           (FILE        *infile,
                               FILE        *outfile);
static void    output64chunk  (gint         c1,
                               gint         c2,
                               gint         c3,
                               gint         pads,
                               FILE        *outfile);
Elliot Lee's avatar
Elliot Lee committed
155

Sven Neumann's avatar
Sven Neumann committed
156
GimpPlugInInfo PLUG_IN_INFO =
Elliot Lee's avatar
Elliot Lee committed
157
{
158 159 160 161
  NULL,  /* init_proc  */
  NULL,  /* quit_proc  */
  query, /* query_proc */
  run,   /* run_proc   */
Elliot Lee's avatar
Elliot Lee committed
162 163 164
};

typedef struct
165
{
166 167 168 169 170
  gchar receipt[BUFFER_SIZE];
  gchar subject[BUFFER_SIZE];
  gchar comment[BUFFER_SIZE];
  gchar from[BUFFER_SIZE];
  gchar filename[BUFFER_SIZE];
171 172
  gint  encapsulation;
}
Elliot Lee's avatar
Elliot Lee committed
173 174
m_info;

175 176
static m_info mail_info =
{
Elliot Lee's avatar
Elliot Lee committed
177 178 179 180 181
  /* I would a assume there is a better way to do this, but this works for now */
  "\0",
  "\0",
  "\0",
  "\0",
182
  "\0",
Elliot Lee's avatar
Elliot Lee committed
183 184 185 186
  ENCAPSULATION_MIME,  /* Change this to ENCAPSULATION_UUENCODE
			  if you prefer that as the default */
};

187
static gchar * mesg_body = NULL;
188

Elliot Lee's avatar
Elliot Lee committed
189 190 191 192

MAIN ()

static void
193
query (void)
Elliot Lee's avatar
Elliot Lee committed
194
{
Sven Neumann's avatar
Sven Neumann committed
195
  static GimpParamDef args[] =
Elliot Lee's avatar
Elliot Lee committed
196
  {
Sven Neumann's avatar
Sven Neumann committed
197 198 199 200 201 202 203 204 205
    { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
    { 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, "receipt", "The email address to send to" },
    { GIMP_PDB_STRING, "from", "The email address for the From: field" },
    { GIMP_PDB_STRING, "subject", "The subject" },
    { GIMP_PDB_STRING, "comment", "The Comment" },
    { GIMP_PDB_INT32,  "encapsulation", "Uuencode, MIME" }
Elliot Lee's avatar
Elliot Lee committed
206
  };
207

Elliot Lee's avatar
Elliot Lee committed
208
  gimp_install_procedure ("plug_in_mail_image",
Marc Lehmann's avatar
Marc Lehmann committed
209 210
			  "pipe files to uuencode then mail them",
			  "You need to have uuencode and mail installed",
Elliot Lee's avatar
Elliot Lee committed
211 212 213
			  "Adrian Likins, Reagan Blundell",
			  "Adrian Likins, Reagan Blundell, Daniel Risacher, Spencer Kimball and Peter Mattis",
			  "1995-1997",
Jakub Steiner's avatar
Jakub Steiner committed
214
			  N_("<Image>/File/_Mail Image..."),
Elliot Lee's avatar
Elliot Lee committed
215
			  "RGB*, GRAY*, INDEXED*",
Sven Neumann's avatar
Sven Neumann committed
216
			  GIMP_PLUGIN,
217
			  G_N_ELEMENTS (args), 0,
218
			  args, NULL);
Elliot Lee's avatar
Elliot Lee committed
219 220 221
}

static void
222 223 224 225 226
run (const gchar      *name,
     gint              nparams,
     const GimpParam  *param,
     gint             *nreturn_vals,
     GimpParam       **return_vals)
Elliot Lee's avatar
Elliot Lee committed
227
{
228
  static GimpParam   values[2];
229
  GimpRunMode        run_mode;
230
  GimpPDBStatusType  status = GIMP_PDB_SUCCESS;
231 232
  gint32             image_ID;
  gint32             drawable_ID;
Elliot Lee's avatar
Elliot Lee committed
233

234
  INIT_I18N ();
Elliot Lee's avatar
Elliot Lee committed
235

236 237
  run_mode    = param[0].data.d_int32;
  image_ID    = param[1].data.d_image;
Elliot Lee's avatar
Elliot Lee committed
238 239
  drawable_ID = param[2].data.d_drawable;

240 241
  *nreturn_vals = 1;
  *return_vals  = values;
242

Sven Neumann's avatar
Sven Neumann committed
243 244
  values[0].type          = GIMP_PDB_STATUS;
  values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
Elliot Lee's avatar
Elliot Lee committed
245 246 247 248 249

  if (strcmp (name, "plug_in_mail_image") == 0)
    {
      switch (run_mode)
	{
Sven Neumann's avatar
Sven Neumann committed
250
	case GIMP_RUN_INTERACTIVE:
Elliot Lee's avatar
Elliot Lee committed
251 252
	  gimp_get_data ("plug_in_mail_image", &mail_info);
	  if (!save_dialog ())
Sven Neumann's avatar
Sven Neumann committed
253
	    status = GIMP_PDB_CANCEL;
Elliot Lee's avatar
Elliot Lee committed
254
	  break;
255

Sven Neumann's avatar
Sven Neumann committed
256
	case GIMP_RUN_NONINTERACTIVE:
Elliot Lee's avatar
Elliot Lee committed
257
	  /*  Make sure all the arguments are there!  */
258
	  if (nparams != 9)
259
	    {
Sven Neumann's avatar
Sven Neumann committed
260
	      status = GIMP_PDB_CALLING_ERROR;
261 262
	    }
	  else
Elliot Lee's avatar
Elliot Lee committed
263 264
	    {
	      /* this hasnt been tested yet */
265 266 267 268 269
	      strncpy (mail_info.filename, param[3].data.d_string, BUFFER_SIZE);
	      strncpy (mail_info.receipt, param[4].data.d_string, BUFFER_SIZE);
	      strncpy (mail_info.receipt, param[5].data.d_string, BUFFER_SIZE);
	      strncpy (mail_info.subject, param[6].data.d_string, BUFFER_SIZE);
	      strncpy (mail_info.comment, param[7].data.d_string, BUFFER_SIZE);
270
	      mail_info.encapsulation = param[8].data.d_int32;
Elliot Lee's avatar
Elliot Lee committed
271 272
	    }
	  break;
273

Sven Neumann's avatar
Sven Neumann committed
274
	case GIMP_RUN_WITH_LAST_VALS:
Elliot Lee's avatar
Elliot Lee committed
275 276
	  gimp_get_data ("plug_in_mail_image", &mail_info);
	  break;
277

Elliot Lee's avatar
Elliot Lee committed
278 279 280 281
	default:
	  break;
	}

Sven Neumann's avatar
Sven Neumann committed
282
      if (status == GIMP_PDB_SUCCESS)
Elliot Lee's avatar
Elliot Lee committed
283
	{
284 285 286 287 288
	  status = save_image (mail_info.filename,
			       image_ID,
			       drawable_ID,
			       run_mode);

Sven Neumann's avatar
Sven Neumann committed
289
	  if (status == GIMP_PDB_SUCCESS)
290
	    gimp_set_data ("plug_in_mail_image", &mail_info, sizeof(m_info));
Elliot Lee's avatar
Elliot Lee committed
291 292 293
	}
    }
  else
294
    {
Sven Neumann's avatar
Sven Neumann committed
295
      status = GIMP_PDB_CALLING_ERROR;
296 297 298
    }

  values[0].data.d_status = status;
Elliot Lee's avatar
Elliot Lee committed
299 300
}

Sven Neumann's avatar
Sven Neumann committed
301
static GimpPDBStatusType
302 303 304 305
save_image (const gchar *filename,
	    gint32       image_ID,
	    gint32       drawable_ID,
	    gint32       run_mode)
Elliot Lee's avatar
Elliot Lee committed
306
{
307 308 309 310
  gchar  *ext;
  gchar  *tmpname;
  gchar   mailcmdline[512];
  gint    pid;
311
  gint    wpid;
312 313 314
  gint    process_status;
  FILE   *mailpipe;
  FILE   *infile;
Elliot Lee's avatar
Elliot Lee committed
315 316

  if (NULL == (ext = find_extension (filename)))
Sven Neumann's avatar
Sven Neumann committed
317
    return GIMP_PDB_CALLING_ERROR;
Elliot Lee's avatar
Elliot Lee committed
318 319

  /* get a temp name with the right extension and save into it. */
320
  tmpname = gimp_temp_name (ext + 1);
Elliot Lee's avatar
Elliot Lee committed
321 322

  /* construct the "sendmail user@location" line */
323
  strcpy (mailcmdline, SENDMAIL);
Elliot Lee's avatar
Elliot Lee committed
324 325 326 327 328
  strcat (mailcmdline, " ");
  strcat (mailcmdline, mail_info.receipt);

  /* create a pipe to sendmail */
  mailpipe = popen (mailcmdline, "w");
329

Elliot Lee's avatar
Elliot Lee committed
330
  create_headers (mailpipe);
331

Elliot Lee's avatar
Elliot Lee committed
332
  /* This is necessary to make the comments and headers work correctly. Not real sure why */
333
  fflush (mailpipe);
Elliot Lee's avatar
Elliot Lee committed
334

335 336 337
  if (! (gimp_file_save (run_mode,
			 image_ID,
			 drawable_ID,
338
			 tmpname,
339
			 tmpname) && valid_file (tmpname)) )
Elliot Lee's avatar
Elliot Lee committed
340 341
    {
      unlink (tmpname);
342
      g_free (tmpname);
343
      return GIMP_PDB_EXECUTION_ERROR;
Elliot Lee's avatar
Elliot Lee committed
344 345
    }

346 347
  if (mail_info.encapsulation == ENCAPSULATION_UUENCODE)
    {
Elliot Lee's avatar
Elliot Lee committed
348 349
      /* fork off a uuencode process */
      if ((pid = fork ()) < 0)
350
	{
351
	  g_message ("fork() failed: %s", g_strerror (errno));
352
	  g_free (tmpname);
Sven Neumann's avatar
Sven Neumann committed
353
	  return GIMP_PDB_EXECUTION_ERROR;
354
	}
Elliot Lee's avatar
Elliot Lee committed
355
      else if (pid == 0)
356 357 358
	{
	  if (-1 == dup2 (fileno (mailpipe), fileno (stdout)))
	    {
359
	      g_message ("dup2() failed: %s", g_strerror (errno));
360 361 362 363
	    }

	  execlp (UUENCODE, UUENCODE, tmpname, filename, NULL);
	  /* What are we doing here? exec must have failed */
364
	  g_message ("exec failed: uuencode: %s", g_strerror (errno));
365 366 367 368 369 370

	  /* close the pipe now */
	  pclose (mailpipe);
	  g_free (tmpname);
	  _exit (127);
	}
Elliot Lee's avatar
Elliot Lee committed
371
      else
372
        {
373
	  wpid = waitpid (pid, &process_status, 0);
374

375 376 377
	  if ((wpid < 0)
	      || !WIFEXITED (process_status)
	      || (WEXITSTATUS (process_status) != 0))
378
	    {
379
	      g_message ("mail didnt work or something on file '%s'",
380
                         gimp_filename_to_utf8 (tmpname));
381
	      g_free (tmpname);
Sven Neumann's avatar
Sven Neumann committed
382
	      return GIMP_PDB_EXECUTION_ERROR;
383 384 385 386 387
	    }
	}
    }
  else
    {  /* This must be MIME stuff. Base64 away... */
Elliot Lee's avatar
Elliot Lee committed
388 389 390
      infile = fopen(tmpname,"r");
      to64(infile,mailpipe);
      /* close off mime */
391 392 393 394 395 396
      if( mail_info.encapsulation == ENCAPSULATION_MIME )
	{
	  fprintf (mailpipe, "\n--GUMP-MIME-boundary--\n");
	}
    }

Elliot Lee's avatar
Elliot Lee committed
397 398
  /* delete the tmpfile that was generated */
  unlink (tmpname);
399 400
  g_free (tmpname);

Sven Neumann's avatar
Sven Neumann committed
401
  return GIMP_PDB_SUCCESS;
Elliot Lee's avatar
Elliot Lee committed
402 403 404 405
}


static gint
406
save_dialog (void)
Elliot Lee's avatar
Elliot Lee committed
407
{
408 409 410 411 412 413 414 415
  GtkWidget     *dlg;
  GtkWidget     *entry;
  GtkWidget     *table;
  GtkWidget     *label;
  GtkWidget     *vbox;
  GtkWidget     *scrolled_window;
  GtkWidget     *text_view;
  GtkTextBuffer *text_buffer;
416 417 418
  gchar          buffer[BUFFER_SIZE];
  gchar         *gump_from;
  gboolean       run;
Elliot Lee's avatar
Elliot Lee committed
419

420
  gimp_ui_init ("mail", FALSE);
Elliot Lee's avatar
Elliot Lee committed
421

422
  /* check gimprc for a preffered "From:" address */
423
  gump_from = gimp_gimprc_query ("gump-from");
424

425 426 427 428 429
  if (gump_from)
    {
      strncpy (mail_info.from, gump_from, BUFFER_SIZE);
      g_free (gump_from);
    }
430 431

  dlg = gimp_dialog_new (_("Send to Mail"), "mail",
432
                         NULL, 0,
433
			 gimp_standard_help_func, "filters/mail.html",
434

435 436
			 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
			 GTK_STOCK_OK,     GTK_RESPONSE_OK,
437 438 439

			 NULL);

Elliot Lee's avatar
Elliot Lee committed
440
  /* table */
Sven Neumann's avatar
Sven Neumann committed
441
  table = gtk_table_new (7, 2, FALSE);
442
  gtk_container_set_border_width (GTK_CONTAINER (table), 6);
Elliot Lee's avatar
Elliot Lee committed
443 444 445
  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), table, TRUE, TRUE, 0);
  gtk_widget_show (table);

Sven Neumann's avatar
Sven Neumann committed
446 447
  gtk_table_set_row_spacings (GTK_TABLE (table), 4);
  gtk_table_set_col_spacings (GTK_TABLE (table), 4);
Elliot Lee's avatar
Elliot Lee committed
448 449 450

  /* to: dialog */
  entry = gtk_entry_new ();
451
  gtk_widget_set_size_request (entry, 200, -1);
452
  g_snprintf (buffer, sizeof (buffer), "%s", mail_info.receipt);
Elliot Lee's avatar
Elliot Lee committed
453
  gtk_entry_set_text (GTK_ENTRY (entry), buffer);
454
  gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
455
			     _("_Recipient:"), 1.0, 0.5,
456
			     entry, 1, FALSE);
457
  g_signal_connect (entry, "changed",
458 459
                    G_CALLBACK (mail_entry_callback),
                    &mail_info.receipt);
460

Sven Neumann's avatar
Sven Neumann committed
461
  /* From entry */
462
  entry = gtk_entry_new ();
463
  gtk_widget_set_size_request (entry, 200, -1);
464
  g_snprintf (buffer, sizeof (buffer), "%s", mail_info.from);
465
  gtk_entry_set_text (GTK_ENTRY (entry), buffer);
466
  gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
467
			     _("_Sender:"), 1.0, 0.5,
468
			     entry, 1, FALSE);
469
  g_signal_connect (entry, "changed",
470 471
                    G_CALLBACK (mail_entry_callback),
                    &mail_info.from);
Elliot Lee's avatar
Elliot Lee committed
472 473 474

  /* Subject entry */
  entry = gtk_entry_new ();
475
  gtk_widget_set_size_request (entry, 200, -1);
476
  g_snprintf (buffer, sizeof (buffer), "%s", mail_info.subject);
Elliot Lee's avatar
Elliot Lee committed
477
  gtk_entry_set_text (GTK_ENTRY (entry), buffer);
478
  gimp_table_attach_aligned (GTK_TABLE (table), 0, 2,
479
			     _("S_ubject:"), 1.0, 0.5,
480
			     entry, 1, FALSE);
481
  g_signal_connect (entry, "changed",
482 483
                    G_CALLBACK (mail_entry_callback),
                    &mail_info.subject);
Elliot Lee's avatar
Elliot Lee committed
484

Sven Neumann's avatar
Sven Neumann committed
485
  /* Comment entry */
Elliot Lee's avatar
Elliot Lee committed
486
  entry = gtk_entry_new ();
487
  gtk_widget_set_size_request (entry, 200, -1);
488
  g_snprintf (buffer, sizeof (buffer), "%s", mail_info.comment);
Elliot Lee's avatar
Elliot Lee committed
489
  gtk_entry_set_text (GTK_ENTRY (entry), buffer);
490
  gimp_table_attach_aligned (GTK_TABLE (table), 0, 3,
491
			     _("Comm_ent:"), 1.0, 0.5,
492
			     entry, 1, FALSE);
493
  g_signal_connect (entry, "changed",
494 495
                    G_CALLBACK (mail_entry_callback),
                    &mail_info.comment);
Elliot Lee's avatar
Elliot Lee committed
496

Sven Neumann's avatar
Sven Neumann committed
497
  /* Filename entry */
Elliot Lee's avatar
Elliot Lee committed
498
  entry = gtk_entry_new ();
499
  gtk_widget_set_size_request (entry, 200, -1);
500
  g_snprintf (buffer, sizeof (buffer), "%s", mail_info.filename);
Elliot Lee's avatar
Elliot Lee committed
501
  gtk_entry_set_text (GTK_ENTRY (entry), buffer);
502
  gimp_table_attach_aligned (GTK_TABLE (table), 0, 4,
503
			     _("_Filename:"), 1.0, 0.5,
504
			     entry, 1, FALSE);
505
  g_signal_connect (entry, "changed",
506 507
                    G_CALLBACK (mail_entry_callback),
                    &mail_info.filename);
Elliot Lee's avatar
Elliot Lee committed
508

509
  /* comment  */
510
  scrolled_window = gtk_scrolled_window_new (NULL, NULL);
511 512
  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
                                       GTK_SHADOW_IN);
513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
                                  GTK_POLICY_AUTOMATIC,
                                  GTK_POLICY_AUTOMATIC);
  gtk_table_attach (GTK_TABLE (table), scrolled_window,
                    0, 2, 5, 6,
                    GTK_EXPAND | GTK_FILL,
                    GTK_EXPAND | GTK_FILL,
                    0, 0);
  gtk_widget_show (scrolled_window);

  text_buffer = gtk_text_buffer_new (NULL);

  text_view = gtk_text_view_new_with_buffer (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);

530
  g_object_unref (text_buffer);
531

532
  g_signal_connect (text_buffer, "changed",
533 534
                    G_CALLBACK (mesg_body_callback),
		    NULL);
535

Elliot Lee's avatar
Elliot Lee committed
536
  /* Encapsulation label */
537
  label = gtk_label_new (_("Encapsulation:"));
538
  gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
539 540
  gtk_table_attach (GTK_TABLE (table), label, 0, 1, 6, 7,
		    GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
Sven Neumann's avatar
Sven Neumann committed
541
  gtk_widget_show (label);
Elliot Lee's avatar
Elliot Lee committed
542

543
  /* Encapsulation radiobuttons */
544 545 546 547
  vbox = gimp_int_radio_group_new (FALSE, NULL,
				   G_CALLBACK (gimp_radio_button_update),
				   &mail_info.encapsulation,
				   mail_info.encapsulation,
Elliot Lee's avatar
Elliot Lee committed
548

549 550
				   _("_Uuencode"), ENCAPSULATION_UUENCODE, NULL,
				   _("_MIME"),     ENCAPSULATION_MIME,     NULL,
551

552
				   NULL);
553
  gtk_table_attach (GTK_TABLE (table), vbox, 1, 2, 6, 8,
554
		    GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
555
  gtk_widget_show (vbox);
Elliot Lee's avatar
Elliot Lee committed
556 557

  gtk_widget_show (dlg);
558

559
  run = (gimp_dialog_run (GIMP_DIALOG (dlg)) == GTK_RESPONSE_OK);
Elliot Lee's avatar
Elliot Lee committed
560

561 562 563
  gtk_widget_destroy (dlg);

  return run;
Elliot Lee's avatar
Elliot Lee committed
564 565
}

566
static gint
567
valid_file (const gchar *filename)
Elliot Lee's avatar
Elliot Lee committed
568 569 570 571 572 573 574 575 576 577 578 579
{
  int stat_res;
  struct stat buf;

  stat_res = stat (filename, &buf);

  if ((0 == stat_res) && (buf.st_size > 0))
    return 1;
  else
    return 0;
}

580
static gchar *
581
find_content_type (const gchar *filename)
Elliot Lee's avatar
Elliot Lee committed
582
{
583 584
  /* This function returns a MIME Content-type: value based on the
     filename it is given.  */
585
  const gchar *type_mappings[20] =
586 587 588 589 590 591 592 593 594 595 596 597 598 599
  {
    "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;
600
  gchar *mimetype = g_new (gchar, 100);
601 602 603 604 605 606 607
  gint i=0;

  ext = find_extension (filename);
  if (!ext)
    {
      strcpy (mimetype, "application/octet-stream");
      return mimetype;
Elliot Lee's avatar
Elliot Lee committed
608
    }
609 610 611 612 613 614 615

  while (type_mappings[i])
    {
      if (strcmp (ext+1, type_mappings[i]) == 0)
	{
	  strcpy (mimetype, type_mappings[i + 1]);
	  return mimetype;
Elliot Lee's avatar
Elliot Lee committed
616
	}
617
      i += 2;
Elliot Lee's avatar
Elliot Lee committed
618
    }
619 620 621
  strcpy (mimetype, "image/x-");
  strncat (mimetype, ext + 1, 91);
  mimetype[99] = '\0';
Elliot Lee's avatar
Elliot Lee committed
622

623
  return mimetype;
Elliot Lee's avatar
Elliot Lee committed
624 625
}

626
static gchar *
627
find_extension (const gchar *filename)
Elliot Lee's avatar
Elliot Lee committed
628
{
629 630 631 632 633 634 635 636
  gchar *filename_copy;
  gchar *ext;

  /* this whole routine needs to be redone so it works for xccfgz and gz files*/
  /* not real sure where to start......                                       */
  /* right now saving for .xcfgz works but not .xcf.gz                        */
  /* this is all pretty close to straight from gz. It needs to be changed to  */
  /* work better for this plugin                                              */
Elliot Lee's avatar
Elliot Lee committed
637 638 639 640 641 642 643 644 645 646 647 648 649
  /* ie, FIXME */

  /* we never free this copy - aren't we evil! */
  filename_copy = malloc (strlen (filename) + 1);
  strcpy (filename_copy, filename);

  /* find the extension, boy! */
  ext = strrchr (filename_copy, '.');

  while (1)
    {
      if (!ext || ext[1] == 0 || strchr (ext, '/'))
	{
650
	  g_message (_("some sort of error with the file extension or lack thereof"));
651

Elliot Lee's avatar
Elliot Lee committed
652 653 654
	  return NULL;
	}
      if (0 != strcmp(ext,".gz"))
655
	{
Elliot Lee's avatar
Elliot Lee committed
656 657 658 659 660 661 662 663 664 665 666 667 668
	  return ext;
	}
      else
	{
	  /* we found somehting, loop back, and look again */
	  *ext = 0;
	  ext = strrchr (filename_copy, '.');
	}
    }
  return ext;
}

static void
669 670
mail_entry_callback (GtkWidget *widget,
		     gpointer   data)
Elliot Lee's avatar
Elliot Lee committed
671
{
672
  strncpy ((gchar *) data, gtk_entry_get_text (GTK_ENTRY (widget)), BUFFER_SIZE);
Elliot Lee's avatar
Elliot Lee committed
673 674
}

675
static void
676 677
mesg_body_callback (GtkTextBuffer *buffer,
		    gpointer       data)
678
{
679 680
  GtkTextIter start_iter;
  GtkTextIter end_iter;
681 682 683 684


  if (mesg_body)
    g_free (mesg_body);
685 686

  gtk_text_buffer_get_bounds (buffer, &start_iter, &end_iter);
687
  mesg_body = gtk_text_buffer_get_text (buffer, &start_iter, &end_iter, FALSE);
688
}
689

Elliot Lee's avatar
Elliot Lee committed
690
static void
691
create_headers (FILE *mailpipe)
Elliot Lee's avatar
Elliot Lee committed
692 693 694 695 696 697 698 699
{
  /* 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);
700 701 702
  fprintf (mailpipe, "From: %s \n", mail_info.from);
  fprintf (mailpipe, "X-Mailer: GIMP Useless Mail Program v.85\n");

703 704
  if (mail_info.encapsulation == ENCAPSULATION_MIME )
    {
Elliot Lee's avatar
Elliot Lee committed
705 706
      fprintf (mailpipe, "MIME-Version: 1.0\n");
      fprintf (mailpipe, "Content-type: multipart/mixed; boundary=GUMP-MIME-boundary\n");
707
    }
Elliot Lee's avatar
Elliot Lee committed
708
  fprintf (mailpipe, "\n\n");
709 710
  if (mail_info.encapsulation == ENCAPSULATION_MIME )
    {
Elliot Lee's avatar
Elliot Lee committed
711 712
      fprintf (mailpipe, "--GUMP-MIME-boundary\n");
      fprintf (mailpipe, "Content-type: text/plain; charset=US-ASCII\n\n");
713
    }
Elliot Lee's avatar
Elliot Lee committed
714 715
  fprintf (mailpipe, mail_info.comment);
  fprintf (mailpipe, "\n\n");
716
  if (mesg_body)
717
    fprintf (mailpipe, mesg_body);
718
  fprintf (mailpipe, "\n\n");
719 720
  if (mail_info.encapsulation == ENCAPSULATION_MIME )
    {
721 722
      gchar *content = find_content_type (mail_info.filename);

Elliot Lee's avatar
Elliot Lee committed
723 724 725
      fprintf (mailpipe, "--GUMP-MIME-boundary\n");
      fprintf (mailpipe, "Content-type: %s\n",content);
      fprintf (mailpipe, "Content-transfer-encoding: base64\n");
726 727
      fprintf (mailpipe, "Content-disposition: attachment; filename=\"%s\"\n",
               mail_info.filename);
Elliot Lee's avatar
Elliot Lee committed
728
      fprintf (mailpipe, "Content-description: %s\n\n",mail_info.filename);
729 730

      g_free (content);
731
    }
Elliot Lee's avatar
Elliot Lee committed
732 733 734 735
}

/*
 * The following code taken from codes.c in the mpack-1.5 distribution
736 737
 * by Carnegie Mellon University.
 *
Elliot Lee's avatar
Elliot Lee committed
738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753
 *
 * (C) Copyright 1993,1994 by Carnegie Mellon University
 * All Rights Reserved.
 *
 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 */
/*
Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore)

754 755 756 757 758 759 760 761 762
Permission to use, copy, modify, and distribute this material
for any purpose and without fee is hereby granted, provided
that the above copyright notice and this permission notice
appear in all copies, and that the name of Bellcore not be
used in advertising or publicity pertaining to this
material without the specific, prior written permission
of an authorized representative of Bellcore.  BELLCORE
MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY
OF THIS MATERIAL FOR ANY PURPOSE.  IT IS PROVIDED "AS IS",
Elliot Lee's avatar
Elliot Lee committed
763 764 765
WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.  */


766 767
static gchar basis_64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
Elliot Lee's avatar
Elliot Lee committed
768

769 770
static gint
to64 (FILE *infile,
771
      FILE *outfile)
Elliot Lee's avatar
Elliot Lee committed
772
{
773
  gint c1, c2, c3, ct = 0, written = 0;
774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791

  while ((c1 = getc (infile)) != EOF)
    {
      c2 = getc (infile);
      if (c2 == EOF)
	{
	  output64chunk (c1, 0, 0, 2, outfile);
        }
      else
	{
	  c3 = getc (infile);
	  if (c3 == EOF)
	    {
	      output64chunk (c1, c2, 0, 1, outfile);
            }
	  else
	    {
	      output64chunk (c1, c2, c3, 0, outfile);
Elliot Lee's avatar
Elliot Lee committed
792 793
            }
        }
794 795 796 797 798 799
      ct += 4;
      if (ct > 71)
	{
	  putc ('\n', outfile);
	  written += 73;
	  ct = 0;
Elliot Lee's avatar
Elliot Lee committed
800 801
        }
    }
802 803 804 805
  if (ct)
    {
      putc ('\n', outfile);
      ct++;
Elliot Lee's avatar
Elliot Lee committed
806
    }
807 808

  return written + ct;
Elliot Lee's avatar
Elliot Lee committed
809 810 811
}

static void
812 813 814 815 816
output64chunk (gint  c1,
	       gint  c2,
	       gint  c3,
	       gint  pads,
	       FILE *outfile)
Elliot Lee's avatar
Elliot Lee committed
817
{
818 819
  putc (basis_64[c1>>2], outfile);
  putc (basis_64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)], outfile);
820

821 822 823 824 825 826 827 828 829 830 831 832 833 834
  if (pads == 2)
    {
      putc ('=', outfile);
      putc ('=', outfile);
    }
  else if (pads)
    {
      putc (basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)], outfile);
      putc ('=', outfile);
    }
  else
    {
      putc (basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)], outfile);
      putc (basis_64[c3 & 0x3F], outfile);
Elliot Lee's avatar
Elliot Lee committed
835 836
    }
}