1cdef extern from "libimobiledevice/debugserver.h":
2    cdef struct debugserver_client_private:
3        pass
4    ctypedef debugserver_client_private *debugserver_client_t
5    cdef struct debugserver_command_private:
6        pass
7    ctypedef debugserver_command_private *debugserver_command_t
8    ctypedef enum debugserver_error_t:
9        DEBUGSERVER_E_SUCCESS = 0
10        DEBUGSERVER_E_INVALID_ARG = -1
11        DEBUGSERVER_E_MUX_ERROR = -2
12        DEBUGSERVER_E_SSL_ERROR = -3
13        DEBUGSERVER_E_RESPONSE_ERROR = -4
14        DEBUGSERVER_E_UNKNOWN_ERROR = -256
15
16    debugserver_error_t debugserver_client_new(idevice_t device, lockdownd_service_descriptor_t service, debugserver_client_t * client)
17    debugserver_error_t debugserver_client_free(debugserver_client_t client)
18
19    debugserver_error_t debugserver_client_send(debugserver_client_t client, const char* data, uint32_t size, uint32_t *sent)
20    debugserver_error_t debugserver_client_send_command(debugserver_client_t client, debugserver_command_t command, char** response, size_t* response_size)
21    debugserver_error_t debugserver_client_receive(debugserver_client_t client, char *data, uint32_t size, uint32_t *received)
22    debugserver_error_t debugserver_client_receive_with_timeout(debugserver_client_t client, char *data, uint32_t size, uint32_t *received, unsigned int timeout)
23    debugserver_error_t debugserver_client_receive_response(debugserver_client_t client, char** response, size_t* response_size)
24    debugserver_error_t debugserver_client_set_argv(debugserver_client_t client, int argc, char* argv[], char** response)
25    debugserver_error_t debugserver_client_set_environment_hex_encoded(debugserver_client_t client, const char* env, char** response)
26
27    debugserver_error_t debugserver_command_new(const char* name, int argc, const char* argv[], debugserver_command_t* command)
28    debugserver_error_t debugserver_command_free(debugserver_command_t command)
29    void debugserver_encode_string(const char* buffer, char** encoded_buffer, uint32_t* encoded_length)
30    void debugserver_decode_string(const char *encoded_buffer, size_t encoded_length, char** buffer)
31
32
33cdef class DebugServerError(BaseError):
34    def __init__(self, *args, **kwargs):
35        self._lookup_table = {
36            DEBUGSERVER_E_SUCCESS: "Success",
37            DEBUGSERVER_E_INVALID_ARG: "Invalid argument",
38            DEBUGSERVER_E_MUX_ERROR: "MUX error",
39            DEBUGSERVER_E_SSL_ERROR: "SSL error",
40            DEBUGSERVER_E_RESPONSE_ERROR: "Response error",
41            DEBUGSERVER_E_UNKNOWN_ERROR: "Unknown error",
42        }
43        BaseError.__init__(self, *args, **kwargs)
44
45
46# from http://stackoverflow.com/a/17511714
47from cpython.string cimport PyString_AsString
48cdef char ** to_cstring_array(list_str):
49    if not list_str:
50        return NULL
51    cdef char **ret = <char **>malloc(len(list_str) * sizeof(char *))
52    for i in xrange(len(list_str)):
53        ret[i] = PyString_AsString(list_str[i])
54    return ret
55
56
57cdef class DebugServerCommand(Base):
58    cdef debugserver_command_t _c_command
59
60    def __init__(self, bytes name, int argc = 0, argv = None, *args, **kwargs):
61        cdef:
62            char* c_name = name
63            char** c_argv = to_cstring_array(argv)
64
65        try:
66            self.handle_error(debugserver_command_new(c_name, argc, c_argv, &self._c_command))
67        except BaseError, e:
68            raise
69        finally:
70            free(c_argv)
71
72    def __enter__(self):
73        return self
74
75    def __exit__(self, type, value, traceback):
76        self.free()
77
78    cdef free(self):
79        cdef debugserver_error_t err
80        if self._c_command is not NULL:
81            err = debugserver_command_free(self._c_command)
82            self.handle_error(err)
83
84    cdef inline BaseError _error(self, int16_t ret):
85        return DebugServerError(ret)
86
87
88cdef class DebugServerClient(BaseService):
89    __service_name__ = "com.apple.debugserver"
90    cdef debugserver_client_t _c_client
91
92    def __cinit__(self, iDevice device = None, LockdownServiceDescriptor descriptor = None, *args, **kwargs):
93        if (device is not None and descriptor is not None):
94            self.handle_error(debugserver_client_new(device._c_dev, descriptor._c_service_descriptor, &(self._c_client)))
95
96    def __dealloc__(self):
97        cdef debugserver_error_t err
98        if self._c_client is not NULL:
99            err = debugserver_client_free(self._c_client)
100            self.handle_error(err)
101
102    cdef BaseError _error(self, int16_t ret):
103        return DebugServerError(ret)
104
105    cpdef uint32_t send(self, bytes data):
106        cdef:
107            uint32_t bytes_send
108            char* c_data = data
109        try:
110            self.handle_error(debugserver_client_send(self._c_client, c_data, len(data), &bytes_send))
111        except BaseError, e:
112            raise
113
114        return bytes_send
115
116    cpdef bytes send_command(self, DebugServerCommand command):
117        cdef:
118            char* c_response = NULL
119            bytes result
120
121        try:
122            self.handle_error(debugserver_client_send_command(self._c_client, command._c_command, &c_response, NULL))
123            if c_response:
124                result = c_response
125                return result
126            else:
127                return None
128        except BaseError, e:
129            raise
130        finally:
131            free(c_response)
132
133    cpdef bytes receive(self, uint32_t size):
134        cdef:
135            uint32_t bytes_received
136            char* c_data = <char *>malloc(size)
137            bytes result
138
139        try:
140            self.handle_error(debugserver_client_receive(self._c_client, c_data, size, &bytes_received))
141            result = c_data[:bytes_received]
142            return result
143        except BaseError, e:
144            raise
145        finally:
146            free(c_data)
147
148    cpdef bytes receive_with_timeout(self, uint32_t size, unsigned int timeout):
149        cdef:
150            uint32_t bytes_received
151            char* c_data = <char *>malloc(size)
152            bytes result
153
154        try:
155            self.handle_error(debugserver_client_receive_with_timeout(self._c_client, c_data, size, &bytes_received, timeout))
156            result = c_data[:bytes_received]
157            return result
158        except BaseError, e:
159            raise
160        finally:
161            free(c_data)
162
163    cpdef bytes receive_response(self):
164        cdef:
165            char* c_response = NULL
166            bytes result
167
168        try:
169            self.handle_error(debugserver_client_receive_response(self._c_client, &c_response, NULL))
170            if c_response:
171                result = c_response
172                return result
173            else:
174                return None
175        except BaseError, e:
176            raise
177        finally:
178            free(c_response)
179
180    cpdef bytes set_argv(self, int argc, argv):
181        cdef:
182            char** c_argv = to_cstring_array(argv)
183            char* c_response = NULL
184            bytes result
185
186        try:
187            self.handle_error(debugserver_client_set_argv(self._c_client, argc, c_argv, &c_response))
188            if c_response:
189                result = c_response
190                return result
191            else:
192                return None
193        except BaseError, e:
194            raise
195        finally:
196            free(c_argv)
197            free(c_response)
198
199    cpdef bytes set_environment_hex_encoded(self, bytes env):
200        cdef:
201            char* c_env = env
202            char* c_response = NULL
203            bytes result
204
205        try:
206            self.handle_error(debugserver_client_set_environment_hex_encoded(self._c_client, c_env, &c_response))
207            if c_response:
208                result = c_response
209                return result
210            else:
211                return None
212        except BaseError, e:
213            raise
214        finally:
215            free(c_response)
216
217    cpdef bytes encode_string(self, bytes buffer):
218        cdef:
219            char *c_buffer = buffer
220            uint32_t encoded_length = len(c_buffer) * 2 + 0x3 + 1
221            char* c_encoded_buffer = <char *>malloc(encoded_length)
222            bytes result
223
224        try:
225            debugserver_encode_string(c_buffer, &c_encoded_buffer, &encoded_length)
226            result = c_encoded_buffer[:encoded_length]
227            return result
228        except BaseError, e:
229            raise
230        finally:
231            free(c_encoded_buffer)
232
233    cpdef bytes decode_string(self, bytes encoded_buffer):
234        cdef:
235            char* c_encoded_buffer = encoded_buffer
236            uint32_t encoded_length = len(c_encoded_buffer)
237            char *c_buffer = <char *>malloc(encoded_length)
238            bytes result
239
240        try:
241            debugserver_decode_string(c_encoded_buffer, encoded_length, &c_buffer)
242            result = c_buffer
243            return result
244        except BaseError, e:
245            raise
246        finally:
247            free(c_buffer)
248