]> git.lizzy.rs Git - plan9front.git/blob - sys/lib/python/gopherlib.py
hgwebfs: write headers individually, so they are not limited by webfs iounit (thanks...
[plan9front.git] / sys / lib / python / gopherlib.py
1 """Gopher protocol client interface."""
2
3 __all__ = ["send_selector","send_query"]
4
5 import warnings
6 warnings.warn("the gopherlib module is deprecated", DeprecationWarning,
7               stacklevel=2)
8
9 # Default selector, host and port
10 DEF_SELECTOR = '1/'
11 DEF_HOST     = 'gopher.micro.umn.edu'
12 DEF_PORT     = 70
13
14 # Recognized file types
15 A_TEXT       = '0'
16 A_MENU       = '1'
17 A_CSO        = '2'
18 A_ERROR      = '3'
19 A_MACBINHEX  = '4'
20 A_PCBINHEX   = '5'
21 A_UUENCODED  = '6'
22 A_INDEX      = '7'
23 A_TELNET     = '8'
24 A_BINARY     = '9'
25 A_DUPLICATE  = '+'
26 A_SOUND      = 's'
27 A_EVENT      = 'e'
28 A_CALENDAR   = 'c'
29 A_HTML       = 'h'
30 A_TN3270     = 'T'
31 A_MIME       = 'M'
32 A_IMAGE      = 'I'
33 A_WHOIS      = 'w'
34 A_QUERY      = 'q'
35 A_GIF        = 'g'
36 A_HTML       = 'h'          # HTML file
37 A_WWW        = 'w'          # WWW address
38 A_PLUS_IMAGE = ':'
39 A_PLUS_MOVIE = ';'
40 A_PLUS_SOUND = '<'
41
42
43 _names = dir()
44 _type_to_name_map = {}
45 def type_to_name(gtype):
46     """Map all file types to strings; unknown types become TYPE='x'."""
47     global _type_to_name_map
48     if _type_to_name_map=={}:
49         for name in _names:
50             if name[:2] == 'A_':
51                 _type_to_name_map[eval(name)] = name[2:]
52     if gtype in _type_to_name_map:
53         return _type_to_name_map[gtype]
54     return 'TYPE=%r' % (gtype,)
55
56 # Names for characters and strings
57 CRLF = '\r\n'
58 TAB = '\t'
59
60 def send_selector(selector, host, port = 0):
61     """Send a selector to a given host and port, return a file with the reply."""
62     import socket
63     if not port:
64         i = host.find(':')
65         if i >= 0:
66             host, port = host[:i], int(host[i+1:])
67     if not port:
68         port = DEF_PORT
69     elif type(port) == type(''):
70         port = int(port)
71     s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
72     s.connect((host, port))
73     s.sendall(selector + CRLF)
74     s.shutdown(1)
75     return s.makefile('rb')
76
77 def send_query(selector, query, host, port = 0):
78     """Send a selector and a query string."""
79     return send_selector(selector + '\t' + query, host, port)
80
81 def path_to_selector(path):
82     """Takes a path as returned by urlparse and returns the appropriate selector."""
83     if path=="/":
84         return "/"
85     else:
86         return path[2:] # Cuts initial slash and data type identifier
87
88 def path_to_datatype_name(path):
89     """Takes a path as returned by urlparse and maps it to a string.
90     See section 3.4 of RFC 1738 for details."""
91     if path=="/":
92         # No way to tell, although "INDEX" is likely
93         return "TYPE='unknown'"
94     else:
95         return type_to_name(path[1])
96
97 # The following functions interpret the data returned by the gopher
98 # server according to the expected type, e.g. textfile or directory
99
100 def get_directory(f):
101     """Get a directory in the form of a list of entries."""
102     entries = []
103     while 1:
104         line = f.readline()
105         if not line:
106             print '(Unexpected EOF from server)'
107             break
108         if line[-2:] == CRLF:
109             line = line[:-2]
110         elif line[-1:] in CRLF:
111             line = line[:-1]
112         if line == '.':
113             break
114         if not line:
115             print '(Empty line from server)'
116             continue
117         gtype = line[0]
118         parts = line[1:].split(TAB)
119         if len(parts) < 4:
120             print '(Bad line from server: %r)' % (line,)
121             continue
122         if len(parts) > 4:
123             if parts[4:] != ['+']:
124                 print '(Extra info from server:',
125                 print parts[4:], ')'
126         else:
127             parts.append('')
128         parts.insert(0, gtype)
129         entries.append(parts)
130     return entries
131
132 def get_textfile(f):
133     """Get a text file as a list of lines, with trailing CRLF stripped."""
134     lines = []
135     get_alt_textfile(f, lines.append)
136     return lines
137
138 def get_alt_textfile(f, func):
139     """Get a text file and pass each line to a function, with trailing CRLF stripped."""
140     while 1:
141         line = f.readline()
142         if not line:
143             print '(Unexpected EOF from server)'
144             break
145         if line[-2:] == CRLF:
146             line = line[:-2]
147         elif line[-1:] in CRLF:
148             line = line[:-1]
149         if line == '.':
150             break
151         if line[:2] == '..':
152             line = line[1:]
153         func(line)
154
155 def get_binary(f):
156     """Get a binary file as one solid data block."""
157     data = f.read()
158     return data
159
160 def get_alt_binary(f, func, blocksize):
161     """Get a binary file and pass each block to a function."""
162     while 1:
163         data = f.read(blocksize)
164         if not data:
165             break
166         func(data)
167
168 def test():
169     """Trivial test program."""
170     import sys
171     import getopt
172     opts, args = getopt.getopt(sys.argv[1:], '')
173     selector = DEF_SELECTOR
174     type = selector[0]
175     host = DEF_HOST
176     if args:
177         host = args[0]
178         args = args[1:]
179     if args:
180         type = args[0]
181         args = args[1:]
182         if len(type) > 1:
183             type, selector = type[0], type
184         else:
185             selector = ''
186             if args:
187                 selector = args[0]
188                 args = args[1:]
189         query = ''
190         if args:
191             query = args[0]
192             args = args[1:]
193     if type == A_INDEX:
194         f = send_query(selector, query, host)
195     else:
196         f = send_selector(selector, host)
197     if type == A_TEXT:
198         lines = get_textfile(f)
199         for item in lines: print item
200     elif type in (A_MENU, A_INDEX):
201         entries = get_directory(f)
202         for item in entries: print item
203     else:
204         data = get_binary(f)
205         print 'binary data:', len(data), 'bytes:', repr(data[:100])[:40]
206
207 # Run the test when run as script
208 if __name__ == '__main__':
209     test()