1#!../expect -f
2# ftp-inband - copy files over a telnet/rlogin/etc link
3# Author: Don Libes, NIST
4# Date: Jan 11, 1993
5
6# Program follows usual conventions and is otherwise self-documenting.
7# Assumes standard UNIX conventions on both sides.  It uses "compress"
8# which can be replaced with gzip or removed totally - it's just there
9# for efficiency.
10# Assumes error-free transmission (i.e., MNP modems), telnet links, etc.
11# Assumes remote shell does not reset tty modes after each command.
12
13# Note, there is very little error checking.  This script was written
14# primarily as an exercise - just to demonstrate Expect.
15
16set prompt "(%|#|\\\$) $"		;# default prompt
17catch {set prompt $env(EXPECT_PROMPT)}
18
19set timeout -1
20set verbose_flag 0
21
22proc send_verbose {msg} {
23	global verbose_flag
24
25	if {$verbose_flag} {
26		send_user $msg
27	}
28}
29
30proc get {infile outfile} {
31	global prompt verbose_flag
32
33	if {!$verbose_flag} {
34		log_user 0
35	}
36
37	send_verbose "disabling echo: "
38	send "stty -echo\r"
39	expect -re $prompt
40
41	send_verbose "remote pid is "
42	send "echo $$\r"
43	expect -re "(.*)\r\n.*$prompt" {set rpid $expect_out(1,string)}
44
45	set pid [pid]
46	# pid is local pid, rpid is remote pid
47
48	set infile_plain	"/tmp/$rpid"
49	set infile_compressed	"$infile_plain.Z"
50	set infile_encoded	"$infile_compressed.uu"
51
52	set outfile_plain	"/tmp/$pid"
53	set outfile_compressed	"$outfile_plain.Z"
54	set outfile_encoded	"$outfile_compressed.uu"
55
56	set out [open $outfile_encoded w]
57
58	send_verbose "compressing\n"
59	send "compress -fc $infile > $infile_compressed\r"
60	expect -re $prompt
61
62	# use label corresponding to temporary name on local system
63	send_verbose "uuencoding\n"
64	send "uuencode $infile_compressed $outfile_compressed > $infile_encoded\r"
65	expect -re $prompt
66
67	send_verbose "copying\n"
68	send "cat $infile_encoded\r"
69
70	log_user 0
71
72	expect {
73		-re "^end\r\n" {
74			puts $out "end"
75			close $out
76		} -re "^(\[^\r]*)\r\n" {
77			puts $out $expect_out(1,string)
78			send_verbose "."
79			exp_continue
80		}
81	}
82
83	if {$verbose_flag} {
84		send_user "\n"		;# after last "."
85		log_user 1
86	}
87
88	expect -re $prompt			;# wait for prompt from cat
89
90	send_verbose "deleting temporary files\n"
91	send "rm -f $infile_compressed $infile_encoded\r"
92	expect -re $prompt
93
94	send_verbose "switching attention to local system\nuudecoding\n"
95	exec uudecode $outfile_encoded
96
97	send_verbose "uncompressing\n"
98	exec uncompress -f $outfile_compressed
99
100	send_verbose "renaming\n"
101	if {[catch "exec cp $outfile_plain $outfile" msg]} {
102		send_user "could not move file in place, reason: $msg\n"
103		send_user "left as $outfile_plain\n"
104		exec rm -f $outfile_encoded
105	} else {
106		exec rm -f $outfile_plain $outfile_encoded
107	}
108
109	# restore echo and serendipitously reprompt
110	send "stty echo\r"
111
112	log_user 1
113}	
114
115proc put {infile outfile} {
116	global prompt verbose_flag
117
118	if {!$verbose_flag} {
119		log_user 0
120	}
121
122	send_verbose "disabling echo: "
123	send "stty -echo\r"
124	expect -re $prompt
125
126	send_verbose "remote pid is "
127	send "echo $$\r"
128	expect -re "(.*)\r\n.*$prompt" {set rpid $expect_out(1,string)}
129
130	set pid [pid]
131	# pid is local pid, rpid is remote pid
132
133	set infile_plain	"/tmp/$pid"
134	set infile_compressed	"$infile_plain.Z"
135	set infile_encoded	"$infile_compressed.uu"
136
137	set outfile_plain	"/tmp/$rpid"
138	set outfile_compressed	"$outfile_plain.Z"
139	set outfile_encoded	"$outfile_compressed.uu"
140
141	set out [open $outfile_encoded w]
142
143	send_verbose "compressing\n"
144	exec compress -fc $infile > $infile_compressed
145
146	# use label corresponding to temporary name on local system
147	send_verbose "uuencoding\n"
148	exec uuencode $infile_compressed $outfile_compressed > $infile_encoded
149
150	send_verbose "copying\n"
151	send "cat > $outfile_encoded\r"
152
153	log_user 0
154
155	set fp [open $infile_encoded r]
156	while {1} {
157		if {-1 == [gets $fp buf]} break
158		send_verbose "."
159		send -- "$buf\r"
160	}
161
162	if {$verbose_flag} {
163		send_user "\n"			;# after last "."
164		log_user 1
165	}
166
167	send "\004"				;# eof
168	close $fp
169
170	send_verbose "deleting temporary files\n"
171	exec rm -f $infile_compressed $infile_encoded
172
173	send_verbose "switching attention to remote system\n"
174
175	expect -re $prompt			;# wait for prompt from cat
176
177	send_verbose "uudecoding\n"
178	send "uudecode $outfile_encoded\r"
179	expect -re $prompt
180
181	send_verbose "uncompressing\n"
182	send "uncompress -f $outfile_compressed\r"
183	expect -re $prompt
184
185	send_verbose "renaming\n"
186	send "cp $outfile_plain $outfile\r"
187	expect -re $prompt
188
189	send_verbose "deleting temporary files\n"
190	send "rm -f $outfile_plain $outfile_encoded\r"
191	expect -re $prompt
192
193	# restore echo and serendipitously reprompt
194	send "stty echo\r"
195
196	log_user 1
197}	
198
199proc get_main {} {
200	stty -raw echo
201	send_user "g\nget remote file \[localfile]: "
202	expect_user {
203		-re "(\[^ ]+) +(\[^ ]+)\n" {
204			send_user "copying (remote) $expect_out(1,string) to (local) $expect_out(2,string)\n"
205			get $expect_out(1,string) $expect_out(2,string)
206		} -re "(\[^ ]+)\n" {
207			send_user "copying $expect_out(1,string)\n"
208			get $expect_out(1,string) $expect_out(1,string)
209		} -re "\n" {
210			send_user "eh?\n"
211		}
212	}
213	stty raw -echo
214}
215
216proc put_main {} {
217	stty -raw echo
218	send_user "p\nput localfile \[remotefile]: "
219	expect_user {
220		-re "(\[^ ]+) +(\[^ ]+)\n" {
221			send_user "copying (local) $expect_out(1,string) to (remote) $expect_out(2,string)\n"
222			put $expect_out(1,string) $expect_out(2,string)
223		} -re "(\[^ ]+)\n" {
224			send_user "copying $expect_out(1,string)\n"
225			put $expect_out(1,string) $expect_out(1,string)
226		} -re "\n" {
227			send_user "eh?\n"
228		}
229	}
230	stty raw -echo
231}
232
233proc chdir {} {
234	stty -raw echo
235	send_user "c\n"
236	send_user "current directory is [pwd], new directory: "
237	expect_user -re "(.*)\n" {
238		cd $expect_out(1,string)
239	}
240	stty raw -echo
241}
242
243proc verbose {} {
244	global verbose_flag
245
246	set verbose_flag [expr !$verbose_flag]
247	send_user "verbose [verbose_status]\r\n"
248}
249
250proc verbose_status {} {
251	global verbose_flag
252
253	if {$verbose_flag} {
254		return "on"
255	} else {
256		return "off"
257	}
258}
259
260proc cmd {} {
261	set CTRLZ \032
262
263	send_user "command (g,p,? for more): "
264	expect_user {
265		g get_main
266		p put_main
267		c chdir
268		v verbose
269		~ {send "~"}
270		"\\?" {
271			send_user "?\n"
272			send_user "~~g  get file from remote system\n"
273			send_user "~~p  put file to remote system\n"
274			send_user "~~c  change/show directory on local system\n"
275			send_user "~~~  send ~~ to remote system\n"
276			send_user "~~?  this list\n"
277			send_user "~~v  verbose mode toggle (currently [verbose_status])\n"
278			send_user "~~^Z suspend\n"
279		}
280		$CTRLZ {
281			stty -raw echo
282			exec kill -STOP [pid]
283			stty raw -echo
284		}
285		-re . {send_user "unknown command\n"}
286	}
287	send_user "resuming session...\n"
288}
289
290spawn -noecho $env(SHELL)
291
292send_user "Once logged in, cd to directory to transfer to/from and press: ~~\n"
293send_user "One moment...\n"
294interact ~~ cmd
295
296