| |
1 #include "edisc.h" |
| |
2 |
| |
3 #include <debug.h> |
| |
4 |
| |
5 #include "gg.h" |
| |
6 #include "libgaduw.h" |
| |
7 #include <http.h> |
| |
8 |
| |
9 #define GGP_EDISC_HOSTNAME "MyComputer" |
| |
10 #define GGP_EDISC_OS "WINNT x86-msvc" |
| |
11 #define GGP_EDISC_TYPE "desktop" |
| |
12 |
| |
13 #define GGP_EDISC_RESPONSE_MAX 10240 |
| |
14 |
| |
15 typedef struct _ggp_edisc_auth_data ggp_edisc_auth_data; |
| |
16 |
| |
17 typedef struct _ggp_edisc_xfer ggp_edisc_xfer; |
| |
18 |
| |
19 struct _ggp_edisc_session_data |
| |
20 { |
| |
21 PurpleHttpCookieJar *cookies; |
| |
22 gchar *security_token; |
| |
23 |
| |
24 PurpleHttpConnection *auth_request; |
| |
25 gboolean auth_done; |
| |
26 GList *auth_pending; |
| |
27 }; |
| |
28 |
| |
29 struct _ggp_edisc_xfer |
| |
30 { |
| |
31 PurpleConnection *gc; |
| |
32 }; |
| |
33 |
| |
34 typedef void (*ggp_ggdrive_auth_cb)(PurpleConnection *gc, gboolean success, |
| |
35 gpointer user_data); |
| |
36 |
| |
37 static void ggp_ggdrive_auth(PurpleConnection *gc, ggp_ggdrive_auth_cb cb, |
| |
38 gpointer user_data); |
| |
39 |
| |
40 static void ggp_edisc_xfer_free(PurpleXfer *xfer); |
| |
41 |
| |
42 /******************************************************************************* |
| |
43 * Setting up. |
| |
44 ******************************************************************************/ |
| |
45 |
| |
46 static inline ggp_edisc_session_data * |
| |
47 ggp_edisc_get_sdata(PurpleConnection *gc) |
| |
48 { |
| |
49 GGPInfo *accdata = purple_connection_get_protocol_data(gc); |
| |
50 return accdata->edisc_data; |
| |
51 } |
| |
52 |
| |
53 void ggp_edisc_setup(PurpleConnection *gc) |
| |
54 { |
| |
55 GGPInfo *accdata = purple_connection_get_protocol_data(gc); |
| |
56 ggp_edisc_session_data *sdata = g_new0(ggp_edisc_session_data, 1); |
| |
57 |
| |
58 accdata->edisc_data = sdata; |
| |
59 |
| |
60 sdata->cookies = purple_http_cookie_jar_new(); |
| |
61 } |
| |
62 |
| |
63 void ggp_edisc_cleanup(PurpleConnection *gc) |
| |
64 { |
| |
65 ggp_edisc_session_data *sdata = ggp_edisc_get_sdata(gc); |
| |
66 |
| |
67 purple_http_conn_cancel(sdata->auth_request); |
| |
68 g_list_free_full(sdata->auth_pending, g_free); |
| |
69 g_free(sdata->security_token); |
| |
70 |
| |
71 purple_http_cookie_jar_unref(sdata->cookies); |
| |
72 |
| |
73 g_free(sdata); |
| |
74 } |
| |
75 |
| |
76 /******************************************************************************* |
| |
77 * Sending a file. |
| |
78 ******************************************************************************/ |
| |
79 |
| |
80 static void ggp_edisc_xfer_init(PurpleXfer *xfer); |
| |
81 static void ggp_edisc_xfer_init_authenticated(PurpleConnection *gc, |
| |
82 gboolean success, gpointer _xfer); |
| |
83 |
| |
84 static void ggp_edisc_xfer_error(PurpleXfer *xfer, const gchar *msg); |
| |
85 |
| |
86 static void ggp_edisc_xfer_free(PurpleXfer *xfer) |
| |
87 { |
| |
88 ggp_edisc_xfer *edisc_xfer = purple_xfer_get_protocol_data(xfer); |
| |
89 |
| |
90 if (edisc_xfer == NULL) |
| |
91 return; |
| |
92 |
| |
93 g_free(edisc_xfer); |
| |
94 purple_xfer_set_protocol_data(xfer, NULL); |
| |
95 } |
| |
96 |
| |
97 static void ggp_edisc_xfer_error(PurpleXfer *xfer, const gchar *msg) |
| |
98 { |
| |
99 purple_xfer_error( |
| |
100 purple_xfer_get_type(xfer), |
| |
101 purple_xfer_get_account(xfer), |
| |
102 purple_xfer_get_remote_user(xfer), |
| |
103 msg); |
| |
104 ggp_edisc_xfer_free(xfer); |
| |
105 } |
| |
106 |
| |
107 gboolean ggp_edisc_xfer_can_receive_file(PurpleConnection *gc, const char *who) |
| |
108 { |
| |
109 return TRUE; /* TODO: only online, buddies (?) */ |
| |
110 } |
| |
111 |
| |
112 static void ggp_edisc_xfer_init(PurpleXfer *xfer) |
| |
113 { |
| |
114 ggp_edisc_xfer *edisc_xfer = purple_xfer_get_protocol_data(xfer); |
| |
115 |
| |
116 if (purple_xfer_get_type(xfer) != PURPLE_XFER_SEND) { |
| |
117 purple_debug_error("gg", "ggp_edisc_xfer_init: " |
| |
118 "Not yet implemented\n"); |
| |
119 return; |
| |
120 } |
| |
121 |
| |
122 ggp_ggdrive_auth(edisc_xfer->gc, ggp_edisc_xfer_init_authenticated, xfer); |
| |
123 } |
| |
124 |
| |
125 static void ggp_edisc_xfer_init_authenticated(PurpleConnection *gc, |
| |
126 gboolean success, gpointer _xfer) |
| |
127 { |
| |
128 PurpleXfer *xfer = _xfer; |
| |
129 |
| |
130 if (!success) { |
| |
131 ggp_edisc_xfer_error(xfer, _("Authentication failed")); |
| |
132 return; |
| |
133 } |
| |
134 |
| |
135 /* TODO: requesting a ticket */ |
| |
136 |
| |
137 purple_xfer_start(xfer, -1, NULL, 0); |
| |
138 } |
| |
139 |
| |
140 static void ggp_edisc_xfer_start(PurpleXfer *xfer) |
| |
141 { |
| |
142 g_return_if_fail(xfer != NULL); |
| |
143 |
| |
144 if (purple_xfer_get_type(xfer) != PURPLE_XFER_SEND) { |
| |
145 purple_debug_error("gg", "ggp_edisc_xfer_start: " |
| |
146 "Not yet implemented\n"); |
| |
147 return; |
| |
148 } |
| |
149 |
| |
150 purple_debug_info("gg", "Starting a file transfer...\n"); |
| |
151 } |
| |
152 |
| |
153 PurpleXfer * ggp_edisc_xfer_new(PurpleConnection *gc, const char *who) |
| |
154 { |
| |
155 PurpleXfer *xfer; |
| |
156 ggp_edisc_xfer *edisc_xfer; |
| |
157 |
| |
158 g_return_val_if_fail(gc != NULL, NULL); |
| |
159 g_return_val_if_fail(who != NULL, NULL); |
| |
160 |
| |
161 xfer = purple_xfer_new(purple_connection_get_account(gc), |
| |
162 PURPLE_XFER_SEND, who); |
| |
163 edisc_xfer = g_new0(ggp_edisc_xfer, 1); |
| |
164 purple_xfer_set_protocol_data(xfer, edisc_xfer); |
| |
165 |
| |
166 edisc_xfer->gc = gc; |
| |
167 |
| |
168 purple_xfer_set_init_fnc(xfer, ggp_edisc_xfer_init); |
| |
169 purple_xfer_set_start_fnc(xfer, ggp_edisc_xfer_start); |
| |
170 |
| |
171 //purple_xfer_set_cancel_send_fnc(xfer, bonjour_xfer_cancel_send); |
| |
172 //purple_xfer_set_end_fnc(xfer, bonjour_xfer_end); |
| |
173 |
| |
174 return xfer; |
| |
175 } |
| |
176 |
| |
177 void ggp_edisc_xfer_send_file(PurpleConnection *gc, const char *who, |
| |
178 const char *filename) |
| |
179 { |
| |
180 PurpleXfer *xfer; |
| |
181 |
| |
182 g_return_if_fail(gc != NULL); |
| |
183 g_return_if_fail(who != NULL); |
| |
184 |
| |
185 /* Nothing interesting here, this code is common among prpls. |
| |
186 * See ggp_edisc_new_xfer. */ |
| |
187 |
| |
188 xfer = ggp_edisc_xfer_new(gc, who); |
| |
189 if (filename) |
| |
190 purple_xfer_request_accepted(xfer, filename); |
| |
191 else |
| |
192 purple_xfer_request(xfer); |
| |
193 } |
| |
194 |
| |
195 /******************************************************************************* |
| |
196 * Authentication |
| |
197 ******************************************************************************/ |
| |
198 |
| |
199 struct _ggp_edisc_auth_data |
| |
200 { |
| |
201 ggp_ggdrive_auth_cb cb; |
| |
202 gpointer user_data; |
| |
203 }; |
| |
204 |
| |
205 static void ggp_ggdrive_auth_done(PurpleHttpConnection *hc, |
| |
206 PurpleHttpResponse *response, gpointer user_data); |
| |
207 |
| |
208 static void ggp_ggdrive_auth(PurpleConnection *gc, ggp_ggdrive_auth_cb cb, |
| |
209 gpointer user_data) |
| |
210 { |
| |
211 GGPInfo *accdata = purple_connection_get_protocol_data(gc); |
| |
212 ggp_edisc_session_data *sdata = ggp_edisc_get_sdata(gc); |
| |
213 ggp_edisc_auth_data *auth; |
| |
214 const gchar *imtoken; |
| |
215 gchar *metadata; |
| |
216 PurpleHttpRequest *req; |
| |
217 |
| |
218 imtoken = ggp_get_imtoken(gc); |
| |
219 if (!imtoken) |
| |
220 { |
| |
221 cb(gc, FALSE, user_data); |
| |
222 return; |
| |
223 } |
| |
224 |
| |
225 if (sdata->auth_done) |
| |
226 { |
| |
227 cb(gc, sdata->security_token != NULL, user_data); |
| |
228 return; |
| |
229 } |
| |
230 |
| |
231 auth = g_new0(ggp_edisc_auth_data, 1); |
| |
232 auth->cb = cb; |
| |
233 auth->user_data = user_data; |
| |
234 sdata->auth_pending = g_list_prepend(sdata->auth_pending, auth); |
| |
235 |
| |
236 if (sdata->auth_request) |
| |
237 return; |
| |
238 |
| |
239 purple_debug_info("gg", "ggp_ggdrive_auth(gc=%p)\n", gc); |
| |
240 |
| |
241 req = purple_http_request_new("https://drive.mpa.gg.pl/signin"); |
| |
242 purple_http_request_set_method(req, "PUT"); |
| |
243 |
| |
244 /* TODO: defaults (browser name, etc) */ |
| |
245 purple_http_request_set_max_len(req, GGP_EDISC_RESPONSE_MAX); |
| |
246 purple_http_request_set_cookie_jar(req, sdata->cookies); |
| |
247 |
| |
248 metadata = g_strdup_printf("{" |
| |
249 "\"id\": \"%032x\", " |
| |
250 "\"name\": \"" GGP_EDISC_HOSTNAME "\", " |
| |
251 "\"os_version\": \"" GGP_EDISC_OS "\", " |
| |
252 "\"client_version\": \"%s\", " |
| |
253 "\"type\": \"" GGP_EDISC_TYPE "\"}", |
| |
254 g_random_int_range(1, 1 << 16), |
| |
255 ggp_libgaduw_version(gc)); |
| |
256 |
| |
257 purple_http_request_header_set_printf(req, "Authorization", |
| |
258 "IMToken %s", imtoken); |
| |
259 purple_http_request_header_set_printf(req, "X-gged-user", |
| |
260 "gg/pl:%u", accdata->session->uin); |
| |
261 purple_http_request_header_set(req, "X-gged-client-metadata", metadata); |
| |
262 purple_http_request_header_set(req, "X-gged-api-version", "6"); |
| |
263 g_free(metadata); |
| |
264 |
| |
265 sdata->auth_request = purple_http_request(gc, req, |
| |
266 ggp_ggdrive_auth_done, NULL); |
| |
267 purple_http_request_unref(req); |
| |
268 } |
| |
269 |
| |
270 static void ggp_ggdrive_auth_results(PurpleConnection *gc, gboolean success) |
| |
271 { |
| |
272 ggp_edisc_session_data *sdata = ggp_edisc_get_sdata(gc); |
| |
273 GList *it; |
| |
274 |
| |
275 purple_debug_info("gg", "ggp_ggdrive_auth_results(gc=%p): %d\n", |
| |
276 gc, success); |
| |
277 |
| |
278 it = g_list_first(sdata->auth_pending); |
| |
279 while (it) { |
| |
280 ggp_edisc_auth_data *auth = it->data; |
| |
281 it = g_list_next(it); |
| |
282 |
| |
283 auth->cb(gc, success, auth->user_data); |
| |
284 g_free(auth); |
| |
285 } |
| |
286 g_list_free(sdata->auth_pending); |
| |
287 sdata->auth_pending = NULL; |
| |
288 sdata->auth_done = TRUE; |
| |
289 } |
| |
290 |
| |
291 static void ggp_ggdrive_auth_done(PurpleHttpConnection *hc, |
| |
292 PurpleHttpResponse *response, gpointer user_data) |
| |
293 { |
| |
294 PurpleConnection *gc = purple_http_conn_get_purple_connection(hc); |
| |
295 ggp_edisc_session_data *sdata = ggp_edisc_get_sdata(gc); |
| |
296 |
| |
297 sdata->auth_request = NULL; |
| |
298 |
| |
299 if (!purple_http_response_is_successfull(response) || |
| |
300 0 != strcmp(purple_http_response_get_data(response), |
| |
301 "{\"result\":{\"status\":0}}")) { |
| |
302 ggp_ggdrive_auth_results(gc, FALSE); |
| |
303 return; |
| |
304 } |
| |
305 |
| |
306 sdata->security_token = g_strdup(purple_http_response_get_header( |
| |
307 response, "X-gged-security-token")); |
| |
308 if (!sdata->security_token) { |
| |
309 ggp_ggdrive_auth_results(gc, FALSE); |
| |
310 return; |
| |
311 } |
| |
312 |
| |
313 if (purple_debug_is_unsafe()) |
| |
314 purple_debug_misc("gg", "ggp_ggdrive_auth_done: " |
| |
315 "security_token=%s\n", sdata->security_token); |
| |
316 ggp_ggdrive_auth_results(gc, TRUE); |
| |
317 } |