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" | ||
