summaryrefslogtreecommitdiffstats
path: root/src/screenshotr.c
diff options
context:
space:
mode:
authorGravatar Nikias Bassen2010-02-17 16:33:18 +0100
committerGravatar Matt Colyer2010-02-19 09:34:43 -0800
commita5d7f3815adc052a8fb5ec71bf66386c2384d7d1 (patch)
tree6e3b67b338e76805775ff1797c2d0aec4d9d0f82 /src/screenshotr.c
parentf364f1984e3d3ea2baa18ec7e939f912ddc06dbf (diff)
downloadlibimobiledevice-a5d7f3815adc052a8fb5ec71bf66386c2384d7d1.tar.gz
libimobiledevice-a5d7f3815adc052a8fb5ec71bf66386c2384d7d1.tar.bz2
New screenshotr service plus idevicescreenshot tool
[#113 state:resolved]
Diffstat (limited to 'src/screenshotr.c')
-rw-r--r--src/screenshotr.c186
1 files changed, 186 insertions, 0 deletions
diff --git a/src/screenshotr.c b/src/screenshotr.c
new file mode 100644
index 0000000..f8866d0
--- /dev/null
+++ b/src/screenshotr.c
@@ -0,0 +1,186 @@
1/*
2 * screenshotr.c
3 * com.apple.mobile.screenshotr implementation.
4 *
5 * Copyright (c) 2010 Nikias Bassen All Rights Reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#include <plist/plist.h>
23#include <string.h>
24#include <stdlib.h>
25#include <arpa/inet.h>
26
27#include "screenshotr.h"
28#include "device_link_service.h"
29#include "debug.h"
30
31#define SCREENSHOTR_VERSION_INT1 100
32#define SCREENSHOTR_VERSION_INT2 0
33
34/**
35 * Convert a device_link_service_error_t value to a screenshotr_error_t value.
36 * Used internally to get correct error codes.
37 *
38 * @param err An device_link_service_error_t error code
39 *
40 * @return A matching screenshotr_error_t error code,
41 * SCREENSHOTR_E_UNKNOWN_ERROR otherwise.
42 */
43static screenshotr_error_t screenshotr_error(device_link_service_error_t err)
44{
45 switch (err) {
46 case DEVICE_LINK_SERVICE_E_SUCCESS:
47 return SCREENSHOTR_E_SUCCESS;
48 case DEVICE_LINK_SERVICE_E_INVALID_ARG:
49 return SCREENSHOTR_E_INVALID_ARG;
50 case DEVICE_LINK_SERVICE_E_PLIST_ERROR:
51 return SCREENSHOTR_E_PLIST_ERROR;
52 case DEVICE_LINK_SERVICE_E_MUX_ERROR:
53 return SCREENSHOTR_E_MUX_ERROR;
54 case DEVICE_LINK_SERVICE_E_BAD_VERSION:
55 return SCREENSHOTR_E_BAD_VERSION;
56 default:
57 break;
58 }
59 return SCREENSHOTR_E_UNKNOWN_ERROR;
60}
61
62/**
63 * Makes a connection to the screenshotr service on the device.
64 *
65 * @param device The device to connect to.
66 * @param port Destination port (usually given by lockdownd_start_service).
67 * @param client Pointer that will be set to a newly allocated
68 * screenshotr_client_t upon successful return.
69 *
70 * @return SCREENSHOTR_E_SUCCESS on success, SCREENSHOTR_E_INVALID ARG if one
71 * or more parameters are invalid, or SCREENSHOTR_E_CONN_FAILED if the
72 * connection to the device could not be established.
73 */
74screenshotr_error_t screenshotr_client_new(idevice_t device, uint16_t port,
75 screenshotr_client_t * client)
76{
77 if (!device || port == 0 || !client || *client)
78 return SCREENSHOTR_E_INVALID_ARG;
79
80 device_link_service_client_t dlclient = NULL;
81 screenshotr_error_t ret = screenshotr_error(device_link_service_client_new(device, port, &dlclient));
82 if (ret != SCREENSHOTR_E_SUCCESS) {
83 return ret;
84 }
85
86 screenshotr_client_t client_loc = (screenshotr_client_t) malloc(sizeof(struct screenshotr_client_int));
87 client_loc->parent = dlclient;
88
89 /* perform handshake */
90 ret = screenshotr_error(device_link_service_version_exchange(dlclient, SCREENSHOTR_VERSION_INT1, SCREENSHOTR_VERSION_INT2));
91 if (ret != SCREENSHOTR_E_SUCCESS) {
92 debug_info("version exchange failed, error %d", ret);
93 screenshotr_client_free(client_loc);
94 return ret;
95 }
96
97 *client = client_loc;
98
99 return ret;
100}
101
102/**
103 * Disconnects a screenshotr client from the device.
104 *
105 * @param client The client to disconnect.
106 *
107 * @return SCREENSHOTR_E_SUCCESS on success, or SCREENSHOTR_E_INVALID_ARG
108 * if client is NULL.
109 */
110screenshotr_error_t screenshotr_client_free(screenshotr_client_t client)
111{
112 if (!client)
113 return SCREENSHOTR_E_INVALID_ARG;
114 device_link_service_disconnect(client->parent);
115 screenshotr_error_t err = screenshotr_error(device_link_service_client_free(client->parent));
116 free(client);
117 return err;
118}
119
120/**
121 * Get a screen shot from the connected device.
122 *
123 * @param client The connection screenshotr service client.
124 * @param imgdata Pointer that will point to a newly allocated buffer
125 * containing TIFF image data upon successful return. It is up to the
126 * caller to free the memory.
127 * @param imgsize Pointer to a uint64_t that will be set to the size of the
128 * buffer imgdata points to upon successful return.
129 *
130 * @return SCREENSHOTR_E_SUCCESS on success, SCREENSHOTR_E_INVALID_ARG if
131 * one or more parameters are invalid, or another error code if an
132 * error occured.
133 */
134screenshotr_error_t screenshotr_take_screenshot(screenshotr_client_t client, char **imgdata, uint64_t *imgsize)
135{
136 if (!client || !client->parent || !imgdata)
137 return SCREENSHOTR_E_INVALID_ARG;
138
139 screenshotr_error_t res = SCREENSHOTR_E_UNKNOWN_ERROR;
140
141 plist_t dict = plist_new_dict();
142 plist_dict_insert_item(dict, "MessageType", plist_new_string("ScreenShotRequest"));
143
144 res = screenshotr_error(device_link_service_process_message(client->parent, dict));
145 plist_free(dict);
146 if (res != SCREENSHOTR_E_SUCCESS) {
147 debug_info("could not send plist, error %d", res);
148 return res;
149 }
150
151 dict = NULL;
152 res = screenshotr_error(device_link_service_get_process_message(client->parent, &dict));
153 if (res != SCREENSHOTR_E_SUCCESS) {
154 debug_info("could not get screenshot data, error %d", res);
155 goto leave;
156 }
157 if (!dict) {
158 debug_info("did not receive screenshot data!");
159 res = SCREENSHOTR_E_PLIST_ERROR;
160 goto leave;
161 }
162
163 plist_t node = plist_dict_get_item(dict, "MessageType");
164 char *strval = NULL;
165 plist_get_string_val(node, &strval);
166 if (!strval || strcmp(strval, "ScreenShotReply")) {
167 debug_info("invalid screenshot data received!");
168 res = SCREENSHOTR_E_PLIST_ERROR;
169 goto leave;
170 }
171 node = plist_dict_get_item(dict, "ScreenShotData");
172 if (!node || plist_get_node_type(node) != PLIST_DATA) {
173 debug_info("no PNG data received!");
174 res = SCREENSHOTR_E_PLIST_ERROR;
175 goto leave;
176 }
177
178 plist_get_data_val(node, imgdata, imgsize);
179 res = SCREENSHOTR_E_SUCCESS;
180
181leave:
182 if (dict)
183 plist_free(dict);
184
185 return res;
186}