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
= {}
42 def type_to_name(gtype
):
43 global _type_to_name_map
44 if _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('rb')
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 # Takes a path as returned by urlparse and returns the appropriate selector
79 def path_to_selector(path
):
83 return path
[2:] # Cuts initial slash and data type identifier
85 # Takes a path as returned by urlparse and maps it to a string
86 # See section 3.4 of RFC 1738 for details
87 def path_to_datatype_name(path
):
89 # No way to tell, although "INDEX" is likely
90 return "TYPE='unknown'"
92 return type_to_name(path
[1])
94 # The following functions interpret the data returned by the gopher
95 # server according to the expected type, e.g. textfile or directory
97 # Get a directory in the form of a list of entries
104 print '(Unexpected EOF from server)'
106 if line
[-2:] == CRLF
:
108 elif line
[-1:] in CRLF
:
113 print '(Empty line from server)'
116 parts
= string
.splitfields(line
[1:], TAB
)
118 print '(Bad line from server:', `line`
, ')'
121 if parts
[4:] != ['+']:
122 print '(Extra info from server:',
126 parts
.insert(0, gtype
)
130 # Get a text file as a list of lines, with trailing CRLF stripped
133 get_alt_textfile(f
, list.append
)
136 # Get a text file and pass each line to a function, with trailing CRLF stripped
137 def get_alt_textfile(f
, func
):
141 print '(Unexpected EOF from server)'
143 if line
[-2:] == CRLF
:
145 elif line
[-1:] in CRLF
:
153 # Get a binary file as one solid data block
158 # Get a binary file and pass each block to a function
159 def get_alt_binary(f
, func
, blocksize
):
161 data
= f
.read(blocksize
)
166 # Trivial test program
170 opts
, args
= getopt
.getopt(sys
.argv
[1:], '')
171 selector
= DEF_SELECTOR
182 type, selector
= type[0], type
193 f
= send_query(selector
, query
, host
)
195 f
= send_selector(selector
, host
)
197 list = get_textfile(f
)
198 for item
in list: print item
199 elif type in (A_MENU
, A_INDEX
):
200 list = get_directory(f
)
201 for item
in list: print item
204 print 'binary data:', len(data
), 'bytes:', `data
[:100]`
[:40]
206 # Run the test when run as script
207 if __name__
== '__main__':