X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/02105c79d5cbe02d41294d7eeeb603b94706bbcc..514702987c9252fcb0ab98882a6603b3bd0505ce:/scp.c diff --git a/scp.c b/scp.c index 3527f2b1..25f29b44 100644 --- a/scp.c +++ b/scp.c @@ -40,15 +40,39 @@ ((*(LONGLONG*)&(ft)) / (LONGLONG) 10000000 - (LONGLONG) 11644473600)) /* GUI Adaptation - Sept 2000 */ + +/* This is just a base value from which the main message numbers are + * derived. */ #define WM_APP_BASE 0x8000 + +/* These two pass a single character value in wParam. They represent + * the visible output from PSCP. */ #define WM_STD_OUT_CHAR ( WM_APP_BASE+400 ) #define WM_STD_ERR_CHAR ( WM_APP_BASE+401 ) + +/* These pass a transfer status update. WM_STATS_CHAR passes a single + * character in wParam, and is called repeatedly to pass the name of + * the file, terminated with "\n". WM_STATS_SIZE passes the size of + * the file being transferred in wParam. WM_STATS_ELAPSED is called + * to pass the elapsed time (in seconds) in wParam, and + * WM_STATS_PERCENT passes the percentage of the transfer which is + * complete, also in wParam. */ #define WM_STATS_CHAR ( WM_APP_BASE+402 ) #define WM_STATS_SIZE ( WM_APP_BASE+403 ) #define WM_STATS_PERCENT ( WM_APP_BASE+404 ) #define WM_STATS_ELAPSED ( WM_APP_BASE+405 ) + +/* These are used at the end of a run to pass an error code in + * wParam: zero means success, nonzero means failure. WM_RET_ERR_CNT + * is used after a copy, and WM_LS_RET_ERR_CNT is used after a file + * list operation. */ #define WM_RET_ERR_CNT ( WM_APP_BASE+406 ) #define WM_LS_RET_ERR_CNT ( WM_APP_BASE+407 ) + +/* More transfer status update messages. WM_STATS_DONE passes the + * number of bytes sent so far in wParam. WM_STATS_ETA passes the + * estimated time to completion (in seconds). WM_STATS_RATEBS passes + * the average transfer rate (in bytes per second). */ #define WM_STATS_DONE ( WM_APP_BASE+408 ) #define WM_STATS_ETA ( WM_APP_BASE+409 ) #define WM_STATS_RATEBS ( WM_APP_BASE+410 ) @@ -59,10 +83,8 @@ static int recursive = 0; static int preserve = 0; static int targetshouldbedirectory = 0; static int statistics = 1; -static int portnumber = 0; static int prev_stats_len = 0; static int scp_unsafe_mode = 0; -static char *password = NULL; static int errs = 0; /* GUI Adaptation - Sept 2000 */ #define NAME_STR_MAX 2048 @@ -212,6 +234,29 @@ void fatalbox(char *fmt, ...) cleanup_exit(1); } +void modalfatalbox(char *fmt, ...) +{ + char str[0x100]; /* Make the size big enough */ + va_list ap; + va_start(ap, fmt); + strcpy(str, "Fatal: "); + vsprintf(str + strlen(str), fmt, ap); + va_end(ap); + strcat(str, "\n"); + tell_str(stderr, str); + errs++; + + if (gui_mode) { + unsigned int msg_id = WM_RET_ERR_CNT; + if (list) + msg_id = WM_LS_RET_ERR_CNT; + while (!PostMessage + ((HWND) atoi(gui_hwnd), msg_id, (WPARAM) errs, + 0 /*lParam */ ))SleepEx(1000, TRUE); + } + + cleanup_exit(1); +} void connection_fatal(char *fmt, ...) { char str[0x100]; /* Make the size big enough */ @@ -263,7 +308,7 @@ static unsigned char *outptr; /* where to put the data */ static unsigned outlen; /* how much data required */ static unsigned char *pending = NULL; /* any spare data */ static unsigned pendlen = 0, pendsize = 0; /* length and phys. size of buffer */ -int from_backend(int is_stderr, char *data, int datalen) +int from_backend(void *frontend, int is_stderr, char *data, int datalen) { unsigned char *p = (unsigned char *) data; unsigned len = (unsigned) datalen; @@ -363,7 +408,7 @@ static void ssh_scp_init(void) { if (scp_ssh_socket == INVALID_SOCKET) return; - while (!back->sendok()) { + while (!back->sendok(backhandle)) { fd_set readfds; FD_ZERO(&readfds); FD_SET(scp_ssh_socket, &readfds); @@ -371,7 +416,7 @@ static void ssh_scp_init(void) return; /* doom */ select_result((WPARAM) scp_ssh_socket, (LPARAM) FD_READ); } - using_sftp = !ssh_fallback_cmd; + using_sftp = !ssh_fallback_cmd(backhandle); } /* @@ -389,9 +434,9 @@ static void bump(char *fmt, ...) tell_str(stderr, str); errs++; - if (back != NULL && back->socket() != NULL) { + if (back != NULL && back->socket(backhandle) != NULL) { char ch; - back->special(TS_EOF); + back->special(backhandle, TS_EOF); ssh_scp_recv(&ch, 1); } @@ -425,10 +470,23 @@ static void do_cmd(char *host, char *user, char *cmd) do_defaults(NULL, &cfg); strncpy(cfg.host, host, sizeof(cfg.host) - 1); cfg.host[sizeof(cfg.host) - 1] = '\0'; - cfg.port = 22; } /* + * Force use of SSH. (If they got the protocol wrong we assume the + * port is useless too.) + */ + if (cfg.protocol != PROT_SSH) { + cfg.protocol = PROT_SSH; + cfg.port = 22; + } + + /* + * Enact command-line overrides. + */ + cmdline_run_saved(); + + /* * Trim leading whitespace off the hostname if it's there. */ { @@ -454,6 +512,21 @@ static void do_cmd(char *host, char *user, char *cmd) */ cfg.host[strcspn(cfg.host, ":")] = '\0'; + /* + * Remove any remaining whitespace from the hostname. + */ + { + int p1 = 0, p2 = 0; + while (cfg.host[p2] != '\0') { + if (cfg.host[p2] != ' ' && cfg.host[p2] != '\t') { + cfg.host[p1] = cfg.host[p2]; + p1++; + } + p2++; + } + cfg.host[p1] = '\0'; + } + /* Set username */ if (user != NULL && user[0] != '\0') { strncpy(cfg.username, user, sizeof(cfg.username) - 1); @@ -471,12 +544,6 @@ static void do_cmd(char *host, char *user, char *cmd) free(user); } - if (cfg.protocol != PROT_SSH) - cfg.port = 22; - - if (portnumber) - cfg.port = portnumber; - /* * Disable scary things which shouldn't be enabled for simple * things like SCP and SFTP: agent forwarding, port forwarding, @@ -498,7 +565,7 @@ static void do_cmd(char *host, char *user, char *cmd) back = &ssh_backend; - err = back->init(cfg.host, cfg.port, &realhost, 0); + err = back->init(NULL, &backhandle, cfg.host, cfg.port, &realhost, 0); if (err != NULL) bump("ssh_init: %s", err); ssh_scp_init(); @@ -645,7 +712,7 @@ int sftp_recvdata(char *buf, int len) } int sftp_senddata(char *buf, int len) { - back->send((unsigned char *) buf, len); + back->send(backhandle, (unsigned char *) buf, len); return 1; } @@ -666,6 +733,12 @@ void scp_sftp_listdir(char *dirname) int nnames, namesize; int i; + if (!fxp_init()) { + tell_user(stderr, "unable to initialise SFTP: %s", fxp_error()); + errs++; + return; + } + printf("Listing directory %s\n", dirname); dirh = fxp_opendir(dirname); @@ -751,7 +824,7 @@ void scp_source_setup(char *target, int shouldbedir) if (!fxp_init()) { tell_user(stderr, "unable to initialise SFTP: %s", fxp_error()); errs++; - return 1; + return; } if (!fxp_stat(target, &attrs) || @@ -777,8 +850,8 @@ int scp_send_errmsg(char *str) if (using_sftp) { /* do nothing; we never need to send our errors to the server */ } else { - back->send("\001", 1); /* scp protocol error prefix */ - back->send(str, strlen(str)); + back->send(backhandle, "\001", 1);/* scp protocol error prefix */ + back->send(backhandle, str, strlen(str)); } return 0; /* can't fail */ } @@ -793,7 +866,7 @@ int scp_send_filetimes(unsigned long mtime, unsigned long atime) } else { char buf[80]; sprintf(buf, "T%lu 0 %lu 0\n", mtime, atime); - back->send(buf, strlen(buf)); + back->send(backhandle, buf, strlen(buf)); return response(); } } @@ -821,9 +894,9 @@ int scp_send_filename(char *name, unsigned long size, int modes) } else { char buf[40]; sprintf(buf, "C%04o %lu ", modes, size); - back->send(buf, strlen(buf)); - back->send(name, strlen(name)); - back->send("\n", 1); + back->send(backhandle, buf, strlen(buf)); + back->send(backhandle, name, strlen(name)); + back->send(backhandle, "\n", 1); return response(); } } @@ -842,7 +915,7 @@ int scp_send_filedata(char *data, int len) scp_sftp_fileoffset = uint64_add32(scp_sftp_fileoffset, len); return 0; } else { - int bufsize = back->send(data, len); + int bufsize = back->send(backhandle, data, len); /* * If the network transfer is backing up - that is, the @@ -853,7 +926,7 @@ int scp_send_filedata(char *data, int len) while (bufsize > MAX_SCP_BUFSIZE) { if (!scp_process_network_event()) return 1; - bufsize = back->sendbuffer(); + bufsize = back->sendbuffer(backhandle); } return 0; @@ -880,7 +953,7 @@ int scp_send_finish(void) scp_has_times = 0; return 0; } else { - back->send("", 1); + back->send(backhandle, "", 1); return response(); } } @@ -937,9 +1010,9 @@ int scp_send_dirname(char *name, int modes) } else { char buf[40]; sprintf(buf, "D%04o 0 ", modes); - back->send(buf, strlen(buf)); - back->send(name, strlen(name)); - back->send("\n", 1); + back->send(backhandle, buf, strlen(buf)); + back->send(backhandle, name, strlen(name)); + back->send(backhandle, "\n", 1); return response(); } } @@ -950,7 +1023,7 @@ int scp_send_enddir(void) sfree(scp_sftp_remotepath); return 0; } else { - back->send("E\n", 2); + back->send(backhandle, "E\n", 2); return response(); } } @@ -1045,7 +1118,7 @@ int scp_sink_setup(char *source, int preserve, int recursive) int scp_sink_init(void) { if (!using_sftp) { - back->send("", 1); + back->send(backhandle, "", 1); } return 0; } @@ -1331,14 +1404,14 @@ int scp_get_sink_action(struct scp_sink_action *act) case '\02': /* fatal error */ bump("%s", act->buf); case 'E': - back->send("", 1); + back->send(backhandle, "", 1); act->action = SCP_SINK_ENDDIR; return 0; case 'T': if (sscanf(act->buf, "%ld %*d %ld %*d", &act->mtime, &act->atime) == 2) { act->settime = 1; - back->send("", 1); + back->send(backhandle, "", 1); continue; /* go round again */ } bump("Protocol error: Illegal time format"); @@ -1382,7 +1455,7 @@ int scp_accept_filexfer(void) sfree(scp_sftp_currentname); return 0; } else { - back->send("", 1); + back->send(backhandle, "", 1); return 0; /* can't fail */ } } @@ -1414,7 +1487,7 @@ int scp_finish_filerecv(void) fxp_close(scp_sftp_filehandle); return 0; } else { - back->send("", 1); + back->send(backhandle, "", 1); return response(); } } @@ -2053,8 +2126,14 @@ static void usage(void) printf(" -q quiet, don't show statistics\n"); printf(" -r copy directories recursively\n"); printf(" -v show verbose messages\n"); + printf(" -load sessname Load settings from saved session\n"); printf(" -P port connect to specified port\n"); + printf(" -l user connect with specified username\n"); printf(" -pw passw login with specified password\n"); + printf(" -1 -2 force use of particular SSH protocol version\n"); + printf(" -C enable compression\n"); + printf(" -i key private key file for authentication\n"); + printf(" -batch disable all interactive prompts\n"); printf(" -unsafe allow server-side wildcards (DANGEROUS)\n"); #if 0 /* @@ -2070,6 +2149,17 @@ static void usage(void) cleanup_exit(1); } +void cmdline_error(char *p, ...) +{ + va_list ap; + fprintf(stderr, "pscp: "); + va_start(ap, p); + vfprintf(stderr, p, ap); + va_end(ap); + fputc('\n', stderr); + exit(1); +} + /* * Main program (no, really?) */ @@ -2080,38 +2170,43 @@ int main(int argc, char *argv[]) default_protocol = PROT_TELNET; flags = FLAG_STDERR; + cmdline_tooltype = TOOLTYPE_FILETRANSFER; ssh_get_line = &console_get_line; init_winsock(); sk_init(); for (i = 1; i < argc; i++) { + int ret; if (argv[i][0] != '-') break; - if (strcmp(argv[i], "-v") == 0) - verbose = 1, flags |= FLAG_VERBOSE; - else if (strcmp(argv[i], "-r") == 0) + ret = cmdline_process_param(argv[i], i+1socket() != NULL) { + if (back != NULL && back->socket(backhandle) != NULL) { char ch; - back->special(TS_EOF); + back->special(backhandle, TS_EOF); ssh_scp_recv(&ch, 1); } WSACleanup();