]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - scp.c
Configurable TCP_NODELAY option on network connections
[PuTTY.git] / scp.c
1 /*
2  * scp.c  -  Scp (Secure Copy) client for PuTTY.
3  * Joris van Rantwijk, Simon Tatham
4  *
5  * This is mainly based on ssh-1.2.26/scp.c by Timo Rinne & Tatu Ylonen.
6  * They, in turn, used stuff from BSD rcp.
7  * 
8  * (SGT, 2001-09-10: Joris van Rantwijk assures me that although
9  * this file as originally submitted was inspired by, and
10  * _structurally_ based on, ssh-1.2.26's scp.c, there wasn't any
11  * actual code duplicated, so the above comment shouldn't give rise
12  * to licensing issues.)
13  */
14
15 #include <windows.h>
16 #ifndef AUTO_WINSOCK
17 #ifdef WINSOCK_TWO
18 #include <winsock2.h>
19 #else
20 #include <winsock.h>
21 #endif
22 #endif
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <limits.h>
27 #include <time.h>
28 #include <assert.h>
29
30 #define PUTTY_DO_GLOBALS
31 #include "putty.h"
32 #include "ssh.h"
33 #include "sftp.h"
34 #include "winstuff.h"
35 #include "storage.h"
36
37 #define TIME_POSIX_TO_WIN(t, ft) (*(LONGLONG*)&(ft) = \
38         ((LONGLONG) (t) + (LONGLONG) 11644473600) * (LONGLONG) 10000000)
39 #define TIME_WIN_TO_POSIX(ft, t) ((t) = (unsigned long) \
40         ((*(LONGLONG*)&(ft)) / (LONGLONG) 10000000 - (LONGLONG) 11644473600))
41
42 /* GUI Adaptation - Sept 2000 */
43 #define   WM_APP_BASE           0x8000
44 #define   WM_STD_OUT_CHAR       ( WM_APP_BASE+400 )
45 #define   WM_STD_ERR_CHAR       ( WM_APP_BASE+401 )
46 #define   WM_STATS_CHAR         ( WM_APP_BASE+402 )
47 #define   WM_STATS_SIZE         ( WM_APP_BASE+403 )
48 #define   WM_STATS_PERCENT      ( WM_APP_BASE+404 )
49 #define   WM_STATS_ELAPSED      ( WM_APP_BASE+405 )
50 #define   WM_RET_ERR_CNT        ( WM_APP_BASE+406 )
51 #define   WM_LS_RET_ERR_CNT     ( WM_APP_BASE+407 )
52 #define   WM_STATS_DONE         ( WM_APP_BASE+408 )
53 #define   WM_STATS_ETA          ( WM_APP_BASE+409 )
54 #define   WM_STATS_RATEBS       ( WM_APP_BASE+410 )
55
56 static int list = 0;
57 static int verbose = 0;
58 static int recursive = 0;
59 static int preserve = 0;
60 static int targetshouldbedirectory = 0;
61 static int statistics = 1;
62 static int portnumber = 0;
63 static int prev_stats_len = 0;
64 static int scp_unsafe_mode = 0;
65 static char *password = NULL;
66 static int errs = 0;
67 /* GUI Adaptation - Sept 2000 */
68 #define NAME_STR_MAX 2048
69 static char statname[NAME_STR_MAX + 1];
70 static unsigned long statsize = 0;
71 static unsigned long statdone = 0;
72 static unsigned long stateta = 0;
73 static unsigned long statratebs = 0;
74 static int statperct = 0;
75 static unsigned long statelapsed = 0;
76 static int gui_mode = 0;
77 static char *gui_hwnd = NULL;
78 static int using_sftp = 0;
79
80 static void source(char *src);
81 static void rsource(char *src);
82 static void sink(char *targ, char *src);
83 /* GUI Adaptation - Sept 2000 */
84 static void tell_char(FILE * stream, char c);
85 static void tell_str(FILE * stream, char *str);
86 static void tell_user(FILE * stream, char *fmt, ...);
87 static void gui_update_stats(char *name, unsigned long size,
88                              int percentage, unsigned long elapsed, 
89                              unsigned long done, unsigned long eta,
90                              unsigned long ratebs);
91
92 /*
93  * The maximum amount of queued data we accept before we stop and
94  * wait for the server to process some.
95  */
96 #define MAX_SCP_BUFSIZE 16384
97
98 void logevent(char *string)
99 {
100 }
101
102 void ldisc_send(char *buf, int len, int interactive)
103 {
104     /*
105      * This is only here because of the calls to ldisc_send(NULL,
106      * 0) in ssh.c. Nothing in PSCP actually needs to use the ldisc
107      * as an ldisc. So if we get called with any real data, I want
108      * to know about it.
109      */
110     assert(len == 0);
111 }
112
113 void verify_ssh_host_key(char *host, int port, char *keytype,
114                          char *keystr, char *fingerprint)
115 {
116     int ret;
117     HANDLE hin;
118     DWORD savemode, i;
119
120     static const char absentmsg[] =
121         "The server's host key is not cached in the registry. You\n"
122         "have no guarantee that the server is the computer you\n"
123         "think it is.\n"
124         "The server's key fingerprint is:\n"
125         "%s\n"
126         "If you trust this host, enter \"y\" to add the key to\n"
127         "PuTTY's cache and carry on connecting.\n"
128         "If you want to carry on connecting just once, without\n"
129         "adding the key to the cache, enter \"n\".\n"
130         "If you do not trust this host, press Return to abandon the\n"
131         "connection.\n"
132         "Store key in cache? (y/n) ";
133
134     static const char wrongmsg[] =
135         "WARNING - POTENTIAL SECURITY BREACH!\n"
136         "The server's host key does not match the one PuTTY has\n"
137         "cached in the registry. This means that either the\n"
138         "server administrator has changed the host key, or you\n"
139         "have actually connected to another computer pretending\n"
140         "to be the server.\n"
141         "The new key fingerprint is:\n"
142         "%s\n"
143         "If you were expecting this change and trust the new key,\n"
144         "enter \"y\" to update PuTTY's cache and continue connecting.\n"
145         "If you want to carry on connecting but without updating\n"
146         "the cache, enter \"n\".\n"
147         "If you want to abandon the connection completely, press\n"
148         "Return to cancel. Pressing Return is the ONLY guaranteed\n"
149         "safe choice.\n"
150         "Update cached key? (y/n, Return cancels connection) ";
151
152     static const char abandoned[] = "Connection abandoned.\n";
153
154     char line[32];
155
156     /*
157      * Verify the key against the registry.
158      */
159     ret = verify_host_key(host, port, keytype, keystr);
160
161     if (ret == 0)                      /* success - key matched OK */
162         return;
163
164     if (ret == 2) {                    /* key was different */
165         fprintf(stderr, wrongmsg, fingerprint);
166         fflush(stderr);
167     }
168     if (ret == 1) {                    /* key was absent */
169         fprintf(stderr, absentmsg, fingerprint);
170         fflush(stderr);
171     }
172
173     hin = GetStdHandle(STD_INPUT_HANDLE);
174     GetConsoleMode(hin, &savemode);
175     SetConsoleMode(hin, (savemode | ENABLE_ECHO_INPUT |
176                          ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT));
177     ReadFile(hin, line, sizeof(line) - 1, &i, NULL);
178     SetConsoleMode(hin, savemode);
179
180     if (line[0] != '\0' && line[0] != '\r' && line[0] != '\n') {
181         if (line[0] == 'y' || line[0] == 'Y')
182             store_host_key(host, port, keytype, keystr);
183     } else {
184         fprintf(stderr, abandoned);
185         exit(0);
186     }
187 }
188
189 /*
190  * Ask whether the selected cipher is acceptable (since it was
191  * below the configured 'warn' threshold).
192  * cs: 0 = both ways, 1 = client->server, 2 = server->client
193  */
194 void askcipher(char *ciphername, int cs)
195 {
196     HANDLE hin;
197     DWORD savemode, i;
198
199     static const char msg[] =
200         "The first %scipher supported by the server is\n"
201         "%s, which is below the configured warning threshold.\n"
202         "Continue with connection? (y/n) ";
203     static const char abandoned[] = "Connection abandoned.\n";
204
205     char line[32];
206
207     fprintf(stderr, msg,
208             (cs == 0) ? "" :
209             (cs == 1) ? "client-to-server " :
210                         "server-to-client ",
211             ciphername);
212     fflush(stderr);
213
214     hin = GetStdHandle(STD_INPUT_HANDLE);
215     GetConsoleMode(hin, &savemode);
216     SetConsoleMode(hin, (savemode | ENABLE_ECHO_INPUT |
217                          ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT));
218     ReadFile(hin, line, sizeof(line) - 1, &i, NULL);
219     SetConsoleMode(hin, savemode);
220
221     if (line[0] == 'y' || line[0] == 'Y') {
222         return;
223     } else {
224         fprintf(stderr, abandoned);
225         exit(0);
226     }
227 }
228
229 /*
230  * Warn about the obsolescent key file format.
231  */
232 void old_keyfile_warning(void)
233 {
234     static const char message[] =
235         "You are loading an SSH 2 private key which has an\n"
236         "old version of the file format. This means your key\n"
237         "file is not fully tamperproof. Future versions of\n"
238         "PuTTY may stop supporting this private key format,\n"
239         "so we recommend you convert your key to the new\n"
240         "format.\n"
241         "\n"
242         "Once the key is loaded into PuTTYgen, you can perform\n"
243         "this conversion simply by saving it again.\n";
244
245     fputs(message, stderr);
246 }
247
248 /* GUI Adaptation - Sept 2000 */
249 static void send_msg(HWND h, UINT message, WPARAM wParam)
250 {
251     while (!PostMessage(h, message, wParam, 0))
252         SleepEx(1000, TRUE);
253 }
254
255 static void tell_char(FILE * stream, char c)
256 {
257     if (!gui_mode)
258         fputc(c, stream);
259     else {
260         unsigned int msg_id = WM_STD_OUT_CHAR;
261         if (stream == stderr)
262             msg_id = WM_STD_ERR_CHAR;
263         send_msg((HWND) atoi(gui_hwnd), msg_id, (WPARAM) c);
264     }
265 }
266
267 static void tell_str(FILE * stream, char *str)
268 {
269     unsigned int i;
270
271     for (i = 0; i < strlen(str); ++i)
272         tell_char(stream, str[i]);
273 }
274
275 static void tell_user(FILE * stream, char *fmt, ...)
276 {
277     char str[0x100];                   /* Make the size big enough */
278     va_list ap;
279     va_start(ap, fmt);
280     vsprintf(str, fmt, ap);
281     va_end(ap);
282     strcat(str, "\n");
283     tell_str(stream, str);
284 }
285
286 static void gui_update_stats(char *name, unsigned long size,
287                              int percentage, unsigned long elapsed,
288                              unsigned long done, unsigned long eta,
289                              unsigned long ratebs)
290 {
291     unsigned int i;
292
293     if (strcmp(name, statname) != 0) {
294         for (i = 0; i < strlen(name); ++i)
295             send_msg((HWND) atoi(gui_hwnd), WM_STATS_CHAR,
296                      (WPARAM) name[i]);
297         send_msg((HWND) atoi(gui_hwnd), WM_STATS_CHAR, (WPARAM) '\n');
298         strcpy(statname, name);
299     }
300     if (statsize != size) {
301         send_msg((HWND) atoi(gui_hwnd), WM_STATS_SIZE, (WPARAM) size);
302         statsize = size;
303     }
304     if (statdone != done) {
305         send_msg((HWND) atoi(gui_hwnd), WM_STATS_DONE, (WPARAM) done);
306         statdone = done;
307     }
308     if (stateta != eta) {
309         send_msg((HWND) atoi(gui_hwnd), WM_STATS_ETA, (WPARAM) eta);
310         stateta = eta;
311     }
312     if (statratebs != ratebs) {
313         send_msg((HWND) atoi(gui_hwnd), WM_STATS_RATEBS, (WPARAM) ratebs);
314         statratebs = ratebs;
315     }
316     if (statelapsed != elapsed) {
317         send_msg((HWND) atoi(gui_hwnd), WM_STATS_ELAPSED,
318                  (WPARAM) elapsed);
319         statelapsed = elapsed;
320     }
321     if (statperct != percentage) {
322         send_msg((HWND) atoi(gui_hwnd), WM_STATS_PERCENT,
323                  (WPARAM) percentage);
324         statperct = percentage;
325     }
326 }
327
328 /*
329  *  Print an error message and perform a fatal exit.
330  */
331 void fatalbox(char *fmt, ...)
332 {
333     char str[0x100];                   /* Make the size big enough */
334     va_list ap;
335     va_start(ap, fmt);
336     strcpy(str, "Fatal: ");
337     vsprintf(str + strlen(str), fmt, ap);
338     va_end(ap);
339     strcat(str, "\n");
340     tell_str(stderr, str);
341     errs++;
342
343     if (gui_mode) {
344         unsigned int msg_id = WM_RET_ERR_CNT;
345         if (list)
346             msg_id = WM_LS_RET_ERR_CNT;
347         while (!PostMessage
348                ((HWND) atoi(gui_hwnd), msg_id, (WPARAM) errs,
349                 0 /*lParam */ ))SleepEx(1000, TRUE);
350     }
351
352     exit(1);
353 }
354 void connection_fatal(char *fmt, ...)
355 {
356     char str[0x100];                   /* Make the size big enough */
357     va_list ap;
358     va_start(ap, fmt);
359     strcpy(str, "Fatal: ");
360     vsprintf(str + strlen(str), fmt, ap);
361     va_end(ap);
362     strcat(str, "\n");
363     tell_str(stderr, str);
364     errs++;
365
366     if (gui_mode) {
367         unsigned int msg_id = WM_RET_ERR_CNT;
368         if (list)
369             msg_id = WM_LS_RET_ERR_CNT;
370         while (!PostMessage
371                ((HWND) atoi(gui_hwnd), msg_id, (WPARAM) errs,
372                 0 /*lParam */ ))SleepEx(1000, TRUE);
373     }
374
375     exit(1);
376 }
377
378 /*
379  * Be told what socket we're supposed to be using.
380  */
381 static SOCKET scp_ssh_socket;
382 char *do_select(SOCKET skt, int startup)
383 {
384     if (startup)
385         scp_ssh_socket = skt;
386     else
387         scp_ssh_socket = INVALID_SOCKET;
388     return NULL;
389 }
390 extern int select_result(WPARAM, LPARAM);
391
392 /*
393  * Receive a block of data from the SSH link. Block until all data
394  * is available.
395  *
396  * To do this, we repeatedly call the SSH protocol module, with our
397  * own trap in from_backend() to catch the data that comes back. We
398  * do this until we have enough data.
399  */
400
401 static unsigned char *outptr;          /* where to put the data */
402 static unsigned outlen;                /* how much data required */
403 static unsigned char *pending = NULL;  /* any spare data */
404 static unsigned pendlen = 0, pendsize = 0;      /* length and phys. size of buffer */
405 int from_backend(int is_stderr, char *data, int datalen)
406 {
407     unsigned char *p = (unsigned char *) data;
408     unsigned len = (unsigned) datalen;
409
410     /*
411      * stderr data is just spouted to local stderr and otherwise
412      * ignored.
413      */
414     if (is_stderr) {
415         fwrite(data, 1, len, stderr);
416         return 0;
417     }
418
419     /*
420      * If this is before the real session begins, just return.
421      */
422     if (!outptr)
423         return 0;
424
425     if (outlen > 0) {
426         unsigned used = outlen;
427         if (used > len)
428             used = len;
429         memcpy(outptr, p, used);
430         outptr += used;
431         outlen -= used;
432         p += used;
433         len -= used;
434     }
435
436     if (len > 0) {
437         if (pendsize < pendlen + len) {
438             pendsize = pendlen + len + 4096;
439             pending = (pending ? srealloc(pending, pendsize) :
440                        smalloc(pendsize));
441             if (!pending)
442                 fatalbox("Out of memory");
443         }
444         memcpy(pending + pendlen, p, len);
445         pendlen += len;
446     }
447
448     return 0;
449 }
450 static int scp_process_network_event(void)
451 {
452     fd_set readfds;
453
454     FD_ZERO(&readfds);
455     FD_SET(scp_ssh_socket, &readfds);
456     if (select(1, &readfds, NULL, NULL, NULL) < 0)
457         return 0;                      /* doom */
458     select_result((WPARAM) scp_ssh_socket, (LPARAM) FD_READ);
459     return 1;
460 }
461 static int ssh_scp_recv(unsigned char *buf, int len)
462 {
463     outptr = buf;
464     outlen = len;
465
466     /*
467      * See if the pending-input block contains some of what we
468      * need.
469      */
470     if (pendlen > 0) {
471         unsigned pendused = pendlen;
472         if (pendused > outlen)
473             pendused = outlen;
474         memcpy(outptr, pending, pendused);
475         memmove(pending, pending + pendused, pendlen - pendused);
476         outptr += pendused;
477         outlen -= pendused;
478         pendlen -= pendused;
479         if (pendlen == 0) {
480             pendsize = 0;
481             sfree(pending);
482             pending = NULL;
483         }
484         if (outlen == 0)
485             return len;
486     }
487
488     while (outlen > 0) {
489         if (!scp_process_network_event())
490             return 0;                  /* doom */
491     }
492
493     return len;
494 }
495
496 /*
497  * Loop through the ssh connection and authentication process.
498  */
499 static void ssh_scp_init(void)
500 {
501     if (scp_ssh_socket == INVALID_SOCKET)
502         return;
503     while (!back->sendok()) {
504         fd_set readfds;
505         FD_ZERO(&readfds);
506         FD_SET(scp_ssh_socket, &readfds);
507         if (select(1, &readfds, NULL, NULL, NULL) < 0)
508             return;                    /* doom */
509         select_result((WPARAM) scp_ssh_socket, (LPARAM) FD_READ);
510     }
511     using_sftp = !ssh_fallback_cmd;
512 }
513
514 /*
515  *  Print an error message and exit after closing the SSH link.
516  */
517 static void bump(char *fmt, ...)
518 {
519     char str[0x100];                   /* Make the size big enough */
520     va_list ap;
521     va_start(ap, fmt);
522     strcpy(str, "Fatal: ");
523     vsprintf(str + strlen(str), fmt, ap);
524     va_end(ap);
525     strcat(str, "\n");
526     tell_str(stderr, str);
527     errs++;
528
529     if (back != NULL && back->socket() != NULL) {
530         char ch;
531         back->special(TS_EOF);
532         ssh_scp_recv(&ch, 1);
533     }
534
535     if (gui_mode) {
536         unsigned int msg_id = WM_RET_ERR_CNT;
537         if (list)
538             msg_id = WM_LS_RET_ERR_CNT;
539         while (!PostMessage
540                ((HWND) atoi(gui_hwnd), msg_id, (WPARAM) errs,
541                 0 /*lParam */ ))SleepEx(1000, TRUE);
542     }
543
544     exit(1);
545 }
546
547 static int get_line(const char *prompt, char *str, int maxlen, int is_pw)
548 {
549     HANDLE hin, hout;
550     DWORD savemode, newmode, i;
551
552     if (is_pw && password) {
553         static int tried_once = 0;
554
555         if (tried_once) {
556             return 0;
557         } else {
558             strncpy(str, password, maxlen);
559             str[maxlen - 1] = '\0';
560             tried_once = 1;
561             return 1;
562         }
563     }
564
565     /* GUI Adaptation - Sept 2000 */
566     if (gui_mode) {
567         if (maxlen > 0)
568             str[0] = '\0';
569     } else {
570         hin = GetStdHandle(STD_INPUT_HANDLE);
571         hout = GetStdHandle(STD_OUTPUT_HANDLE);
572         if (hin == INVALID_HANDLE_VALUE || hout == INVALID_HANDLE_VALUE)
573             bump("Cannot get standard input/output handles");
574
575         GetConsoleMode(hin, &savemode);
576         newmode = savemode | ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT;
577         if (is_pw)
578             newmode &= ~ENABLE_ECHO_INPUT;
579         else
580             newmode |= ENABLE_ECHO_INPUT;
581         SetConsoleMode(hin, newmode);
582
583         WriteFile(hout, prompt, strlen(prompt), &i, NULL);
584         ReadFile(hin, str, maxlen - 1, &i, NULL);
585
586         SetConsoleMode(hin, savemode);
587
588         if ((int) i > maxlen)
589             i = maxlen - 1;
590         else
591             i = i - 2;
592         str[i] = '\0';
593
594         if (is_pw)
595             WriteFile(hout, "\r\n", 2, &i, NULL);
596     }
597
598     return 1;
599 }
600
601 /*
602  *  Open an SSH connection to user@host and execute cmd.
603  */
604 static void do_cmd(char *host, char *user, char *cmd)
605 {
606     char *err, *realhost;
607     DWORD namelen;
608
609     if (host == NULL || host[0] == '\0')
610         bump("Empty host name");
611
612     /* Try to load settings for this host */
613     do_defaults(host, &cfg);
614     if (cfg.host[0] == '\0') {
615         /* No settings for this host; use defaults */
616         do_defaults(NULL, &cfg);
617         strncpy(cfg.host, host, sizeof(cfg.host) - 1);
618         cfg.host[sizeof(cfg.host) - 1] = '\0';
619         cfg.port = 22;
620     }
621
622     /*
623      * Trim leading whitespace off the hostname if it's there.
624      */
625     {
626         int space = strspn(cfg.host, " \t");
627         memmove(cfg.host, cfg.host+space, 1+strlen(cfg.host)-space);
628     }
629
630     /* See if host is of the form user@host */
631     if (cfg.host[0] != '\0') {
632         char *atsign = strchr(cfg.host, '@');
633         /* Make sure we're not overflowing the user field */
634         if (atsign) {
635             if (atsign - cfg.host < sizeof cfg.username) {
636                 strncpy(cfg.username, cfg.host, atsign - cfg.host);
637                 cfg.username[atsign - cfg.host] = '\0';
638             }
639             memmove(cfg.host, atsign + 1, 1 + strlen(atsign + 1));
640         }
641     }
642
643     /*
644      * Trim a colon suffix off the hostname if it's there.
645      */
646     cfg.host[strcspn(cfg.host, ":")] = '\0';
647
648     /* Set username */
649     if (user != NULL && user[0] != '\0') {
650         strncpy(cfg.username, user, sizeof(cfg.username) - 1);
651         cfg.username[sizeof(cfg.username) - 1] = '\0';
652     } else if (cfg.username[0] == '\0') {
653         namelen = 0;
654         if (GetUserName(user, &namelen) == FALSE)
655             bump("Empty user name");
656         user = smalloc(namelen * sizeof(char));
657         GetUserName(user, &namelen);
658         if (verbose)
659             tell_user(stderr, "Guessing user name: %s", user);
660         strncpy(cfg.username, user, sizeof(cfg.username) - 1);
661         cfg.username[sizeof(cfg.username) - 1] = '\0';
662         free(user);
663     }
664
665     if (cfg.protocol != PROT_SSH)
666         cfg.port = 22;
667
668     if (portnumber)
669         cfg.port = portnumber;
670
671     /*
672      * Disable scary things which shouldn't be enabled for simple
673      * things like SCP and SFTP: agent forwarding, port forwarding,
674      * X forwarding.
675      */
676     cfg.x11_forward = 0;
677     cfg.agentfwd = 0;
678     cfg.portfwd[0] = cfg.portfwd[1] = '\0';
679
680     /*
681      * Attempt to start the SFTP subsystem as a first choice,
682      * falling back to the provided scp command if that fails.
683      */
684     strcpy(cfg.remote_cmd, "sftp");
685     cfg.ssh_subsys = TRUE;
686     cfg.remote_cmd_ptr2 = cmd;
687     cfg.ssh_subsys2 = FALSE;
688     cfg.nopty = TRUE;
689
690     back = &ssh_backend;
691
692     err = back->init(cfg.host, cfg.port, &realhost, 0);
693     if (err != NULL)
694         bump("ssh_init: %s", err);
695     ssh_scp_init();
696     if (verbose && realhost != NULL)
697         tell_user(stderr, "Connected to %s\n", realhost);
698     sfree(realhost);
699 }
700
701 /*
702  *  Update statistic information about current file.
703  */
704 static void print_stats(char *name, unsigned long size, unsigned long done,
705                         time_t start, time_t now)
706 {
707     float ratebs;
708     unsigned long eta;
709     char etastr[10];
710     int pct;
711     int len;
712     int elap;
713
714     elap = (unsigned long) difftime(now, start);
715
716     if (now > start)
717         ratebs = (float) done / elap;
718     else
719         ratebs = (float) done;
720
721     if (ratebs < 1.0)
722         eta = size - done;
723     else
724         eta = (unsigned long) ((size - done) / ratebs);
725     sprintf(etastr, "%02ld:%02ld:%02ld",
726             eta / 3600, (eta % 3600) / 60, eta % 60);
727
728     pct = (int) (100 * (done * 1.0 / size));
729
730     if (gui_mode)
731         /* GUI Adaptation - Sept 2000 */
732         gui_update_stats(name, size, pct, elap, done, eta, 
733                          (unsigned long) ratebs);
734     else {
735         len = printf("\r%-25.25s | %10ld kB | %5.1f kB/s | ETA: %8s | %3d%%",
736                      name, done / 1024, ratebs / 1024.0, etastr, pct);
737         if (len < prev_stats_len)
738             printf("%*s", prev_stats_len - len, "");
739         prev_stats_len = len;
740
741         if (done == size)
742             printf("\n");
743     }
744 }
745
746 /*
747  *  Find a colon in str and return a pointer to the colon.
748  *  This is used to separate hostname from filename.
749  */
750 static char *colon(char *str)
751 {
752     /* We ignore a leading colon, since the hostname cannot be
753        empty. We also ignore a colon as second character because
754        of filenames like f:myfile.txt. */
755     if (str[0] == '\0' || str[0] == ':' || str[1] == ':')
756         return (NULL);
757     while (*str != '\0' && *str != ':' && *str != '/' && *str != '\\')
758         str++;
759     if (*str == ':')
760         return (str);
761     else
762         return (NULL);
763 }
764
765 /*
766  * Return a pointer to the portion of str that comes after the last
767  * slash (or backslash or colon, if `local' is TRUE).
768  */
769 static char *stripslashes(char *str, int local)
770 {
771     char *p;
772
773     if (local) {
774         p = strchr(str, ':');
775         if (p) str = p+1;
776     }
777
778     p = strrchr(str, '/');
779     if (p) str = p+1;
780
781     if (local) {
782         p = strrchr(str, '\\');
783         if (p) str = p+1;
784     }
785
786     return str;
787 }
788
789 /*
790  * Determine whether a string is entirely composed of dots.
791  */
792 static int is_dots(char *str)
793 {
794     return str[strspn(str, ".")] == '\0';
795 }
796
797 /*
798  *  Wait for a response from the other side.
799  *  Return 0 if ok, -1 if error.
800  */
801 static int response(void)
802 {
803     char ch, resp, rbuf[2048];
804     int p;
805
806     if (ssh_scp_recv(&resp, 1) <= 0)
807         bump("Lost connection");
808
809     p = 0;
810     switch (resp) {
811       case 0:                          /* ok */
812         return (0);
813       default:
814         rbuf[p++] = resp;
815         /* fallthrough */
816       case 1:                          /* error */
817       case 2:                          /* fatal error */
818         do {
819             if (ssh_scp_recv(&ch, 1) <= 0)
820                 bump("Protocol error: Lost connection");
821             rbuf[p++] = ch;
822         } while (p < sizeof(rbuf) && ch != '\n');
823         rbuf[p - 1] = '\0';
824         if (resp == 1)
825             tell_user(stderr, "%s\n", rbuf);
826         else
827             bump("%s", rbuf);
828         errs++;
829         return (-1);
830     }
831 }
832
833 int sftp_recvdata(char *buf, int len)
834 {
835     return ssh_scp_recv(buf, len);
836 }
837 int sftp_senddata(char *buf, int len)
838 {
839     back->send((unsigned char *) buf, len);
840     return 1;
841 }
842
843 /* ----------------------------------------------------------------------
844  * sftp-based replacement for the hacky `pscp -ls'.
845  */
846 static int sftp_ls_compare(const void *av, const void *bv)
847 {
848     const struct fxp_name *a = (const struct fxp_name *) av;
849     const struct fxp_name *b = (const struct fxp_name *) bv;
850     return strcmp(a->filename, b->filename);
851 }
852 void scp_sftp_listdir(char *dirname)
853 {
854     struct fxp_handle *dirh;
855     struct fxp_names *names;
856     struct fxp_name *ournames;
857     int nnames, namesize;
858     int i;
859
860     printf("Listing directory %s\n", dirname);
861
862     dirh = fxp_opendir(dirname);
863     if (dirh == NULL) {
864         printf("Unable to open %s: %s\n", dirname, fxp_error());
865     } else {
866         nnames = namesize = 0;
867         ournames = NULL;
868
869         while (1) {
870
871             names = fxp_readdir(dirh);
872             if (names == NULL) {
873                 if (fxp_error_type() == SSH_FX_EOF)
874                     break;
875                 printf("Reading directory %s: %s\n", dirname, fxp_error());
876                 break;
877             }
878             if (names->nnames == 0) {
879                 fxp_free_names(names);
880                 break;
881             }
882
883             if (nnames + names->nnames >= namesize) {
884                 namesize += names->nnames + 128;
885                 ournames =
886                     srealloc(ournames, namesize * sizeof(*ournames));
887             }
888
889             for (i = 0; i < names->nnames; i++)
890                 ournames[nnames++] = names->names[i];
891
892             names->nnames = 0;         /* prevent free_names */
893             fxp_free_names(names);
894         }
895         fxp_close(dirh);
896
897         /*
898          * Now we have our filenames. Sort them by actual file
899          * name, and then output the longname parts.
900          */
901         qsort(ournames, nnames, sizeof(*ournames), sftp_ls_compare);
902
903         /*
904          * And print them.
905          */
906         for (i = 0; i < nnames; i++)
907             printf("%s\n", ournames[i].longname);
908     }
909 }
910
911 /* ----------------------------------------------------------------------
912  * Helper routines that contain the actual SCP protocol elements,
913  * implemented both as SCP1 and SFTP.
914  */
915
916 static struct scp_sftp_dirstack {
917     struct scp_sftp_dirstack *next;
918     struct fxp_name *names;
919     int namepos, namelen;
920     char *dirpath;
921     char *wildcard;
922     int matched_something;             /* wildcard match set was non-empty */
923 } *scp_sftp_dirstack_head;
924 static char *scp_sftp_remotepath, *scp_sftp_currentname;
925 static char *scp_sftp_wildcard;
926 static int scp_sftp_targetisdir, scp_sftp_donethistarget;
927 static int scp_sftp_preserve, scp_sftp_recursive;
928 static unsigned long scp_sftp_mtime, scp_sftp_atime;
929 static int scp_has_times;
930 static struct fxp_handle *scp_sftp_filehandle;
931 static uint64 scp_sftp_fileoffset;
932
933 void scp_source_setup(char *target, int shouldbedir)
934 {
935     if (using_sftp) {
936         /*
937          * Find out whether the target filespec is in fact a
938          * directory.
939          */
940         struct fxp_attrs attrs;
941
942         if (!fxp_stat(target, &attrs) ||
943             !(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS))
944             scp_sftp_targetisdir = 0;
945         else
946             scp_sftp_targetisdir = (attrs.permissions & 0040000) != 0;
947
948         if (shouldbedir && !scp_sftp_targetisdir) {
949             bump("pscp: remote filespec %s: not a directory\n", target);
950         }
951
952         scp_sftp_remotepath = dupstr(target);
953
954         scp_has_times = 0;
955     } else {
956         (void) response();
957     }
958 }
959
960 int scp_send_errmsg(char *str)
961 {
962     if (using_sftp) {
963         /* do nothing; we never need to send our errors to the server */
964     } else {
965         back->send("\001", 1);         /* scp protocol error prefix */
966         back->send(str, strlen(str));
967     }
968     return 0;                          /* can't fail */
969 }
970
971 int scp_send_filetimes(unsigned long mtime, unsigned long atime)
972 {
973     if (using_sftp) {
974         scp_sftp_mtime = mtime;
975         scp_sftp_atime = atime;
976         scp_has_times = 1;
977         return 0;
978     } else {
979         char buf[80];
980         sprintf(buf, "T%lu 0 %lu 0\n", mtime, atime);
981         back->send(buf, strlen(buf));
982         return response();
983     }
984 }
985
986 int scp_send_filename(char *name, unsigned long size, int modes)
987 {
988     if (using_sftp) {
989         char *fullname;
990         if (scp_sftp_targetisdir) {
991             fullname = dupcat(scp_sftp_remotepath, "/", name, NULL);
992         } else {
993             fullname = dupstr(scp_sftp_remotepath);
994         }
995         scp_sftp_filehandle =
996             fxp_open(fullname, SSH_FXF_WRITE | SSH_FXF_CREAT | SSH_FXF_TRUNC);
997         if (!scp_sftp_filehandle) {
998             tell_user(stderr, "pscp: unable to open %s: %s",
999                       fullname, fxp_error());
1000             errs++;
1001             return 1;
1002         }
1003         scp_sftp_fileoffset = uint64_make(0, 0);
1004         sfree(fullname);
1005         return 0;
1006     } else {
1007         char buf[40];
1008         sprintf(buf, "C%04o %lu ", modes, size);
1009         back->send(buf, strlen(buf));
1010         back->send(name, strlen(name));
1011         back->send("\n", 1);
1012         return response();
1013     }
1014 }
1015
1016 int scp_send_filedata(char *data, int len)
1017 {
1018     if (using_sftp) {
1019         if (!scp_sftp_filehandle) {
1020             return 1;
1021         }
1022         if (!fxp_write(scp_sftp_filehandle, data, scp_sftp_fileoffset, len)) {
1023             tell_user(stderr, "error while writing: %s\n", fxp_error());
1024             errs++;
1025             return 1;
1026         }
1027         scp_sftp_fileoffset = uint64_add32(scp_sftp_fileoffset, len);
1028         return 0;
1029     } else {
1030         int bufsize = back->send(data, len);
1031
1032         /*
1033          * If the network transfer is backing up - that is, the
1034          * remote site is not accepting data as fast as we can
1035          * produce it - then we must loop on network events until
1036          * we have space in the buffer again.
1037          */
1038         while (bufsize > MAX_SCP_BUFSIZE) {
1039             if (!scp_process_network_event())
1040                 return 1;
1041             bufsize = back->sendbuffer();
1042         }
1043
1044         return 0;
1045     }
1046 }
1047
1048 int scp_send_finish(void)
1049 {
1050     if (using_sftp) {
1051         struct fxp_attrs attrs;
1052         if (!scp_sftp_filehandle) {
1053             return 1;
1054         }
1055         if (scp_has_times) {
1056             attrs.flags = SSH_FILEXFER_ATTR_ACMODTIME;
1057             attrs.atime = scp_sftp_atime;
1058             attrs.mtime = scp_sftp_mtime;
1059             if (!fxp_fsetstat(scp_sftp_filehandle, attrs)) {
1060                 tell_user(stderr, "unable to set file times: %s\n", fxp_error());
1061                 errs++;
1062             }
1063         }
1064         fxp_close(scp_sftp_filehandle);
1065         scp_has_times = 0;
1066         return 0;
1067     } else {
1068         back->send("", 1);
1069         return response();
1070     }
1071 }
1072
1073 char *scp_save_remotepath(void)
1074 {
1075     if (using_sftp)
1076         return scp_sftp_remotepath;
1077     else
1078         return NULL;
1079 }
1080
1081 void scp_restore_remotepath(char *data)
1082 {
1083     if (using_sftp)
1084         scp_sftp_remotepath = data;
1085 }
1086
1087 int scp_send_dirname(char *name, int modes)
1088 {
1089     if (using_sftp) {
1090         char *fullname;
1091         char const *err;
1092         struct fxp_attrs attrs;
1093         if (scp_sftp_targetisdir) {
1094             fullname = dupcat(scp_sftp_remotepath, "/", name, NULL);
1095         } else {
1096             fullname = dupstr(scp_sftp_remotepath);
1097         }
1098
1099         /*
1100          * We don't worry about whether we managed to create the
1101          * directory, because if it exists already it's OK just to
1102          * use it. Instead, we will stat it afterwards, and if it
1103          * exists and is a directory we will assume we were either
1104          * successful or it didn't matter.
1105          */
1106         if (!fxp_mkdir(fullname))
1107             err = fxp_error();
1108         else
1109             err = "server reported no error";
1110         if (!fxp_stat(fullname, &attrs) ||
1111             !(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS) ||
1112             !(attrs.permissions & 0040000)) {
1113             tell_user(stderr, "unable to create directory %s: %s",
1114                       fullname, err);
1115             errs++;
1116             return 1;
1117         }
1118
1119         scp_sftp_remotepath = fullname;
1120
1121         return 0;
1122     } else {
1123         char buf[40];
1124         sprintf(buf, "D%04o 0 ", modes);
1125         back->send(buf, strlen(buf));
1126         back->send(name, strlen(name));
1127         back->send("\n", 1);
1128         return response();
1129     }
1130 }
1131
1132 int scp_send_enddir(void)
1133 {
1134     if (using_sftp) {
1135         sfree(scp_sftp_remotepath);
1136         return 0;
1137     } else {
1138         back->send("E\n", 2);
1139         return response();
1140     }
1141 }
1142
1143 /*
1144  * Yes, I know; I have an scp_sink_setup _and_ an scp_sink_init.
1145  * That's bad. The difference is that scp_sink_setup is called once
1146  * right at the start, whereas scp_sink_init is called to
1147  * initialise every level of recursion in the protocol.
1148  */
1149 int scp_sink_setup(char *source, int preserve, int recursive)
1150 {
1151     if (using_sftp) {
1152         char *newsource;
1153         /*
1154          * It's possible that the source string we've been given
1155          * contains a wildcard. If so, we must split the directory
1156          * away from the wildcard itself (throwing an error if any
1157          * wildcardness comes before the final slash) and arrange
1158          * things so that a dirstack entry will be set up.
1159          */
1160         newsource = smalloc(1+strlen(source));
1161         if (!wc_unescape(newsource, source)) {
1162             /* Yes, here we go; it's a wildcard. Bah. */
1163             char *dupsource, *lastpart, *dirpart, *wildcard;
1164             dupsource = dupstr(source);
1165             lastpart = stripslashes(dupsource, 0);
1166             wildcard = dupstr(lastpart);
1167             *lastpart = '\0';
1168             if (*dupsource && dupsource[1]) {
1169                 /*
1170                  * The remains of dupsource are at least two
1171                  * characters long, meaning the pathname wasn't
1172                  * empty or just `/'. Hence, we remove the trailing
1173                  * slash.
1174                  */
1175                 lastpart[-1] = '\0';
1176             } else if (!*dupsource) {
1177                 /*
1178                  * The remains of dupsource are _empty_ - the whole
1179                  * pathname was a wildcard. Hence we need to
1180                  * replace it with ".".
1181                  */
1182                 sfree(dupsource);
1183                 dupsource = dupstr(".");
1184             }
1185
1186             /*
1187              * Now we have separated our string into dupsource (the
1188              * directory part) and wildcard. Both of these will
1189              * need freeing at some point. Next step is to remove
1190              * wildcard escapes from the directory part, throwing
1191              * an error if it contains a real wildcard.
1192              */
1193             dirpart = smalloc(1+strlen(dupsource));
1194             if (!wc_unescape(dirpart, dupsource)) {
1195                 tell_user(stderr, "%s: multiple-level wildcards unsupported",
1196                           source);
1197                 errs++;
1198                 sfree(dirpart);
1199                 sfree(wildcard);
1200                 sfree(dupsource);
1201                 return 1;
1202             }
1203
1204             /*
1205              * Now we have dirpart (unescaped, ie a valid remote
1206              * path), and wildcard (a wildcard). This will be
1207              * sufficient to arrange a dirstack entry.
1208              */
1209             scp_sftp_remotepath = dirpart;
1210             scp_sftp_wildcard = wildcard;
1211             sfree(dupsource);
1212         } else {
1213             scp_sftp_remotepath = newsource;
1214             scp_sftp_wildcard = NULL;
1215         }
1216         scp_sftp_preserve = preserve;
1217         scp_sftp_recursive = recursive;
1218         scp_sftp_donethistarget = 0;
1219         scp_sftp_dirstack_head = NULL;
1220     }
1221     return 0;
1222 }
1223
1224 int scp_sink_init(void)
1225 {
1226     if (!using_sftp) {
1227         back->send("", 1);
1228     }
1229     return 0;
1230 }
1231
1232 #define SCP_SINK_FILE   1
1233 #define SCP_SINK_DIR    2
1234 #define SCP_SINK_ENDDIR 3
1235 #define SCP_SINK_RETRY  4              /* not an action; just try again */
1236 struct scp_sink_action {
1237     int action;                        /* FILE, DIR, ENDDIR */
1238     char *buf;                         /* will need freeing after use */
1239     char *name;                        /* filename or dirname (not ENDDIR) */
1240     int mode;                          /* access mode (not ENDDIR) */
1241     unsigned long size;                /* file size (not ENDDIR) */
1242     int settime;                       /* 1 if atime and mtime are filled */
1243     unsigned long atime, mtime;        /* access times for the file */
1244 };
1245
1246 int scp_get_sink_action(struct scp_sink_action *act)
1247 {
1248     if (using_sftp) {
1249         char *fname;
1250         int must_free_fname;
1251         struct fxp_attrs attrs;
1252         int ret;
1253
1254         if (!scp_sftp_dirstack_head) {
1255             if (!scp_sftp_donethistarget) {
1256                 /*
1257                  * Simple case: we are only dealing with one file.
1258                  */
1259                 fname = scp_sftp_remotepath;
1260                 must_free_fname = 0;
1261                 scp_sftp_donethistarget = 1;
1262             } else {
1263                 /*
1264                  * Even simpler case: one file _which we've done_.
1265                  * Return 1 (finished).
1266                  */
1267                 return 1;
1268             }
1269         } else {
1270             /*
1271              * We're now in the middle of stepping through a list
1272              * of names returned from fxp_readdir(); so let's carry
1273              * on.
1274              */
1275             struct scp_sftp_dirstack *head = scp_sftp_dirstack_head;
1276             while (head->namepos < head->namelen &&
1277                    (is_dots(head->names[head->namepos].filename) ||
1278                     (head->wildcard &&
1279                      !wc_match(head->wildcard,
1280                                head->names[head->namepos].filename))))
1281                 head->namepos++;       /* skip . and .. */
1282             if (head->namepos < head->namelen) {
1283                 head->matched_something = 1;
1284                 fname = dupcat(head->dirpath, "/",
1285                                head->names[head->namepos++].filename,
1286                                NULL);
1287                 must_free_fname = 1;
1288             } else {
1289                 /*
1290                  * We've come to the end of the list; pop it off
1291                  * the stack and return an ENDDIR action (or RETRY
1292                  * if this was a wildcard match).
1293                  */
1294                 if (head->wildcard) {
1295                     act->action = SCP_SINK_RETRY;
1296                     if (!head->matched_something) {
1297                         tell_user(stderr, "pscp: wildcard '%s' matched "
1298                                   "no files", head->wildcard);
1299                         errs++;
1300                     }
1301                     sfree(head->wildcard);
1302
1303                 } else {
1304                     act->action = SCP_SINK_ENDDIR;
1305                 }
1306
1307                 sfree(head->dirpath);
1308                 sfree(head->names);
1309                 scp_sftp_dirstack_head = head->next;
1310                 sfree(head);
1311
1312                 return 0;
1313             }
1314         }
1315
1316         /*
1317          * Now we have a filename. Stat it, and see if it's a file
1318          * or a directory.
1319          */
1320         ret = fxp_stat(fname, &attrs);
1321         if (!ret || !(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS)) {
1322             tell_user(stderr, "unable to identify %s: %s", fname,
1323                       ret ? "file type not supplied" : fxp_error());
1324             errs++;
1325             return 1;
1326         }
1327
1328         if (attrs.permissions & 0040000) {
1329             struct scp_sftp_dirstack *newitem;
1330             struct fxp_handle *dirhandle;
1331             int nnames, namesize;
1332             struct fxp_name *ournames;
1333             struct fxp_names *names;
1334
1335             /*
1336              * It's a directory. If we're not in recursive mode,
1337              * this merits a complaint (which is fatal if the name
1338              * was specified directly, but not if it was matched by
1339              * a wildcard).
1340              * 
1341              * We skip this complaint completely if
1342              * scp_sftp_wildcard is set, because that's an
1343              * indication that we're not actually supposed to
1344              * _recursively_ transfer the dir, just scan it for
1345              * things matching the wildcard.
1346              */
1347             if (!scp_sftp_recursive && !scp_sftp_wildcard) {
1348                 tell_user(stderr, "pscp: %s: is a directory", fname);
1349                 errs++;
1350                 if (must_free_fname) sfree(fname);
1351                 if (scp_sftp_dirstack_head) {
1352                     act->action = SCP_SINK_RETRY;
1353                     return 0;
1354                 } else {
1355                     return 1;
1356                 }
1357             }
1358
1359             /*
1360              * Otherwise, the fun begins. We must fxp_opendir() the
1361              * directory, slurp the filenames into memory, return
1362              * SCP_SINK_DIR (unless this is a wildcard match), and
1363              * set targetisdir. The next time we're called, we will
1364              * run through the list of filenames one by one,
1365              * matching them against a wildcard if present.
1366              * 
1367              * If targetisdir is _already_ set (meaning we're
1368              * already in the middle of going through another such
1369              * list), we must push the other (target,namelist) pair
1370              * on a stack.
1371              */
1372             dirhandle = fxp_opendir(fname);
1373             if (!dirhandle) {
1374                 tell_user(stderr, "scp: unable to open directory %s: %s",
1375                           fname, fxp_error());
1376                 if (must_free_fname) sfree(fname);
1377                 errs++;
1378                 return 1;
1379             }
1380             nnames = namesize = 0;
1381             ournames = NULL;
1382             while (1) {
1383                 int i;
1384
1385                 names = fxp_readdir(dirhandle);
1386                 if (names == NULL) {
1387                     if (fxp_error_type() == SSH_FX_EOF)
1388                         break;
1389                     tell_user(stderr, "scp: reading directory %s: %s\n",
1390                               fname, fxp_error());
1391                     if (must_free_fname) sfree(fname);
1392                     sfree(ournames);
1393                     errs++;
1394                     return 1;
1395                 }
1396                 if (names->nnames == 0) {
1397                     fxp_free_names(names);
1398                     break;
1399                 }
1400                 if (nnames + names->nnames >= namesize) {
1401                     namesize += names->nnames + 128;
1402                     ournames =
1403                         srealloc(ournames, namesize * sizeof(*ournames));
1404                 }
1405                 for (i = 0; i < names->nnames; i++)
1406                     ournames[nnames++] = names->names[i];
1407                 names->nnames = 0;             /* prevent free_names */
1408                 fxp_free_names(names);
1409             }
1410             fxp_close(dirhandle);
1411
1412             newitem = smalloc(sizeof(struct scp_sftp_dirstack));
1413             newitem->next = scp_sftp_dirstack_head;
1414             newitem->names = ournames;
1415             newitem->namepos = 0;
1416             newitem->namelen = nnames;
1417             if (must_free_fname)
1418                 newitem->dirpath = fname;
1419             else
1420                 newitem->dirpath = dupstr(fname);
1421             if (scp_sftp_wildcard) {
1422                 newitem->wildcard = scp_sftp_wildcard;
1423                 newitem->matched_something = 0;
1424                 scp_sftp_wildcard = NULL;
1425             } else {
1426                 newitem->wildcard = NULL;
1427             }
1428             scp_sftp_dirstack_head = newitem;
1429
1430             if (newitem->wildcard) {
1431                 act->action = SCP_SINK_RETRY;
1432             } else {
1433                 act->action = SCP_SINK_DIR;
1434                 act->buf = dupstr(stripslashes(fname, 0));
1435                 act->name = act->buf;
1436                 act->size = 0;         /* duhh, it's a directory */
1437                 act->mode = 07777 & attrs.permissions;
1438                 if (scp_sftp_preserve &&
1439                     (attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME)) {
1440                     act->atime = attrs.atime;
1441                     act->mtime = attrs.mtime;
1442                     act->settime = 1;
1443                 } else
1444                     act->settime = 0;
1445             }
1446             return 0;
1447
1448         } else {
1449             /*
1450              * It's a file. Return SCP_SINK_FILE.
1451              */
1452             act->action = SCP_SINK_FILE;
1453             act->buf = dupstr(stripslashes(fname, 0));
1454             act->name = act->buf;
1455             if (attrs.flags & SSH_FILEXFER_ATTR_SIZE) {
1456                 if (uint64_compare(attrs.size,
1457                                    uint64_make(0, ULONG_MAX)) > 0) {
1458                     act->size = ULONG_MAX;   /* *boggle* */
1459                 } else
1460                     act->size = attrs.size.lo;
1461             } else
1462                 act->size = ULONG_MAX;   /* no idea */
1463             act->mode = 07777 & attrs.permissions;
1464             if (scp_sftp_preserve &&
1465                 (attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME)) {
1466                 act->atime = attrs.atime;
1467                 act->mtime = attrs.mtime;
1468                 act->settime = 1;
1469             } else
1470                 act->settime = 0;
1471             if (must_free_fname)
1472                 scp_sftp_currentname = fname;
1473             else
1474                 scp_sftp_currentname = dupstr(fname);
1475             return 0;
1476         }
1477
1478     } else {
1479         int done = 0;
1480         int i, bufsize;
1481         int action;
1482         char ch;
1483
1484         act->settime = 0;
1485         act->buf = NULL;
1486         bufsize = 0;
1487
1488         while (!done) {
1489             if (ssh_scp_recv(&ch, 1) <= 0)
1490                 return 1;
1491             if (ch == '\n')
1492                 bump("Protocol error: Unexpected newline");
1493             i = 0;
1494             action = ch;
1495             do {
1496                 if (ssh_scp_recv(&ch, 1) <= 0)
1497                     bump("Lost connection");
1498                 if (i >= bufsize) {
1499                     bufsize = i + 128;
1500                     act->buf = srealloc(act->buf, bufsize);
1501                 }
1502                 act->buf[i++] = ch;
1503             } while (ch != '\n');
1504             act->buf[i - 1] = '\0';
1505             switch (action) {
1506               case '\01':                      /* error */
1507                 tell_user(stderr, "%s\n", act->buf);
1508                 errs++;
1509                 continue;                      /* go round again */
1510               case '\02':                      /* fatal error */
1511                 bump("%s", act->buf);
1512               case 'E':
1513                 back->send("", 1);
1514                 act->action = SCP_SINK_ENDDIR;
1515                 return 0;
1516               case 'T':
1517                 if (sscanf(act->buf, "%ld %*d %ld %*d",
1518                            &act->mtime, &act->atime) == 2) {
1519                     act->settime = 1;
1520                     back->send("", 1);
1521                     continue;          /* go round again */
1522                 }
1523                 bump("Protocol error: Illegal time format");
1524               case 'C':
1525               case 'D':
1526                 act->action = (action == 'C' ? SCP_SINK_FILE : SCP_SINK_DIR);
1527                 break;
1528               default:
1529                 bump("Protocol error: Expected control record");
1530             }
1531             /*
1532              * We will go round this loop only once, unless we hit
1533              * `continue' above.
1534              */
1535             done = 1;
1536         }
1537
1538         /*
1539          * If we get here, we must have seen SCP_SINK_FILE or
1540          * SCP_SINK_DIR.
1541          */
1542         if (sscanf(act->buf, "%o %lu %n", &act->mode, &act->size, &i) != 2)
1543             bump("Protocol error: Illegal file descriptor format");
1544         act->name = act->buf + i;
1545         return 0;
1546     }
1547 }
1548
1549 int scp_accept_filexfer(void)
1550 {
1551     if (using_sftp) {
1552         scp_sftp_filehandle =
1553             fxp_open(scp_sftp_currentname, SSH_FXF_READ);
1554         if (!scp_sftp_filehandle) {
1555             tell_user(stderr, "pscp: unable to open %s: %s",
1556                       scp_sftp_currentname, fxp_error());
1557             errs++;
1558             return 1;
1559         }
1560         scp_sftp_fileoffset = uint64_make(0, 0);
1561         sfree(scp_sftp_currentname);
1562         return 0;
1563     } else {
1564         back->send("", 1);
1565         return 0;                      /* can't fail */
1566     }
1567 }
1568
1569 int scp_recv_filedata(char *data, int len)
1570 {
1571     if (using_sftp) {
1572         int actuallen = fxp_read(scp_sftp_filehandle, data,
1573                                  scp_sftp_fileoffset, len);
1574         if (actuallen == -1 && fxp_error_type() != SSH_FX_EOF) {
1575             tell_user(stderr, "pscp: error while reading: %s", fxp_error());
1576             errs++;
1577             return -1;
1578         }
1579         if (actuallen < 0)
1580             actuallen = 0;
1581
1582         scp_sftp_fileoffset = uint64_add32(scp_sftp_fileoffset, actuallen);
1583
1584         return actuallen;
1585     } else {
1586         return ssh_scp_recv(data, len);
1587     }
1588 }
1589
1590 int scp_finish_filerecv(void)
1591 {
1592     if (using_sftp) {
1593         fxp_close(scp_sftp_filehandle);
1594         return 0;
1595     } else {
1596         back->send("", 1);
1597         return response();
1598     }
1599 }
1600
1601 /* ----------------------------------------------------------------------
1602  *  Send an error message to the other side and to the screen.
1603  *  Increment error counter.
1604  */
1605 static void run_err(const char *fmt, ...)
1606 {
1607     char str[2048];
1608     va_list ap;
1609     va_start(ap, fmt);
1610     errs++;
1611     strcpy(str, "scp: ");
1612     vsprintf(str + strlen(str), fmt, ap);
1613     strcat(str, "\n");
1614     scp_send_errmsg(str);
1615     tell_user(stderr, "%s", str);
1616     va_end(ap);
1617 }
1618
1619 /*
1620  *  Execute the source part of the SCP protocol.
1621  */
1622 static void source(char *src)
1623 {
1624     unsigned long size;
1625     char *last;
1626     HANDLE f;
1627     DWORD attr;
1628     unsigned long i;
1629     unsigned long stat_bytes;
1630     time_t stat_starttime, stat_lasttime;
1631
1632     attr = GetFileAttributes(src);
1633     if (attr == (DWORD) - 1) {
1634         run_err("%s: No such file or directory", src);
1635         return;
1636     }
1637
1638     if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
1639         if (recursive) {
1640             /*
1641              * Avoid . and .. directories.
1642              */
1643             char *p;
1644             p = strrchr(src, '/');
1645             if (!p)
1646                 p = strrchr(src, '\\');
1647             if (!p)
1648                 p = src;
1649             else
1650                 p++;
1651             if (!strcmp(p, ".") || !strcmp(p, ".."))
1652                 /* skip . and .. */ ;
1653             else
1654                 rsource(src);
1655         } else {
1656             run_err("%s: not a regular file", src);
1657         }
1658         return;
1659     }
1660
1661     if ((last = strrchr(src, '/')) == NULL)
1662         last = src;
1663     else
1664         last++;
1665     if (strrchr(last, '\\') != NULL)
1666         last = strrchr(last, '\\') + 1;
1667     if (last == src && strchr(src, ':') != NULL)
1668         last = strchr(src, ':') + 1;
1669
1670     f = CreateFile(src, GENERIC_READ, FILE_SHARE_READ, NULL,
1671                    OPEN_EXISTING, 0, 0);
1672     if (f == INVALID_HANDLE_VALUE) {
1673         run_err("%s: Cannot open file", src);
1674         return;
1675     }
1676
1677     if (preserve) {
1678         FILETIME actime, wrtime;
1679         unsigned long mtime, atime;
1680         GetFileTime(f, NULL, &actime, &wrtime);
1681         TIME_WIN_TO_POSIX(actime, atime);
1682         TIME_WIN_TO_POSIX(wrtime, mtime);
1683         if (scp_send_filetimes(mtime, atime))
1684             return;
1685     }
1686
1687     size = GetFileSize(f, NULL);
1688     if (verbose)
1689         tell_user(stderr, "Sending file %s, size=%lu", last, size);
1690     if (scp_send_filename(last, size, 0644))
1691         return;
1692
1693     stat_bytes = 0;
1694     stat_starttime = time(NULL);
1695     stat_lasttime = 0;
1696
1697     for (i = 0; i < size; i += 4096) {
1698         char transbuf[4096];
1699         DWORD j, k = 4096;
1700
1701         if (i + k > size)
1702             k = size - i;
1703         if (!ReadFile(f, transbuf, k, &j, NULL) || j != k) {
1704             if (statistics)
1705                 printf("\n");
1706             bump("%s: Read error", src);
1707         }
1708         if (scp_send_filedata(transbuf, k))
1709             bump("%s: Network error occurred", src);
1710
1711         if (statistics) {
1712             stat_bytes += k;
1713             if (time(NULL) != stat_lasttime || i + k == size) {
1714                 stat_lasttime = time(NULL);
1715                 print_stats(last, size, stat_bytes,
1716                             stat_starttime, stat_lasttime);
1717             }
1718         }
1719
1720     }
1721     CloseHandle(f);
1722
1723     (void) scp_send_finish();
1724 }
1725
1726 /*
1727  *  Recursively send the contents of a directory.
1728  */
1729 static void rsource(char *src)
1730 {
1731     char *last, *findfile;
1732     char *save_target;
1733     HANDLE dir;
1734     WIN32_FIND_DATA fdat;
1735     int ok;
1736
1737     if ((last = strrchr(src, '/')) == NULL)
1738         last = src;
1739     else
1740         last++;
1741     if (strrchr(last, '\\') != NULL)
1742         last = strrchr(last, '\\') + 1;
1743     if (last == src && strchr(src, ':') != NULL)
1744         last = strchr(src, ':') + 1;
1745
1746     /* maybe send filetime */
1747
1748     save_target = scp_save_remotepath();
1749
1750     if (verbose)
1751         tell_user(stderr, "Entering directory: %s", last);
1752     if (scp_send_dirname(last, 0755))
1753         return;
1754
1755     findfile = dupcat(src, "/*", NULL);
1756     dir = FindFirstFile(findfile, &fdat);
1757     ok = (dir != INVALID_HANDLE_VALUE);
1758     while (ok) {
1759         if (strcmp(fdat.cFileName, ".") == 0 ||
1760             strcmp(fdat.cFileName, "..") == 0) {
1761             /* ignore . and .. */
1762         } else {
1763             char *foundfile = dupcat(src, "/", fdat.cFileName, NULL);
1764             source(foundfile);
1765             sfree(foundfile);
1766         }
1767         ok = FindNextFile(dir, &fdat);
1768     }
1769     FindClose(dir);
1770     sfree(findfile);
1771
1772     (void) scp_send_enddir();
1773
1774     scp_restore_remotepath(save_target);
1775 }
1776
1777 /*
1778  * Execute the sink part of the SCP protocol.
1779  */
1780 static void sink(char *targ, char *src)
1781 {
1782     char *destfname;
1783     int targisdir = 0;
1784     int exists;
1785     DWORD attr;
1786     HANDLE f;
1787     unsigned long received;
1788     int wrerror = 0;
1789     unsigned long stat_bytes;
1790     time_t stat_starttime, stat_lasttime;
1791     char *stat_name;
1792
1793     attr = GetFileAttributes(targ);
1794     if (attr != (DWORD) - 1 && (attr & FILE_ATTRIBUTE_DIRECTORY) != 0)
1795         targisdir = 1;
1796
1797     if (targetshouldbedirectory && !targisdir)
1798         bump("%s: Not a directory", targ);
1799
1800     scp_sink_init();
1801     while (1) {
1802         struct scp_sink_action act;
1803         if (scp_get_sink_action(&act))
1804             return;
1805
1806         if (act.action == SCP_SINK_ENDDIR)
1807             return;
1808
1809         if (act.action == SCP_SINK_RETRY)
1810             continue;
1811
1812         if (targisdir) {
1813             /*
1814              * Prevent the remote side from maliciously writing to
1815              * files outside the target area by sending a filename
1816              * containing `../'. In fact, it shouldn't be sending
1817              * filenames with any slashes or colons in at all; so
1818              * we'll find the last slash, backslash or colon in the
1819              * filename and use only the part after that. (And
1820              * warn!)
1821              * 
1822              * In addition, we also ensure here that if we're
1823              * copying a single file and the target is a directory
1824              * (common usage: `pscp host:filename .') the remote
1825              * can't send us a _different_ file name. We can
1826              * distinguish this case because `src' will be non-NULL
1827              * and the last component of that will fail to match
1828              * (the last component of) the name sent.
1829              * 
1830              * Well, not always; if `src' is a wildcard, we do
1831              * expect to get back filenames that don't correspond
1832              * exactly to it. Ideally in this case, we would like
1833              * to ensure that the returned filename actually
1834              * matches the wildcard pattern - but one of SCP's
1835              * protocol infelicities is that wildcard matching is
1836              * done at the server end _by the server's rules_ and
1837              * so in general this is infeasible. Hence, we only
1838              * accept filenames that don't correspond to `src' if
1839              * unsafe mode is enabled or we are using SFTP (which
1840              * resolves remote wildcards on the client side and can
1841              * be trusted).
1842              */
1843             char *striptarget, *stripsrc;
1844
1845             striptarget = stripslashes(act.name, 1);
1846             if (striptarget != act.name) {
1847                 tell_user(stderr, "warning: remote host sent a compound"
1848                           " pathname '%s'", act.name);
1849                 tell_user(stderr, "         renaming local file to '%s'",
1850                           striptarget);
1851             }
1852
1853             /*
1854              * Also check to see if the target filename is '.' or
1855              * '..', or indeed '...' and so on because Windows
1856              * appears to interpret those like '..'.
1857              */
1858             if (is_dots(striptarget)) {
1859                 bump("security violation: remote host attempted to write to"
1860                      " a '.' or '..' path!");
1861             }
1862
1863             if (src) {
1864                 stripsrc = stripslashes(src, 1);
1865                 if (strcmp(striptarget, stripsrc) &&
1866                     !using_sftp && !scp_unsafe_mode) {
1867                     tell_user(stderr, "warning: remote host tried to write "
1868                               "to a file called '%s'", striptarget);
1869                     tell_user(stderr, "         when we requested a file "
1870                               "called '%s'.", stripsrc);
1871                     tell_user(stderr, "         If this is a wildcard, "
1872                               "consider upgrading to SSH 2 or using");
1873                     tell_user(stderr, "         the '-unsafe' option. Renaming"
1874                               " of this file has been disallowed.");
1875                     /* Override the name the server provided with our own. */
1876                     striptarget = stripsrc;
1877                 }
1878             }
1879
1880             if (targ[0] != '\0')
1881                 destfname = dupcat(targ, "\\", striptarget, NULL);
1882             else
1883                 destfname = dupstr(striptarget);
1884         } else {
1885             /*
1886              * In this branch of the if, the target area is a
1887              * single file with an explicitly specified name in any
1888              * case, so there's no danger.
1889              */
1890             destfname = dupstr(targ);
1891         }
1892         attr = GetFileAttributes(destfname);
1893         exists = (attr != (DWORD) - 1);
1894
1895         if (act.action == SCP_SINK_DIR) {
1896             if (exists && (attr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
1897                 run_err("%s: Not a directory", destfname);
1898                 continue;
1899             }
1900             if (!exists) {
1901                 if (!CreateDirectory(destfname, NULL)) {
1902                     run_err("%s: Cannot create directory", destfname);
1903                     continue;
1904                 }
1905             }
1906             sink(destfname, NULL);
1907             /* can we set the timestamp for directories ? */
1908             continue;
1909         }
1910
1911         f = CreateFile(destfname, GENERIC_WRITE, 0, NULL,
1912                        CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
1913         if (f == INVALID_HANDLE_VALUE) {
1914             run_err("%s: Cannot create file", destfname);
1915             continue;
1916         }
1917
1918         if (scp_accept_filexfer())
1919             return;
1920
1921         stat_bytes = 0;
1922         stat_starttime = time(NULL);
1923         stat_lasttime = 0;
1924         stat_name = stripslashes(destfname, 1);
1925
1926         received = 0;
1927         while (received < act.size) {
1928             char transbuf[4096];
1929             DWORD blksize, read, written;
1930             blksize = 4096;
1931             if (blksize > act.size - received)
1932                 blksize = act.size - received;
1933             read = scp_recv_filedata(transbuf, blksize);
1934             if (read <= 0)
1935                 bump("Lost connection");
1936             if (wrerror)
1937                 continue;
1938             if (!WriteFile(f, transbuf, read, &written, NULL) ||
1939                 written != read) {
1940                 wrerror = 1;
1941                 /* FIXME: in sftp we can actually abort the transfer */
1942                 if (statistics)
1943                     printf("\r%-25.25s | %50s\n",
1944                            stat_name,
1945                            "Write error.. waiting for end of file");
1946                 continue;
1947             }
1948             if (statistics) {
1949                 stat_bytes += read;
1950                 if (time(NULL) > stat_lasttime ||
1951                     received + read == act.size) {
1952                     stat_lasttime = time(NULL);
1953                     print_stats(stat_name, act.size, stat_bytes,
1954                                 stat_starttime, stat_lasttime);
1955                 }
1956             }
1957             received += read;
1958         }
1959         if (act.settime) {
1960             FILETIME actime, wrtime;
1961             TIME_POSIX_TO_WIN(act.atime, actime);
1962             TIME_POSIX_TO_WIN(act.mtime, wrtime);
1963             SetFileTime(f, NULL, &actime, &wrtime);
1964         }
1965
1966         CloseHandle(f);
1967         if (wrerror) {
1968             run_err("%s: Write error", destfname);
1969             continue;
1970         }
1971         (void) scp_finish_filerecv();
1972         sfree(destfname);
1973         sfree(act.buf);
1974     }
1975 }
1976
1977 /*
1978  * We will copy local files to a remote server.
1979  */
1980 static void toremote(int argc, char *argv[])
1981 {
1982     char *src, *targ, *host, *user;
1983     char *cmd;
1984     int i;
1985
1986     targ = argv[argc - 1];
1987
1988     /* Separate host from filename */
1989     host = targ;
1990     targ = colon(targ);
1991     if (targ == NULL)
1992         bump("targ == NULL in toremote()");
1993     *targ++ = '\0';
1994     if (*targ == '\0')
1995         targ = ".";
1996     /* Substitute "." for emtpy target */
1997
1998     /* Separate host and username */
1999     user = host;
2000     host = strrchr(host, '@');
2001     if (host == NULL) {
2002         host = user;
2003         user = NULL;
2004     } else {
2005         *host++ = '\0';
2006         if (*user == '\0')
2007             user = NULL;
2008     }
2009
2010     if (argc == 2) {
2011         /* Find out if the source filespec covers multiple files
2012            if so, we should set the targetshouldbedirectory flag */
2013         HANDLE fh;
2014         WIN32_FIND_DATA fdat;
2015         if (colon(argv[0]) != NULL)
2016             bump("%s: Remote to remote not supported", argv[0]);
2017         fh = FindFirstFile(argv[0], &fdat);
2018         if (fh == INVALID_HANDLE_VALUE)
2019             bump("%s: No such file or directory\n", argv[0]);
2020         if (FindNextFile(fh, &fdat))
2021             targetshouldbedirectory = 1;
2022         FindClose(fh);
2023     }
2024
2025     cmd = smalloc(strlen(targ) + 100);
2026     sprintf(cmd, "scp%s%s%s%s -t %s",
2027             verbose ? " -v" : "",
2028             recursive ? " -r" : "",
2029             preserve ? " -p" : "",
2030             targetshouldbedirectory ? " -d" : "", targ);
2031     do_cmd(host, user, cmd);
2032     sfree(cmd);
2033
2034     scp_source_setup(targ, targetshouldbedirectory);
2035
2036     for (i = 0; i < argc - 1; i++) {
2037         char *srcpath, *last;
2038         HANDLE dir;
2039         WIN32_FIND_DATA fdat;
2040         src = argv[i];
2041         if (colon(src) != NULL) {
2042             tell_user(stderr, "%s: Remote to remote not supported\n", src);
2043             errs++;
2044             continue;
2045         }
2046
2047         /*
2048          * Trim off the last pathname component of `src', to
2049          * provide the base pathname which will be prepended to
2050          * filenames returned from Find{First,Next}File.
2051          */
2052         srcpath = dupstr(src);
2053         last = stripslashes(srcpath, 1);
2054         *last = '\0';
2055
2056         dir = FindFirstFile(src, &fdat);
2057         if (dir == INVALID_HANDLE_VALUE) {
2058             run_err("%s: No such file or directory", src);
2059             continue;
2060         }
2061         do {
2062             char *filename;
2063             /*
2064              * Ensure that . and .. are never matched by wildcards,
2065              * but only by deliberate action.
2066              */
2067             if (!strcmp(fdat.cFileName, ".") ||
2068                 !strcmp(fdat.cFileName, "..")) {
2069                 /*
2070                  * Find*File has returned a special dir. We require
2071                  * that _either_ `src' ends in a backslash followed
2072                  * by that string, _or_ `src' is precisely that
2073                  * string.
2074                  */
2075                 int len = strlen(src), dlen = strlen(fdat.cFileName);
2076                 if (len == dlen && !strcmp(src, fdat.cFileName)) {
2077                     /* ok */ ;
2078                 } else if (len > dlen + 1 && src[len - dlen - 1] == '\\' &&
2079                            !strcmp(src + len - dlen, fdat.cFileName)) {
2080                     /* ok */ ;
2081                 } else
2082                     continue;          /* ignore this one */
2083             }
2084             filename = dupcat(srcpath, fdat.cFileName, NULL);
2085             source(filename);
2086             sfree(filename);
2087         } while (FindNextFile(dir, &fdat));
2088         FindClose(dir);
2089         sfree(srcpath);
2090     }
2091 }
2092
2093 /*
2094  *  We will copy files from a remote server to the local machine.
2095  */
2096 static void tolocal(int argc, char *argv[])
2097 {
2098     char *src, *targ, *host, *user;
2099     char *cmd;
2100
2101     if (argc != 2)
2102         bump("More than one remote source not supported");
2103
2104     src = argv[0];
2105     targ = argv[1];
2106
2107     /* Separate host from filename */
2108     host = src;
2109     src = colon(src);
2110     if (src == NULL)
2111         bump("Local to local copy not supported");
2112     *src++ = '\0';
2113     if (*src == '\0')
2114         src = ".";
2115     /* Substitute "." for empty filename */
2116
2117     /* Separate username and hostname */
2118     user = host;
2119     host = strrchr(host, '@');
2120     if (host == NULL) {
2121         host = user;
2122         user = NULL;
2123     } else {
2124         *host++ = '\0';
2125         if (*user == '\0')
2126             user = NULL;
2127     }
2128
2129     cmd = smalloc(strlen(src) + 100);
2130     sprintf(cmd, "scp%s%s%s%s -f %s",
2131             verbose ? " -v" : "",
2132             recursive ? " -r" : "",
2133             preserve ? " -p" : "",
2134             targetshouldbedirectory ? " -d" : "", src);
2135     do_cmd(host, user, cmd);
2136     sfree(cmd);
2137
2138     if (scp_sink_setup(src, preserve, recursive))
2139         return;
2140
2141     sink(targ, src);
2142 }
2143
2144 /*
2145  *  We will issue a list command to get a remote directory.
2146  */
2147 static void get_dir_list(int argc, char *argv[])
2148 {
2149     char *src, *host, *user;
2150     char *cmd, *p, *q;
2151     char c;
2152
2153     src = argv[0];
2154
2155     /* Separate host from filename */
2156     host = src;
2157     src = colon(src);
2158     if (src == NULL)
2159         bump("Local to local copy not supported");
2160     *src++ = '\0';
2161     if (*src == '\0')
2162         src = ".";
2163     /* Substitute "." for empty filename */
2164
2165     /* Separate username and hostname */
2166     user = host;
2167     host = strrchr(host, '@');
2168     if (host == NULL) {
2169         host = user;
2170         user = NULL;
2171     } else {
2172         *host++ = '\0';
2173         if (*user == '\0')
2174             user = NULL;
2175     }
2176
2177     cmd = smalloc(4 * strlen(src) + 100);
2178     strcpy(cmd, "ls -la '");
2179     p = cmd + strlen(cmd);
2180     for (q = src; *q; q++) {
2181         if (*q == '\'') {
2182             *p++ = '\'';
2183             *p++ = '\\';
2184             *p++ = '\'';
2185             *p++ = '\'';
2186         } else {
2187             *p++ = *q;
2188         }
2189     }
2190     *p++ = '\'';
2191     *p = '\0';
2192
2193     do_cmd(host, user, cmd);
2194     sfree(cmd);
2195
2196     if (using_sftp) {
2197         scp_sftp_listdir(src);
2198     } else {
2199         while (ssh_scp_recv(&c, 1) > 0)
2200             tell_char(stdout, c);
2201     }
2202 }
2203
2204 /*
2205  *  Initialize the Win$ock driver.
2206  */
2207 static void init_winsock(void)
2208 {
2209     WORD winsock_ver;
2210     WSADATA wsadata;
2211
2212     winsock_ver = MAKEWORD(1, 1);
2213     if (WSAStartup(winsock_ver, &wsadata))
2214         bump("Unable to initialise WinSock");
2215     if (LOBYTE(wsadata.wVersion) != 1 || HIBYTE(wsadata.wVersion) != 1)
2216         bump("WinSock version is incompatible with 1.1");
2217 }
2218
2219 /*
2220  *  Short description of parameters.
2221  */
2222 static void usage(void)
2223 {
2224     printf("PuTTY Secure Copy client\n");
2225     printf("%s\n", ver);
2226     printf("Usage: pscp [options] [user@]host:source target\n");
2227     printf
2228         ("       pscp [options] source [source...] [user@]host:target\n");
2229     printf("       pscp [options] -ls user@host:filespec\n");
2230     printf("Options:\n");
2231     printf("  -p        preserve file attributes\n");
2232     printf("  -q        quiet, don't show statistics\n");
2233     printf("  -r        copy directories recursively\n");
2234     printf("  -v        show verbose messages\n");
2235     printf("  -P port   connect to specified port\n");
2236     printf("  -pw passw login with specified password\n");
2237     printf("  -unsafe   allow server-side wildcards (DANGEROUS)\n");
2238 #if 0
2239     /*
2240      * -gui is an internal option, used by GUI front ends to get
2241      * pscp to pass progress reports back to them. It's not an
2242      * ordinary user-accessible option, so it shouldn't be part of
2243      * the command-line help. The only people who need to know
2244      * about it are programmers, and they can read the source.
2245      */
2246     printf
2247         ("  -gui hWnd GUI mode with the windows handle for receiving messages\n");
2248 #endif
2249     exit(1);
2250 }
2251
2252 /*
2253  *  Main program (no, really?)
2254  */
2255 int main(int argc, char *argv[])
2256 {
2257     int i;
2258
2259     default_protocol = PROT_TELNET;
2260
2261     flags = FLAG_STDERR;
2262     ssh_get_line = &get_line;
2263     init_winsock();
2264     sk_init();
2265
2266     for (i = 1; i < argc; i++) {
2267         if (argv[i][0] != '-')
2268             break;
2269         if (strcmp(argv[i], "-v") == 0)
2270             verbose = 1, flags |= FLAG_VERBOSE;
2271         else if (strcmp(argv[i], "-r") == 0)
2272             recursive = 1;
2273         else if (strcmp(argv[i], "-p") == 0)
2274             preserve = 1;
2275         else if (strcmp(argv[i], "-q") == 0)
2276             statistics = 0;
2277         else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "-?") == 0)
2278             usage();
2279         else if (strcmp(argv[i], "-P") == 0 && i + 1 < argc)
2280             portnumber = atoi(argv[++i]);
2281         else if (strcmp(argv[i], "-pw") == 0 && i + 1 < argc)
2282             password = argv[++i];
2283         else if (strcmp(argv[i], "-gui") == 0 && i + 1 < argc) {
2284             gui_hwnd = argv[++i];
2285             gui_mode = 1;
2286         } else if (strcmp(argv[i], "-ls") == 0)
2287             list = 1;
2288         else if (strcmp(argv[i], "-unsafe") == 0)
2289             scp_unsafe_mode = 1;
2290         else if (strcmp(argv[i], "--") == 0) {
2291             i++;
2292             break;
2293         } else
2294             usage();
2295     }
2296     argc -= i;
2297     argv += i;
2298     back = NULL;
2299
2300     if (list) {
2301         if (argc != 1)
2302             usage();
2303         get_dir_list(argc, argv);
2304
2305     } else {
2306
2307         if (argc < 2)
2308             usage();
2309         if (argc > 2)
2310             targetshouldbedirectory = 1;
2311
2312         if (colon(argv[argc - 1]) != NULL)
2313             toremote(argc, argv);
2314         else
2315             tolocal(argc, argv);
2316     }
2317
2318     if (back != NULL && back->socket() != NULL) {
2319         char ch;
2320         back->special(TS_EOF);
2321         ssh_scp_recv(&ch, 1);
2322     }
2323     WSACleanup();
2324     random_save_seed();
2325
2326     /* GUI Adaptation - August 2000 */
2327     if (gui_mode) {
2328         unsigned int msg_id = WM_RET_ERR_CNT;
2329         if (list)
2330             msg_id = WM_LS_RET_ERR_CNT;
2331         while (!PostMessage
2332                ((HWND) atoi(gui_hwnd), msg_id, (WPARAM) errs,
2333                 0 /*lParam */ ))SleepEx(1000, TRUE);
2334     }
2335     return (errs == 0 ? 0 : 1);
2336 }
2337
2338 /* end */