2 * scp.c - Scp (Secure Copy) client for PuTTY.
3 * Joris van Rantwijk, Simon Tatham
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.
8 * Adaptations to enable connecting a GUI by L. Gunnarsson - Sept 2000
23 /* GUI Adaptation - Sept 2000 */
27 #define PUTTY_DO_GLOBALS
31 #define TIME_POSIX_TO_WIN(t, ft) (*(LONGLONG*)&(ft) = \
32 ((LONGLONG) (t) + (LONGLONG) 11644473600) * (LONGLONG) 10000000)
33 #define TIME_WIN_TO_POSIX(ft, t) ((t) = (unsigned long) \
34 ((*(LONGLONG*)&(ft)) / (LONGLONG) 10000000 - (LONGLONG) 11644473600))
36 /* GUI Adaptation - Sept 2000 */
37 #define WM_APP_BASE 0x8000
38 #define WM_STD_OUT_CHAR ( WM_APP_BASE+400 )
39 #define WM_STD_ERR_CHAR ( WM_APP_BASE+401 )
40 #define WM_STATS_CHAR ( WM_APP_BASE+402 )
41 #define WM_STATS_SIZE ( WM_APP_BASE+403 )
42 #define WM_STATS_PERCENT ( WM_APP_BASE+404 )
43 #define WM_STATS_ELAPSED ( WM_APP_BASE+405 )
44 #define WM_RET_ERR_CNT ( WM_APP_BASE+406 )
45 #define WM_LS_RET_ERR_CNT ( WM_APP_BASE+407 )
47 static int verbose
= 0;
48 static int recursive
= 0;
49 static int preserve
= 0;
50 static int targetshouldbedirectory
= 0;
51 static int statistics
= 1;
52 static int portnumber
= 0;
53 static char *password
= NULL
;
55 static int connection_open
= 0;
56 /* GUI Adaptation - Sept 2000 */
57 #define NAME_STR_MAX 2048
58 static char statname
[NAME_STR_MAX
+1];
59 static unsigned long statsize
= 0;
60 static int statperct
= 0;
61 static time_t statelapsed
= 0;
62 static int gui_mode
= 0;
63 static char *gui_hwnd
= NULL
;
65 static void source(char *src
);
66 static void rsource(char *src
);
67 static void sink(char *targ
);
68 /* GUI Adaptation - Sept 2000 */
69 static void tell_char(FILE *stream
, char c
);
70 static void tell_str(FILE *stream
, char *str
);
71 static void tell_user(FILE *stream
, char *fmt
, ...);
72 static void send_char_msg(unsigned int msg_id
, char c
);
73 static void send_str_msg(unsigned int msg_id
, char *str
);
74 static void gui_update_stats(char *name
, unsigned long size
, int percentage
, time_t elapsed
);
76 void begin_session(void) { }
77 void logevent(char *string
) { }
79 void verify_ssh_host_key(char *host
, int port
, char *keytype
,
80 char *keystr
, char *fingerprint
) {
83 static const char absentmsg
[] =
84 "The server's host key is not cached in the registry. You\n"
85 "have no guarantee that the server is the computer you\n"
87 "The server's key fingerprint is:\n"
89 "If you trust this host, enter \"y\" to add the key to\n"
90 "PuTTY's cache and carry on connecting.\n"
91 "If you do not trust this host, enter \"n\" to abandon the\n"
93 "Continue connecting? (y/n) ";
95 static const char wrongmsg
[] =
96 "WARNING - POTENTIAL SECURITY BREACH!\n"
97 "The server's host key does not match the one PuTTY has\n"
98 "cached in the registry. This means that either the\n"
99 "server administrator has changed the host key, or you\n"
100 "have actually connected to another computer pretending\n"
101 "to be the server.\n"
102 "The new key fingerprint is:\n"
104 "If you were expecting this change and trust the new key,\n"
105 "enter Yes to update PuTTY's cache and continue connecting.\n"
106 "If you want to carry on connecting but without updating\n"
107 "the cache, enter No.\n"
108 "If you want to abandon the connection completely, press\n"
109 "Return to cancel. Pressing Return is the ONLY guaranteed\n"
111 "Update cached key? (y/n, Return cancels connection) ";
113 static const char abandoned
[] = "Connection abandoned.\n";
118 * Verify the key against the registry.
120 ret
= verify_host_key(host
, port
, keytype
, keystr
);
122 if (ret
== 0) /* success - key matched OK */
124 if (ret
== 2) { /* key was different */
125 fprintf(stderr
, wrongmsg
, fingerprint
);
126 if (fgets(line
, sizeof(line
), stdin
) &&
127 line
[0] != '\0' && line
[0] != '\n') {
128 if (line
[0] == 'y' || line
[0] == 'Y')
129 store_host_key(host
, port
, keytype
, keystr
);
131 fprintf(stderr
, abandoned
);
135 if (ret
== 1) { /* key was absent */
136 fprintf(stderr
, absentmsg
, fingerprint
);
137 if (fgets(line
, sizeof(line
), stdin
) &&
138 (line
[0] == 'y' || line
[0] == 'Y'))
139 store_host_key(host
, port
, keytype
, keystr
);
141 fprintf(stderr
, abandoned
);
147 /* GUI Adaptation - Sept 2000 */
148 static void send_msg(HWND h
, UINT message
, WPARAM wParam
)
150 while (!PostMessage( h
, message
, wParam
, 0))
154 static void tell_char(FILE *stream
, char c
)
160 unsigned int msg_id
= WM_STD_OUT_CHAR
;
161 if (stream
== stderr
) msg_id
= WM_STD_ERR_CHAR
;
162 send_msg( (HWND
)atoi(gui_hwnd
), msg_id
, (WPARAM
)c
);
166 static void tell_str(FILE *stream
, char *str
)
170 for( i
= 0; i
< strlen(str
); ++i
)
171 tell_char(stream
, str
[i
]);
174 static void tell_user(FILE *stream
, char *fmt
, ...)
176 char str
[0x100]; /* Make the size big enough */
179 vsprintf(str
, fmt
, ap
);
182 tell_str(stream
, str
);
185 static void gui_update_stats(char *name
, unsigned long size
, int percentage
, time_t elapsed
)
189 if (strcmp(name
,statname
) != 0)
191 for( i
= 0; i
< strlen(name
); ++i
)
192 send_msg( (HWND
)atoi(gui_hwnd
), WM_STATS_CHAR
, (WPARAM
)name
[i
]);
193 send_msg( (HWND
)atoi(gui_hwnd
), WM_STATS_CHAR
, (WPARAM
)'\n' );
194 strcpy(statname
,name
);
196 if (statsize
!= size
)
198 send_msg( (HWND
)atoi(gui_hwnd
), WM_STATS_SIZE
, (WPARAM
)size
);
201 if (statelapsed
!= elapsed
)
203 send_msg( (HWND
)atoi(gui_hwnd
), WM_STATS_ELAPSED
, (WPARAM
)elapsed
);
204 statelapsed
= elapsed
;
206 if (statperct
!= percentage
)
208 send_msg( (HWND
)atoi(gui_hwnd
), WM_STATS_PERCENT
, (WPARAM
)percentage
);
209 statperct
= percentage
;
214 * Print an error message and perform a fatal exit.
216 void fatalbox(char *fmt
, ...)
218 char str
[0x100]; /* Make the size big enough */
221 strcpy(str
, "Fatal:");
222 vsprintf(str
+strlen(str
), fmt
, ap
);
225 tell_str(stderr
, str
);
229 void connection_fatal(char *fmt
, ...)
231 char str
[0x100]; /* Make the size big enough */
234 strcpy(str
, "Fatal:");
235 vsprintf(str
+strlen(str
), fmt
, ap
);
238 tell_str(stderr
, str
);
244 * Receive a block of data from the SSH link. Block until all data
247 * To do this, we repeatedly call the SSH protocol module, with our
248 * own trap in term_out() to catch the data that comes back. We do
249 * this until we have enough data.
251 static unsigned char *outptr
; /* where to put the data */
252 static unsigned outlen
; /* how much data required */
253 static unsigned char *pending
= NULL
; /* any spare data */
254 static unsigned pendlen
=0, pendsize
=0; /* length and phys. size of buffer */
255 void term_out(void) {
257 * Here we must deal with a block of data, in `inbuf', size
260 unsigned char *p
= inbuf
;
261 unsigned len
= inbuf_head
;
266 * If this is before the real session begins, just return.
272 unsigned used
= outlen
;
273 if (used
> len
) used
= len
;
274 memcpy(outptr
, p
, used
);
275 outptr
+= used
; outlen
-= used
;
276 p
+= used
; len
-= used
;
280 if (pendsize
< pendlen
+ len
) {
281 pendsize
= pendlen
+ len
+ 4096;
282 pending
= (pending ?
realloc(pending
, pendsize
) :
285 fatalbox("Out of memory");
287 memcpy(pending
+pendlen
, p
, len
);
291 static int ssh_scp_recv(unsigned char *buf
, int len
) {
298 * See if the pending-input block contains some of what we
302 unsigned pendused
= pendlen
;
303 if (pendused
> outlen
)
305 memcpy(outptr
, pending
, pendused
);
306 memmove(pending
, pending
+pendused
, pendlen
-pendused
);
322 if (s
== INVALID_SOCKET
) {
323 connection_open
= FALSE
;
328 if (select(1, &readfds
, NULL
, NULL
, NULL
) < 0)
330 back
->msg(0, FD_READ
);
338 * Loop through the ssh connection and authentication process.
340 static void ssh_scp_init(void) {
344 if (s
== INVALID_SOCKET
)
346 while (!back
->sendok()) {
350 if (select(1, &readfds
, NULL
, NULL
, NULL
) < 0)
352 back
->msg(0, FD_READ
);
358 * Print an error message and exit after closing the SSH link.
360 static void bump(char *fmt
, ...)
362 char str
[0x100]; /* Make the size big enough */
365 strcpy(str
, "Fatal:");
366 vsprintf(str
+strlen(str
), fmt
, ap
);
369 tell_str(stderr
, str
);
371 if (connection_open
) {
373 back
->special(TS_EOF
);
374 ssh_scp_recv(&ch
, 1);
379 static int get_password(const char *prompt
, char *str
, int maxlen
)
385 static int tried_once
= 0;
390 strncpy(str
, password
, maxlen
);
391 str
[maxlen
-1] = '\0';
397 /* GUI Adaptation - Sept 2000 */
399 if (maxlen
>0) str
[0] = '\0';
401 hin
= GetStdHandle(STD_INPUT_HANDLE
);
402 hout
= GetStdHandle(STD_OUTPUT_HANDLE
);
403 if (hin
== INVALID_HANDLE_VALUE
|| hout
== INVALID_HANDLE_VALUE
)
404 bump("Cannot get standard input/output handles");
406 GetConsoleMode(hin
, &savemode
);
407 SetConsoleMode(hin
, (savemode
& (~ENABLE_ECHO_INPUT
)) |
408 ENABLE_PROCESSED_INPUT
| ENABLE_LINE_INPUT
);
410 WriteFile(hout
, prompt
, strlen(prompt
), &i
, NULL
);
411 ReadFile(hin
, str
, maxlen
-1, &i
, NULL
);
413 SetConsoleMode(hin
, savemode
);
415 if ((int)i
> maxlen
) i
= maxlen
-1; else i
= i
- 2;
418 WriteFile(hout
, "\r\n", 2, &i
, NULL
);
425 * Open an SSH connection to user@host and execute cmd.
427 static void do_cmd(char *host
, char *user
, char *cmd
)
429 char *err
, *realhost
;
431 if (host
== NULL
|| host
[0] == '\0')
432 bump("Empty host name");
434 /* Try to load settings for this host */
435 do_defaults(host
, &cfg
);
436 if (cfg
.host
[0] == '\0') {
437 /* No settings for this host; use defaults */
438 strncpy(cfg
.host
, host
, sizeof(cfg
.host
)-1);
439 cfg
.host
[sizeof(cfg
.host
)-1] = '\0';
444 if (user
!= NULL
&& user
[0] != '\0') {
445 strncpy(cfg
.username
, user
, sizeof(cfg
.username
)-1);
446 cfg
.username
[sizeof(cfg
.username
)-1] = '\0';
447 } else if (cfg
.username
[0] == '\0') {
448 bump("Empty user name");
451 if (cfg
.protocol
!= PROT_SSH
)
455 cfg
.port
= portnumber
;
457 strncpy(cfg
.remote_cmd
, cmd
, sizeof(cfg
.remote_cmd
));
458 cfg
.remote_cmd
[sizeof(cfg
.remote_cmd
)-1] = '\0';
463 err
= back
->init(NULL
, cfg
.host
, cfg
.port
, &realhost
);
465 bump("ssh_init: %s", err
);
467 if (verbose
&& realhost
!= NULL
)
468 tell_user(stderr
, "Connected to %s\n", realhost
);
474 * Update statistic information about current file.
476 static void print_stats(char *name
, unsigned long size
, unsigned long done
,
477 time_t start
, time_t now
)
484 /* GUI Adaptation - Sept 2000 */
486 gui_update_stats(name
, size
, ((done
*100) / size
), now
-start
);
489 ratebs
= (float) done
/ (now
- start
);
491 ratebs
= (float) done
;
496 eta
= (unsigned long) ((size
- done
) / ratebs
);
497 sprintf(etastr
, "%02ld:%02ld:%02ld",
498 eta
/ 3600, (eta
% 3600) / 60, eta
% 60);
500 pct
= (int) (100.0 * (float) done
/ size
);
502 printf("\r%-25.25s | %10ld kB | %5.1f kB/s | ETA: %8s | %3d%%",
503 name
, done
/ 1024, ratebs
/ 1024.0,
512 * Find a colon in str and return a pointer to the colon.
513 * This is used to separate hostname from filename.
515 static char * colon(char *str
)
517 /* We ignore a leading colon, since the hostname cannot be
518 empty. We also ignore a colon as second character because
519 of filenames like f:myfile.txt. */
520 if (str
[0] == '\0' ||
524 while (*str
!= '\0' &&
536 * Wait for a response from the other side.
537 * Return 0 if ok, -1 if error.
539 static int response(void)
541 char ch
, resp
, rbuf
[2048];
544 if (ssh_scp_recv(&resp
, 1) <= 0)
545 bump("Lost connection");
555 case 2: /* fatal error */
557 if (ssh_scp_recv(&ch
, 1) <= 0)
558 bump("Protocol error: Lost connection");
560 } while (p
< sizeof(rbuf
) && ch
!= '\n');
563 tell_user(stderr
, "%s\n", rbuf
);
572 * Send an error message to the other side and to the screen.
573 * Increment error counter.
575 static void run_err(const char *fmt
, ...)
581 strcpy(str
, "\01scp: ");
582 vsprintf(str
+strlen(str
), fmt
, ap
);
584 back
->send(str
, strlen(str
));
585 tell_user(stderr
, "%s",str
);
590 * Execute the source part of the SCP protocol.
592 static void source(char *src
)
600 unsigned long stat_bytes
;
601 time_t stat_starttime
, stat_lasttime
;
603 attr
= GetFileAttributes(src
);
604 if (attr
== (DWORD
)-1) {
605 run_err("%s: No such file or directory", src
);
609 if ((attr
& FILE_ATTRIBUTE_DIRECTORY
) != 0) {
612 * Avoid . and .. directories.
615 p
= strrchr(src
, '/');
617 p
= strrchr(src
, '\\');
622 if (!strcmp(p
, ".") || !strcmp(p
, ".."))
627 run_err("%s: not a regular file", src
);
632 if ((last
= strrchr(src
, '/')) == NULL
)
636 if (strrchr(last
, '\\') != NULL
)
637 last
= strrchr(last
, '\\') + 1;
638 if (last
== src
&& strchr(src
, ':') != NULL
)
639 last
= strchr(src
, ':') + 1;
641 f
= CreateFile(src
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
642 OPEN_EXISTING
, 0, 0);
643 if (f
== INVALID_HANDLE_VALUE
) {
644 run_err("%s: Cannot open file", src
);
649 FILETIME actime
, wrtime
;
650 unsigned long mtime
, atime
;
651 GetFileTime(f
, NULL
, &actime
, &wrtime
);
652 TIME_WIN_TO_POSIX(actime
, atime
);
653 TIME_WIN_TO_POSIX(wrtime
, mtime
);
654 sprintf(buf
, "T%lu 0 %lu 0\n", mtime
, atime
);
655 back
->send(buf
, strlen(buf
));
660 size
= GetFileSize(f
, NULL
);
661 sprintf(buf
, "C0644 %lu %s\n", size
, last
);
663 tell_user(stderr
, "Sending file modes: %s", buf
);
664 back
->send(buf
, strlen(buf
));
670 stat_starttime
= time(NULL
);
674 for (i
= 0; i
< size
; i
+= 4096) {
677 if (i
+ k
> size
) k
= size
- i
;
678 if (! ReadFile(f
, transbuf
, k
, &j
, NULL
) || j
!= k
) {
679 if (statistics
) printf("\n");
680 bump("%s: Read error", src
);
682 back
->send(transbuf
, k
);
685 if (time(NULL
) != stat_lasttime
||
687 stat_lasttime
= time(NULL
);
688 print_stats(last
, size
, stat_bytes
,
689 stat_starttime
, stat_lasttime
);
700 * Recursively send the contents of a directory.
702 static void rsource(char *src
)
707 WIN32_FIND_DATA fdat
;
710 if ((last
= strrchr(src
, '/')) == NULL
)
714 if (strrchr(last
, '\\') != NULL
)
715 last
= strrchr(last
, '\\') + 1;
716 if (last
== src
&& strchr(src
, ':') != NULL
)
717 last
= strchr(src
, ':') + 1;
719 /* maybe send filetime */
721 sprintf(buf
, "D0755 0 %s\n", last
);
723 tell_user(stderr
, "Entering directory: %s", buf
);
724 back
->send(buf
, strlen(buf
));
728 sprintf(buf
, "%s/*", src
);
729 dir
= FindFirstFile(buf
, &fdat
);
730 ok
= (dir
!= INVALID_HANDLE_VALUE
);
732 if (strcmp(fdat
.cFileName
, ".") == 0 ||
733 strcmp(fdat
.cFileName
, "..") == 0) {
734 } else if (strlen(src
) + 1 + strlen(fdat
.cFileName
) >=
736 run_err("%s/%s: Name too long", src
, fdat
.cFileName
);
738 sprintf(buf
, "%s/%s", src
, fdat
.cFileName
);
741 ok
= FindNextFile(dir
, &fdat
);
746 back
->send(buf
, strlen(buf
));
751 * Execute the sink part of the SCP protocol.
753 static void sink(char *targ
)
763 unsigned long mtime
, atime
;
765 unsigned long size
, i
;
767 unsigned long stat_bytes
;
768 time_t stat_starttime
, stat_lasttime
;
771 attr
= GetFileAttributes(targ
);
772 if (attr
!= (DWORD
)-1 && (attr
& FILE_ATTRIBUTE_DIRECTORY
) != 0)
775 if (targetshouldbedirectory
&& !targisdir
)
776 bump("%s: Not a directory", targ
);
782 if (ssh_scp_recv(&ch
, 1) <= 0)
785 bump("Protocol error: Unexpected newline");
789 if (ssh_scp_recv(&ch
, 1) <= 0)
790 bump("Lost connection");
792 } while (i
< sizeof(buf
) && ch
!= '\n');
795 case '\01': /* error */
796 tell_user(stderr
, "%s\n", buf
+1);
799 case '\02': /* fatal error */
805 if (sscanf(buf
, "T%ld %*d %ld %*d",
806 &mtime
, &atime
) == 2) {
811 bump("Protocol error: Illegal time format");
816 bump("Protocol error: Expected control record");
819 if (sscanf(buf
+1, "%u %lu %[^\n]", &mode
, &size
, namebuf
) != 3)
820 bump("Protocol error: Illegal file descriptor format");
829 strcpy(namebuf
, targ
);
831 attr
= GetFileAttributes(namebuf
);
832 exists
= (attr
!= (DWORD
)-1);
835 if (exists
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
) == 0) {
836 run_err("%s: Not a directory", namebuf
);
840 if (! CreateDirectory(namebuf
, NULL
)) {
841 run_err("%s: Cannot create directory",
847 /* can we set the timestamp for directories ? */
851 f
= CreateFile(namebuf
, GENERIC_WRITE
, 0, NULL
,
852 CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, 0);
853 if (f
== INVALID_HANDLE_VALUE
) {
854 run_err("%s: Cannot create file", namebuf
);
862 stat_starttime
= time(NULL
);
864 if ((stat_name
= strrchr(namebuf
, '/')) == NULL
)
868 if (strrchr(stat_name
, '\\') != NULL
)
869 stat_name
= strrchr(stat_name
, '\\') + 1;
872 for (i
= 0; i
< size
; i
+= 4096) {
875 if (i
+ k
> size
) k
= size
- i
;
876 if (ssh_scp_recv(transbuf
, k
) == 0)
877 bump("Lost connection");
878 if (wrerror
) continue;
879 if (! WriteFile(f
, transbuf
, k
, &j
, NULL
) || j
!= k
) {
882 printf("\r%-25.25s | %50s\n",
884 "Write error.. waiting for end of file");
889 if (time(NULL
) > stat_lasttime
||
891 stat_lasttime
= time(NULL
);
892 print_stats(stat_name
, size
, stat_bytes
,
893 stat_starttime
, stat_lasttime
);
900 FILETIME actime
, wrtime
;
901 TIME_POSIX_TO_WIN(atime
, actime
);
902 TIME_POSIX_TO_WIN(mtime
, wrtime
);
903 SetFileTime(f
, NULL
, &actime
, &wrtime
);
908 run_err("%s: Write error", namebuf
);
916 * We will copy local files to a remote server.
918 static void toremote(int argc
, char *argv
[])
920 char *src
, *targ
, *host
, *user
;
926 /* Separate host from filename */
930 bump("targ == NULL in toremote()");
934 /* Substitute "." for emtpy target */
936 /* Separate host and username */
938 host
= strrchr(host
, '@');
949 /* Find out if the source filespec covers multiple files
950 if so, we should set the targetshouldbedirectory flag */
952 WIN32_FIND_DATA fdat
;
953 if (colon(argv
[0]) != NULL
)
954 bump("%s: Remote to remote not supported", argv
[0]);
955 fh
= FindFirstFile(argv
[0], &fdat
);
956 if (fh
== INVALID_HANDLE_VALUE
)
957 bump("%s: No such file or directory\n", argv
[0]);
958 if (FindNextFile(fh
, &fdat
))
959 targetshouldbedirectory
= 1;
963 cmd
= smalloc(strlen(targ
) + 100);
964 sprintf(cmd
, "scp%s%s%s%s -t %s",
965 verbose ?
" -v" : "",
966 recursive ?
" -r" : "",
967 preserve ?
" -p" : "",
968 targetshouldbedirectory ?
" -d" : "",
970 do_cmd(host
, user
, cmd
);
975 for (i
= 0; i
< argc
- 1; i
++) {
977 WIN32_FIND_DATA fdat
;
979 if (colon(src
) != NULL
) {
980 tell_user(stderr
, "%s: Remote to remote not supported\n", src
);
984 dir
= FindFirstFile(src
, &fdat
);
985 if (dir
== INVALID_HANDLE_VALUE
) {
986 run_err("%s: No such file or directory", src
);
992 if (strlen(src
) + strlen(fdat
.cFileName
) >=
994 tell_user(stderr
, "%s: Name too long", src
);
997 strcpy(namebuf
, src
);
998 if ((last
= strrchr(namebuf
, '/')) == NULL
)
1002 if (strrchr(last
, '\\') != NULL
)
1003 last
= strrchr(last
, '\\') + 1;
1004 if (last
== namebuf
&& strrchr(namebuf
, ':') != NULL
)
1005 last
= strchr(namebuf
, ':') + 1;
1006 strcpy(last
, fdat
.cFileName
);
1008 } while (FindNextFile(dir
, &fdat
));
1014 * We will copy files from a remote server to the local machine.
1016 static void tolocal(int argc
, char *argv
[])
1018 char *src
, *targ
, *host
, *user
;
1022 bump("More than one remote source not supported");
1027 /* Separate host from filename */
1031 bump("Local to local copy not supported");
1035 /* Substitute "." for empty filename */
1037 /* Separate username and hostname */
1039 host
= strrchr(host
, '@');
1049 cmd
= smalloc(strlen(src
) + 100);
1050 sprintf(cmd
, "scp%s%s%s%s -f %s",
1051 verbose ?
" -v" : "",
1052 recursive ?
" -r" : "",
1053 preserve ?
" -p" : "",
1054 targetshouldbedirectory ?
" -d" : "",
1056 do_cmd(host
, user
, cmd
);
1063 * We will issue a list command to get a remote directory.
1065 static void get_dir_list(int argc
, char *argv
[])
1067 char *src
, *host
, *user
;
1073 /* Separate host from filename */
1077 bump("Local to local copy not supported");
1081 /* Substitute "." for empty filename */
1083 /* Separate username and hostname */
1085 host
= strrchr(host
, '@');
1095 cmd
= smalloc(4*strlen(src
) + 100);
1096 strcpy(cmd
, "ls -la '");
1097 p
= cmd
+ strlen(cmd
);
1098 for (q
= src
; *q
; q
++) {
1100 *p
++ = '\''; *p
++ = '\\'; *p
++ = '\''; *p
++ = '\'';
1108 do_cmd(host
, user
, cmd
);
1111 while (ssh_scp_recv(&c
, 1) > 0)
1112 tell_char(stdout
, c
);
1116 * Initialize the Win$ock driver.
1118 static void init_winsock(void)
1123 winsock_ver
= MAKEWORD(1, 1);
1124 if (WSAStartup(winsock_ver
, &wsadata
))
1125 bump("Unable to initialise WinSock");
1126 if (LOBYTE(wsadata
.wVersion
) != 1 ||
1127 HIBYTE(wsadata
.wVersion
) != 1)
1128 bump("WinSock version is incompatible with 1.1");
1132 * Short description of parameters.
1134 static void usage(void)
1136 printf("PuTTY Secure Copy client\n");
1137 printf("%s\n", ver
);
1138 printf("Usage: pscp [options] [user@]host:source target\n");
1139 printf(" pscp [options] source [source...] [user@]host:target\n");
1140 printf(" pscp [options] -ls user@host:filespec\n");
1141 printf("Options:\n");
1142 printf(" -p preserve file attributes\n");
1143 printf(" -q quiet, don't show statistics\n");
1144 printf(" -r copy directories recursively\n");
1145 printf(" -v show verbose messages\n");
1146 printf(" -P port connect to specified port\n");
1147 printf(" -pw passw login with specified password\n");
1148 /* GUI Adaptation - Sept 2000 */
1149 printf(" -gui hWnd GUI mode with the windows handle for receiving messages\n");
1154 * Main program (no, really?)
1156 int main(int argc
, char *argv
[])
1161 default_protocol
= PROT_TELNET
;
1163 flags
= FLAG_STDERR
;
1164 ssh_get_password
= &get_password
;
1167 for (i
= 1; i
< argc
; i
++) {
1168 if (argv
[i
][0] != '-')
1170 if (strcmp(argv
[i
], "-v") == 0)
1171 verbose
= 1, flags
|= FLAG_VERBOSE
;
1172 else if (strcmp(argv
[i
], "-r") == 0)
1174 else if (strcmp(argv
[i
], "-p") == 0)
1176 else if (strcmp(argv
[i
], "-q") == 0)
1178 else if (strcmp(argv
[i
], "-h") == 0 ||
1179 strcmp(argv
[i
], "-?") == 0)
1181 else if (strcmp(argv
[i
], "-P") == 0 && i
+1 < argc
)
1182 portnumber
= atoi(argv
[++i
]);
1183 else if (strcmp(argv
[i
], "-pw") == 0 && i
+1 < argc
)
1184 password
= argv
[++i
];
1185 else if (strcmp(argv
[i
], "-gui") == 0 && i
+1 < argc
) {
1186 gui_hwnd
= argv
[++i
];
1188 } else if (strcmp(argv
[i
], "-ls") == 0)
1190 else if (strcmp(argv
[i
], "--") == 0)
1201 get_dir_list(argc
, argv
);
1208 targetshouldbedirectory
= 1;
1210 if (colon(argv
[argc
-1]) != NULL
)
1211 toremote(argc
, argv
);
1213 tolocal(argc
, argv
);
1216 if (connection_open
) {
1218 back
->special(TS_EOF
);
1219 ssh_scp_recv(&ch
, 1);
1224 /* GUI Adaptation - August 2000 */
1226 unsigned int msg_id
= WM_RET_ERR_CNT
;
1227 if (list
) msg_id
= WM_LS_RET_ERR_CNT
;
1228 while (!PostMessage( (HWND
)atoi(gui_hwnd
), msg_id
, (WPARAM
)errs
, 0/*lParam*/ ) )
1231 return (errs
== 0 ?
0 : 1);