diff options
Diffstat (limited to 'cython')
-rw-r--r-- | cython/Makefile.am | 84 | ||||
-rw-r--r-- | cython/afc.pxi | 337 | ||||
-rw-r--r-- | cython/debugserver.pxi | 252 | ||||
-rw-r--r-- | cython/diagnostics_relay.pxi | 128 | ||||
-rw-r--r-- | cython/file_relay.pxi | 68 | ||||
-rw-r--r-- | cython/heartbeat.pxi | 60 | ||||
-rw-r--r-- | cython/house_arrest.pxi | 84 | ||||
-rw-r--r-- | cython/imobiledevice.pxd | 110 | ||||
-rw-r--r-- | cython/imobiledevice.pyx | 294 | ||||
-rw-r--r-- | cython/installation_proxy.pxi | 304 | ||||
-rw-r--r-- | cython/lockdown.pxi | 351 | ||||
-rw-r--r-- | cython/misagent.pxi | 74 | ||||
-rw-r--r-- | cython/mobile_image_mounter.pxi | 115 | ||||
-rw-r--r-- | cython/mobilebackup.pxi | 110 | ||||
-rw-r--r-- | cython/mobilebackup2.pxi | 123 | ||||
-rw-r--r-- | cython/mobilesync.pxi | 164 | ||||
-rw-r--r-- | cython/notification_proxy.pxi | 110 | ||||
-rw-r--r-- | cython/restore.pxi | 131 | ||||
-rw-r--r-- | cython/sbservices.pxi | 80 | ||||
-rw-r--r-- | cython/screenshotr.pxi | 66 | ||||
-rw-r--r-- | cython/webinspector.pxi | 60 |
21 files changed, 3105 insertions, 0 deletions
diff --git a/cython/Makefile.am b/cython/Makefile.am new file mode 100644 index 0000000..93ea6ed --- /dev/null +++ b/cython/Makefile.am @@ -0,0 +1,84 @@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/include + +AM_CFLAGS = \ + $(GLOBAL_CFLAGS) \ + $(ssl_lib_CFLAGS) \ + $(LFS_CFLAGS) \ + $(PTHREAD_CFLAGS) \ + $(libplist_CFLAGS) + +AM_LIBS = \ + $(ssl_lib_LIBS) \ + $(PTHREAD_LIBS) \ + $(libplist_LIBS) + +if HAVE_CYTHON + +BUILT_SOURCES = imobiledevice.c +PXDINCLUDES = \ + imobiledevice.pxd \ + $(CYTHON_PLIST_INCLUDE_DIR)/plist.pxd + +PXIINCLUDES = \ + lockdown.pxi \ + mobilesync.pxi \ + notification_proxy.pxi \ + sbservices.pxi \ + mobilebackup.pxi \ + mobilebackup2.pxi \ + afc.pxi \ + file_relay.pxi \ + screenshotr.pxi \ + installation_proxy.pxi \ + webinspector.pxi \ + heartbeat.pxi \ + diagnostics_relay.pxi \ + misagent.pxi \ + house_arrest.pxi \ + restore.pxi \ + mobile_image_mounter.pxi \ + debugserver.pxi + +CLEANFILES = \ + *.pyc \ + *.pyo \ + imobiledevice.c + +EXTRA_DIST = \ + imobiledevice.pyx \ + imobiledevice.pxd \ + $(PXIINCLUDES) + +imobiledevicedir = $(pyexecdir) +imobiledevice_LTLIBRARIES = imobiledevice.la +imobiledevice_la_SOURCES = imobiledevice.pyx +imobiledevice_la_CFLAGS = \ + -I$(top_srcdir)/include \ + -I$(top_srcdir)/src \ + $(PYTHON_CPPFLAGS) \ + $(AM_CFLAGS) \ + -Wno-shadow \ + -Wno-redundant-decls \ + -Wno-switch-default \ + -Wno-strict-aliasing \ + -Wno-implicit-function-declaration \ + -fvisibility=default \ + $(CYTHON_CFLAGS) + +imobiledevice_la_LDFLAGS = \ + -module \ + -avoid-version \ + -L$(libdir) \ + $(PYTHON_LIBS) \ + $(AM_LIBS) \ + -no-undefined + +imobiledevice_la_LIBADD = $(top_builddir)/src/libimobiledevice-1.0.la + +imobiledevice.c: imobiledevice.pyx $(PXDINCLUDES) $(PXIINCLUDES) + +.pyx.c: + $(CYTHON) -I$(CYTHON_PLIST_INCLUDE_DIR) -I$(top_srcdir)/src -o $@ $< + +endif diff --git a/cython/afc.pxi b/cython/afc.pxi new file mode 100644 index 0000000..6bd8182 --- /dev/null +++ b/cython/afc.pxi @@ -0,0 +1,337 @@ +cdef extern from "libimobiledevice/afc.h": + cdef struct afc_client_private: + pass + ctypedef afc_client_private *afc_client_t + ctypedef enum afc_error_t: + AFC_E_SUCCESS = 0 + AFC_E_UNKNOWN_ERROR = 1 + AFC_E_OP_HEADER_INVALID = 2 + AFC_E_NO_RESOURCES = 3 + AFC_E_READ_ERROR = 4 + AFC_E_WRITE_ERROR = 5 + AFC_E_UNKNOWN_PACKET_TYPE = 6 + AFC_E_INVALID_ARG = 7 + AFC_E_OBJECT_NOT_FOUND = 8 + AFC_E_OBJECT_IS_DIR = 9 + AFC_E_PERM_DENIED = 10 + AFC_E_SERVICE_NOT_CONNECTED = 11 + AFC_E_OP_TIMEOUT = 12 + AFC_E_TOO_MUCH_DATA = 13 + AFC_E_END_OF_DATA = 14 + AFC_E_OP_NOT_SUPPORTED = 15 + AFC_E_OBJECT_EXISTS = 16 + AFC_E_OBJECT_BUSY = 17 + AFC_E_NO_SPACE_LEFT = 18 + AFC_E_OP_WOULD_BLOCK = 19 + AFC_E_IO_ERROR = 20 + AFC_E_OP_INTERRUPTED = 21 + AFC_E_OP_IN_PROGRESS = 22 + AFC_E_INTERNAL_ERROR = 23 + AFC_E_MUX_ERROR = 30 + AFC_E_NO_MEM = 31 + AFC_E_NOT_ENOUGH_DATA = 32 + AFC_E_DIR_NOT_EMPTY = 33 + ctypedef enum afc_file_mode_t: + AFC_FOPEN_RDONLY = 0x00000001 + AFC_FOPEN_RW = 0x00000002 + AFC_FOPEN_WRONLY = 0x00000003 + AFC_FOPEN_WR = 0x00000004 + AFC_FOPEN_APPEND = 0x00000005 + AFC_FOPEN_RDAPPEND = 0x00000006 + ctypedef enum afc_link_type_t: + AFC_HARDLINK = 1 + AFC_SYMLINK = 2 + ctypedef enum afc_lock_op_t: + AFC_LOCK_SH = 1 | 4 + AFC_LOCK_EX = 2 | 4 + AFC_LOCK_UN = 8 | 4 + + afc_error_t afc_client_new(idevice_t device, lockdownd_service_descriptor_t descriptor, afc_client_t *client) + afc_error_t afc_client_free(afc_client_t client) + afc_error_t afc_get_device_info(afc_client_t client, char ***infos) + afc_error_t afc_read_directory(afc_client_t client, char *dir, char ***list) + afc_error_t afc_get_file_info(afc_client_t client, char *filename, char ***infolist) + afc_error_t afc_remove_path(afc_client_t client, char *path) + afc_error_t afc_remove_path_and_contents(afc_client_t client, char *path) + afc_error_t afc_rename_path(afc_client_t client, char *f, char *to) + afc_error_t afc_make_directory(afc_client_t client, char *dir) + afc_error_t afc_truncate(afc_client_t client, char *path, uint64_t newsize) + afc_error_t afc_make_link(afc_client_t client, afc_link_type_t linktype, char *target, char *linkname) + afc_error_t afc_set_file_time(afc_client_t client, char *path, uint64_t mtime) + + afc_error_t afc_file_open(afc_client_t client, char *filename, afc_file_mode_t file_mode, uint64_t *handle) + afc_error_t afc_file_close(afc_client_t client, uint64_t handle) + afc_error_t afc_file_lock(afc_client_t client, uint64_t handle, afc_lock_op_t operation) + afc_error_t afc_file_read(afc_client_t client, uint64_t handle, char *data, uint32_t length, uint32_t *bytes_read) + afc_error_t afc_file_write(afc_client_t client, uint64_t handle, char *data, uint32_t length, uint32_t *bytes_written) + afc_error_t afc_file_seek(afc_client_t client, uint64_t handle, int64_t offset, int whence) + afc_error_t afc_file_tell(afc_client_t client, uint64_t handle, uint64_t *position) + afc_error_t afc_file_truncate(afc_client_t client, uint64_t handle, uint64_t newsize) + +LOCK_SH = AFC_LOCK_SH +LOCK_EX = AFC_LOCK_EX +LOCK_UN = AFC_LOCK_UN + +cdef class AfcError(BaseError): + def __init__(self, *args, **kwargs): + self._lookup_table = { + AFC_E_SUCCESS: "Success", + AFC_E_UNKNOWN_ERROR: "Unknown error", + AFC_E_OP_HEADER_INVALID: "OP header invalid", + AFC_E_NO_RESOURCES: "No resources", + AFC_E_READ_ERROR: "Read error", + AFC_E_WRITE_ERROR: "Write error", + AFC_E_UNKNOWN_PACKET_TYPE: "Unknown packet type", + AFC_E_INVALID_ARG: "Invalid argument", + AFC_E_OBJECT_NOT_FOUND: "Object not found", + AFC_E_OBJECT_IS_DIR: "Object is directory", + AFC_E_PERM_DENIED: "Permission denied", + AFC_E_SERVICE_NOT_CONNECTED: "Service not connected", + AFC_E_OP_TIMEOUT: "OP timeout", + AFC_E_TOO_MUCH_DATA: "Too much data", + AFC_E_END_OF_DATA: "End of data", + AFC_E_OP_NOT_SUPPORTED: "OP not supported", + AFC_E_OBJECT_EXISTS: "Object exists", + AFC_E_OBJECT_BUSY: "Object busy", + AFC_E_NO_SPACE_LEFT: "No space left", + AFC_E_OP_WOULD_BLOCK: "OP would block", + AFC_E_IO_ERROR: "IO error", + AFC_E_OP_INTERRUPTED: "OP interrupted", + AFC_E_OP_IN_PROGRESS: "OP in progress", + AFC_E_INTERNAL_ERROR: "Internal error", + AFC_E_MUX_ERROR: "MUX error", + AFC_E_NO_MEM: "No memory", + AFC_E_NOT_ENOUGH_DATA: "Not enough data", + AFC_E_DIR_NOT_EMPTY: "Directory not empty" + } + BaseError.__init__(self, *args, **kwargs) + +# forward declaration of AfcClient +cdef class AfcClient(BaseService) + +cdef class AfcFile(Base): + cdef uint64_t _c_handle + cdef AfcClient _client + cdef bytes _filename + + def __init__(self, *args, **kwargs): + raise TypeError("AfcFile cannot be instantiated") + + def __enter__(self): + return self + + def __exit__(self, type, value, traceback): + self.close() + + cpdef close(self): + self.handle_error(afc_file_close(self._client._c_client, self._c_handle)) + + cpdef lock(self, int operation): + self.handle_error(afc_file_lock(self._client._c_client, self._c_handle, <afc_lock_op_t>operation)) + + cpdef seek(self, int64_t offset, int whence): + self.handle_error(afc_file_seek(self._client._c_client, self._c_handle, offset, whence)) + + cpdef uint64_t tell(self): + cdef uint64_t position + self.handle_error(afc_file_tell(self._client._c_client, self._c_handle, &position)) + return position + + cpdef truncate(self, uint64_t newsize): + self.handle_error(afc_file_truncate(self._client._c_client, self._c_handle, newsize)) + + cpdef bytes read(self, uint32_t size): + cdef: + uint32_t bytes_read + char* c_data = <char *>malloc(size) + bytes result + try: + self.handle_error(afc_file_read(self._client._c_client, self._c_handle, c_data, size, &bytes_read)) + result = c_data[:bytes_read] + return result + except BaseError, e: + raise + finally: + free(c_data) + + cpdef uint32_t write(self, bytes data): + cdef: + uint32_t bytes_written + char* c_data = data + try: + self.handle_error(afc_file_write(self._client._c_client, self._c_handle, c_data, len(data), &bytes_written)) + except BaseError, e: + raise + + return bytes_written + + cdef inline BaseError _error(self, int16_t ret): + return AfcError(ret) + +cdef class AfcClient(BaseService): + __service_name__ = "com.apple.afc" + cdef afc_client_t _c_client + + def __cinit__(self, iDevice device = None, LockdownServiceDescriptor descriptor = None, *args, **kwargs): + if (device is not None and descriptor is not None): + self.handle_error(afc_client_new(device._c_dev, descriptor._c_service_descriptor, &(self._c_client))) + + def __dealloc__(self): + cdef afc_error_t err + if self._c_client is not NULL: + err = afc_client_free(self._c_client) + self.handle_error(err) + + cdef BaseError _error(self, int16_t ret): + return AfcError(ret) + + cpdef list get_device_info(self): + cdef: + afc_error_t err + char** infos = NULL + bytes info + int i = 0 + list result = [] + err = afc_get_device_info(self._c_client, &infos) + try: + self.handle_error(err) + except BaseError, e: + raise + finally: + if infos != NULL: + while infos[i]: + info = infos[i] + result.append(info) + free(infos[i]) + i = i + 1 + free(infos) + + return result + + cpdef list read_directory(self, bytes directory): + cdef: + afc_error_t err + char** dir_list = NULL + bytes f + int i = 0 + list result = [] + err = afc_read_directory(self._c_client, directory, &dir_list) + try: + self.handle_error(err) + except BaseError, e: + raise + finally: + if dir_list != NULL: + while dir_list[i]: + f = dir_list[i] + result.append(f) + free(dir_list[i]) + i = i + 1 + free(dir_list) + + return result + + cpdef AfcFile open(self, bytes filename, bytes mode=b'r'): + cdef: + afc_file_mode_t c_mode + uint64_t handle + AfcFile f + if mode == b'r': + c_mode = AFC_FOPEN_RDONLY + elif mode == b'r+': + c_mode = AFC_FOPEN_RW + elif mode == b'w': + c_mode = AFC_FOPEN_WRONLY + elif mode == b'w+': + c_mode = AFC_FOPEN_WR + elif mode == b'a': + c_mode = AFC_FOPEN_APPEND + elif mode == b'a+': + c_mode = AFC_FOPEN_RDAPPEND + else: + raise ValueError("mode string must be 'r', 'r+', 'w', 'w+', 'a', or 'a+'") + + self.handle_error(afc_file_open(self._c_client, filename, c_mode, &handle)) + f = AfcFile.__new__(AfcFile) + f._c_handle = handle + f._client = self + f._filename = filename + + return f + + cpdef list get_file_info(self, bytes path): + cdef: + list result = [] + char** c_result = NULL + int i = 0 + bytes info + try: + self.handle_error(afc_get_file_info(self._c_client, path, &c_result)) + except BaseError, e: + raise + finally: + if c_result != NULL: + while c_result[i]: + info = c_result[i] + result.append(info) + free(c_result[i]) + i = i + 1 + free(c_result) + + return result + + cpdef remove_path(self, bytes path): + self.handle_error(afc_remove_path(self._c_client, path)) + + cpdef remove_path_and_contents(self, bytes path): + self.handle_error(afc_remove_path_and_contents(self._c_client, path)) + + cpdef rename_path(self, bytes f, bytes t): + self.handle_error(afc_rename_path(self._c_client, f, t)) + + cpdef make_directory(self, bytes d): + self.handle_error(afc_make_directory(self._c_client, d)) + + cpdef truncate(self, bytes path, uint64_t newsize): + self.handle_error(afc_truncate(self._c_client, path, newsize)) + + cpdef link(self, bytes source, bytes link_name): + self.handle_error(afc_make_link(self._c_client, AFC_HARDLINK, source, link_name)) + + cpdef symlink(self, bytes source, bytes link_name): + self.handle_error(afc_make_link(self._c_client, AFC_SYMLINK, source, link_name)) + + cpdef set_file_time(self, bytes path, uint64_t mtime): + self.handle_error(afc_set_file_time(self._c_client, path, mtime)) + +cdef class Afc2Client(AfcClient): + __service_name__ = "com.apple.afc2" + + cpdef AfcFile open(self, bytes filename, bytes mode=b'r'): + cdef: + afc_file_mode_t c_mode + uint64_t handle + AfcFile f + if mode == b'r': + c_mode = AFC_FOPEN_RDONLY + elif mode == b'r+': + c_mode = AFC_FOPEN_RW + elif mode == b'w': + c_mode = AFC_FOPEN_WRONLY + elif mode == b'w+': + c_mode = AFC_FOPEN_WR + elif mode == b'a': + c_mode = AFC_FOPEN_APPEND + elif mode == b'a+': + c_mode = AFC_FOPEN_RDAPPEND + else: + raise ValueError("mode string must be 'r', 'r+', 'w', 'w+', 'a', or 'a+'") + + self.handle_error(afc_file_open(self._c_client, filename, c_mode, &handle)) + f = AfcFile.__new__(AfcFile) + f._c_handle = handle + f._client = <AfcClient>self + f._filename = filename + + return f + diff --git a/cython/debugserver.pxi b/cython/debugserver.pxi new file mode 100644 index 0000000..a3b7d1e --- /dev/null +++ b/cython/debugserver.pxi @@ -0,0 +1,252 @@ +cdef extern from "libimobiledevice/debugserver.h": + cdef struct debugserver_client_private: + pass + ctypedef debugserver_client_private *debugserver_client_t + cdef struct debugserver_command_private: + pass + ctypedef debugserver_command_private *debugserver_command_t + ctypedef enum debugserver_error_t: + DEBUGSERVER_E_SUCCESS = 0 + DEBUGSERVER_E_INVALID_ARG = -1 + DEBUGSERVER_E_MUX_ERROR = -2 + DEBUGSERVER_E_SSL_ERROR = -3 + DEBUGSERVER_E_RESPONSE_ERROR = -4 + DEBUGSERVER_E_UNKNOWN_ERROR = -256 + + debugserver_error_t debugserver_client_new(idevice_t device, lockdownd_service_descriptor_t service, debugserver_client_t * client) + debugserver_error_t debugserver_client_free(debugserver_client_t client) + + debugserver_error_t debugserver_client_send(debugserver_client_t client, const char* data, uint32_t size, uint32_t *sent) + debugserver_error_t debugserver_client_send_command(debugserver_client_t client, debugserver_command_t command, char** response, size_t* response_size) + debugserver_error_t debugserver_client_receive(debugserver_client_t client, char *data, uint32_t size, uint32_t *received) + debugserver_error_t debugserver_client_receive_with_timeout(debugserver_client_t client, char *data, uint32_t size, uint32_t *received, unsigned int timeout) + debugserver_error_t debugserver_client_receive_response(debugserver_client_t client, char** response, size_t* response_size) + debugserver_error_t debugserver_client_set_argv(debugserver_client_t client, int argc, char* argv[], char** response) + debugserver_error_t debugserver_client_set_environment_hex_encoded(debugserver_client_t client, const char* env, char** response) + + debugserver_error_t debugserver_command_new(const char* name, int argc, const char* argv[], debugserver_command_t* command) + debugserver_error_t debugserver_command_free(debugserver_command_t command) + void debugserver_encode_string(const char* buffer, char** encoded_buffer, uint32_t* encoded_length) + void debugserver_decode_string(const char *encoded_buffer, size_t encoded_length, char** buffer) + + +cdef class DebugServerError(BaseError): + def __init__(self, *args, **kwargs): + self._lookup_table = { + DEBUGSERVER_E_SUCCESS: "Success", + DEBUGSERVER_E_INVALID_ARG: "Invalid argument", + DEBUGSERVER_E_MUX_ERROR: "MUX error", + DEBUGSERVER_E_SSL_ERROR: "SSL error", + DEBUGSERVER_E_RESPONSE_ERROR: "Response error", + DEBUGSERVER_E_UNKNOWN_ERROR: "Unknown error", + } + BaseError.__init__(self, *args, **kwargs) + + +# from http://stackoverflow.com/a/17511714 +# https://github.com/libimobiledevice/libimobiledevice/pull/198 +from cpython cimport PY_MAJOR_VERSION +if PY_MAJOR_VERSION <= 2: + from cpython.string cimport PyString_AsString +else: + from cpython.bytes cimport PyBytes_AsString as PyString_AsString +cdef char ** to_cstring_array(list_str): + if not list_str: + return NULL + cdef char **ret = <char **>malloc(len(list_str) * sizeof(char *)) + for i in xrange(len(list_str)): + ret[i] = PyString_AsString(list_str[i]) + return ret + + +cdef class DebugServerCommand(Base): + cdef debugserver_command_t _c_command + + def __init__(self, bytes name, int argc = 0, argv = None, *args, **kwargs): + cdef: + char* c_name = name + char** c_argv = to_cstring_array(argv) + + try: + self.handle_error(debugserver_command_new(c_name, argc, c_argv, &self._c_command)) + except BaseError, e: + raise + finally: + free(c_argv) + + def __enter__(self): + return self + + def __exit__(self, type, value, traceback): + self.free() + + cdef free(self): + cdef debugserver_error_t err + if self._c_command is not NULL: + err = debugserver_command_free(self._c_command) + self.handle_error(err) + + cdef inline BaseError _error(self, int16_t ret): + return DebugServerError(ret) + + +cdef class DebugServerClient(BaseService): + __service_name__ = "com.apple.debugserver" + cdef debugserver_client_t _c_client + + def __cinit__(self, iDevice device = None, LockdownServiceDescriptor descriptor = None, *args, **kwargs): + if (device is not None and descriptor is not None): + self.handle_error(debugserver_client_new(device._c_dev, descriptor._c_service_descriptor, &(self._c_client))) + + def __dealloc__(self): + cdef debugserver_error_t err + if self._c_client is not NULL: + err = debugserver_client_free(self._c_client) + self.handle_error(err) + + cdef BaseError _error(self, int16_t ret): + return DebugServerError(ret) + + cpdef uint32_t send(self, bytes data): + cdef: + uint32_t bytes_send + char* c_data = data + try: + self.handle_error(debugserver_client_send(self._c_client, c_data, len(data), &bytes_send)) + except BaseError, e: + raise + + return bytes_send + + cpdef bytes send_command(self, DebugServerCommand command): + cdef: + char* c_response = NULL + bytes result + + try: + self.handle_error(debugserver_client_send_command(self._c_client, command._c_command, &c_response, NULL)) + if c_response: + result = c_response + return result + else: + return None + except BaseError, e: + raise + finally: + free(c_response) + + cpdef bytes receive(self, uint32_t size): + cdef: + uint32_t bytes_received + char* c_data = <char *>malloc(size) + bytes result + + try: + self.handle_error(debugserver_client_receive(self._c_client, c_data, size, &bytes_received)) + result = c_data[:bytes_received] + return result + except BaseError, e: + raise + finally: + free(c_data) + + cpdef bytes receive_with_timeout(self, uint32_t size, unsigned int timeout): + cdef: + uint32_t bytes_received + char* c_data = <char *>malloc(size) + bytes result + + try: + self.handle_error(debugserver_client_receive_with_timeout(self._c_client, c_data, size, &bytes_received, timeout)) + result = c_data[:bytes_received] + return result + except BaseError, e: + raise + finally: + free(c_data) + + cpdef bytes receive_response(self): + cdef: + char* c_response = NULL + bytes result + + try: + self.handle_error(debugserver_client_receive_response(self._c_client, &c_response, NULL)) + if c_response: + result = c_response + return result + else: + return None + except BaseError, e: + raise + finally: + free(c_response) + + cpdef bytes set_argv(self, int argc, argv): + cdef: + char** c_argv = to_cstring_array(argv) + char* c_response = NULL + bytes result + + try: + self.handle_error(debugserver_client_set_argv(self._c_client, argc, c_argv, &c_response)) + if c_response: + result = c_response + return result + else: + return None + except BaseError, e: + raise + finally: + free(c_argv) + free(c_response) + + cpdef bytes set_environment_hex_encoded(self, bytes env): + cdef: + char* c_env = env + char* c_response = NULL + bytes result + + try: + self.handle_error(debugserver_client_set_environment_hex_encoded(self._c_client, c_env, &c_response)) + if c_response: + result = c_response + return result + else: + return None + except BaseError, e: + raise + finally: + free(c_response) + + cpdef bytes encode_string(self, bytes buffer): + cdef: + char *c_buffer = buffer + uint32_t encoded_length = len(c_buffer) * 2 + 0x3 + 1 + char* c_encoded_buffer = <char *>malloc(encoded_length) + bytes result + + try: + debugserver_encode_string(c_buffer, &c_encoded_buffer, &encoded_length) + result = c_encoded_buffer[:encoded_length] + return result + except BaseError, e: + raise + finally: + free(c_encoded_buffer) + + cpdef bytes decode_string(self, bytes encoded_buffer): + cdef: + char* c_encoded_buffer = encoded_buffer + uint32_t encoded_length = len(c_encoded_buffer) + char *c_buffer = <char *>malloc(encoded_length) + bytes result + + try: + debugserver_decode_string(c_encoded_buffer, encoded_length, &c_buffer) + result = c_buffer + return result + except BaseError, e: + raise + finally: + free(c_buffer) diff --git a/cython/diagnostics_relay.pxi b/cython/diagnostics_relay.pxi new file mode 100644 index 0000000..0e6bd20 --- /dev/null +++ b/cython/diagnostics_relay.pxi @@ -0,0 +1,128 @@ +REQUEST_TYPE_ALL = "All" +REQUEST_TYPE_WIFI = "WiFi" +REQUEST_TYPE_GAS_GAUGE = "GasGauge" +REQUEST_TYPE_NAND = "NAND" + +cdef extern from "libimobiledevice/diagnostics_relay.h": + cdef struct diagnostics_relay_client_private: + pass + ctypedef diagnostics_relay_client_private *diagnostics_relay_client_t + + ctypedef enum diagnostics_relay_error_t: + DIAGNOSTICS_RELAY_E_SUCCESS = 0 + DIAGNOSTICS_RELAY_E_INVALID_ARG = -1 + DIAGNOSTICS_RELAY_E_PLIST_ERROR = -2 + DIAGNOSTICS_RELAY_E_MUX_ERROR = -3 + DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST = -4 + DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR = -256 + ctypedef enum diagnostics_relay_action_t: + DIAGNOSTICS_RELAY_ACTION_FLAG_WAIT_FOR_DISCONNECT = (1 << 1) + DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_PASS = (1 << 2) + DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_FAIL = (1 << 3) + + diagnostics_relay_error_t diagnostics_relay_client_new(idevice_t device, lockdownd_service_descriptor_t descriptor, diagnostics_relay_client_t * client) + diagnostics_relay_error_t diagnostics_relay_client_free(diagnostics_relay_client_t client) + + diagnostics_relay_error_t diagnostics_relay_goodbye(diagnostics_relay_client_t client) + diagnostics_relay_error_t diagnostics_relay_sleep(diagnostics_relay_client_t client) + diagnostics_relay_error_t diagnostics_relay_restart(diagnostics_relay_client_t client, diagnostics_relay_action_t flags) + diagnostics_relay_error_t diagnostics_relay_shutdown(diagnostics_relay_client_t client, diagnostics_relay_action_t flags) + diagnostics_relay_error_t diagnostics_relay_request_diagnostics(diagnostics_relay_client_t client, char* type, plist.plist_t* diagnostics) + diagnostics_relay_error_t diagnostics_relay_query_mobilegestalt(diagnostics_relay_client_t client, plist.plist_t keys, plist.plist_t* result) + diagnostics_relay_error_t diagnostics_relay_query_ioregistry_entry(diagnostics_relay_client_t client, char* name, char* class_name, plist.plist_t* result) + diagnostics_relay_error_t diagnostics_relay_query_ioregistry_plane(diagnostics_relay_client_t client, char* plane, plist.plist_t* result) + +cdef class DiagnosticsRelayError(BaseError): + def __init__(self, *args, **kwargs): + self._lookup_table = { + DIAGNOSTICS_RELAY_E_SUCCESS: "Success", + DIAGNOSTICS_RELAY_E_INVALID_ARG: "Invalid argument", + DIAGNOSTICS_RELAY_E_PLIST_ERROR: "Property list error", + DIAGNOSTICS_RELAY_E_MUX_ERROR: "MUX error", + DIAGNOSTICS_RELAY_E_UNKNOWN_REQUEST: "Unknown request", + DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR: "Unknown error" + } + BaseError.__init__(self, *args, **kwargs) + +cdef class DiagnosticsRelayClient(PropertyListService): + __service_name__ = "com.apple.mobile.diagnostics_relay" + cdef diagnostics_relay_client_t _c_client + + def __cinit__(self, iDevice device not None, LockdownServiceDescriptor descriptor, *args, **kwargs): + self.handle_error(diagnostics_relay_client_new(device._c_dev, descriptor._c_service_descriptor, &self._c_client)) + + def __dealloc__(self): + cdef diagnostics_relay_error_t err + if self._c_client is not NULL: + err = diagnostics_relay_client_free(self._c_client) + self.handle_error(err) + + cdef inline BaseError _error(self, int16_t ret): + return DiagnosticsRelayError(ret) + + cpdef goodbye(self): + self.handle_error(diagnostics_relay_goodbye(self._c_client)) + + cpdef sleep(self): + self.handle_error(diagnostics_relay_sleep(self._c_client)) + + cpdef restart(self, diagnostics_relay_action_t flags): + self.handle_error(diagnostics_relay_restart(self._c_client, flags)) + + cpdef shutdown(self, diagnostics_relay_action_t flags): + self.handle_error(diagnostics_relay_shutdown(self._c_client, flags)) + + cpdef plist.Node request_diagnostics(self, bytes type): + cdef: + plist.plist_t c_node = NULL + diagnostics_relay_error_t err + err = diagnostics_relay_request_diagnostics(self._c_client, type, &c_node) + try: + self.handle_error(err) + return plist.plist_t_to_node(c_node) + except BaseError, e: + if c_node != NULL: + plist.plist_free(c_node) + raise + + cpdef plist.Node query_mobilegestalt(self, plist.Node keys = None): + cdef: + plist.plist_t c_node = NULL + diagnostics_relay_error_t err + plist.plist_t keys_c_node = NULL + if keys is not None: + keys_c_node = keys._c_node + err = diagnostics_relay_query_mobilegestalt(self._c_client, keys_c_node, &c_node) + try: + self.handle_error(err) + return plist.plist_t_to_node(c_node) + except BaseError, e: + if c_node != NULL: + plist.plist_free(c_node) + raise + + cpdef plist.Node query_ioregistry_entry(self, bytes name, bytes class_name): + cdef: + plist.plist_t c_node = NULL + diagnostics_relay_error_t err + err = diagnostics_relay_query_ioregistry_entry(self._c_client, name, class_name, &c_node) + try: + self.handle_error(err) + return plist.plist_t_to_node(c_node) + except BaseError, e: + if c_node != NULL: + plist.plist_free(c_node) + raise + + cpdef plist.Node query_ioregistry_plane(self, bytes plane = None): + cdef: + plist.plist_t c_node = NULL + diagnostics_relay_error_t err + err = diagnostics_relay_query_ioregistry_plane(self._c_client, plane, &c_node) + try: + self.handle_error(err) + return plist.plist_t_to_node(c_node) + except BaseError, e: + if c_node != NULL: + plist.plist_free(c_node) + raise diff --git a/cython/file_relay.pxi b/cython/file_relay.pxi new file mode 100644 index 0000000..5e9cbbe --- /dev/null +++ b/cython/file_relay.pxi @@ -0,0 +1,68 @@ +cdef extern from "libimobiledevice/file_relay.h": + cdef struct file_relay_client_private: + pass + ctypedef file_relay_client_private *file_relay_client_t + ctypedef char** const_sources_t "const char**" + + ctypedef enum file_relay_error_t: + FILE_RELAY_E_SUCCESS = 0 + FILE_RELAY_E_INVALID_ARG = -1 + FILE_RELAY_E_PLIST_ERROR = -2 + FILE_RELAY_E_MUX_ERROR = -3 + FILE_RELAY_E_INVALID_SOURCE = -4 + FILE_RELAY_E_STAGING_EMPTY = -5 + FILE_RELAY_E_PERMISSION_DENIED = -6 + FILE_RELAY_E_UNKNOWN_ERROR = -256 + + file_relay_error_t file_relay_client_new(idevice_t device, lockdownd_service_descriptor_t descriptor, file_relay_client_t *client) + file_relay_error_t file_relay_client_free(file_relay_client_t client) + + file_relay_error_t file_relay_request_sources(file_relay_client_t client, const_sources_t sources, idevice_connection_t *connection) + +cdef class FileRelayError(BaseError): + def __init__(self, *args, **kwargs): + self._lookup_table = { + FILE_RELAY_E_SUCCESS: "Success", + FILE_RELAY_E_INVALID_ARG: "Invalid argument", + FILE_RELAY_E_PLIST_ERROR: "Property list error", + FILE_RELAY_E_MUX_ERROR: "MUX error", + FILE_RELAY_E_INVALID_SOURCE: "Invalid source", + FILE_RELAY_E_STAGING_EMPTY: "Staging empty", + FILE_RELAY_E_PERMISSION_DENIED: "Permission denied", + FILE_RELAY_E_UNKNOWN_ERROR: "Unknown error" + } + BaseError.__init__(self, *args, **kwargs) + +from libc.stdlib cimport * + +cdef class FileRelayClient(PropertyListService): + __service_name__ = "com.apple.mobile.file_relay" + cdef file_relay_client_t _c_client + + def __cinit__(self, iDevice device not None, LockdownServiceDescriptor descriptor, *args, **kwargs): + self.handle_error(file_relay_client_new(device._c_dev, descriptor._c_service_descriptor, &self._c_client)) + + def __dealloc__(self): + cdef file_relay_error_t err + if self._c_client is not NULL: + err = file_relay_client_free(self._c_client) + self.handle_error(err) + + cpdef iDeviceConnection request_sources(self, list sources): + cdef: + file_relay_error_t err + Py_ssize_t count = len(sources) + char** c_sources = <char**>malloc(sizeof(char*) * (count + 1)) + iDeviceConnection conn = iDeviceConnection.__new__(iDeviceConnection) + + for i, value in enumerate(sources): + c_sources[i] = value + c_sources[count] = NULL + + err = file_relay_request_sources(self._c_client, <const_sources_t>c_sources, &conn._c_connection) + free(c_sources) + self.handle_error(err) + return conn + + cdef inline BaseError _error(self, int16_t ret): + return FileRelayError(ret) diff --git a/cython/heartbeat.pxi b/cython/heartbeat.pxi new file mode 100644 index 0000000..2f58909 --- /dev/null +++ b/cython/heartbeat.pxi @@ -0,0 +1,60 @@ +cdef extern from "libimobiledevice/heartbeat.h": + cdef struct heartbeat_client_private: + pass + ctypedef heartbeat_client_private *heartbeat_client_t + + ctypedef enum heartbeat_error_t: + HEARTBEAT_E_SUCCESS = 0 + HEARTBEAT_E_INVALID_ARG = -1 + HEARTBEAT_E_PLIST_ERROR = -2 + HEARTBEAT_E_MUX_ERROR = -3 + HEARTBEAT_E_SSL_ERROR = -4 + HEARTBEAT_E_NOT_ENOUGH_DATA = -5 + HEARTBEAT_E_TIMEOUT = -6 + HEARTBEAT_E_UNKNOWN_ERROR = -256 + + heartbeat_error_t heartbeat_client_new(idevice_t device, lockdownd_service_descriptor_t descriptor, heartbeat_client_t * client) + heartbeat_error_t heartbeat_client_free(heartbeat_client_t client) + + heartbeat_error_t heartbeat_send(heartbeat_client_t client, plist.plist_t plist) + heartbeat_error_t heartbeat_receive(heartbeat_client_t client, plist.plist_t * plist) + heartbeat_error_t heartbeat_receive_with_timeout(heartbeat_client_t client, plist.plist_t * plist, uint32_t timeout_ms) + +cdef class HeartbeatError(BaseError): + def __init__(self, *args, **kwargs): + self._lookup_table = { + HEARTBEAT_E_SUCCESS: "Success", + HEARTBEAT_E_INVALID_ARG: "Invalid argument", + HEARTBEAT_E_PLIST_ERROR: "Property list error", + HEARTBEAT_E_MUX_ERROR: "MUX error", + HEARTBEAT_E_SSL_ERROR: "SSL Error", + HEARTBEAT_E_NOT_ENOUGH_DATA: 'Not enough data', + HEARTBEAT_E_TIMEOUT: 'Connection timeout', + HEARTBEAT_E_UNKNOWN_ERROR: "Unknown error" + } + BaseError.__init__(self, *args, **kwargs) + +cdef class HeartbeatClient(PropertyListService): + __service_name__ = "com.apple.heartbeat" + cdef heartbeat_client_t _c_client + + def __cinit__(self, iDevice device not None, LockdownServiceDescriptor descriptor, *args, **kwargs): + self.handle_error(heartbeat_client_new(device._c_dev, descriptor._c_service_descriptor, &self._c_client)) + + def __dealloc__(self): + cdef heartbeat_error_t err + if self._c_client is not NULL: + err = heartbeat_client_free(self._c_client) + self.handle_error(err) + + cdef inline int16_t _send(self, plist.plist_t node): + return heartbeat_send(self._c_client, node) + + cdef inline int16_t _receive(self, plist.plist_t* node): + return heartbeat_receive(self._c_client, node) + + cdef inline int16_t _receive_with_timeout(self, plist.plist_t* node, int timeout_ms): + return heartbeat_receive_with_timeout(self._c_client, node, timeout_ms) + + cdef inline BaseError _error(self, int16_t ret): + return HeartbeatError(ret) diff --git a/cython/house_arrest.pxi b/cython/house_arrest.pxi new file mode 100644 index 0000000..54eebc1 --- /dev/null +++ b/cython/house_arrest.pxi @@ -0,0 +1,84 @@ +cdef extern from "libimobiledevice/house_arrest.h": + cdef struct house_arrest_client_private: + pass + ctypedef house_arrest_client_private *house_arrest_client_t + + ctypedef enum house_arrest_error_t: + HOUSE_ARREST_E_SUCCESS = 0 + HOUSE_ARREST_E_INVALID_ARG = -1 + HOUSE_ARREST_E_PLIST_ERROR = -2 + HOUSE_ARREST_E_CONN_FAILED = -3 + HOUSE_ARREST_E_INVALID_MODE = -4 + HOUSE_ARREST_E_UNKNOWN_ERROR = -256 + + house_arrest_error_t house_arrest_client_new(idevice_t device, lockdownd_service_descriptor_t descriptor, house_arrest_client_t * client) + house_arrest_error_t house_arrest_client_free(house_arrest_client_t client) + + house_arrest_error_t house_arrest_send_request(house_arrest_client_t client, plist.plist_t dict) + house_arrest_error_t house_arrest_send_command(house_arrest_client_t client, char *command, char *appid) + house_arrest_error_t house_arrest_get_result(house_arrest_client_t client, plist.plist_t *dict) + + afc_error_t afc_client_new_from_house_arrest_client(house_arrest_client_t client, afc_client_t *afc_client) + +cdef class HouseArrestError(BaseError): + def __init__(self, *args, **kwargs): + self._lookup_table = { + HOUSE_ARREST_E_SUCCESS: "Success", + HOUSE_ARREST_E_INVALID_ARG: "Invalid argument", + HOUSE_ARREST_E_PLIST_ERROR: "Property list error", + HOUSE_ARREST_E_CONN_FAILED: "Connection failed", + HOUSE_ARREST_E_INVALID_MODE: "Invalid mode", + HOUSE_ARREST_E_UNKNOWN_ERROR: "Unknown error" + } + BaseError.__init__(self, *args, **kwargs) + +cdef class HouseArrestClient(PropertyListService): + __service_name__ = "com.apple.mobile.house_arrest" + cdef house_arrest_client_t _c_client + + def __cinit__(self, iDevice device not None, LockdownServiceDescriptor descriptor, *args, **kwargs): + self.handle_error(house_arrest_client_new(device._c_dev, descriptor._c_service_descriptor, &self._c_client)) + + def __dealloc__(self): + cdef house_arrest_error_t err + if self._c_client is not NULL: + err = house_arrest_client_free(self._c_client) + self.handle_error(err) + + cdef inline BaseError _error(self, int16_t ret): + return HouseArrestError(ret) + + cpdef send_request(self, plist.Node message): + self.handle_error(house_arrest_send_request(self._c_client, message._c_node)) + + cpdef send_command(self, bytes command, bytes appid): + self.handle_error(house_arrest_send_command(self._c_client, command, appid)) + + cpdef plist.Node get_result(self): + cdef: + plist.plist_t c_node = NULL + house_arrest_error_t err + err = house_arrest_get_result(self._c_client, &c_node) + try: + self.handle_error(err) + return plist.plist_t_to_node(c_node) + except BaseError, e: + if c_node != NULL: + plist.plist_free(c_node) + raise + + cpdef AfcClient to_afc_client(self): + cdef: + afc_client_t c_afc_client = NULL + AfcClient result + afc_error_t err + err = afc_client_new_from_house_arrest_client(self._c_client, &c_afc_client) + try: + result = AfcClient.__new__(AfcClient) + result._c_client = c_afc_client + result.handle_error(err) + return result + except BaseError, e: + if c_afc_client != NULL: + afc_client_free(c_afc_client); + raise diff --git a/cython/imobiledevice.pxd b/cython/imobiledevice.pxd new file mode 100644 index 0000000..238df68 --- /dev/null +++ b/cython/imobiledevice.pxd @@ -0,0 +1,110 @@ +#!python +#cython: language_level=3str + +cimport plist + +from libc.stdint cimport * + +cdef extern from "pyerrors.h": + ctypedef class __builtin__.Exception [object PyBaseExceptionObject]: + pass + +cdef class BaseError(Exception): + cdef dict _lookup_table + cdef int16_t _c_errcode + +cdef class Base: + cdef inline int handle_error(self, int16_t ret) except -1 + cdef BaseError _error(self, int16_t ret) + +cdef class iDeviceError(BaseError): pass + +cdef extern from "libimobiledevice/libimobiledevice.h": + cdef struct idevice_private: + pass + ctypedef idevice_private* idevice_t + cdef struct idevice_connection_private: + pass + ctypedef idevice_connection_private* idevice_connection_t + cdef enum idevice_connection_type: + CONNECTION_USBMUXD = 1 + CONNECTION_NETWORK + cdef enum idevice_event_type: + IDEVICE_DEVICE_ADD = 1 + IDEVICE_DEVICE_REMOVE + IDEVICE_DEVICE_PAIRED + ctypedef struct idevice_event_t: + idevice_event_type event + char *udid + idevice_connection_type conn_type + ctypedef idevice_event_t* const_idevice_event_t "const idevice_event_t*" + +cdef class iDeviceEvent: + cdef const_idevice_event_t _c_event + +cdef class iDeviceConnection(Base): + cdef idevice_connection_t _c_connection + + cpdef bytes receive_timeout(self, uint32_t max_len, unsigned int timeout) + cpdef bytes receive(self, max_len) + cpdef disconnect(self) + +cdef class iDevice(Base): + cdef idevice_t _c_dev + + cpdef iDeviceConnection connect(self, uint16_t port) + +cdef class BaseService(Base): + pass + +cdef class PropertyListService(BaseService): + cpdef send(self, plist.Node node) + cpdef object receive(self) + cpdef object receive_with_timeout(self, int timeout_ms) + cdef int16_t _send(self, plist.plist_t node) + cdef int16_t _receive(self, plist.plist_t* c_node) + cdef int16_t _receive_with_timeout(self, plist.plist_t* c_node, int timeout_ms) + +cdef extern from "libimobiledevice/lockdown.h": + cdef struct lockdownd_client_private: + pass + ctypedef lockdownd_client_private *lockdownd_client_t + cdef struct lockdownd_pair_record: + char *device_certificate + char *host_certificate + char *host_id + char *root_certificate + ctypedef lockdownd_pair_record *lockdownd_pair_record_t + cdef struct lockdownd_service_descriptor: + uint16_t port + uint8_t ssl_enabled + ctypedef lockdownd_service_descriptor *lockdownd_service_descriptor_t + +cdef class LockdownError(BaseError): pass + +cdef class LockdownPairRecord: + cdef lockdownd_pair_record_t _c_record + +cdef class LockdownServiceDescriptor(Base): + cdef lockdownd_service_descriptor_t _c_service_descriptor + +cdef class LockdownClient(PropertyListService): + cdef lockdownd_client_t _c_client + cdef readonly iDevice device + + cpdef bytes query_type(self) + cpdef plist.Node get_value(self, bytes domain=*, bytes key=*) + cpdef set_value(self, bytes domain, bytes key, object value) + cpdef remove_value(self, bytes domain, bytes key) + cpdef object start_service(self, object service) + cpdef object get_service_client(self, object service_class) + cpdef tuple start_session(self, bytes host_id) + cpdef stop_session(self, bytes session_id) + cpdef pair(self, object pair_record=*) + cpdef validate_pair(self, object pair_record=*) + cpdef unpair(self, object pair_record=*) + cpdef activate(self, plist.Node activation_record) + cpdef deactivate(self) + cpdef enter_recovery(self) + cpdef goodbye(self) + cpdef list get_sync_data_classes(self) 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 @@ +cdef class BaseError(Exception): + def __cinit__(self, int16_t errcode): + self._c_errcode = errcode + + def __nonzero__(self): + return self._c_errcode != 0 + + property message: + def __get__(self): + if self._c_errcode in self._lookup_table: + return self._lookup_table[self._c_errcode] + else: + return "Unknown error ({0})".format(self._c_errcode) + + property code: + def __get__(self): + return self._c_errcode + + def __str__(self): + return '%s (%s)' % (self.message, self.code) + + def __repr__(self): + return self.__str__() + +cdef class Base: + cdef inline int handle_error(self, int16_t ret) except -1: + if ret == 0: + return 0 + cdef BaseError err = self._error(ret) + raise err + + cdef BaseError _error(self, int16_t ret): pass + +cdef extern from "libimobiledevice/libimobiledevice.h": + ctypedef enum idevice_error_t: + IDEVICE_E_SUCCESS = 0 + IDEVICE_E_INVALID_ARG = -1 + IDEVICE_E_UNKNOWN_ERROR = -2 + IDEVICE_E_NO_DEVICE = -3 + IDEVICE_E_NOT_ENOUGH_DATA = -4 + IDEVICE_E_SSL_ERROR = -6 + IDEVICE_E_TIMEOUT = -7 + cdef enum idevice_options: + IDEVICE_LOOKUP_USBMUX = 1 << 1 + IDEVICE_LOOKUP_NETWORK = 1 << 2 + IDEVICE_LOOKUP_PREFER_NETWORK = 1 << 3 + ctypedef void (*idevice_event_cb_t) (const_idevice_event_t event, void *user_data) + cdef extern idevice_error_t idevice_event_subscribe(idevice_event_cb_t callback, void *user_data) + cdef extern idevice_error_t idevice_event_unsubscribe() + idevice_error_t idevice_get_device_list(char ***devices, int *count) + idevice_error_t idevice_device_list_free(char **devices) + void idevice_set_debug_level(int level) + idevice_error_t idevice_new(idevice_t *device, char *udid) + idevice_error_t idevice_new_with_options(idevice_t *device, const char *udid, idevice_options options); + idevice_error_t idevice_free(idevice_t device) + idevice_error_t idevice_get_udid(idevice_t device, char** udid) + idevice_error_t idevice_get_handle(idevice_t device, uint32_t *handle) + idevice_error_t idevice_connect(idevice_t device, uint16_t port, idevice_connection_t *connection) + idevice_error_t idevice_disconnect(idevice_connection_t connection) + idevice_error_t idevice_connection_send(idevice_connection_t connection, char *data, uint32_t len, uint32_t *sent_bytes) + idevice_error_t idevice_connection_receive_timeout(idevice_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout) + idevice_error_t idevice_connection_receive(idevice_connection_t connection, char *data, uint32_t len, uint32_t *recv_bytes) + +cdef class iDeviceError(BaseError): + def __init__(self, *args, **kwargs): + self._lookup_table = { + IDEVICE_E_SUCCESS: 'Success', + IDEVICE_E_INVALID_ARG: 'Invalid argument', + IDEVICE_E_UNKNOWN_ERROR: 'Unknown error', + IDEVICE_E_NO_DEVICE: 'No device', + IDEVICE_E_NOT_ENOUGH_DATA: 'Not enough data', + IDEVICE_E_SSL_ERROR: 'SSL Error', + IDEVICE_E_TIMEOUT: 'Connection timeout' + } + BaseError.__init__(self, *args, **kwargs) + +def set_debug_level(int level): + idevice_set_debug_level(level) + +cdef class iDeviceEvent: + def __init__(self, *args, **kwargs): + raise TypeError("iDeviceEvent cannot be instantiated") + + def __str__(self): + return 'iDeviceEvent: %s (%s)' % (self.event == IDEVICE_DEVICE_ADD and 'Add' or 'Remove', self.udid) + + property event: + def __get__(self): + return self._c_event.event + property udid: + def __get__(self): + return self._c_event.udid + property conn_type: + def __get__(self): + return self._c_event.conn_type + +cdef void idevice_event_cb(const_idevice_event_t c_event, void *user_data) noexcept: + cdef iDeviceEvent event = iDeviceEvent.__new__(iDeviceEvent) + event._c_event = c_event + (<object>user_data)(event) + +def event_subscribe(object callback): + cdef iDeviceError err = iDeviceError(idevice_event_subscribe(idevice_event_cb, <void*>callback)) + if err: raise err + +def event_unsubscribe(): + cdef iDeviceError err = iDeviceError(idevice_event_unsubscribe()) + if err: raise err + +def get_device_list(): + cdef: + char** devices = NULL + int count + list result + bytes device + iDeviceError err = iDeviceError(idevice_get_device_list(&devices, &count)) + + if err: + if devices != NULL: + idevice_device_list_free(devices) + raise err + + result = [] + for i from 0 <= i < count: + device = devices[i] + result.append(device) + + err = iDeviceError(idevice_device_list_free(devices)) + if err: raise err + return result + +cdef class iDeviceConnection(Base): + def __init__(self, *args, **kwargs): + raise TypeError("iDeviceConnection cannot be instantiated. Please use iDevice.connect()") + + cpdef bytes receive_timeout(self, uint32_t max_len, unsigned int timeout): + cdef: + uint32_t bytes_received + char* c_data = <char *>malloc(max_len) + bytes result + + try: + self.handle_error(idevice_connection_receive_timeout(self._c_connection, c_data, max_len, &bytes_received, timeout)) + result = c_data[:bytes_received] + return result + except BaseError, e: + raise + finally: + free(c_data) + + cpdef bytes receive(self, max_len): + cdef: + uint32_t bytes_received + char* c_data = <char *>malloc(max_len) + bytes result + + try: + self.handle_error(idevice_connection_receive(self._c_connection, c_data, max_len, &bytes_received)) + result = c_data[:bytes_received] + return result + except BaseError, e: + raise + finally: + free(c_data) + + cpdef disconnect(self): + cdef idevice_error_t err + err = idevice_disconnect(self._c_connection) + self.handle_error(err) + + cdef BaseError _error(self, int16_t ret): + return iDeviceError(ret) + +from libc.stdlib cimport * + +cdef class iDevice(Base): + def __cinit__(self, object udid=None, *args, **kwargs): + cdef char* c_udid = NULL + if isinstance(udid, (str, bytes)): + c_udid = <bytes>udid + elif udid is not None: + raise TypeError("iDevice's constructor takes a string or None as the udid argument") + self.handle_error(idevice_new(&self._c_dev, c_udid)) + + def __dealloc__(self): + if self._c_dev is not NULL: + self.handle_error(idevice_free(self._c_dev)) + + cdef BaseError _error(self, int16_t ret): + return iDeviceError(ret) + + cpdef iDeviceConnection connect(self, uint16_t port): + cdef: + idevice_error_t err + idevice_connection_t c_conn = NULL + iDeviceConnection conn + err = idevice_connect(self._c_dev, port, &c_conn) + try: + self.handle_error(err) + + conn = iDeviceConnection.__new__(iDeviceConnection) + conn._c_connection = c_conn + + return conn + except Exception, e: + if c_conn != NULL: + idevice_disconnect(c_conn) + + property udid: + def __get__(self): + cdef: + char* udid + idevice_error_t err + err = idevice_get_udid(self._c_dev, &udid) + try: + self.handle_error(err) + return udid + except Exception, e: + if udid != NULL: + free(udid) + property handle: + def __get__(self): + cdef uint32_t handle + self.handle_error(idevice_get_handle(self._c_dev, &handle)) + return handle + +cdef extern from *: + ctypedef char* const_char_ptr "const char*" + +cdef class BaseService(Base): + __service_name__ = None + +cdef class PropertyListService(BaseService): + cpdef send(self, plist.Node node): + self.handle_error(self._send(node._c_node)) + + cpdef object receive(self): + cdef: + plist.plist_t c_node = NULL + int16_t err + err = self._receive(&c_node) + try: + self.handle_error(err) + + return plist.plist_t_to_node(c_node) + except BaseError, e: + if c_node != NULL: + plist.plist_free(c_node) + raise + + cpdef object receive_with_timeout(self, int timeout_ms): + cdef: + plist.plist_t c_node = NULL + int16_t err + err = self._receive_with_timeout(&c_node, timeout_ms) + try: + self.handle_error(err) + + return plist.plist_t_to_node(c_node) + except BaseError, e: + if c_node != NULL: + plist.plist_free(c_node) + raise + + cdef int16_t _send(self, plist.plist_t node): + raise NotImplementedError("send is not implemented") + + cdef int16_t _receive(self, plist.plist_t* c_node): + raise NotImplementedError("receive is not implemented") + + cdef int16_t _receive_with_timeout(self, plist.plist_t* c_node, int timeout_ms): + raise NotImplementedError("receive_with_timeout is not implemented") + +cdef class DeviceLinkService(PropertyListService): + pass + +include "lockdown.pxi" +include "mobilesync.pxi" +include "notification_proxy.pxi" +include "sbservices.pxi" +include "mobilebackup.pxi" +include "mobilebackup2.pxi" +include "afc.pxi" +include "file_relay.pxi" +include "screenshotr.pxi" +include "installation_proxy.pxi" +include "mobile_image_mounter.pxi" +include "webinspector.pxi" +include "heartbeat.pxi" +include "diagnostics_relay.pxi" +include "misagent.pxi" +include "house_arrest.pxi" +include "restore.pxi" +include "debugserver.pxi" diff --git a/cython/installation_proxy.pxi b/cython/installation_proxy.pxi new file mode 100644 index 0000000..1d3e323 --- /dev/null +++ b/cython/installation_proxy.pxi @@ -0,0 +1,304 @@ +cdef extern from "libimobiledevice/installation_proxy.h": + cdef struct instproxy_client_private: + pass + ctypedef instproxy_client_private *instproxy_client_t + ctypedef void (*instproxy_status_cb_t) (plist.plist_t command, plist.plist_t status, void *user_data) + + ctypedef enum instproxy_error_t: + INSTPROXY_E_SUCCESS = 0 + INSTPROXY_E_INVALID_ARG = -1 + INSTPROXY_E_PLIST_ERROR = -2 + INSTPROXY_E_CONN_FAILED = -3 + INSTPROXY_E_OP_IN_PROGRESS = -4 + INSTPROXY_E_OP_FAILED = -5 + INSTPROXY_E_UNKNOWN_ERROR = -256 + + instproxy_error_t instproxy_client_new(idevice_t device, lockdownd_service_descriptor_t descriptor, instproxy_client_t *client) + instproxy_error_t instproxy_client_free(instproxy_client_t client) + instproxy_error_t instproxy_client_get_path_for_bundle_identifier(instproxy_client_t client, const char* bundle_id, char** path) + + instproxy_error_t instproxy_browse(instproxy_client_t client, plist.plist_t client_options, plist.plist_t *result) + instproxy_error_t instproxy_install(instproxy_client_t client, char *pkg_path, plist.plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) + instproxy_error_t instproxy_upgrade(instproxy_client_t client, char *pkg_path, plist.plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) + instproxy_error_t instproxy_uninstall(instproxy_client_t client, char *appid, plist.plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) + + instproxy_error_t instproxy_lookup_archives(instproxy_client_t client, plist.plist_t client_options, plist.plist_t *result) + instproxy_error_t instproxy_archive(instproxy_client_t client, char *appid, plist.plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) + instproxy_error_t instproxy_restore(instproxy_client_t client, char *appid, plist.plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) + instproxy_error_t instproxy_remove_archive(instproxy_client_t client, char *appid, plist.plist_t client_options, instproxy_status_cb_t status_cb, void *user_data) + +cdef void instproxy_notify_cb(plist.plist_t command, plist.plist_t status, void *py_callback) noexcept: + (<object>py_callback)(plist.plist_t_to_node(command, False), plist.plist_t_to_node(status, False)) + +cdef class InstallationProxyError(BaseError): + def __init__(self, *args, **kwargs): + self._lookup_table = { + INSTPROXY_E_SUCCESS: "Success", + INSTPROXY_E_INVALID_ARG: "Invalid argument", + INSTPROXY_E_PLIST_ERROR: "Property list error", + INSTPROXY_E_CONN_FAILED: "Connection failed", + INSTPROXY_E_OP_IN_PROGRESS: "Operation in progress", + INSTPROXY_E_OP_FAILED: "Operation failed", + INSTPROXY_E_UNKNOWN_ERROR: "Unknown error" + } + BaseError.__init__(self, *args, **kwargs) + +cdef class InstallationProxyClient(PropertyListService): + __service_name__ = "com.apple.mobile.installation_proxy" + cdef instproxy_client_t _c_client + + def __cinit__(self, iDevice device not None, LockdownServiceDescriptor descriptor, *args, **kwargs): + cdef: + iDevice dev = device + instproxy_error_t err + err = instproxy_client_new(dev._c_dev, descriptor._c_service_descriptor, &self._c_client) + self.handle_error(err) + + def __dealloc__(self): + cdef instproxy_error_t err + if self._c_client is not NULL: + err = instproxy_client_free(self._c_client) + self.handle_error(err) + + cpdef get_path_for_bundle_identifier(self, bytes bundle_id): + cdef: + char* c_bundle_id = bundle_id + char* c_path = NULL + bytes result + + try: + self.handle_error(instproxy_client_get_path_for_bundle_identifier(self._c_client, c_bundle_id, &c_path)) + if c_path != NULL: + result = c_path + return result + else: + return None + except BaseError, e: + raise + finally: + free(c_path) + + cpdef plist.Node browse(self, object client_options): + cdef: + plist.Node options + plist.plist_t c_options + plist.plist_t c_result = NULL + bint free_options = False + instproxy_error_t err + if isinstance(client_options, plist.Dict): + options = client_options + c_options = options._c_node + elif isinstance(client_options, dict): + c_options = plist.native_to_plist_t(client_options) + free_options = True + else: + raise InstallationProxyError(INSTPROXY_E_INVALID_ARG) + err = instproxy_browse(self._c_client, c_options, &c_result) + + try: + self.handle_error(err) + return plist.plist_t_to_node(c_result) + except Exception, e: + if c_result != NULL: + plist.plist_free(c_result) + raise + finally: + if free_options: + plist.plist_free(c_options) + + cpdef install(self, bytes pkg_path, object client_options, object callback=None): + cdef: + plist.Node options + plist.plist_t c_options + bint free_options = False + instproxy_error_t err + if isinstance(client_options, plist.Dict): + options = client_options + c_options = options._c_node + elif isinstance(client_options, dict): + c_options = plist.native_to_plist_t(client_options) + free_options = True + else: + raise InstallationProxyError(INSTPROXY_E_INVALID_ARG) + if callback is None: + err = instproxy_install(self._c_client, pkg_path, c_options, NULL, NULL) + else: + err = instproxy_install(self._c_client, pkg_path, c_options, instproxy_notify_cb, <void*>callback) + + try: + self.handle_error(err) + except Exception, e: + raise + finally: + if free_options: + plist.plist_free(c_options) + + cpdef upgrade(self, bytes pkg_path, object client_options, object callback=None): + cdef: + plist.Node options + plist.plist_t c_options + bint free_options = False + instproxy_error_t err + if isinstance(client_options, plist.Dict): + options = client_options + c_options = options._c_node + elif isinstance(client_options, dict): + c_options = plist.native_to_plist_t(client_options) + free_options = True + else: + raise InstallationProxyError(INSTPROXY_E_INVALID_ARG) + if callback is None: + err = instproxy_upgrade(self._c_client, pkg_path, c_options, NULL, NULL) + else: + err = instproxy_upgrade(self._c_client, pkg_path, c_options, instproxy_notify_cb, <void*>callback) + try: + self.handle_error(err) + except Exception, e: + raise + finally: + if free_options: + plist.plist_free(c_options) + + cpdef uninstall(self, bytes appid, object client_options, object callback=None): + cdef: + plist.Node options + plist.plist_t c_options + instproxy_error_t err + bint free_options = False + if isinstance(client_options, plist.Dict): + options = client_options + c_options = options._c_node + elif isinstance(client_options, dict): + c_options = plist.native_to_plist_t(client_options) + free_options = True + else: + raise InstallationProxyError(INSTPROXY_E_INVALID_ARG) + + if callback is None: + err = instproxy_uninstall(self._c_client, appid, c_options, NULL, NULL) + else: + err = instproxy_uninstall(self._c_client, appid, c_options, instproxy_notify_cb, <void*>callback) + + try: + self.handle_error(err) + except Exception, e: + raise + finally: + if free_options: + plist.plist_free(c_options) + + cpdef plist.Node lookup_archives(self, object client_options): + cdef: + plist.Node options + plist.plist_t c_options + plist.plist_t c_node = NULL + instproxy_error_t err + bint free_options = False + if isinstance(client_options, plist.Dict): + options = client_options + c_options = options._c_node + elif isinstance(client_options, dict): + c_options = plist.native_to_plist_t(client_options) + free_options = True + else: + raise InstallationProxyError(INSTPROXY_E_INVALID_ARG) + + err = instproxy_lookup_archives(self._c_client, c_options, &c_node) + + try: + self.handle_error(err) + return plist.plist_t_to_node(c_node) + except Exception, e: + if c_node != NULL: + plist.plist_free(c_node) + raise + finally: + if free_options: + plist.plist_free(c_options) + + cpdef archive(self, bytes appid, object client_options, object callback=None): + cdef: + plist.Node options + plist.plist_t c_options + bint free_options = False + instproxy_error_t err + if isinstance(client_options, plist.Dict): + options = client_options + c_options = options._c_node + elif isinstance(client_options, dict): + c_options = plist.native_to_plist_t(client_options) + free_options = True + else: + raise InstallationProxyError(INSTPROXY_E_INVALID_ARG) + + if callback is None: + err = instproxy_archive(self._c_client, appid, c_options, NULL, NULL) + else: + err = instproxy_archive(self._c_client, appid, c_options, instproxy_notify_cb, <void*>callback) + + try: + self.handle_error(err) + except Exception, e: + raise + finally: + if free_options: + plist.plist_free(c_options) + + cpdef restore(self, bytes appid, object client_options, object callback=None): + cdef: + plist.Node options + plist.plist_t c_options + bint free_options = False + instproxy_error_t err + if isinstance(client_options, plist.Dict): + options = client_options + c_options = options._c_node + elif isinstance(client_options, dict): + c_options = plist.native_to_plist_t(client_options) + free_options = True + else: + raise InstallationProxyError(INSTPROXY_E_INVALID_ARG) + + if callback is None: + err = instproxy_restore(self._c_client, appid, c_options, NULL, NULL) + else: + err = instproxy_restore(self._c_client, appid, c_options, instproxy_notify_cb, <void*>callback) + + try: + self.handle_error(err) + except Exception, e: + raise + finally: + if free_options: + plist.plist_free(c_options) + + cpdef remove_archive(self, bytes appid, object client_options, object callback=None): + cdef: + plist.Node options + plist.plist_t c_options + bint free_options = False + instproxy_error_t err + if isinstance(client_options, plist.Dict): + options = client_options + c_options = options._c_node + elif isinstance(client_options, dict): + c_options = plist.native_to_plist_t(client_options) + free_options = True + else: + raise InstallationProxyError(INSTPROXY_E_INVALID_ARG) + + if callback is None: + err = instproxy_remove_archive(self._c_client, appid, c_options, NULL, NULL) + else: + err = instproxy_remove_archive(self._c_client, appid, c_options, instproxy_notify_cb, <void*>callback) + + try: + self.handle_error(err) + except Exception, e: + raise + finally: + if free_options: + plist.plist_free(c_options) + + cdef inline BaseError _error(self, int16_t ret): + return InstallationProxyError(ret) diff --git a/cython/lockdown.pxi b/cython/lockdown.pxi new file mode 100644 index 0000000..25edb4c --- /dev/null +++ b/cython/lockdown.pxi @@ -0,0 +1,351 @@ +cdef extern from "libimobiledevice/lockdown.h": + ctypedef enum lockdownd_error_t: + LOCKDOWN_E_SUCCESS + LOCKDOWN_E_INVALID_ARG + LOCKDOWN_E_INVALID_CONF + LOCKDOWN_E_PLIST_ERROR + LOCKDOWN_E_PAIRING_FAILED + LOCKDOWN_E_SSL_ERROR + LOCKDOWN_E_DICT_ERROR + LOCKDOWN_E_RECEIVE_TIMEOUT + LOCKDOWN_E_SET_VALUE_PROHIBITED + LOCKDOWN_E_GET_VALUE_PROHIBITED + LOCKDOWN_E_MUX_ERROR + LOCKDOWN_E_NO_RUNNING_SESSION + LOCKDOWN_E_INVALID_RESPONSE + LOCKDOWN_E_MISSING_KEY + LOCKDOWN_E_MISSING_VALUE + LOCKDOWN_E_GET_PROHIBITED + LOCKDOWN_E_SET_PROHIBITED + LOCKDOWN_E_REMOVE_PROHIBITED + LOCKDOWN_E_IMMUTABLE_VALUE + LOCKDOWN_E_PASSWORD_PROTECTED + LOCKDOWN_E_USER_DENIED_PAIRING + LOCKDOWN_E_PAIRING_DIALOG_RESPONSE_PENDING + LOCKDOWN_E_MISSING_HOST_ID + LOCKDOWN_E_INVALID_HOST_ID + LOCKDOWN_E_SESSION_ACTIVE + LOCKDOWN_E_SESSION_INACTIVE + LOCKDOWN_E_MISSING_SESSION_ID + LOCKDOWN_E_INVALID_SESSION_ID + LOCKDOWN_E_MISSING_SERVICE + LOCKDOWN_E_INVALID_SERVICE + LOCKDOWN_E_SERVICE_LIMIT + LOCKDOWN_E_MISSING_PAIR_RECORD + LOCKDOWN_E_SAVE_PAIR_RECORD_FAILED + LOCKDOWN_E_INVALID_PAIR_RECORD + LOCKDOWN_E_INVALID_ACTIVATION_RECORD + LOCKDOWN_E_MISSING_ACTIVATION_RECORD + LOCKDOWN_E_SERVICE_PROHIBITED + LOCKDOWN_E_ESCROW_LOCKED + LOCKDOWN_E_PAIRING_PROHIBITED_OVER_THIS_CONNECTION + LOCKDOWN_E_FMIP_PROTECTED + LOCKDOWN_E_MC_PROTECTED + LOCKDOWN_E_MC_CHALLENGE_REQUIRED + LOCKDOWN_E_UNKNOWN_ERROR + + lockdownd_error_t lockdownd_client_new(idevice_t device, lockdownd_client_t *client, char *label) + lockdownd_error_t lockdownd_client_new_with_handshake(idevice_t device, lockdownd_client_t *client, char *label) + lockdownd_error_t lockdownd_client_free(lockdownd_client_t client) + + lockdownd_error_t lockdownd_query_type(lockdownd_client_t client, char **tp) + lockdownd_error_t lockdownd_get_value(lockdownd_client_t client, char *domain, char *key, plist.plist_t *value) + lockdownd_error_t lockdownd_set_value(lockdownd_client_t client, char *domain, char *key, plist.plist_t value) + lockdownd_error_t lockdownd_remove_value(lockdownd_client_t client, char *domain, char *key) + lockdownd_error_t lockdownd_start_service(lockdownd_client_t client, char *identifier, lockdownd_service_descriptor_t *service) + lockdownd_error_t lockdownd_start_session(lockdownd_client_t client, char *host_id, char **session_id, int *ssl_enabled) + lockdownd_error_t lockdownd_stop_session(lockdownd_client_t client, char *session_id) + lockdownd_error_t lockdownd_send(lockdownd_client_t client, plist.plist_t plist) + lockdownd_error_t lockdownd_receive(lockdownd_client_t client, plist.plist_t *plist) + lockdownd_error_t lockdownd_pair(lockdownd_client_t client, lockdownd_pair_record_t pair_record) + lockdownd_error_t lockdownd_validate_pair(lockdownd_client_t client, lockdownd_pair_record_t pair_record) + lockdownd_error_t lockdownd_unpair(lockdownd_client_t client, lockdownd_pair_record_t pair_record) + lockdownd_error_t lockdownd_activate(lockdownd_client_t client, plist.plist_t activation_record) + lockdownd_error_t lockdownd_deactivate(lockdownd_client_t client) + lockdownd_error_t lockdownd_enter_recovery(lockdownd_client_t client) + lockdownd_error_t lockdownd_goodbye(lockdownd_client_t client) + lockdownd_error_t lockdownd_get_sync_data_classes(lockdownd_client_t client, char ***classes, int *count) + lockdownd_error_t lockdownd_data_classes_free(char **classes) + lockdownd_error_t lockdownd_service_descriptor_free(lockdownd_service_descriptor_t service) + +cdef class LockdownError(BaseError): + def __init__(self, *args, **kwargs): + self._lookup_table = { + LOCKDOWN_E_SUCCESS: "Success", + LOCKDOWN_E_INVALID_ARG: "Invalid argument", + LOCKDOWN_E_INVALID_CONF: "Invalid configuration", + LOCKDOWN_E_PLIST_ERROR: "Property list error", + LOCKDOWN_E_PAIRING_FAILED: "Pairing failed", + LOCKDOWN_E_SSL_ERROR: "SSL error", + LOCKDOWN_E_DICT_ERROR: "Dictionary error", + LOCKDOWN_E_RECEIVE_TIMEOUT: "Receive timeout", + LOCKDOWN_E_MUX_ERROR: "Mux Protocol Error", + LOCKDOWN_E_NO_RUNNING_SESSION: "No running session", + LOCKDOWN_E_INVALID_RESPONSE: "Invalid response", + LOCKDOWN_E_MISSING_KEY: "Missing key", + LOCKDOWN_E_MISSING_VALUE: "Missing value", + LOCKDOWN_E_GET_PROHIBITED: "Get value prohibited", + LOCKDOWN_E_SET_PROHIBITED: "Set value prohibited", + LOCKDOWN_E_REMOVE_PROHIBITED: "Remove value prohibited", + LOCKDOWN_E_IMMUTABLE_VALUE: "Immutable value", + LOCKDOWN_E_PASSWORD_PROTECTED: "Password protected", + LOCKDOWN_E_USER_DENIED_PAIRING: "User denied pairing", + LOCKDOWN_E_PAIRING_DIALOG_RESPONSE_PENDING: "Pairing dialog response pending", + LOCKDOWN_E_MISSING_HOST_ID: "Missing host ID", + LOCKDOWN_E_INVALID_HOST_ID: "Invalid host ID", + LOCKDOWN_E_SESSION_ACTIVE: "Session active", + LOCKDOWN_E_SESSION_INACTIVE: "Session inactive", + LOCKDOWN_E_MISSING_SESSION_ID: "Missing session ID", + LOCKDOWN_E_INVALID_SESSION_ID: "Invalid session ID", + LOCKDOWN_E_MISSING_SERVICE: "Missing service", + LOCKDOWN_E_INVALID_SERVICE: "Invalid service", + LOCKDOWN_E_SERVICE_LIMIT: "Service limit reached", + LOCKDOWN_E_MISSING_PAIR_RECORD: "Missing pair record", + LOCKDOWN_E_SAVE_PAIR_RECORD_FAILED: "Saving pair record failed", + LOCKDOWN_E_INVALID_PAIR_RECORD: "Invalid pair record", + LOCKDOWN_E_INVALID_ACTIVATION_RECORD: "Invalid activation record", + LOCKDOWN_E_MISSING_ACTIVATION_RECORD: "Missing activation record", + LOCKDOWN_E_SERVICE_PROHIBITED: "Service prohibited", + LOCKDOWN_E_ESCROW_LOCKED: "Escrow locked", + LOCKDOWN_E_PAIRING_PROHIBITED_OVER_THIS_CONNECTION: "Pairing prohibited over this connection", + LOCKDOWN_E_FMIP_PROTECTED: "Find My iPhone/iPod/iPad protected", + LOCKDOWN_E_MC_PROTECTED: "MC protected", + LOCKDOWN_E_MC_CHALLENGE_REQUIRED: "MC challenge required", + LOCKDOWN_E_UNKNOWN_ERROR: "Unknown error" + } + BaseError.__init__(self, *args, **kwargs) + +cdef class LockdownPairRecord: + #def __cinit__(self, bytes device_certificate, bytes host_certificate, bytes host_id, bytes root_certificate, *args, **kwargs): + property device_certificate: + def __get__(self): + cdef bytes result = self._c_record.device_certificate + return result + property host_certificate: + def __get__(self): + cdef bytes result = self._c_record.host_certificate + return result + property host_id: + def __get__(self): + cdef bytes result = self._c_record.host_id + return result + property root_certificate: + def __get__(self): + cdef bytes result = self._c_record.root_certificate + return result + +cdef class LockdownServiceDescriptor(Base): + #def __cinit__(self, uint16_t port, uint8_t ssl_enabled, *args, **kwargs): + def __dealloc__(self): + cdef lockdownd_error_t err + if self._c_service_descriptor is not NULL: + err = lockdownd_service_descriptor_free(self._c_service_descriptor) + self._c_service_descriptor = NULL + self.handle_error(err) + property port: + def __get__(self): + return self._c_service_descriptor.port + property ssl_enabled: + def __get__(self): + return self._c_service_descriptor.ssl_enabled + +cdef class LockdownClient(PropertyListService): + def __cinit__(self, iDevice device not None, bytes label=b'', bint handshake=True, *args, **kwargs): + cdef: + lockdownd_error_t err + char* c_label = NULL + if label: + c_label = label + if handshake: + err = lockdownd_client_new_with_handshake(device._c_dev, &self._c_client, c_label) + else: + err = lockdownd_client_new(device._c_dev, &self._c_client, c_label) + self.handle_error(err) + + self.device = device + + def __dealloc__(self): + cdef lockdownd_error_t err + if self._c_client is not NULL: + err = lockdownd_client_free(self._c_client) + self.handle_error(err) + + cpdef bytes query_type(self): + cdef: + lockdownd_error_t err + char* c_type = NULL + bytes result + err = lockdownd_query_type(self._c_client, &c_type) + try: + self.handle_error(err) + result = c_type + + return result + except BaseError, e: + raise + finally: + if c_type != NULL: + free(c_type) + + cpdef plist.Node get_value(self, bytes domain=None, bytes key=None): + cdef: + lockdownd_error_t err + plist.plist_t c_node = NULL + char* c_domain = NULL + char* c_key = NULL + if domain is not None: + c_domain = domain + if key is not None: + c_key = key + + err = lockdownd_get_value(self._c_client, c_domain, c_key, &c_node) + + try: + self.handle_error(err) + + return plist.plist_t_to_node(c_node) + except BaseError, e: + if c_node != NULL: + plist.plist_free(c_node) + raise + + cpdef set_value(self, bytes domain, bytes key, object value): + cdef: + plist.plist_t c_node = NULL + char* c_domain = NULL + char* c_key = NULL + + c_node = plist.native_to_plist_t(value) + if domain is not None: + c_domain = domain + if key is not None: + c_key = key + try: + self.handle_error(lockdownd_set_value(self._c_client, c_domain, c_key, c_node)) + except BaseError, e: + raise + finally: + if c_node != NULL: + c_node = NULL + + cpdef remove_value(self, bytes domain, bytes key): + self.handle_error(lockdownd_remove_value(self._c_client, domain, key)) + + cpdef object start_service(self, object service): + cdef: + char* c_service_name = NULL + lockdownd_service_descriptor_t c_descriptor = NULL + LockdownServiceDescriptor result + + if issubclass(service, BaseService) and \ + service.__service_name__ is not None \ + and isinstance(service.__service_name__, (str, bytes)): + c_service_name_str = service.__service_name__.encode('utf-8') + elif isinstance(service, (str, bytes)): + c_service_name_str = service.encode('utf-8') + else: + raise TypeError("LockdownClient.start_service() takes a BaseService or string as its first argument") + c_service_name = c_service_name_str + + try: + self.handle_error(lockdownd_start_service(self._c_client, c_service_name, &c_descriptor)) + + result = LockdownServiceDescriptor.__new__(LockdownServiceDescriptor) + result._c_service_descriptor = c_descriptor + + return result + except BaseError, e: + raise + + cpdef object get_service_client(self, object service_class): + cdef: + LockdownServiceDescriptor descriptor + + if not hasattr(service_class, '__service_name__') and \ + not service_class.__service_name__ is not None \ + and not isinstance(service_class.__service_name__, (str, bytes)): + raise TypeError("LockdownClient.get_service_client() takes a BaseService as its first argument") + + descriptor = self.start_service(service_class) + return service_class(self.device, descriptor) + + cpdef tuple start_session(self, bytes host_id): + cdef: + lockdownd_error_t err + char* c_session_id = NULL + bint ssl_enabled + bytes session_id + err = lockdownd_start_session(self._c_client, host_id, &c_session_id, <int *>&ssl_enabled) + try: + self.handle_error(err) + + session_id = c_session_id + return (session_id, ssl_enabled) + except BaseError, e: + raise + finally: + if c_session_id != NULL: + free(c_session_id) + + cpdef stop_session(self, bytes session_id): + self.handle_error(lockdownd_stop_session(self._c_client, session_id)) + + cpdef pair(self, object pair_record=None): + cdef lockdownd_pair_record_t c_pair_record = NULL + if pair_record is not None: + c_pair_record = (<LockdownPairRecord>pair_record)._c_record + self.handle_error(lockdownd_pair(self._c_client, c_pair_record)) + + cpdef validate_pair(self, object pair_record=None): + cdef lockdownd_pair_record_t c_pair_record = NULL + if pair_record is not None: + c_pair_record = (<LockdownPairRecord>pair_record)._c_record + self.handle_error(lockdownd_validate_pair(self._c_client, c_pair_record)) + + cpdef unpair(self, object pair_record=None): + cdef lockdownd_pair_record_t c_pair_record = NULL + if pair_record is not None: + c_pair_record = (<LockdownPairRecord>pair_record)._c_record + self.handle_error(lockdownd_unpair(self._c_client, c_pair_record)) + + cpdef activate(self, plist.Node activation_record): + self.handle_error(lockdownd_activate(self._c_client, activation_record._c_node)) + + cpdef deactivate(self): + self.handle_error(lockdownd_deactivate(self._c_client)) + + cpdef enter_recovery(self): + self.handle_error(lockdownd_enter_recovery(self._c_client)) + + cpdef goodbye(self): + self.handle_error(lockdownd_goodbye(self._c_client)) + + cpdef list get_sync_data_classes(self): + cdef: + char **classes = NULL + int count = 0 + list result = [] + bytes data_class + + try: + self.handle_error(lockdownd_get_sync_data_classes(self._c_client, &classes, &count)) + + for i from 0 <= i < count: + data_class = classes[i] + result.append(data_class) + + return result + except Exception, e: + raise + finally: + if classes != NULL: + lockdownd_data_classes_free(classes) + + cdef inline int16_t _send(self, plist.plist_t node): + return lockdownd_send(self._c_client, node) + + cdef inline int16_t _receive(self, plist.plist_t* node): + return lockdownd_receive(self._c_client, node) + + cdef inline BaseError _error(self, int16_t ret): + return LockdownError(ret) diff --git a/cython/misagent.pxi b/cython/misagent.pxi new file mode 100644 index 0000000..1fee4b9 --- /dev/null +++ b/cython/misagent.pxi @@ -0,0 +1,74 @@ +cdef extern from "libimobiledevice/misagent.h": + cdef struct misagent_client_private: + pass + ctypedef misagent_client_private *misagent_client_t + + ctypedef enum misagent_error_t: + MISAGENT_E_SUCCESS = 0 + MISAGENT_E_INVALID_ARG = -1 + MISAGENT_E_PLIST_ERROR = -2 + MISAGENT_E_CONN_FAILED = -3 + MISAGENT_E_REQUEST_FAILED = -4 + MISAGENT_E_UNKNOWN_ERROR = -256 + + misagent_error_t misagent_client_new(idevice_t device, lockdownd_service_descriptor_t descriptor, misagent_client_t * client) + misagent_error_t misagent_client_free(misagent_client_t client) + + misagent_error_t misagent_install(misagent_client_t client, plist.plist_t profile) + misagent_error_t misagent_copy(misagent_client_t client, plist.plist_t* profiles) + misagent_error_t misagent_remove(misagent_client_t client, char* profileID) + int misagent_get_status_code(misagent_client_t client) + +cdef class MisagentError(BaseError): + def __init__(self, *args, **kwargs): + self._lookup_table = { + MISAGENT_E_SUCCESS: "Success", + MISAGENT_E_INVALID_ARG: "Invalid argument", + MISAGENT_E_PLIST_ERROR: "Property list error", + MISAGENT_E_CONN_FAILED: "Connection failed", + MISAGENT_E_REQUEST_FAILED: "Request failed", + MISAGENT_E_UNKNOWN_ERROR: "Unknown error" + } + BaseError.__init__(self, *args, **kwargs) + +cdef class MisagentClient(PropertyListService): + __service_name__ = "com.apple.misagent" + cdef misagent_client_t _c_client + + def __cinit__(self, iDevice device not None, LockdownServiceDescriptor descriptor, *args, **kwargs): + self.handle_error(misagent_client_new(device._c_dev, descriptor._c_service_descriptor, &self._c_client)) + + def __dealloc__(self): + cdef misagent_error_t err + if self._c_client is not NULL: + err = misagent_client_free(self._c_client) + self.handle_error(err) + + cdef inline BaseError _error(self, int16_t ret): + return MisagentError(ret) + + cpdef install(self, plist.Node profile): + cdef misagent_error_t err + err = misagent_install(self._c_client, profile._c_node) + self.handle_error(err) + + cpdef plist.Node copy(self): + cdef: + plist.plist_t c_node = NULL + misagent_error_t err + err = misagent_copy(self._c_client, &c_node) + try: + self.handle_error(err) + return plist.plist_t_to_node(c_node) + except BaseError, e: + if c_node != NULL: + plist.plist_free(c_node) + raise + + cpdef remove(self, bytes profile_id): + cdef misagent_error_t err + err = misagent_remove(self._c_client, profile_id) + self.handle_error(err) + + cpdef int get_status_code(self): + return misagent_get_status_code(self._c_client) diff --git a/cython/mobile_image_mounter.pxi b/cython/mobile_image_mounter.pxi new file mode 100644 index 0000000..d9d40d5 --- /dev/null +++ b/cython/mobile_image_mounter.pxi @@ -0,0 +1,115 @@ +cdef extern from "libimobiledevice/mobile_image_mounter.h": + cdef struct mobile_image_mounter_client_private: + pass + ctypedef mobile_image_mounter_client_private *mobile_image_mounter_client_t + + ctypedef enum mobile_image_mounter_error_t: + MOBILE_IMAGE_MOUNTER_E_SUCCESS = 0 + MOBILE_IMAGE_MOUNTER_E_INVALID_ARG = -1 + MOBILE_IMAGE_MOUNTER_E_PLIST_ERROR = -2 + MOBILE_IMAGE_MOUNTER_E_CONN_FAILED = -3 + MOBILE_IMAGE_MOUNTER_E_UNKNOWN_ERROR = -256 + + mobile_image_mounter_error_t mobile_image_mounter_new(idevice_t device, lockdownd_service_descriptor_t descriptor, mobile_image_mounter_client_t *client) + mobile_image_mounter_error_t mobile_image_mounter_free(mobile_image_mounter_client_t client) + mobile_image_mounter_error_t mobile_image_mounter_lookup_image(mobile_image_mounter_client_t client, char *image_type, plist.plist_t *result) + mobile_image_mounter_error_t mobile_image_mounter_mount_image_with_options(mobile_image_mounter_client_t client, char *image_path, const unsigned char *signature, unsigned int signature_length, char *image_type, plist.plist_t options, plist.plist_t *result) + mobile_image_mounter_error_t mobile_image_mounter_mount_image(mobile_image_mounter_client_t client, char *image_path, const unsigned char *signature, unsigned int signature_length, char *image_type, plist.plist_t *result) + mobile_image_mounter_error_t mobile_image_mounter_unmount_image(mobile_image_mounter_client_t client, const char *mount_path); + mobile_image_mounter_error_t mobile_image_mounter_hangup(mobile_image_mounter_client_t client) + +cdef class MobileImageMounterError(BaseError): + def __init__(self, *args, **kwargs): + self._lookup_table = { + MOBILE_IMAGE_MOUNTER_E_SUCCESS: "Success", + MOBILE_IMAGE_MOUNTER_E_INVALID_ARG: "Invalid argument", + MOBILE_IMAGE_MOUNTER_E_PLIST_ERROR: "Property list error", + MOBILE_IMAGE_MOUNTER_E_CONN_FAILED: "Connection failed", + MOBILE_IMAGE_MOUNTER_E_UNKNOWN_ERROR: "Unknown error" + } + BaseError.__init__(self, *args, **kwargs) + +cdef class MobileImageMounterClient(PropertyListService): + __service_name__ = "com.apple.mobile.mobile_image_mounter" + cdef mobile_image_mounter_client_t _c_client + + def __cinit__(self, iDevice device not None, LockdownServiceDescriptor descriptor, *args, **kwargs): + self.handle_error(mobile_image_mounter_new(device._c_dev, descriptor._c_service_descriptor, &self._c_client)) + + def __dealloc__(self): + cdef mobile_image_mounter_error_t err + if self._c_client is not NULL: + err = mobile_image_mounter_free(self._c_client) + self.handle_error(err) + + cdef inline BaseError _error(self, int16_t ret): + return MobileImageMounterError(ret) + + cpdef plist.Node lookup_image(self, bytes image_type): + cdef: + plist.plist_t c_node = NULL + mobile_image_mounter_error_t err + err = mobile_image_mounter_lookup_image(self._c_client, image_type, &c_node) + + try: + self.handle_error(err) + + return plist.plist_t_to_node(c_node) + except Exception, e: + if c_node != NULL: + plist.plist_free(c_node) + + cpdef plist.Node mount_image_with_options(self, bytes image_path, bytes signature, bytes image_type, object options): + cdef: + plist.Node n_options + plist.plist_t c_options + plist.plist_t c_result = NULL + bint free_options = False + plist.plist_t c_node = NULL + mobile_image_mounter_error_t err + if isinstance(options, plist.Dict): + n_options = options + c_options = n_options._c_node + elif isinstance(options, dict): + c_options = plist.native_to_plist_t(options) + free_options = True + else: + raise InstallationProxyError(INSTPROXY_E_INVALID_ARG) + err = mobile_image_mounter_mount_image_with_options(self._c_client, image_path, signature, len(signature), + image_type, c_options, &c_node) + if free_options: + plist.plist_free(c_options) + try: + self.handle_error(err) + + return plist.plist_t_to_node(c_node) + except Exception, e: + if c_node != NULL: + plist.plist_free(c_node) + + cpdef plist.Node mount_image(self, bytes image_path, bytes signature, bytes image_type): + cdef: + plist.plist_t c_node = NULL + mobile_image_mounter_error_t err + err = mobile_image_mounter_mount_image(self._c_client, image_path, signature, len(signature), + image_type, &c_node) + + try: + self.handle_error(err) + + return plist.plist_t_to_node(c_node) + except Exception, e: + if c_node != NULL: + plist.plist_free(c_node) + + cpdef unmount_image(self, bytes mount_path): + cdef: + mobile_image_mounter_error_t err + err = mobile_image_mounter_unmount_image(self._c_client, mount_path) + + self.handle_error(err) + + cpdef hangup(self): + cdef mobile_image_mounter_error_t err + err = mobile_image_mounter_hangup(self._c_client) + self.handle_error(err) diff --git a/cython/mobilebackup.pxi b/cython/mobilebackup.pxi new file mode 100644 index 0000000..f2d58d4 --- /dev/null +++ b/cython/mobilebackup.pxi @@ -0,0 +1,110 @@ +cdef extern from "libimobiledevice/mobilebackup.h": + cdef struct mobilebackup_client_private: + pass + ctypedef mobilebackup_client_private *mobilebackup_client_t + + ctypedef enum mobilebackup_error_t: + MOBILEBACKUP_E_SUCCESS = 0 + MOBILEBACKUP_E_INVALID_ARG = -1 + MOBILEBACKUP_E_PLIST_ERROR = -2 + MOBILEBACKUP_E_MUX_ERROR = -3 + MOBILEBACKUP_E_SSL_ERROR = -4 + MOBILEBACKUP_E_RECEIVE_TIMEOUT = -5 + MOBILEBACKUP_E_BAD_VERSION = -6 + MOBILEBACKUP_E_REPLY_NOT_OK = -7 + MOBILEBACKUP_E_UNKNOWN_ERROR = -256 + + ctypedef enum mobilebackup_flags_t: + MB_RESTORE_NOTIFY_SPRINGBOARD = (1 << 0) + MB_RESTORE_PRESERVE_SETTINGS = (1 << 1) + MB_RESTORE_PRESERVE_CAMERA_ROLL = (1 << 2) + + mobilebackup_error_t mobilebackup_client_new(idevice_t device, lockdownd_service_descriptor_t descriptor, mobilebackup_client_t * client) + mobilebackup_error_t mobilebackup_client_free(mobilebackup_client_t client) + mobilebackup_error_t mobilebackup_receive(mobilebackup_client_t client, plist.plist_t *plist) + mobilebackup_error_t mobilebackup_send(mobilebackup_client_t client, plist.plist_t plist) + mobilebackup_error_t mobilebackup_request_backup(mobilebackup_client_t client, plist.plist_t backup_manifest, char *base_path, char *proto_version) + mobilebackup_error_t mobilebackup_send_backup_file_received(mobilebackup_client_t client) + mobilebackup_error_t mobilebackup_request_restore(mobilebackup_client_t client, plist.plist_t backup_manifest, mobilebackup_flags_t flags, char *proto_version) + mobilebackup_error_t mobilebackup_receive_restore_file_received(mobilebackup_client_t client, plist.plist_t *result) + mobilebackup_error_t mobilebackup_receive_restore_application_received(mobilebackup_client_t client, plist.plist_t *result) + mobilebackup_error_t mobilebackup_send_restore_complete(mobilebackup_client_t client) + mobilebackup_error_t mobilebackup_send_error(mobilebackup_client_t client, char *reason) + +cdef class MobileBackupError(BaseError): + def __init__(self, *args, **kwargs): + self._lookup_table = { + MOBILEBACKUP_E_SUCCESS: "Success", + MOBILEBACKUP_E_INVALID_ARG: "Invalid argument", + MOBILEBACKUP_E_PLIST_ERROR: "Property list error", + MOBILEBACKUP_E_MUX_ERROR: "MUX error", + MOBILEBACKUP_E_SSL_ERROR: "SSL error", + MOBILEBACKUP_E_RECEIVE_TIMEOUT: "Receive timeout", + MOBILEBACKUP_E_BAD_VERSION: "Bad version", + MOBILEBACKUP_E_REPLY_NOT_OK: "Reply not OK", + MOBILEBACKUP_E_UNKNOWN_ERROR: "Unknown error" + } + BaseError.__init__(self, *args, **kwargs) + +cdef class MobileBackupClient(PropertyListService): + __service_name__ = "com.apple.mobilebackup" + cdef mobilebackup_client_t _c_client + + def __cinit__(self, iDevice device not None, LockdownServiceDescriptor descriptor, *args, **kwargs): + self.handle_error(mobilebackup_client_new(device._c_dev, descriptor._c_service_descriptor, &self._c_client)) + + def __dealloc__(self): + cdef mobilebackup_error_t err + if self._c_client is not NULL: + err = mobilebackup_client_free(self._c_client) + self.handle_error(err) + + cdef inline BaseError _error(self, int16_t ret): + return MobileBackupError(ret) + + cdef inline int16_t _send(self, plist.plist_t node): + return mobilebackup_send(self._c_client, node) + + cdef inline int16_t _receive(self, plist.plist_t* node): + return mobilebackup_receive(self._c_client, node) + + cdef request_backup(self, plist.Node backup_manifest, bytes base_path, bytes proto_version): + self.handle_error(mobilebackup_request_backup(self._c_client, backup_manifest._c_node, base_path, proto_version)) + + cdef send_backup_file_received(self): + self.handle_error(mobilebackup_send_backup_file_received(self._c_client)) + + cdef request_restore(self, plist.Node backup_manifest, int flags, proto_version): + self.handle_error(mobilebackup_request_restore(self._c_client, backup_manifest._c_node, <mobilebackup_flags_t>flags, proto_version)) + + cpdef plist.Node receive_restore_file_received(self): + cdef: + plist.plist_t c_node = NULL + mobilebackup_error_t err + err = mobilebackup_receive_restore_file_received(self._c_client, &c_node) + try: + self.handle_error(err) + return plist.plist_t_to_node(c_node) + except BaseError, e: + if c_node != NULL: + plist.plist_free(c_node) + raise + + cpdef plist.Node receive_restore_application_received(self): + cdef: + plist.plist_t c_node = NULL + mobilebackup_error_t err + err = mobilebackup_receive_restore_application_received(self._c_client, &c_node) + try: + self.handle_error(err) + return plist.plist_t_to_node(c_node) + except BaseError, e: + if c_node != NULL: + plist.plist_free(c_node) + raise + + cdef send_restore_complete(self): + self.handle_error(mobilebackup_send_restore_complete(self._c_client)) + + cdef send_error(self, bytes reason): + self.handle_error(mobilebackup_send_error(self._c_client, reason)) diff --git a/cython/mobilebackup2.pxi b/cython/mobilebackup2.pxi new file mode 100644 index 0000000..4b47e5b --- /dev/null +++ b/cython/mobilebackup2.pxi @@ -0,0 +1,123 @@ +cdef extern from "libimobiledevice/mobilebackup2.h": + cdef struct mobilebackup2_client_private: + pass + ctypedef mobilebackup2_client_private *mobilebackup2_client_t + + ctypedef enum mobilebackup2_error_t: + MOBILEBACKUP2_E_SUCCESS = 0 + MOBILEBACKUP2_E_INVALID_ARG = -1 + MOBILEBACKUP2_E_PLIST_ERROR = -2 + MOBILEBACKUP2_E_MUX_ERROR = -3 + MOBILEBACKUP2_E_SSL_ERROR = -4 + MOBILEBACKUP2_E_RECEIVE_TIMEOUT = -5 + MOBILEBACKUP2_E_BAD_VERSION = -6 + MOBILEBACKUP2_E_REPLY_NOT_OK = -7 + MOBILEBACKUP2_E_NO_COMMON_VERSION = -8 + MOBILEBACKUP2_E_UNKNOWN_ERROR = -256 + + mobilebackup2_error_t mobilebackup2_client_new(idevice_t device, lockdownd_service_descriptor_t descriptor, mobilebackup2_client_t * client) + mobilebackup2_error_t mobilebackup2_client_free(mobilebackup2_client_t client) + + mobilebackup2_error_t mobilebackup2_send_message(mobilebackup2_client_t client, char *message, plist.plist_t options) + mobilebackup2_error_t mobilebackup2_receive_message(mobilebackup2_client_t client, plist.plist_t *msg_plist, char **dlmessage) + mobilebackup2_error_t mobilebackup2_send_raw(mobilebackup2_client_t client, char *data, uint32_t length, uint32_t *bytes) + mobilebackup2_error_t mobilebackup2_receive_raw(mobilebackup2_client_t client, char *data, uint32_t length, uint32_t *bytes) + mobilebackup2_error_t mobilebackup2_version_exchange(mobilebackup2_client_t client, double local_versions[], char count, double *remote_version) + mobilebackup2_error_t mobilebackup2_send_request(mobilebackup2_client_t client, char *request, char *target_identifier, char *source_identifier, plist.plist_t options) + mobilebackup2_error_t mobilebackup2_send_status_response(mobilebackup2_client_t client, int status_code, char *status1, plist.plist_t status2) + +cdef class MobileBackup2Error(BaseError): + def __init__(self, *args, **kwargs): + self._lookup_table = { + MOBILEBACKUP2_E_SUCCESS: "Success", + MOBILEBACKUP2_E_INVALID_ARG: "Invalid argument", + MOBILEBACKUP2_E_PLIST_ERROR: "Property list error", + MOBILEBACKUP2_E_MUX_ERROR: "MUX error", + MOBILEBACKUP2_E_SSL_ERROR: "SSL error", + MOBILEBACKUP2_E_RECEIVE_TIMEOUT: "Receive timeout", + MOBILEBACKUP2_E_BAD_VERSION: "Bad version", + MOBILEBACKUP2_E_REPLY_NOT_OK: "Reply not OK", + MOBILEBACKUP2_E_NO_COMMON_VERSION: "No common version", + MOBILEBACKUP2_E_UNKNOWN_ERROR: "Unknown error" + } + BaseError.__init__(self, *args, **kwargs) + +cdef class MobileBackup2Client(PropertyListService): + __service_name__ = "com.apple.mobilebackup2" + cdef mobilebackup2_client_t _c_client + + def __cinit__(self, iDevice device not None, LockdownServiceDescriptor descriptor, *args, **kwargs): + self.handle_error(mobilebackup2_client_new(device._c_dev, descriptor._c_service_descriptor, &self._c_client)) + + def __dealloc__(self): + cdef mobilebackup2_error_t err + if self._c_client is not NULL: + err = mobilebackup2_client_free(self._c_client) + self.handle_error(err) + + cdef inline BaseError _error(self, int16_t ret): + return MobileBackup2Error(ret) + + cpdef send_message(self, bytes message, plist.Node options): + self.handle_error(mobilebackup2_send_message(self._c_client, message, options._c_node)) + + cpdef tuple receive_message(self): + cdef: + char* dlmessage = NULL + plist.plist_t c_node = NULL + mobilebackup2_error_t err + err = mobilebackup2_receive_message(self._c_client, &c_node, &dlmessage) + try: + self.handle_error(err) + return (plist.plist_t_to_node(c_node), <bytes>dlmessage) + except BaseError, e: + if c_node != NULL: + plist.plist_free(c_node) + if dlmessage != NULL: + free(dlmessage) + raise + + cpdef int send_raw(self, bytes data, int length): + cdef: + uint32_t bytes_recvd = 0 + mobilebackup2_error_t err + err = mobilebackup2_send_raw(self._c_client, data, length, &bytes_recvd) + try: + self.handle_error(err) + return <bint>bytes_recvd + except BaseError, e: + raise + + cpdef int receive_raw(self, bytearray data, int length): + cdef: + uint32_t bytes_recvd = 0 + mobilebackup2_error_t err + err = mobilebackup2_receive_raw(self._c_client, data, length, &bytes_recvd) + + # Throwing an exception when we test if theres more data to read is excessive + if err == -1 and bytes_recvd == 0: + return 0 + + try: + self.handle_error(err) + return <bint>bytes_recvd + except BaseError, e: + raise + + cpdef float version_exchange(self, double[::1] local_versions): + cdef: + double[::1] temp = None + double remote_version = 0.0 + mobilebackup2_error_t err + err = mobilebackup2_version_exchange(self._c_client, &local_versions[0], len(local_versions), &remote_version) + try: + self.handle_error(err) + return <float>remote_version + except BaseError, e: + raise + + cpdef send_request(self, bytes request, bytes target_identifier, bytes source_identifier, plist.Node options): + self.handle_error(mobilebackup2_send_request(self._c_client, request, target_identifier, source_identifier, options._c_node)) + + cpdef send_status_response(self, int status_code, bytes status1, plist.Node status2): + self.handle_error(mobilebackup2_send_status_response(self._c_client, status_code, status1, status2._c_node)) diff --git a/cython/mobilesync.pxi b/cython/mobilesync.pxi new file mode 100644 index 0000000..23f0005 --- /dev/null +++ b/cython/mobilesync.pxi @@ -0,0 +1,164 @@ +cdef extern from "libimobiledevice/mobilesync.h": + cdef struct mobilesync_client_private: + pass + ctypedef mobilesync_client_private *mobilesync_client_t + ctypedef enum mobilesync_error_t: + MOBILESYNC_E_SUCCESS = 0 + MOBILESYNC_E_INVALID_ARG = -1 + MOBILESYNC_E_PLIST_ERROR = -2 + MOBILESYNC_E_MUX_ERROR = -3 + MOBILESYNC_E_SSL_ERROR = -4 + MOBILESYNC_E_RECEIVE_TIMEOUT = -5 + MOBILESYNC_E_BAD_VERSION = -6 + MOBILESYNC_E_SYNC_REFUSED = -7 + MOBILESYNC_E_CANCELLED = -8 + MOBILESYNC_E_WRONG_DIRECTION = -9 + MOBILESYNC_E_NOT_READY = -10 + MOBILESYNC_E_UNKNOWN_ERROR = -256 + + ctypedef enum mobilesync_sync_type_t: + MOBILESYNC_SYNC_TYPE_FAST + MOBILESYNC_SYNC_TYPE_SLOW + MOBILESYNC_SYNC_TYPE_RESET + + ctypedef struct mobilesync_anchors: + char *device_anchor + char *host_anchor + ctypedef mobilesync_anchors *mobilesync_anchors_t + + mobilesync_error_t mobilesync_client_new(idevice_t device, lockdownd_service_descriptor_t service, mobilesync_client_t * client) + mobilesync_error_t mobilesync_client_free(mobilesync_client_t client) + mobilesync_error_t mobilesync_receive(mobilesync_client_t client, plist.plist_t *plist) + mobilesync_error_t mobilesync_send(mobilesync_client_t client, plist.plist_t plist) + + mobilesync_error_t mobilesync_start(mobilesync_client_t client, char *data_class, mobilesync_anchors_t anchors, uint64_t computer_data_class_version, mobilesync_sync_type_t *sync_type, uint64_t *device_data_class_version, char** error_description) + mobilesync_error_t mobilesync_cancel(mobilesync_client_t client, char* reason) + mobilesync_error_t mobilesync_finish(mobilesync_client_t client) + + mobilesync_error_t mobilesync_get_all_records_from_device(mobilesync_client_t client) + mobilesync_error_t mobilesync_get_changes_from_device(mobilesync_client_t client) + mobilesync_error_t mobilesync_receive_changes(mobilesync_client_t client, plist.plist_t *entities, uint8_t *is_last_record, plist.plist_t *actions) + mobilesync_error_t mobilesync_acknowledge_changes_from_device(mobilesync_client_t client) + + mobilesync_error_t mobilesync_ready_to_send_changes_from_computer(mobilesync_client_t client) + mobilesync_error_t mobilesync_send_changes(mobilesync_client_t client, plist.plist_t changes, uint8_t is_last_record, plist.plist_t actions) + mobilesync_error_t mobilesync_remap_identifiers(mobilesync_client_t client, plist.plist_t *mapping) + + mobilesync_anchors_t mobilesync_anchors_new(char *device_anchor, char *computer_anchor) + void mobilesync_anchors_free(mobilesync_anchors_t anchors) + + plist.plist_t mobilesync_actions_new() + void mobilesync_actions_add(plist.plist_t actions, ...) + void mobilesync_actions_free(plist.plist_t actions) + +SYNC_TYPE_FAST = MOBILESYNC_SYNC_TYPE_FAST +SYNC_TYPE_SLOW = MOBILESYNC_SYNC_TYPE_SLOW +SYNC_TYPE_RESET = MOBILESYNC_SYNC_TYPE_RESET + +cdef class MobileSyncError(BaseError): + def __init__(self, *args, **kwargs): + self._lookup_table = { + MOBILESYNC_E_SUCCESS: "Success", + MOBILESYNC_E_INVALID_ARG: "Invalid argument", + MOBILESYNC_E_PLIST_ERROR: "Property list error", + MOBILESYNC_E_MUX_ERROR: "MUX error", + MOBILESYNC_E_SSL_ERROR: "SSL error", + MOBILESYNC_E_RECEIVE_TIMEOUT: "Receive timeout", + MOBILESYNC_E_BAD_VERSION: "Bad version", + MOBILESYNC_E_SYNC_REFUSED: "Sync refused", + MOBILESYNC_E_CANCELLED: "Sync cancelled", + MOBILESYNC_E_WRONG_DIRECTION: "Wrong sync direction", + MOBILESYNC_E_NOT_READY: "Not ready to receive changes", + MOBILESYNC_E_UNKNOWN_ERROR: "Unknown error" + } + BaseError.__init__(self, *args, **kwargs) + +cdef class MobileSyncClient(DeviceLinkService): + __service_name__ = "com.apple.mobilesync" + cdef mobilesync_client_t _c_client + + def __cinit__(self, iDevice device not None, LockdownServiceDescriptor descriptor, *args, **kwargs): + self.handle_error(mobilesync_client_new(device._c_dev, descriptor._c_service_descriptor, &(self._c_client))) + + def __dealloc__(self): + cdef mobilesync_error_t err + if self._c_client is not NULL: + err = mobilesync_client_free(self._c_client) + self.handle_error(err) + + cpdef tuple start(self, bytes data_class, bytes device_anchor, bytes host_anchor): + cdef: + mobilesync_anchors_t anchors = NULL + mobilesync_sync_type_t sync_type + uint64_t computer_data_class_version = 1 + uint64_t device_data_class_version + char* error_description = NULL + + if device_anchor is None: + anchors = mobilesync_anchors_new(NULL, host_anchor) + else: + anchors = mobilesync_anchors_new(device_anchor, host_anchor) + + try: + self.handle_error(mobilesync_start(self._c_client, data_class, anchors, computer_data_class_version, &sync_type, &device_data_class_version, &error_description)) + return (sync_type, <bint>computer_data_class_version, <bint>device_data_class_version, <bytes>error_description) + except Exception, e: + raise + finally: + mobilesync_anchors_free(anchors) + + cpdef finish(self): + self.handle_error(mobilesync_finish(self._c_client)) + + cpdef cancel(self, bytes reason): + self.handle_error(mobilesync_cancel(self._c_client, reason)) + + cpdef get_all_records_from_device(self): + self.handle_error(mobilesync_get_all_records_from_device(self._c_client)) + + cpdef get_changes_from_device(self): + self.handle_error(mobilesync_get_changes_from_device(self._c_client)) + + cpdef tuple receive_changes(self): + cdef: + plist.plist_t entities = NULL + uint8_t is_last_record = 0 + plist.plist_t actions = NULL + try: + self.handle_error(mobilesync_receive_changes(self._c_client, &entities, &is_last_record, &actions)) + return (plist.plist_t_to_node(entities), <bint>is_last_record, plist.plist_t_to_node(actions)) + except Exception, e: + if entities != NULL: + plist.plist_free(entities) + if actions != NULL: + plist.plist_free(actions) + raise + + cpdef acknowledge_changes_from_device(self): + self.handle_error(mobilesync_acknowledge_changes_from_device(self._c_client)) + + cpdef ready_to_send_changes_from_computer(self): + self.handle_error(mobilesync_ready_to_send_changes_from_computer(self._c_client)) + + cpdef send_changes(self, plist.Node changes, bint is_last_record, plist.Node actions): + self.handle_error(mobilesync_send_changes(self._c_client, changes._c_node, is_last_record, actions._c_node)) + + cpdef remap_identifiers(self): + cdef plist.plist_t remapping = NULL + + try: + self.handle_error(mobilesync_remap_identifiers(self._c_client, &remapping)) + return plist.plist_t_to_node(remapping) + except Exception, e: + if remapping != NULL: + plist.plist_free(remapping) + raise + + cdef int16_t _send(self, plist.plist_t node): + return mobilesync_send(self._c_client, node) + + cdef int16_t _receive(self, plist.plist_t* node): + return mobilesync_receive(self._c_client, node) + + cdef inline BaseError _error(self, int16_t ret): + return MobileSyncError(ret) diff --git a/cython/notification_proxy.pxi b/cython/notification_proxy.pxi new file mode 100644 index 0000000..261200e --- /dev/null +++ b/cython/notification_proxy.pxi @@ -0,0 +1,110 @@ +cdef extern from "libimobiledevice/notification_proxy.h": + cdef struct np_client_private: + pass + ctypedef np_client_private *np_client_t + ctypedef enum np_error_t: + NP_E_SUCCESS = 0 + NP_E_INVALID_ARG = -1 + NP_E_PLIST_ERROR = -2 + NP_E_CONN_FAILED = -3 + NP_E_UNKNOWN_ERROR = -256 + ctypedef void (*np_notify_cb_t) (const_char_ptr notification, void *userdata) + np_error_t np_client_new(idevice_t device, lockdownd_service_descriptor_t descriptor, np_client_t *client) + np_error_t np_client_free(np_client_t client) + np_error_t np_post_notification(np_client_t client, char *notification) + np_error_t np_observe_notification(np_client_t client, char *notification) + np_error_t np_observe_notifications(np_client_t client, char **notification_spec) + np_error_t np_set_notify_callback(np_client_t client, np_notify_cb_t notify_cb, void *userdata) + + cdef char* C_NP_SYNC_WILL_START "NP_SYNC_WILL_START" + cdef char* C_NP_SYNC_DID_START "NP_SYNC_DID_START" + cdef char* C_NP_SYNC_DID_FINISH "NP_SYNC_DID_FINISH" + cdef char* C_NP_SYNC_LOCK_REQUEST "NP_SYNC_LOCK_REQUEST" + + cdef char* C_NP_SYNC_CANCEL_REQUEST "NP_SYNC_CANCEL_REQUEST" + cdef char* C_NP_SYNC_SUSPEND_REQUEST "NP_SYNC_SUSPEND_REQUEST" + cdef char* C_NP_SYNC_RESUME_REQUEST "NP_SYNC_RESUME_REQUEST" + cdef char* C_NP_PHONE_NUMBER_CHANGED "NP_PHONE_NUMBER_CHANGED" + cdef char* C_NP_DEVICE_NAME_CHANGED "NP_DEVICE_NAME_CHANGED" + cdef char* C_NP_TIMEZONE_CHANGED "NP_TIMEZONE_CHANGED" + cdef char* C_NP_TRUSTED_HOST_ATTACHED "NP_TRUSTED_HOST_ATTACHED" + cdef char* C_NP_HOST_DETACHED "NP_HOST_DETACHED" + cdef char* C_NP_HOST_ATTACHED "NP_HOST_ATTACHED" + cdef char* C_NP_REGISTRATION_FAILED "NP_REGISTRATION_FAILED" + cdef char* C_NP_ACTIVATION_STATE "NP_ACTIVATION_STATE" + cdef char* C_NP_BRICK_STATE "NP_BRICK_STATE" + cdef char* C_NP_DS_DOMAIN_CHANGED "NP_DS_DOMAIN_CHANGED" + cdef char* C_NP_BACKUP_DOMAIN_CHANGED "NP_BACKUP_DOMAIN_CHANGED" + cdef char* C_NP_APP_INSTALLED "NP_APP_INSTALLED" + cdef char* C_NP_APP_UNINSTALLED "NP_APP_UNINSTALLED" + cdef char* C_NP_DEV_IMAGE_MOUNTED "NP_DEV_IMAGE_MOUNTED" + cdef char* C_NP_ATTEMPTACTIVATION "NP_ATTEMPTACTIVATION" + cdef char* C_NP_ITDBPREP_DID_END "NP_ITDBPREP_DID_END" + cdef char* C_NP_LANGUAGE_CHANGED "NP_LANGUAGE_CHANGED" + cdef char* C_NP_ADDRESS_BOOK_PREF_CHANGED "NP_ADDRESS_BOOK_PREF_CHANGED" + +NP_SYNC_WILL_START = C_NP_SYNC_WILL_START +NP_SYNC_DID_START = C_NP_SYNC_DID_START +NP_SYNC_DID_FINISH = C_NP_SYNC_DID_FINISH +NP_SYNC_LOCK_REQUEST = C_NP_SYNC_LOCK_REQUEST + +NP_SYNC_CANCEL_REQUEST = C_NP_SYNC_CANCEL_REQUEST +NP_SYNC_SUSPEND_REQUEST = C_NP_SYNC_SUSPEND_REQUEST +NP_SYNC_RESUME_REQUEST = C_NP_SYNC_RESUME_REQUEST +NP_PHONE_NUMBER_CHANGED = C_NP_PHONE_NUMBER_CHANGED +NP_DEVICE_NAME_CHANGED = C_NP_DEVICE_NAME_CHANGED +NP_TIMEZONE_CHANGED = C_NP_TIMEZONE_CHANGED +NP_TRUSTED_HOST_ATTACHED = C_NP_TRUSTED_HOST_ATTACHED +NP_HOST_DETACHED = C_NP_HOST_DETACHED +NP_HOST_ATTACHED = C_NP_HOST_ATTACHED +NP_REGISTRATION_FAILED = C_NP_REGISTRATION_FAILED +NP_ACTIVATION_STATE = C_NP_ACTIVATION_STATE +NP_BRICK_STATE = C_NP_BRICK_STATE +NP_DS_DOMAIN_CHANGED = C_NP_DS_DOMAIN_CHANGED +NP_BACKUP_DOMAIN_CHANGED = C_NP_BACKUP_DOMAIN_CHANGED +NP_APP_INSTALLED = C_NP_APP_INSTALLED +NP_APP_UNINSTALLED = C_NP_APP_UNINSTALLED +NP_DEV_IMAGE_MOUNTED = C_NP_DEV_IMAGE_MOUNTED +NP_ATTEMPTACTIVATION = C_NP_ATTEMPTACTIVATION +NP_ITDBPREP_DID_END = C_NP_ITDBPREP_DID_END +NP_LANGUAGE_CHANGED = C_NP_LANGUAGE_CHANGED +NP_ADDRESS_BOOK_PREF_CHANGED = C_NP_ADDRESS_BOOK_PREF_CHANGED + +cdef void np_notify_cb(const_char_ptr notification, void *py_callback) noexcept: + (<object>py_callback)(notification) + +cdef class NotificationProxyError(BaseError): + def __init__(self, *args, **kwargs): + self._lookup_table = { + NP_E_SUCCESS: "Success", + NP_E_INVALID_ARG: "Invalid argument", + NP_E_PLIST_ERROR: "Property list error", + NP_E_CONN_FAILED: "Connection failed", + NP_E_UNKNOWN_ERROR: "Unknown error" + } + BaseError.__init__(self, *args, **kwargs) + +cdef class NotificationProxyClient(PropertyListService): + __service_name__ = "com.apple.mobile.notification_proxy" + cdef np_client_t _c_client + + def __cinit__(self, iDevice device not None, LockdownServiceDescriptor descriptor, *args, **kwargs): + self.handle_error(np_client_new(device._c_dev, descriptor._c_service_descriptor, &self._c_client)) + + def __dealloc__(self): + cdef np_error_t err + if self._c_client is not NULL: + err = np_client_free(self._c_client) + self.handle_error(err) + + cdef inline BaseError _error(self, int16_t ret): + return NotificationProxyError(ret) + + cpdef set_notify_callback(self, object callback): + self.handle_error(np_set_notify_callback(self._c_client, np_notify_cb, <void*>callback)) + + cpdef observe_notification(self, bytes notification): + self.handle_error(np_observe_notification(self._c_client, notification)) + + cpdef post_notification(self, bytes notification): + self.handle_error(np_post_notification(self._c_client, notification)) diff --git a/cython/restore.pxi b/cython/restore.pxi new file mode 100644 index 0000000..9d03935 --- /dev/null +++ b/cython/restore.pxi @@ -0,0 +1,131 @@ +cdef extern from "libimobiledevice/restore.h": + cdef struct restored_client_private: + pass + ctypedef restored_client_private *restored_client_t + + ctypedef enum restored_error_t: + RESTORE_E_SUCCESS = 0 + RESTORE_E_INVALID_ARG = -1 + RESTORE_E_PLIST_ERROR = -2 + RESTORE_E_MUX_ERROR = -3 + RESTORE_E_NOT_ENOUGH_DATA = -4 + RESTORE_E_RECEIVE_TIMEOUT = -5 + RESTORE_E_UNKNOWN_ERROR = -256 + + restored_error_t restored_client_new(idevice_t device, restored_client_t *client, char *label) + restored_error_t restored_client_free(restored_client_t client) + + restored_error_t restored_query_type(restored_client_t client, char **tp, uint64_t *version) + restored_error_t restored_query_value(restored_client_t client, char *key, plist.plist_t *value) + restored_error_t restored_get_value(restored_client_t client, char *key, plist.plist_t *value) + restored_error_t restored_send(restored_client_t client, plist.plist_t plist) + restored_error_t restored_receive(restored_client_t client, plist.plist_t *plist) + restored_error_t restored_goodbye(restored_client_t client) + + restored_error_t restored_start_restore(restored_client_t client, plist.plist_t options, uint64_t version) + restored_error_t restored_reboot(restored_client_t client) + + void restored_client_set_label(restored_client_t client, char *label) + +cdef class RestoreError(BaseError): + def __init__(self, *args, **kwargs): + self._lookup_table = { + RESTORE_E_SUCCESS: "Success", + RESTORE_E_INVALID_ARG: "Invalid argument", + RESTORE_E_PLIST_ERROR: "Property list error", + RESTORE_E_MUX_ERROR: "MUX Error", + RESTORE_E_NOT_ENOUGH_DATA: "Not enough data", + RESTORE_E_RECEIVE_TIMEOUT: "Receive timeout", + RESTORE_E_UNKNOWN_ERROR: "Unknown error" + } + BaseError.__init__(self, *args, **kwargs) + +cdef class RestoreClient(PropertyListService): + cdef restored_client_t _c_client + + def __cinit__(self, iDevice device not None, bytes label=b'', *args, **kwargs): + cdef: + restored_error_t err + char* c_label = NULL + if label: + c_label = label + err = restored_client_new(device._c_dev, &self._c_client, c_label) + self.handle_error(err) + + self.device = device + + def __dealloc__(self): + cdef restored_error_t err + if self._c_client is not NULL: + err = restored_client_free(self._c_client) + self.handle_error(err) + + cdef inline BaseError _error(self, int16_t ret): + return RestoreError(ret) + + cdef inline int16_t _send(self, plist.plist_t node): + return restored_send(self._c_client, node) + + cdef inline int16_t _receive(self, plist.plist_t* node): + return restored_receive(self._c_client, node) + + cpdef tuple query_type(self): + cdef: + restored_error_t err + char* c_type = NULL + uint64_t c_version = 0 + tuple result + err = restored_query_type(self._c_client, &c_type, &c_version) + try: + self.handle_error(err) + result = (c_type, c_version) + return result + except BaseError, e: + raise + finally: + if c_type != NULL: + free(c_type) + + cpdef plist.Node query_value(self, bytes key=None): + cdef: + restored_error_t err + plist.plist_t c_node = NULL + char* c_key = NULL + if key is not None: + c_key = key + err = restored_query_value(self._c_client, c_key, &c_node) + try: + self.handle_error(err) + return plist.plist_t_to_node(c_node) + except BaseError, e: + if c_node != NULL: + plist.plist_free(c_node) + raise + + cpdef plist.Node get_value(self, bytes key=None): + cdef: + restored_error_t err + plist.plist_t c_node = NULL + char* c_key = NULL + if key is not None: + c_key = key + err = restored_get_value(self._c_client, c_key, &c_node) + try: + self.handle_error(err) + return plist.plist_t_to_node(c_node) + except BaseError, e: + if c_node != NULL: + plist.plist_free(c_node) + raise + + cpdef goodbye(self): + self.handle_error(restored_goodbye(self._c_client)) + + cpdef start_restore(self, plist.Node options, uint64_t version): + self.handle_error(restored_start_restore(self._c_client, options._c_node, version)) + + cpdef reboot(self): + self.handle_error(restored_reboot(self._c_client)) + + cpdef set_label(self, bytes label): + restored_client_set_label(self._c_client, label) diff --git a/cython/sbservices.pxi b/cython/sbservices.pxi new file mode 100644 index 0000000..8ff2595 --- /dev/null +++ b/cython/sbservices.pxi @@ -0,0 +1,80 @@ +cdef extern from "libimobiledevice/sbservices.h": + cdef struct sbservices_client_private: + pass + ctypedef sbservices_client_private *sbservices_client_t + ctypedef enum sbservices_error_t: + SBSERVICES_E_SUCCESS = 0 + SBSERVICES_E_INVALID_ARG = -1 + SBSERVICES_E_PLIST_ERROR = -2 + SBSERVICES_E_CONN_FAILED = -3 + SBSERVICES_E_UNKNOWN_ERROR = -256 + sbservices_error_t sbservices_client_new(idevice_t device, lockdownd_service_descriptor_t descriptor, sbservices_client_t *client) + sbservices_error_t sbservices_client_free(sbservices_client_t client) + sbservices_error_t sbservices_get_icon_state(sbservices_client_t client, plist.plist_t *state, char *format_version) + sbservices_error_t sbservices_set_icon_state(sbservices_client_t client, plist.plist_t newstate) + sbservices_error_t sbservices_get_icon_pngdata(sbservices_client_t client, char *bundleId, char **pngdata, uint64_t *pngsize) + +cdef class SpringboardServicesError(BaseError): + def __init__(self, *args, **kwargs): + self._lookup_table = { + SBSERVICES_E_SUCCESS: "Success", + SBSERVICES_E_INVALID_ARG: "Invalid argument", + SBSERVICES_E_PLIST_ERROR: "Property list error", + SBSERVICES_E_CONN_FAILED: "Connection failed", + SBSERVICES_E_UNKNOWN_ERROR: "Unknown error" + } + BaseError.__init__(self, *args, **kwargs) + +cdef class SpringboardServicesClient(PropertyListService): + __service_name__ = "com.apple.springboardservices" + cdef sbservices_client_t _c_client + cdef char* format_version + + def __cinit__(self, iDevice device not None, LockdownServiceDescriptor descriptor, *args, **kwargs): + self.handle_error(sbservices_client_new(device._c_dev, descriptor._c_service_descriptor, &self._c_client)) + self.format_version = "2" + + def __dealloc__(self): + if self._c_client is not NULL: + err = sbservices_client_free(self._c_client) + self.handle_error(err) + + cdef inline BaseError _error(self, int16_t ret): + return SpringboardServicesError(ret) + + property format_version: + def __get__(self): + return <bytes>self.format_version + def __set__(self, char* newversion): + self.format_version = newversion + + property icon_state: + def __get__(self): + cdef: + plist.plist_t c_node = NULL + sbservices_error_t err + err = sbservices_get_icon_state(self._c_client, &c_node, self.format_version) + try: + self.handle_error(err) + + return plist.plist_t_to_node(c_node) + except BaseError, e: + if c_node != NULL: + plist.plist_free(c_node) + raise + def __set__(self, plist.Node newstate not None): + self.handle_error(sbservices_set_icon_state(self._c_client, newstate._c_node)) + + cpdef bytes get_pngdata(self, bytes bundleId): + cdef: + char* pngdata = NULL + uint64_t pngsize + sbservices_error_t err + err = sbservices_get_icon_pngdata(self._c_client, bundleId, &pngdata, &pngsize) + try: + self.handle_error(err) + + return pngdata[:pngsize] + except BaseError, e: + free(pngdata) + raise diff --git a/cython/screenshotr.pxi b/cython/screenshotr.pxi new file mode 100644 index 0000000..a1e82e2 --- /dev/null +++ b/cython/screenshotr.pxi @@ -0,0 +1,66 @@ +cdef extern from "libimobiledevice/screenshotr.h": + cdef struct screenshotr_client_private: + pass + ctypedef screenshotr_client_private *screenshotr_client_t + + ctypedef enum screenshotr_error_t: + SCREENSHOTR_E_SUCCESS = 0 + SCREENSHOTR_E_INVALID_ARG = -1 + SCREENSHOTR_E_PLIST_ERROR = -2 + SCREENSHOTR_E_MUX_ERROR = -3 + SCREENSHOTR_E_SSL_ERROR = -4 + SCREENSHOTR_E_RECEIVE_TIMEOUT = 5 + SCREENSHOTR_E_BAD_VERSION = -6 + SCREENSHOTR_E_UNKNOWN_ERROR = -256 + + screenshotr_error_t screenshotr_client_new(idevice_t device, lockdownd_service_descriptor_t descriptor, screenshotr_client_t * client) + screenshotr_error_t screenshotr_client_free(screenshotr_client_t client) + screenshotr_error_t screenshotr_take_screenshot(screenshotr_client_t client, char **imgdata, uint64_t *imgsize) + +cdef class ScreenshotrError(BaseError): + def __init__(self, *args, **kwargs): + self._lookup_table = { + SCREENSHOTR_E_SUCCESS: "Success", + SCREENSHOTR_E_INVALID_ARG: "Invalid argument", + SCREENSHOTR_E_PLIST_ERROR: "Property list error", + SCREENSHOTR_E_MUX_ERROR: "MUX error", + SCREENSHOTR_E_SSL_ERROR: "SSL error", + SCREENSHOTR_E_RECEIVE_TIMEOUT: "Receive timeout", + SCREENSHOTR_E_BAD_VERSION: "Bad version", + SCREENSHOTR_E_UNKNOWN_ERROR: "Unknown error" + } + BaseError.__init__(self, *args, **kwargs) + +cdef class ScreenshotrClient(DeviceLinkService): + __service_name__ = "com.apple.mobile.screenshotr" + cdef screenshotr_client_t _c_client + + def __cinit__(self, iDevice device not None, LockdownServiceDescriptor descriptor, *args, **kwargs): + self.handle_error(screenshotr_client_new(device._c_dev, descriptor._c_service_descriptor, &self._c_client)) + + def __dealloc__(self): + cdef screenshotr_error_t err + if self._c_client is not NULL: + err = screenshotr_client_free(self._c_client) + self.handle_error(err) + + cpdef bytes take_screenshot(self): + cdef: + char* c_data = NULL + uint64_t data_size + bytes result + screenshotr_error_t err + + err = screenshotr_take_screenshot(self._c_client, &c_data, &data_size) + try: + self.handle_error(err) + + result = c_data[:data_size] + return result + except Exception, e: + if c_data != NULL: + free(c_data) + raise + + cdef inline BaseError _error(self, int16_t ret): + return ScreenshotrError(ret) diff --git a/cython/webinspector.pxi b/cython/webinspector.pxi new file mode 100644 index 0000000..f77547d --- /dev/null +++ b/cython/webinspector.pxi @@ -0,0 +1,60 @@ +cdef extern from "libimobiledevice/webinspector.h": + cdef struct webinspector_client_private: + pass + ctypedef webinspector_client_private *webinspector_client_t + + ctypedef enum webinspector_error_t: + WEBINSPECTOR_E_SUCCESS = 0 + WEBINSPECTOR_E_INVALID_ARG = -1 + WEBINSPECTOR_E_PLIST_ERROR = -2 + WEBINSPECTOR_E_MUX_ERROR = -3 + WEBINSPECTOR_E_SSL_ERROR = -4 + WEBINSPECTOR_E_RECEIVE_TIMEOUT = -5, + WEBINSPECTOR_E_NOT_ENOUGH_DATA = -6, + WEBINSPECTOR_E_UNKNOWN_ERROR = -256 + + webinspector_error_t webinspector_client_new(idevice_t device, lockdownd_service_descriptor_t descriptor, webinspector_client_t * client) + webinspector_error_t webinspector_client_free(webinspector_client_t client) + + webinspector_error_t webinspector_send(webinspector_client_t client, plist.plist_t plist) + webinspector_error_t webinspector_receive(webinspector_client_t client, plist.plist_t * plist) + webinspector_error_t webinspector_receive_with_timeout(webinspector_client_t client, plist.plist_t * plist, uint32_t timeout_ms) + +cdef class WebinspectorError(BaseError): + def __init__(self, *args, **kwargs): + self._lookup_table = { + WEBINSPECTOR_E_SUCCESS: "Success", + WEBINSPECTOR_E_INVALID_ARG: "Invalid argument", + WEBINSPECTOR_E_PLIST_ERROR: "Property list error", + WEBINSPECTOR_E_MUX_ERROR: "MUX error", + WEBINSPECTOR_E_SSL_ERROR: "SSL Error", + WEBINSPECTOR_E_NOT_ENOUGH_DATA: 'Not enough data', + WEBINSPECTOR_E_RECEIVE_TIMEOUT: 'Connection timeout', + WEBINSPECTOR_E_UNKNOWN_ERROR: "Unknown error" + } + BaseError.__init__(self, *args, **kwargs) + +cdef class WebinspectorClient(PropertyListService): + __service_name__ = "com.apple.webinspector" + cdef webinspector_client_t _c_client + + def __cinit__(self, iDevice device not None, LockdownServiceDescriptor descriptor, *args, **kwargs): + self.handle_error(webinspector_client_new(device._c_dev, descriptor._c_service_descriptor, &self._c_client)) + + def __dealloc__(self): + cdef webinspector_error_t err + if self._c_client is not NULL: + err = webinspector_client_free(self._c_client) + self.handle_error(err) + + cdef inline int16_t _send(self, plist.plist_t node): + return webinspector_send(self._c_client, node) + + cdef inline int16_t _receive(self, plist.plist_t* node): + return webinspector_receive(self._c_client, node) + + cdef inline int16_t _receive_with_timeout(self, plist.plist_t* node, int timeout_ms): + return webinspector_receive_with_timeout(self._c_client, node, timeout_ms) + + cdef inline BaseError _error(self, int16_t ret): + return WebinspectorError(ret) |