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 #include "libskypeweb.h"
20 #include "skypeweb_connection.h"
21 #include "skypeweb_contacts.h"
22 #include "skypeweb_login.h"
23 #include "skypeweb_messages.h"
24 #include "skypeweb_util.h"
25 
26 void
skypeweb_do_all_the_things(SkypeWebAccount * sa)27 skypeweb_do_all_the_things(SkypeWebAccount *sa)
28 {
29 	skypeweb_get_vdms_token(sa);
30 
31 	if (!sa->username) {
32 		skypeweb_get_self_details(sa);
33 	} else
34 	if (sa->registration_token) {
35 		skypeweb_get_self_details(sa);
36 
37 		if (sa->authcheck_timeout)
38 			g_source_remove(sa->authcheck_timeout);
39 		skypeweb_check_authrequests(sa);
40 		sa->authcheck_timeout = g_timeout_add_seconds(120, (GSourceFunc)skypeweb_check_authrequests, sa);
41 		purple_connection_set_state(sa->pc, PURPLE_CONNECTION_CONNECTED);
42 
43 		skypeweb_get_friend_list(sa);
44 		skypeweb_poll(sa);
45 
46 		skype_web_get_offline_history(sa);
47 
48 		skypeweb_set_status(sa->account, purple_account_get_active_status(sa->account));
49 	} else {
50 		//Too soon!
51 		skypeweb_get_registration_token(sa);
52 	}
53 
54 
55 }
56 
57 
58 /******************************************************************************/
59 /* PRPL functions */
60 /******************************************************************************/
61 
62 static const char *
skypeweb_list_icon(PurpleAccount * account,PurpleBuddy * buddy)63 skypeweb_list_icon(PurpleAccount *account, PurpleBuddy *buddy)
64 {
65 
66 	if (buddy != NULL) {
67 		const gchar *buddy_name = purple_buddy_get_name(buddy);
68 		if (buddy_name && SKYPEWEB_BUDDY_IS_MSN(buddy_name)) {
69 			return "msn";
70 		}
71 	}
72 	return "skype";
73 }
74 
75 static gchar *
skypeweb_status_text(PurpleBuddy * buddy)76 skypeweb_status_text(PurpleBuddy *buddy)
77 {
78 	SkypeWebBuddy *sbuddy = purple_buddy_get_protocol_data(buddy);
79 
80 	if (sbuddy && sbuddy->mood && *(sbuddy->mood))
81 	{
82 		gchar *stripped = purple_markup_strip_html(sbuddy->mood);
83 		gchar *escaped = g_markup_printf_escaped("%s", stripped);
84 
85 		g_free(stripped);
86 
87 		return escaped;
88 	}
89 
90 	return NULL;
91 }
92 
93 void
skypeweb_tooltip_text(PurpleBuddy * buddy,PurpleNotifyUserInfo * user_info,gboolean full)94 skypeweb_tooltip_text(PurpleBuddy *buddy, PurpleNotifyUserInfo *user_info, gboolean full)
95 {
96 	SkypeWebBuddy *sbuddy = purple_buddy_get_protocol_data(buddy);
97 
98 	if (sbuddy)
99 	{
100 		PurplePresence *presence;
101 		PurpleStatus *status;
102 		SkypeWebBuddy *sbuddy = purple_buddy_get_protocol_data(buddy);
103 
104 		presence = purple_buddy_get_presence(buddy);
105 		status = purple_presence_get_active_status(presence);
106 		purple_notify_user_info_add_pair_html(user_info, _("Status"), purple_status_get_name(status));
107 		if (sbuddy->mood && *sbuddy->mood) {
108 			gchar *stripped = purple_markup_strip_html(sbuddy->mood);
109 			gchar *escaped = g_markup_printf_escaped("%s", stripped);
110 
111 			purple_notify_user_info_add_pair_html(user_info, _("Message"), escaped);
112 
113 			g_free(stripped);
114 			g_free(escaped);
115 		}
116 
117 		if (sbuddy->display_name && *sbuddy->display_name) {
118 			gchar *escaped = g_markup_printf_escaped("%s", sbuddy->display_name);
119 			purple_notify_user_info_add_pair_html(user_info, "Alias", escaped);
120 			g_free(escaped);
121 		}
122 		if (sbuddy->fullname && *sbuddy->fullname) {
123 			gchar *escaped = g_markup_printf_escaped("%s", sbuddy->fullname);
124 			purple_notify_user_info_add_pair_html(user_info, "Full Name", escaped);
125 			g_free(escaped);
126 		}
127 	}
128 }
129 
130 const gchar *
skypeweb_list_emblem(PurpleBuddy * buddy)131 skypeweb_list_emblem(PurpleBuddy *buddy)
132 {
133 	if (buddy != NULL) {
134 		//SkypeWebBuddy *sbuddy = purple_buddy_get_protocol_data(buddy);
135 		const gchar *buddy_name = purple_buddy_get_name(buddy);
136 
137 		if (buddy_name && SKYPEWEB_BUDDY_IS_BOT(buddy_name)) {
138 			return "bot";
139 		}
140 	}
141 	return NULL;
142 }
143 
144 GList *
skypeweb_status_types(PurpleAccount * account)145 skypeweb_status_types(PurpleAccount *account)
146 {
147 	GList *types = NULL;
148 	PurpleStatusType *status;
149 
150 	status = purple_status_type_new_full(PURPLE_STATUS_OFFLINE, NULL, NULL, FALSE, FALSE, FALSE);
151 	types = g_list_append(types, status);
152 
153 	status = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE, SKYPEWEB_STATUS_ONLINE, _("Online"), TRUE, TRUE, FALSE, "message", "Mood", purple_value_new(PURPLE_TYPE_STRING), NULL);
154 	types = g_list_append(types, status);
155 	status = purple_status_type_new_with_attrs(PURPLE_STATUS_AWAY, SKYPEWEB_STATUS_AWAY, _("Away"), TRUE, TRUE, FALSE, "message", "Mood", purple_value_new(PURPLE_TYPE_STRING), NULL);
156 	types = g_list_append(types, status);
157 //	status = purple_status_type_new_with_attrs(PURPLE_STATUS_EXTENDED_AWAY, SKYPEWEB_STATUS_AWAY, _("Not Available"), TRUE, TRUE, FALSE, "message", "Mood", purple_value_new(PURPLE_TYPE_STRING), NULL);
158 //	types = g_list_append(types, status);
159 	status = purple_status_type_new_with_attrs(PURPLE_STATUS_UNAVAILABLE, SKYPEWEB_STATUS_BUSY, _("Do Not Disturb"), TRUE, TRUE, FALSE, "message", "Mood", purple_value_new(PURPLE_TYPE_STRING), NULL);
160 	types = g_list_append(types, status);
161 	status = purple_status_type_new_with_attrs(PURPLE_STATUS_INVISIBLE, SKYPEWEB_STATUS_HIDDEN, _("Invisible"), TRUE, TRUE, FALSE, "message", "Mood", purple_value_new(PURPLE_TYPE_STRING), NULL);
162 	types = g_list_append(types, status);
163 	status = purple_status_type_new_with_attrs(PURPLE_STATUS_OFFLINE, SKYPEWEB_STATUS_OFFLINE, _("Offline"), TRUE, TRUE, FALSE, "message", "Mood", purple_value_new(PURPLE_TYPE_STRING), NULL);
164 	types = g_list_append(types, status);
165 
166 	return types;
167 }
168 
169 
170 static GList *
skypeweb_chat_info(PurpleConnection * gc)171 skypeweb_chat_info(PurpleConnection *gc)
172 {
173 	GList *m = NULL;
174 	PurpleProtocolChatEntry *pce;
175 
176 	pce = g_new0(PurpleProtocolChatEntry, 1);
177 	pce->label = _("Skype Name");
178 	pce->identifier = "chatname";
179 	pce->required = TRUE;
180 	m = g_list_append(m, pce);
181 
182 	/*pce = g_new0(PurpleProtocolChatEntry, 1);
183 	pce->label = _("Password");
184 	pce->identifier = "password";
185 	pce->required = FALSE;
186 	m = g_list_append(m, pce);*/
187 
188 	return m;
189 }
190 
191 static GHashTable *
skypeweb_chat_info_defaults(PurpleConnection * gc,const char * chatname)192 skypeweb_chat_info_defaults(PurpleConnection *gc, const char *chatname)
193 {
194 	GHashTable *defaults;
195 	defaults = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free);
196 	if (chatname != NULL)
197 	{
198 		g_hash_table_insert(defaults, "chatname", g_strdup(chatname));
199 	}
200 	return defaults;
201 }
202 
203 static gchar *
skypeweb_get_chat_name(GHashTable * data)204 skypeweb_get_chat_name(GHashTable *data)
205 {
206 	gchar *temp;
207 
208 	if (data == NULL)
209 		return NULL;
210 
211 	temp = g_hash_table_lookup(data, "chatname");
212 
213 	if (temp == NULL)
214 		return NULL;
215 
216 	return g_strdup(temp);
217 }
218 
219 
220 static void
skypeweb_join_chat(PurpleConnection * pc,GHashTable * data)221 skypeweb_join_chat(PurpleConnection *pc, GHashTable *data)
222 {
223 	SkypeWebAccount *sa = purple_connection_get_protocol_data(pc);
224 	gchar *chatname;
225 	gchar *post;
226 	GString *url;
227 	PurpleChatConversation *chatconv;
228 
229 	chatname = (gchar *)g_hash_table_lookup(data, "chatname");
230 	if (chatname == NULL)
231 	{
232 		return;
233 	}
234 
235 	chatconv = purple_conversations_find_chat_with_account(chatname, sa->account);
236 	if (chatconv != NULL && !purple_chat_conversation_has_left(chatconv)) {
237 		purple_conversation_present(PURPLE_CONVERSATION(chatconv));
238 		return;
239 	}
240 
241 	url = g_string_new("/v1/threads/");
242 	g_string_append_printf(url, "%s", purple_url_encode(chatname));
243 	g_string_append(url, "/members/");
244 	g_string_append_printf(url, "8:%s", purple_url_encode(sa->username));
245 
246 	/* Specifying the role does not seem to be required and often result in a users role being
247 	 * downgraded from admin to user
248 	 * post = "{\"role\":\"User\"}"; */
249 	post = "{}";
250 
251 	skypeweb_post_or_get(sa, SKYPEWEB_METHOD_PUT | SKYPEWEB_METHOD_SSL, sa->messages_host, url->str, post, NULL, NULL, TRUE);
252 
253 	g_string_free(url, TRUE);
254 
255 	skypeweb_get_conversation_history(sa, chatname);
256 	skypeweb_get_thread_users(sa, chatname);
257 
258 	chatconv = purple_serv_got_joined_chat(pc, g_str_hash(chatname), chatname);
259 	purple_conversation_set_data(PURPLE_CONVERSATION(chatconv), "chatname", g_strdup(chatname));
260 
261 	purple_conversation_present(PURPLE_CONVERSATION(chatconv));
262 }
263 
264 void
skypeweb_buddy_free(PurpleBuddy * buddy)265 skypeweb_buddy_free(PurpleBuddy *buddy)
266 {
267 	SkypeWebBuddy *sbuddy = purple_buddy_get_protocol_data(buddy);
268 	if (sbuddy != NULL)
269 	{
270 		purple_buddy_set_protocol_data(buddy, NULL);
271 
272 		g_free(sbuddy->skypename);
273 		g_free(sbuddy->fullname);
274 		g_free(sbuddy->display_name);
275 		g_free(sbuddy->avatar_url);
276 		g_free(sbuddy->mood);
277 
278 		g_free(sbuddy);
279 	}
280 }
281 
282 void
skypeweb_fake_group_buddy(PurpleConnection * pc,const char * who,const char * old_group,const char * new_group)283 skypeweb_fake_group_buddy(PurpleConnection *pc, const char *who, const char *old_group, const char *new_group)
284 {
285 	// Do nothing to stop the remove+add behaviour
286 }
287 void
skypeweb_fake_group_rename(PurpleConnection * pc,const char * old_name,PurpleGroup * group,GList * moved_buddies)288 skypeweb_fake_group_rename(PurpleConnection *pc, const char *old_name, PurpleGroup *group, GList *moved_buddies)
289 {
290 	// Do nothing to stop the remove+add behaviour
291 }
292 
293 static GList *
skypeweb_node_menu(PurpleBlistNode * node)294 skypeweb_node_menu(PurpleBlistNode *node)
295 {
296 	GList *m = NULL;
297 	PurpleMenuAction *act;
298 	PurpleBuddy *buddy;
299 	SkypeWebAccount *sa = NULL;
300 
301 	if(PURPLE_IS_BUDDY(node))
302 	{
303 		buddy = PURPLE_BUDDY(node);
304 		if (purple_buddy_get_protocol_data(buddy)) {
305 			SkypeWebBuddy *sbuddy = purple_buddy_get_protocol_data(buddy);
306 			sa = sbuddy->sa;
307 		}
308 		if (sa == NULL) {
309 			PurpleConnection *pc = purple_account_get_connection(purple_buddy_get_account(buddy));
310 			sa = purple_connection_get_protocol_data(pc);
311 		}
312 
313 		if (sa != NULL) {
314 			act = purple_menu_action_new(_("Initiate _Chat"),
315 								PURPLE_CALLBACK(skypeweb_initiate_chat_from_node),
316 								sa, NULL);
317 			m = g_list_append(m, act);
318 		}
319 	}
320 
321 	return m;
322 }
323 
324 static gulong conversation_updated_signal = 0;
325 static gulong chat_conversation_typing_signal = 0;
326 
327 static void
skypeweb_login(PurpleAccount * account)328 skypeweb_login(PurpleAccount *account)
329 {
330 	PurpleConnection *pc = purple_account_get_connection(account);
331 	SkypeWebAccount *sa = g_new0(SkypeWebAccount, 1);
332 	PurpleConnectionFlags flags;
333 
334 	purple_connection_set_protocol_data(pc, sa);
335 
336 	flags = purple_connection_get_flags(pc);
337 	flags |= PURPLE_CONNECTION_FLAG_HTML | PURPLE_CONNECTION_FLAG_NO_BGCOLOR | PURPLE_CONNECTION_FLAG_NO_FONTSIZE;
338 	purple_connection_set_flags(pc, flags);
339 
340 	if (!SKYPEWEB_BUDDY_IS_MSN(purple_account_get_username(account))) {
341 		sa->username = g_ascii_strdown(purple_account_get_username(account), -1);
342 	}
343 	sa->account = account;
344 	sa->pc = pc;
345 	sa->cookie_jar = purple_http_cookie_jar_new();
346 	sa->sent_messages_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
347 	sa->messages_host = g_strdup(SKYPEWEB_DEFAULT_MESSAGES_HOST);
348 	sa->keepalive_pool = purple_http_keepalive_pool_new();
349 	purple_http_keepalive_pool_set_limit_per_host(sa->keepalive_pool, SKYPEWEB_MAX_CONNECTIONS);
350 	sa->conns = purple_http_connection_set_new();
351 
352 	if (purple_account_get_bool(account, "alt-login", FALSE)) {
353 		skypeweb_begin_soapy_login(sa);
354 	} else {
355 		if (purple_account_get_string(account, "refresh-token", NULL) && purple_account_get_remember_password(account)) {
356 			skypeweb_refresh_token_login(sa);
357 		} else {
358 			skypeweb_begin_oauth_login(sa);
359 		}
360 	}
361 
362 	if (!conversation_updated_signal) {
363 		conversation_updated_signal = purple_signal_connect(purple_conversations_get_handle(), "conversation-updated", purple_connection_get_protocol(pc), PURPLE_CALLBACK(skypeweb_mark_conv_seen), NULL);
364 	}
365 	if (!chat_conversation_typing_signal) {
366 		chat_conversation_typing_signal = purple_signal_connect(purple_conversations_get_handle(), "chat-conversation-typing", purple_connection_get_protocol(pc), PURPLE_CALLBACK(skypeweb_conv_send_typing), NULL);
367 	}
368 }
369 
370 static void
skypeweb_close(PurpleConnection * pc)371 skypeweb_close(PurpleConnection *pc)
372 {
373 	SkypeWebAccount *sa;
374 	GSList *buddies;
375 
376 	g_return_if_fail(pc != NULL);
377 #if !PURPLE_VERSION_CHECK(3, 0, 0)
378 	purple_connection_set_state(pc, PURPLE_CONNECTION_DISCONNECTING);
379 #endif
380 
381 	sa = purple_connection_get_protocol_data(pc);
382 	g_return_if_fail(sa != NULL);
383 
384 	g_source_remove(sa->authcheck_timeout);
385 	g_source_remove(sa->poll_timeout);
386 	g_source_remove(sa->watchdog_timeout);
387 
388 	skypeweb_logout(sa);
389 
390 	purple_debug_info("skypeweb", "destroying incomplete connections\n");
391 
392 	purple_http_connection_set_destroy(sa->conns);
393 	purple_http_conn_cancel_all(pc);
394 	purple_http_keepalive_pool_unref(sa->keepalive_pool);
395 	purple_http_cookie_jar_unref(sa->cookie_jar);
396 
397 	buddies = purple_blist_find_buddies(sa->account, NULL);
398 	while (buddies != NULL) {
399 		PurpleBuddy *buddy = buddies->data;
400 		skypeweb_buddy_free(buddy);
401 		purple_buddy_set_protocol_data(buddy, NULL);
402 		buddies = g_slist_delete_link(buddies, buddies);
403 	}
404 
405 	g_hash_table_destroy(sa->sent_messages_hash);
406 
407 	g_free(sa->vdms_token);
408 	g_free(sa->messages_host);
409 	g_free(sa->skype_token);
410 	g_free(sa->registration_token);
411 	g_free(sa->endpoint);
412 	g_free(sa->primary_member_name);
413 	g_free(sa->self_display_name);
414 	g_free(sa->username);
415 	g_free(sa);
416 }
417 
418 gboolean
skypeweb_offline_message(const PurpleBuddy * buddy)419 skypeweb_offline_message(const PurpleBuddy *buddy)
420 {
421 	return TRUE;
422 }
423 
424 static PurpleCmdRet
skypeweb_cmd_list(PurpleConversation * conv,const gchar * cmd,gchar ** args,gchar ** error,void * data)425 skypeweb_cmd_list(PurpleConversation *conv, const gchar *cmd, gchar **args, gchar **error, void *data)
426 {
427 	purple_roomlist_show_with_account(purple_conversation_get_account(conv));
428 
429 	return PURPLE_CMD_RET_OK;
430 }
431 
432 static PurpleCmdRet
skypeweb_cmd_leave(PurpleConversation * conv,const gchar * cmd,gchar ** args,gchar ** error,void * data)433 skypeweb_cmd_leave(PurpleConversation *conv, const gchar *cmd, gchar **args, gchar **error, void *data)
434 {
435 	PurpleConnection *pc = NULL;
436 	int id = -1;
437 	SkypeWebAccount *sa;
438 
439 	pc = purple_conversation_get_connection(conv);
440 	id = purple_chat_conversation_get_id(PURPLE_CHAT_CONVERSATION(conv));
441 
442 	if (pc == NULL || id == -1)
443 		return PURPLE_CMD_RET_FAILED;
444 
445 	sa = purple_connection_get_protocol_data(pc);
446 	if (sa == NULL)
447 		return PURPLE_CMD_RET_FAILED;
448 
449 	skypeweb_chat_kick(pc, id, sa->username);
450 
451 	return PURPLE_CMD_RET_OK;
452 }
453 
454 static PurpleCmdRet
skypeweb_cmd_kick(PurpleConversation * conv,const gchar * cmd,gchar ** args,gchar ** error,void * data)455 skypeweb_cmd_kick(PurpleConversation *conv, const gchar *cmd, gchar **args, gchar **error, void *data)
456 {
457 	PurpleConnection *pc = NULL;
458 	int id = -1;
459 
460 	pc = purple_conversation_get_connection(conv);
461 	id = purple_chat_conversation_get_id(PURPLE_CHAT_CONVERSATION(conv));
462 
463 	if (pc == NULL || id == -1)
464 		return PURPLE_CMD_RET_FAILED;
465 
466 	skypeweb_chat_kick(pc, id, args[0]);
467 
468 	return PURPLE_CMD_RET_OK;
469 }
470 
471 static PurpleCmdRet
skypeweb_cmd_invite(PurpleConversation * conv,const gchar * cmd,gchar ** args,gchar ** error,void * data)472 skypeweb_cmd_invite(PurpleConversation *conv, const gchar *cmd, gchar **args, gchar **error, void *data)
473 {
474 	PurpleConnection *pc = NULL;
475 	int id = -1;
476 
477 	pc = purple_conversation_get_connection(conv);
478 	id = purple_chat_conversation_get_id(PURPLE_CHAT_CONVERSATION(conv));
479 
480 	if (pc == NULL || id == -1)
481 		return PURPLE_CMD_RET_FAILED;
482 
483 	skypeweb_chat_invite(pc, id, NULL, args[0]);
484 
485 	return PURPLE_CMD_RET_OK;
486 }
487 
488 static PurpleCmdRet
skypeweb_cmd_topic(PurpleConversation * conv,const gchar * cmd,gchar ** args,gchar ** error,void * data)489 skypeweb_cmd_topic(PurpleConversation *conv, const gchar *cmd, gchar **args, gchar **error, void *data)
490 {
491 	PurpleConnection *pc = NULL;
492 	PurpleChatConversation *chat;
493 	int id = -1;
494 
495 	pc = purple_conversation_get_connection(conv);
496 	chat = PURPLE_CHAT_CONVERSATION(conv);
497 	id = purple_chat_conversation_get_id(chat);
498 
499 	if (pc == NULL || id == -1)
500 		return PURPLE_CMD_RET_FAILED;
501 
502 	if (!args || !args[0]) {
503 		gchar *buf;
504 		const gchar *topic = purple_chat_conversation_get_topic(chat);
505 
506 		if (topic) {
507 			gchar *tmp, *tmp2;
508 			tmp = g_markup_escape_text(topic, -1);
509 			tmp2 = purple_markup_linkify(tmp);
510 			buf = g_strdup_printf(_("current topic is: %s"), tmp2);
511 			g_free(tmp);
512 			g_free(tmp2);
513 		} else {
514 			buf = g_strdup(_("No topic is set"));
515 		}
516 
517 		purple_conversation_write_system_message(conv, buf, PURPLE_MESSAGE_NO_LOG);
518 
519 		g_free(buf);
520 		return PURPLE_CMD_RET_OK;
521 	}
522 
523 	skypeweb_chat_set_topic(pc, id, args[0]);
524 
525 	return PURPLE_CMD_RET_OK;
526 }
527 
528 /******************************************************************************/
529 /* Plugin functions */
530 /******************************************************************************/
531 
532 static gboolean
skypeweb_uri_handler(const char * proto,const char * cmd,GHashTable * params)533 skypeweb_uri_handler(const char *proto, const char *cmd, GHashTable *params)
534 {
535 	PurpleAccount *account;
536 	PurpleConnection *pc;
537 
538 	if (!g_str_equal(proto, "skype"))
539 		return FALSE;
540 
541 	/*skype uri's:
542 
543 		skype:						//does nothing
544 		skype:{buddyname}			//open im with {buddyname}
545 		skype:{buddynames}?chat		//open multi-user chat with {buddynames}
546 		skype:?chat&blob={blob id}	//open public multi-user chat with the blob id of {blob id}
547 		skype:?chat&id={chat id}	//open multi-user chat with the id of {chat id}
548 		skype:{buddyname}?add		//add user to buddy list
549 		skype:{buddyname}?userinfo	//get buddy's info
550 
551 		skype:{buddynames}?call		//call {buddynames}
552 		skype:{buddyname}?voicemail	//send a voice mail message
553 		skype:{buddyname}?sendfile	//send a file
554 		*/
555 
556 	account = find_acct(SKYPEWEB_PLUGIN_ID, g_hash_table_lookup(params, "account"));
557 	pc = purple_account_get_connection(account);
558 
559 	if (g_hash_table_lookup(params, "chat")) {
560 		if (cmd && *cmd) {
561 			//there'll be a bunch of usernames, seperated by semi-colon
562 			if (strchr(cmd, ';')) {
563 				gchar **users = g_strsplit_set(cmd, ";", -1);
564 				skypeweb_initiate_chat(purple_connection_get_protocol_data(pc), users[0]);
565 				//TODO the other users
566 				g_strfreev(users);
567 			} else {
568 				PurpleIMConversation *imconv;
569 				imconv = purple_conversations_find_im_with_account(cmd, account);
570 				if (!imconv) {
571 					imconv = purple_im_conversation_new(account, cmd);
572 				}
573 				purple_conversation_present(PURPLE_CONVERSATION(imconv));
574 			}
575 		} else {
576 			//probably a public multi-user chat?
577 			GHashTable *chatinfo = NULL;
578 			if (g_hash_table_lookup(params, "id")) {
579 				chatinfo = skypeweb_chat_info_defaults(pc, g_hash_table_lookup(params, "id"));
580 			} else if (g_hash_table_lookup(params, "blob")) {
581 				chatinfo = skypeweb_chat_info_defaults(pc, g_hash_table_lookup(params, "blob"));
582 			}
583 
584 			if (chatinfo != NULL) {
585 				skypeweb_join_chat(pc, chatinfo);
586 				g_hash_table_destroy(chatinfo);
587 			}
588 		}
589 	} else if (g_hash_table_lookup(params, "add")) {
590 		purple_blist_request_add_buddy(account, cmd, "Skype", g_hash_table_lookup(params, "displayname"));
591 		return TRUE;
592 	} else if (g_hash_table_lookup(params, "call")) {
593 
594 	} else if (g_hash_table_lookup(params, "userinfo")) {
595 		skypeweb_get_info(pc, cmd);
596 		return TRUE;
597 	} else if (g_hash_table_lookup(params, "voicemail")) {
598 
599 	} else if (g_hash_table_lookup(params, "sendfile")) {
600 
601 	} else if (strlen(cmd)) {
602 		//supposed to be the same as call?
603 	}
604 
605 	//we don't know how to handle this
606 	return FALSE;
607 }
608 
609 #if PURPLE_VERSION_CHECK(3, 0, 0)
610 	typedef struct _SkypeWebProtocol
611 	{
612 		PurpleProtocol parent;
613 	} SkypeWebProtocol;
614 
615 	typedef struct _SkypeWebProtocolClass
616 	{
617 		PurpleProtocolClass parent_class;
618 	} SkypeWebProtocolClass;
619 
620 	G_MODULE_EXPORT GType skypeweb_protocol_get_type(void);
621 	#define SKYPEWEB_TYPE_PROTOCOL             (skypeweb_protocol_get_type())
622 	#define SKYPEWEB_PROTOCOL(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj), SKYPEWEB_TYPE_PROTOCOL, SkypeWebProtocol))
623 	#define SKYPEWEB_PROTOCOL_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass), SKYPEWEB_TYPE_PROTOCOL, SkypeWebProtocolClass))
624 	#define SKYPEWEB_IS_PROTOCOL(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj), SKYPEWEB_TYPE_PROTOCOL))
625 	#define SKYPEWEB_IS_PROTOCOL_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass), SKYPEWEB_TYPE_PROTOCOL))
626 	#define SKYPEWEB_PROTOCOL_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS((obj), SKYPEWEB_TYPE_PROTOCOL, SkypeWebProtocolClass))
627 
628 	static PurpleProtocol *skypeweb_protocol;
629 #else
630 
631 // Normally set in core.c in purple3
632 void _purple_socket_init(void);
633 void _purple_socket_uninit(void);
634 
635 #endif
636 
637 
638 static gboolean
plugin_load(PurplePlugin * plugin,GError ** error)639 plugin_load(PurplePlugin *plugin
640 #if PURPLE_VERSION_CHECK(3, 0, 0)
641 , GError **error
642 #endif
643 )
644 {
645 
646 #if !PURPLE_VERSION_CHECK(3, 0, 0)
647 	_purple_socket_init();
648 	purple_http_init();
649 #endif
650 
651 
652 	//leave
653 	purple_cmd_register("leave", "", PURPLE_CMD_P_PLUGIN, PURPLE_CMD_FLAG_CHAT |
654 						PURPLE_CMD_FLAG_PROTOCOL_ONLY | PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS,
655 						SKYPEWEB_PLUGIN_ID, skypeweb_cmd_leave,
656 						_("leave:  Leave the group chat"), NULL);
657 	//kick
658 	purple_cmd_register("kick", "s", PURPLE_CMD_P_PLUGIN, PURPLE_CMD_FLAG_CHAT |
659 						PURPLE_CMD_FLAG_PROTOCOL_ONLY,
660 						SKYPEWEB_PLUGIN_ID, skypeweb_cmd_kick,
661 						_("kick &lt;user&gt;:  Kick a user from the group chat."),
662 						NULL);
663 	//add
664 	purple_cmd_register("add", "s", PURPLE_CMD_P_PLUGIN, PURPLE_CMD_FLAG_CHAT |
665 						PURPLE_CMD_FLAG_PROTOCOL_ONLY,
666 						SKYPEWEB_PLUGIN_ID, skypeweb_cmd_invite,
667 						_("add &lt;user&gt;:  Add a user to the group chat."),
668 						NULL);
669 	//topic
670 	purple_cmd_register("topic", "s", PURPLE_CMD_P_PLUGIN, PURPLE_CMD_FLAG_CHAT |
671 						PURPLE_CMD_FLAG_PROTOCOL_ONLY | PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS,
672 						SKYPEWEB_PLUGIN_ID, skypeweb_cmd_topic,
673 						_("topic [&lt;new topic&gt;]:  View or change the topic"),
674 						NULL);
675 	/*
676 	//call, as in call person
677 	//kickban
678 	purple_cmd_register("kickban", "s", PURPLE_CMD_P_PLUGIN, PURPLE_CMD_FLAG_CHAT |
679 						PURPLE_CMD_FLAG_PROTOCOL_ONLY,
680 						SKYPEWEB_PLUGIN_ID, skypeweb_cmd_kickban,
681 						_("kickban &lt;user&gt; [room]:  Kick and ban a user from the room."),
682 						NULL);
683 	//setrole
684 	purple_cmd_register("setrole", "ss", PURPLE_CMD_P_PLUGIN, PURPLE_CMD_FLAG_CHAT |
685 						PURPLE_CMD_FLAG_PROTOCOL_ONLY,
686 						SKYPEWEB_PLUGIN_ID, skypeweb_cmd_setrole,
687 						_("setrole &lt;user&gt; &lt;MASTER | USER | ADMIN&gt;:  Change the role of a user."),
688 						NULL);
689 	*/
690 
691 	purple_cmd_register("list", "", PURPLE_CMD_P_PLUGIN, PURPLE_CMD_FLAG_CHAT |
692 						PURPLE_CMD_FLAG_PROTOCOL_ONLY | PURPLE_CMD_FLAG_IM,
693 						SKYPEWEB_PLUGIN_ID, skypeweb_cmd_list,
694 						_("list: Display a list of multi-chat group chats you are in."),
695 						NULL);
696 
697 	purple_signal_connect(purple_get_core(), "uri-handler", plugin, PURPLE_CALLBACK(skypeweb_uri_handler), NULL);
698 
699 	return TRUE;
700 }
701 
702 static gboolean
plugin_unload(PurplePlugin * plugin,GError ** error)703 plugin_unload(PurplePlugin *plugin
704 #if PURPLE_VERSION_CHECK(3, 0, 0)
705 , GError **error
706 #endif
707 )
708 {
709 #if !PURPLE_VERSION_CHECK(3, 0, 0)
710 	_purple_socket_uninit();
711 	purple_http_uninit();
712 #endif
713 	purple_signals_disconnect_by_handle(plugin);
714 
715 	return TRUE;
716 }
717 
718 static GList *
skypeweb_actions(PurplePlugin * plugin,gpointer context)719 skypeweb_actions(
720 #if !PURPLE_VERSION_CHECK(3, 0, 0)
721 PurplePlugin *plugin, gpointer context
722 #else
723 PurpleConnection *pc
724 #endif
725 )
726 {
727 	GList *m = NULL;
728 	PurpleProtocolAction *act;
729 
730 	act = purple_protocol_action_new(_("Search for friends..."), skypeweb_search_users);
731 	m = g_list_append(m, act);
732 
733 	act = purple_protocol_action_new(_("People you might know..."), skypeweb_contact_suggestions);
734 	m = g_list_append(m, act);
735 
736 	return m;
737 }
738 
739 #if !PURPLE_VERSION_CHECK(2, 8, 0)
740 #	define OPT_PROTO_INVITE_MESSAGE 0x00000800
741 #endif
742 
743 #if !PURPLE_VERSION_CHECK(3, 0, 0)
744 static void
plugin_init(PurplePlugin * plugin)745 plugin_init(PurplePlugin *plugin)
746 {
747 	PurplePluginInfo *info = g_new0(PurplePluginInfo, 1);
748 	PurplePluginProtocolInfo *prpl_info = g_new0(PurplePluginProtocolInfo, 1);
749 #endif
750 
751 #if PURPLE_VERSION_CHECK(3, 0, 0)
752 static void
753 skypeweb_protocol_init(PurpleProtocol *prpl_info)
754 {
755 	PurpleProtocol *info = prpl_info;
756 #endif
757 	PurpleAccountOption *typing_type1, *typing_type2, *alt_login;
758 	PurpleBuddyIconSpec icon_spec = {"jpeg", 0, 0, 96, 96, 0, PURPLE_ICON_SCALE_DISPLAY};
759 
760 	//PurpleProtocol
761 	info->id = SKYPEWEB_PLUGIN_ID;
762 	info->name = "Skype (HTTP)";
763 	prpl_info->options = OPT_PROTO_CHAT_TOPIC | OPT_PROTO_INVITE_MESSAGE /*| OPT_PROTO_IM_IMAGE*/;
764 	typing_type1 = purple_account_option_bool_new(N_("Show 'Typing' status as system message in chat window."), "show-typing-as-text", FALSE);
765 	typing_type2 = purple_account_option_bool_new(N_("Show 'Typing' status with 'Voice' icon near buddy name."), "show-typing-as-icon", FALSE);
766 	alt_login = purple_account_option_bool_new(N_("Use alternative login method"), "alt-login", TRUE);
767 
768 #if !PURPLE_VERSION_CHECK(3, 0, 0)
769 	prpl_info->protocol_options = g_list_append(prpl_info->protocol_options, typing_type1);
770 	prpl_info->protocol_options = g_list_append(prpl_info->protocol_options, typing_type2);
771 	prpl_info->protocol_options = g_list_append(prpl_info->protocol_options, alt_login);
772 	prpl_info->icon_spec = icon_spec;
773 #else
774 	prpl_info->account_options = g_list_append(prpl_info->account_options, typing_type1);
775 	prpl_info->account_options = g_list_append(prpl_info->account_options, typing_type2);
776 	prpl_info->account_options = g_list_append(prpl_info->account_options, alt_login);
777 	prpl_info->icon_spec = &icon_spec;
778 #endif
779 
780 #if PURPLE_VERSION_CHECK(3, 0, 0)
781 }
782 
783 static void
784 skypeweb_protocol_class_init(PurpleProtocolClass *prpl_info)
785 {
786 #endif
787 	//PurpleProtocolClass
788 	prpl_info->login = skypeweb_login;
789 	prpl_info->close = skypeweb_close;
790 	prpl_info->status_types = skypeweb_status_types;
791 	prpl_info->list_icon = skypeweb_list_icon;
792 #if PURPLE_VERSION_CHECK(3, 0, 0)
793 }
794 
795 static void
796 skypeweb_protocol_client_iface_init(PurpleProtocolClientIface *prpl_info)
797 {
798 	PurpleProtocolClientIface *info = prpl_info;
799 #endif
800 
801 	//PurpleProtocolClientIface
802 #if !PURPLE_VERSION_CHECK(3, 0, 0)
803 	info->actions = skypeweb_actions;
804 #else
805 	info->get_actions = skypeweb_actions;
806 #endif
807 	prpl_info->list_emblem = skypeweb_list_emblem;
808 	prpl_info->status_text = skypeweb_status_text;
809 	prpl_info->tooltip_text = skypeweb_tooltip_text;
810 	prpl_info->blist_node_menu = skypeweb_node_menu;
811 	prpl_info->buddy_free = skypeweb_buddy_free;
812 	prpl_info->normalize = purple_normalize_nocase;
813 	prpl_info->offline_message = skypeweb_offline_message;
814 	prpl_info->get_account_text_table = NULL; // skypeweb_get_account_text_table;
815 #if PURPLE_VERSION_CHECK(3, 0, 0)
816 }
817 
818 static void
819 skypeweb_protocol_server_iface_init(PurpleProtocolServerIface *prpl_info)
820 {
821 #endif
822 
823 	//PurpleProtocolServerIface
824 	prpl_info->get_info = skypeweb_get_info;
825 	prpl_info->set_status = skypeweb_set_status;
826 	prpl_info->set_idle = skypeweb_set_idle;
827 #if !PURPLE_VERSION_CHECK(3, 0, 0)
828 	prpl_info->add_buddy = skypeweb_add_buddy;
829 #else
830 	prpl_info->add_buddy = skypeweb_add_buddy_with_invite;
831 #endif
832 	prpl_info->remove_buddy = skypeweb_buddy_remove;
833 	prpl_info->group_buddy = skypeweb_fake_group_buddy;
834 	prpl_info->rename_group = skypeweb_fake_group_rename;
835 #if PURPLE_VERSION_CHECK(3, 0, 0)
836 }
837 
838 static void
839 skypeweb_protocol_im_iface_init(PurpleProtocolIMIface *prpl_info)
840 {
841 #endif
842 
843 	//PurpleProtocolIMIface
844 #if !PURPLE_VERSION_CHECK(3, 0, 0)
845 	prpl_info->send_im = skypeweb_send_im;
846 #else
847 	prpl_info->send = skypeweb_send_im;
848 #endif
849 	prpl_info->send_typing = skypeweb_send_typing;
850 #if PURPLE_VERSION_CHECK(3, 0, 0)
851 }
852 
853 static void
854 skypeweb_protocol_chat_iface_init(PurpleProtocolChatIface *prpl_info)
855 {
856 #endif
857 
858 	//PurpleProtocolChatIface
859 #if !PURPLE_VERSION_CHECK(3, 0, 0)
860 	prpl_info->chat_info = skypeweb_chat_info;
861 	prpl_info->chat_info_defaults = skypeweb_chat_info_defaults;
862 	prpl_info->join_chat = skypeweb_join_chat;
863 	prpl_info->get_chat_name = skypeweb_get_chat_name;
864 	prpl_info->chat_invite = skypeweb_chat_invite;
865 	prpl_info->chat_leave =	NULL; //skypeweb_chat_fake_leave;
866 	prpl_info->chat_send = skypeweb_chat_send;
867 	prpl_info->set_chat_topic = skypeweb_chat_set_topic;
868 #else
869 	prpl_info->info = skypeweb_chat_info;
870 	prpl_info->info_defaults = skypeweb_chat_info_defaults;
871 	prpl_info->join = skypeweb_join_chat;
872 	prpl_info->get_name = skypeweb_get_chat_name;
873 	prpl_info->invite = skypeweb_chat_invite;
874 	prpl_info->leave =	NULL; //skypeweb_chat_fake_leave;
875 	prpl_info->send = skypeweb_chat_send;
876 	prpl_info->set_topic = skypeweb_chat_set_topic;
877 #endif
878 #if PURPLE_VERSION_CHECK(3, 0, 0)
879 }
880 
881 static void
882 skypeweb_protocol_privacy_iface_init(PurpleProtocolPrivacyIface *prpl_info)
883 {
884 #endif
885 
886 	//PurpleProtocolPrivacyIface
887 	prpl_info->add_deny = skypeweb_buddy_block;
888 	prpl_info->rem_deny = skypeweb_buddy_unblock;
889 #if PURPLE_VERSION_CHECK(3, 0, 0)
890 }
891 
892 static void
893 skypeweb_protocol_xfer_iface_init(PurpleProtocolXferInterface *prpl_info)
894 {
895 #endif
896 
897 	//PurpleProtocolXferInterface
898 	prpl_info->new_xfer = skypeweb_new_xfer;
899 	prpl_info->send_file = skypeweb_send_file;
900 #if !PURPLE_VERSION_CHECK(3, 0, 0)
901 	prpl_info->can_receive_file = skypeweb_can_receive_file;
902 #else
903 	prpl_info->can_receive = skypeweb_can_receive_file;
904 #endif
905 
906 #if PURPLE_VERSION_CHECK(3, 0, 0)
907 }
908 
909 static void
910 skypeweb_protocol_roomlist_iface_init(PurpleProtocolRoomlistIface *prpl_info)
911 {
912 #endif
913 
914 	//PurpleProtocolRoomlistIface
915 #if !PURPLE_VERSION_CHECK(3, 0, 0)
916 	prpl_info->roomlist_get_list = skypeweb_roomlist_get_list;
917 #else
918 	prpl_info->get_list = skypeweb_roomlist_get_list;
919 #endif
920 
921 #if !PURPLE_VERSION_CHECK(3, 0, 0)
922 	// Plugin info
923 	info->magic = PURPLE_PLUGIN_MAGIC;
924 	info->major_version = 2;
925 	info->minor_version = MIN(PURPLE_MINOR_VERSION, 8);
926 	info->type = PURPLE_PLUGIN_PROTOCOL;
927 	info->priority = PURPLE_PRIORITY_DEFAULT;
928 	info->version = SKYPEWEB_PLUGIN_VERSION;
929 	info->summary = N_("Skype for Web Protocol Plugin");
930 	info->description = N_("Skype for Web Protocol Plugin");
931 	info->author = "Eion Robb <eionrobb@gmail.com>";
932 	info->homepage = "http://github.com/EionRobb/skype4pidgin";
933 	info->load = plugin_load;
934 	info->unload = plugin_unload;
935 	info->extra_info = prpl_info;
936 
937 	// Protocol info
938 	#if PURPLE_MINOR_VERSION >= 5
939 		prpl_info->struct_size = sizeof(PurplePluginProtocolInfo);
940 	#endif
941 	#if PURPLE_MINOR_VERSION >= 8
942 		prpl_info->add_buddy_with_invite = skypeweb_add_buddy_with_invite;
943 	#endif
944 
945 	plugin->info = info;
946 #endif
947 
948 }
949 
950 #if PURPLE_VERSION_CHECK(3, 0, 0)
951 
952 
953 PURPLE_DEFINE_TYPE_EXTENDED(
954 	SkypeWebProtocol, skypeweb_protocol, PURPLE_TYPE_PROTOCOL, 0,
955 
956 	PURPLE_IMPLEMENT_INTERFACE_STATIC(PURPLE_TYPE_PROTOCOL_CLIENT_IFACE,
957 	                                  skypeweb_protocol_client_iface_init)
958 
959 	PURPLE_IMPLEMENT_INTERFACE_STATIC(PURPLE_TYPE_PROTOCOL_SERVER_IFACE,
960 	                                  skypeweb_protocol_server_iface_init)
961 
962 	PURPLE_IMPLEMENT_INTERFACE_STATIC(PURPLE_TYPE_PROTOCOL_IM_IFACE,
963 	                                  skypeweb_protocol_im_iface_init)
964 
965 	PURPLE_IMPLEMENT_INTERFACE_STATIC(PURPLE_TYPE_PROTOCOL_CHAT_IFACE,
966 	                                  skypeweb_protocol_chat_iface_init)
967 
968 	PURPLE_IMPLEMENT_INTERFACE_STATIC(PURPLE_TYPE_PROTOCOL_PRIVACY_IFACE,
969 	                                  skypeweb_protocol_privacy_iface_init)
970 
971 	PURPLE_IMPLEMENT_INTERFACE_STATIC(PURPLE_TYPE_PROTOCOL_ROOMLIST_IFACE,
972 	                                  skypeweb_protocol_roomlist_iface_init)
973 
974 	PURPLE_IMPLEMENT_INTERFACE_STATIC(PURPLE_TYPE_PROTOCOL_XFER,
975 	                                  skypeweb_protocol_xfer_iface_init)
976 );
977 
978 static gboolean
979 libpurple3_plugin_load(PurplePlugin *plugin, GError **error)
980 {
981 	skypeweb_protocol_register_type(plugin);
982 	skypeweb_protocol = purple_protocols_add(SKYPEWEB_TYPE_PROTOCOL, error);
983 	if (!skypeweb_protocol)
984 		return FALSE;
985 
986 	return plugin_load(plugin, error);
987 }
988 
989 static gboolean
990 libpurple3_plugin_unload(PurplePlugin *plugin, GError **error)
991 {
992 	if (!plugin_unload(plugin, error))
993 		return FALSE;
994 
995 	if (!purple_protocols_remove(skypeweb_protocol, error))
996 		return FALSE;
997 
998 	return TRUE;
999 }
1000 
1001 static PurplePluginInfo *
1002 plugin_query(GError **error)
1003 {
1004 	return purple_plugin_info_new(
1005 		"id",           SKYPEWEB_PLUGIN_ID,
1006 		"name",         "SkypeWeb Protocol",
1007 		"version",      SKYPEWEB_PLUGIN_VERSION,
1008 		"category",     N_("Protocol"),
1009 		"summary",      N_("SkypeWeb Protocol Plugin"),
1010 		"description",  N_("SkypeWeb Protocol Plugin"),
1011 		"website",      "http://github.com/EionRobb/skype4pidgin",
1012 		"abi-version",  PURPLE_ABI_VERSION,
1013 		"flags",        PURPLE_PLUGIN_INFO_FLAGS_INTERNAL |
1014 		                PURPLE_PLUGIN_INFO_FLAGS_AUTO_LOAD,
1015 		NULL
1016 	);
1017 }
1018 
1019 
1020 PURPLE_PLUGIN_INIT(skypeweb, plugin_query, libpurple3_plugin_load, libpurple3_plugin_unload);
1021 #else
1022 
1023 static PurplePluginInfo aLovelyBunchOfCoconuts;
1024 PURPLE_INIT_PLUGIN(skypeweb, plugin_init, aLovelyBunchOfCoconuts);
1025 #endif
1026 
1027