/*
    send.c - Provide the send dialog and related routines
    Copyright (c) 1999,2006  Joey Schulze <joey@infodrom.org>

    This file is part of the Gerstensaft package.

    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., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*/

#define _GNU_SOURCE

#include <gtk/gtk.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "main.h"
#include "beer.h"
#include "send.h"
#include "msgbox.h"
#include "saft.h"
#include "nls.h"
#include "io.h"
#include "config.h"

#define SENDMSG_MAXLEN   4090	/* max length of various strings - 6 chars safety */
#define SENDMSG_DELTA     200	/* search for newline delta chars before limit */

gint send_delete(GtkWidget *widget, GdkEvent *event, gpointer data)
{
#ifdef DEBUG
  printf ("send_delete()\n");
#endif

  return (FALSE);
}

void send_destroy (GtkWidget *widget, gpointer data)
{
#ifdef DEBUG
  printf ("send_destroy()\n");
#endif

  if (((struct s_send_data *) data) != NULL)
    free (((struct s_send_data *) data));
}

void send_addr_change (GtkWidget *widget, gpointer data)
{
  /* De/-activate the Send button only if needed */
  if (strlen(gtk_entry_get_text (GTK_ENTRY(widget))) > 0) {
    if (!((struct s_send_data *) data)->addrok) {
      if (GTK_CLIST(((struct s_send_data *) data)->listbox)->selection)
	gtk_widget_set_sensitive (((struct s_send_data *) data)->sendbutton, TRUE);
      ((struct s_send_data *) data)->addrok = 1;
    }
  } else {
    if (((struct s_send_data *) data)->addrok) {
      gtk_widget_set_sensitive (((struct s_send_data *) data)->sendbutton, FALSE);
      ((struct s_send_data *) data)->addrok = 0;
    }
  }
}

void send_row_select (GtkCList *clist, gint row, gint column, GdkEventButton *event, gpointer data)
{
#ifdef DEBUG
  printf ("send_row_select()\n");
#endif

  if (strlen(gtk_entry_get_text (GTK_ENTRY(((struct s_send_data *) data)->addrinput->entry))) > 0)
    gtk_widget_set_sensitive (((struct s_send_data *) data)->sendbutton, TRUE);
}

void send_button_select_all (GtkWidget *widget, gpointer data)
{
  int i;

  gtk_clist_freeze (GTK_CLIST(((struct s_send_data *) data)->listbox));

  for (i=0; i < GTK_CLIST(((struct s_send_data *) data)->listbox)->rows; i++)
    gtk_clist_select_row (GTK_CLIST(((struct s_send_data *) data)->listbox), i, 0);

  gtk_clist_thaw (GTK_CLIST(((struct s_send_data *) data)->listbox));
  if (((struct s_send_data *) data)->addrok == 1)
    gtk_widget_set_sensitive (((struct s_send_data *) data)->sendbutton, TRUE);
}

void send_button_unselect_all (GtkWidget *widget, gpointer data)
{
  int i;

  gtk_clist_freeze (GTK_CLIST(((struct s_send_data *) data)->listbox));

  for (i=0; i < GTK_CLIST(((struct s_send_data *) data)->listbox)->rows; i++)
    gtk_clist_unselect_row (GTK_CLIST(((struct s_send_data *) data)->listbox), i, 0);

  gtk_clist_thaw (GTK_CLIST(((struct s_send_data *) data)->listbox));
    gtk_widget_set_sensitive (((struct s_send_data *) data)->sendbutton, FALSE);
}

void send_button_clear (GtkWidget *widget, gpointer data)
{
  gtk_clist_clear (GTK_CLIST(((struct s_send_data *) data)->listbox));

  gtk_widget_set_sensitive (((struct s_send_data *) data)->sendbutton, FALSE);

  gtk_entry_set_text (GTK_ENTRY(((struct s_send_data *) data)->addrinput->entry), "");
  main_clear (((struct s_send_data *) data)->wdata);
  gtk_widget_set_sensitive (((struct s_send_data *) data)->clearbutton, FALSE);
}

gint send_history_add (const gchar *addr, GtkCombo *combo)
{
  int i, n;
  gchar *xp;

  /* Find out if the address is already listed in the history */
  for (i=0,n=0;i<g_list_length (config.addrs); i++) {
    if (!strcmp (addr, g_list_nth (config.addrs, i)->data)) {
      n++;
      break;
    }
  }

  /* Add address to history if it isn't in already */
  if (!n && (xp = (char *)malloc (strlen(addr)+1)) != NULL) {
    sprintf (xp, addr);
    config.addrs = g_list_insert_sorted (config.addrs, xp, (GCompareFunc)strcmp);

    gtk_combo_set_popdown_strings (combo, config.addrs);
    gtk_entry_set_text (GTK_ENTRY(combo->entry), xp);
  }
  return (n == 0);
}

void send_button_send (GtkWidget *widget, gpointer data)
{
  int i, n;
  gchar *fname;
  const gchar *addr;
  const gchar *comment;
  char **files;
  GList *selection;

  addr = gtk_entry_get_text (GTK_ENTRY(((struct s_send_data *) data)->addrinput->entry));
  comment = gtk_entry_get_text (GTK_ENTRY(((struct s_send_data *) data)->comment));

  if (send_history_add (addr, ((struct s_send_data *) data)->addrinput)) {
    gtk_combo_set_popdown_strings (GTK_COMBO(((struct s_send_data *) data)->wdata->addrinput), config.addrs);
    gtk_entry_set_text (GTK_ENTRY(GTK_COMBO((((struct s_send_data *) data)->wdata)->addrinput)->entry), "");
  }

  for (selection = GTK_CLIST(((struct s_send_data *) data)->listbox)->selection, n=0;
       selection;
       selection = selection->next)
      n++;

  if (n>0 && (files = (char **)malloc ((n+1)*sizeof (char *))) != NULL) {
    memset (files, 0, (n+1)*sizeof (char *));
    for (selection = GTK_CLIST(((struct s_send_data *) data)->listbox)->selection, i=0;
	 selection;
	 selection = selection->next) {

      gtk_clist_get_text (GTK_CLIST(((struct s_send_data *) data)->listbox), (int)selection->data, 1, &fname);
      files[i++] = fname;
    }

    if (saft_send (addr, files, comment)) {
      send_button_unselect_all (widget, data);
      gtk_entry_set_text (GTK_ENTRY(((struct s_send_data *) data)->comment), "");
      free (files);
      if (config.closewindow)
	gtk_signal_emit_by_name (GTK_OBJECT (((struct s_send_data *) data)->dialog), "destroy");
    } else 
      free (files);
  }
}

void send_dialog (gpointer data)
{
  GtkWidget *mainbox, *hbox, *vbox;
  GtkWidget *frame;
  GtkWidget *label;
  GtkWidget *button;
#if GTK_MAJOR_VERSION >= 1 && GTK_MINOR_VERSION >= 1
  GtkWidget *scrollwin;
#endif
  GtkTooltips *tooltips;
  char *titles[3] = {"", _("Filename"), _("Size")};
  struct stat st;
  char *name, asize[10];
  char **clp;
  GdkColor background;
  GdkColormap *colormap;
  int i;
  char *cp;
  struct s_send_data *sdata;

  if ((sdata = (struct s_send_data *) malloc (sizeof(struct s_send_data))) == NULL) {
    perror ("malloc");
    return;
  }
  memset (sdata, 0, sizeof (struct s_send_data));

  if ((clp = (char **)malloc(sizeof(char *)*3)) == NULL) {
    perror ("malloc");
    free (sdata);
    return;
  }
  clp[0] = NULL;

  sdata->wdata = data;

  /* Create a new dialog box */
  sdata->dialog = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_grab_add (sdata->dialog);
  gtk_window_set_title (GTK_WINDOW (sdata->dialog), _("Send Files"));
  gtk_widget_set_usize (GTK_WIDGET (sdata->dialog), 450, 270);

  /* Connect the appropriate signal handlers */
  g_signal_connect (G_OBJECT (sdata->dialog), "delete_event",
		    G_CALLBACK (send_delete), (gpointer) sdata);
  g_signal_connect (G_OBJECT (sdata->dialog), "destroy",
		    G_CALLBACK (send_destroy), (gpointer) sdata);

  mainbox = gtk_vbox_new(FALSE, 0);
  gtk_container_add (GTK_CONTAINER (sdata->dialog), mainbox);

  frame = gtk_frame_new (NULL);
  gtk_container_border_width (GTK_CONTAINER(frame), 5);
  gtk_container_add (GTK_CONTAINER(mainbox), frame);

  vbox = gtk_vbox_new (FALSE, 0);
  gtk_container_border_width (GTK_CONTAINER(vbox), 5);
  gtk_container_add (GTK_CONTAINER(frame), vbox);

  label = gtk_label_new (_("Recipient"));
  gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
  gtk_box_pack_start (GTK_BOX(vbox), label, FALSE, FALSE, 0);
  gtk_widget_show (label);

  sdata->addrinput = GTK_COMBO(gtk_combo_new());
  if (config.addrs)
    gtk_combo_set_popdown_strings (sdata->addrinput, config.addrs);
  gtk_entry_set_text (GTK_ENTRY(sdata->addrinput->entry), "");
  g_signal_connect (G_OBJECT (sdata->addrinput->entry), "changed",
		    G_CALLBACK (send_addr_change), (gpointer) sdata);
  tooltips = gtk_tooltips_new();
  gtk_tooltips_set_tip (tooltips, sdata->addrinput->entry, _("Enter recipient's address"), NULL);
  gtk_box_pack_start (GTK_BOX(vbox), GTK_WIDGET(sdata->addrinput), FALSE, FALSE, FALSE);
  gtk_widget_show (GTK_WIDGET(sdata->addrinput));

  label = gtk_label_new (_("Comment"));
  gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
  gtk_box_pack_start (GTK_BOX(vbox), label, FALSE, FALSE, 0);
  gtk_widget_show (label);

  sdata->comment = gtk_entry_new();
  tooltips = gtk_tooltips_new();
  gtk_tooltips_set_tip (tooltips, sdata->comment, _("Enter optional comment"), NULL);
  gtk_box_pack_start (GTK_BOX(vbox), GTK_WIDGET(sdata->comment), FALSE, FALSE, FALSE);
  gtk_widget_show (GTK_WIDGET(sdata->comment));

  sdata->listbox = gtk_clist_new_with_titles (3, titles);
  gtk_clist_column_titles_passive (GTK_CLIST(sdata->listbox));
  gtk_clist_set_selection_mode (GTK_CLIST(sdata->listbox), GTK_SELECTION_MULTIPLE);
  gtk_clist_set_column_width (GTK_CLIST(sdata->listbox), 0, 16);
  gtk_clist_set_column_justification (GTK_CLIST(sdata->listbox), 0, GTK_JUSTIFY_CENTER);
  gtk_clist_set_column_width (GTK_CLIST(sdata->listbox), 1, 340);
  gtk_clist_set_column_justification (GTK_CLIST(sdata->listbox), 1, GTK_JUSTIFY_LEFT);
  gtk_clist_set_column_width (GTK_CLIST(sdata->listbox), 2, 30);
  gtk_clist_set_column_justification (GTK_CLIST(sdata->listbox), 2, GTK_JUSTIFY_RIGHT);

  g_signal_connect(G_OBJECT (sdata->listbox), "select_row",
		   G_CALLBACK (send_row_select), (gpointer) sdata);
#if GTK_MAJOR_VERSION >= 1 && GTK_MINOR_VERSION >= 1
  scrollwin = gtk_scrolled_window_new (NULL, NULL);
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(scrollwin), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
  gtk_box_pack_start (GTK_BOX(vbox), scrollwin, TRUE, TRUE, 0);
  gtk_container_add (GTK_CONTAINER(scrollwin), sdata->listbox);
  gtk_widget_show (scrollwin);
#else
  gtk_box_pack_start (GTK_BOX(vbox) , sdata->listbox, TRUE, TRUE, 0);
#endif

  for (i=0; i < GTK_CLIST(((struct s_main_data *) data)->filebox)->rows; i++) {
    gtk_clist_get_text(GTK_CLIST(((struct s_main_data *) data)->filebox), i, 1, &name);
    if ((cp = (char *)malloc (strlen(name)+1)) == NULL)
      continue;
    memcpy (cp, name, strlen(name)+1);
    clp[1] = cp;

    if (stat (name, &st))
      continue;

#if defined _FILE_OFFSET_BITS && _FILE_OFFSET_BITS == 64
    snprintf (asize, sizeof (asize), "%lld", (st.st_size+1023)/1024);
#else
    snprintf (asize, sizeof (asize), "%ld", (st.st_size+1023)/1024);
#endif

    if ((cp = (char *)malloc (strlen(asize)+1)) == NULL)
      continue;
    memcpy (cp, asize, strlen(asize)+1);
    clp[2] = cp;

    gtk_clist_append (GTK_CLIST(sdata->listbox), clp);

    background.red = background.green = background.blue =  ~0;
    colormap = gdk_colormap_get_system();
    gdk_color_alloc (colormap, &background);

    gtk_clist_set_background (GTK_CLIST(sdata->listbox), GTK_CLIST(sdata->listbox)->rows-1, &background);
    if (S_ISDIR(st.st_mode)) 
      gtk_clist_set_pixmap (GTK_CLIST(sdata->listbox), GTK_CLIST(sdata->listbox)->rows-1, 0, dir_pixmap, dir_mask);
    else
      gtk_clist_set_pixmap (GTK_CLIST(sdata->listbox), GTK_CLIST(sdata->listbox)->rows-1, 0, doc_pixmap, doc_mask);
    gtk_clist_select_row (GTK_CLIST(sdata->listbox), GTK_CLIST(sdata->listbox)->rows-1, 0);
  }

  gtk_clist_set_column_width (GTK_CLIST(sdata->listbox), 2,
			      gtk_clist_optimal_column_width (GTK_CLIST(sdata->listbox), 2));

  gtk_widget_show (sdata->listbox);
  gtk_widget_show (vbox);

  /* horizontal box containing the buttons */
  hbox = gtk_hbox_new (FALSE, 0);
  gtk_container_border_width (GTK_CONTAINER(hbox), 5);
  gtk_box_pack_start (GTK_BOX(mainbox), hbox, FALSE, TRUE, 0);

  button = gtk_button_new_with_label (_(" Select all "));
  g_signal_connect (G_OBJECT (button), "clicked",
		    G_CALLBACK (send_button_select_all), (gpointer) sdata);
  tooltips = gtk_tooltips_new();
  gtk_tooltips_set_tip (tooltips, button, _("Select all files"), NULL);
  gtk_box_pack_start (GTK_BOX(hbox), button, TRUE, FALSE, 0);
  gtk_widget_show (button);

  button = gtk_button_new_with_label (_(" Unselect all "));
  g_signal_connect (G_OBJECT (button), "clicked",
		    G_CALLBACK (send_button_unselect_all), (gpointer) sdata);
  tooltips = gtk_tooltips_new();
  gtk_tooltips_set_tip (tooltips, button, _("Unselected all files"), NULL);
  gtk_box_pack_start (GTK_BOX(hbox), button, TRUE, FALSE, 0);
  gtk_widget_show (button);

  sdata->sendbutton = gtk_button_new_with_mnemonic (_(" _Send "));
  gtk_widget_set_sensitive (sdata->sendbutton, FALSE);
  g_signal_connect (G_OBJECT (sdata->sendbutton), "clicked",
		    G_CALLBACK (send_button_send), (gpointer) sdata);
  tooltips = gtk_tooltips_new();
  gtk_tooltips_set_tip (tooltips, sdata->sendbutton, _("Send selected files to recipient"), NULL);
  gtk_box_pack_start (GTK_BOX(hbox), sdata->sendbutton, TRUE, FALSE, 0);
  gtk_widget_show (sdata->sendbutton);

  sdata->clearbutton = gtk_button_new_from_stock ("gtk-clear");
  g_signal_connect (G_OBJECT (sdata->clearbutton), "clicked",
		    G_CALLBACK (send_button_clear), (gpointer) sdata);
  tooltips = gtk_tooltips_new();
  gtk_tooltips_set_tip (tooltips, sdata->clearbutton, _("Clear list of files"), NULL);
  gtk_box_pack_start (GTK_BOX(hbox), sdata->clearbutton, TRUE, FALSE, 0);
  gtk_widget_show (sdata->clearbutton);

  button = gtk_button_new_from_stock ("gtk-close");
  g_signal_connect_swapped (G_OBJECT (button), "clicked",
			   G_CALLBACK (gtk_widget_destroy), (gpointer) sdata->dialog);
  tooltips = gtk_tooltips_new();
  gtk_tooltips_set_tip (tooltips, button, _("Return to main program"), NULL);
  gtk_box_pack_start (GTK_BOX(hbox), button, TRUE, FALSE, 0);
  gtk_widget_show (button);

  gtk_widget_show (hbox);
  gtk_widget_show (frame);
  gtk_widget_show (mainbox);
  gtk_widget_show (sdata->dialog);
}

int sendmsg (const char *addr, char *text)
{
  char *cmd;
  char *msg;
  char *stext;
  char *cp;
  int ret;
  char protocol[4];

  if ((stext = escape_quotes(text)) == NULL)
    return 0;

  for (cp=text,ret=0; *cp; cp++)
    if (*cp == '\n') {
      ret++;
      break;
    }

  if (config.protocol == PROTOCOL_AUTO)
    protocol[0] = '\0';
  else if (config.protocol == PROTOCOL_IPV4)
    strcpy (protocol, " -4");
  else if (config.protocol == PROTOCOL_IPV6)
    strcpy (protocol, " -6");

  if (asprintf (&cmd, "sendmsg -q -m%s%s -s '%s%s' %s 2> /dev/null",
		(ret?" -l":""), protocol,
		stext, (ret?"\n":""), addr) == -1) {
    free (stext);
    return 0;
  }
  free (stext);

#ifdef DEBUG
  printf ("%s\n", cmd);
#endif

  ret = system (cmd);
  if (ret == -1) {
    perror ("system");
    free (cmd);
    return 0;
  } else if (WEXITSTATUS(ret)) {
    if (asprintf (&msg, _("%s terminated with exit code %d."),
		  "sendmsg", WEXITSTATUS(ret)) != -1) {

      if (WEXITSTATUS(ret) == 1) {
	cp = msg;
	if (asprintf (&msg, "%s %s", cp, _("Maybe the recipient is not available at the moment.")) != -1)
	  free (cp);
	else
	  msg = cp;
      }

      msgbox (_("Error condition"), msg);
      free (msg);
    }
    free (cmd);
    return 0;
  }

  free (cmd);

  return 1;
}

int sendmessage (const char *addr, char *text)
{
  int ret = 1;
  char *sp;
  char *pivot;
  char pv = '\0';

  if (strlen(text) > SENDMSG_MAXLEN)
    msgbox (_("Message information"),
	    _("Your message is longer than the SAFT limit for single messages and will be transmitted in several chunks therefore."));

  sp = text;
  while (*sp) {
    if (strlen(sp) > SENDMSG_MAXLEN) {
      for (pivot = sp+SENDMSG_MAXLEN-1; 
	   (sp+SENDMSG_MAXLEN-1 - pivot) < SENDMSG_DELTA && *pivot != '\n';
	   pivot--);

      /* No newline found, use maximum length then */
      if (*pivot != '\n')
	pivot = sp+SENDMSG_MAXLEN-1;

      pv = *pivot; *pivot = '\0';
    } else
      pv = '\0';

    ret &= sendmsg (addr, sp);

    sp += (strlen(sp));
    if (pv) {
      if (pv == '\n')
	sp++;
      else
	*pivot = pv;
    }
  }

  return ret;
}
