Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6b8d699

Browse files
committed
Initial revision
1 parent a9e7dc1 commit 6b8d699

1 file changed

Lines changed: 347 additions & 0 deletions

File tree

Demo/sockets/gopher.py

Lines changed: 347 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,347 @@
1+
#! /usr/local/bin/python
2+
3+
# A simple gopher client.
4+
#
5+
# Usage: gopher [ [selector] host [port] ]
6+
7+
import string
8+
import sys
9+
import os
10+
import socket
11+
12+
# Default selector, host and port
13+
DEF_SELECTOR = ''
14+
DEF_HOST = 'gopher.micro.umn.edu'
15+
DEF_PORT = 70
16+
17+
# Recognized file types
18+
T_TEXTFILE = '0'
19+
T_MENU = '1'
20+
T_CSO = '2'
21+
T_ERROR = '3'
22+
T_BINHEX = '4'
23+
T_DOS = '5'
24+
T_UUENCODE = '6'
25+
T_SEARCH = '7'
26+
T_TELNET = '8'
27+
T_BINARY = '9'
28+
T_REDUNDANT = '+'
29+
T_SOUND = 's'
30+
31+
# Dictionary mapping types to strings
32+
typename = {'0': '<TEXT>', '1': '<DIR>', '2': '<CSO>', '3': '<ERROR>', \
33+
'4': '<BINHEX>', '5': '<DOS>', '6': '<UUENCODE>', '7': '<SEARCH>', \
34+
'8': '<TELNET>', '9': '<BINARY>', '+': '<REDUNDANT>', 's': '<SOUND>'}
35+
36+
# Oft-used characters and strings
37+
CRLF = '\r\n'
38+
TAB = '\t'
39+
40+
# Open a TCP connection to a given host and port
41+
def open_socket(host, port):
42+
if type(port) == type(''):
43+
port = string.atoi(port)
44+
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
45+
s.connect((host, port))
46+
return s
47+
48+
# Send a selector to a given host and port, return a file with the reply
49+
def send_request(selector, host, port):
50+
s = open_socket(host, port)
51+
s.send(selector + CRLF)
52+
s.shutdown(1)
53+
return s.makefile('r')
54+
55+
# Get a menu in the form of a list of entries
56+
def get_menu(selector, host, port):
57+
f = send_request(selector, host, port)
58+
list = []
59+
while 1:
60+
line = f.readline()
61+
if not line:
62+
print '(Unexpected EOF from server)'
63+
break
64+
if line[-2:] == CRLF:
65+
line = line[:-2]
66+
elif line[-1:] in CRLF:
67+
line = line[:-1]
68+
if line == '.':
69+
break
70+
if not line:
71+
print '(Empty line from server)'
72+
continue
73+
typechar = line[0]
74+
parts = string.splitfields(line[1:], TAB)
75+
if len(parts) < 4:
76+
print '(Bad line from server:', `line`, ')'
77+
continue
78+
if len(parts) > 4:
79+
print '(Extra info from server:', parts[4:], ')'
80+
parts.insert(0, typechar)
81+
list.append(parts)
82+
f.close()
83+
return list
84+
85+
# Get a text file as a list of lines, with trailing CRLF stripped
86+
def get_textfile(selector, host, port):
87+
list = []
88+
get_alt_textfile(selector, host, port, list.append)
89+
return list
90+
91+
# Get a text file and pass each line to a function, with trailing CRLF stripped
92+
def get_alt_textfile(selector, host, port, func):
93+
f = send_request(selector, host, port)
94+
while 1:
95+
line = f.readline()
96+
if not line:
97+
print '(Unexpected EOF from server)'
98+
break
99+
if line[-2:] == CRLF:
100+
line = line[:-2]
101+
elif line[-1:] in CRLF:
102+
line = line[:-1]
103+
if line == '.':
104+
break
105+
if line[:2] == '..':
106+
line = line[1:]
107+
func(line)
108+
f.close()
109+
110+
# Get a binary file as one solid data block
111+
def get_binary(selector, host, port):
112+
f = send_request(selector, host, port)
113+
data = f.read()
114+
f.close()
115+
return data
116+
117+
# Get a binary file and pass each block to a function
118+
def get_alt_binary(selector, host, port, func, blocksize):
119+
f = send_request(selector, host, port)
120+
while 1:
121+
data = f.read(blocksize)
122+
if not data:
123+
break
124+
func(data)
125+
126+
# A *very* simple interactive browser
127+
128+
# Browser main command, has default arguments
129+
def browser(*args):
130+
selector = DEF_SELECTOR
131+
host = DEF_HOST
132+
port = DEF_PORT
133+
n = len(args)
134+
if n > 0 and args[0]:
135+
selector = args[0]
136+
if n > 1 and args[1]:
137+
host = args[1]
138+
if n > 2 and args[2]:
139+
port = args[2]
140+
if n > 3:
141+
raise RuntimeError, 'too many args'
142+
try:
143+
browse_menu(selector, host, port)
144+
except socket.error, msg:
145+
print 'Socket error:', msg
146+
sys.exit(1)
147+
except KeyboardInterrupt:
148+
print '\n[Goodbye]'
149+
150+
# Browse a menu
151+
def browse_menu(selector, host, port):
152+
list = get_menu(selector, host, port)
153+
while 1:
154+
print '----- MENU -----'
155+
print 'Selector:', `selector`
156+
print 'Host:', host, ' Port:', port
157+
print
158+
for i in range(len(list)):
159+
item = list[i]
160+
typechar, description = item[0], item[1]
161+
print string.rjust(`i+1`, 3) + ':', description,
162+
if typename.has_key(typechar):
163+
print typename[typechar]
164+
else:
165+
print '<TYPE=' + `typechar` + '>'
166+
print
167+
while 1:
168+
try:
169+
str = raw_input('Choice [CR == up a level]: ')
170+
except EOFError:
171+
print
172+
return
173+
if not str:
174+
return
175+
try:
176+
choice = string.atoi(str)
177+
except string.atoi_error:
178+
print 'Choice must be a number; try again:'
179+
continue
180+
if not 0 < choice <= len(list):
181+
print 'Choice out of range; try again:'
182+
continue
183+
break
184+
item = list[choice-1]
185+
typechar = item[0]
186+
[i_selector, i_host, i_port] = item[2:5]
187+
if typebrowser.has_key(typechar):
188+
browserfunc = typebrowser[typechar]
189+
try:
190+
browserfunc(i_selector, i_host, i_port)
191+
except (IOError, socket.error):
192+
print '***', sys.exc_type, ':', sys.exc_value
193+
else:
194+
print 'Unsupported object type'
195+
196+
# Browse a text file
197+
def browse_textfile(selector, host, port):
198+
x = None
199+
try:
200+
p = os.popen('${PAGER-more}', 'w')
201+
x = SaveLines().init(p)
202+
get_alt_textfile(selector, host, port, x.writeln)
203+
except IOError, msg:
204+
print 'IOError:', msg
205+
if x:
206+
x.close()
207+
f = open_savefile()
208+
if not f:
209+
return
210+
x = SaveLines().init(f)
211+
try:
212+
get_alt_textfile(selector, host, port, x.writeln)
213+
print 'Done.'
214+
except IOError, msg:
215+
print 'IOError:', msg
216+
x.close()
217+
218+
# Browse a search index
219+
def browse_search(selector, host, port):
220+
while 1:
221+
print '----- SEARCH -----'
222+
print 'Selector:', `selector`
223+
print 'Host:', host, ' Port:', port
224+
print
225+
try:
226+
query = raw_input('Query [CR == up a level]: ')
227+
except EOFError:
228+
print
229+
break
230+
query = string.strip(query)
231+
if not query:
232+
break
233+
if '\t' in query:
234+
print 'Sorry, queries cannot contain tabs'
235+
continue
236+
browse_menu(selector + TAB + query, host, port)
237+
238+
# "Browse" telnet-based information, i.e. open a telnet session
239+
def browse_telnet(selector, host, port):
240+
if selector:
241+
print 'Log in as', `selector`
242+
if type(port) <> type(''):
243+
port = `port`
244+
sts = os.system('set -x; exec telnet ' + host + ' ' + port)
245+
if sts:
246+
print 'Exit status:', sts
247+
248+
# "Browse" a binary file, i.e. save it to a file
249+
def browse_binary(selector, host, port):
250+
f = open_savefile()
251+
if not f:
252+
return
253+
x = SaveWithProgress().init(f)
254+
get_alt_binary(selector, host, port, x.write, 8*1024)
255+
x.close()
256+
257+
# "Browse" a sound file, i.e. play it or save it
258+
def browse_sound(selector, host, port):
259+
browse_binary(selector, host, port)
260+
261+
# Dictionary mapping types to browser functions
262+
typebrowser = {'0': browse_textfile, '1': browse_menu, \
263+
'4': browse_binary, '5': browse_binary, '6': browse_textfile, \
264+
'7': browse_search, \
265+
'8': browse_telnet, '9': browse_binary, 's': browse_sound}
266+
267+
# Class used to save lines, appending a newline to each line
268+
class SaveLines:
269+
def init(self, f):
270+
self.f = f
271+
return self
272+
def writeln(self, line):
273+
self.f.write(line + '\n')
274+
def close(self):
275+
sts = self.f.close()
276+
if sts:
277+
print 'Exit status:', sts
278+
279+
# Class used to save data while showing progress
280+
class SaveWithProgress:
281+
def init(self, f):
282+
self.f = f
283+
return self
284+
def write(self, data):
285+
sys.stdout.write('#')
286+
sys.stdout.flush()
287+
self.f.write(data)
288+
def close(self):
289+
print
290+
sts = self.f.close()
291+
if sts:
292+
print 'Exit status:', sts
293+
294+
# Ask for and open a save file, or return None if not to save
295+
def open_savefile():
296+
try:
297+
savefile = raw_input( \
298+
'Save as file [CR == don\'t save; |pipeline or ~user/... OK]: ')
299+
except EOFError:
300+
print
301+
return None
302+
savefile = string.strip(savefile)
303+
if not savefile:
304+
return None
305+
if savefile[0] == '|':
306+
cmd = string.strip(savefile[1:])
307+
try:
308+
p = os.popen(cmd, 'w')
309+
except IOError, msg:
310+
print `cmd`, ':', msg
311+
return None
312+
print 'Piping through', `cmd`, '...'
313+
return p
314+
if savefile[0] == '~':
315+
savefile = os.path.expanduser(savefile)
316+
try:
317+
f = open(savefile, 'w')
318+
except IOError, msg:
319+
print `savefile`, ':', msg
320+
return None
321+
print 'Saving to', `savefile`, '...'
322+
return f
323+
324+
# Test program
325+
def test():
326+
if sys.argv[4:]:
327+
print 'usage: gopher [ [selector] host [port] ]'
328+
sys.exit(2)
329+
elif sys.argv[3:]:
330+
browser(sys.argv[1], sys.argv[2], sys.argv[3])
331+
elif sys.argv[2:]:
332+
try:
333+
port = string.atoi(sys.argv[2])
334+
selector = ''
335+
host = sys.argv[1]
336+
except string.atoi_error:
337+
selector = sys.argv[1]
338+
host = sys.argv[2]
339+
port = ''
340+
browser(selector, host, port)
341+
elif sys.argv[1:]:
342+
browser('', sys.argv[1])
343+
else:
344+
browser()
345+
346+
# Call the test program as a main program
347+
test()

0 commit comments

Comments
 (0)