/***************************************************************************/
/***************************************************************************/
/* */
/* (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 <sys/types.h>
#include <sys/socket.h>
#ifdef HIPPI
#include <netinet/in.h>
#include <netinet/tcp.h>
#endif
#include <unistd.h>
#include <Xm/Xm.h>
#include "xdir.h"
#include "xfer.h"
#include "str.h"
static char *tcpbuf = NULL;
extern struct xfer_ctrl_block xc;
extern int diagnostics;
extern int store_unique;
extern int maxt;
extern int passive_mode;
extern int preserve_vms_ver_nums;
extern struct st_host_info hinfo[];
long extract_file_len();
char *create_unique_name();
/*
* init_get - Initialize transfer of file from remote host to local host.
* "xc" is used for input and output. Returns 0 if successful,
* -3 for lost source connection, -6 for stop button pressed,
* and -1 for other errors.
*/
init_get()
{
char *src_dir;
char *src_file;
char snk_path[MAXPATHLEN+1];
char *tmp_snk_path;
char *q;
int data_fd;
int code;
char reply[MAXFTPREPLY];
int sock;
FILE *fp;
char cmd[MAXPATHLEN+5];
int retval;
long file_len;
int scode;
int errval;
int sys_tcpbuflen = XFER_SYS_TCPBUFLEN;
char *src_path;
#ifdef HIPPI
int winshift = XFER_TCPWINSHIFT;
#endif
/* Get path of sink file */
snk_paths_of_xfer_node(xc.current_node, NULL, &tmp_snk_path);
strcpy(snk_path, tmp_snk_path);
XtFree(tmp_snk_path);
if ((xc.src_host_system == SYS_VMS) &&
(!preserve_vms_ver_nums || (xc.operation == VIEW))) {
if ((q = strrchr(snk_path, ';')))
*q = '\0';
}
/* Get unique file name if requested */
if (store_unique) {
if ((tmp_snk_path = create_unique_name(snk_path)) == NULL)
return -1;
strcpy(snk_path, tmp_snk_path);
}
/* Verify that a writable sink file can be created */
if (!can_create_sinkfile(snk_path))
return -1;
/* "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;
}
/* Initialize data connection */
if (passive_mode) {
if ((data_fd = passive_data_conn(xc.src_dirwin->host)) < 0)
return data_fd;
} else if ((sock = init_data_conn(xc.src_dirwin->host)) < 0) {
XtFree(src_file);
return sock;
}
/* Send RETR command to FTP server */
sprintf(cmd, "RETR %s", src_file);
XtFree(src_file);
if ((retval = send_ftp_cmd(xc.src_dirwin->host, cmd)) == -2) {
report_client_timeout(xc.src_dirwin->host);
errval = -1;
goto error;
} else if (retval < 0) {
errval = retval;
goto error;
}
/* Get initial response from FTP server */
scode = get_ftp_reply(xc.src_dirwin->host, reply, MAXFTPREPLY, &code, maxt);
switch (scode) {
case 1:
file_len = extract_file_len(reply);
break;
case 4:
if (diagnostics < VERBOSE)
report_ftp_reply(xc.src_dirwin->host, reply);
errval = -1;
goto error;
case -6:
abort_ftp_cmd(xc.src_dirwin->host);
case -3:
errval = scode;
goto error;
case -2:
report_client_timeout(xc.src_dirwin->host);
default:
if (scode > 0 && diagnostics < VERBOSE)
report_ftp_reply(xc.src_dirwin->host, reply);
errval = -1;
goto error;
}
/* Establish data connection */
if (!passive_mode) {
data_fd = accept_data_conn(sock);
close(sock);
if (data_fd < 0)
return -1;
}
/* Attempt to increase TCP receive buffer size to improve performance */
#if defined(SOL_SOCKET) && defined(SO_RCVBUF)
setsockopt(data_fd, SOL_SOCKET, SO_RCVBUF, (char *)&sys_tcpbuflen,
sizeof(sys_tcpbuflen));
#endif
/* Optimize tranfer rate for HIPPI channel on UNICOS Cray */
#ifdef HIPPI
setsockopt(data_fd, IPPROTO_TCP, TCP_WINSHIFT, (char *)&winshift,
sizeof(winshift));
#endif
/* Create sink file */
if ((fp = fopen(snk_path, "w")) == NULL) {
report_perror(snk_path);
return abort_get();
}
/* Allocate user TCP buffer (but first perform sanity check) */
if (tcpbuf)
fatal_error("Programming bug in init_get() involving tcpbuf");
tcpbuf = XtMalloc(XFER_USER_TCPBUFLEN);
xc.data_fd = data_fd;
xc.snk_fp = fp;
xc.file_index = 0;
xc.file_len = file_len;
return 0;
error:
if (passive_mode)
close(data_fd);
else
close(sock);
return errval;
}
/*
* do_get - Transfer next part of file from remote host to local 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, -6 for stop button pressed,
* and -1 for other errors.
*/
do_get()
{
char ch;
int nbytes;
int code;
char reply[MAXFTPREPLY];
int len_tcpbuf = 0;
int index_tcpbuf = 0;
int scode;
char *snk_path;
if (xc.mode == ASCII) { /* Receive ASCII file from FTP server */
switch (nbytes = read_tcp(xc.src_dirwin->host, xc.data_fd, tcpbuf,
XFER_USER_TCPBUFLEN, DELTA)) {
case -2:
return 1;
case -1:
case -3:
return abort_get();
case 0:
goto done;
case -6:
abort_get();
return -6;
}
len_tcpbuf = nbytes;
while (index_tcpbuf < len_tcpbuf) {
ch = tcpbuf[index_tcpbuf++];
if (ch == '\r') {
if (index_tcpbuf >= len_tcpbuf) {
do {
nbytes = read_tcp(xc.src_dirwin->host, xc.data_fd,
tcpbuf, 1, DELTA);
} while (nbytes == -2);
switch (nbytes) {
case 1:
index_tcpbuf = 0;
len_tcpbuf = 1;
break;
case 0:
putc('\r', xc.snk_fp);
xc.file_index++;
goto done;
case -6:
abort_get();
return -6;
default:
fclose(xc.snk_fp);
close(xc.data_fd);
return abort_get();
}
}
ch = tcpbuf[index_tcpbuf];
if (ch != '\n') {
putc('\r', xc.snk_fp);
xc.file_index++;
}
} else {
putc(ch, xc.snk_fp);
xc.file_index++;
}
}
} else /* Receive binary file from FTP server */
switch (nbytes = read_tcp(xc.src_dirwin->host, xc.data_fd, tcpbuf,
XFER_USER_TCPBUFLEN, DELTA)) {
case -2:
return 1;
case -1:
case -3:
return abort_get();
case 0:
goto done;
case -6:
abort_get();
return -6;
default:
if (iwrite(fileno(xc.snk_fp), tcpbuf, nbytes) != nbytes) {
snk_paths_of_xfer_node(xc.current_node, NULL, &snk_path);
report_perror(snk_path);
XtFree(snk_path);
return abort_get();
}
xc.file_index += nbytes;
}
return 1;
done:
/* Close sink file */
fclose(xc.snk_fp);
/* Free up user TCP buffer */
XtFree(tcpbuf);
tcpbuf = NULL;
/* Get final response from FTP server */
close(xc.data_fd);
scode = get_ftp_reply(xc.src_dirwin->host, reply, MAXFTPREPLY, &code, maxt);
switch (scode) {
case 2:
return 0;
case -6:
abort_ftp_cmd(xc.src_dirwin->host);
case -3:
return scode;
case -2:
report_client_timeout(xc.src_dirwin->host);
default:
if (scode > 0 && diagnostics < VERBOSE)
report_ftp_reply(xc.src_dirwin->host, reply);
return -1;
}
}
/*
* abort_get - Abort transfer of file from remote host to local host.
* "xc" is used for input and output. Returns -3 for lost
* source connection, -6 for stop button pressed, else -1.
* (If connection is lost and stop button is pressed, -6 is
* returned.)
*/
abort_get()
{
int code;
char reply[MAXFTPREPLY];
int retval;
int stop_was_pressed = False;
int nsecs;
/* Pop up abort dialog */
show_abort_dialog();
/* Close sink file */
fclose(xc.snk_fp);
/* Send urgent abort to server */
if (urgent_abort(xc.src_dirwin->host) == -6)
stop_was_pressed = True;
/* Make sure user TCP buffer is allocated */
if (!tcpbuf)
tcpbuf = XtMalloc(XFER_USER_TCPBUFLEN);
/* Clear out all incoming data */
if ((xc.src_host_server != SERVER_UNIX_UNITREE) &&
(xc.src_host_server != SERVER_UNIX_NSL_UNITREE)) {
while ((retval = read_tcp(xc.src_dirwin->host, xc.data_fd, tcpbuf,
XFER_USER_TCPBUFLEN, 10)) > 0);
if (retval == -6)
stop_was_pressed = True;
}
close(xc.data_fd);
/* Get responses from server */
nsecs = 15;
retval = 1;
while (retval > 0) {
retval = get_ftp_reply(xc.src_dirwin->host, reply, MAXFTPREPLY, &code,
nsecs);
nsecs = 5;
}
if (retval == -6)
stop_was_pressed = True;
/* Free up user TCP buffer */
XtFree(tcpbuf);
tcpbuf = NULL;
/* Want to check for lost host before issuing next command */
hinfo[xc.src_dirwin->host].last_reply_time = 0;
/* Hide abort dialog */
hide_abort_dialog();
/* Determine return value */
if (stop_was_pressed)
return -6;
else if (retval == -3)
return -3;
else if (retval == -2)
report_client_timeout(xc.src_dirwin->host);
return -1;
}
syntax highlighted by Code2HTML, v. 0.9.1