/*  GFAX - Gnome fax application
 *  Copyright (C) 1999 George A. Farris
 *
 *  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-1307, USA.
*/


#include <config.h>
#include <gnome.h>
#include <glade/glade.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <ctype.h>

#include "gfax.h"
#include "setup.h"
#include "hylafax_sendfax.h"

void show_output_toggled(GtkToggleButton *show_output, gpointer user_data);
int execute_command(int argc, char *argv[]);
void show_command_result(int exitcode, char *output);

/* memory that holds the command output */
gchar  *command_output = NULL;
size_t  command_output_size = 0;
gint    command_output_pos = 0;

/**
 * Callback function, that gets called, when the user toggles the
 * "show_output" toggle button. Shows and hides the GnomeLess widget, that
 * displays the command output.
 */
void show_output_toggled(GtkToggleButton *show_output,
						 gpointer user_data) 
{
   GtkWidget *command_output_widget;
   
   command_output_widget = (GtkWidget *)user_data;
   if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(show_output))) {
	   gtk_widget_show_now(GTK_WIDGET(command_output_widget));
   } else {
	   gtk_widget_hide(GTK_WIDGET(command_output_widget));
   }
}


/**
 * Function that executes the given program and shows the program output in a
 * new dialog box. The dialog box contains a toggle button to show and hide
 * the program output.
 */
int execute_command(int argc, char *argv[]) 
{
   /* pipe from command */
   int pipe_fds[2];
   int parent_end, child_end;
   pid_t child_pid, wait_pid;
   int wstatus;
   size_t len;
   int exitcode = -1;

   int i;
   
   /* start the command and capture the output: */
   pipe(pipe_fds);
   parent_end = pipe_fds[0];
   child_end  = pipe_fds[1];
   child_pid  = fork();
   if ( child_pid == 0 ) {
	   close(0);				 /* no stdin for fax software */
	   close(parent_end);
	   /* make child_end on fd=1 */
	   if ( child_end != 1 ) {
		   dup2(child_end, 1);
		   close(child_end);
	   }
	   dup2(1, 2);    /* send stderr to stdout: */
	   execvp(argv[0], argv + 1);
           perror("Command not found");
	   _exit(127);
   } else {
	   close(child_end);

	   /* start output with command line options: */
	   command_output_size = 1024;
	   command_output	   = g_malloc(command_output_size);
	   command_output[0]   = 0;
	   for ( i = 0; i < argc - 1; i++ ) {
		   if ( i == 1 ) continue;  	/* skip argv[0] */
		   sprintf(command_output + strlen(command_output), 
			   "%s ", argv[i]);
	   }
	   sprintf(command_output + strlen(command_output), "\n");
	   command_output_pos  = strlen(command_output);

	   /* read from child until eof: */
	   do {
		   /* enough memory available? */
		   if ( command_output_size - command_output_pos < 1024) {
			   command_output_size += 1024;
			   /* allocate 1 more byte for \0 */
			   command_output = realloc(command_output, command_output_size + 1);
		   }
		   len = read(parent_end, 
				  command_output + command_output_pos, 
				  command_output_size - command_output_pos);
		   if ( len > 0 ) {
			   command_output_pos += len;
		   }
	   } while (len > 0 );
	   command_output[command_output_pos] = 0;
	   close(parent_end);
	   do {
		   wait_pid = waitpid (child_pid, &wstatus, 0);
	   } while (wait_pid == -1 && errno == EINTR);


	   if ( WIFEXITED(wstatus) ) {
		   exitcode = WEXITSTATUS(wstatus);
	   }
   }
   
   return exitcode;
}

/**
 * Shows the result of the programm execution and frees memory of
 * output text.
 */
void show_command_result(int exitcode, char *output) 
{
	char *result_text;
	gchar   *s;
	
	/* widgets for ui */
	GtkWidget *dialog, *label, *show_output, *command_output_widget;
	GtkWidget *pixmap = NULL, *hbox;
	
	if ( exitcode == 0 ) {
		result_text = _("Job suceeded.");
		s = gnome_unconditional_pixmap_file("gnome-info.png");
	} else {
		result_text = _("Error occured.");
		s = gnome_unconditional_pixmap_file("gnome-error.png");
	}		
	
	dialog = gnome_dialog_new(_("Gfax result"), 
				  GNOME_STOCK_BUTTON_OK, NULL);
	hbox = gtk_hbox_new (FALSE, 0);
	gtk_box_pack_start (GTK_BOX(GNOME_DIALOG(dialog)->vbox),
			    hbox, FALSE, FALSE, 0);
	gtk_widget_show (hbox);
	label	   = gtk_label_new(result_text);
	show_output = gtk_check_button_new_with_label(_("Show output of fax spooling software"));
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(show_output), FALSE);
	command_output_widget = gnome_less_new();
	gnome_less_show_string(GNOME_LESS(command_output_widget), output);
	gtk_widget_hide(GTK_WIDGET(command_output_widget));
	
	if (s) {
		pixmap = gnome_pixmap_new_from_file(s);
		g_free(s);
	}
	if (pixmap) {
		gtk_box_pack_start (GTK_BOX(hbox),
				    pixmap, FALSE, TRUE, 0);
		gtk_widget_show (pixmap);
	}
	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(dialog)->vbox), show_output, FALSE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(dialog)->vbox), command_output_widget, TRUE, TRUE, 0);
	
	gtk_widget_show(GTK_WIDGET(label));
	gtk_widget_show(GTK_WIDGET(show_output));
	gtk_signal_connect(GTK_OBJECT(show_output), "toggled",
			   GTK_SIGNAL_FUNC(show_output_toggled), 
			   command_output_widget);
	
	/*
	 * Run the dialog and wait for the user to select yes or no.
	 * If the user closes the window with the window manager, we
	 * will get a -1 return value
	 */
	gnome_dialog_run_and_close (GNOME_DIALOG (dialog));
	
	g_free(command_output);
}

gint send_fax(Destination *dest, gboolean testMode)
{
   char *argv[20];
   int  argc = 0;
   char time[20];
   char number[32];
   char tmpnum[32];
   char hylafax_host[128];
   int i;
   char *output;
   int   exitcode;

/* -------------------- START OF MGETTY -------------------------------------------	*/

	if (g_strcasecmp(transmitAgent, "mgetty") == 0) {
		/* set the initial fax command */

		argv[argc++] = "faxspool";    /* program to execute */
		argv[argc++] = "faxspool";    /* argv[0] */

		/* set the resolution, true is fine res */
		if (!resolution_state) {
			argv[argc++] = "-n";
		}

		if (coverPage_state) {
			argv[argc++] = "-C";
			argv[argc++] = "/usr/lib/mgetty+sendfax/make.coverpg";
		} else { 
			argv[argc++] = "-C";
			argv[argc++] = "-";
		}

		/* set the email address for notification */
		if (emailNotify_state) {
			if (strlen(emailAddress) <= 1) {
				return(NO_EMAIL_ADDRESS);
			}
			argv[argc++] = "-f";
			argv[argc++] = emailAddress;
		}


		/* set the verbose destination for return mail and @D@ on each
                 * page */
		if (strlen(dest->organization) > 1) {
			argv[argc++] = "-D";
			argv[argc++] = dest->organization;
		}

		/* set time to send fax only if not send immediate */
		if (!sendNow_state) {
			sprintf(time, "%s:%s", hour, minute);
			argv[argc++] = "-t";
			argv[argc++] = time;
		}

		/* set the phone number to send to.  First we want to strip all the spaces
		   out of the number */
		for (i=0; *dest->faxNumber; i++, dest->faxNumber++) {
			if (*dest->faxNumber == ' ') {
				i--;
				continue;
			} else {
				 tmpnum[i] = *dest->faxNumber;
			}
		}
		tmpnum[i] = '\0';	
		
		if (strlen(tmpnum) < 4) {	/* we at least want local numbers */
			return(NO_FAX_NUMBER);
		} else {	
			sprintf(number, "%s%s", phonePrefix, tmpnum);
			argv[argc++] = number;
		}

		
		/* tack the filename onto the end */
		argv[argc++] = dest->fileName;

		/* at this point we will let faxspool do the rest of the sanity checking */
		/* more and better checking will be done in the future. */
	}
/* -------------------  END OF MGETTY ---------------------------------------------- */
	



/* -------------------- START OF HYLAFAX -------------------------------------------
 * 	Start of Hylafax options.
 *
 *	Note:  The order of options sent to sendfax is significant.  All cover page
 *		   fine res etc should come **after** the destination fax number.
*/

	/* go here if it's Hylafax */
	if (g_strcasecmp(transmitAgent, "hylafax") == 0) {
		
		argv[argc++] = "sendfax";     /* program to execute */
		argv[argc++] = "sendfax";     /* argv[0] */

		/* is there a cover page ?  Note this isn't supported yet so always say no
		   to cover page genearation */
		if (coverPage_state)
			argv[argc++] = "-n";
		else
			argv[argc++] = "-n";


/*		
		// set the verbose destination for return mail and @D@ on each page
		if (strlen(organization) > 1) {
	        argv[argc++] = "-D";
	        argv[argc++] = organization;

		}
*/
		/* set time to send fax only if not send immediate */
		if (!sendNow_state) {
			sprintf(time, "%s:%s", hour, minute);
			argv[argc++] = "-a";
			argv[argc++] = time;
		}
		
		/* set the phone number to send to */
		if (strlen(dest->faxNumber) >= 4) {		/* we at least want local numbers */
			argv[argc++] = "-d";     /* the destination command */
			sprintf(number, "%s%s", phonePrefix, dest->faxNumber);
			argv[argc++] = number;
		}

		/* set the resolution, true is fine res */
		if (resolution_state)
			argv[argc++] = "-m";
		else
			argv[argc++] = "-l";
		
		/* set the email address for notification */
		if (emailNotify_state) {
			if (strlen(emailAddress) <= 1) {
				return(NO_EMAIL_ADDRESS);
			}
			argv[argc++] = "-D";
			argv[argc++] = "-f";
			argv[argc++] = emailAddress;
		}

		/* set host:port of hylafax server */
		sprintf(hylafax_host, "%s:%d", 
			hylafaxServerName, hylafaxServerPort);
		argv[argc++] = "-h";
		argv[argc++] = hylafax_host;

		
		/* tack the filename onto the end */
		argv[argc++] = dest->fileName;
	}
/* -------------------  END OF HYLAFAX ---------------------------------------------- */
	

	
	/* Don't run command if it's in test mode */
	if (testMode) { 
		g_print(_("Sendfax command is:\n"));
		for ( i = 0; i < argc; i++ ) 
			g_print("%s ", argv[i]);
		g_print(_("\n\nDelete file is %d\n"), dest->deleteFile);
	} else {
		argv[argc++] = NULL;

		if ( hylafaxInternalSendfax ) {
			/* use built-in hylafax client */
			exitcode = hylafax_sendfax(dest);
			output = hylafax_getlog();
		} else {
			exitcode = execute_command(argc, argv);
			output = command_output;
		}
		show_command_result(exitcode, output);

		if ( dest->deleteFile)  /* we use this if faxing a file, we don't want to delete it */
			if (remove(dest->fileName)) {
				gchar *msg;
			   
				msg = g_strdup_printf("Error removing %s\n", fileName);
				do_message(msg);
				g_free(msg);
			} 
	}
	
	
	/* set the default back to automatic file deletion */
	dest->deleteFile = TRUE;
	
		
	return(0);
}	

/* These are Emacs variables to use a common "Gfax" coding style:
 * ;;; Local Variables: ***
 * ;;; mode:C ***
 * ;;; c-basic-offset:8 ***
 * ;;; indent-tabs-mode:t ***
 * ;;; End: ***
 */
