/***************************************************************************/
/***************************************************************************/
/*                                                                         */
/*   (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/Xm.h>
#include "xdir.h"
#include "xfer.h"
#include "str.h"

extern struct xfer_ctrl_block xc;
extern struct st_host_info hinfo[];
extern int diagnostics;
extern int store_unique;
extern int maxt;
extern int preserve_vms_ver_nums;

long extract_file_len();


/*
 * init_remote_copy - Initialize transfer of file from remote host to
 *                    remote host.  "xc" is used for input and
 *                    output.  Returns 0 if successful, -3 for lost
 *                    source connection, -4 for lost sink connection,
 *                    -5 for lost source and sink connections, -6 for
 *                    stop button pressed, and -1 for other errors.
 *                    The transfer will work only if at least one of
 *                    the FTP servers supports the PASV command.
 */
init_remote_copy()
{
	char *src_dir;
	char *src_file;
	char *snk_dir;
	char *snk_file;
	char *port;
	char *q;
	char cmd[MAXPATHLEN+5];
	char reply[MAXFTPREPLY];
	int code;
	int retval;
	int src_scode = 0;
	int snk_scode = 0;
	long file_len;
	int passive_mode_host;
	char *src_path;
	char *snk_path;

    /* "cd" into source directory */
	src_paths_of_xfer_node(xc.current_node, NULL, &src_path);
    parse_path(xc.src_host_system, src_path, &src_dir, &src_file);
	XtFree(src_path);
    retval = remote_cd(xc.src_dirwin->host, src_dir, True);
    XtFree(src_dir);
    switch (retval) {
    case 0:
        break;
    case -3:
	case -6:
        XtFree(src_file);
        return retval;
    default:
        XtFree(src_file);
        return -1;
    }

    /* "cd" into sink directory */
	snk_paths_of_xfer_node(xc.current_node, NULL, &snk_path);
    parse_path(xc.snk_host_system, snk_path, &snk_dir, &snk_file);
	XtFree(snk_path);
	if ((xc.src_host_system == SYS_VMS) && !preserve_vms_ver_nums) {
		if ((q = strrchr(snk_file, ';')))
			*q = '\0';
	}
    retval = remote_cd(xc.snk_dirwin->host, snk_dir, True);
    XtFree(snk_dir);
    switch (retval) {
    case 0:
        break;
    case -3:
		XtFree(src_file);
        XtFree(snk_file);
        return -4;
	case -6:
		XtFree(src_file);
		XtFree(snk_file);
		return -6;
    default:
		XtFree(src_file);
        XtFree(snk_file);
        return -1;
    }

	/* Try to put either sink or source host into passive mode */
	if ((hinfo[xc.snk_dirwin->host].server != SERVER_UNIX_UNITREE) &&
			(hinfo[xc.snk_dirwin->host].server != SERVER_UNIX_NSL_UNITREE) &&
			(hinfo[xc.src_dirwin->host].server != SERVER_NT) &&
			(retval = ftp_passive(xc.snk_dirwin->host, &port)) == 0) {
		passive_mode_host = xc.snk_dirwin->host;
		if ((retval = ftp_port(xc.src_dirwin->host, port)) < 0) {
			XtFree(src_file);
			XtFree(snk_file);
			XtFree(port);
			switch (retval) {
			case -6:
				abort_rcopy(False, True);
				return -6;
			case -2:
				report_client_timeout(xc.src_dirwin->host);
			case -1:
				return abort_rcopy(False, True);
			case -3:
				switch (abort_rcopy(False, True)) {
				case -6:
					return -6;
				case -3:
					return -5;
				default:
					return -3;
				}
			}
		}
	} else if (retval == -6) {
		XtFree(src_file);
		XtFree(src_file);
		return -6;
	} else if ((hinfo[xc.snk_dirwin->host].server != SERVER_UNIX_UNITREE) &&
			(hinfo[xc.snk_dirwin->host].server != SERVER_UNIX_NSL_UNITREE) &&
			(retval == -3)) {
		XtFree(src_file);
		XtFree(snk_file);
		return -4;
	} else if ((retval = ftp_passive(xc.src_dirwin->host, &port)) == 0) {
		passive_mode_host = xc.src_dirwin->host;
		if ((retval = ftp_port(xc.snk_dirwin->host, port)) < 0) {
			XtFree(src_file);
			XtFree(snk_file);
			XtFree(port);
			switch (retval) {
			case -6:
				abort_rcopy(True, False);
				return -6;
			case -2:
				report_client_timeout(xc.snk_dirwin->host, port);
			case -1:
				return abort_rcopy(True, False);
			case -3:
				switch (abort_rcopy(True, False)) {
				case -6:
					return -6;
				case -3:
					return -5;
				default:
					return -4;
				}
			}
		}
	} else {
		XtFree(src_file);
		XtFree(snk_file);
		return retval;
	}
	XtFree(port);

	if (passive_mode_host == xc.src_dirwin->host) {

	    /* Send STOR command to sink FTP server */
		if (store_unique)
			sprintf(cmd, "STOU %s", snk_file);
		else
   		 	sprintf(cmd, "STOR %s", snk_file);
		XtFree(snk_file);
		switch (send_ftp_cmd(xc.snk_dirwin->host, cmd)) {
		case -6:
			XtFree(src_file);
			abort_rcopy(True, False);
			return -6;
		case -2:
			report_client_timeout(xc.snk_dirwin->host);
		case -1:
			XtFree(src_file);
			return abort_rcopy(True, False);
		case -3:
			XtFree(src_file);
			switch (abort_rcopy(True, False)) {
			case -6:
				return -6;
			case -3:
				return -5;
			default:
				return -4;
			}
		}

    	/* Get STOR reply from sink FTP server */
		snk_scode = get_ftp_reply(xc.snk_dirwin->host, reply, MAXFTPREPLY,
			&code, maxt);
		switch (snk_scode) {
		case -6:
			XtFree(src_file);
			abort_rcopy(True, True);
			return -6;
		case -3:
			XtFree(src_file);
			switch (abort_rcopy(True, False)) {
			case -3:
				return -5;
			case -6:
				return -6;
			default:
				return -4;
			}
		case 1:
			break;
		case -2:
			report_client_timeout(xc.snk_dirwin->host);
		default:
			if (snk_scode > 0 && diagnostics < VERBOSE)
				report_ftp_reply(xc.snk_dirwin->host, reply);
			XtFree(src_file);
			return abort_rcopy(True, False);
		}

    	/* Send RETR command to source FTP server */
    	sprintf(cmd, "RETR %s", src_file);
		XtFree(src_file);
		switch (send_ftp_cmd(xc.src_dirwin->host, cmd)) {
		case -6:
			abort_rcopy(True, True);
			return -6;
		case -2:
			report_client_timeout(xc.src_dirwin->host);
		case -1:
			return abort_rcopy(True, True);
		case -3:
			switch (abort_rcopy(False, True)) {
			case -6:
				return -6;
			case -4:
				return -5;
			default:
				return -3;
			}
		}

    	/* Get RETR reply from source FTP server */
		src_scode = get_ftp_reply(xc.src_dirwin->host, reply, MAXFTPREPLY,
			&code, maxt);
		switch (src_scode) {
		case -6:
			abort_rcopy(True, True);
			return -6;
		case -3:
			switch (abort_rcopy(False, True)) {
			case -6:
				return -6;
			case -4:
				return -5;
			default:
				return -3;
			}
		case 1:
			file_len = extract_file_len(reply);
			xc.substate = 0;  /* Need to wait for file source response */
			xc.file_index = -1;
			xc.file_len = file_len;
			return 0;
		case -2:
			report_client_timeout(xc.src_dirwin->host);
		default:
			if (src_scode > 0 && diagnostics < VERBOSE)
				report_ftp_reply(xc.src_dirwin->host, reply);
			return abort_rcopy(True, True);
		}

	} else {     /* Sink host is in passive mode */

    	/* Send RETR command to source FTP server */
    	sprintf(cmd, "RETR %s", src_file);
		XtFree(src_file);
		switch (send_ftp_cmd(xc.src_dirwin->host, cmd)) {
		case -6:
			XtFree(snk_file);
			abort_rcopy(True, True);
			return -6;
		case -3:
			XtFree(snk_file);
			switch (abort_rcopy(False, True)) {
			case -6:
				return -6;
			case -4:
				return -5;
			default:
				return -3;
			}
		case -2:
			report_client_timeout(xc.src_dirwin->host);
		case -1:
			XtFree(snk_file);
			return abort_rcopy(False, True);
		}

    	/* Get RETR reply from source FTP server */
		src_scode = get_ftp_reply(xc.src_dirwin->host, reply, MAXFTPREPLY,
			&code, maxt);
		switch (src_scode) {
		case -6:
			XtFree(snk_file);
			abort_rcopy(True, True);
			return -6;
		case -3:
			XtFree(snk_file);
			switch (abort_rcopy(False, True)) {
			case -4:
				return -5;
			case -6:
				return -6;
			default:
				return -3;
			}
		case 1:
			file_len = extract_file_len(reply);
			break;
		case -2:
			report_client_timeout(xc.src_dirwin->host);
		default:
			if (src_scode > 0 && diagnostics < VERBOSE)
				report_ftp_reply(xc.src_dirwin->host, reply);
			XtFree(snk_file);
			return abort_rcopy(False, True);
		}

	    /* Send STOR command to sink FTP server */
		if (store_unique)
			sprintf(cmd, "STOU %s", snk_file);
		else
   		 	sprintf(cmd, "STOR %s", snk_file);
		XtFree(snk_file);
		switch (send_ftp_cmd(xc.snk_dirwin->host, cmd)) {
		case -6:
			abort_rcopy(True, True);
			return -6;
		case -2:
			report_client_timeout(xc.snk_dirwin->host);
		case -1:
			return abort_rcopy(True, True);
		case -3:
			switch (abort_rcopy(True, False)) {
			case -6:
				return -6;
			case -3:
				return -5;
			default:
				return -4;
			}
		}

    	/* Get STOR reply from sink FTP server */
		snk_scode = get_ftp_reply(xc.snk_dirwin->host, reply, MAXFTPREPLY,
			&code, maxt);
		switch (snk_scode) {
		case -6:
			abort_rcopy(True, True);
			return -6;
		case -3:
			switch (abort_rcopy(True, False)) {
			case -6:
				return -6;
			case -3:
				return -5;
			default:
				return -4;
			}
		case 1:
			xc.substate = 0;  /* Need to wait for file source response */
			xc.file_index = -1;
			xc.file_len = file_len;
			return 0;
		case -2:
			report_client_timeout(xc.snk_dirwin->host);
		default:
			if (snk_scode > 0 && diagnostics < VERBOSE)
				report_ftp_reply(xc.snk_dirwin->host, reply);
			return abort_rcopy(True, False);
		}

	}
}


/*
 * do_remote_copy - Transfer next part of file from remote host to remote
 *                  host.  "xc" is used for input and output.
 *                  Returns 0 if file transfer complete, 1 if file
 *                  transfer not complete, -3 for lost source connection,
 *                  -4 for lost sink connection, -5 for lost source and
 *                  sink connections, -7 for a "552" reply (for UniTree
 *                  retry mechanism), -6 for stop button pressed, and -1
 *                  for other errors.
 */
do_remote_copy()
{
	char reply[MAXFTPREPLY];
	int code;
	int scode;

    /* Get final response from source FTP server */
	if (xc.substate == 0) {
		scode = get_ftp_reply(xc.src_dirwin->host, reply, MAXFTPREPLY, &code,
			DELTA);
		switch (scode) {
		case -6:
			abort_rcopy(True, True);
			return -6;
		case -3:
			switch (abort_rcopy(False, True)) {
			case -6:
				return -6;
			case -4:
				return -5;
			default:
				return -3;
			}
		case -2:
			return 1;
		case 2:
			xc.substate = 1;
			break;
		default:
			if (scode > 0 && diagnostics < VERBOSE)
				report_ftp_reply(xc.src_dirwin->host, reply);
			return abort_rcopy(False, True);
		}
	}

    /* Get final response from sink FTP server */
	scode = get_ftp_reply(xc.snk_dirwin->host, reply, MAXFTPREPLY, &code,
		DELTA);
	switch (scode) {
	case -6:
		abort_rcopy(False, True);
		return -6;
	case -3:
		return -4;
	case -2:
		return 1;
	case 2:
		return 0;
	default:
		if (scode > 0 && diagnostics < VERBOSE)
			report_ftp_reply(xc.snk_dirwin->host, reply);
		if (code == 552)        /* UniTree retry logic */
			return -7;
		else
			return -1;
	}
}


/*
 * abort_remote_copy - Abort transfer of file from remote host to remote
 *                     host.  "xc" is used for input and output.
 */
void
abort_remote_copy()
{
	abort_rcopy(True, True);
}


/*
 * abort_rcopy - Abort transfer of file from remote host to remote host.
 *               "abort_src" specifies whether to send abort request to
 *               source host.  "abort_snk" specifies whether to send
 *               abort request to sink host.  "xc" is used for
 *               all other input and output.  Returns -3 for lost source
 *               connection, -4 for lost sink connection, -5 for lost
 *               source and sink connections, -6 for stop button pressed,
 *               else -1.
 */
abort_rcopy(abort_src, abort_snk)
int abort_src;
int abort_snk;
{
	char reply[MAXFTPREPLY];
	int code;
	int src_scode = 0;
	int snk_scode = 0;
	int stop_was_pressed = False;
	int retval;

	/* Pop up abort dialog */
	show_abort_dialog();

	/* Is the source FTP server already done? */
	if (abort_src) {
		src_scode = get_ftp_reply(xc.src_dirwin->host, reply, MAXFTPREPLY,
			&code, 5);
		switch (src_scode) {
		case -6:
			stop_was_pressed = True;
			break;
		case 2:
		case 4:
		case 5:
			abort_src = False;
			src_scode = 0;
			break;
		case -3:
			abort_src = False;
		}
	}

	/* Is the sink FTP server already done? */
	if (abort_snk) {
		snk_scode = get_ftp_reply(xc.snk_dirwin->host, reply, MAXFTPREPLY,
			&code, 5);
		switch (snk_scode) {
		case -6:
			stop_was_pressed = True;
			break;
		case 2:
		case 4:
		case 5:
			abort_snk = False;
			snk_scode = 0;
			break;
		case -3:
			abort_snk = False;
		}
	}

	/* Send abort request to source FTP server */
	if (abort_src)
		if (urgent_abort(xc.src_dirwin->host) == -6)
			stop_was_pressed = True;

	/* Send abort request to sink FTP server */
	if (abort_snk)
		if (urgent_abort(xc.snk_dirwin->host) == -6)
			stop_was_pressed = True;

	/* Get responses from source FTP server */
	if (abort_src) {
    	src_scode = get_ftp_reply(xc.src_dirwin->host, reply, MAXFTPREPLY,
			&code, 15);
		if (src_scode == -6) {
			stop_was_pressed = True;
			src_scode = get_ftp_reply(xc.src_dirwin->host, reply, MAXFTPREPLY,
				&code, 15);
		}
		if (src_scode == 2) {
			retval = get_ftp_reply(xc.src_dirwin->host, reply, MAXFTPREPLY,
				&code, 5);
			if (retval == -6) {
				stop_was_pressed = True;
				get_ftp_reply(xc.src_dirwin->host, reply, MAXFTPREPLY, &code,
					5);
			}
    	} else if (src_scode > 0) {
        	src_scode = get_ftp_reply(xc.src_dirwin->host, reply, MAXFTPREPLY,
				&code, 15);
			if (src_scode == -6) {
				stop_was_pressed = True;
				src_scode = get_ftp_reply(xc.src_dirwin->host, reply,
					MAXFTPREPLY, &code, 15);
			}
		}
		if (src_scode == -2) {
			report_client_timeout(xc.src_dirwin->host);
			src_scode = -3;
		}
	}

	/* Get responses from sink FTP server */
	if (abort_snk) {
    	snk_scode = get_ftp_reply(xc.snk_dirwin->host, reply, MAXFTPREPLY,
			&code, 15);
		if (snk_scode == -6) {
			stop_was_pressed = True;
			snk_scode = get_ftp_reply(xc.snk_dirwin->host, reply, MAXFTPREPLY,
				&code, 15);
		}
		if (snk_scode == 2) {
			retval = get_ftp_reply(xc.snk_dirwin->host, reply, MAXFTPREPLY,
				&code, 5);
			if (retval == -6) {
				stop_was_pressed = True;
				get_ftp_reply(xc.snk_dirwin->host, reply, MAXFTPREPLY, &code,
					5);
			}
    	} else if (snk_scode > 0) {
       		snk_scode = get_ftp_reply(xc.snk_dirwin->host, reply, MAXFTPREPLY,
				&code, 15);
			if (snk_scode == -6) {
				stop_was_pressed = True;
				snk_scode = get_ftp_reply(xc.snk_dirwin->host, reply,
					MAXFTPREPLY, &code, 15);
			}
		}
		if (snk_scode == -2) {
			report_client_timeout(xc.snk_dirwin->host);
			snk_scode = -3;
		}
	}

	/* Want to check for lost host before issuing next command */
	hinfo[xc.src_dirwin->host].last_reply_time = 0;
	hinfo[xc.snk_dirwin->host].last_reply_time = 0;

	/* Hide abort dialog */
	hide_abort_dialog();

	/* Return appropriate error value */
	if (stop_was_pressed)
		return -6;
	if (src_scode == -3 && snk_scode == -3)
		return -5;
	else if (src_scode == -3)
		return -3;
	else if (snk_scode == -3)
		return -4;
	else
		return -1;
}



syntax highlighted by Code2HTML, v. 0.9.1