/***************************************************************************/
/***************************************************************************/
/*                                                                         */
/*   (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 <Xm/TextF.h>
#include <netdb.h>
#include "xdir.h"
#ifdef __osf__
#include <netdnet/dnetdb.h>
#endif
#include "list.h"
#include "str.h"

#define FTPCTRLPORT 21

extern struct st_host_info hinfo[];
extern int diagnostics;
extern struct sl_struct *proxy_domains_list;

char *encrypt_password();
char *decrypt_password();
char *get_password();
char *get_account();
char *system_name();
char *server_name();


/*
 * do_connect - Establish connection to remote host.   Use password
 *              and account fields of hinfo[host] if non-null, otherwise
 *              prompt user for them.  Returns 0 if successful, -2 if
 *              user cancels out from within password dialog, -6 if stop
 *              button pressed, else -1.  "dirwin" is the directory window 
 *              to center auxiliary dialogs on.
 */
do_connect(host, dirwin)
int host;
struct dirwin_st *dirwin;
{
	char *acct = NULL;
	char *passwrd = NULL;
	int i;
	int use;
	int retval;
	int len_hostname;
	int len_domain;
	char *temp;
	char *host_part;
	int port_part;
	char *homedir;
	char *uname;
#ifdef KERBEROS
	int first_time = True;
	int use_kerberos;
#endif

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

	/* Initialize FTP server information */
	hinfo[host].system = SYS_UNIX;
	hinfo[host].server = SERVER_UNKNOWN;

#ifdef KERBEROS
retry:
#endif

	/* Use a proxy server? */
	if (hinfo[host].use_proxy) {
		use = True;
		for (i=0; i<proxy_domains_list->nentries; i++) {
			temp = XtNewString(hinfo[host].hostname);
			cvt_to_lower(temp);
			if (!strcmp(temp, proxy_domains_list->entries[i])) {
				use = False;
				XtFree(temp);
				break;
			}
			len_hostname = strlen(temp);
			len_domain = strlen(proxy_domains_list->entries[i]);
			if (len_hostname > len_domain &&
					temp[len_hostname-len_domain-1] == '.' &&
					!strcmp(&(temp[len_hostname-len_domain]),
					proxy_domains_list->entries[i])) {
				use = False;
				XtFree(temp);
				break;
			}
			XtFree(temp);
		}
	} else
		use = False;

	/* Open connection with FTP server */
	if (use) {
		retval = ftp_open(host, hinfo[host].proxy_host, hinfo[host].proxy_port);
		hinfo[host].system = SYS_UNIX;
		hinfo[host].server = SERVER_UNKNOWN;
	} else {
		if (parse_hostname(hinfo[host].hostname, &host_part, &port_part))
			fatal_error("Bug in do_connect()");
		retval = ftp_open(host, host_part, port_part);
		XtFree(host_part);
	}
	if (retval == -6) {
		restore_prev_cursor();
		return -6;
	} else if (retval < 0) {
		restore_prev_cursor();
		return -1;
	}

	/* Try to login user */
	if (use) {
		uname = XtMalloc(
			strlen(hinfo[host].username)+strlen(hinfo[host].hostname)+2);
		sprintf(uname, "%s@%s", hinfo[host].username, hinfo[host].hostname);
	} else
		uname = XtNewString(hinfo[host].username);
	retval = ftp_user(host, uname);
	XtFree(uname);
	switch (retval) {
	case 0:
		goto logged_on;
	case 1: 
#ifdef KERBEROS
		use_kerberos = False;
#endif
		break;
#ifdef KERBEROS
	case 2:
		if (first_time)
			use_kerberos = True;
		else
			use_kerberos = False;
		first_time = False;
		break;
#endif
	case -6:
		restore_prev_cursor();
		close(hinfo[host].ctrl_fd);
		return -6;
	default:
		restore_prev_cursor();
		close(hinfo[host].ctrl_fd);
		return -1;
	}

	/* Need some sort of authorization */
#ifdef KERBEROS
	if (use_kerberos) {
		switch (ftp_kerberos_ticket(host)) {
		case -6:
			restore_prev_cursor();
			close(hinfo[host].ctrl_fd);
			return -6;
		case 0:
			goto logged_on;
		case 1:
			break;
		default:
			close(hinfo[host].ctrl_fd);
			restore_prev_cursor();
			goto retry;
		}
	} else {
#endif
		if (hinfo[host].password)   /* Use last password */
			passwrd = decrypt_password(hinfo[host].password);
		else {          /* Get password from user */
			hide_stop_button();
			passwrd = get_password(dirwin);
			show_stop_button(dirwin);
			if (passwrd == NULL) {
				close(hinfo[host].ctrl_fd);
				restore_prev_cursor();
				return -2;
			}
		}
		switch (ftp_password(host, passwrd)) {
		case 0:
			goto logged_on;
		case 1:
			break;
		case -6:
			close(hinfo[host].ctrl_fd);
			restore_prev_cursor();
			bzero(passwrd, (int)strlen(passwrd));
			XtFree(passwrd);
			return -6;
		default:
			close(hinfo[host].ctrl_fd);
			restore_prev_cursor();
			bzero(passwrd, (int)strlen(passwrd));
			XtFree(passwrd);
			return -1;
		}
#ifdef KERBEROS
	}
#endif

	/* Account required.  Get it from user */
	if (hinfo[host].account)   /* Use last account */
		acct = XtNewString(hinfo[host].account);
	else {         /* Get account from user */
		hide_stop_button();
		acct = get_account(dirwin);
		show_stop_button(dirwin);
		if (acct == NULL) {
			close(hinfo[host].ctrl_fd);
			restore_prev_cursor();
			bzero(passwrd, (int)strlen(passwrd));
			XtFree(passwrd);
			return -1;
		}
	}

	/* Send account to FTP server */
	if ((retval = ftp_account(host, acct)) < 0) {
		XtFree(acct);
		close(hinfo[host].ctrl_fd);
		restore_prev_cursor();
		bzero(passwrd, (int)strlen(passwrd));
		XtFree(passwrd);
		if (retval == -6)
			return -6;
		else
			return -1;
	}

logged_on:

	/* Try to determine system type.  If failure, assume Unix */
	if (ftp_system(host, False) == -6) {
		close(hinfo[host].ctrl_fd);
		restore_prev_cursor();
		XtFree(acct);
		return -6;
	}
	if (diagnostics == DEBUG) {
		write_log("*** System is ");
		write_log(system_name(hinfo[host].system));
		write_log("\n");
		write_log("*** Server is ");
		write_log(server_name(hinfo[host].server));
		write_log("\n");
	}

	/* Set wait mode of HPSS server to "no wait" */
	if (hinfo[host].server == SERVER_UNIX_HPSS && 
			(retval = set_hpss_wait(host)) < 0) {
		close(hinfo[host].ctrl_fd);
		restore_prev_cursor();
		XtFree(acct);
		if (retval == -6)
			return -6;
		else {
			record_warning("Unable to set HPSS wait mode.");
			return -1;
		}
	}

	/* What is the home directory?  Get actual name */
	if ((retval = remote_pwd(host, &homedir)) < 0) {
		close(hinfo[host].ctrl_fd);
		restore_prev_cursor();
		XtFree(acct);
		if (retval == -6)
			return -6;
		else {
			record_warning("Unable to get home directory.");
			return -1;
		}
	}
	XtFree(hinfo[host].homedir);
	hinfo[host].homedir = homedir;

	/* Success */
	XtFree(hinfo[host].password);
	if (passwrd) {
		hinfo[host].password = encrypt_password(passwrd);
		bzero(passwrd, (int)strlen(passwrd));
		XtFree(passwrd);
	} else
		hinfo[host].password = NULL;
	XtFree(hinfo[host].account);
	hinfo[host].account = acct;
	restore_prev_cursor();
	return 0;
}


/*
 * parse_hostname - Parse "hostname" into its host name and port address
 *                  components.  "hostname" can either consist of a blank-
 *                  delimited host name / port address pair, or just a
 *                  host name.  If the port address part is not given,
 *                  the default control connection port will be used.
 *                  If successful, "host_part" is set to point to a
 *                  string (which the caller can free by calling XtFree()),
 *                  "port_part" is set to the specified port, and a value
 *                  of 0 is returned.  If no host name is given, -1 is
 *                  returned.  If an invalid port designator is given,
 *                  -2 is returned.
 */
parse_hostname(hostname, host_part, port_part)
char *hostname;
char **host_part;
int *port_part;
{
    char *temp;
    char *hp;
    char *pp;
    int port;
    int len;
    int i;

    /* Make copy of hostname */
    temp = XtNewString(hostname);

    /* Get host part */
    if ((hp = strtok(temp, " ")) == NULL) {
        XtFree(temp);
        return -1;
    }

    /* Get port part */
    if ((pp = strtok(NULL, " ")) == NULL)
        port = FTPCTRLPORT;
    else {
        port = 0;
        len = strlen(pp);
        for (i=0; i<len; i++)
            if (pp[i] >= '0' && pp[i] <= '9')
                port = 10*port+(pp[i]-'0');
            else {
                XtFree(temp);
                return -2;
            }
        if (strtok(NULL, " ") != NULL) {
            XtFree(temp);
            return -2;
        }
    }

    /* Everything looks good */
    *host_part = XtNewString(hp);
    XtFree(temp);
    *port_part = port;
    return 0;
}


/*
 * parse_hostuser - Parse the hostname/username pair in "hostuser" to
 *                  "host_part" and "user_part".  Use XtFree() to free
 *                  returned memory.  Returns -1 if either part is null,
 *                  otherwise 0 is returned.
 */
parse_hostuser(hostuser, host_part, user_part)
char *hostuser;
char **host_part;
char **user_part;
{
	int i;
	char *p;
	char *text = XtNewString(hostuser);

	/* Host comes before the first "(" */
    if ((p = strtok(text, "(")) == NULL) {
		XtFree(text);
		return -1;
	}
    for (i=strlen(p)-1; i>=0; i--)
        if (p[i] == ' ')
            p[i] = '\0';
        else
            break;
    if (strlen(p) == 0) {
		XtFree(text);
		return -1;
	}
	*host_part = XtNewString(p);

    /* Get user name.  Spaces must be embedded */
    if ((p = strtok(NULL, "()")) == NULL) {
		XtFree(text);
		XtFree(*host_part);
		return -1;
    }
	while (*p == ' ')
		p++;
    for (i=strlen(p)-1; i>=0; i--)
        if (p[i] == ' ')
            p[i] = '\0';
        else
            break;
    if (strlen(p) == 0) {
		XtFree(text);
		XtFree(*host_part);
		return -1;
	}
	*user_part = XtNewString(p);

	XtFree(text);
	return 0;
}



syntax highlighted by Code2HTML, v. 0.9.1