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
32 #define TIME_POSIX_TO_WIN(t, ft) (*(LONGLONG*)&(ft) = \
33 ((LONGLONG) (t) + (LONGLONG) 11644473600) * (LONGLONG) 10000000)
34 #define TIME_WIN_TO_POSIX(ft, t) ((t) = (unsigned long) \
35 ((*(LONGLONG*)&(ft)) / (LONGLONG) 10000000 - (LONGLONG) 11644473600))
37 /* GUI Adaptation - Sept 2000 */
38 #define WM_APP_BASE 0x8000
39 #define WM_STD_OUT_CHAR ( WM_APP_BASE+400 )
40 #define WM_STD_ERR_CHAR ( WM_APP_BASE+401 )
41 #define WM_STATS_CHAR ( WM_APP_BASE+402 )
42 #define WM_STATS_SIZE ( WM_APP_BASE+403 )
43 #define WM_STATS_PERCENT ( WM_APP_BASE+404 )
44 #define WM_STATS_ELAPSED ( WM_APP_BASE+405 )
45 #define WM_RET_ERR_CNT ( WM_APP_BASE+406 )
46 #define WM_LS_RET_ERR_CNT ( WM_APP_BASE+407 )
48 static int verbose
= 0;
49 static int recursive
= 0;
50 static int preserve
= 0;
51 static int targetshouldbedirectory
= 0;
52 static int statistics
= 1;
53 static int portnumber
= 0;
54 static char *password
= NULL
;
56 static int connection_open
= 0;
57 /* GUI Adaptation - Sept 2000 */
58 #define NAME_STR_MAX 2048
59 static char statname
[NAME_STR_MAX
+1];
60 static unsigned long statsize
= 0;
61 static int statperct
= 0;
62 static time_t statelapsed
= 0;
63 static int gui_mode
= 0;
64 static char *gui_hwnd
= NULL
;
66 static void source(char *src
);
67 static void rsource(char *src
);
68 static void sink(char *targ
);
69 /* GUI Adaptation - Sept 2000 */
70 static void tell_char(FILE *stream
, char c
);
71 static void tell_str(FILE *stream
, char *str
);
72 static void tell_user(FILE *stream
, char *fmt
, ...);
73 static void send_char_msg(unsigned int msg_id
, char c
);
74 static void send_str_msg(unsigned int msg_id
, char *str
);
75 static void gui_update_stats(char *name
, unsigned long size
, int percentage
, time_t elapsed
);
77 void begin_session(void) { }
78 void logevent(char *string
) { }
80 void verify_ssh_host_key(char *host
, int port
, char *keytype
,
81 char *keystr
, char *fingerprint
) {
84 static const char absentmsg
[] =
85 "The server's host key is not cached in the registry. You\n"
86 "have no guarantee that the server is the computer you\n"
88 "The server's key fingerprint is:\n"
90 "If you trust this host, enter \"y\" to add the key to\n"
91 "PuTTY's cache and carry on connecting.\n"
92 "If you do not trust this host, enter \"n\" to abandon the\n"
94 "Continue connecting? (y/n) ";
96 static const char wrongmsg
[] =
97 "WARNING - POTENTIAL SECURITY BREACH!\n"
98 "The server's host key does not match the one PuTTY has\n"
99 "cached in the registry. This means that either the\n"
100 "server administrator has changed the host key, or you\n"
101 "have actually connected to another computer pretending\n"
102 "to be the server.\n"
103 "The new key fingerprint is:\n"
105 "If you were expecting this change and trust the new key,\n"
106 "enter Yes to update PuTTY's cache and continue connecting.\n"
107 "If you want to carry on connecting but without updating\n"
108 "the cache, enter No.\n"
109 "If you want to abandon the connection completely, press\n"
110 "Return to cancel. Pressing Return is the ONLY guaranteed\n"
112 "Update cached key? (y/n, Return cancels connection) ";
114 static const char abandoned
[] = "Connection abandoned.\n";
119 * Verify the key against the registry.
121 ret
= verify_host_key(host
, port
, keytype
, keystr
);
123 if (ret
== 0) /* success - key matched OK */
125 if (ret
== 2) { /* key was different */
126 fprintf(stderr
, wrongmsg
, fingerprint
);
127 if (fgets(line
, sizeof(line
), stdin
) &&
128 line
[0] != '\0' && line
[0] != '\n') {
129 if (line
[0] == 'y' || line
[0] == 'Y')
130 store_host_key(host
, port
, keytype
, keystr
);
132 fprintf(stderr
, abandoned
);
136 if (ret
== 1) { /* key was absent */
137 fprintf(stderr
, absentmsg
, fingerprint
);
138 if (fgets(line
, sizeof(line
), stdin
) &&
139 (line
[0] == 'y' || line
[0] == 'Y'))
140 store_host_key(host
, port
, keytype
, keystr
);
142 fprintf(stderr
, abandoned
);
148 /* GUI Adaptation - Sept 2000 */
149 static void send_msg(HWND h
, UINT message
, WPARAM wParam
)
151 while (!PostMessage( h
, message
, wParam
, 0))
155 static void tell_char(FILE *stream
, char c
)
161 unsigned int msg_id
= WM_STD_OUT_CHAR
;
162 if (stream
== stderr
) msg_id
= WM_STD_ERR_CHAR
;
163 send_msg( (HWND
)atoi(gui_hwnd
), msg_id
, (WPARAM
)c
);
167 static void tell_str(FILE *stream
, char *str
)
171 for( i
= 0; i
< strlen(str
); ++i
)
172 tell_char(stream
, str
[i
]);
175 static void tell_user(FILE *stream
, char *fmt
, ...)
177 char str
[0x100]; /* Make the size big enough */
180 vsprintf(str
, fmt
, ap
);
183 tell_str(stream
, str
);
186 static void gui_update_stats(char *name
, unsigned long size
, int percentage
, time_t elapsed
)
190 if (strcmp(name
,statname
) != 0)
192 for( i
= 0; i
< strlen(name
); ++i
)
193 send_msg( (HWND
)atoi(gui_hwnd
), WM_STATS_CHAR
, (WPARAM
)name
[i
]);
194 send_msg( (HWND
)atoi(gui_hwnd
), WM_STATS_CHAR
, (WPARAM
)'\n' );
195 strcpy(statname
,name
);
197 if (statsize
!= size
)
199 send_msg( (HWND
)atoi(gui_hwnd
), WM_STATS_SIZE
, (WPARAM
)size
);
202 if (statelapsed
!= elapsed
)
204 send_msg( (HWND
)atoi(gui_hwnd
), WM_STATS_ELAPSED
, (WPARAM
)elapsed
);
205 statelapsed
= elapsed
;
207 if (statperct
!= percentage
)
209 send_msg( (HWND
)atoi(gui_hwnd
), WM_STATS_PERCENT
, (WPARAM
)percentage
);
210 statperct
= percentage
;
215 * Print an error message and perform a fatal exit.
217 void fatalbox(char *fmt
, ...)
219 char str
[0x100]; /* Make the size big enough */
222 strcpy(str
, "Fatal:");
223 vsprintf(str
+strlen(str
), fmt
, ap
);
226 tell_str(stderr
, str
);
230 void connection_fatal(char *fmt
, ...)
232 char str
[0x100]; /* Make the size big enough */
235 strcpy(str
, "Fatal:");
236 vsprintf(str
+strlen(str
), fmt
, ap
);
239 tell_str(stderr
, str
);
245 * Receive a block of data from the SSH link. Block until all data
248 * To do this, we repeatedly call the SSH protocol module, with our
249 * own trap in term_out() to catch the data that comes back. We do
250 * this until we have enough data.
252 static unsigned char *outptr
; /* where to put the data */
253 static unsigned outlen
; /* how much data required */
254 static unsigned char *pending
= NULL
; /* any spare data */
255 static unsigned pendlen
=0, pendsize
=0; /* length and phys. size of buffer */
256 void term_out(void) {
258 * Here we must deal with a block of data, in `inbuf', size
261 unsigned char *p
= inbuf
;
262 unsigned len
= inbuf_head
;
267 * If this is before the real session begins, just return.
273 unsigned used
= outlen
;
274 if (used
> len
) used
= len
;
275 memcpy(outptr
, p
, used
);
276 outptr
+= used
; outlen
-= used
;
277 p
+= used
; len
-= used
;
281 if (pendsize
< pendlen
+ len
) {
282 pendsize
= pendlen
+ len
+ 4096;
283 pending
= (pending ?
realloc(pending
, pendsize
) :
286 fatalbox("Out of memory");
288 memcpy(pending
+pendlen
, p
, len
);
292 static int ssh_scp_recv(unsigned char *buf
, int len
) {
299 * See if the pending-input block contains some of what we
303 unsigned pendused
= pendlen
;
304 if (pendused
> outlen
)
306 memcpy(outptr
, pending
, pendused
);
307 memmove(pending
, pending
+pendused
, pendlen
-pendused
);
323 if (s
== INVALID_SOCKET
) {
324 connection_open
= FALSE
;
329 if (select(1, &readfds
, NULL
, NULL
, NULL
) < 0)
331 back
->msg(0, FD_READ
);
339 * Loop through the ssh connection and authentication process.
341 static void ssh_scp_init(void) {
345 if (s
== INVALID_SOCKET
)
347 while (!back
->sendok()) {
351 if (select(1, &readfds
, NULL
, NULL
, NULL
) < 0)
353 back
->msg(0, FD_READ
);
359 * Print an error message and exit after closing the SSH link.
361 static void bump(char *fmt
, ...)
363 char str
[0x100]; /* Make the size big enough */
366 strcpy(str
, "Fatal:");
367 vsprintf(str
+strlen(str
), fmt
, ap
);
370 tell_str(stderr
, str
);
372 if (connection_open
) {
374 back
->special(TS_EOF
);
375 ssh_scp_recv(&ch
, 1);
380 static int get_password(const char *prompt
, char *str
, int maxlen
)
386 static int tried_once
= 0;
391 strncpy(str
, password
, maxlen
);
392 str
[maxlen
-1] = '\0';
398 /* GUI Adaptation - Sept 2000 */
400 if (maxlen
>0) str
[0] = '\0';
402 hin
= GetStdHandle(STD_INPUT_HANDLE
);
403 hout
= GetStdHandle(STD_OUTPUT_HANDLE
);
404 if (hin
== INVALID_HANDLE_VALUE
|| hout
== INVALID_HANDLE_VALUE
)
405 bump("Cannot get standard input/output handles");
407 GetConsoleMode(hin
, &savemode
);
408 SetConsoleMode(hin
, (savemode
& (~ENABLE_ECHO_INPUT
)) |
409 ENABLE_PROCESSED_INPUT
| ENABLE_LINE_INPUT
);
411 WriteFile(hout
, prompt
, strlen(prompt
), &i
, NULL
);
412 ReadFile(hin
, str
, maxlen
-1, &i
, NULL
);
414 SetConsoleMode(hin
, savemode
);
416 if ((int)i
> maxlen
) i
= maxlen
-1; else i
= i
- 2;
419 WriteFile(hout
, "\r\n", 2, &i
, NULL
);
426 * Open an SSH connection to user@host and execute cmd.
428 static void do_cmd(char *host
, char *user
, char *cmd
)
430 char *err
, *realhost
;
432 if (host
== NULL
|| host
[0] == '\0')
433 bump("Empty host name");
435 /* Try to load settings for this host */
436 do_defaults(host
, &cfg
);
437 if (cfg
.host
[0] == '\0') {
438 /* No settings for this host; use defaults */
439 strncpy(cfg
.host
, host
, sizeof(cfg
.host
)-1);
440 cfg
.host
[sizeof(cfg
.host
)-1] = '\0';
445 if (user
!= NULL
&& user
[0] != '\0') {
446 strncpy(cfg
.username
, user
, sizeof(cfg
.username
)-1);
447 cfg
.username
[sizeof(cfg
.username
)-1] = '\0';
448 } else if (cfg
.username
[0] == '\0') {
449 bump("Empty user name");
452 if (cfg
.protocol
!= PROT_SSH
)
456 cfg
.port
= portnumber
;
458 strncpy(cfg
.remote_cmd
, cmd
, sizeof(cfg
.remote_cmd
));
459 cfg
.remote_cmd
[sizeof(cfg
.remote_cmd
)-1] = '\0';
464 err
= back
->init(NULL
, cfg
.host
, cfg
.port
, &realhost
);
466 bump("ssh_init: %s", err
);
468 if (verbose
&& realhost
!= NULL
)
469 tell_user(stderr
, "Connected to %s\n", realhost
);
475 * Update statistic information about current file.
477 static void print_stats(char *name
, unsigned long size
, unsigned long done
,
478 time_t start
, time_t now
)
485 /* GUI Adaptation - Sept 2000 */
487 gui_update_stats(name
, size
, ((done
*100) / size
), now
-start
);
490 ratebs
= (float) done
/ (now
- start
);
492 ratebs
= (float) done
;
497 eta
= (unsigned long) ((size
- done
) / ratebs
);
498 sprintf(etastr
, "%02ld:%02ld:%02ld",
499 eta
/ 3600, (eta
% 3600) / 60, eta
% 60);
501 pct
= (int) (100.0 * (float) done
/ size
);
503 printf("\r%-25.25s | %10ld kB | %5.1f kB/s | ETA: %8s | %3d%%",
504 name
, done
/ 1024, ratebs
/ 1024.0,
513 * Find a colon in str and return a pointer to the colon.
514 * This is used to separate hostname from filename.
516 static char * colon(char *str
)
518 /* We ignore a leading colon, since the hostname cannot be
519 empty. We also ignore a colon as second character because
520 of filenames like f:myfile.txt. */
521 if (str
[0] == '\0' ||
525 while (*str
!= '\0' &&
537 * Wait for a response from the other side.
538 * Return 0 if ok, -1 if error.
540 static int response(void)
542 char ch
, resp
, rbuf
[2048];
545 if (ssh_scp_recv(&resp
, 1) <= 0)
546 bump("Lost connection");
556 case 2: /* fatal error */
558 if (ssh_scp_recv(&ch
, 1) <= 0)
559 bump("Protocol error: Lost connection");
561 } while (p
< sizeof(rbuf
) && ch
!= '\n');
564 tell_user(stderr
, "%s\n", rbuf
);
573 * Send an error message to the other side and to the screen.
574 * Increment error counter.
576 static void run_err(const char *fmt
, ...)
582 strcpy(str
, "\01scp: ");
583 vsprintf(str
+strlen(str
), fmt
, ap
);
585 back
->send(str
, strlen(str
));
586 tell_user(stderr
, "%s",str
);
591 * Execute the source part of the SCP protocol.
593 static void source(char *src
)
601 unsigned long stat_bytes
;
602 time_t stat_starttime
, stat_lasttime
;
604 attr
= GetFileAttributes(src
);
605 if (attr
== (DWORD
)-1) {
606 run_err("%s: No such file or directory", src
);
610 if ((attr
& FILE_ATTRIBUTE_DIRECTORY
) != 0) {
613 * Avoid . and .. directories.
616 p
= strrchr(src
, '/');
618 p
= strrchr(src
, '\\');
623 if (!strcmp(p
, ".") || !strcmp(p
, ".."))
628 run_err("%s: not a regular file", src
);
633 if ((last
= strrchr(src
, '/')) == NULL
)
637 if (strrchr(last
, '\\') != NULL
)
638 last
= strrchr(last
, '\\') + 1;
639 if (last
== src
&& strchr(src
, ':') != NULL
)
640 last
= strchr(src
, ':') + 1;
642 f
= CreateFile(src
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
643 OPEN_EXISTING
, 0, 0);
644 if (f
== INVALID_HANDLE_VALUE
) {
645 run_err("%s: Cannot open file", src
);
650 FILETIME actime
, wrtime
;
651 unsigned long mtime
, atime
;
652 GetFileTime(f
, NULL
, &actime
, &wrtime
);
653 TIME_WIN_TO_POSIX(actime
, atime
);
654 TIME_WIN_TO_POSIX(wrtime
, mtime
);
655 sprintf(buf
, "T%lu 0 %lu 0\n", mtime
, atime
);
656 back
->send(buf
, strlen(buf
));
661 size
= GetFileSize(f
, NULL
);
662 sprintf(buf
, "C0644 %lu %s\n", size
, last
);
664 tell_user(stderr
, "Sending file modes: %s", buf
);
665 back
->send(buf
, strlen(buf
));
671 stat_starttime
= time(NULL
);
675 for (i
= 0; i
< size
; i
+= 4096) {
678 if (i
+ k
> size
) k
= size
- i
;
679 if (! ReadFile(f
, transbuf
, k
, &j
, NULL
) || j
!= k
) {
680 if (statistics
) printf("\n");
681 bump("%s: Read error", src
);
683 back
->send(transbuf
, k
);
686 if (time(NULL
) != stat_lasttime
||
688 stat_lasttime
= time(NULL
);
689 print_stats(last
, size
, stat_bytes
,
690 stat_starttime
, stat_lasttime
);
701 * Recursively send the contents of a directory.
703 static void rsource(char *src
)
708 WIN32_FIND_DATA fdat
;
711 if ((last
= strrchr(src
, '/')) == NULL
)
715 if (strrchr(last
, '\\') != NULL
)
716 last
= strrchr(last
, '\\') + 1;
717 if (last
== src
&& strchr(src
, ':') != NULL
)
718 last
= strchr(src
, ':') + 1;
720 /* maybe send filetime */
722 sprintf(buf
, "D0755 0 %s\n", last
);
724 tell_user(stderr
, "Entering directory: %s", buf
);
725 back
->send(buf
, strlen(buf
));
729 sprintf(buf
, "%s/*", src
);
730 dir
= FindFirstFile(buf
, &fdat
);
731 ok
= (dir
!= INVALID_HANDLE_VALUE
);
733 if (strcmp(fdat
.cFileName
, ".") == 0 ||
734 strcmp(fdat
.cFileName
, "..") == 0) {
735 } else if (strlen(src
) + 1 + strlen(fdat
.cFileName
) >=
737 run_err("%s/%s: Name too long", src
, fdat
.cFileName
);
739 sprintf(buf
, "%s/%s", src
, fdat
.cFileName
);
742 ok
= FindNextFile(dir
, &fdat
);
747 back
->send(buf
, strlen(buf
));
752 * Execute the sink part of the SCP protocol.
754 static void sink(char *targ
)
764 unsigned long mtime
, atime
;
766 unsigned long size
, i
;
768 unsigned long stat_bytes
;
769 time_t stat_starttime
, stat_lasttime
;
772 attr
= GetFileAttributes(targ
);
773 if (attr
!= (DWORD
)-1 && (attr
& FILE_ATTRIBUTE_DIRECTORY
) != 0)
776 if (targetshouldbedirectory
&& !targisdir
)
777 bump("%s: Not a directory", targ
);
783 if (ssh_scp_recv(&ch
, 1) <= 0)
786 bump("Protocol error: Unexpected newline");
790 if (ssh_scp_recv(&ch
, 1) <= 0)
791 bump("Lost connection");
793 } while (i
< sizeof(buf
) && ch
!= '\n');
796 case '\01': /* error */
797 tell_user(stderr
, "%s\n", buf
+1);
800 case '\02': /* fatal error */
806 if (sscanf(buf
, "T%ld %*d %ld %*d",
807 &mtime
, &atime
) == 2) {
812 bump("Protocol error: Illegal time format");
817 bump("Protocol error: Expected control record");
820 if (sscanf(buf
+1, "%u %lu %[^\n]", &mode
, &size
, namebuf
) != 3)
821 bump("Protocol error: Illegal file descriptor format");
830 strcpy(namebuf
, targ
);
832 attr
= GetFileAttributes(namebuf
);
833 exists
= (attr
!= (DWORD
)-1);
836 if (exists
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
) == 0) {
837 run_err("%s: Not a directory", namebuf
);
841 if (! CreateDirectory(namebuf
, NULL
)) {
842 run_err("%s: Cannot create directory",
848 /* can we set the timestamp for directories ? */
852 f
= CreateFile(namebuf
, GENERIC_WRITE
, 0, NULL
,
853 CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, 0);
854 if (f
== INVALID_HANDLE_VALUE
) {
855 run_err("%s: Cannot create file", namebuf
);
863 stat_starttime
= time(NULL
);
865 if ((stat_name
= strrchr(namebuf
, '/')) == NULL
)
869 if (strrchr(stat_name
, '\\') != NULL
)
870 stat_name
= strrchr(stat_name
, '\\') + 1;
873 for (i
= 0; i
< size
; i
+= 4096) {
876 if (i
+ k
> size
) k
= size
- i
;
877 if (ssh_scp_recv(transbuf
, k
) == 0)
878 bump("Lost connection");
879 if (wrerror
) continue;
880 if (! WriteFile(f
, transbuf
, k
, &j
, NULL
) || j
!= k
) {
883 printf("\r%-25.25s | %50s\n",
885 "Write error.. waiting for end of file");
890 if (time(NULL
) > stat_lasttime
||
892 stat_lasttime
= time(NULL
);
893 print_stats(stat_name
, size
, stat_bytes
,
894 stat_starttime
, stat_lasttime
);
901 FILETIME actime
, wrtime
;
902 TIME_POSIX_TO_WIN(atime
, actime
);
903 TIME_POSIX_TO_WIN(mtime
, wrtime
);
904 SetFileTime(f
, NULL
, &actime
, &wrtime
);
909 run_err("%s: Write error", namebuf
);
917 * We will copy local files to a remote server.
919 static void toremote(int argc
, char *argv
[])
921 char *src
, *targ
, *host
, *user
;
927 /* Separate host from filename */
931 bump("targ == NULL in toremote()");
935 /* Substitute "." for emtpy target */
937 /* Separate host and username */
939 host
= strrchr(host
, '@');
950 /* Find out if the source filespec covers multiple files
951 if so, we should set the targetshouldbedirectory flag */
953 WIN32_FIND_DATA fdat
;
954 if (colon(argv
[0]) != NULL
)
955 bump("%s: Remote to remote not supported", argv
[0]);
956 fh
= FindFirstFile(argv
[0], &fdat
);
957 if (fh
== INVALID_HANDLE_VALUE
)
958 bump("%s: No such file or directory\n", argv
[0]);
959 if (FindNextFile(fh
, &fdat
))
960 targetshouldbedirectory
= 1;
964 cmd
= smalloc(strlen(targ
) + 100);
965 sprintf(cmd
, "scp%s%s%s%s -t %s",
966 verbose ?
" -v" : "",
967 recursive ?
" -r" : "",
968 preserve ?
" -p" : "",
969 targetshouldbedirectory ?
" -d" : "",
971 do_cmd(host
, user
, cmd
);
976 for (i
= 0; i
< argc
- 1; i
++) {
978 WIN32_FIND_DATA fdat
;
980 if (colon(src
) != NULL
) {
981 tell_user(stderr
, "%s: Remote to remote not supported\n", src
);
985 dir
= FindFirstFile(src
, &fdat
);
986 if (dir
== INVALID_HANDLE_VALUE
) {
987 run_err("%s: No such file or directory", src
);
993 if (strlen(src
) + strlen(fdat
.cFileName
) >=
995 tell_user(stderr
, "%s: Name too long", src
);
998 strcpy(namebuf
, src
);
999 if ((last
= strrchr(namebuf
, '/')) == NULL
)
1003 if (strrchr(last
, '\\') != NULL
)
1004 last
= strrchr(last
, '\\') + 1;
1005 if (last
== namebuf
&& strrchr(namebuf
, ':') != NULL
)
1006 last
= strchr(namebuf
, ':') + 1;
1007 strcpy(last
, fdat
.cFileName
);
1009 } while (FindNextFile(dir
, &fdat
));
1015 * We will copy files from a remote server to the local machine.
1017 static void tolocal(int argc
, char *argv
[])
1019 char *src
, *targ
, *host
, *user
;
1023 bump("More than one remote source not supported");
1028 /* Separate host from filename */
1032 bump("Local to local copy not supported");
1036 /* Substitute "." for empty filename */
1038 /* Separate username and hostname */
1040 host
= strrchr(host
, '@');
1050 cmd
= smalloc(strlen(src
) + 100);
1051 sprintf(cmd
, "scp%s%s%s%s -f %s",
1052 verbose ?
" -v" : "",
1053 recursive ?
" -r" : "",
1054 preserve ?
" -p" : "",
1055 targetshouldbedirectory ?
" -d" : "",
1057 do_cmd(host
, user
, cmd
);
1064 * We will issue a list command to get a remote directory.
1066 static void get_dir_list(int argc
, char *argv
[])
1068 char *src
, *host
, *user
;
1074 /* Separate host from filename */
1078 bump("Local to local copy not supported");
1082 /* Substitute "." for empty filename */
1084 /* Separate username and hostname */
1086 host
= strrchr(host
, '@');
1096 cmd
= smalloc(4*strlen(src
) + 100);
1097 strcpy(cmd
, "ls -la '");
1098 p
= cmd
+ strlen(cmd
);
1099 for (q
= src
; *q
; q
++) {
1101 *p
++ = '\''; *p
++ = '\\'; *p
++ = '\''; *p
++ = '\'';
1109 do_cmd(host
, user
, cmd
);
1112 while (ssh_scp_recv(&c
, 1) > 0)
1113 tell_char(stdout
, c
);
1117 * Initialize the Win$ock driver.
1119 static void init_winsock(void)
1124 winsock_ver
= MAKEWORD(1, 1);
1125 if (WSAStartup(winsock_ver
, &wsadata
))
1126 bump("Unable to initialise WinSock");
1127 if (LOBYTE(wsadata
.wVersion
) != 1 ||
1128 HIBYTE(wsadata
.wVersion
) != 1)
1129 bump("WinSock version is incompatible with 1.1");
1133 * Short description of parameters.
1135 static void usage(void)
1137 printf("PuTTY Secure Copy client\n");
1138 printf("%s\n", ver
);
1139 printf("Usage: pscp [options] [user@]host:source target\n");
1140 printf(" pscp [options] source [source...] [user@]host:target\n");
1141 printf(" pscp [options] -ls user@host:filespec\n");
1142 printf("Options:\n");
1143 printf(" -p preserve file attributes\n");
1144 printf(" -q quiet, don't show statistics\n");
1145 printf(" -r copy directories recursively\n");
1146 printf(" -v show verbose messages\n");
1147 printf(" -P port connect to specified port\n");
1148 printf(" -pw passw login with specified password\n");
1149 /* GUI Adaptation - Sept 2000 */
1150 printf(" -gui hWnd GUI mode with the windows handle for receiving messages\n");
1155 * Main program (no, really?)
1157 int main(int argc
, char *argv
[])
1162 default_protocol
= PROT_TELNET
;
1164 flags
= FLAG_STDERR
;
1165 ssh_get_password
= &get_password
;
1168 for (i
= 1; i
< argc
; i
++) {
1169 if (argv
[i
][0] != '-')
1171 if (strcmp(argv
[i
], "-v") == 0)
1172 verbose
= 1, flags
|= FLAG_VERBOSE
;
1173 else if (strcmp(argv
[i
], "-r") == 0)
1175 else if (strcmp(argv
[i
], "-p") == 0)
1177 else if (strcmp(argv
[i
], "-q") == 0)
1179 else if (strcmp(argv
[i
], "-h") == 0 ||
1180 strcmp(argv
[i
], "-?") == 0)
1182 else if (strcmp(argv
[i
], "-P") == 0 && i
+1 < argc
)
1183 portnumber
= atoi(argv
[++i
]);
1184 else if (strcmp(argv
[i
], "-pw") == 0 && i
+1 < argc
)
1185 password
= argv
[++i
];
1186 else if (strcmp(argv
[i
], "-gui") == 0 && i
+1 < argc
) {
1187 gui_hwnd
= argv
[++i
];
1189 } else if (strcmp(argv
[i
], "-ls") == 0)
1191 else if (strcmp(argv
[i
], "--") == 0)
1202 get_dir_list(argc
, argv
);
1209 targetshouldbedirectory
= 1;
1211 if (colon(argv
[argc
-1]) != NULL
)
1212 toremote(argc
, argv
);
1214 tolocal(argc
, argv
);
1217 if (connection_open
) {
1219 back
->special(TS_EOF
);
1220 ssh_scp_recv(&ch
, 1);
1225 /* GUI Adaptation - August 2000 */
1227 unsigned int msg_id
= WM_RET_ERR_CNT
;
1228 if (list
) msg_id
= WM_LS_RET_ERR_CNT
;
1229 while (!PostMessage( (HWND
)atoi(gui_hwnd
), msg_id
, (WPARAM
)errs
, 0/*lParam*/ ) )
1232 return (errs
== 0 ?
0 : 1);