1 # Gopher protocol client interface
5 # Default selector, host and port
7 DEF_HOST
= 'gopher.micro.umn.edu'
10 # Recognized file types
32 A_HTML
= 'h' # HTML file
33 A_WWW
= 'w' # WWW address
39 # Function mapping all file types to strings; unknown types become TYPE='x'
41 _type_to_name_map
= None
42 def type_to_name(gtype
):
43 global _type_to_name_map
44 if not _type_to_name_map
:
47 _type_to_name_map
[eval(name
)] = name
[2:]
48 if _type_to_name_map
.has_key(gtype
):
49 return _type_to_name_map
[gtype
]
50 return 'TYPE=' + `gtype`
52 # Names for characters and strings
56 # Send a selector to a given host and port, return a file with the reply
57 def send_selector(selector
, host
, port
= 0):
61 i
= string
.find(host
, ':')
63 host
, port
= host
[:i
], string
.atoi(host
[i
+1:])
66 elif type(port
) == type(''):
67 port
= string
.atoi(port
)
68 s
= socket
.socket(socket
.AF_INET
, socket
.SOCK_STREAM
)
70 s
.send(selector
+ CRLF
)
72 return s
.makefile('r')
74 # Send a selector and a query string
75 def send_query(selector
, query
, host
, port
= 0):
76 return send_selector(selector
+ '\t' + query
, host
, port
)
78 # The following functions interpret the data returned by the gopher
79 # server according to the expected type, e.g. textfile or directory
81 # Get a directory in the form of a list of entries
88 print '(Unexpected EOF from server)'
92 elif line
[-1:] in CRLF
:
97 print '(Empty line from server)'
100 parts
= string
.splitfields(line
[1:], TAB
)
102 print '(Bad line from server:', `line`
, ')'
105 if parts
[4:] != ['+']:
106 print '(Extra info from server:', parts
[4:], ')'
109 parts
.insert(0, gtype
)
113 # Get a text file as a list of lines, with trailing CRLF stripped
116 get_alt_textfile(f
, list.append
)
119 # Get a text file and pass each line to a function, with trailing CRLF stripped
120 def get_alt_textfile(f
, func
):
124 print '(Unexpected EOF from server)'
126 if line
[-2:] == CRLF
:
128 elif line
[-1:] in CRLF
:
136 # Get a binary file as one solid data block
141 # Get a binary file and pass each block to a function
142 def get_alt_binary(f
, func
, blocksize
):
144 data
= f
.read(blocksize
)
149 # Trivial test program
153 opts
, args
= getopt
.getopt(sys
.argv
[1:], '')
154 selector
= DEF_SELECTOR
165 type, selector
= type[0], type
176 f
= send_query(selector
, query
, host
)
178 f
= send_selector(selector
, host
)
180 list = get_textfile(f
)
181 for item
in list: print item
182 elif type in (A_MENU
, A_INDEX
):
183 list = get_directory(f
)
184 for item
in list: print item
187 print 'binary data:', len(data
), 'bytes:', `data
[:100]`
[:40]
189 # Run the test when run as script
190 if __name__
== '__main__':