/*
- * scp.c - Scp (Secure Copy) client for PuTTY.
- * Joris van Rantwijk, Simon Tatham
+ * scp.c - Scp (Secure Copy) client for PuTTY.
+ * Joris van Rantwijk, Simon Tatham
*
- * This is mainly based on ssh-1.2.26/scp.c by Timo Rinne & Tatu Ylonen.
- * They, in turn, used stuff from BSD rcp.
- *
- * Adaptations to enable connecting a GUI by L. Gunnarsson - Sept 2000
+ * This is mainly based on ssh-1.2.26/scp.c by Timo Rinne & Tatu Ylonen.
+ * They, in turn, used stuff from BSD rcp.
+ *
+ * (SGT, 2001-09-10: Joris van Rantwijk assures me that although
+ * this file as originally submitted was inspired by, and
+ * _structurally_ based on, ssh-1.2.26's scp.c, there wasn't any
+ * actual code duplicated, so the above comment shouldn't give rise
+ * to licensing issues.)
*/
#include <windows.h>
#include <limits.h>
#include <time.h>
#include <assert.h>
-/* GUI Adaptation - Sept 2000 */
-#include <winuser.h>
-#include <winbase.h>
#define PUTTY_DO_GLOBALS
#include "putty.h"
#define WM_STATS_ELAPSED ( WM_APP_BASE+405 )
#define WM_RET_ERR_CNT ( WM_APP_BASE+406 )
#define WM_LS_RET_ERR_CNT ( WM_APP_BASE+407 )
+#define WM_STATS_DONE ( WM_APP_BASE+408 )
+#define WM_STATS_ETA ( WM_APP_BASE+409 )
+#define WM_STATS_RATEBS ( WM_APP_BASE+410 )
static int list = 0;
static int verbose = 0;
#define NAME_STR_MAX 2048
static char statname[NAME_STR_MAX + 1];
static unsigned long statsize = 0;
+static unsigned long statdone = 0;
+static unsigned long stateta = 0;
+static unsigned long statratebs = 0;
static int statperct = 0;
static unsigned long statelapsed = 0;
static int gui_mode = 0;
static void tell_str(FILE * stream, char *str);
static void tell_user(FILE * stream, char *fmt, ...);
static void gui_update_stats(char *name, unsigned long size,
- int percentage, unsigned long elapsed);
+ int percentage, unsigned long elapsed,
+ unsigned long done, unsigned long eta,
+ unsigned long ratebs);
/*
* The maximum amount of queued data we accept before we stop and
{
}
-void ldisc_send(char *buf, int len)
+void ldisc_send(char *buf, int len, int interactive)
{
/*
* This is only here because of the calls to ldisc_send(NULL,
}
}
+/*
+ * Ask whether to wipe a session log file before writing to it.
+ * Returns 2 for wipe, 1 for append, 0 for cancel (don't log).
+ */
+int askappend(char *filename)
+{
+ HANDLE hin;
+ DWORD savemode, i;
+
+ static const char msgtemplate[] =
+ "The session log file \"%.*s\" already exists.\n"
+ "You can overwrite it with a new session log,\n"
+ "append your session log to the end of it,\n"
+ "or disable session logging for this session.\n"
+ "Enter \"y\" to wipe the file, \"n\" to append to it,\n"
+ "or just press Return to disable logging.\n"
+ "Wipe the log file? (y/n, Return cancels logging) ";
+
+ char line[32];
+
+ fprintf(stderr, msgtemplate, FILENAME_MAX, filename);
+ fflush(stderr);
+
+ hin = GetStdHandle(STD_INPUT_HANDLE);
+ GetConsoleMode(hin, &savemode);
+ SetConsoleMode(hin, (savemode | ENABLE_ECHO_INPUT |
+ ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT));
+ ReadFile(hin, line, sizeof(line) - 1, &i, NULL);
+ SetConsoleMode(hin, savemode);
+
+ if (line[0] == 'y' || line[0] == 'Y')
+ return 2;
+ else if (line[0] == 'n' || line[0] == 'N')
+ return 1;
+ else
+ return 0;
+}
+
+/*
+ * Warn about the obsolescent key file format.
+ */
+void old_keyfile_warning(void)
+{
+ static const char message[] =
+ "You are loading an SSH 2 private key which has an\n"
+ "old version of the file format. This means your key\n"
+ "file is not fully tamperproof. Future versions of\n"
+ "PuTTY may stop supporting this private key format,\n"
+ "so we recommend you convert your key to the new\n"
+ "format.\n"
+ "\n"
+ "Once the key is loaded into PuTTYgen, you can perform\n"
+ "this conversion simply by saving it again.\n";
+
+ fputs(message, stderr);
+}
+
/* GUI Adaptation - Sept 2000 */
static void send_msg(HWND h, UINT message, WPARAM wParam)
{
}
static void gui_update_stats(char *name, unsigned long size,
- int percentage, unsigned long elapsed)
+ int percentage, unsigned long elapsed,
+ unsigned long done, unsigned long eta,
+ unsigned long ratebs)
{
unsigned int i;
send_msg((HWND) atoi(gui_hwnd), WM_STATS_SIZE, (WPARAM) size);
statsize = size;
}
+ if (statdone != done) {
+ send_msg((HWND) atoi(gui_hwnd), WM_STATS_DONE, (WPARAM) done);
+ statdone = done;
+ }
+ if (stateta != eta) {
+ send_msg((HWND) atoi(gui_hwnd), WM_STATS_ETA, (WPARAM) eta);
+ stateta = eta;
+ }
+ if (statratebs != ratebs) {
+ send_msg((HWND) atoi(gui_hwnd), WM_STATS_RATEBS, (WPARAM) ratebs);
+ statratebs = ratebs;
+ }
if (statelapsed != elapsed) {
send_msg((HWND) atoi(gui_hwnd), WM_STATS_ELAPSED,
(WPARAM) elapsed);
return 0;
}
- inbuf_head = 0;
-
/*
* If this is before the real session begins, just return.
*/
cfg.port = 22;
}
+ /*
+ * Trim leading whitespace off the hostname if it's there.
+ */
+ {
+ int space = strspn(cfg.host, " \t");
+ memmove(cfg.host, cfg.host+space, 1+strlen(cfg.host)-space);
+ }
+
+ /* See if host is of the form user@host */
+ if (cfg.host[0] != '\0') {
+ char *atsign = strchr(cfg.host, '@');
+ /* Make sure we're not overflowing the user field */
+ if (atsign) {
+ if (atsign - cfg.host < sizeof cfg.username) {
+ strncpy(cfg.username, cfg.host, atsign - cfg.host);
+ cfg.username[atsign - cfg.host] = '\0';
+ }
+ memmove(cfg.host, atsign + 1, 1 + strlen(atsign + 1));
+ }
+ }
+
+ /*
+ * Trim a colon suffix off the hostname if it's there.
+ */
+ cfg.host[strcspn(cfg.host, ":")] = '\0';
+
/* Set username */
if (user != NULL && user[0] != '\0') {
strncpy(cfg.username, user, sizeof(cfg.username) - 1);
if (portnumber)
cfg.port = portnumber;
+ /*
+ * Disable scary things which shouldn't be enabled for simple
+ * things like SCP and SFTP: agent forwarding, port forwarding,
+ * X forwarding.
+ */
+ cfg.x11_forward = 0;
+ cfg.agentfwd = 0;
+ cfg.portfwd[0] = cfg.portfwd[1] = '\0';
+
/*
* Attempt to start the SFTP subsystem as a first choice,
* falling back to the provided scp command if that fails.
back = &ssh_backend;
- err = back->init(cfg.host, cfg.port, &realhost);
+ err = back->init(cfg.host, cfg.port, &realhost, 0);
if (err != NULL)
bump("ssh_init: %s", err);
ssh_scp_init();
char etastr[10];
int pct;
int len;
+ int elap;
- /* GUI Adaptation - Sept 2000 */
- if (gui_mode)
- gui_update_stats(name, size, (int) (100 * (done * 1.0 / size)),
- (unsigned long) difftime(now, start));
- else {
- if (now > start)
- ratebs = (float) done / (now - start);
- else
- ratebs = (float) done;
+ elap = (unsigned long) difftime(now, start);
- if (ratebs < 1.0)
- eta = size - done;
- else
- eta = (unsigned long) ((size - done) / ratebs);
- sprintf(etastr, "%02ld:%02ld:%02ld",
- eta / 3600, (eta % 3600) / 60, eta % 60);
+ if (now > start)
+ ratebs = (float) done / elap;
+ else
+ ratebs = (float) done;
- pct = (int) (100.0 * (float) done / size);
+ if (ratebs < 1.0)
+ eta = size - done;
+ else
+ eta = (unsigned long) ((size - done) / ratebs);
+ sprintf(etastr, "%02ld:%02ld:%02ld",
+ eta / 3600, (eta % 3600) / 60, eta % 60);
+ pct = (int) (100 * (done * 1.0 / size));
+
+ if (gui_mode)
+ /* GUI Adaptation - Sept 2000 */
+ gui_update_stats(name, size, pct, elap, done, eta,
+ (unsigned long) ratebs);
+ else {
len = printf("\r%-25.25s | %10ld kB | %5.1f kB/s | ETA: %8s | %3d%%",
name, done / 1024, ratebs / 1024.0, etastr, pct);
if (len < prev_stats_len)