/* The GIMP -- an image manipulation program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 * Copyright (C) 1997 Daniel Risacher 
 *
 * 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
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/*
   *   GUMP - Gimp Useless Mail Plugin (or Gump Useless Mail Plugin if you prefer)
   *          version about .645 I would say... give or take a few decimal points
   *
   *
   *   by Adrian Likins <aklikins@eos.ncsu.edu>
   *
   *
   *
   *   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.
   *
   *
   * TODO: 1) the aforementioned abilty to specify the 
   *           uuencode filename                         *done*
   *       2) someway to do this without tmp files
   *              * wont happen anytime soon*
   *       3) MIME?
   *       4) a pointlessly snazzier dialog
   *       5) make sure it works with gz     
   *               * works for .xcfgz but not .xcf.gz *
   *       6) add an option to choose if mail get 
   *          uuencode or not (or MIME'ed for that matter)
   *       7) realtime preview
   *       8) better entry for comments
   *       9) list of frequently used addreses
   *      10) openGL compliance
   *      11) better handling of filesave errors
   *
   *
   *  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
   *
   * As always: The utility of this plugin is left as an exercise for the reader
   *
 */
#ifndef MAILER
#define MAILER "/usr/lib/sendmail"
#endif

#ifndef UUENCODE
#define UUENCODE "uuencode"
#endif

#include <stdlib.h>
#include <stdio.h>
#include <sys/param.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "gtk/gtk.h"
#include "libgimp/gimp.h"


static void query (void);
static void run (char *name,
		 int nparams,
		 GParam * param,
		 int *nreturn_vals,
		 GParam ** return_vals);


static gint save_image (char *filename,
			gint32 image_ID,
			gint32 drawable_ID,
			gint32 run_mode);

static gint save_dialog ();
static void close_callback (GtkWidget * widget, gpointer data);
static void ok_callback (GtkWidget * widget, gpointer data);
static void receipt_callback (GtkWidget * widget, gpointer data);
static void subject_callback (GtkWidget * widget, gpointer data);
static void comment_callback (GtkWidget * widget, gpointer data);
static void filename_callback (GtkWidget * widget, gpointer data);
static int valid_file (char *filename);
static void create_headers (FILE * mailpipe);
static char *find_extension (char *filename);

GPlugInInfo PLUG_IN_INFO =
{
  NULL,				/* init_proc */
  NULL,				/* quit_proc */
  query,			/* query_proc */
  run,				/* run_proc */
};


typedef struct
  {
    char receipt[256];
    char subject[256];
    char comment[256];
    char filename[256];
  }
m_info;

static m_info mail_info = {
  /* I would a assume there is a better way to do this, but this works for now */
  "\0",
  "\0",
  "\0",
  "\0",
};

static int run_flag = 0;

MAIN ();

static void
query ()
{

  static GParamDef args[] =
  {
    {PARAM_INT32, "run_mode", "Interactive, non-interactive"},
    {PARAM_IMAGE, "image", "Input image"},
    {PARAM_DRAWABLE, "drawable", "Drawable to save"},
    {PARAM_STRING, "filename", "The name of the file to save the image in"},
    {PARAM_STRING, "receipt", "The email address to send to"},
    {PARAM_STRING, "subject", "The subject"},
    {PARAM_STRING, "comment", "The Comment"}
  };
  static int nargs = sizeof (args) / sizeof (args[0]);
  static GParamDef *return_vals = NULL;
  static int nreturn_vals = 0;

  gimp_install_procedure ("plug_in_mail_image",
			  "pipe files to uuencode then mail them",
			  "You need to have uuencode and mail installed",
			  "Adrian Likins",
			  "Adrian Likins, Daniel Risacher, Spencer Kimball and Peter Mattis",
			  "1995-1997",
			  "<Image>/File/Mail image",
			  "RGB*, GRAY*, INDEXED*",
			  PROC_PLUG_IN,
			  nargs, nreturn_vals,
			  args, return_vals);

}


static void
run (char *name,
     int nparams,
     GParam * param,
     int *nreturn_vals,
     GParam ** return_vals)
{
  static GParam values[2];
  GRunModeType run_mode;
  gint32 drawable_ID;
  GStatusType status = STATUS_SUCCESS;
  gint32 image_ID;


  run_mode = param[0].data.d_int32;
  drawable_ID = param[2].data.d_drawable;
  image_ID = param[1].data.d_image;
  *nreturn_vals = 1;
  *return_vals = values;

  values[0].type = PARAM_STATUS;
  values[0].data.d_status = STATUS_CALLING_ERROR;

  if (strcmp (name, "plug_in_mail_image") == 0)
    {
      switch (run_mode)
	{
	case RUN_INTERACTIVE:
	  gimp_get_data ("plug_in_mail_image", &mail_info);
	  if (!save_dialog ())
	    return;
	  break;
	case RUN_NONINTERACTIVE:
	  /*  Make sure all the arguments are there!  */
	  if (nparams != 7)
	    status = STATUS_CALLING_ERROR;
	  if(status == STATUS_SUCCESS)
	    {
	      /* this hasnt been tested yet */
	      strncpy (mail_info.filename, param[3].data.d_string,256);
	      strncpy (mail_info.receipt, param[4].data.d_string,256);
	      strncpy (mail_info.subject, param[5].data.d_string,256);
	      strncpy (mail_info.comment, param[6].data.d_string,256);
	    }
	  break;
	case RUN_WITH_LAST_VALS:
	  gimp_get_data ("plug_in_mail_image", &mail_info);
	  break;
	  
	default:
	  break;
	}

      *nreturn_vals = 1;
      if (save_image (mail_info.filename,
		      image_ID,
		      drawable_ID,
		      run_mode))
	{
	  values[0].data.d_status = STATUS_SUCCESS;
	}
      else
	values[0].data.d_status = STATUS_EXECUTION_ERROR;
    }
  else
    g_assert (FALSE);
}

static gint
save_image (char *filename,
	    gint32 image_ID,
	    gint32 drawable_ID,
	    gint32 run_mode)
{

  GParam *params;
  gint retvals;
  char *ext;
  char *tmpname;
  char mailcmdline[512];
  int pid;
  int status;
  FILE *mailpipe;


  if (NULL == (ext = find_extension (filename)))
    return -1;

  /* get a temp name with the right extension and save into it. */
  params = gimp_run_procedure ("gimp_temp_name",
			       &retvals,
			       PARAM_STRING, ext + 1,
			       PARAM_END);
  tmpname = params[1].data.d_string;

  /* construct the "sendmail user@location" line */
  strcpy (mailcmdline, MAILER);
  strcat (mailcmdline, " ");
  strcat (mailcmdline, mail_info.receipt);

  /* create a pipe to sendmail */
  mailpipe = popen (mailcmdline, "w");
  create_headers (mailpipe);
  
  /* This is necessary to make the comments and headers work correctly. Not real sure why */
  fflush (mailpipe);      

  params = gimp_run_procedure ("gimp_file_save",
			       &retvals,
			       PARAM_INT32, run_mode,
			       PARAM_IMAGE, image_ID,
			       PARAM_DRAWABLE, drawable_ID,
			       PARAM_STRING, tmpname,
			       PARAM_STRING, tmpname,
			       PARAM_END);

  /* need to figure a way to make sure the user is trying to save in an approriate format */
  /* but this can wait....                                                                */

  if (params[0].data.d_status == FALSE || !valid_file (tmpname))
    {
      unlink (tmpname);
      return -1;
    }


/* fork off a uuencode process */
  if ((pid = fork ()) < 0)
    {
      g_warning ("mail: fork failed: %s\n", g_strerror (errno));
      return -1;
    }
  else if (pid == 0)
    {
      if (-1 == dup2 (fileno (mailpipe), fileno (stdout)))
	{
	  g_warning ("mail: dup2 failed: %s\n", g_strerror (errno));
	}
      
      /* and uuencode into it */
      execlp ("uuencode", UUENCODE, tmpname, filename, NULL);
      
      /* close the pipe now */
      pclose (mailpipe);
      
      /* show error if neccesary */
      g_warning ("mail: exec failed: uuencode: %s\n", g_strerror (errno));
      _exit (127);
    }
  else
    {
      waitpid (pid, &status, 0);
      
      if (!WIFEXITED (status) ||
	  WEXITSTATUS (status) != 0)
	{
	  g_warning ("mail: mail didnt work or something on  file %s\n", tmpname);
	  return 0;
	}
    }
  /* delete the tmpfile that was generated */
  unlink (tmpname);
  return TRUE;
}


static gint
save_dialog ()
{
  GtkWidget *dlg;
  GtkWidget *button;
  GtkWidget *entry;
  GtkWidget *table;
  GtkWidget *label;
  gint argc;
  gchar **argv;
  gchar buffer[32];

  argc = 1;
  argv = g_new (gchar *, 1);
  argv[0] = g_strdup ("mail");

  gtk_init (&argc, &argv);
  gtk_rc_parse (gimp_gtkrc ());

  dlg = gtk_dialog_new ();
  gtk_window_set_title (GTK_WINDOW (dlg), "Send to mail");
  gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
		      (GtkSignalFunc) close_callback, NULL);
  /* action area   */
  /* Okay buton */
  button = gtk_button_new_with_label ("OK");
  GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
  gtk_signal_connect (GTK_OBJECT (button), "clicked",
		      (GtkSignalFunc) ok_callback,
		      dlg);
  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
  gtk_widget_grab_default (button);
  gtk_widget_show (button);


  /* cancel button */
  button = gtk_button_new_with_label ("Cancel");
  GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
  gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
			     (GtkSignalFunc) gtk_widget_destroy,
			     GTK_OBJECT (dlg));
  gtk_widget_show (button);

  /* table */
  table = gtk_table_new (4, 2, FALSE);
  gtk_container_border_width (GTK_CONTAINER (table), 10);
  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), table, TRUE, TRUE, 0);
  gtk_widget_show (table);

  gtk_table_set_row_spacings (GTK_TABLE (table), 10);
  gtk_table_set_col_spacings (GTK_TABLE (table), 10);

  /*  To:  Label */
  label = gtk_label_new ("To:");
  gtk_table_attach (GTK_TABLE (table), label,
		    0, 1, 0, 1,
		    GTK_EXPAND | GTK_FILL,
		    GTK_EXPAND | GTK_FILL,
		    0, 0);
  gtk_widget_show (label);

  /* to: dialog */
  entry = gtk_entry_new ();
  gtk_table_attach (GTK_TABLE (table), entry,
		    1, 2, 0, 1, 
		    GTK_EXPAND | GTK_FILL,
		    GTK_EXPAND | GTK_FILL,
		    0, 0);
  gtk_widget_set_usize (entry, 200, 0);
  sprintf (buffer, "%s", mail_info.receipt);
  gtk_entry_set_text (GTK_ENTRY (entry), buffer);
  gtk_signal_connect (GTK_OBJECT (entry), "changed",
		      (GtkSignalFunc) receipt_callback, &mail_info.receipt);
  gtk_widget_show (entry);

  /*  subject Label */
  label = gtk_label_new ("Subject:");
  gtk_table_attach (GTK_TABLE (table), label,
		    0, 1, 1, 2,
		    GTK_EXPAND | GTK_FILL,
		    GTK_EXPAND | GTK_FILL,
		    0, 0);
  gtk_widget_show (label);

  /* Subject entry */
  entry = gtk_entry_new ();
  gtk_table_attach (GTK_TABLE (table), entry,
		    1, 2, 1, 2,
		    GTK_EXPAND | GTK_FILL,
		    GTK_EXPAND | GTK_FILL,
		    0, 0);
  gtk_widget_set_usize (entry, 200, 0);
  sprintf (buffer, "%s", mail_info.subject);
  gtk_entry_set_text (GTK_ENTRY (entry), buffer);
  gtk_signal_connect (GTK_OBJECT (entry), "changed",
		      (GtkSignalFunc) subject_callback, &mail_info.subject);
  gtk_widget_show (entry);


  /* Comment label  */
  label = gtk_label_new ("Comment:");
  gtk_table_attach (GTK_TABLE (table), label, 
		    0, 1, 2, 3, 
		    GTK_EXPAND | GTK_FILL,
		    GTK_EXPAND | GTK_FILL,
		    0, 0);
  gtk_widget_show (label);

  /* Comment dialog */
  entry = gtk_entry_new ();
  gtk_table_attach (GTK_TABLE (table), entry, 
		    1, 2, 2, 3,
		    GTK_EXPAND | GTK_FILL,
		    GTK_EXPAND | GTK_FILL,
		    0, 0);
  gtk_widget_set_usize (entry, 200, 0);
  sprintf (buffer, "%s", mail_info.comment);
  gtk_entry_set_text (GTK_ENTRY (entry), buffer);
  gtk_signal_connect (GTK_OBJECT (entry), "changed",
		      (GtkSignalFunc) comment_callback, &mail_info.comment);
  gtk_widget_show (entry);

  /* filename label  */
  label = gtk_label_new ("Filename:");
  gtk_table_attach (GTK_TABLE (table), label, 
		    0, 1, 3, 4, 
		    GTK_EXPAND | GTK_FILL,
		    GTK_EXPAND | GTK_FILL,
		    0, 0);
  gtk_widget_show (label);

  /* Filename dialog */
  entry = gtk_entry_new ();
  gtk_table_attach (GTK_TABLE (table), entry, 
		    1, 2, 3, 4,
		    GTK_EXPAND | GTK_FILL,
		    GTK_EXPAND | GTK_FILL,
		    0, 0);
  gtk_widget_set_usize (entry, 200, 0);
  sprintf (buffer, "%s", mail_info.filename);
  gtk_entry_set_text (GTK_ENTRY (entry), buffer);
  gtk_signal_connect (GTK_OBJECT (entry), "changed",
		      (GtkSignalFunc) filename_callback, &mail_info.filename);
  gtk_widget_show (entry);


  gtk_widget_show (dlg);
  gtk_main ();
  gdk_flush ();
  return run_flag;

}

static int 
valid_file (char *filename)
{
  int stat_res;
  struct stat buf;

  stat_res = stat (filename, &buf);

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

static char *
find_extension (char *filename)
{
  char *filename_copy;
  char *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                                                */
  /* 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, '/'))
	{
	  g_warning ("mail: some sort of error with the file extension or lack thereof \n");
	  
	  return NULL;
	}
      if (0 != strcmp(ext,".gz"))
	{ 
	  return ext;
	}
      else
	{
	  /* we found somehting, loop back, and look again */
	  *ext = 0;
	  ext = strrchr (filename_copy, '.');
	}
    }
  return ext;
}


static void
close_callback (GtkWidget * widget, gpointer data)
{
  gtk_main_quit ();
}

static void
ok_callback (GtkWidget * widget, gpointer data)
{
  run_flag = 1;
  gtk_widget_destroy (GTK_WIDGET (data));
}

static void
receipt_callback (GtkWidget * widget, gpointer data)
{
  strncpy (mail_info.receipt, gtk_entry_get_text (GTK_ENTRY (widget)), 256);
}

static void
subject_callback (GtkWidget * widget, gpointer data)
{
  strncpy (mail_info.subject, gtk_entry_get_text (GTK_ENTRY (widget)), 256);
}

static void
comment_callback (GtkWidget * widget, gpointer data)
{
  strncpy (mail_info.comment, gtk_entry_get_text (GTK_ENTRY (widget)), 256);
}


static void
filename_callback (GtkWidget * widget, gpointer data)
{
  strncpy (mail_info.filename, gtk_entry_get_text (GTK_ENTRY (widget)), 256);
}

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);
  fprintf (mailpipe, "X-Mailer: GIMP Useless Mail Program v.65\n");
  fprintf (mailpipe, "X-GUMP-Author: Adrian Likins\n");
  fprintf (mailpipe, "\n\n");
  fprintf (mailpipe, mail_info.comment);
  fprintf (mailpipe, "\n\n");
}











