/***************************************************************************/
/***************************************************************************/
/*                                                                         */
/*   (c) 1995-1999.  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     */
/*   XDIR 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 XDIR 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 <stdlib.h>
#include <Xm/SelectioB.h>
#include <Xm/Form.h>
#include <Xm/List.h>
#include <Xm/TextF.h>
#include <Xm/Label.h>
#include "xdir.h"
#include "list.h"
#include "str.h"
#include "history.h"

static struct {
    Widget w_dialog;
    Widget w_form;
    Widget w_hostListLabel;
    Widget w_hostList;
    Widget w_hostName;
    Widget w_hostNameLabel;
    Widget w_userName;
    Widget w_userNameLabel;
	Widget w_connectButton;
} rconnect;

static char *rconnect_help[] = {
	"This dialog enables you to connect to a remote host.  Use",
	"the dialog \"Connect to Anonymous\" (accessed via the host's",
	"\"Connect\" menu) to more easily connect to an anonymous",
	"FTP site.\n",
	"\n",
	"When this dialog pops up, the \"User Name\" field is",
	"initialized to the value of the environment variable USER.\n",
	"\n",
	"An optional port number may follow the host name (using",
	"a space as the delimiter).\n",
	"\n",
    "Previously referenced host/user pairs are remembered, and those",
	"with user names other than \"anonymous\" and \"ftp\", and other",
	"than those that start with \"anonymous@\" or \"ftp@\", are",
    "displayed in the scrollable list labeled \"Recently",
    "Referenced Hosts\".  Double-click on an expression in the",
    "list to initiate a connection using that host name and user",
	"name.  Single-click on an entry in the list to place that",
    "information into the text fields labeled \"Host Name\" and",
    "\"User Name\", where it can be edited.\n",
    "\n",
    "The user preference HISTORY SORT ORDER specifies whether previously",
    "used host/user pairs are displayed in alphabetical order or",
    "with the most-recently-referenced pairs at the top of",
    "the list.  The user preference MAX USER NAME HISTORY",
    "specifies the maximum number of user names to remember per host.  ",
	"The user preference MAX HOST NAME HISTORY specifies the maximum",
	"number of hosts to remember information for (including user names).  ",
    "The host/user information is preserved across LLNL XDIR sessions.\n",
    "\n",
    "Click on the CONNECT button to initiate a connection and",
    "remove the dialog.  Click on the CANCEL button to remove",
    "the dialog without attemping to connect.",
    NULL
};

extern struct st_host_info hinfo[];
extern int sort_caches;
extern struct dirwin_st *dirwin_head;
extern Display *display;
extern int use_proxy;
extern char *proxy_host;
extern int proxy_port;

void cb_rconnect_single_selection();
void cb_rconnect_connect();
void cb_rconnect_cancel();
void cb_rconnect_help();
void cb_rconnect_def_action();
void cb_map_dialog();
void create_rconnect_dialog();
void update_rconnect_dialog();
Widget vertical_sb();
char *cstring_to_text();


/*
 * cb_connect_to_remote - Callback that pops up the Remote Connection dialog.
 */
void
cb_connect_to_remote(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
    struct dirwin_st *dirwin = (struct dirwin_st *)client_data;

	/* Start operation */
	if (!start_op(False))
		return;

	/* Clear error flag */
	raise_okflag();

	create_rconnect_dialog(dirwin);
	update_rconnect_dialog();

    /* Pop up dialog */
    XtManageChild(rconnect.w_dialog);
	traverse_to_widget(rconnect.w_hostName);
}


/*
 * create_rconnect_dialog - Creates the Remote Connection dialog.
 */
void
create_rconnect_dialog(dirwin)
struct dirwin_st *dirwin;
{
	Arg	args[3];
	int i;
	Widget widget;

	/* Create prompt dialog for connection to remote host */
	i = 0;
	XtSetArg(args[i], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); i++;
	XtSetArg(args[i], XmNdefaultPosition, False); i++;
	XtSetArg(args[i], XmNautoUnmanage, False); i++;
	rconnect.w_dialog = XmCreatePromptDialog(dirwin->w_shell,"rConnect",args,i);
    XtAddCallback(rconnect.w_dialog, XmNokCallback, cb_rconnect_connect,
		(XtPointer)dirwin);
	XtAddCallback(rconnect.w_dialog, XmNcancelCallback, cb_rconnect_cancel,
		(XtPointer)NULL);
	XtAddCallback(rconnect.w_dialog, XmNhelpCallback, cb_rconnect_help,
		(XtPointer)NULL);
	XtAddCallback(rconnect.w_dialog, XmNmapCallback, cb_map_dialog,
		(XtPointer)XtWindow(dirwin->w_shell));

	/* Don't show prompt dialog's selection label and text */
	widget = XmSelectionBoxGetChild(rconnect.w_dialog,XmDIALOG_SELECTION_LABEL);
	XtUnmanageChild(widget);
	widget = XmSelectionBoxGetChild(rconnect.w_dialog, XmDIALOG_TEXT);
	XtUnmanageChild(widget);

	/* Get widget id for "Connect" button */
	rconnect.w_connectButton = XmSelectionBoxGetChild(rconnect.w_dialog,
		XmDIALOG_OK_BUTTON);

	/* Add callback for the WM_DELETE_WINDOW protocol */
	add_wm_delete_window_cb(rconnect.w_dialog, cb_rconnect_cancel, NULL, False);

	/* Create form for control area */
	rconnect.w_form = XtVaCreateManagedWidget(
		"form",
		xmFormWidgetClass,
		rconnect.w_dialog,
		XmNwidth,	250,
		NULL
	);

	/* Create label for host list */
	rconnect.w_hostListLabel = XtVaCreateManagedWidget(
		"hostListLabel",
		xmLabelWidgetClass,
		rconnect.w_form,
		XmNalignment,		XmALIGNMENT_BEGINNING,
		XmNtopAttachment,	XmATTACH_FORM,
		XmNleftAttachment,	XmATTACH_FORM,
		XmNrightAttachment,	XmATTACH_FORM,
		NULL
	);

	/* Create scrolled list to contain host names */
	i = 0;
	XtSetArg(args[i], XmNlistSizePolicy, XmCONSTANT); i++;
	XtSetArg(args[i], XmNselectionPolicy, XmSINGLE_SELECT); i++;
	rconnect.w_hostList = XmCreateScrolledList(rconnect.w_form,
		"hostList", args, i);
	XtVaSetValues(XtParent(rconnect.w_hostList),
		XmNtopAttachment,		XmATTACH_WIDGET,
		XmNtopWidget,			rconnect.w_hostListLabel,
		XmNrightAttachment,		XmATTACH_FORM,
		XmNleftAttachment,		XmATTACH_FORM,
		NULL
	);
	XtManageChild(rconnect.w_hostList);

    /* Add single-selection callback */
    XtAddCallback(
        rconnect.w_hostList,
        XmNsingleSelectionCallback,
        cb_rconnect_single_selection,
        (XtPointer)NULL
    );

    /* Add double-click callback to directory list*/
    XtAddCallback(
        rconnect.w_hostList,
        XmNdefaultActionCallback,
        cb_rconnect_def_action,
        (XtPointer)dirwin
    );

	/* Create label for host name */
	rconnect.w_hostNameLabel = XtVaCreateManagedWidget(
		"hostNameLabel",
		xmLabelWidgetClass,
		rconnect.w_form,
		XmNalignment,		XmALIGNMENT_BEGINNING,
		XmNtopAttachment,	XmATTACH_WIDGET,
		XmNtopWidget,		rconnect.w_hostList,
		XmNtopOffset,		10,
		XmNleftAttachment,	XmATTACH_FORM,
		XmNrightAttachment,	XmATTACH_FORM,
		NULL
	);

	/* Create text field for host name */
	rconnect.w_hostName = XtVaCreateManagedWidget(
		"hostName",
		xmTextFieldWidgetClass,
		rconnect.w_form,
		XmNtopAttachment,	XmATTACH_WIDGET,
		XmNtopWidget,		rconnect.w_hostNameLabel,
		XmNrightAttachment,	XmATTACH_FORM,
		XmNleftAttachment,	XmATTACH_FORM,
		NULL
	);

	/* Create label for user name */
	rconnect.w_userNameLabel = XtVaCreateManagedWidget(
		"userNameLabel",
		xmLabelWidgetClass,
		rconnect.w_form,
		XmNalignment,		XmALIGNMENT_BEGINNING,
		XmNtopAttachment,	XmATTACH_WIDGET,
		XmNtopWidget,		rconnect.w_hostName,
		XmNtopOffset,		10,
		XmNleftAttachment,	XmATTACH_FORM,
		XmNrightAttachment,	XmATTACH_FORM,
		NULL
	);

	/* Create text field for user name */
	rconnect.w_userName = XtVaCreateManagedWidget(
		"userName",
		xmTextFieldWidgetClass,
		rconnect.w_form,
		XmNtopAttachment,		XmATTACH_WIDGET,
		XmNtopWidget,			rconnect.w_userNameLabel,
		XmNrightAttachment,		XmATTACH_FORM,
		XmNleftAttachment,		XmATTACH_FORM,
		XmNbottomAttachment,	XmATTACH_FORM,
		NULL
	);
}


/*
 * update_rconnect_dialog - Display the last referenced hostname/username
 *                          pairs in the scrolled list of the remote
 *                          connection dialog.
 */
void
update_rconnect_dialog()
{
    struct sl_struct *list;
    XmString string;
    int i;
	char *host_part;
	char *user_part;

    /* Get remembered host/user names*/
    retrieve_hostuser_history(&list, sort_caches);

    /* Enter host/user names into scrolled list */
    reset_list(rconnect.w_hostList);
    for (i=0; i<list->nentries; i++)
		if (parse_hostuser(list->entries[i], &host_part, &user_part) == 0) {
			if (strcmp(user_part, "anonymous") && strcmp(user_part, "ftp") &&
				(strstr(user_part, "anonymous@") != user_part) && 
				(strstr(user_part, "ftp@") != user_part)) {
        		string = XmStringCreateSimple(list->entries[i]);
        		XmListAddItem(rconnect.w_hostList, string, 0);
        		XmStringFree(string);
			}
			XtFree(host_part);
			XtFree(user_part);
		}
    release_array_list(list);

    /* Clear hostname field */
    XmTextFieldSetString(rconnect.w_hostName, "");

	/* Try to set user name to local user name */
	if (strlen(hinfo[LOCAL].username))
		XmTextFieldSetString(rconnect.w_userName, hinfo[LOCAL].username);
	else
		XmTextFieldSetString(rconnect.w_userName, "");
}


/*
 * cb_rconnect_single_selection - This callback is invoked when a
 *                                host/user pair is selected.
 */
void
cb_rconnect_single_selection(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
    XmListCallbackStruct *cbs = (XmListCallbackStruct *)call_data;
    XmStringTable selected_items;
    int nselected_items;
    char *text;
	char *host_part;
	char *user_part;

	/* Don't let user deselect item */
    XtVaGetValues(
        rconnect.w_hostList,
        XmNselectedItemCount, &nselected_items,
        XmNselectedItems,     &selected_items,
        NULL
    );
    if (nselected_items == 0) {
        XmListSelectPos(rconnect.w_hostList, cbs->item_position, False);
        XtVaGetValues(
            rconnect.w_hostList,
            XmNselectedItems,     &selected_items,
            NULL
        );
    }

    /* Use selected item to update host and user fields */
	text = cstring_to_text(selected_items[0]);
    if (parse_hostuser(text, &host_part, &user_part) < 0)
        fatal_error("Trouble in cb_rconnect_single_selection()");
    XmTextFieldSetString(rconnect.w_hostName, host_part);
    XmTextFieldSetString(rconnect.w_userName, user_part);
    XtFree(text);
    XtFree(host_part);
    XtFree(user_part);
}


/*
 * cb_rconnect_help - Callback to display help information for the remote
 *                    connection dialog.
 */
void
cb_rconnect_help(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
    help_dialog(widget, True, "Connect to Remote Host", rconnect_help);
}


/*
 * cb_rconnect_def_action - Callback to filter out carriage returns pressed
 *                          in the remote connection dialog's scrolling
 *                          list widget.  This is necessary to avoid invoking
 *                          cb_rconnect_connect() twice (because of the way
 *                          the Prompt Dialog widget works).
 */
void
cb_rconnect_def_action(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
	XmListCallbackStruct *cbs = (XmListCallbackStruct *)call_data;

	/* Reality check */
	if (cbs->reason != XmCR_DEFAULT_ACTION)
		fatal_error("Programming bug in cb_rconnect_def_action()");

	/* Filter out carriage returns */
	if (cbs->event->type != KeyPress)
		cb_rconnect_connect(widget, client_data, call_data);
}


/*
 * cb_rconnect_connect - Callback that uses information in remote connection
 *                       dialog to attempt a control connection to a remote
 *                       FTP server.
 */
void
cb_rconnect_connect(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
	struct dirwin_st *dirwin = (struct dirwin_st *)client_data;
	struct dirwin_st *dwin;
    char *username;
    char *hostname;
    int host;
    int retval;
    int i;
    int len;
    char *host_part;
    int port_part;
	char *msg;
	char *wd;

	/* Get host and user names */
    username = XmTextFieldGetString(rconnect.w_userName);
    hostname = XmTextFieldGetString(rconnect.w_hostName);

    /* Verify that user name is non-null */
    len = strlen(username);
    for (i=0; i<len; i++)
        if (username[i] != ' ')
            break;
    if (i == len) {
        XtFree(username);
		XtFree(hostname);
        warn("Unable to log onto FTP server.  No user name.",
			XtParent(rconnect.w_dialog));
		XtUnmanageChild(rconnect.w_connectButton);
		XtManageChild(rconnect.w_connectButton);
		traverse_to_widget(rconnect.w_userName);
        return;
    }

	/* Verify format of host name / port address */
    switch (parse_hostname(hostname, &host_part, &port_part)) {
    case -1:
        XtFree(hostname);
        XtFree(username);
        warn("Unable to log onto FTP server.  No host name.",
			XtParent(rconnect.w_dialog));
		XtUnmanageChild(rconnect.w_connectButton);
		XtManageChild(rconnect.w_connectButton);
		traverse_to_widget(rconnect.w_hostName);
		return;
    case -2:
        XtFree(hostname);
        XtFree(username);
        warn("Unable to log onto FTP server.  Bad port number.",
			XtParent(rconnect.w_dialog));
		XtUnmanageChild(rconnect.w_connectButton);
		XtManageChild(rconnect.w_connectButton);
		traverse_to_widget(rconnect.w_hostName);
        return;
    case 0:
        XtFree(host_part);
    }

    /* Destroy "Remote Connect" dialog */
	XtUnmanageChild(rconnect.w_dialog);
	XtDestroyWidget(XtParent(rconnect.w_dialog));

    /* Add user name to history */
	add_to_history(USER, hostname, username);

	/* If user is already connected, pop up one of the host's dirwins */
	dwin = dirwin_head;
	while (dwin) {
		if (!strcmp(hinfo[dwin->host].hostname, hostname)
				&& !strcmp(hinfo[dwin->host].username, username)) {
			msg = XtMalloc(strlen(username)+strlen(hostname)+30);
			sprintf(msg, "%s is already connected to %s.", username, hostname);
			info_dialog(msg, dirwin->w_shell);
			XtFree(msg);
			XMapRaised(display, XtWindow(dwin->w_shell));
			XtFree(hostname);
			XtFree(username);
			end_op();
			return;
		}
		dwin = dwin->next;
	}

    /* Set up host structure */
    if ((host = get_host()) == -1) {
        XtFree(hostname);
        XtFree(username);
        warn("Maximum number of hosts exceeded.", dirwin->w_shell);
		end_op();
        return;
    }

	/* Make operation interruptable */
	show_stop_button(dirwin);

    /* Do it */
	hinfo[host].hostname = hostname;
	hinfo[host].username = username;
	hinfo[host].password = NULL;
	hinfo[host].account = NULL;
	hinfo[host].use_proxy = use_proxy;
	if (use_proxy) {
		hinfo[host].proxy_host = XtNewString(proxy_host);
		hinfo[host].proxy_port = proxy_port;
	}
    retval = do_connect(host, dirwin);

    /* Well, are we connected? */
	switch (retval) {
	case -6:
		record_abort("Connect to Remote Host");
	case -2:   /* User bailed out */
		release_host(host);
		hide_stop_button();
		end_op();
		return;
	case -1:
		goto error;
	}

	/* Display one of the host's directories */
	if ((retval = starting_dir(host, &wd)) == -6) {
		record_abort("Connect to Remote Host");
		release_host(host);
		hide_stop_button();
		end_op();
		return;
	} else if (retval < 0)
		goto error;
	retval = display_dir(host, dirwin, wd, False, False, dirwin->cache_mode,
		dirwin->cache_mode);
	XtFree(wd);
	switch (retval) {
	case -6:
		record_abort("Connect to Remote Host");
		release_host(host);
	case 0:
		hide_stop_button();
		end_op();
		return;
	case -3:
	case -1:
		close(hinfo[host].ctrl_fd);
	}
	
error:

	msg = XtMalloc(strlen(hinfo[host].hostname)+30);
	sprintf(msg, "Unable to connect to %s.", hinfo[host].hostname);
	record_and_alert(msg, dirwin->w_shell);
	XtFree(msg);
	release_host(host);
	hide_stop_button();
	end_op();
}


/*
 * cb_rconnect_cancel - Callback to handle Remote Connection "Cancel" button.
 */
void
cb_rconnect_cancel(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
	/* Get rid of Remote Connection Dialog */
	XtDestroyWidget(XtParent(rconnect.w_dialog));

	/* End operation */
	end_op();
}



syntax highlighted by Code2HTML, v. 0.9.1