/* abort routine originally from Cftp by Dieter Baron */ int ftp_abort(Socket* fp) { char buf[4096]; #ifdef HAVE_LIBSSH if(ftp->session) /* FIXME: what? */ return 0; #endif if(!ftp_connected()) return -1; ftp_set_close_handler(); if (sock_check_pending(fp, false) == 1) { ftp_trace("There is data on the control channel, won't send ABOR\n"); /* read remaining bytes from connection */ while(fp && sock_read(fp, buf, sizeof(buf)) > 0) /* LOOP */ ; return 0; } ftp->ti.interrupted = true; ftp_err(_("Waiting for remote to finish abort...\n")); ftp_trace("--> telnet interrupt\n"); if(sock_telnet_interrupt(ftp->ctrl) != 0) ftp_err("telnet interrupt: %s\n", strerror(errno)); /* ftp_cmd("ABOR") won't work here, * we must flush data between the ABOR command and ftp_read_reply() */ sock_krb_printf(ftp->ctrl, "ABOR"); sock_printf(ftp->ctrl, "\r\n"); sock_flush(ftp->ctrl); if(ftp_get_verbosity() == vbDebug) ftp_err("--> [%s] ABOR\n", ftp->url->hostname); else ftp_trace("--> [%s] ABOR\n", ftp->url->hostname); /* read remaining bytes from connection */ while(fp && sock_read(fp, buf, sizeof(buf)) > 0) /* LOOP */ ; /* we expect a 426 or 226 reply here... */ ftp_read_reply(); if(ftp->fullcode != 426 && ftp->fullcode != 226) ftp_trace("Huh!? Expected a 426 or 226 reply\n"); /* ... and a 226 or 225 reply here, respectively */ /* FIXME: should skip this reply if prev. reply wasn't 426 or 226 ? */ ftp_read_reply(); if(ftp->fullcode != 226 && ftp->fullcode != 225) ftp_trace("Huh!? Expected a 226 or 225 reply\n"); return -1; }
void ftp_flush_reply(void) { fd_set ready; struct timeval poll; if(!ftp_connected()) return; #ifdef HAVE_LIBSSH if (ftp->session) return; #endif /* ftp_set_signal(SIGINT, SIG_IGN);*/ fprintf(stderr, "flushing replies...\r"); /* ftp_reply_timeout(10);*/ while(ftp_connected()) { poll.tv_sec = 1; poll.tv_usec = 0; FD_ZERO(&ready); int handle = sock_handle(ftp->ctrl); FD_SET(handle, &ready); if(select(handle+1, &ready, 0, 0, &poll) == 1) ftp_read_reply(); else break; } #if 0 if(ftp_loggedin()) ftp_chdir(ftp->curdir); #endif ftp_set_close_handler(); }
void ftp_flush_reply(void) { if(!ftp_connected()) return; #ifdef HAVE_LIBSSH if (ftp->session) return; #endif /* ftp_set_signal(SIGINT, SIG_IGN);*/ fprintf(stderr, "flushing replies...\r"); /* ftp_reply_timeout(10);*/ while(ftp_connected()) { if (sock_check_pending(ftp->ctrl, false) == 1) ftp_read_reply(); else break; } #if 0 if(ftp_loggedin()) ftp_chdir(ftp->curdir); #endif ftp_set_close_handler(); }
static int ftp_do_receive(FILE *fp, transfer_mode_t mode, ftp_transfer_func hookf) { int r; if(mode == tmBinary) r = FILE_recv_binary(ftp->data, fp); else r = FILE_recv_ascii(ftp->data, fp); sock_destroy(ftp->data); ftp->data = 0; if(r == 0) { transfer_finished(); ftp_read_reply(); ftp->ti.ioerror = (ftp->code != ctComplete); if(ftp->code != ctComplete) { ftp_trace("transfer failed\n"); return -1; } } else transfer_finished(); return (r == 0 && !ftp->ti.ioerror && !ftp->ti.interrupted) ? 0 : -1; }
int ftp_list(const char *cmd, const char *param, FILE *fp) { if (!cmd || !fp || !ftp_connected()) return -1; #ifdef HAVE_LIBSSH if (ftp->session) return ssh_list(cmd, param, fp); #endif reset_transfer_info(); foo_hookf = NULL; #if 0 /* don't care about transfer type, binary should work well... */ ftp_type(tmAscii); #endif if (ftp_init_transfer() != 0) { ftp_err(_("transfer initialization failed")); return -1; } ftp_set_tmp_verbosity(vbNone); if (param) ftp_cmd("%s %s", cmd, param); else ftp_cmd("%s", cmd); if (ftp->code != ctPrelim) return -1; if (!sock_accept(ftp->data, "r", ftp_is_passive())) { perror("accept()"); return -1; } if (FILE_recv_ascii(ftp->data, fp) != 0) return -1; sock_destroy(ftp->data); ftp->data = NULL; ftp_read_reply(); return ftp->code == ctComplete ? 0 : -1; }
/* sends an FTP command on the control channel * returns reply status code on success or -1 on error */ int ftp_cmd(const char *cmd, ...) { va_list ap; int resp; bool recon = false; if(!sock_connected(ftp->ctrl)) { ftp_err(_("No control connection\n")); ftp->code = ctNone; ftp->fullcode = -1; return -1; } ftp_set_abort_handler(); ugly: va_start(ap, cmd); sock_krb_vprintf(ftp->ctrl, cmd, ap); sock_printf(ftp->ctrl, "\r\n"); sock_flush(ftp->ctrl); va_end(ap); if(ferror(sock_sout(ftp->ctrl))) { ftp_err(_("error writing command")); ftp_err(" ("); va_start(ap, cmd); vfprintf(stderr, cmd, ap); va_end(ap); va_start(ap, cmd); ftp_vtrace(cmd, ap); va_end(ap); ftp_err(")\n"); ftp->code = ctNone; ftp->fullcode = -1; return -1; } va_start(ap, cmd); ftp_print_cmd(cmd, ap); va_end(ap); resp = ftp_read_reply(); ftp_set_close_handler(); if(resp == 421) { /* server is closing control connection! */ ftp_err(_("Server closed control connection\n")); if(gvAutoReconnect && ftp_loggedin() && strcasecmp(cmd, "QUIT") != 0) { if(recon) { ftp_err(_("Reconnect failed\n")); } else { ftp_err(_("Automatic reconnect...\n")); ftp_reopen(); recon = true; goto ugly; } } else { /* ftp_close();*/ ftp->fullcode = 421; ftp->code = 4; return -1; } } return resp; }
int ftp_open_url(url_t *urlp, bool reset_vars) { bool use_proxy; int i; if(reset_vars) ftp_reset_vars(); /* don't assume server is in ascii mode initially even if RFC says so */ ftp->prev_type = '?'; #ifdef HAVE_POSIX_SIGSETJMP if(sigsetjmp(open_timeout_jmp, 1)) #else if(setjmp(open_timeout_jmp)) #endif { ftp_close(); ftp_err(_("Connection timeout after %u seconds\n"), ftp->open_timeout); return 1; } ftp_set_signal(SIGALRM, ftp_open_handler); alarm(ftp->open_timeout); use_proxy = (proxy_type(urlp) != 0); ftp_err(_("Looking up %s... "), use_proxy ? gvProxyUrl->hostname : urlp->hostname); /* Set the default port (22) for SSH if no port is specified. We * need to do this here, 'cause host_lookup() sets it to 21 * (default port for vanilla FTP) */ if(urlp->protocol) { if(strcmp(urlp->protocol, "sftp") == 0) url_setprotocol(urlp, "ssh"); if(strcmp(urlp->protocol, "ssh") == 0 && urlp->port == -1) urlp->port = 22; /* default SSH port */ } ftp->host = host_create(use_proxy ? gvProxyUrl : urlp); if(!host_lookup(ftp->host)) { herror(host_getname(ftp->host)); alarm(0); ftp_set_signal(SIGALRM, SIG_IGN); return -1; } /* keep the value in urlp->port urlp->port = ntohs(ftp->host->port); and set it to 21 if it is -1 */ if(urlp->port == -1) { urlp->port = 21; } fprintf(stderr, "\r "); i = strlen(use_proxy ? gvProxyUrl->hostname : urlp->hostname); while(i--) fprintf(stderr, " "); fprintf(stderr, "\r"); ftp_trace("\n"); #ifdef HAVE_LIBSSH if(urlp->protocol && strcmp(urlp->protocol, "ssh") == 0) { int ret = ssh_open_url(urlp); alarm(0); return ret; } #endif if(urlp->protocol && strcmp(urlp->protocol, "ftp") != 0) { ftp_err(_("Sorry, don't know how to handle your '%s' protocol\n" "trying 'ftp' instead...\n"), urlp->protocol); url_setprotocol(urlp, 0); } if(use_proxy) { ftp_err(_("Connecting to proxy %s at port %d...\n"), host_getoname(ftp->host), urlp->port); } else { ftp_err(_("Connecting to %s at port %d...\n"), host_getoname(ftp->host), urlp->port); } ftp->ctrl = sock_create(); if (ftp->ctrl == 0) { ftp_err(_("Unable to create socket.\n")); alarm(0); ftp_set_signal(SIGALRM, SIG_IGN); return -1; } if(!sock_connect_host(ftp->ctrl, ftp->host)) { alarm(0); ftp_set_signal(SIGALRM, SIG_IGN); return -1; } sock_lowdelay(ftp->ctrl); char* ip = host_getip(ftp->host); ftp_err(_("Connected to %s ([%s]:%d).\n"), host_getoname(ftp->host), ip, urlp->port); free(ip); /* read startup message from server */ ftp_set_tmp_verbosity(vbCommand); ftp_read_reply(); if(ftp->fullcode == 120) { ftp_set_tmp_verbosity(vbCommand); ftp_read_reply(); } alarm(0); ftp_set_signal(SIGALRM, SIG_IGN); if(!sock_connected(ftp->ctrl)) { ftp_close(); return 1; } ftp->connected = (ftp->fullcode == 220); if(ftp->connected) { void (*tracefunq)(const char *fmt, ...); url_destroy(ftp->url); ftp->url = url_clone(urlp); tracefunq = (ftp->verbosity == vbDebug ? ftp_err : ftp_trace); char* remote_addr = printable_address(sock_remote_addr(ftp->ctrl)), *local_addr = printable_address(sock_local_addr(ftp->ctrl)); tracefunq("remote address: %s\n", remote_addr); tracefunq("local address: %s\n", local_addr); free(remote_addr); free(local_addr); return 0; } else { ftp_close(); return 1; } }
/* transfers SRCFILE on SRCFTP to DESTFILE on DESTFTP * using pasv mode on SRCFTP and port mode on DESTFTP * */ int ftp_fxpfile(Ftp *srcftp, const char *srcfile, Ftp *destftp, const char *destfile, fxpmode_t how, transfer_mode_t mode) { int r; unsigned int old_reply_timeout; Ftp *thisftp; unsigned char addr[6]; /* printf("FxP: %s -> %s\n", srcftp->url->hostname, destftp->url->hostname);*/ if(srcftp == destftp) { ftp_err(_("FxP between same hosts\n")); return -1; } #ifdef HAVE_LIBSSH if(ftp->session) { ftp_err("FxP with SSH not implemented\n"); return -1; } #endif thisftp = ftp; /* save currently active connection */ /* setup source side */ ftp_use(srcftp); ftp_type(mode); // TODO: IPv6 support if(!ftp_pasv(false, addr, NULL)) { ftp_use(thisftp); return -1; } ftp->ti.total_size = -1; /* setup destination side */ ftp_use(destftp); ftp_type(mode); ftp_cmd("PORT %d,%d,%d,%d,%d,%d", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); if(ftp->code != ctComplete) { ftp_use(thisftp); return -1; } ftp->ti.total_size = -1; ftp_use(destftp); if(how == fxpResume) { rfile *f; f = ftp_get_file(destfile); if(f && f->size != (unsigned long long)-1) ftp->restart_offset = f->size; else { ftp->restart_offset = ftp_filesize(destfile); if(ftp->restart_offset == (unsigned long long)-1) { ftp_err(_("unable to get remote filesize of '%s'," " unable to resume\n"), destfile); ftp->restart_offset = 0L; } } } else ftp->restart_offset = 0L; if(ftp->restart_offset) { /* RESTart on destftp */ ftp_cmd("REST %ld", ftp->restart_offset); if(ftp->code != ctContinue) return -1; ftp_use(srcftp); ftp_cmd("REST %ld", ftp->restart_offset); if(ftp->code != ctContinue) return -1; } /* issue a STOR command on DESTFTP */ ftp_use(destftp); switch(how) { case fxpUnique: if(ftp->has_stou_command) { ftp_cmd("STOU %s", destfile); if(ftp->fullcode == 502) ftp->has_stou_command = false; } else { ftp->code = ctError; ftp->fullcode = 502; } break; case fxpAppend: ftp_cmd("APPE %s", destfile); break; case fxpNormal: default: ftp_cmd("STOR %s", destfile); break; } ftp_cache_flush_mark_for(destfile); if(ftp->code != ctPrelim) { ftp_use(thisftp); return -1; } /* issue a RETR command on SRCFTP */ ftp_use(srcftp); ftp_cmd("RETR %s", srcfile); if(ftp->code != ctPrelim) { ftp_use(destftp); ftp_abort(NULL); ftp_use(thisftp); return -1; } ftp_use(destftp); old_reply_timeout = ftp->reply_timeout; ftp_reply_timeout(0); ftp_read_reply(); ftp_reply_timeout(old_reply_timeout); r = (ftp->code == ctComplete ? 0 : -1); ftp_use(srcftp); old_reply_timeout = ftp->reply_timeout; ftp_reply_timeout(0); ftp_read_reply(); ftp_reply_timeout(old_reply_timeout); ftp_use(thisftp); return r; }
static int ftp_send(const char *path, FILE *fp, putmode_t how, transfer_mode_t mode, ftp_transfer_func hookf) { int r; long rp = ftp->restart_offset; ftp->restart_offset = 0L; if(how == putUnique && !ftp->has_stou_command) return -1; if (how == putTryUnique && !ftp->has_stou_command) how = putNormal; reset_transfer_info(); ftp->ti.transfer_is_put = true; if(ftp_init_transfer() != 0) return -1; ftp_type(mode); if(rp > 0) { /* fp is assumed to be fseek'd already */ ftp_cmd("REST %ld", rp); if(ftp->code != ctContinue) return -1; ftp->ti.size = rp; ftp->ti.restart_size = rp; } ftp_set_tmp_verbosity(vbError); switch (how) { case putAppend: ftp_cmd("APPE %s", path); break; case putTryUnique: case putUnique: ftp_cmd("STOU %s", path); if (ftp->fullcode == 502 || ftp->fullcode == 504) { ftp->has_stou_command = false; if (how == putTryUnique) how = putNormal; else break; } else break; default: ftp_cmd("STOR %s", path); break; } if(ftp->code != ctPrelim) return -1; if(how == putUnique) { /* try to figure out remote filename */ char *e = strstr(ftp->reply, " for "); if(e) { int l; e += 5; l = strlen(e); if(l) { free(ftp->ti.local_name); if(*e == '\'') ftp->ti.local_name = xstrndup(e+1, l-3); else ftp->ti.local_name = xstrndup(e, l-1); ftp_trace("parsed unique filename as '%s'\n", ftp->ti.local_name); } } } if(!sock_accept(ftp->data, "w", ftp_is_passive())) { ftp_err(_("data connection not accepted\n")); return -1; } ftp_cache_flush_mark_for(path); if(mode == tmBinary) r = FILE_send_binary(fp, ftp->data); else r = FILE_send_ascii(fp, ftp->data); sock_flush(ftp->data); sock_destroy(ftp->data); ftp->data = 0; if(r == 0) { transfer_finished(); ftp_read_reply(); ftp->ti.ioerror = (ftp->code != ctComplete); if(ftp->code != ctComplete) { ftp_trace("transfer failed\n"); return -1; } } else transfer_finished(); return 0; }
/* abort routine originally from Cftp by Dieter Baron */ int ftp_abort(FILE *fp) { char buf[4096]; fd_set ready; struct timeval poll; if(ftp->ssh_pid) /* FIXME: what? */ return 0; if(!ftp_connected()) return -1; ftp_set_close_handler(); poll.tv_sec = poll.tv_usec = 0; FD_ZERO(&ready); FD_SET(ftp->ctrl->handle, &ready); if(select(ftp->ctrl->handle+1, &ready, 0, 0, &poll) == 1) { ftp_trace("There is data on the control channel, won't send ABOR\n"); /* read remaining bytes from connection */ while(fp && fread(buf, 1, 4096, fp) > 0) /* LOOP */ ; return 0; } ftp->ti.interrupted = true; ftp_err(_("Waiting for remote to finish abort...\n")); ftp_trace("--> telnet interrupt\n"); if(sock_telnet_interrupt(ftp->ctrl) != 0) ftp_err("telnet interrupt: %s\n", strerror(errno)); /* ftp_cmd("ABOR") won't work here, * we must flush data between the ABOR command and ftp_read_reply() */ sock_krb_printf(ftp->ctrl, "ABOR"); sock_printf(ftp->ctrl, "\r\n"); sock_flush(ftp->ctrl); if(ftp_get_verbosity() == vbDebug) ftp_err("--> [%s] ABOR\n", ftp->url->hostname); else ftp_trace("--> [%s] ABOR\n", ftp->url->hostname); /* read remaining bytes from connection */ while(fp && fread(buf, 1, 4096, fp) > 0) /* LOOP */ ; /* we expect a 426 or 226 reply here... */ ftp_read_reply(); if(ftp->fullcode != 426 && ftp->fullcode != 226) ftp_trace("Huh!? Expected a 426 or 226 reply\n"); /* ... and a 226 or 225 reply here, respectively */ /* FIXME: should skip this reply if prev. reply wasn't 426 or 226 ? */ ftp_read_reply(); if(ftp->fullcode != 226 && ftp->fullcode != 225) ftp_trace("Huh!? Expected a 226 or 225 reply\n"); return -1; }