/***************************************************************************/
/***************************************************************************/
/*                                                                         */
/*   (c) 1993-1994.  The Regents of the University of California.  All     */
/*   rights reserved.                                                      */
/*                                                                         */
/*   This work was produced at the University of California, Lawrence      */
/*   Livermore National Laboratory (UC LLNL) under contract no.            */
/*   W-7405-ENG-48 (Contract 48) between the U.S. Department of Energy     */
/*   (DOE) and The Regents of the University of California (University)    */
/*   for the operation of UC LLNL.  Copyright is reserved to the           */
/*   University for purposes of controlled dissemination,                  */
/*   commercialization through formal licensing, or other disposition      */
/*   under terms of Contract 48; DOE policies, regulations and orders;     */
/*   and U.S. statutes.  The rights of the Federal Government are          */
/*   reserved under Contract 48 subject to the restrictions agreed upon    */
/*   by the DOE and University.                                            */
/*                                                                         */
/*                                                                         */
/*                              DISCLAIMER                                 */
/*                                                                         */
/*   This software was prepared as an account of work sponsored by an      */
/*   agency of the United States Government.  Neither the United States    */
/*   Government nor the University of California nor any of their          */
/*   employees, makes any warranty, express or implied, or assumes any     */
/*   liability or responsibility for the accuracy, completeness, or        */
/*   usefulness of any information, apparatus, product, or process         */
/*   disclosed, or represents that its specific commercial products,       */
/*   process, or service by trade name, trademark, manufacturer, or        */
/*   otherwise, does not necessarily constitute or imply its               */
/*   endorsement, recommendation, or favoring by the United States         */
/*   Government or the University of California. The views and opinions    */
/*   of the authors expressed herein do not necessarily state or reflect   */
/*   those of the United States Government or the University of            */
/*   California, and shall not be used for advertising or product          */
/*   endorsement purposes.                                                 */
/*                                                                         */
/*   Permission to use, copy, modify and distribute this software and its  */
/*   documentation for any non-commercial purpose, without fee, is         */
/*   hereby granted, provided that the above copyright notice and this     */
/*   permission notice appear in all copies of the software and            */
/*   supporting documentation, and that all UC LLNL identification in      */
/*   the user interface remain unchanged.  The title to copyright LLNL     */
/*   XFTP shall at all times remain with The Regents of the University     */
/*   of California and users agree to preserve same. Users seeking the     */
/*   right to make derivative works with LLNL XFTP for commercial          */
/*   purposes may obtain a license from the Lawrence Livermore National    */
/*   Laboratory's Technology Transfer Office, P.O. Box 808, L-795,         */
/*   Livermore, CA 94550.                                                  */
/*                                                                         */
/***************************************************************************/
/***************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <Xm/Xm.h>
#include <Xm/Form.h>
#include <Xm/Label.h>
#include <Xm/ToggleB.h>
#include "xftp.h"
#include "xfer.h"
#include "list.h"

#define MAXTRIES  10

#ifndef P_tmpdir
#define P_tmpdir "/tmp"
#endif

int cb_xfer_files();
int cb_delete_entries();
char *temp_file_name();
char *cstring_to_text();

static Widget w_abortDialog;

extern int inquire_on_delete;
extern int inquire_on_copy;
extern Widget w_ascii;
extern Widget w_dirList[];
extern struct st_host_info hinfo[];
extern struct xfer_ctrl_block xfer_ctrl;
extern struct del_ctrl_block del_ctrl;
extern XtAppContext app;
extern Widget w_toplev;
extern Widget w_copyButton;
extern Widget w_rCopyButton;
extern Widget w_viewButton;
extern Display *display;


/*
 * cb_copy - Callback that copies selected file(s).
 */
void
cb_copy(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
	int operation = (int)client_data;
	int xfer_mode;
	int src_host;
	int snk_host;
	struct entry_link *head;
	struct entry_link *ptr;
	XmStringTable selected_items;
	int nselected_items;
	int i;
	int retval;
	char *view_snk_dir;
	char *temp_ptr;

	/* Clear error flag */
	raise_okflag();

	/* Determine source and sink hosts */
	if (host_selected(LEFT)) {
		src_host = LEFT;
		snk_host = RIGHT;
	} else if (host_selected(RIGHT)) {
		src_host = RIGHT;
		snk_host = LEFT;
	} else
		fatal_error("Bug in cb_copy() - Contact programmer");

	/* For view operation, make sink host same as source for error reporting */
	if (operation == VIEW)
		snk_host = src_host;

	/* Ask the user if okay to copy? */
	if (inquire_on_copy) {
        switch (operation) {
        case COPY:
            retval = verify_selection(src_host,
                "Do you really want to transfer these items?");
            break;
        case RCOPY:
            retval = verify_selection(src_host,
                "Do you really want to recursively transfer these items?");
            break;
        case VIEW:
            retval = True;
        }
		if (retval == False)
			return;
	}

	/* This might take some time */
	use_busy_cursor();

	/* Set transfer mode */
	if (XmToggleButtonGetState(w_ascii))
		xfer_mode = ASCII;
	else
		xfer_mode = BINARY;
    switch (operation) {
    case COPY:
    case RCOPY:
		if (hinfo[snk_host].type == REMOTE)
			if (ftp_type(snk_host, xfer_mode) < 0) {
				restore_prev_cursor();
				lost_connection(snk_host);
				return;
			}
	case VIEW:
        if (hinfo[src_host].type == REMOTE)
            if (ftp_type(src_host, xfer_mode) < 0) {
                restore_prev_cursor();
                lost_connection(src_host);
                return;
            }
    }

	/* Create temporary directory name for view operation */
	if (operation == VIEW) {
		if ((temp_ptr = temp_file_name()) == NULL) {
			warning_error("Unable to create temporary directory for viewer");
			restore_prev_cursor();
			return;
		}
		view_snk_dir = XtNewString(temp_ptr);
		XtFree(temp_ptr);
	}

	/* Pop up file transfer monitor */
	show_monitor();
	clear_monitor();
	XSync(display, 0);
	sleep(1);

	/* Disable controls */
	enable_controls(False);

	/* Form linked list of selected entries */
	XtVaGetValues(
		w_dirList[src_host],
		XmNselectedItemCount, &nselected_items,
		XmNselectedItems,     &selected_items,
		NULL
	);
	head = NULL;
	for (i=nselected_items-1; i>=0; i--) {
		ptr = XtNew(struct entry_link);
		ptr->entry = cstring_to_text(selected_items[i]);
		strip_off_symbol(hinfo[src_host].system, hinfo[src_host].server,
			ptr->entry);
		ptr->next = head;
		head = ptr;
	}

	/* Set up file control block */
	xfer_ctrl.operation = operation;
	xfer_ctrl.mode = xfer_mode;
	xfer_ctrl.level = 0;
	xfer_ctrl.state = 0;
	xfer_ctrl.nretries = 0;
	xfer_ctrl.src_host = src_host;
	xfer_ctrl.snk_host = snk_host;
	xfer_ctrl.head[0] = head;
	xfer_ctrl.abort_requested = False;
	xfer_ctrl.src_host_type = hinfo[src_host].type;
	xfer_ctrl.src_host_system = hinfo[src_host].system;
	xfer_ctrl.src_host_server = hinfo[src_host].server;
	xfer_ctrl.src_host_wd = XtNewString(hinfo[src_host].wd);
	switch (operation) {
	case COPY:
	case RCOPY:
		xfer_ctrl.snk_host_type = hinfo[snk_host].type;
		xfer_ctrl.snk_host_system = hinfo[snk_host].system;
		xfer_ctrl.snk_host_wd = XtNewString(hinfo[snk_host].wd);
		break;
	case VIEW:
		xfer_ctrl.snk_host_type = LOCAL;
		xfer_ctrl.snk_host_system = SYS_UNIX;
		xfer_ctrl.snk_host_wd = view_snk_dir;
	}

	/* Transfer file */
	XtAppAddWorkProc(app, (XtWorkProc)cb_xfer_files, NULL);
}


/*
 * cb_delete - Callback that deletes selected file(s).
 */
void
cb_delete(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
	int host = (int)client_data;

	init_delete(host, False);
}


/*
 * cb_rdelete - Callback that recursively deletes selected entries.
 */
void
cb_rdelete(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
	int host = (int)client_data;

	init_delete(host, True);
}


/*
 * init_delete - Initialize delection(s).
 */
init_delete(host, recursive)
int host;
int recursive;
{
	XmStringTable selected_items;
	int nselected_items;
	int i;
	struct entry_link *head;
	struct entry_link *ptr;
	int retval;

	/* Clear error flag */
	raise_okflag();

	/* Ask the user if okay to delete? */
	if (inquire_on_delete) {
		if (recursive)
			retval = verify_selection(host,
				"Do you really want to recursively delete these items?");
		else
			retval = verify_selection(host,
				"Do you really want to delete these items?");
		if (retval == False)
			return;
	}

	/* This might take some time */
	use_busy_cursor();

	/* Pop up deletion monitor */
	show_mp_monitor("Now Deleting:");
	clear_mp_monitor();

	/* Disable controls */
	enable_controls(False);

	/* Get list of entries to delete */
	XtVaGetValues(
		w_dirList[host],
		XmNselectedItemCount, &nselected_items,
		XmNselectedItems,     &selected_items,
		NULL
	);
    head = NULL;
    for (i=nselected_items-1; i>=0; i--) {
        ptr = XtNew(struct entry_link);
		ptr->entry = cstring_to_text(selected_items[i]);
        strip_off_symbol(hinfo[host].system, hinfo[host].server, ptr->entry);
        ptr->next = head;
        head = ptr;
    }

    /* Set up deletion control block */
    del_ctrl.recursive = recursive;
    del_ctrl.level = 0;
    del_ctrl.host = host;
    del_ctrl.head[0] = head;

    /* Perform deletion */
    XtAppAddWorkProc(app, (XtWorkProc)cb_delete_entries, NULL);
}


/*
 * show_abort_dialog - Pop up a dialog that displays an abort-in-progress
 *                     message.
 */
show_abort_dialog()
{
	create_abort_dialog();
	XtManageChild(w_abortDialog);
	add_dialog_to_list(w_abortDialog);
	force_update(w_abortDialog);
}


/*
 * hide_abort_dialog - Pop down dialog that displays an abort-in-progress
 *                     message.
 */
hide_abort_dialog()
{
	XtUnmanageChild(w_abortDialog);
}


/*
 * create_abort_dialog - Creates a dialog that displays an abort-in-progress
 *                       message.
 */
create_abort_dialog()
{
	static int initialized = False;
	Arg args[1];
	int i;

    /* Create dialog only once */
    if (initialized)
        return;
    initialized = True;

	/* Create form dialog */
	i = 0;
	XtSetArg(args[i], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); i++;
	w_abortDialog = XmCreateFormDialog(w_toplev, "abort", args, i);

	/* Monitor dialog to control help dialog modality */
	register_as_modal(w_abortDialog);

	/* Kludge to add title bar under OLWM */
	AddOLWMDialogFrame(w_abortDialog);

	/* Create message */
	XtVaCreateManagedWidget(
		"abortMessage",
		xmLabelWidgetClass,
		w_abortDialog,
		XmNtopAttachment,		XmATTACH_FORM,
		XmNtopOffset,			40,
		XmNbottomAttachment,	XmATTACH_FORM,
		XmNbottomOffset,		40,
		XmNleftAttachment,		XmATTACH_FORM,
		XmNleftOffset,			50,
		XmNrightAttachment,		XmATTACH_FORM,
		XmNrightOffset,			50,
		NULL
	);
}


/*
 * update_xfer_controls - Update the sensitivity of the "Copy" and "Rcopy"
 *                        buttons to reflect connection and selection states.
 */
update_xfer_controls()
{
    XmString copy_label;
    XmString rcopy_label;
    XmString str;
    int sensitivity;

	/* Is a copy possible? */
    if (hinfo[LEFT].type == NEITHER || hinfo[RIGHT].type == NEITHER) {
        sensitivity = False;
        copy_label = XmStringCreateSimple("Copy");
        rcopy_label = XmStringCreateSimple("Rcopy");
    } else {
        if (host_selected(LEFT)) {
            sensitivity = True;
            copy_label = XmStringCreateSimple(">>Copy>>");
            rcopy_label = XmStringCreateSimple(">>Rcopy>>");
        } else if (host_selected(RIGHT)) {
            sensitivity = True;
            copy_label = XmStringCreateSimple("<<Copy<<");
            rcopy_label = XmStringCreateSimple("<<Rcopy<<");
        } else {
            sensitivity = False;
            copy_label = XmStringCreateSimple("Copy");
            rcopy_label = XmStringCreateSimple("Rcopy");
        }
    }

    /* Update "Copy" button label only if it has changed */
    XtVaGetValues(w_copyButton, XmNlabelString, &str, NULL);
    if (XmStringCompare(str, copy_label) == False)
        XtVaSetValues(w_copyButton, XmNlabelString, copy_label, NULL);
    XmStringFree(copy_label);
    XmStringFree(str);   /* Yes, this is necessary */
    XtSetSensitive(w_copyButton, sensitivity);

    /* Update "Rcopy" button label only if it has changed */
    XtVaGetValues(w_rCopyButton, XmNlabelString, &str, NULL);
    if (XmStringCompare(str, rcopy_label) == False)
        XtVaSetValues(w_rCopyButton, XmNlabelString, rcopy_label, NULL);
    XmStringFree(rcopy_label);
    XmStringFree(str);   /* Yes, this is necessary */
    XtSetSensitive(w_rCopyButton, sensitivity);

	/* Adjust sensitivity of "View" button */
	if ((selection_count(LEFT) == 1) || (selection_count(RIGHT) == 1))
		XtSetSensitive(w_viewButton, True);
	else
		XtSetSensitive(w_viewButton, False);
}


/*
 * temp_file_name - Create a unique name for a temporary file in the
 *                  directory defined as P_tmpdir in <stdio.h>.  If the
 *                  environment variable TMPDIR is defined, it is used
 *                  as the directory.  If successful, this function returns
 *                  a pointer to the name, which can be released by calling
 *                  XtFree(); if unsuccessful, NULL is returned.  The name
 *                  will begin with the prefix "xftp".
 */
char *
temp_file_name()
{
	char *dir_path = NULL;
	char *file_path;
	char *temp;
	int pid;
	char pid_string[5];
	char suffix[5];
	int i;
	int j;

	/* Get directory path */
	if ((temp = getenv("TMPDIR")))
		dir_path = XtNewString(temp);
	else
		dir_path = XtNewString(P_tmpdir);

	/* Verify that directory is accessible */
	if (access(dir_path, 0) < 0) {
		XtFree(dir_path);
		return NULL;
	}

	/* Convert PID into string */
	pid = getpid();
	sprintf(pid_string, "%04d", pid%10000);

	/* Try several times to create a unique name */
	for (i=0; i<MAXTRIES; i++) {
		for (j=0; j<4; j++)
			suffix[j] = ((rand()&0xff)%26)+'A';
		suffix[4] = '\0';
		file_path = XtMalloc(strlen(dir_path)+14);
		strcpy(file_path, dir_path);
		if (file_path[strlen(file_path)-1] != '/')
			strcat(file_path, "/");
		strcat(file_path, "xftp");
		strcat(file_path, pid_string);
		strcat(file_path, suffix);
		if (access(file_path, 0) < 0) {
			if (errno == ENOENT) {
				XtFree(dir_path);
				return file_path;
			}
		}
		XtFree(file_path);
	}

	XtFree(dir_path);
	return NULL;
}

