idevice 1.1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/NOTICE +202 -0
- data/README.md +74 -0
- data/Rakefile +37 -0
- data/examples/idevimgmount +58 -0
- data/examples/idumplockdownvalues +64 -0
- data/examples/ifetchcrashreports +54 -0
- data/examples/ilistapps +38 -0
- data/examples/ilistudids +26 -0
- data/examples/ilog +35 -0
- data/examples/installipa +51 -0
- data/examples/iremoveapp +42 -0
- data/examples/irestart +26 -0
- data/examples/iscreenshotr +39 -0
- data/idevice.gemspec +33 -0
- data/lib/idevice.rb +69 -0
- data/lib/idevice/afc.rb +518 -0
- data/lib/idevice/c.rb +129 -0
- data/lib/idevice/diagnostics_relay.rb +185 -0
- data/lib/idevice/file_relay.rb +83 -0
- data/lib/idevice/heartbeat.rb +99 -0
- data/lib/idevice/house_arrest.rb +138 -0
- data/lib/idevice/idevice.rb +208 -0
- data/lib/idevice/image_mounter.rb +117 -0
- data/lib/idevice/installation_proxy.rb +193 -0
- data/lib/idevice/lockdown.rb +350 -0
- data/lib/idevice/misagent.rb +112 -0
- data/lib/idevice/mobilebackup.rb +183 -0
- data/lib/idevice/mobilebackup2.rb +174 -0
- data/lib/idevice/mobilesync.rb +306 -0
- data/lib/idevice/notification_proxy.rb +168 -0
- data/lib/idevice/plist.rb +366 -0
- data/lib/idevice/restore.rb +176 -0
- data/lib/idevice/sbservices.rb +152 -0
- data/lib/idevice/screenshotr.rb +88 -0
- data/lib/idevice/version.rb +3 -0
- data/lib/idevice/webinspector.rb +96 -0
- data/spec/afc_devicespec.rb +409 -0
- data/spec/diagnostics_relay_devicespec.rb +125 -0
- data/spec/file_relay_devicespec.rb +45 -0
- data/spec/heartbeat_devicespec.rb +39 -0
- data/spec/idevice_devicespec.rb +93 -0
- data/spec/idevice_spec.rb +29 -0
- data/spec/image_mounter_devicespec.rb +65 -0
- data/spec/installation_proxy_devicespec.rb +54 -0
- data/spec/lockdown_devicespec.rb +106 -0
- data/spec/misagent_devicespec.rb +43 -0
- data/spec/mobilebackup2_devicespec.rb +58 -0
- data/spec/mobilebackup_devicespec.rb +41 -0
- data/spec/mobilesync_devicespec.rb +62 -0
- data/spec/notification_proxy_devicespec.rb +45 -0
- data/spec/plist_spec.rb +176 -0
- data/spec/restore_devicespec.rb +72 -0
- data/spec/samples/plist.bin +0 -0
- data/spec/samples/plist.xml +10 -0
- data/spec/sbservices_devicespec.rb +64 -0
- data/spec/screenshotr_devicespec.rb +39 -0
- data/spec/spec_helper.rb +73 -0
- data/spec/webinspector_devicespec.rb +36 -0
- metadata +233 -0
@@ -0,0 +1,306 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2013 Eric Monti - Bluebox Security
|
3
|
+
#
|
4
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
5
|
+
# or more contributor license agreements. See the NOTICE file
|
6
|
+
# distributed with this work for additional information
|
7
|
+
# regarding copyright ownership. The ASF licenses this file
|
8
|
+
# to you under the Apache License, Version 2.0 (the
|
9
|
+
# "License"); you may not use this file except in compliance
|
10
|
+
# with the License. You may obtain a copy of the License at
|
11
|
+
#
|
12
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
13
|
+
#
|
14
|
+
# Unless required by applicable law or agreed to in writing,
|
15
|
+
# software distributed under the License is distributed on an
|
16
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
17
|
+
# KIND, either express or implied. See the License for the
|
18
|
+
# specific language governing permissions and limitations
|
19
|
+
# under the License.
|
20
|
+
|
21
|
+
require 'idevice/c'
|
22
|
+
require 'idevice/plist'
|
23
|
+
require 'idevice/idevice'
|
24
|
+
require 'idevice/lockdown'
|
25
|
+
require 'time'
|
26
|
+
|
27
|
+
module Idevice
|
28
|
+
class MobileSyncError < IdeviceLibError
|
29
|
+
end
|
30
|
+
|
31
|
+
# Used to synchronize data classes with a device and computer.
|
32
|
+
class MobileSyncClient < C::ManagedOpaquePointer
|
33
|
+
include LibHelpers
|
34
|
+
|
35
|
+
def self.release(ptr)
|
36
|
+
C.mobilesync_client_free(ptr) unless ptr.null?
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.attach(opts={})
|
40
|
+
_attach_helper("com.apple.mobilesync", opts) do |idevice, ldsvc, p_ms|
|
41
|
+
err = C.mobilesync_client_new(idevice, ldsvc, p_ms)
|
42
|
+
raise MobileSyncError, "MobileSync error: #{err}" if err != :SUCCESS
|
43
|
+
|
44
|
+
ms = p_ms.read_pointer
|
45
|
+
raise MobileSyncError, "mobilesync_client_new returned a NULL client" if ms.null?
|
46
|
+
return new(ms)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def receive_plist
|
51
|
+
FFI::MemoryPointer.new(:pointer) do |p_result|
|
52
|
+
err = C.mobilesync_receive(self, p_result)
|
53
|
+
raise MobileSyncError, "MobileSync error: #{err}" if err != :SUCCESS
|
54
|
+
return p_result.read_pointer.read_plist_t
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def send_plist(request)
|
59
|
+
err = C.mobilesync_send(self, Plist_t.from_ruby(request))
|
60
|
+
raise MobileSyncError, "MobileSync error: #{err}" if err != :SUCCESS
|
61
|
+
|
62
|
+
return true
|
63
|
+
end
|
64
|
+
|
65
|
+
SYNC_TYPES = [
|
66
|
+
:FAST, # Fast-sync requires that only the changes made since the last synchronization should be reported by the computer.
|
67
|
+
:SLOW, # Slow-sync requires that all data from the computer needs to be synchronized/sent.
|
68
|
+
:RESET, # Reset-sync signals that the computer should send all data again.
|
69
|
+
]
|
70
|
+
|
71
|
+
def start(data_class, anchors, data_class_version=106)
|
72
|
+
anchors = C.mobilesync_anchors_new(*anchors)
|
73
|
+
|
74
|
+
FFI::MemoryPointer.new(:int) do |p_sync_type|
|
75
|
+
FFI::MemoryPointer.new(:uint64) do |p_dev_data_class_version|
|
76
|
+
FFI::MemoryPointer.new(:pointer) do |p_error|
|
77
|
+
err = C.mobilesync_send(self, data_class, anchors, data_class_version, p_sync_type, p_dev_data_class_version, p_error)
|
78
|
+
errstr = nil
|
79
|
+
p_errstr = p_error.read_pointer
|
80
|
+
unless p_errstr.null?
|
81
|
+
errstr = p_errstr.read_string
|
82
|
+
C.free(p_errstr)
|
83
|
+
end
|
84
|
+
|
85
|
+
if err != :SUCCESS
|
86
|
+
msg = "MobileSync error: #{err}"
|
87
|
+
msg << "(#{errstr})" if errstr
|
88
|
+
raise MobileSyncError, msg
|
89
|
+
end
|
90
|
+
|
91
|
+
sync_type = sync_type.read_int
|
92
|
+
ddc_ver = p_device_data_class_version.read_uint64
|
93
|
+
|
94
|
+
return({
|
95
|
+
sync_type: (SYNC_TYPES[sync_type] || sync_type),
|
96
|
+
device_data_class_version: ddc_ver,
|
97
|
+
error: errstr,
|
98
|
+
})
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def cancel(reason)
|
105
|
+
err = C.mobilesync_cancel(self, reason)
|
106
|
+
raise MobileSyncError, "MobileSync error: #{err}" if err != :SUCCESS
|
107
|
+
|
108
|
+
return true
|
109
|
+
end
|
110
|
+
|
111
|
+
def finish
|
112
|
+
err = C.mobilesync_finish(self)
|
113
|
+
raise MobileSyncError, "MobileSync error: #{err}" if err != :SUCCESS
|
114
|
+
|
115
|
+
return true
|
116
|
+
end
|
117
|
+
|
118
|
+
def request_all_records_from_device
|
119
|
+
err = C.mobilesync_get_all_records_from_device(self)
|
120
|
+
raise MobileSyncError, "MobileSync error: #{err}" if err != :SUCCESS
|
121
|
+
|
122
|
+
return true
|
123
|
+
end
|
124
|
+
|
125
|
+
def request_changes_from_device
|
126
|
+
err = C.mobilesync_get_changes_from_device(self)
|
127
|
+
raise MobileSyncError, "MobileSync error: #{err}" if err != :SUCCESS
|
128
|
+
|
129
|
+
return true
|
130
|
+
end
|
131
|
+
|
132
|
+
def clear_all_records_on_device
|
133
|
+
err = C.mobilesync_clear_all_records_on_device(self)
|
134
|
+
raise MobileSyncError, "MobileSync error: #{err}" if err != :SUCCESS
|
135
|
+
|
136
|
+
return true
|
137
|
+
end
|
138
|
+
|
139
|
+
def receive_changes
|
140
|
+
ret = []
|
141
|
+
|
142
|
+
FFI::MemoryPointer.new(:pointer) do |p_entities|
|
143
|
+
FFI::MemoryPointer.new(:uint8) do |p_is_last_record|
|
144
|
+
FFI::MemoryPointer.new(:pointer) do |p_actions|
|
145
|
+
last_record = false
|
146
|
+
until last_record
|
147
|
+
err = C.mobilesync_receive_changes(self, p_entities, p_is_last_record, p_actions)
|
148
|
+
raise MobileSyncError, "MobileSync error: #{err}" if err != :SUCCESS
|
149
|
+
|
150
|
+
last_record = (p_is_last_record.read_uint8 != 0)
|
151
|
+
ret << {
|
152
|
+
entities: p_entities.read_pointer.read_plist_t,
|
153
|
+
actions: p_actions.read_pointer.read_plist_t,
|
154
|
+
}
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
return ret
|
161
|
+
end
|
162
|
+
|
163
|
+
def acknowledge_changes_from_device
|
164
|
+
err = C.mobilesync_acknowledge_changes_from_device(self)
|
165
|
+
raise MobileSyncError, "MobileSync error: #{err}" if err != :SUCCESS
|
166
|
+
|
167
|
+
return true
|
168
|
+
end
|
169
|
+
|
170
|
+
def signal_ready_to_send_changes_from_computer
|
171
|
+
err = C.mobilesync_ready_to_send_changes_from_computer(self)
|
172
|
+
raise MobileSyncError, "MobileSync error: #{err}" if err != :SUCCESS
|
173
|
+
|
174
|
+
return true
|
175
|
+
end
|
176
|
+
|
177
|
+
def _send_changes(entities, is_last, actions=nil)
|
178
|
+
act = actions ? Plist_t.from_ruby(actions) : nil
|
179
|
+
err = C.mobilesync_send_changes(self, Plist_t.from_ruby(entities), is_last, act)
|
180
|
+
raise MobileSyncError, "MobileSync error: #{err}" if err != :SUCCESS
|
181
|
+
end
|
182
|
+
|
183
|
+
def send_changes(changes)
|
184
|
+
raise TypeError, "changes must be an array" unless changes.is_a? Array
|
185
|
+
raise ArgumentError, "changes must not be empty" if changes.empty?
|
186
|
+
|
187
|
+
lastchange = changes.unshift
|
188
|
+
changes.each { |change| _send_changes(change[:entities], 0, change[:actions]) }
|
189
|
+
_send_changes(lastchange[:entities], 1, lastchange[:actions])
|
190
|
+
return true
|
191
|
+
end
|
192
|
+
|
193
|
+
#mobilesync_error_t mobilesync_remap_identifiers(mobilesync_client_t client, plist_t *mapping);
|
194
|
+
def remap_identifiers(mappings)
|
195
|
+
raise TypeError, "mappings must be an array" unless changes.is_a? Array
|
196
|
+
raise ArgumentError, "mappings must not be empty" if changes.empty?
|
197
|
+
|
198
|
+
FFI::MemoryPointer.new(FFI::Pointer.size * (mappings.count+1)) do |p_mapping|
|
199
|
+
p_mapping.write_array_of_pointer(mappings.map{|m| Plist_t.from_ruby(m)} + nil)
|
200
|
+
err = C.mobilesync_remap_identifiers(self, p_mapping)
|
201
|
+
raise MobileSyncError, "MobileSync error: #{err}" if err != :SUCCESS
|
202
|
+
return true
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
# Mobile Sync anchors used by the device and computer
|
208
|
+
class MobileSyncAnchors < FFI::ManagedStruct
|
209
|
+
def self.release(ptr)
|
210
|
+
C.mobilesync_anchors_free(ptr) unless ptr.null?
|
211
|
+
end
|
212
|
+
|
213
|
+
layout(
|
214
|
+
:device_anchor, :string,
|
215
|
+
:computer_anchor, :string,
|
216
|
+
)
|
217
|
+
end
|
218
|
+
|
219
|
+
module C
|
220
|
+
ffi_lib 'imobiledevice'
|
221
|
+
|
222
|
+
typedef enum(
|
223
|
+
:SUCCESS , 0,
|
224
|
+
:INVALID_ARG , -1,
|
225
|
+
:PLIST_ERROR , -2,
|
226
|
+
:MUX_ERROR , -3,
|
227
|
+
:BAD_VERSION , -4,
|
228
|
+
:SYNC_REFUSED , -5,
|
229
|
+
:CANCELLED , -6,
|
230
|
+
:WRONG_DIRECTION, -7,
|
231
|
+
:NOT_READY , -8,
|
232
|
+
:UNKNOWN_ERROR , -256,
|
233
|
+
), :mobilesync_error_t
|
234
|
+
|
235
|
+
## The sync type of the current sync session.
|
236
|
+
typedef enum(
|
237
|
+
:FAST, # Fast-sync requires that only the changes made since the last synchronization should be reported by the computer.
|
238
|
+
:SLOW, # Slow-sync requires that all data from the computer needs to be synchronized/sent.
|
239
|
+
:RESET, # Reset-sync signals that the computer should send all data again.
|
240
|
+
), :mobilesync_sync_type_t
|
241
|
+
|
242
|
+
#mobilesync_error_t mobilesync_client_new(idevice_t device, lockdownd_service_descriptor_t service, mobilesync_client_t * client);
|
243
|
+
attach_function :mobilesync_client_new, [Idevice, LockdownServiceDescriptor, :pointer], :mobilesync_error_t
|
244
|
+
|
245
|
+
#mobilesync_error_t mobilesync_client_free(mobilesync_client_t client);
|
246
|
+
attach_function :mobilesync_client_free, [MobileSyncClient], :mobilesync_error_t
|
247
|
+
|
248
|
+
#mobilesync_error_t mobilesync_receive(mobilesync_client_t client, plist_t *plist);
|
249
|
+
attach_function :mobilesync_receive, [MobileSyncClient, :pointer], :mobilesync_error_t
|
250
|
+
|
251
|
+
#mobilesync_error_t mobilesync_send(mobilesync_client_t client, plist_t plist);
|
252
|
+
attach_function :mobilesync_send, [MobileSyncClient, Plist_t], :mobilesync_error_t
|
253
|
+
|
254
|
+
#mobilesync_error_t mobilesync_start(mobilesync_client_t client, const 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);
|
255
|
+
attach_function :mobilesync_start, [MobileSyncClient, :string, MobileSyncAnchors, :uint64, :pointer, :pointer, :pointer], :mobilesync_error_t
|
256
|
+
|
257
|
+
#mobilesync_error_t mobilesync_cancel(mobilesync_client_t client, const char* reason);
|
258
|
+
attach_function :mobilesync_cancel, [MobileSyncClient, :string], :mobilesync_error_t
|
259
|
+
|
260
|
+
#mobilesync_error_t mobilesync_finish(mobilesync_client_t client);
|
261
|
+
attach_function :mobilesync_finish, [MobileSyncClient], :mobilesync_error_t
|
262
|
+
|
263
|
+
#mobilesync_error_t mobilesync_get_all_records_from_device(mobilesync_client_t client);
|
264
|
+
attach_function :mobilesync_get_all_records_from_device, [MobileSyncClient], :mobilesync_error_t
|
265
|
+
|
266
|
+
#mobilesync_error_t mobilesync_get_changes_from_device(mobilesync_client_t client);
|
267
|
+
attach_function :mobilesync_get_changes_from_device, [MobileSyncClient], :mobilesync_error_t
|
268
|
+
|
269
|
+
#mobilesync_error_t mobilesync_clear_all_records_on_device(mobilesync_client_t client);
|
270
|
+
attach_function :mobilesync_clear_all_records_on_device, [MobileSyncClient], :mobilesync_error_t
|
271
|
+
|
272
|
+
#mobilesync_error_t mobilesync_receive_changes(mobilesync_client_t client, plist_t *entities, uint8_t *is_last_record, plist_t *actions);
|
273
|
+
attach_function :mobilesync_receive_changes, [MobileSyncClient, :pointer, :pointer, :pointer], :mobilesync_error_t
|
274
|
+
|
275
|
+
#mobilesync_error_t mobilesync_acknowledge_changes_from_device(mobilesync_client_t client);
|
276
|
+
attach_function :mobilesync_acknowledge_changes_from_device, [MobileSyncClient], :mobilesync_error_t
|
277
|
+
|
278
|
+
#mobilesync_error_t mobilesync_ready_to_send_changes_from_computer(mobilesync_client_t client);
|
279
|
+
attach_function :mobilesync_ready_to_send_changes_from_computer, [MobileSyncClient], :mobilesync_error_t
|
280
|
+
|
281
|
+
#mobilesync_error_t mobilesync_send_changes(mobilesync_client_t client, plist_t entities, uint8_t is_last_record, plist_t actions);
|
282
|
+
attach_function :mobilesync_send_changes, [MobileSyncClient, Plist_t, :uint8, Plist_t], :mobilesync_error_t
|
283
|
+
|
284
|
+
#mobilesync_error_t mobilesync_remap_identifiers(mobilesync_client_t client, plist_t *mapping);
|
285
|
+
attach_function :mobilesync_remap_identifiers, [MobileSyncClient, :pointer], :mobilesync_error_t
|
286
|
+
|
287
|
+
#mobilesync_anchors_t mobilesync_anchors_new(const char *device_anchor, const char *computer_anchor);
|
288
|
+
attach_function :mobilesync_anchors_new, [:string, :string], MobileSyncAnchors
|
289
|
+
|
290
|
+
#void mobilesync_anchors_free(mobilesync_anchors_t anchors);
|
291
|
+
attach_function :mobilesync_anchors_free, [MobileSyncAnchors], :void
|
292
|
+
|
293
|
+
|
294
|
+
### actions Helpers
|
295
|
+
|
296
|
+
#plist_t mobilesync_actions_new();
|
297
|
+
attach_function :mobilesync_actions_new, [], Plist_t
|
298
|
+
|
299
|
+
#void mobilesync_actions_add(plist_t actions, ...);
|
300
|
+
attach_function :mobilesync_actions_add, [Plist_t, :varargs], Plist_t
|
301
|
+
|
302
|
+
#void mobilesync_actions_free(plist_t actions);
|
303
|
+
attach_function :mobilesync_actions_free, [Plist_t], :void
|
304
|
+
|
305
|
+
end
|
306
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2013 Eric Monti - Bluebox Security
|
3
|
+
#
|
4
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
5
|
+
# or more contributor license agreements. See the NOTICE file
|
6
|
+
# distributed with this work for additional information
|
7
|
+
# regarding copyright ownership. The ASF licenses this file
|
8
|
+
# to you under the Apache License, Version 2.0 (the
|
9
|
+
# "License"); you may not use this file except in compliance
|
10
|
+
# with the License. You may obtain a copy of the License at
|
11
|
+
#
|
12
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
13
|
+
#
|
14
|
+
# Unless required by applicable law or agreed to in writing,
|
15
|
+
# software distributed under the License is distributed on an
|
16
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
17
|
+
# KIND, either express or implied. See the License for the
|
18
|
+
# specific language governing permissions and limitations
|
19
|
+
# under the License.
|
20
|
+
|
21
|
+
require 'idevice/c'
|
22
|
+
require 'idevice/idevice'
|
23
|
+
require 'idevice/lockdown'
|
24
|
+
|
25
|
+
module Idevice
|
26
|
+
class NotificationProxyError < IdeviceLibError
|
27
|
+
end
|
28
|
+
|
29
|
+
# Aliased short name for NotificationProxyError
|
30
|
+
NPError = NotificationProxyError
|
31
|
+
|
32
|
+
# Notifications that can be received from the device
|
33
|
+
module NPRecvNotifications
|
34
|
+
SYNC_CANCEL_REQUEST = "com.apple.itunes-client.syncCancelRequest"
|
35
|
+
SYNC_SUSPEND_REQUEST = "com.apple.itunes-client.syncSuspendRequest"
|
36
|
+
SYNC_RESUME_REQUEST = "com.apple.itunes-client.syncResumeRequest"
|
37
|
+
PHONE_NUMBER_CHANGED = "com.apple.mobile.lockdown.phone_number_changed"
|
38
|
+
DEVICE_NAME_CHANGED = "com.apple.mobile.lockdown.device_name_changed"
|
39
|
+
TIMEZONE_CHANGED = "com.apple.mobile.lockdown.timezone_changed"
|
40
|
+
TRUSTED_HOST_ATTACHED = "com.apple.mobile.lockdown.trusted_host_attached"
|
41
|
+
HOST_DETACHED = "com.apple.mobile.lockdown.host_detached"
|
42
|
+
HOST_ATTACHED = "com.apple.mobile.lockdown.host_attached"
|
43
|
+
REGISTRATION_FAILED = "com.apple.mobile.lockdown.registration_failed"
|
44
|
+
ACTIVATION_STATE = "com.apple.mobile.lockdown.activation_state"
|
45
|
+
BRICK_STATE = "com.apple.mobile.lockdown.brick_state"
|
46
|
+
DISK_USAGE_CHANGED = "com.apple.mobile.lockdown.disk_usage_changed"# /**< iOS 4.0+ */
|
47
|
+
DS_DOMAIN_CHANGED = "com.apple.mobile.data_sync.domain_changed"
|
48
|
+
BACKUP_DOMAIN_CHANGED = "com.apple.mobile.backup.domain_changed"
|
49
|
+
APP_INSTALLED = "com.apple.mobile.application_installed"
|
50
|
+
APP_UNINSTALLED = "com.apple.mobile.application_uninstalled"
|
51
|
+
DEV_IMAGE_MOUNTED = "com.apple.mobile.developer_image_mounted"
|
52
|
+
ATTEMPTACTIVATION = "com.apple.springboard.attemptactivation"
|
53
|
+
ITDBPREP_DID_END = "com.apple.itdbprep.notification.didEnd"
|
54
|
+
LANGUAGE_CHANGED = "com.apple.language.changed"
|
55
|
+
ADDRESS_BOOK_PREF_CHANGED = "com.apple.AddressBook.PreferenceChanged"
|
56
|
+
end
|
57
|
+
|
58
|
+
# Notifications that can be sent to the device
|
59
|
+
module NPSendNotifications
|
60
|
+
SYNC_WILL_START = "com.apple.itunes-mobdev.syncWillStart"
|
61
|
+
SYNC_DID_START = "com.apple.itunes-mobdev.syncDidStart"
|
62
|
+
SYNC_DID_FINISH = "com.apple.itunes-mobdev.syncDidFinish"
|
63
|
+
SYNC_LOCK_REQUEST = "com.apple.itunes-mobdev.syncLockRequest"
|
64
|
+
end
|
65
|
+
|
66
|
+
# Used to receive and post device notifications
|
67
|
+
class NotificationProxyClient < C::ManagedOpaquePointer
|
68
|
+
include LibHelpers
|
69
|
+
|
70
|
+
def self.release(ptr)
|
71
|
+
C.np_client_free(ptr) unless ptr.null?
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.attach(opts={})
|
75
|
+
_attach_helper("com.apple.mobile.notification_proxy", opts) do |idevice, ldsvc, p_np|
|
76
|
+
err = C.np_client_new(idevice, ldsvc, p_np)
|
77
|
+
raise NotificationProxyError, "Notification Proxy Error: #{err}" if err != :SUCCESS
|
78
|
+
|
79
|
+
np = p_np.read_pointer
|
80
|
+
raise NPError, "np_client_new returned a NULL client" if np.null?
|
81
|
+
return new(np)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def post_notification(notification)
|
86
|
+
err = C.np_post_notification(self, notification)
|
87
|
+
raise NotificationProxyError, "Notification Proxy Error: #{err}" if err != :SUCCESS
|
88
|
+
|
89
|
+
return true
|
90
|
+
end
|
91
|
+
|
92
|
+
def observe_notification
|
93
|
+
FFI::MemoryPointer.new(:pointer) do |p_notification|
|
94
|
+
err = C.np_observe_notification(self, p_notification)
|
95
|
+
raise NotificationProxyError, "Notification Proxy Error: #{err}" if err != :SUCCESS
|
96
|
+
|
97
|
+
notification = p_notification.read_pointer
|
98
|
+
unless notification.null?
|
99
|
+
ret = notification.read_string
|
100
|
+
C.free(notification)
|
101
|
+
return ret
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def observe_notifications
|
107
|
+
FFI::MemoryPointer.new(:pointer) do |p_notifications|
|
108
|
+
err = C.np_observe_notifications(self, p_notifications)
|
109
|
+
raise NotificationProxyError, "Notification Proxy Error: #{err}" if err != :SUCCESS
|
110
|
+
|
111
|
+
return _unbound_list_to_array(p_notifications)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def set_notify_callback(&block)
|
116
|
+
err = C.np_set_notify_callback(self, _cb(&block), nil)
|
117
|
+
raise NotificationProxyError, "Notification Proxy Error: #{err}" if err != :SUCCESS
|
118
|
+
|
119
|
+
@notify_callback = block
|
120
|
+
return true
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
def _cb
|
125
|
+
lambda do |notification, junk|
|
126
|
+
yield(notification)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# Aliased short name for NotificationProxyClient
|
132
|
+
NPClient = NotificationProxyClient
|
133
|
+
|
134
|
+
module C
|
135
|
+
ffi_lib 'imobiledevice'
|
136
|
+
|
137
|
+
typedef enum(
|
138
|
+
:SUCCESS , 0,
|
139
|
+
:INVALID_ARG , -1,
|
140
|
+
:PLIST_ERROR , -2,
|
141
|
+
:CONN_FAILED , -3,
|
142
|
+
:UNKNOWN_ERROR, -256,
|
143
|
+
), :np_error_t
|
144
|
+
|
145
|
+
#np_error_t np_client_new(idevice_t device, lockdownd_service_descriptor_t service, np_client_t *client);
|
146
|
+
attach_function :np_client_new, [Idevice, LockdownServiceDescriptor, :pointer], :np_error_t
|
147
|
+
|
148
|
+
#np_error_t np_client_free(np_client_t client);
|
149
|
+
attach_function :np_client_free, [NPClient], :np_error_t
|
150
|
+
|
151
|
+
#np_error_t np_post_notification(np_client_t client, const char *notification);
|
152
|
+
attach_function :np_post_notification, [NPClient, :string], :np_error_t
|
153
|
+
|
154
|
+
#np_error_t np_observe_notification(np_client_t client, const char *notification);
|
155
|
+
attach_function :np_observe_notification, [NPClient, :string], :np_error_t
|
156
|
+
|
157
|
+
#np_error_t np_observe_notifications(np_client_t client, const char **notification_spec);
|
158
|
+
attach_function :np_observe_notifications, [NPClient, :pointer], :np_error_t
|
159
|
+
|
160
|
+
#/** Reports which notification was received. */
|
161
|
+
#typedef void (*np_notify_cb_t) (const char *notification, void *user_data);
|
162
|
+
callback :np_notify_cb_t, [:string, :pointer], :void
|
163
|
+
|
164
|
+
#np_error_t np_set_notify_callback(np_client_t client, np_notify_cb_t notify_cb, void *userdata);
|
165
|
+
attach_function :np_set_notify_callback, [NPClient, :np_notify_cb_t, :pointer], :np_error_t
|
166
|
+
|
167
|
+
end
|
168
|
+
end
|