1 /*
2  * SkypeWeb Plugin for libpurple/Pidgin
3  * Copyright (c) 2014-2020 Eion Robb
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 
20 #include "skypeweb_contacts.h"
21 #include "skypeweb_connection.h"
22 #include "skypeweb_messages.h"
23 #include "skypeweb_util.h"
24 
25 #include "http.h"
26 #include "xfer.h"
27 #include "image-store.h"
28 
purple_conversation_write_system_message_ts(PurpleConversation * conv,const gchar * msg,PurpleMessageFlags flags,time_t ts)29 static void purple_conversation_write_system_message_ts(
30 		PurpleConversation *conv, const gchar *msg, PurpleMessageFlags flags,
31 		time_t ts) {
32 	PurpleMessage *pmsg = purple_message_new_system(msg, flags);
33 	purple_message_set_time(pmsg, ts);
34 	purple_conversation_write_message(conv, pmsg);
35 	purple_message_destroy(pmsg);
36 }
purple_conversation_write_img_message(PurpleConversation * conv,const char * who,const gchar * msg,PurpleMessageFlags flags,time_t ts)37 static void purple_conversation_write_img_message(
38 		PurpleConversation *conv, const char* who, const gchar *msg,
39 		PurpleMessageFlags flags, time_t ts) {
40 	PurpleMessage *pmsg;
41 
42 	if (flags & PURPLE_MESSAGE_SEND) {
43 		pmsg = purple_message_new_outgoing(who, msg, flags);
44 		purple_message_set_time(pmsg, ts);
45 	} else {
46 		pmsg = purple_message_new_incoming(who, msg, flags, ts);
47 	}
48 
49 	purple_conversation_write_message(conv, pmsg);
50 	purple_message_destroy(pmsg);
51 }
52 
53 // Check that the conversation hasn't been closed
54 static gboolean
purple_conversation_is_valid(PurpleConversation * conv)55 purple_conversation_is_valid(PurpleConversation *conv)
56 {
57 	GList *convs = purple_conversations_get_all();
58 
59 	return (g_list_find(convs, conv) != NULL);
60 }
61 
62 
63 typedef struct {
64 	PurpleXfer *xfer;
65 	JsonObject *info;
66 	gchar *from;
67 	gchar *url;
68 	gchar *id;
69 	SkypeWebAccount *sa;
70 } SkypeWebFileTransfer;
71 
72 static guint active_icon_downloads = 0;
73 
74 static void
skypeweb_get_icon_cb(PurpleHttpConnection * http_conn,PurpleHttpResponse * response,gpointer user_data)75 skypeweb_get_icon_cb(PurpleHttpConnection *http_conn, PurpleHttpResponse *response, gpointer user_data)
76 {
77 	PurpleHttpRequest *request = purple_http_conn_get_request(http_conn);
78 	PurpleBuddy *buddy = user_data;
79 	const gchar *url = purple_http_request_get_url(request);
80 	const gchar *data;
81 	gsize len;
82 
83 	active_icon_downloads--;
84 
85 	if (!buddy || !purple_http_response_is_successful(response)) {
86 		return;
87 	}
88 
89 	data = purple_http_response_get_data(response, &len);
90 
91 	if (!len || !*data) {
92 		return;
93 	}
94 
95 	purple_buddy_icons_set_for_user(purple_buddy_get_account(buddy), purple_buddy_get_name(buddy), g_memdup(data, len), len, url);
96 
97 }
98 
99 static void
skypeweb_get_icon_now(PurpleBuddy * buddy)100 skypeweb_get_icon_now(PurpleBuddy *buddy)
101 {
102 	SkypeWebBuddy *sbuddy;
103 	SkypeWebAccount *sa;
104 	gchar *url;
105 
106 	purple_debug_info("skypeweb", "getting new buddy icon for %s\n", purple_buddy_get_name(buddy));
107 
108 	sbuddy = purple_buddy_get_protocol_data(buddy);
109 
110 	if (!sbuddy || !sbuddy->sa || !sbuddy->sa->pc)
111 		return;
112 
113 	if (sbuddy->avatar_url && sbuddy->avatar_url[0]) {
114 		url = g_strdup(sbuddy->avatar_url);
115 	} else {
116 		url = g_strdup_printf("https://avatar.skype.com/v1/avatars/%s/public?returnDefaultImage=false", purple_url_encode(purple_buddy_get_name(buddy)));
117 	}
118 
119 	sa = sbuddy->sa;
120 
121 	purple_http_get(sa->pc, skypeweb_get_icon_cb, buddy, url);
122 	g_free(url);
123 
124 	active_icon_downloads++;
125 }
126 
127 static gboolean
skypeweb_get_icon_queuepop(gpointer data)128 skypeweb_get_icon_queuepop(gpointer data)
129 {
130 	PurpleBuddy *buddy = data;
131 
132 	// Only allow 4 simultaneous downloads
133 	if (active_icon_downloads > 4)
134 		return TRUE;
135 
136 	skypeweb_get_icon_now(buddy);
137 	return FALSE;
138 }
139 
140 void
skypeweb_get_icon(PurpleBuddy * buddy)141 skypeweb_get_icon(PurpleBuddy *buddy)
142 {
143 	if (!buddy) return;
144 
145 	g_timeout_add(100, skypeweb_get_icon_queuepop, (gpointer)buddy);
146 }
147 
148 typedef struct SkypeImgMsgContext_ {
149 	PurpleConversation *conv;
150 	time_t composetimestamp;
151 	gchar* from;
152 } SkypeImgMsgContext;
153 
154 static void
skypeweb_got_imagemessage(PurpleHttpConnection * http_conn,PurpleHttpResponse * response,gpointer user_data)155 skypeweb_got_imagemessage(PurpleHttpConnection *http_conn, PurpleHttpResponse *response, gpointer user_data)
156 {
157 	gint icon_id;
158 	gchar *msg_tmp;
159 	const gchar *url_text;
160 	gsize len;
161 	PurpleImage *image;
162 
163 	SkypeImgMsgContext *ctx = user_data;
164 	PurpleConversation *conv = ctx->conv;
165 	time_t ts = ctx->composetimestamp;
166 	gchar* ctx_from = ctx->from;
167 	ctx->from = NULL;
168 	g_free(ctx);
169 
170 	// Conversation could have been closed before we retrieved the image
171 	if (!purple_conversation_is_valid(conv)) {
172 		return;
173 	}
174 
175 	url_text = purple_http_response_get_data(response, &len);
176 
177 	if (!url_text || !len || url_text[0] == '{' || url_text[0] == '<')
178 		return;
179 
180 	if (!purple_http_response_is_successful(response))
181 		return;
182 
183 	image = purple_image_new_from_data(g_memdup(url_text, len), len);
184 	icon_id = purple_image_store_add(image);
185 	msg_tmp = g_strdup_printf("<img id='%d'>", icon_id);
186 	purple_conversation_write_img_message(conv, ctx_from, msg_tmp, PURPLE_MESSAGE_NO_LOG | PURPLE_MESSAGE_IMAGES, ts);
187 	g_free(msg_tmp);
188 	g_free(ctx_from);
189 }
190 
191 void
skypeweb_download_uri_to_conv(SkypeWebAccount * sa,const gchar * uri,PurpleConversation * conv,time_t ts,const gchar * from)192 skypeweb_download_uri_to_conv(SkypeWebAccount *sa, const gchar *uri, PurpleConversation *conv, time_t ts, const gchar* from)
193 {
194 	gchar *url, *text;
195 	PurpleHttpRequest *request;
196 
197 	if (purple_strequal(purple_core_get_ui(), "BitlBee")) {
198 		// Bitlbee doesn't support images, so just plop a url to the image instead
199 
200 		url = purple_strreplace(uri, "imgt1", "imgpsh_fullsize");
201 		purple_conversation_write_system_message_ts(conv, url, PURPLE_MESSAGE_SYSTEM, ts);
202 		g_free(url);
203 
204 		return;
205 	}
206 
207 	request = purple_http_request_new(uri);
208 	purple_http_request_set_keepalive_pool(request, sa->keepalive_pool);
209 	purple_http_request_header_set_printf(request, "Cookie", "skypetoken_asm=%s", sa->skype_token);
210 	purple_http_request_header_set(request, "Accept", "image/*");
211 	SkypeImgMsgContext *ctx = g_new(SkypeImgMsgContext, 1);
212 	ctx->composetimestamp = ts;
213 	ctx->conv = conv;
214 	ctx->from = g_strdup(from);
215 	purple_http_request(sa->pc, request, skypeweb_got_imagemessage, ctx);
216 	purple_http_request_unref(request);
217 
218 	url = purple_strreplace(uri, "imgt1", "imgpsh_fullsize");
219 	text = g_strdup_printf("<a href=\"%s\">Click here to view full version</a>", url);
220 	purple_conversation_write_img_message(conv, from, text, 0, ts);
221 
222 	g_free(url);
223 	g_free(text);
224 }
225 
226 void
skypeweb_download_moji_to_conv(SkypeWebAccount * sa,const gchar * text,const gchar * url_thumbnail,PurpleConversation * conv,time_t ts,const gchar * from)227 skypeweb_download_moji_to_conv(SkypeWebAccount *sa, const gchar *text, const gchar *url_thumbnail, PurpleConversation *conv, time_t ts, const gchar* from)
228 {
229 	gchar *cdn_url_thumbnail;
230 	PurpleHttpURL *httpurl;
231 	PurpleHttpRequest *request;
232 
233 	httpurl = purple_http_url_parse(url_thumbnail);
234 
235 	cdn_url_thumbnail = g_strdup_printf("https://%s/%s", SKYPEWEB_STATIC_CDN_HOST, purple_http_url_get_path(httpurl));
236 
237 	request = purple_http_request_new(cdn_url_thumbnail);
238 	purple_http_request_set_keepalive_pool(request, sa->keepalive_pool);
239 	purple_http_request_header_set_printf(request, "Cookie", "vdms-skype-token=%s", sa->vdms_token);
240 	purple_http_request_header_set(request, "Accept", "image/*");
241 	SkypeImgMsgContext *ctx = g_new(SkypeImgMsgContext, 1);
242 	ctx->composetimestamp = ts;
243 	ctx->conv = conv;
244 	ctx->from = g_strdup(from);
245 	purple_http_request(sa->pc, request, skypeweb_got_imagemessage, ctx);
246 	purple_http_request_unref(request);
247 
248 	purple_conversation_write_img_message(conv, from, text, 0, ts);
249 
250 	g_free(cdn_url_thumbnail);
251 	purple_http_url_free(httpurl);
252 }
253 
254 static void
skypeweb_got_vm_file(PurpleHttpConnection * http_conn,PurpleHttpResponse * response,gpointer user_data)255 skypeweb_got_vm_file(PurpleHttpConnection *http_conn, PurpleHttpResponse *response, gpointer user_data)
256 {
257 	PurpleXfer *xfer = user_data;
258 	const gchar *data;
259 	gsize len;
260 
261 	data = purple_http_response_get_data(response, &len);
262 	purple_xfer_write(xfer, (guchar *)data, len);
263 }
264 
265 static void
skypeweb_init_vm_download(PurpleXfer * xfer)266 skypeweb_init_vm_download(PurpleXfer *xfer)
267 {
268 	SkypeWebAccount *sa;
269 	JsonObject *file = purple_xfer_get_protocol_data(xfer);
270 	gint64 fileSize;
271 	const gchar *url;
272 	PurpleHttpRequest *request;
273 
274 	fileSize = json_object_get_int_member(file, "fileSize");
275 	url = json_object_get_string_member(file, "url");
276 
277 	purple_xfer_set_completed(xfer, FALSE);
278 	sa = purple_connection_get_protocol_data(purple_account_get_connection(purple_xfer_get_account(xfer)));
279 
280 	request = purple_http_request_new(url);
281 	purple_http_request_set_keepalive_pool(request, sa->keepalive_pool);
282 	purple_http_request_set_max_len(request, fileSize);
283 	purple_http_request(sa->pc, request, skypeweb_got_vm_file, xfer);
284 	purple_http_request_unref(request);
285 
286 	json_object_unref(file);
287 }
288 
289 static void
skypeweb_cancel_vm_download(PurpleXfer * xfer)290 skypeweb_cancel_vm_download(PurpleXfer *xfer)
291 {
292 	JsonObject *file = purple_xfer_get_protocol_data(xfer);
293 	json_object_unref(file);
294 }
295 
296 static void
skypeweb_got_vm_download_info(SkypeWebAccount * sa,JsonNode * node,gpointer user_data)297 skypeweb_got_vm_download_info(SkypeWebAccount *sa, JsonNode *node, gpointer user_data)
298 {
299 	PurpleConversation *conv = user_data;
300 	PurpleXfer *xfer;
301 	JsonObject *obj, *file;
302 	JsonArray *files;
303 	gint64 fileSize;
304 	const gchar *url, *assetId, *status;
305 	gchar *filename;
306 
307 	if (node == NULL || json_node_get_node_type(node) != JSON_NODE_OBJECT)
308 		return;
309 	obj = json_node_get_object(node);
310 
311 	files = json_object_get_array_member(obj, "files");
312 	file = json_array_get_object_element(files, 0);
313 	if (file != NULL) {
314 		status = json_object_get_string_member(file, "status");
315 		if (status && g_str_equal(status, "ok")) {
316 			assetId = json_object_get_string_member(obj, "assetId");
317 			fileSize = json_object_get_int_member(file, "fileSize");
318 			url = json_object_get_string_member(file, "url");
319 			(void) url;
320 
321 			filename = g_strconcat(assetId, ".mp4", NULL);
322 
323 			xfer = purple_xfer_new(sa->account, PURPLE_XFER_TYPE_RECEIVE, purple_conversation_get_name(conv));
324 			purple_xfer_set_size(xfer, fileSize);
325 			purple_xfer_set_filename(xfer, filename);
326 			json_object_ref(file);
327 			purple_xfer_set_protocol_data(xfer, file);
328 			purple_xfer_set_init_fnc(xfer, skypeweb_init_vm_download);
329 			purple_xfer_set_cancel_recv_fnc(xfer, skypeweb_cancel_vm_download);
330 			purple_xfer_add(xfer);
331 
332 			g_free(filename);
333 		} else if (status && g_str_equal(status, "running")) {
334 			//skypeweb_download_video_message(sa, sid??????, conv);
335 		}
336 	}
337 }
338 
339 static void
skypeweb_got_vm_info(SkypeWebAccount * sa,JsonNode * node,gpointer user_data)340 skypeweb_got_vm_info(SkypeWebAccount *sa, JsonNode *node, gpointer user_data)
341 {
342 	PurpleConversation *conv = user_data;
343 	JsonObject *obj, *response, *media_stream;
344 	const gchar *filename;
345 
346 	if (node == NULL || json_node_get_node_type(node) != JSON_NODE_OBJECT)
347 		return;
348 	obj = json_node_get_object(node);
349 
350 	response = json_object_get_object_member(obj, "response");
351 	media_stream = json_object_get_object_member(response, "media_stream");
352 	filename = json_object_get_string_member(media_stream, "filename");
353 
354 	if (filename != NULL) {
355 		// Need to keep retrying this url until it comes back with status:ok
356 		gchar *url = g_strdup_printf("/vod/api-create?assetId=%s&profile=mp4-vm", purple_url_encode(filename));
357 		skypeweb_post_or_get(sa, SKYPEWEB_METHOD_GET | SKYPEWEB_METHOD_SSL, "media.vm.skype.com", url, NULL, skypeweb_got_vm_download_info, conv, TRUE);
358 		g_free(url);
359 	}
360 
361 }
362 
363 void
skypeweb_download_video_message(SkypeWebAccount * sa,const gchar * sid,PurpleConversation * conv)364 skypeweb_download_video_message(SkypeWebAccount *sa, const gchar *sid, PurpleConversation *conv)
365 {
366 	gchar *url, *username_encoded;
367 
368 	username_encoded = g_strdup(purple_url_encode(sa->username));
369 	url = g_strdup_printf("/users/%s/video_mails/%s", username_encoded, purple_url_encode(sid));
370 
371 	skypeweb_post_or_get(sa, SKYPEWEB_METHOD_GET | SKYPEWEB_METHOD_SSL, SKYPEWEB_VIDEOMAIL_HOST, url, NULL, skypeweb_got_vm_info, conv, TRUE);
372 
373 	g_free(url);
374 	g_free(username_encoded);
375 
376 }
377 
378 
379 static void
skypeweb_free_xfer(PurpleXfer * xfer)380 skypeweb_free_xfer(PurpleXfer *xfer)
381 {
382 	SkypeWebFileTransfer *swft;
383 
384 	swft = purple_xfer_get_protocol_data(xfer);
385 	g_return_if_fail(swft != NULL);
386 
387 	if (swft->info != NULL)
388 		json_object_unref(swft->info);
389 	g_free(swft->url);
390 	g_free(swft->id);
391 	g_free(swft->from);
392 	g_free(swft);
393 
394 	purple_xfer_set_protocol_data(xfer, NULL);
395 }
396 
397 static void
skypeweb_got_file(PurpleHttpConnection * http_conn,PurpleHttpResponse * response,gpointer user_data)398 skypeweb_got_file(PurpleHttpConnection *http_conn, PurpleHttpResponse *response, gpointer user_data)
399 {
400 	SkypeWebFileTransfer *swft = user_data;
401 	PurpleXfer *xfer = swft->xfer;
402 	SkypeWebAccount *sa = swft->sa;
403 	const gchar *data;
404 	gsize len;
405 
406 
407 	if (!purple_http_response_is_successful(response)) {
408 		purple_xfer_error(purple_xfer_get_xfer_type(xfer), sa->account, swft->from, purple_http_response_get_error(response));
409 		purple_xfer_cancel_local(xfer);
410 	} else {
411 		data = purple_http_response_get_data(response, &len);
412 		purple_xfer_write_file(xfer, (guchar *)data, len);
413 		purple_xfer_set_completed(xfer, TRUE);
414 	}
415 
416 	//cleanup
417 	skypeweb_free_xfer(xfer);
418 	purple_xfer_end(xfer);
419 }
420 
421 static void
skypeweb_init_file_download(PurpleXfer * xfer)422 skypeweb_init_file_download(PurpleXfer *xfer)
423 {
424 	SkypeWebAccount *sa;
425 	SkypeWebFileTransfer *swft;
426 	const gchar *view_location;
427 	gint64 content_full_length;
428 	PurpleHttpRequest *request;
429 
430 	swft = purple_xfer_get_protocol_data(xfer);
431 	sa = swft->sa;
432 
433 	view_location = json_object_get_string_member(swft->info, "view_location");
434 	content_full_length = json_object_get_int_member(swft->info, "content_full_length");
435 
436 	purple_xfer_start(xfer, -1, NULL, 0);
437 
438 	request = purple_http_request_new(view_location);
439 	purple_http_request_set_keepalive_pool(request, sa->keepalive_pool);
440 	purple_http_request_header_set_printf(request, "Cookie", "skypetoken_asm=%s", sa->skype_token);
441 	purple_http_request_header_set(request, "Accept", "*/*");
442 	purple_http_request_set_max_len(request, content_full_length);
443 	purple_http_request(sa->pc, request, skypeweb_got_file, swft);
444 	purple_http_request_unref(request);
445 }
446 
447 static void
skypeweb_got_file_info(PurpleHttpConnection * http_conn,PurpleHttpResponse * response,gpointer user_data)448 skypeweb_got_file_info(PurpleHttpConnection *http_conn, PurpleHttpResponse *response, gpointer user_data)
449 {
450 	JsonObject *obj;
451 	PurpleXfer *xfer;
452 	SkypeWebFileTransfer *swft = user_data;
453 	SkypeWebAccount *sa = swft->sa;
454 	JsonParser *parser;
455 	JsonNode *node;
456 	const gchar *data;
457 	gsize len;
458 
459 	data = purple_http_response_get_data(response, &len);
460 
461 	parser = json_parser_new();
462 	if (!json_parser_load_from_data(parser, data, len, NULL)) {
463 		g_free(swft->url);
464 		g_free(swft->from);
465 		g_free(swft);
466 		g_object_unref(parser);
467 		return;
468 	}
469 
470 	node = json_parser_get_root(parser);
471 	if (node == NULL || json_node_get_node_type(node) != JSON_NODE_OBJECT) {
472 		g_free(swft->url);
473 		g_free(swft->from);
474 		g_free(swft);
475 		g_object_unref(parser);
476 		return;
477 	}
478 	obj = json_node_get_object(node);
479 
480 	/*
481 	{
482 		"content_length": 40708,
483 		"content_full_length": 40708,
484 		"view_length": 40708,
485 		"content_state": "ready",
486 		"view_state": "ready",
487 		"view_location": "uri/views/original",
488 		"status_location": "uri/views/original/status",
489 		"scan": {
490 			"status": "passed"
491 		},
492 		"original_filename": "filename"
493 	} */
494 	purple_debug_info("skypeweb", "File info: %s\n", data);
495 
496 	if (!json_object_has_member(obj, "content_state") || !purple_strequal(json_object_get_string_member(obj, "content_state"), "ready")) {
497 		skypeweb_present_uri_as_filetransfer(sa, json_object_get_string_member(obj, "status_location"), swft->from);
498 		g_free(swft->url);
499 		g_free(swft->from);
500 		g_free(swft);
501 		g_object_unref(parser);
502 		return;
503 	}
504 
505 	json_object_ref(obj);
506 	swft->info = obj;
507 
508 	xfer = purple_xfer_new(sa->account, PURPLE_XFER_TYPE_RECEIVE, swft->from);
509 	purple_xfer_set_size(xfer, json_object_get_int_member(obj, "content_full_length"));
510 	purple_xfer_set_filename(xfer, json_object_get_string_member(obj, "original_filename"));
511 	purple_xfer_set_init_fnc(xfer, skypeweb_init_file_download);
512 	purple_xfer_set_cancel_recv_fnc(xfer, skypeweb_free_xfer);
513 
514 	swft->xfer = xfer;
515 	purple_xfer_set_protocol_data(xfer, swft);
516 
517 	purple_xfer_request(xfer);
518 
519 	g_object_unref(parser);
520 }
521 
522 void
skypeweb_present_uri_as_filetransfer(SkypeWebAccount * sa,const gchar * uri,const gchar * from)523 skypeweb_present_uri_as_filetransfer(SkypeWebAccount *sa, const gchar *uri, const gchar *from)
524 {
525 	SkypeWebFileTransfer *swft;
526 	PurpleHttpRequest *request;
527 
528 	swft = g_new0(SkypeWebFileTransfer, 1);
529 	swft->sa = sa;
530 	swft->url = g_strdup(uri);
531 	swft->from = g_strdup(from);
532 
533 	request = purple_http_request_new(uri);
534 	if (!g_str_has_suffix(uri, "/views/original/status")) {
535 		purple_http_request_set_url_printf(request, "%s%s", uri, "/views/original/status");
536 	}
537 	purple_http_request_set_keepalive_pool(request, sa->keepalive_pool);
538 	purple_http_request_header_set_printf(request, "Cookie", "skypetoken_asm=%s", sa->skype_token);
539 	purple_http_request_header_set(request, "Accept", "*/*");
540 	purple_http_request(sa->pc, request, skypeweb_got_file_info, swft);
541 	purple_http_request_unref(request);
542 }
543 
544 static void
got_file_send_progress(PurpleHttpConnection * http_conn,PurpleHttpResponse * response,gpointer user_data)545 got_file_send_progress(PurpleHttpConnection *http_conn, PurpleHttpResponse *response, gpointer user_data)
546 {
547 	SkypeWebFileTransfer *swft = user_data;
548 	PurpleXfer *xfer = swft->xfer;
549 	SkypeWebAccount *sa = swft->sa;
550 	JsonParser *parser;
551 	JsonNode *node;
552 	JsonObject *obj;
553 	const gchar *data;
554 	gsize len;
555 
556 	data = purple_http_response_get_data(response, &len);
557 
558 	//{"content_length":0,"content_full_length":0,"view_length":0,"content_state":"no content","view_state":"none","view_location":"https://nus1-api.asm.skype.com/v1/objects/0-cus-d1-61121cfae8cf601944627a66afdb77ad/views/original","status_location":"https://nus1-api.asm.skype.com/v1/objects/0-cus-d1-61121cfae8cf601944627a66afdb77ad/views/original/status"}
559 	parser = json_parser_new();
560 	if (!json_parser_load_from_data(parser, data, len, NULL)) {
561 		//probably bad
562 		return;
563 	}
564 	node = json_parser_get_root(parser);
565 	if (node == NULL || json_node_get_node_type(node) != JSON_NODE_OBJECT) {
566 		//probably bad
567 		return;
568 	}
569 	obj = json_node_get_object(node);
570 
571 
572 	if (json_object_has_member(obj, "status_location")) {
573 		g_free(swft->url);
574 		swft->url = g_strdup(json_object_get_string_member(obj, "status_location"));
575 	}
576 
577 	if (json_object_has_member(obj, "content_state") && purple_strequal(json_object_get_string_member(obj, "content_state"), "ready")) {
578 		PurpleXmlNode *uriobject = purple_xmlnode_new("URIObject");
579 		PurpleXmlNode *title = purple_xmlnode_new_child(uriobject, "Title");
580 		PurpleXmlNode *description = purple_xmlnode_new_child(uriobject, "Description");
581 		PurpleXmlNode *anchor = purple_xmlnode_new_child(uriobject, "a");
582 		PurpleXmlNode *originalname = purple_xmlnode_new_child(uriobject, "OriginalName");
583 		PurpleXmlNode *filesize = purple_xmlnode_new_child(uriobject, "FileSize");
584 		gchar *message, *temp;
585 		//We finally did it!
586 		// May the pesants rejoyce
587 		purple_xfer_set_completed(xfer, TRUE);
588 
589 		// Don't forget to let the other end know about it
590 
591 		purple_xmlnode_set_attrib(uriobject, "type", "File.1");
592 		temp = g_strconcat("https://" SKYPEWEB_XFER_HOST "/v1/objects/", purple_url_encode(swft->id), NULL);
593 		purple_xmlnode_set_attrib(uriobject, "uri", temp);
594 		g_free(temp);
595 		temp = g_strconcat("https://" SKYPEWEB_XFER_HOST "/v1/objects/", purple_url_encode(swft->id), "/views/thumbnail", NULL);
596 		purple_xmlnode_set_attrib(uriobject, "url_thumbnail", temp);
597 		g_free(temp);
598 		purple_xmlnode_insert_data(title, purple_xfer_get_filename(xfer), -1);
599 		purple_xmlnode_insert_data(description, "Description: ", -1);
600 		temp = g_strconcat("https://login.skype.com/login/sso?go=webclient.xmm&docid=", purple_url_encode(swft->id), NULL);
601 		purple_xmlnode_set_attrib(anchor, "href", temp);
602 		purple_xmlnode_insert_data(anchor, temp, -1);
603 		g_free(temp);
604 		purple_xmlnode_set_attrib(originalname, "v", purple_xfer_get_filename(xfer));
605 		temp = g_strdup_printf("%" G_GSIZE_FORMAT, (gsize) purple_xfer_get_size(xfer));
606 		purple_xmlnode_set_attrib(filesize, "v", temp);
607 		g_free(temp);
608 
609 		temp = purple_xmlnode_to_str(uriobject, NULL);
610 		message = purple_strreplace(temp, "'", "\"");
611 		g_free(temp);
612 #if PURPLE_VERSION_CHECK(3, 0, 0)
613 		PurpleMessage *msg = purple_message_new_outgoing(swft->from, message, PURPLE_MESSAGE_SEND);
614 		skypeweb_send_im(sa->pc, msg);
615 		purple_message_destroy(msg);
616 #else
617 		skypeweb_send_im(sa->pc, swft->from, message, PURPLE_MESSAGE_SEND);
618 #endif
619 		g_free(message);
620 
621 		skypeweb_free_xfer(xfer);
622 		purple_xfer_unref(xfer);
623 
624 		purple_xmlnode_free(uriobject);
625 		g_object_unref(parser);
626 		return;
627 	}
628 
629 
630 	g_object_unref(parser);
631 
632 	// probably good
633 }
634 
635 static gboolean
poll_file_send_progress(gpointer user_data)636 poll_file_send_progress(gpointer user_data)
637 {
638 	SkypeWebFileTransfer *swft = user_data;
639 	SkypeWebAccount *sa = swft->sa;
640 	PurpleHttpRequest *request;
641 
642 	request = purple_http_request_new(swft->url);
643 	purple_http_request_set_keepalive_pool(request, sa->keepalive_pool);
644 	purple_http_request_header_set_printf(request, "Cookie", "skypetoken_asm=%s", sa->skype_token);
645 	purple_http_request_header_set(request, "Accept", "*/*");
646 	purple_http_request(sa->pc, request, got_file_send_progress, swft);
647 	purple_http_request_unref(request);
648 
649 	return FALSE;
650 }
651 
652 static void
skypeweb_xfer_send_contents_reader(PurpleHttpConnection * con,gchar * buf,size_t offset,size_t len,gpointer user_data,PurpleHttpContentReaderCb cb)653 skypeweb_xfer_send_contents_reader(PurpleHttpConnection *con, gchar *buf, size_t offset, size_t len, gpointer user_data, PurpleHttpContentReaderCb cb)
654 {
655 	SkypeWebFileTransfer *swft = user_data;
656 	PurpleXfer *xfer = swft->xfer;
657 	gsize read;
658 
659 	purple_debug_info("skypeweb", "Asked %" G_GSIZE_FORMAT " bytes from offset %" G_GSIZE_FORMAT "\n", len, offset);
660 	purple_xfer_set_bytes_sent(xfer, offset);
661 	read = purple_xfer_read_file(xfer, (guchar *)buf, len);
662 	purple_debug_info("skypeweb", "Read %" G_GSIZE_FORMAT " bytes\n", read);
663 
664 	cb(con, TRUE, read != len, read);
665 }
666 
667 static void
skypeweb_xfer_send_done(PurpleHttpConnection * conn,PurpleHttpResponse * resp,gpointer user_data)668 skypeweb_xfer_send_done(PurpleHttpConnection *conn, PurpleHttpResponse *resp, gpointer user_data)
669 {
670 	gsize len;
671 	const gchar *data = purple_http_response_get_data(resp, &len);
672 	const gchar *error = purple_http_response_get_error(resp);
673 	int code = purple_http_response_get_code(resp);
674 	purple_debug_info("skypeweb", "Finished [%d]: %s\n", code, error);
675 	purple_debug_info("skypeweb", "Server message: %s\n", data);
676 	g_timeout_add_seconds(1, poll_file_send_progress, user_data);
677 }
678 
679 static void
skypeweb_xfer_send_watcher(PurpleHttpConnection * http_conn,gboolean state,int processed,int total,gpointer user_data)680 skypeweb_xfer_send_watcher(PurpleHttpConnection *http_conn, gboolean state, int processed, int total, gpointer user_data)
681 {
682 	SkypeWebFileTransfer *swft = user_data;
683 	PurpleXfer *xfer = swft->xfer;
684 	if (!state) purple_xfer_update_progress(xfer);
685 }
686 
687 static void
skypeweb_xfer_send_begin(gpointer user_data)688 skypeweb_xfer_send_begin(gpointer user_data)
689 {
690 	SkypeWebFileTransfer *swft = user_data;
691 	PurpleXfer *xfer = swft->xfer;
692 	SkypeWebAccount *sa = swft->sa;
693 	PurpleHttpConnection *http_conn;
694 
695 	PurpleHttpRequest *request = purple_http_request_new("");
696 	purple_http_request_set_url_printf(request, "https://%s/v1/objects/%s/content/original", SKYPEWEB_XFER_HOST, purple_url_encode(swft->id));
697 	purple_http_request_set_method(request, "PUT");
698 	purple_http_request_header_set(request, "Host", SKYPEWEB_XFER_HOST);
699 	purple_http_request_header_set(request, "Content-Type", "multipart/form-data");
700 	purple_http_request_header_set_printf(request, "Content-Length", "%" G_GSIZE_FORMAT, (gsize) purple_xfer_get_size(xfer));
701 	purple_http_request_header_set_printf(request, "Authorization", "skype_token %s", sa->skype_token);
702 	purple_http_request_set_contents_reader(request, skypeweb_xfer_send_contents_reader, purple_xfer_get_size(xfer), user_data);
703 	purple_http_request_set_http11(request, TRUE);
704 	purple_xfer_start(xfer, -1, NULL, 0);
705 	http_conn = purple_http_request(sa->pc, request, skypeweb_xfer_send_done, user_data);
706 	purple_http_conn_set_progress_watcher(http_conn, skypeweb_xfer_send_watcher, user_data, 1);
707 
708 	purple_http_request_unref(request);
709 }
710 
711 static void
skypeweb_got_object_for_file(PurpleHttpConnection * http_conn,PurpleHttpResponse * response,gpointer user_data)712 skypeweb_got_object_for_file(PurpleHttpConnection *http_conn, PurpleHttpResponse *response, gpointer user_data)
713 {
714 	SkypeWebFileTransfer *swft = user_data;
715 	PurpleXfer *xfer = swft->xfer;
716 	JsonParser *parser;
717 	JsonNode *node;
718 	JsonObject *obj;
719 	const gchar *data;
720 	gsize len;
721 
722 	data = purple_http_response_get_data(response, &len);
723 
724 	//Get back {"id": "0-cus-d3-deadbeefdeadbeef012345678"}
725 	parser = json_parser_new();
726 	if (!json_parser_load_from_data(parser, data, len, NULL)) {
727 		g_free(swft->from);
728 		g_free(swft);
729 		g_object_unref(parser);
730 		return;
731 	}
732 	node = json_parser_get_root(parser);
733 	if (node == NULL || json_node_get_node_type(node) != JSON_NODE_OBJECT) {
734 		g_free(swft->from);
735 		g_free(swft);
736 		g_object_unref(parser);
737 		purple_xfer_cancel_local(xfer);
738 		return;
739 	}
740 	obj = json_node_get_object(node);
741 
742 	if (!json_object_has_member(obj, "id")) {
743 		g_free(swft->from);
744 		g_free(swft);
745 		g_object_unref(parser);
746 		purple_xfer_cancel_local(xfer);
747 		return;
748 	}
749 
750 	swft->id = g_strdup(json_object_get_string_member(obj, "id"));
751 	swft->url = g_strconcat("https://" SKYPEWEB_XFER_HOST "/v1/objects/", purple_url_encode(swft->id), "/views/original/status", NULL);
752 
753 	g_object_unref(parser);
754 
755 	//Send the data
756 
757 	//can't use fetch_url_request because it doesn't handle binary data
758 	skypeweb_xfer_send_begin(user_data);
759 
760 }
761 
762 static void
skypeweb_xfer_send_init(PurpleXfer * xfer)763 skypeweb_xfer_send_init(PurpleXfer *xfer)
764 {
765 	PurpleConnection *pc = purple_account_get_connection(purple_xfer_get_account(xfer));
766 	SkypeWebAccount *sa = purple_connection_get_protocol_data(pc);
767 	gchar *basename = g_path_get_basename(purple_xfer_get_local_filename(xfer));
768 	gchar *id, *post;
769 	SkypeWebFileTransfer *swft = purple_xfer_get_protocol_data(xfer);
770 	JsonObject *obj = json_object_new();
771 	JsonObject *permissions = json_object_new();
772 	JsonArray *userpermissions = json_array_new();
773 	PurpleHttpRequest *request;
774 
775 	purple_xfer_set_filename(xfer, basename);
776 	purple_xfer_ref(xfer);
777 
778 	json_object_set_string_member(obj, "type", "sharing/file");
779 	json_object_set_string_member(obj, "filename", basename);
780 
781 	id = g_strconcat(skypeweb_user_url_prefix(swft->from), swft->from, NULL);
782 	json_array_add_string_element(userpermissions, "read");
783 	json_object_set_array_member(permissions, id, userpermissions);
784 	json_object_set_object_member(obj, "permissions", permissions);
785 
786 	post = skypeweb_jsonobj_to_string(obj);
787 	//POST to api.asm.skype.com  /v1/objects
788 	//{"type":"sharing/file","permissions":{"8:eionrobb":["read"]},"filename":"GiantLobsterMoose.txt"}
789 
790 	request = purple_http_request_new("https://" SKYPEWEB_XFER_HOST "/v1/objects");
791 	purple_http_request_set_method(request, "POST");
792 	purple_http_request_set_keepalive_pool(request, sa->keepalive_pool);
793 	purple_http_request_header_set_printf(request, "Authorization", "skype_token %s", sa->skype_token); //slightly different to normal!
794 	purple_http_request_header_set(request, "Content-Type", "application/json");
795 	purple_http_request_header_set(request, "X-Client-Version", SKYPEWEB_CLIENTINFO_VERSION);
796 	purple_http_request_set_contents(request, post, -1);
797 	purple_http_request(sa->pc, request, skypeweb_got_object_for_file, swft);
798 	purple_http_request_unref(request);
799 
800 	g_free(post);
801 	json_object_unref(obj);
802 	g_free(id);
803 	g_free(basename);
804 }
805 
806 PurpleXfer *
skypeweb_new_xfer(PurpleProtocolXfer * prplxfer,PurpleConnection * pc,const char * who)807 skypeweb_new_xfer(
808 #if PURPLE_VERSION_CHECK(3, 0, 0)
809 PurpleProtocolXfer *prplxfer,
810 #endif
811 PurpleConnection *pc, const char *who)
812 {
813 	SkypeWebAccount *sa = purple_connection_get_protocol_data(pc);
814 	PurpleXfer *xfer;
815 	SkypeWebFileTransfer *swft;
816 
817 	xfer = purple_xfer_new(sa->account, PURPLE_XFER_TYPE_SEND, who);
818 
819 	swft = g_new0(SkypeWebFileTransfer, 1);
820 	swft->sa = sa;
821 	swft->from = g_strdup(who);
822 	swft->xfer = xfer;
823 	purple_xfer_set_protocol_data(xfer, swft);
824 
825 	purple_xfer_set_init_fnc(xfer, skypeweb_xfer_send_init);
826 	//purple_xfer_set_write_fnc(xfer, skypeweb_xfer_send_write);
827 	//purple_xfer_set_end_fnc(xfer, skypeweb_xfer_send_end);
828 	purple_xfer_set_request_denied_fnc(xfer, skypeweb_free_xfer);
829 	purple_xfer_set_cancel_send_fnc(xfer, skypeweb_free_xfer);
830 
831 	return xfer;
832 }
833 
834 void
skypeweb_send_file(PurpleProtocolXfer * prplxfer,PurpleConnection * pc,const gchar * who,const gchar * filename)835 skypeweb_send_file(
836 #if PURPLE_VERSION_CHECK(3, 0, 0)
837 PurpleProtocolXfer *prplxfer,
838 #endif
839 PurpleConnection *pc, const gchar *who, const gchar *filename)
840 {
841 	PurpleXfer *xfer = skypeweb_new_xfer(
842 #if PURPLE_VERSION_CHECK(3, 0, 0)
843 		prplxfer,
844 #endif
845 		pc, who);
846 
847 	if (filename && *filename)
848 		purple_xfer_request_accepted(xfer, filename);
849 	else
850 		purple_xfer_request(xfer);
851 }
852 
853 gboolean
skypeweb_can_receive_file(PurpleProtocolXfer * prplxfer,PurpleConnection * pc,const gchar * who)854 skypeweb_can_receive_file(
855 #if PURPLE_VERSION_CHECK(3, 0, 0)
856 PurpleProtocolXfer *prplxfer,
857 #endif
858 PurpleConnection *pc, const gchar *who)
859 {
860 	if (!who || g_str_equal(who, purple_account_get_username(purple_connection_get_account(pc))))
861 		return FALSE;
862 
863 	return TRUE;
864 }
865 
866 
867 static void
skypeweb_got_self_details(SkypeWebAccount * sa,JsonNode * node,gpointer user_data)868 skypeweb_got_self_details(SkypeWebAccount *sa, JsonNode *node, gpointer user_data)
869 {
870 	JsonObject *userobj;
871 	const gchar *old_alias;
872 	const gchar *displayname = NULL;
873 	const gchar *username;
874 
875 	if (node == NULL || json_node_get_node_type(node) != JSON_NODE_OBJECT)
876 		return;
877 	userobj = json_node_get_object(node);
878 
879 	username = json_object_get_string_member(userobj, "username");
880 	g_free(sa->username); sa->username = g_strdup(username);
881 	purple_connection_set_display_name(sa->pc, sa->username);
882 
883 	old_alias = purple_account_get_private_alias(sa->account);
884 	if (!old_alias || !*old_alias) {
885 		if (json_object_has_member(userobj, "displayname"))
886 			displayname = json_object_get_string_member(userobj, "displayname");
887 		if (!displayname || purple_strequal(displayname, username))
888 			displayname = json_object_get_string_member(userobj, "firstname");
889 
890 		if (displayname)
891 			purple_account_set_private_alias(sa->account, displayname);
892 	}
893 
894 	if (!PURPLE_CONNECTION_IS_CONNECTED(sa->pc)) {
895 		skypeweb_do_all_the_things(sa);
896 	}
897 
898 	skypeweb_gather_self_properties(sa);
899 }
900 
901 
902 void
skypeweb_get_self_details(SkypeWebAccount * sa)903 skypeweb_get_self_details(SkypeWebAccount *sa)
904 {
905 	skypeweb_post_or_get(sa, SKYPEWEB_METHOD_GET | SKYPEWEB_METHOD_SSL, SKYPEWEB_CONTACTS_HOST, "/users/self/profile", NULL, skypeweb_got_self_details, NULL, TRUE);
906 }
907 
908 
909 
910 
911 
912 
913 
914 
915 
916 void
skypeweb_search_results_add_buddy(PurpleConnection * pc,GList * row,void * user_data)917 skypeweb_search_results_add_buddy(PurpleConnection *pc, GList *row, void *user_data)
918 {
919 	PurpleAccount *account = purple_connection_get_account(pc);
920 
921 	if (!purple_blist_find_buddy(account, g_list_nth_data(row, 0)))
922 		purple_blist_request_add_buddy(account, g_list_nth_data(row, 0), "Skype", g_list_nth_data(row, 1));
923 }
924 
925 void
skypeweb_received_contacts(SkypeWebAccount * sa,PurpleXmlNode * contacts)926 skypeweb_received_contacts(SkypeWebAccount *sa, PurpleXmlNode *contacts)
927 {
928 	PurpleNotifySearchResults *results;
929 	PurpleNotifySearchColumn *column;
930 
931 	PurpleXmlNode *contact;
932 
933 	results = purple_notify_searchresults_new();
934 	if (results == NULL) {
935 		return;
936 	}
937 
938 	/* columns: Friend ID, Name */
939 	column = purple_notify_searchresults_column_new(_("Skype Name"));
940 	purple_notify_searchresults_column_add(results, column);
941 	column = purple_notify_searchresults_column_new(_("Display Name"));
942 	purple_notify_searchresults_column_add(results, column);
943 
944 
945 	purple_notify_searchresults_button_add(results,
946 			PURPLE_NOTIFY_BUTTON_ADD,
947 			skypeweb_search_results_add_buddy);
948 
949 	for(contact = purple_xmlnode_get_child(contacts, "c"); contact;
950 		contact = purple_xmlnode_get_next_twin(contact))
951 	{
952 		GList *row = NULL;
953 
954 		gchar *contact_id = g_strdup(purple_xmlnode_get_attrib(contact, "s"));
955 		gchar *contact_name = g_strdup(purple_xmlnode_get_attrib(contact, "f"));
956 
957 		row = g_list_append(row, contact_id);
958 		row = g_list_append(row, contact_name);
959 
960 		purple_notify_searchresults_row_add(results, row);
961 	}
962 
963 	purple_notify_searchresults(sa->pc, _("Received contacts"), NULL, NULL, results, NULL, NULL);
964 }
965 
966 static PurpleNotifySearchResults*
create_search_results(JsonNode * node,gint * olength)967 create_search_results(JsonNode *node, gint *olength)
968 {
969 	PurpleNotifySearchColumn *column;
970 	gint index, length;
971 	JsonObject *response = NULL;
972 	JsonArray *resultsarray = NULL;
973 
974 	response = json_node_get_object(node);
975 	resultsarray = json_object_get_array_member(response, "results");
976 	length = json_array_get_length(resultsarray);
977 
978 	PurpleNotifySearchResults *results = purple_notify_searchresults_new();
979 	if (results == NULL || length == 0)
980 	{
981 		if (olength)
982 		{
983 			*olength = 0;
984 		}
985 		return NULL;
986 	}
987 
988 	/* columns: Friend ID, Name, Network */
989 	column = purple_notify_searchresults_column_new(_("Skype Name"));
990 	purple_notify_searchresults_column_add(results, column);
991 	column = purple_notify_searchresults_column_new(_("Display Name"));
992 	purple_notify_searchresults_column_add(results, column);
993 	column = purple_notify_searchresults_column_new(_("City"));
994 	purple_notify_searchresults_column_add(results, column);
995 	column = purple_notify_searchresults_column_new(_("Country"));
996 	purple_notify_searchresults_column_add(results, column);
997 
998 	purple_notify_searchresults_button_add(results,
999 			PURPLE_NOTIFY_BUTTON_ADD,
1000 			skypeweb_search_results_add_buddy);
1001 
1002 	for(index = 0; index < length; index++)
1003 	{
1004 		JsonObject *result = json_array_get_object_element(resultsarray, index);
1005 		JsonObject *skypecontact = json_object_get_object_member(result, "nodeProfileData");
1006 
1007 		/* the row in the search results table */
1008 		/* prepend to it backwards then reverse to speed up adds */
1009 		GList *row = NULL;
1010 
1011 #define add_skypecontact_row(value) (\
1012 		row = g_list_prepend(row, \
1013 			!json_object_has_member(skypecontact, (value)) ? NULL : \
1014 			g_strdup(json_object_get_string_member(skypecontact, (value)))\
1015 		) \
1016 )
1017 		add_skypecontact_row("skypeId");
1018 		add_skypecontact_row("name");
1019 		add_skypecontact_row("city");
1020 		add_skypecontact_row("country");
1021 
1022 		row = g_list_reverse(row);
1023 
1024 		purple_notify_searchresults_row_add(results, row);
1025 	}
1026 
1027 	if (olength)
1028 	{
1029 		*olength = length;
1030 	}
1031 	return results;
1032 }
1033 
1034 static void
skypeweb_search_users_text_cb(SkypeWebAccount * sa,JsonNode * node,gpointer user_data)1035 skypeweb_search_users_text_cb(SkypeWebAccount *sa, JsonNode *node, gpointer user_data)
1036 {
1037 	gint length;
1038 	gchar *search_term = user_data;
1039 	PurpleNotifySearchResults *results = create_search_results(node, &length);
1040 
1041 	if (results == NULL || length == 0)
1042 	{
1043 		gchar *primary_text = g_strdup_printf("Your search for the user \"%s\" returned no results", search_term);
1044 		purple_notify_warning(sa->pc, _("No users found"), primary_text, "", purple_request_cpar_from_connection(sa->pc));
1045 		g_free(primary_text);
1046 		g_free(search_term);
1047 		return;
1048 	}
1049 
1050 	purple_notify_searchresults(sa->pc, NULL, search_term, NULL, results, NULL, NULL);
1051 }
1052 
1053 static void
skypeweb_contact_suggestions_received_cb(SkypeWebAccount * sa,JsonNode * node,gpointer user_data)1054 skypeweb_contact_suggestions_received_cb(SkypeWebAccount *sa, JsonNode *node, gpointer user_data)
1055 {
1056 	gint length;
1057 	PurpleNotifySearchResults *results = create_search_results(node, &length);
1058 
1059 	if (results == NULL || length == 0)
1060 	{
1061 		purple_notify_warning(sa->pc, _("No results"), _("There are no contact suggestions available for you"), "", purple_request_cpar_from_connection(sa->pc));
1062 		return;
1063 	}
1064 
1065 	purple_notify_searchresults(sa->pc, _("Contact suggestions"), NULL, NULL, results, NULL, NULL);
1066 }
1067 
1068 void
skypeweb_search_users_text(gpointer user_data,const gchar * text)1069 skypeweb_search_users_text(gpointer user_data, const gchar *text)
1070 {
1071 	SkypeWebAccount *sa = user_data;
1072 	GString *url = g_string_new("/search/v1.1/namesearch/swx/?");
1073 
1074 	g_string_append_printf(url, "searchstring=%s&", purple_url_encode(text));
1075 	g_string_append(url, "requestId=1&");
1076 
1077 	skypeweb_post_or_get(sa, SKYPEWEB_METHOD_GET | SKYPEWEB_METHOD_SSL, SKYPEWEB_GRAPH_HOST, url->str, NULL, skypeweb_search_users_text_cb, g_strdup(text), FALSE);
1078 
1079 	g_string_free(url, TRUE);
1080 }
1081 
1082 void
skypeweb_search_users(PurpleProtocolAction * action)1083 skypeweb_search_users(PurpleProtocolAction *action)
1084 {
1085 	PurpleConnection *pc = purple_protocol_action_get_connection(action);
1086 	SkypeWebAccount *sa = purple_connection_get_protocol_data(pc);
1087 
1088 	purple_request_input(pc, "Search for Skype Friends",
1089 					   "Search for Skype Friends",
1090 					   NULL,
1091 					   NULL, FALSE, FALSE, NULL,
1092 					   _("_Search"), G_CALLBACK(skypeweb_search_users_text),
1093 					   _("_Cancel"), NULL,
1094 					   purple_request_cpar_from_connection(pc),
1095 					   sa);
1096 
1097 }
1098 
1099 void
skypeweb_contact_suggestions(PurpleProtocolAction * action)1100 skypeweb_contact_suggestions(PurpleProtocolAction *action)
1101 {
1102 	PurpleConnection *pc = purple_protocol_action_get_connection(action);
1103 	SkypeWebAccount *sa = purple_connection_get_protocol_data(pc);
1104 
1105 	GString *url = g_string_new("/v1.1/recommend?requestId=1&locale=en-US&count=20");
1106 
1107 	skypeweb_post_or_get(sa, SKYPEWEB_METHOD_GET | SKYPEWEB_METHOD_SSL, SKYPEWEB_DEFAULT_CONTACT_SUGGESTIONS_HOST, url->str, NULL, skypeweb_contact_suggestions_received_cb, 0, FALSE);
1108 
1109 	g_string_free(url, TRUE);
1110 }
1111 
1112 static void
skypeweb_got_friend_profiles(SkypeWebAccount * sa,JsonNode * node,gpointer user_data)1113 skypeweb_got_friend_profiles(SkypeWebAccount *sa, JsonNode *node, gpointer user_data)
1114 {
1115 	JsonArray *contacts;
1116 	PurpleBuddy *buddy;
1117 	SkypeWebBuddy *sbuddy;
1118 	gint index, length;
1119 
1120 	if (node == NULL || json_node_get_node_type(node) != JSON_NODE_ARRAY)
1121 		return;
1122 	contacts = json_node_get_array(node);
1123 	length = json_array_get_length(contacts);
1124 
1125 	for(index = 0; index < length; index++)
1126 	{
1127 		JsonObject *contact = json_array_get_object_element(contacts, index);
1128 
1129 		const gchar *username = json_object_get_string_member(contact, "username");
1130 		const gchar *new_avatar;
1131 
1132 		buddy = purple_blist_find_buddy(sa->account, username);
1133 		if (!buddy)
1134 			continue;
1135 		sbuddy = purple_buddy_get_protocol_data(buddy);
1136 		if (sbuddy == NULL) {
1137 			sbuddy = g_new0(SkypeWebBuddy, 1);
1138 			purple_buddy_set_protocol_data(buddy, sbuddy);
1139 			sbuddy->skypename = g_strdup(username);
1140 			sbuddy->sa = sa;
1141 		}
1142 
1143 		g_free(sbuddy->display_name); sbuddy->display_name = g_strdup(json_object_get_string_member(contact, "displayname"));
1144 		purple_serv_got_alias(sa->pc, username, sbuddy->display_name);
1145 		if (json_object_has_member(contact, "lastname")) {
1146 			gchar *fullname = g_strconcat(json_object_get_string_member(contact, "firstname"), " ", json_object_get_string_member(contact, "lastname"), NULL);
1147 
1148 			purple_buddy_set_server_alias(buddy, fullname);
1149 
1150 			g_free(fullname);
1151 		} else {
1152 			purple_buddy_set_server_alias(buddy, json_object_get_string_member(contact, "firstname"));
1153 		}
1154 
1155 		new_avatar = json_object_get_string_member(contact, "avatarUrl");
1156 		if (new_avatar && *new_avatar && (!sbuddy->avatar_url || !g_str_equal(sbuddy->avatar_url, new_avatar))) {
1157 			g_free(sbuddy->avatar_url);
1158 			sbuddy->avatar_url = g_strdup(new_avatar);
1159 			skypeweb_get_icon(buddy);
1160 		}
1161 
1162 		g_free(sbuddy->mood); sbuddy->mood = g_strdup(json_object_get_string_member(contact, "mood"));
1163 	}
1164 }
1165 
1166 void
skypeweb_get_friend_profiles(SkypeWebAccount * sa,GSList * contacts)1167 skypeweb_get_friend_profiles(SkypeWebAccount *sa, GSList *contacts)
1168 {
1169 	const gchar *profiles_url = "/users/self/contacts/profiles";
1170 	GString *postdata;
1171 	GSList *cur = contacts;
1172 
1173 	if (contacts == NULL)
1174 		return;
1175 
1176 	postdata = g_string_new("");
1177 
1178 	do {
1179 		g_string_append_printf(postdata, "&contacts[]=%s", purple_url_encode(cur->data));
1180 	} while((cur = g_slist_next(cur)));
1181 
1182 	skypeweb_post_or_get(sa, SKYPEWEB_METHOD_POST | SKYPEWEB_METHOD_SSL, SKYPEWEB_CONTACTS_HOST, profiles_url, postdata->str, skypeweb_got_friend_profiles, NULL, TRUE);
1183 
1184 	g_string_free(postdata, TRUE);
1185 }
1186 
1187 
1188 static void
skypeweb_got_info(SkypeWebAccount * sa,JsonNode * node,gpointer user_data)1189 skypeweb_got_info(SkypeWebAccount *sa, JsonNode *node, gpointer user_data)
1190 {
1191 	gchar *username = user_data;
1192 	PurpleNotifyUserInfo *user_info;
1193 	JsonObject *userobj;
1194 	PurpleBuddy *buddy;
1195 	SkypeWebBuddy *sbuddy;
1196 
1197 	if (node == NULL)
1198 		return;
1199 	if (json_node_get_node_type(node) == JSON_NODE_ARRAY)
1200 		node = json_array_get_element(json_node_get_array(node), 0);
1201 	if (json_node_get_node_type(node) != JSON_NODE_OBJECT)
1202 		return;
1203 	userobj = json_node_get_object(node);
1204 
1205 	user_info = purple_notify_user_info_new();
1206 
1207 #define _SKYPE_USER_INFO(prop, key) if (prop && json_object_has_member(userobj, (prop)) && !json_object_get_null_member(userobj, (prop))) \
1208 	purple_notify_user_info_add_pair_html(user_info, _(key), json_object_get_string_member(userobj, (prop)));
1209 
1210 	_SKYPE_USER_INFO("firstname", "First Name");
1211 	_SKYPE_USER_INFO("lastname", "Last Name");
1212 	_SKYPE_USER_INFO("birthday", "Birthday");
1213 	//_SKYPE_USER_INFO("gender", "Gender");
1214 	if (json_object_has_member(userobj, "gender") && !json_object_get_null_member(userobj, "gender")) {
1215 		const gchar *gender_output = _("Unknown");
1216 
1217 		// Can be presented as either a string of a number or as a number argh
1218 		if (json_node_get_value_type(json_object_get_member(userobj, "gender")) == G_TYPE_STRING) {
1219 			const gchar *gender = json_object_get_string_member(userobj, "gender");
1220 			if (gender && *gender == '1') {
1221 				gender_output = _("Male");
1222 			} else if (gender && *gender == '2') {
1223 				gender_output = _("Female");
1224 			}
1225 		} else {
1226 			gint64 gender = json_object_get_int_member(userobj, "gender");
1227 			if (gender == 1) {
1228 				gender_output = _("Male");
1229 			} else if (gender == 2) {
1230 				gender_output = _("Female");
1231 			}
1232 		}
1233 
1234 		purple_notify_user_info_add_pair_html(user_info, _("Gender"), gender_output);
1235 	}
1236 	_SKYPE_USER_INFO("language", "Language");
1237 	_SKYPE_USER_INFO("country", "Country");
1238 	_SKYPE_USER_INFO("province", "Province");
1239 	_SKYPE_USER_INFO("city", "City");
1240 	_SKYPE_USER_INFO("homepage", "Homepage");
1241 	_SKYPE_USER_INFO("about", "About");
1242 	_SKYPE_USER_INFO("jobtitle", "Job Title");
1243 	_SKYPE_USER_INFO("phoneMobile", "Phone - Mobile");
1244 	_SKYPE_USER_INFO("phoneHome", "Phone - Home");
1245 	_SKYPE_USER_INFO("phoneOffice", "Phone - Office");
1246 	//_SKYPE_USER_INFO("mood", "Mood");
1247 	//_SKYPE_USER_INFO("richMood", "Mood");
1248 	//_SKYPE_USER_INFO("avatarUrl", "Avatar");
1249 
1250 	buddy = purple_blist_find_buddy(sa->account, username);
1251 	if (buddy) {
1252 		sbuddy = purple_buddy_get_protocol_data(buddy);
1253 		if (sbuddy == NULL) {
1254 			sbuddy = g_new0(SkypeWebBuddy, 1);
1255 			purple_buddy_set_protocol_data(buddy, sbuddy);
1256 			sbuddy->skypename = g_strdup(username);
1257 			sbuddy->sa = sa;
1258 		}
1259 
1260 		//At the moment, "mood" field is present but always null via this call. Do not clear it.
1261 		if (json_object_has_member(userobj, ("mood")) && !json_object_get_null_member(userobj, ("mood"))) {
1262 			g_free(sbuddy->mood); sbuddy->mood = g_strdup(json_object_get_string_member(userobj, "mood"));
1263 		}
1264 	}
1265 
1266 	purple_notify_userinfo(sa->pc, username, user_info, NULL, NULL);
1267 
1268 	g_free(username);
1269 }
1270 
1271 void
skypeweb_get_info(PurpleConnection * pc,const gchar * username)1272 skypeweb_get_info(PurpleConnection *pc, const gchar *username)
1273 {
1274 	SkypeWebAccount *sa = purple_connection_get_protocol_data(pc);
1275 	gchar *post;
1276 	const gchar *url = "/users/batch/profiles";
1277 	JsonObject *obj;
1278 	JsonArray *usernames_array;
1279 
1280 	obj = json_object_new();
1281 	usernames_array = json_array_new();
1282 
1283 	json_array_add_string_element(usernames_array, username);
1284 	json_object_set_array_member(obj, "usernames", usernames_array);
1285 	post = skypeweb_jsonobj_to_string(obj);
1286 
1287 	skypeweb_post_or_get(sa, SKYPEWEB_METHOD_POST | SKYPEWEB_METHOD_SSL, SKYPEWEB_CONTACTS_HOST, url, post, skypeweb_got_info, g_strdup(username), TRUE);
1288 
1289 	g_free(post);
1290 	json_object_unref(obj);
1291 }
1292 
1293 void
skypeweb_get_friend_profile(SkypeWebAccount * sa,const gchar * who)1294 skypeweb_get_friend_profile(SkypeWebAccount *sa, const gchar *who)
1295 {
1296 	GSList *contacts = NULL;
1297 	gchar *whodup;
1298 
1299 	g_return_if_fail(sa && who && *who);
1300 
1301 	whodup = g_strdup(who);
1302 	contacts = g_slist_prepend(contacts, whodup);
1303 
1304 	skypeweb_get_friend_profiles(sa, contacts);
1305 
1306 	g_free(contacts);
1307 	g_free(whodup);
1308 }
1309 
1310 static void
skypeweb_get_friend_list_cb(SkypeWebAccount * sa,JsonNode * node,gpointer user_data)1311 skypeweb_get_friend_list_cb(SkypeWebAccount *sa, JsonNode *node, gpointer user_data)
1312 {
1313 	JsonObject *obj;
1314 	JsonArray *contacts;
1315 	PurpleGroup *group = NULL;
1316 	GSList *users_to_fetch = NULL;
1317 	guint index, length;
1318 
1319 	obj = json_node_get_object(node);
1320 	contacts = json_object_get_array_member(obj, "contacts");
1321 	length = json_array_get_length(contacts);
1322 
1323 	for(index = 0; index < length; index++)
1324 	{
1325 		JsonObject *contact = json_array_get_object_element(contacts, index);
1326 		JsonObject *profile = json_object_get_object_member(contact, "profile");
1327 		const gchar *mri = json_object_get_string_member(contact, "mri");
1328 		const gchar *display_name = json_object_get_string_member(contact, "display_name");
1329 		const gchar *avatar_url = NULL;
1330 		gboolean authorized = json_object_get_boolean_member(contact, "authorized");
1331 		gboolean blocked = json_object_get_boolean_member(contact, "blocked");
1332 
1333 		const gchar *mood = json_object_get_string_member(profile, "mood");
1334 		JsonObject *name = json_object_get_object_member(profile, "name");
1335 		const gchar *firstname = json_object_get_string_member(name, "first");
1336 		const gchar *surname = NULL;
1337 
1338 		PurpleBuddy *buddy;
1339 		const gchar *id;
1340 
1341 		if (json_object_has_member(contact, "suggested") && json_object_get_boolean_member(contact, "suggested") && !authorized) {
1342 			// suggested buddies wtf? some kind of advertising?
1343 			continue;
1344 		}
1345 
1346 		id = skypeweb_strip_user_prefix(mri);
1347 
1348 		buddy = purple_blist_find_buddy(sa->account, id);
1349 		if (!buddy)
1350 		{
1351 			if (!group)
1352 			{
1353 				group = purple_blist_find_group("Skype");
1354 				if (!group)
1355 				{
1356 					group = purple_group_new("Skype");
1357 					purple_blist_add_group(group, NULL);
1358 				}
1359 			}
1360 			buddy = purple_buddy_new(sa->account, id, display_name);
1361 			purple_blist_add_buddy(buddy, NULL, group, NULL);
1362 		}
1363 
1364 		if (name && json_object_has_member(name, "surname"))
1365 			surname = json_object_get_string_member(name, "surname");
1366 
1367 		// try to free the sbuddy here. no-op if it's not set before, otherwise prevents a leak.
1368 		skypeweb_buddy_free(buddy);
1369 
1370 		SkypeWebBuddy *sbuddy = g_new0(SkypeWebBuddy, 1);
1371 		sbuddy->skypename = g_strdup(id);
1372 		sbuddy->sa = sa;
1373 		sbuddy->fullname = g_strconcat(firstname, (surname ? " " : NULL), surname, NULL);
1374 		sbuddy->display_name = g_strdup(display_name);
1375 		sbuddy->authorized = authorized;
1376 		sbuddy->blocked = blocked;
1377 		sbuddy->avatar_url = g_strdup(purple_buddy_icons_get_checksum_for_user(buddy));
1378 		sbuddy->mood = g_strdup(mood);
1379 
1380 		sbuddy->buddy = buddy;
1381 		purple_buddy_set_protocol_data(buddy, sbuddy);
1382 
1383 		if (!purple_strequal(purple_buddy_get_local_alias(buddy), sbuddy->display_name)) {
1384 			purple_serv_got_alias(sa->pc, id, sbuddy->display_name);
1385 		}
1386 		if (!purple_strequal(purple_buddy_get_server_alias(buddy), sbuddy->fullname)) {
1387 			purple_buddy_set_server_alias(buddy, sbuddy->fullname);
1388 		}
1389 
1390 		if (json_object_has_member(profile, "avatar_url")) {
1391 			avatar_url = json_object_get_string_member(profile, "avatar_url");
1392 			if (avatar_url && *avatar_url && (!sbuddy->avatar_url || !g_str_equal(sbuddy->avatar_url, avatar_url))) {
1393 				g_free(sbuddy->avatar_url);
1394 				sbuddy->avatar_url = g_strdup(avatar_url);
1395 				skypeweb_get_icon(buddy);
1396 			}
1397 		}
1398 
1399 		if (blocked == TRUE) {
1400 			purple_account_privacy_deny_add(sa->account, id, TRUE);
1401 		} else {
1402 			users_to_fetch = g_slist_prepend(users_to_fetch, sbuddy->skypename);
1403 		}
1404 
1405 		if (purple_strequal(skypeweb_strip_user_prefix(id), sa->primary_member_name)) {
1406 			g_free(sa->self_display_name);
1407 			sa->self_display_name = g_strdup(display_name);
1408 		}
1409 	}
1410 
1411 	if (users_to_fetch)
1412 	{
1413 		//skypeweb_get_friend_profiles(sa, users_to_fetch);
1414 		skypeweb_subscribe_to_contact_status(sa, users_to_fetch);
1415 		g_slist_free(users_to_fetch);
1416 	}
1417 }
1418 
1419 void
skypeweb_get_friend_list(SkypeWebAccount * sa)1420 skypeweb_get_friend_list(SkypeWebAccount *sa)
1421 {
1422 	const gchar *url = "/contacts/v2/users/SELF?delta=&reason=default";
1423 
1424 	skypeweb_post_or_get(sa, SKYPEWEB_METHOD_GET | SKYPEWEB_METHOD_SSL, SKYPEWEB_NEW_CONTACTS_HOST, url, NULL, skypeweb_get_friend_list_cb, NULL, TRUE);
1425 }
1426 
1427 
1428 
1429 void
skypeweb_auth_accept_cb(const gchar * who,gpointer sender)1430 skypeweb_auth_accept_cb(
1431 #if PURPLE_VERSION_CHECK(3, 0, 0)
1432 	const gchar *who,
1433 #endif
1434 	gpointer sender)
1435 {
1436 	PurpleBuddy *buddy = sender;
1437 	SkypeWebAccount *sa;
1438 	gchar *url = NULL;
1439 	GSList *users_to_fetch;
1440 	gchar *buddy_name;
1441 
1442 	sa = purple_connection_get_protocol_data(purple_account_get_connection(purple_buddy_get_account(buddy)));
1443 	buddy_name = g_strdup(purple_buddy_get_name(buddy));
1444 
1445 	url = g_strdup_printf("/contacts/v2/users/SELF/invites/%s%s/accept", skypeweb_user_url_prefix(buddy_name), purple_url_encode(buddy_name));
1446 	skypeweb_post_or_get(sa, SKYPEWEB_METHOD_PUT | SKYPEWEB_METHOD_SSL, SKYPEWEB_NEW_CONTACTS_HOST, url, NULL, NULL, NULL, TRUE);
1447 	g_free(url);
1448 
1449 	// Subscribe to status/message updates
1450 	users_to_fetch = g_slist_prepend(NULL, buddy_name);
1451 	skypeweb_subscribe_to_contact_status(sa, users_to_fetch);
1452 	g_slist_free(users_to_fetch);
1453 	g_free(buddy_name);
1454 }
1455 
1456 void
skypeweb_auth_reject_cb(const gchar * who,gpointer sender)1457 skypeweb_auth_reject_cb(
1458 #if PURPLE_VERSION_CHECK(3, 0, 0)
1459 	const gchar *who,
1460 #endif
1461 	gpointer sender)
1462 {
1463 	PurpleBuddy *buddy = sender;
1464 	SkypeWebAccount *sa;
1465 	gchar *url = NULL;
1466 	gchar *buddy_name;
1467 
1468 	sa = purple_connection_get_protocol_data(purple_account_get_connection(purple_buddy_get_account(buddy)));
1469 	buddy_name = g_strdup(purple_buddy_get_name(buddy));
1470 
1471 	url = g_strdup_printf("/contacts/v2/users/SELF/invites/%s%s/decline", skypeweb_user_url_prefix(buddy_name), purple_url_encode(buddy_name));
1472 
1473 	skypeweb_post_or_get(sa, SKYPEWEB_METHOD_PUT | SKYPEWEB_METHOD_SSL, SKYPEWEB_NEW_CONTACTS_HOST, url, NULL, NULL, NULL, TRUE);
1474 
1475 	g_free(url);
1476 	g_free(buddy_name);
1477 }
1478 
1479 static void
skypeweb_got_authrequests(SkypeWebAccount * sa,JsonNode * node,gpointer user_data)1480 skypeweb_got_authrequests(SkypeWebAccount *sa, JsonNode *node, gpointer user_data)
1481 {
1482 	JsonObject *requests;
1483 	JsonArray *invite_list;
1484 	guint index, length;
1485 	time_t latest_timestamp = 0;
1486 
1487 	requests = json_node_get_object(node);
1488 	invite_list = json_object_get_array_member(requests, "invite_list");
1489 	length = json_array_get_length(invite_list);
1490 	for(index = 0; index < length; index++)
1491 	{
1492 		JsonObject *invite = json_array_get_object_element(invite_list, index);
1493 		JsonArray *invites = json_object_get_array_member(invite, "invites");
1494 		const gchar *event_time_iso = json_object_get_string_member(json_array_get_object_element(invites, 0), "time");
1495 		time_t event_timestamp = purple_str_to_time(event_time_iso, TRUE, NULL, NULL, NULL);
1496 		const gchar *sender = json_object_get_string_member(invite, "mri");
1497 		const gchar *greeting = json_object_get_string_member(invite, "greeting");
1498 		if (!greeting)
1499 			greeting = json_object_get_string_member(json_array_get_object_element(invites, 0), "message");
1500 		const gchar *displayname = json_object_get_string_member(invite, "displayname");
1501 
1502 		latest_timestamp = MAX(latest_timestamp, event_timestamp);
1503 		if (sa->last_authrequest && event_timestamp <= sa->last_authrequest)
1504 			continue;
1505 
1506 		if (sender == NULL)
1507 			continue;
1508 		sender = skypeweb_strip_user_prefix(sender);
1509 
1510 		purple_account_request_authorization(
1511 				sa->account, sender, NULL,
1512 				displayname, greeting, FALSE,
1513 				skypeweb_auth_accept_cb, skypeweb_auth_reject_cb, purple_buddy_new(sa->account, sender, displayname));
1514 
1515 	}
1516 
1517 	sa->last_authrequest = latest_timestamp;
1518 }
1519 
1520 gboolean
skypeweb_check_authrequests(SkypeWebAccount * sa)1521 skypeweb_check_authrequests(SkypeWebAccount *sa)
1522 {
1523 	skypeweb_post_or_get(sa, SKYPEWEB_METHOD_GET | SKYPEWEB_METHOD_SSL, SKYPEWEB_NEW_CONTACTS_HOST, "/contacts/v2/users/SELF/invites", NULL, skypeweb_got_authrequests, NULL, TRUE);
1524 	return TRUE;
1525 }
1526 
1527 
1528 void
skypeweb_add_buddy_with_invite(PurpleConnection * pc,PurpleBuddy * buddy,PurpleGroup * group,const char * message)1529 skypeweb_add_buddy_with_invite(PurpleConnection *pc, PurpleBuddy *buddy, PurpleGroup *group, const char *message)
1530 {
1531 	SkypeWebAccount *sa = purple_connection_get_protocol_data(pc);
1532 	gchar *postdata;
1533 	const gchar *url = "/contacts/v2/users/SELF/contacts";
1534 	GSList *users_to_fetch;
1535 	JsonObject *obj;
1536 	gchar *buddy_name, *mri;
1537 
1538 	//https://contacts.skype.com/contacts/v2/users/SELF/contacts
1539 	// POST {"mri":"2:eionrobb@dequis.onmicrosoft.com","greeting":"Hi, eionrobb@dequis.onmicrosoft.com, I'd like to add you as a contact."}
1540 
1541 	buddy_name = g_strdup(purple_buddy_get_name(buddy));
1542 	mri = g_strconcat(skypeweb_user_url_prefix(buddy_name), buddy_name, NULL);
1543 
1544 	obj = json_object_new();
1545 
1546 	json_object_set_string_member(obj, "mri", mri);
1547 	json_object_set_string_member(obj, "greeting", message ? message : _("Please authorize me so I can add you to my buddy list."));
1548 	postdata = skypeweb_jsonobj_to_string(obj);
1549 
1550 	skypeweb_post_or_get(sa, SKYPEWEB_METHOD_POST | SKYPEWEB_METHOD_SSL, SKYPEWEB_NEW_CONTACTS_HOST, url, postdata, NULL, NULL, TRUE);
1551 
1552 	g_free(mri);
1553 	g_free(postdata);
1554 	json_object_unref(obj);
1555 
1556 	// Subscribe to status/message updates
1557 	users_to_fetch = g_slist_prepend(NULL, buddy_name);
1558 	skypeweb_subscribe_to_contact_status(sa, users_to_fetch);
1559 	g_slist_free(users_to_fetch);
1560 
1561 	g_free(buddy_name);
1562 }
1563 
1564 void
skypeweb_add_buddy(PurpleConnection * pc,PurpleBuddy * buddy,PurpleGroup * group)1565 skypeweb_add_buddy(PurpleConnection *pc, PurpleBuddy *buddy, PurpleGroup *group)
1566 {
1567 	skypeweb_add_buddy_with_invite(pc, buddy, group, NULL);
1568 }
1569 
1570 void
skypeweb_buddy_remove(PurpleConnection * pc,PurpleBuddy * buddy,PurpleGroup * group)1571 skypeweb_buddy_remove(PurpleConnection *pc, PurpleBuddy *buddy, PurpleGroup *group)
1572 {
1573 	SkypeWebAccount *sa = purple_connection_get_protocol_data(pc);
1574 	gchar *url;
1575 	const gchar *buddy_name = purple_buddy_get_name(buddy);
1576 
1577 	url = g_strdup_printf("/contacts/v2/users/SELF/contacts/%s%s", skypeweb_user_url_prefix(buddy_name), purple_url_encode(buddy_name));
1578 
1579 	skypeweb_post_or_get(sa, SKYPEWEB_METHOD_DELETE | SKYPEWEB_METHOD_SSL, SKYPEWEB_NEW_CONTACTS_HOST, url, NULL, NULL, NULL, TRUE);
1580 
1581 	g_free(url);
1582 
1583 	skypeweb_unsubscribe_from_contact_status(sa, buddy_name);
1584 }
1585 
1586 void
skypeweb_buddy_block(PurpleConnection * pc,const char * name)1587 skypeweb_buddy_block(PurpleConnection *pc, const char *name)
1588 {
1589 	SkypeWebAccount *sa = purple_connection_get_protocol_data(pc);
1590 	gchar *url;
1591 	const gchar *postdata;
1592 
1593 	url = g_strdup_printf("/contacts/v2/users/SELF/contacts/blocklist/%s%s", skypeweb_user_url_prefix(name), purple_url_encode(name));
1594 	postdata = "{\"report_abuse\":\"false\",\"ui_version\":\"skype.com\"}";
1595 
1596 	skypeweb_post_or_get(sa, SKYPEWEB_METHOD_PUT | SKYPEWEB_METHOD_SSL, SKYPEWEB_NEW_CONTACTS_HOST, url, postdata, NULL, NULL, TRUE);
1597 
1598 	g_free(url);
1599 }
1600 
1601 void
skypeweb_buddy_unblock(PurpleConnection * pc,const char * name)1602 skypeweb_buddy_unblock(PurpleConnection *pc, const char *name)
1603 {
1604 	SkypeWebAccount *sa = purple_connection_get_protocol_data(pc);
1605 	gchar *url;
1606 
1607 	url = g_strdup_printf("/contacts/v2/users/SELF/contacts/blocklist/%s%s", skypeweb_user_url_prefix(name), purple_url_encode(name));
1608 
1609 	skypeweb_post_or_get(sa, SKYPEWEB_METHOD_DELETE | SKYPEWEB_METHOD_SSL, SKYPEWEB_NEW_CONTACTS_HOST, url, NULL, NULL, NULL, TRUE);
1610 
1611 	g_free(url);
1612 }
1613 
1614 
1615 void
skypeweb_set_mood_message(SkypeWebAccount * sa,const gchar * mood)1616 skypeweb_set_mood_message(SkypeWebAccount *sa, const gchar *mood)
1617 {
1618 	JsonObject *obj, *payload;
1619 	gchar *post;
1620 
1621 	obj = json_object_new();
1622 	payload = json_object_new();
1623 
1624 	json_object_set_string_member(payload, "mood", mood ? mood : "");
1625 	json_object_set_object_member(obj, "payload", payload);
1626 	post = skypeweb_jsonobj_to_string(obj);
1627 
1628 	skypeweb_post_or_get(sa, SKYPEWEB_METHOD_POST | SKYPEWEB_METHOD_SSL, SKYPEWEB_CONTACTS_HOST, "/users/self/profile/partial", post, NULL, NULL, TRUE);
1629 
1630 	g_free(post);
1631 	json_object_unref(obj);
1632 }
1633