#include "ftptool.h"
#pragma ident "@(#)transfer.c 1.6 94/07/14"
#ifdef USE_PROTOTYPES
int get_file(char *name, char *localname, int size)
#else
int get_file(name, localname, size)
char *name;
char *localname;
int size;
#endif
{
char *ftperr;
int rval, answer;
footer_message("Receiving %s...", name);
if (abort_transfer) {
return (EINTR);
}
if (!batch_mode && confirmoverwrites && (access(localname,
F_OK) == 0)) {
#ifdef XVIEW3
Xv_notice notice;
notice = xv_create(base_window.panel, NOTICE,
NOTICE_MESSAGE_STRINGS,
localname,
"already exists. Do you want to overwrite it?",
NULL,
NOTICE_BUTTON_YES, "Yes, overwrite it.",
NOTICE_BUTTON, "No, stop the transfer.", 2,
NOTICE_STATUS, &answer,
XV_SHOW, TRUE,
NULL);
xv_destroy_safe(notice);
#else
answer = notice_prompt(base_window.panel, NULL,
NOTICE_MESSAGE_STRINGS,
localname,
"already exists. Do you want to overwrite it?",
NULL,
NOTICE_BUTTON_YES, "Yes, overwrite it.",
NOTICE_BUTTON, "No, stop the transfer.", 2,
NULL);
#endif
if (answer != NOTICE_YES) {
footer_message("");
return (EINTR);
}
}
xv_set(base_window.abort,
PANEL_INACTIVE, FALSE,
NULL);
settype((int)xv_get(host_window.advanced.transfer_mode, PANEL_VALUE));
rval = recvrequest("RETR", localname, name, "w", size);
switch (rval) {
case 1:
/* non_fatal error */
ftperr = index(response_line, ':');
if (ftperr != NULL) {
ftperr++;
if (!strncmp(ftperr, "Permission", 10))
rval = EPERM;
else if (!strncmp(ftperr, "not a plain file", 16))
rval = EISDIR;
else
rval = 0;
} else
rval = 0;
break;
case 2:
rval = EIO;
break;
default:
break;
}
return (rval);
}
#ifdef USE_PROTOTYPES
int put_file(char *name, char *remote_name, int size)
#else
int put_file(name, remote_name, size)
char *name;
char *remote_name;
int size;
#endif
{
char *ftperr;
int rval;
local_footer_message("Sending %s...", name);
if (abort_transfer) {
return (EINTR);
}
xv_set(base_window.abort,
PANEL_INACTIVE, FALSE,
NULL);
settype((int)xv_get(host_window.advanced.transfer_mode, PANEL_VALUE));
/* if unique, then use STOU */
if (unique_remote_names)
rval = sendrequest("STOU", name, remote_name, size);
else
rval = sendrequest("STOR", name, remote_name, size);
switch (rval) {
case 1:
/* non_fatal error */
ftperr = index(response_line, ':');
if (ftperr != NULL) {
ftperr++;
if (!strncmp(ftperr, "Permission", 10))
rval = EPERM;
else
rval = 0;
} else
rval = 0;
break;
case 2:
rval = EIO;
break;
default:
break;
}
return (rval);
}
#ifdef USE_PROTOTYPES
int get_dir(char *parent_remote_dir, char *parent_local_dir,
char *name, char *localname)
#else
int get_dir(parent_remote_dir, parent_local_dir, name, localname)
char *parent_remote_dir;
char *parent_local_dir;
char *name;
char *localname;
#endif
{
int rval = 0;
extern int errno;
struct dirlist *head = NULL;
struct dirlist *tmp;
char *ftperr;
char *rdir = NULL;
char *ldir = NULL;
char *lname = NULL;
/* transfer a remote directory and its contents to the local machine */
/* First, make a directory */
if ((rval = make_dirs(localname, 1)) != 0) {
if (rval != EEXIST) {
/* XXX - this message is clobbered by 'done reading' */
/* message */
return (errno);
}
}
/* cd to that dir */
command("CWD %s", name);
if (code != 250) {
sprintf(scratch, "Remote cd to %s failed.", name);
ftperr = ftp_error(' ', scratch);
footer_message(ftperr);
return (1);
}
/* local cd */
if (chdir(localname) == -1) {
/* go back up */
footer_message("Local cd to %s failed.", localname);
(void) command("CWD %s", parent_remote_dir);
return (errno);
}
head = read_remote_dir();
if (head == NULL)
goto out;
/* do files first */
for (tmp = head->next; tmp != NULL; tmp = tmp->next) {
if (S_ISREG(tmp->mode)) {
if ((rval = get_file(tmp->name, tmp->name,
tmp->size)) != 0)
goto out;
}
}
rdir = make_path(parent_remote_dir, name);
if (rdir == NULL)
goto out;
ldir = make_path(parent_local_dir, localname);
if (ldir == NULL)
goto out;
/* recursively do directories */
for (tmp = head->next; tmp != NULL; tmp = tmp->next) {
if (!S_ISDIR(tmp->mode))
continue;
if ((rval = get_dir(rdir, ldir, tmp->name, tmp->name)) != 0)
goto out;
}
/* try symlinks */
for (tmp = head->next; tmp != NULL; tmp = tmp->next) {
if (!S_ISLNK(tmp->mode))
continue;
lname = linkname(tmp->name);
if (lname == NULL)
goto out;
rval = get_file(lname, lname, -1);
if (rval == EISDIR) {
/* try as a directory */
if ((rval = get_dir(rdir, ldir, lname, lname)) > 1) {
/*
if (rval == EEXIST) {
}
*/
goto out;
}
} else if (rval != 0) {
goto out;
}
free(lname);
lname = NULL;
}
out:
if (head)
free_dirlist(head);
if (rdir)
free(rdir);
if (ldir)
free(ldir);
/* go back up */
(void) command("CWD %s", parent_remote_dir);
chdir(parent_local_dir);
return (rval);
}
#ifdef USE_PROTOTYPES
int put_dir(char *parent_remote_dir, char *parent_local_dir,
char *name, char *localname)
#else
int put_dir(parent_remote_dir, parent_local_dir, name, localname)
char *parent_remote_dir;
char *parent_local_dir;
char *name;
char *localname;
#endif
{
extern int errno;
int rval = 0;
struct dirlist *head = NULL;
struct dirlist *tmp;
char *ftperr;
char *rdir = NULL;
char *ldir = NULL;
char *lname = NULL;
/* transfer a local directory and its contents to the remote machine */
/* First, make a directory */
if (make_remote_dirs(name, 1)) {
/* XXX - error? */
/*
goto out;
*/
}
/* cd to that dir */
if (command("CWD %s", name) == ERROR && code == 250) {
sprintf(scratch, "Remote cd to %s failed.", name);
ftperr = ftp_error(' ', scratch);
local_footer_message(ftperr);
return (1);
}
/* local cd */
if (chdir(localname) == -1) {
local_footer_message("Local cd to %s failed.", localname);
/* go back up */
(void) command("CWD %s", parent_remote_dir);
return (errno);
}
head = read_local_dir(".");
if (head == NULL) {
rval = ENOMEM;
goto out;
}
/* do files first */
for (tmp = head->next; tmp != NULL; tmp = tmp->next) {
if (!S_ISREG(tmp->mode))
continue;
if ((rval = put_file(tmp->name, tmp->name, tmp->size)) != 0)
goto out;
}
rdir = make_path(parent_remote_dir, name);
if (rdir == NULL)
goto out;
ldir = make_path(parent_local_dir, localname);
if (ldir == NULL)
goto out;
/* recursively do directories */
for (tmp = head->next; tmp != NULL; tmp = tmp->next) {
if (!S_ISDIR(tmp->mode))
continue;
if ((rval = put_dir(rdir, ldir, tmp->name, tmp->name)) != 0)
goto out;
}
/* try symlinks */
for (tmp = head->next; tmp != NULL; tmp = tmp->next) {
if (!S_ISLNK(tmp->mode))
continue;
lname = linkname(tmp->name);
if (lname == NULL)
goto out;
rval = put_file(lname, lname, -1);
if (rval == EPERM) {
/* try as a directory */
if ((rval = put_dir(rdir, ldir, lname, lname)) > 1) {
/*
if (rval == EEXIST) {
}
*/
goto out;
}
} else if (rval != 0) {
goto out;
}
free(lname);
lname = NULL;
}
out:
if (head)
free_dirlist(head);
if (rdir)
free(rdir);
if (ldir)
free(ldir);
/* go back up */
(void) command("CWD %s", parent_remote_dir);
chdir(parent_local_dir);
return (rval);
}
#ifdef USE_PROTOTYPES
char *make_path(char *parent, char *curdir)
#else
char *make_path(parent, curdir)
char *parent;
char *curdir;
#endif
{
char *tmp;
if (*curdir == '/') {
tmp = (char *)strdup(curdir);
} else {
tmp = (char *)malloc((unsigned int)(strlen(parent) + 1 +
strlen(curdir) + 1));
if (tmp == NULL)
return (NULL);
strcpy(tmp, parent);
if (strcmp(parent, "/"))
strcat(tmp, "/");
strcat(tmp, curdir);
}
return (tmp);
}
#define FILE_PERCENT 5.0
#define TOTAL_PERCENT 5.0
static double last_percent;
static double last_total_percent;
static int total_so_far;
static int total_transfer_size;
static struct timeval start;
#ifdef USE_PROTOTYPES
void init_status(int total)
#else
void init_status(total)
int total;
#endif
{
int gettimeofday();
total_so_far = 0;
total_transfer_size = total;
last_total_percent = 0;
xv_set(status_window.total_gauge,
PANEL_INACTIVE, FALSE,
PANEL_VALUE, 0,
NULL);
(void) gettimeofday(&start, (struct timezone *)NULL);
status_footer_message("Total transfer size: %d bytes.",
total_transfer_size);
}
#ifdef USE_PROTOTYPES
void end_status(void)
#else
void end_status()
#endif
{
struct timeval stop;
double total_time;
double rate;
char *unit;
int gettimeofday();
(void) gettimeofday(&stop, (struct timezone *)NULL);
xv_set(status_window.total_gauge,
PANEL_INACTIVE, FALSE,
PANEL_VALUE, 0,
NULL);
total_time = (stop.tv_sec + stop.tv_usec/1000000.0)
- (start.tv_sec + start.tv_usec/1000000.0);
rate = (double)total_so_far/total_time;
if (rate >= 1048576.0) {
unit = "Mbyte";
rate /= 1048576.0;
} else if (rate >= 1024.0) {
unit = "Kbyte";
rate /= 1024.0;
} else
unit = "byte";
sprintf(scratch, "%.2f seconds, %.2f %ss/second", total_time,
rate, unit);
status_footer_message(scratch);
(void) strcat(scratch, "\n");
log_message(scratch);
}
#ifdef USE_PROTOTYPES
void update_status_label(char *direction, char *name, int size)
#else
void update_status_label(direction, name, size)
char *direction;
char *name;
int size;
#endif
{
static char sizestr[40];
static char string[MAXPATHLEN + 30];
Rect *butrect;
sprintf(string, "%s %s", direction, name);
xv_set(status_window.message,
PANEL_LABEL_STRING, string,
NULL);
if (size >= 0) {
sprintf(sizestr, "%d bytes", size);
xv_set(status_window.size,
PANEL_LABEL_STRING, sizestr,
NULL);
last_percent = 0;
xv_set(status_window.total_gauge,
PANEL_INACTIVE, FALSE,
NULL);
} else {
xv_set(status_window.size,
PANEL_LABEL_STRING, "Symbolic links not counted.",
NULL);
xv_set(status_window.total_gauge,
PANEL_INACTIVE, TRUE,
NULL);
}
butrect = (Rect *)xv_get(status_window.dismiss, XV_RECT);
xv_set(status_window.dismiss,
XV_X, xv_get(status_window.panel, XV_WIDTH) / 2
- butrect->r_width / 2,
NULL);
}
#ifdef USE_PROTOTYPES
void update_status_gauge(long bytes)
#else
void update_status_gauge(bytes)
long bytes;
#endif
{
double percent;
if (bytes <= 0) /* shouldn't happen */
return;
total_so_far += bytes;
if (total_so_far > total_transfer_size)
total_so_far = total_transfer_size;
if (total_transfer_size > 0.0)
percent = (double)total_so_far / (double)total_transfer_size *
100.0;
else
percent = 0.0;
if (percent < 0.0)
percent = 0.0;
if (percent > 100.0)
percent = 100.0;
if (percent >= (last_total_percent + TOTAL_PERCENT)) {
while ((last_total_percent + TOTAL_PERCENT) < percent)
last_total_percent += TOTAL_PERCENT;
xv_set(status_window.total_gauge,
PANEL_VALUE, (int)last_total_percent,
NULL);
}
}
#ifdef USE_PROTOTYPES
int sum_local_dir(char *parent, char *dir)
#else
int sum_local_dir(parent, dir)
char *parent, *dir;
#endif
{
int total = 0;
char *ldir = NULL;
struct dirlist *head = NULL;
struct dirlist *tmp;
ldir = make_path(parent, dir);
if (ldir == NULL)
return (0);
if (chdir(ldir) == -1) {
status_footer_message("Could not change to directory: %s",
sys_errlist[errno]);
goto out;
}
head = read_local_dir(".");
if (head == NULL) {
goto out;
}
/* do files first */
for (tmp = head->next; tmp != NULL; tmp = tmp->next) {
switch (tmp->mode & S_IFMT) {
case S_IFREG:
total += tmp->size;
break;
case S_IFDIR:
total += sum_local_dir(ldir, tmp->name);
break;
default:
break;
}
}
if (chdir(parent) == -1) {
status_footer_message("Could not change to parent: %s",
sys_errlist[errno]);
}
out:
if (ldir)
free(ldir);
if (head)
free_dirlist(head);
return (total);
}
/*
* Called to sum all the sizes from the currently selected local items.
*/
#ifdef USE_PROTOTYPES
int sum_local_size(void)
#else
int sum_local_size()
#endif
{
int nitems;
int row;
int total = 0;
struct dirlist *tmp;
status_footer_message("Determining send total...");
/* loop over each selected element, and do a get, then unselect */
nitems = xv_get(local_window.list, PANEL_LIST_NROWS);
for (row = 0; row < nitems; row++)
if (xv_get(local_window.list, PANEL_LIST_SELECTED, row)) {
tmp = (struct dirlist *)xv_get(local_window.list,
PANEL_LIST_CLIENT_DATA, row);
switch (tmp->mode & S_IFMT) {
case S_IFDIR:
total +=
sum_local_dir(local_dircache.first->name,
tmp->name);
break;
case S_IFREG:
total += tmp->size;
break;
case S_IFLNK:
status_footer_message(
"Ignoring symlink %s...", tmp->name);
log_message(
"Can only sum sizes of files and directories.\n");
break;
default:
status_footer_message(
"Ignoring non-file/directory %s.",
tmp->name);
log_message(
"Can only transfer files and directories.\n");
break;
}
}
return (total);
}
#ifdef USE_PROTOTYPES
int sum_remote_dir(char *parent, char *dir)
#else
int sum_remote_dir(parent, dir)
char *parent, *dir;
#endif
{
int total = 0;
char *rdir = NULL;
struct dirlist *head = NULL;
struct dirlist *tmp;
if (!strcmp(dir, ".."))
return (0);
rdir = make_path(parent, dir);
if (rdir == NULL)
return (0);
code = -1;
command("CWD %s", rdir);
if (code == 550) {
goto out;
}
head = read_remote_dir();
if (head == NULL) {
goto out;
}
for (tmp = head->next; tmp != NULL; tmp = tmp->next) {
switch (tmp->mode & S_IFMT) {
case S_IFREG:
if (tmp->size != -1)
total += tmp->size;
else
status_footer_message(
"Size of %s not available", tmp->name);
break;
case S_IFDIR:
total += sum_remote_dir(rdir, tmp->name);
break;
default:
break;
}
}
(void) command("CWD %s", parent);
out:
if (rdir)
free(rdir);
if (head)
free_dirlist(head);
return (total);
}
/*
* Called to sum all the sizes from the currently selected local items.
*/
#ifdef USE_PROTOTYPES
int sum_remote_size(void)
#else
int sum_remote_size()
#endif
{
int nitems;
int row;
int total = 0;
struct dirlist *tmp;
int mode;
status_footer_message("Determining receive total...");
/* loop over each selected element, and do a get, then unselect */
nitems = xv_get(base_window.list, PANEL_LIST_NROWS);
for (row = 0; row < nitems; row++)
if (xv_get(base_window.list, PANEL_LIST_SELECTED, row)) {
tmp = (struct dirlist *)xv_get(base_window.list,
PANEL_LIST_CLIENT_DATA, row);
mode = tmp->mode & S_IFMT;
if (non_unix)
mode = S_IFREG;
switch (mode) {
case S_IFDIR:
total +=
sum_remote_dir(remote_dircache.first->name,
tmp->name);
break;
case S_IFREG:
if (tmp->size != -1)
total += tmp->size;
else
status_footer_message(
"Size of %s not available",
tmp->name);
break;
case S_IFLNK:
status_footer_message(
"Ignoring symlink %s...", tmp->name);
log_message(
"Can only sum sizes of files and directories.\n");
break;
default:
status_footer_message(
"Ignoring non-file/directory %s.",
tmp->name);
log_message(
"Can only transfer files and directories.\n");
break;
}
}
return (total);
}
#ifdef USE_PROTOTYPES
int sum_remote_batch_size(void)
#else
int sum_remote_batch_size()
#endif
{
int nitems;
int row;
int total = 0;
struct batchlist *tmp;
int mode;
status_footer_message("Determining receive total...");
/* loop over each selected element, and do a get, then unselect */
nitems = xv_get(schedule_window.receive_list, PANEL_LIST_NROWS);
for (row = 0; row < nitems; row++) {
tmp = (struct batchlist *)xv_get(schedule_window.receive_list,
PANEL_LIST_CLIENT_DATA, row);
mode = tmp->mode & S_IFMT;
if (non_unix)
mode = S_IFREG;
switch (mode) {
case S_IFDIR:
total += sum_remote_dir(remote_dircache.first->name,
tmp->name);
break;
case S_IFREG:
if (tmp->size != -1)
total += tmp->size;
else
status_footer_message(
"Size of %s not available", tmp->name);
break;
case S_IFLNK:
status_footer_message(
"Ignoring symlink %s...", tmp->name);
log_message(
"Can only sum sizes of files and directories.\n");
break;
default:
status_footer_message(
"Ignoring non-file/directory %s.", tmp->name);
log_message(
"Can only transfer files and directories.\n");
break;
}
}
return (total);
}
#ifdef USE_PROTOTYPES
int sum_local_batch_size(void)
#else
int sum_local_batch_size()
#endif
{
int nitems;
int row;
int total = 0;
struct batchlist *tmp;
status_footer_message("Determining send total...");
/* loop over each selected element, and do a get, then unselect */
nitems = xv_get(schedule_window.send_list, PANEL_LIST_NROWS);
for (row = 0; row < nitems; row++) {
tmp = (struct batchlist *)xv_get(schedule_window.send_list,
PANEL_LIST_CLIENT_DATA, row);
switch (tmp->mode & S_IFMT) {
case S_IFDIR:
total += sum_local_dir(local_dircache.first->name,
tmp->name);
break;
case S_IFREG:
total += tmp->size;
break;
case S_IFLNK:
status_footer_message(
"Ignoring symlink %s...", tmp->name);
log_message(
"Can only sum sizes of files and directories.\n");
break;
default:
status_footer_message(
"Ignoring non-file/directory %s.", tmp->name);
log_message(
"Can only transfer files and directories.\n");
break;
}
}
return (total);
}
syntax highlighted by Code2HTML, v. 0.9.1