3 """Items common to both the client and server
8 from . import error as _error
11 LINE_LENGTH = 1002 # 1000 + [CR,]LF
12 _ENCODE_REGEXP = _re.compile(
13 '(' + '|'.join(['%', '\r', '\n']) + ')')
14 _DECODE_REGEXP = _re.compile('(%[0-9A-F]{2})')
15 _REQUEST_REGEXP = _re.compile('^(\w+)( *)(.*)\Z')
21 >>> encode('It grew by 5%!\n')
24 return _ENCODE_REGEXP.sub(
25 lambda x : to_hex(x.group()), string)
30 >>> decode('%22Look out!%22%0AWhere%3F')
33 return _DECODE_REGEXP.sub(
34 lambda x : from_hex(x.group()), string)
44 return chr(int(code[1:], 16))
54 return '%{:02X}'.format(ord(char))
57 class Request (object):
60 http://www.gnupg.org/documentation/manuals/assuan/Client-requests.html
62 >>> r = Request(command='BYE')
65 >>> r = Request(command='OPTION', parameters='testing at 5%')
67 'OPTION testing at 5%25'
68 >>> r.from_string('BYE')
71 >>> print(r.parameters)
73 >>> r.from_string('OPTION testing at 5%25')
76 >>> print(r.parameters)
78 >>> r.from_string(' invalid')
79 Traceback (most recent call last):
81 pyassuan.error.AssuanError: 170 Invalid request
82 >>> r.from_string('in-valid')
83 Traceback (most recent call last):
85 pyassuan.error.AssuanError: 170 Invalid request
87 def __init__(self, command=None, parameters=None, encoded=False):
88 self.command = command
89 self.parameters = parameters
90 self.encoded = encoded
95 encoded_parameters = self.parameters
97 encoded_parameters = encode(self.parameters)
98 return '{} {}'.format(self.command, encoded_parameters)
101 def from_string(self, string):
102 if len(string) > 1000: # TODO: byte-vs-str and newlines?
103 raise _error.AssuanError(message='Line too long')
104 match = _REQUEST_REGEXP.match(string)
106 raise _error.AssuanError(message='Invalid request')
107 self.command = match.group(1)
110 self.parameters = decode(match.group(3))
112 raise _error.AssuanError(message='Invalid request')
114 self.parameters = None
117 class Response (object):
120 http://www.gnupg.org/documentation/manuals/assuan/Server-responses.html
122 >>> r = Response(type='OK')
125 >>> r = Response(type='ERR', parameters='1 General error')
127 'ERR 1 General error'
128 >>> r.from_string('OK')
131 >>> print(r.parameters)
133 >>> r.from_string('ERR 1 General error')
136 >>> print(r.parameters)
138 >>> r.from_string(' invalid')
139 Traceback (most recent call last):
141 pyassuan.error.AssuanError: 76 Invalid response
142 >>> r.from_string('in-valid')
143 Traceback (most recent call last):
145 pyassuan.error.AssuanError: 76 Invalid response
156 def __init__(self, type=None, parameters=None):
158 self.parameters = parameters
162 return '{} {}'.format(self.type, encode(self.parameters))
165 def from_string(self, string):
166 if len(string) > 1000: # TODO: byte-vs-str and newlines?
167 raise _error.AssuanError(message='Line too long')
169 type = self.types[string[0]]
171 raise _error.AssuanError(message='Invalid response')
173 if type == 'D': # data
174 self.parameters = decode(string[2:])
175 elif type == '#': # comment
176 self.parameters = decode(string[2:])
178 match = _REQUEST_REGEXP.match(string)
180 raise _error.AssuanError(message='Invalid request')
183 self.parameters = decode(match.group(3))
185 raise _error.AssuanError(message='Invalid request')
187 self.parameters = None
190 def error_response(error):
193 >>> from pyassuan.error import AssuanError
194 >>> error = AssuanError(1)
195 >>> response = error_response(error)
199 return Response(type='ERR', parameters=str(error))