diff options
Diffstat (limited to 'cython/imobiledevice.pyx')
-rw-r--r-- | cython/imobiledevice.pyx | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/cython/imobiledevice.pyx b/cython/imobiledevice.pyx new file mode 100644 index 0000000..8da2296 --- /dev/null +++ b/cython/imobiledevice.pyx | |||
@@ -0,0 +1,294 @@ | |||
1 | cdef class BaseError(Exception): | ||
2 | def __cinit__(self, int16_t errcode): | ||
3 | self._c_errcode = errcode | ||
4 | |||
5 | def __nonzero__(self): | ||
6 | return self._c_errcode != 0 | ||
7 | |||
8 | property message: | ||
9 | def __get__(self): | ||
10 | if self._c_errcode in self._lookup_table: | ||
11 | return self._lookup_table[self._c_errcode] | ||
12 | else: | ||
13 | return "Unknown error ({0})".format(self._c_errcode) | ||
14 | |||
15 | property code: | ||
16 | def __get__(self): | ||
17 | return self._c_errcode | ||
18 | |||
19 | def __str__(self): | ||
20 | return '%s (%s)' % (self.message, self.code) | ||
21 | |||
22 | def __repr__(self): | ||
23 | return self.__str__() | ||
24 | |||
25 | cdef class Base: | ||
26 | cdef inline int handle_error(self, int16_t ret) except -1: | ||
27 | if ret == 0: | ||
28 | return 0 | ||
29 | cdef BaseError err = self._error(ret) | ||
30 | raise err | ||
31 | |||
32 | cdef BaseError _error(self, int16_t ret): pass | ||
33 | |||
34 | cdef extern from "libimobiledevice/libimobiledevice.h": | ||
35 | ctypedef enum idevice_error_t: | ||
36 | IDEVICE_E_SUCCESS = 0 | ||
37 | IDEVICE_E_INVALID_ARG = -1 | ||
38 | IDEVICE_E_UNKNOWN_ERROR = -2 | ||
39 | IDEVICE_E_NO_DEVICE = -3 | ||
40 | IDEVICE_E_NOT_ENOUGH_DATA = -4 | ||
41 | IDEVICE_E_SSL_ERROR = -6 | ||
42 | IDEVICE_E_TIMEOUT = -7 | ||
43 | cdef enum idevice_options: | ||
44 | IDEVICE_LOOKUP_USBMUX = 1 << 1 | ||
45 | IDEVICE_LOOKUP_NETWORK = 1 << 2 | ||
46 | IDEVICE_LOOKUP_PREFER_NETWORK = 1 << 3 | ||
47 | ctypedef void (*idevice_event_cb_t) (const_idevice_event_t event, void *user_data) | ||
48 | cdef extern idevice_error_t idevice_event_subscribe(idevice_event_cb_t callback, void *user_data) | ||
49 | cdef extern idevice_error_t idevice_event_unsubscribe() | ||
50 | idevice_error_t idevice_get_device_list(char ***devices, int *count) | ||
51 | idevice_error_t idevice_device_list_free(char **devices) | ||
52 | void idevice_set_debug_level(int level) | ||
53 | idevice_error_t idevice_new(idevice_t *device, char *udid) | ||
54 | idevice_error_t idevice_new_with_options(idevice_t *device, const char *udid, idevice_options options); | ||
55 | idevice_error_t idevice_free(idevice_t device) | ||
56 | idevice_error_t idevice_get_udid(idevice_t device, char** udid) | ||
57 | idevice_error_t idevice_get_handle(idevice_t device, uint32_t *handle) | ||
58 | idevice_error_t idevice_connect(idevice_t device, uint16_t port, idevice_connection_t *connection) | ||
59 | idevice_error_t idevice_disconnect(idevice_connection_t connection) | ||
60 | idevice_error_t idevice_connection_send(idevice_connection_t connection, char *data, uint32_t len, uint32_t *sent_bytes) | ||
61 | idevice_error_t idevice_connection_receive_timeout(idevice_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout) | ||
62 | idevice_error_t idevice_connection_receive(idevice_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes) | ||
63 | |||
64 | cdef class iDeviceError(BaseError): | ||
65 | def __init__(self, *args, **kwargs): | ||
66 | self._lookup_table = { | ||
67 | IDEVICE_E_SUCCESS: 'Success', | ||
68 | IDEVICE_E_INVALID_ARG: 'Invalid argument', | ||
69 | IDEVICE_E_UNKNOWN_ERROR: 'Unknown error', | ||
70 | IDEVICE_E_NO_DEVICE: 'No device', | ||
71 | IDEVICE_E_NOT_ENOUGH_DATA: 'Not enough data', | ||
72 | IDEVICE_E_SSL_ERROR: 'SSL Error', | ||
73 | IDEVICE_E_TIMEOUT: 'Connection timeout' | ||
74 | } | ||
75 | BaseError.__init__(self, *args, **kwargs) | ||
76 | |||
77 | def set_debug_level(int level): | ||
78 | idevice_set_debug_level(level) | ||
79 | |||
80 | cdef class iDeviceEvent: | ||
81 | def __init__(self, *args, **kwargs): | ||
82 | raise TypeError("iDeviceEvent cannot be instantiated") | ||
83 | |||
84 | def __str__(self): | ||
85 | return 'iDeviceEvent: %s (%s)' % (self.event == IDEVICE_DEVICE_ADD and 'Add' or 'Remove', self.udid) | ||
86 | |||
87 | property event: | ||
88 | def __get__(self): | ||
89 | return self._c_event.event | ||
90 | property udid: | ||
91 | def __get__(self): | ||
92 | return self._c_event.udid | ||
93 | property conn_type: | ||
94 | def __get__(self): | ||
95 | return self._c_event.conn_type | ||
96 | |||
97 | cdef void idevice_event_cb(const_idevice_event_t c_event, void *user_data) noexcept: | ||
98 | cdef iDeviceEvent event = iDeviceEvent.__new__(iDeviceEvent) | ||
99 | event._c_event = c_event | ||
100 | (<object>user_data)(event) | ||
101 | |||
102 | def event_subscribe(object callback): | ||
103 | cdef iDeviceError err = iDeviceError(idevice_event_subscribe(idevice_event_cb, <void*>callback)) | ||
104 | if err: raise err | ||
105 | |||
106 | def event_unsubscribe(): | ||
107 | cdef iDeviceError err = iDeviceError(idevice_event_unsubscribe()) | ||
108 | if err: raise err | ||
109 | |||
110 | def get_device_list(): | ||
111 | cdef: | ||
112 | char** devices = NULL | ||
113 | int count | ||
114 | list result | ||
115 | bytes device | ||
116 | iDeviceError err = iDeviceError(idevice_get_device_list(&devices, &count)) | ||
117 | |||
118 | if err: | ||
119 | if devices != NULL: | ||
120 | idevice_device_list_free(devices) | ||
121 | raise err | ||
122 | |||
123 | result = [] | ||
124 | for i from 0 <= i < count: | ||
125 | device = devices[i] | ||
126 | result.append(device) | ||
127 | |||
128 | err = iDeviceError(idevice_device_list_free(devices)) | ||
129 | if err: raise err | ||
130 | return result | ||
131 | |||
132 | cdef class iDeviceConnection(Base): | ||
133 | def __init__(self, *args, **kwargs): | ||
134 | raise TypeError("iDeviceConnection cannot be instantiated. Please use iDevice.connect()") | ||
135 | |||
136 | cpdef bytes receive_timeout(self, uint32_t max_len, unsigned int timeout): | ||
137 | cdef: | ||
138 | uint32_t bytes_received | ||
139 | char* c_data = <char *>malloc(max_len) | ||
140 | bytes result | ||
141 | |||
142 | try: | ||
143 | self.handle_error(idevice_connection_receive_timeout(self._c_connection, c_data, max_len, &bytes_received, timeout)) | ||
144 | result = c_data[:bytes_received] | ||
145 | return result | ||
146 | except BaseError, e: | ||
147 | raise | ||
148 | finally: | ||
149 | free(c_data) | ||
150 | |||
151 | cpdef bytes receive(self, max_len): | ||
152 | cdef: | ||
153 | uint32_t bytes_received | ||
154 | char* c_data = <char *>malloc(max_len) | ||
155 | bytes result | ||
156 | |||
157 | try: | ||
158 | self.handle_error(idevice_connection_receive(self._c_connection, c_data, max_len, &bytes_received)) | ||
159 | result = c_data[:bytes_received] | ||
160 | return result | ||
161 | except BaseError, e: | ||
162 | raise | ||
163 | finally: | ||
164 | free(c_data) | ||
165 | |||
166 | cpdef disconnect(self): | ||
167 | cdef idevice_error_t err | ||
168 | err = idevice_disconnect(self._c_connection) | ||
169 | self.handle_error(err) | ||
170 | |||
171 | cdef BaseError _error(self, int16_t ret): | ||
172 | return iDeviceError(ret) | ||
173 | |||
174 | from libc.stdlib cimport * | ||
175 | |||
176 | cdef class iDevice(Base): | ||
177 | def __cinit__(self, object udid=None, *args, **kwargs): | ||
178 | cdef char* c_udid = NULL | ||
179 | if isinstance(udid, (str, bytes)): | ||
180 | c_udid = <bytes>udid | ||
181 | elif udid is not None: | ||
182 | raise TypeError("iDevice's constructor takes a string or None as the udid argument") | ||
183 | self.handle_error(idevice_new(&self._c_dev, c_udid)) | ||
184 | |||
185 | def __dealloc__(self): | ||
186 | if self._c_dev is not NULL: | ||
187 | self.handle_error(idevice_free(self._c_dev)) | ||
188 | |||
189 | cdef BaseError _error(self, int16_t ret): | ||
190 | return iDeviceError(ret) | ||
191 | |||
192 | cpdef iDeviceConnection connect(self, uint16_t port): | ||
193 | cdef: | ||
194 | idevice_error_t err | ||
195 | idevice_connection_t c_conn = NULL | ||
196 | iDeviceConnection conn | ||
197 | err = idevice_connect(self._c_dev, port, &c_conn) | ||
198 | try: | ||
199 | self.handle_error(err) | ||
200 | |||
201 | conn = iDeviceConnection.__new__(iDeviceConnection) | ||
202 | conn._c_connection = c_conn | ||
203 | |||
204 | return conn | ||
205 | except Exception, e: | ||
206 | if c_conn != NULL: | ||
207 | idevice_disconnect(c_conn) | ||
208 | |||
209 | property udid: | ||
210 | def __get__(self): | ||
211 | cdef: | ||
212 | char* udid | ||
213 | idevice_error_t err | ||
214 | err = idevice_get_udid(self._c_dev, &udid) | ||
215 | try: | ||
216 | self.handle_error(err) | ||
217 | return udid | ||
218 | except Exception, e: | ||
219 | if udid != NULL: | ||
220 | free(udid) | ||
221 | property handle: | ||
222 | def __get__(self): | ||
223 | cdef uint32_t handle | ||
224 | self.handle_error(idevice_get_handle(self._c_dev, &handle)) | ||
225 | return handle | ||
226 | |||
227 | cdef extern from *: | ||
228 | ctypedef char* const_char_ptr "const char*" | ||
229 | |||
230 | cdef class BaseService(Base): | ||
231 | __service_name__ = None | ||
232 | |||
233 | cdef class PropertyListService(BaseService): | ||
234 | cpdef send(self, plist.Node node): | ||
235 | self.handle_error(self._send(node._c_node)) | ||
236 | |||
237 | cpdef object receive(self): | ||
238 | cdef: | ||
239 | plist.plist_t c_node = NULL | ||
240 | int16_t err | ||
241 | err = self._receive(&c_node) | ||
242 | try: | ||
243 | self.handle_error(err) | ||
244 | |||
245 | return plist.plist_t_to_node(c_node) | ||
246 | except BaseError, e: | ||
247 | if c_node != NULL: | ||
248 | plist.plist_free(c_node) | ||
249 | raise | ||
250 | |||
251 | cpdef object receive_with_timeout(self, int timeout_ms): | ||
252 | cdef: | ||
253 | plist.plist_t c_node = NULL | ||
254 | int16_t err | ||
255 | err = self._receive_with_timeout(&c_node, timeout_ms) | ||
256 | try: | ||
257 | self.handle_error(err) | ||
258 | |||
259 | return plist.plist_t_to_node(c_node) | ||
260 | except BaseError, e: | ||
261 | if c_node != NULL: | ||
262 | plist.plist_free(c_node) | ||
263 | raise | ||
264 | |||
265 | cdef int16_t _send(self, plist.plist_t node): | ||
266 | raise NotImplementedError("send is not implemented") | ||
267 | |||
268 | cdef int16_t _receive(self, plist.plist_t* c_node): | ||
269 | raise NotImplementedError("receive is not implemented") | ||
270 | |||
271 | cdef int16_t _receive_with_timeout(self, plist.plist_t* c_node, int timeout_ms): | ||
272 | raise NotImplementedError("receive_with_timeout is not implemented") | ||
273 | |||
274 | cdef class DeviceLinkService(PropertyListService): | ||
275 | pass | ||
276 | |||
277 | include "lockdown.pxi" | ||
278 | include "mobilesync.pxi" | ||
279 | include "notification_proxy.pxi" | ||
280 | include "sbservices.pxi" | ||
281 | include "mobilebackup.pxi" | ||
282 | include "mobilebackup2.pxi" | ||
283 | include "afc.pxi" | ||
284 | include "file_relay.pxi" | ||
285 | include "screenshotr.pxi" | ||
286 | include "installation_proxy.pxi" | ||
287 | include "mobile_image_mounter.pxi" | ||
288 | include "webinspector.pxi" | ||
289 | include "heartbeat.pxi" | ||
290 | include "diagnostics_relay.pxi" | ||
291 | include "misagent.pxi" | ||
292 | include "house_arrest.pxi" | ||
293 | include "restore.pxi" | ||
294 | include "debugserver.pxi" | ||