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 #ifndef LIBSKYPEWEB_H
20 #define LIBSKYPEWEB_H
21 
22 #ifndef PURPLE_PLUGINS
23 #	define PURPLE_PLUGINS
24 #endif
25 
26 /* Maximum number of simultaneous connections to a server */
27 #define SKYPEWEB_MAX_CONNECTIONS 16
28 
29 #include <glib.h>
30 
31 #include <inttypes.h>
32 #include <errno.h>
33 #include <string.h>
34 #include <glib/gi18n.h>
35 #include <sys/types.h>
36 #ifdef __GNUC__
37 	#include <sys/time.h>
38 	#include <unistd.h>
39 #endif
40 
41 #ifndef G_GNUC_NULL_TERMINATED
42 #	if __GNUC__ >= 4
43 #		define G_GNUC_NULL_TERMINATED __attribute__((__sentinel__))
44 #	else
45 #		define G_GNUC_NULL_TERMINATED
46 #	endif /* __GNUC__ >= 4 */
47 #endif /* G_GNUC_NULL_TERMINATED */
48 
49 // workaround for MinGW32 which doesn't support "%zu"; see also https://stackoverflow.com/a/44383330
50 #ifdef _WIN32
51 #  ifdef _WIN64
52 #    define PRI_SIZET PRIu64
53 #  else
54 #    define PRI_SIZET PRIu32
55 #  endif
56 #else
57 #  define PRI_SIZET "zu"
58 #endif
59 
60 #include "purplecompat.h"
61 
62 #ifdef _WIN32
63 #	define dlopen(a,b) LoadLibrary(a)
64 #	define RTLD_LAZY
65 #	define dlsym(a,b) GetProcAddress(a,b)
66 #	define dlclose(a) FreeLibrary(a)
67 #else
68 #	include <arpa/inet.h>
69 #	include <dlfcn.h>
70 #	include <netinet/in.h>
71 #	include <sys/socket.h>
72 #endif
73 
74 #include <json-glib/json-glib.h>
75 
76 #define json_object_get_int_member(JSON_OBJECT, MEMBER) \
77 	((JSON_OBJECT) && json_object_has_member((JSON_OBJECT), (MEMBER)) ? json_object_get_int_member((JSON_OBJECT), (MEMBER)) : 0)
78 #define json_object_get_string_member(JSON_OBJECT, MEMBER) \
79 	((JSON_OBJECT) && json_object_has_member((JSON_OBJECT), (MEMBER)) ? json_object_get_string_member((JSON_OBJECT), (MEMBER)) : NULL)
80 #define json_object_get_array_member(JSON_OBJECT, MEMBER) \
81 	((JSON_OBJECT) && json_object_has_member((JSON_OBJECT), (MEMBER)) ? json_object_get_array_member((JSON_OBJECT), (MEMBER)) : NULL)
82 #define json_object_get_object_member(JSON_OBJECT, MEMBER) \
83 	((JSON_OBJECT) && json_object_has_member((JSON_OBJECT), (MEMBER)) ? json_object_get_object_member((JSON_OBJECT), (MEMBER)) : NULL)
84 #define json_object_get_boolean_member(JSON_OBJECT, MEMBER) \
85 	((JSON_OBJECT) && json_object_has_member((JSON_OBJECT), (MEMBER)) ? json_object_get_boolean_member((JSON_OBJECT), (MEMBER)) : FALSE)
86 #define json_array_get_length(JSON_ARRAY) \
87 	((JSON_ARRAY) ? json_array_get_length(JSON_ARRAY) : 0)
88 #define json_node_get_array(JSON_NODE) \
89 	((JSON_NODE) && JSON_NODE_TYPE(JSON_NODE) == (JSON_NODE_ARRAY) ? json_node_get_array(JSON_NODE) : NULL)
90 
91 #include "accountopt.h"
92 #include "core.h"
93 #include "cmds.h"
94 #include "connection.h"
95 #include "debug.h"
96 #include "http.h"
97 #include "plugins.h"
98 #include "proxy.h"
99 #include "request.h"
100 #include "roomlist.h"
101 #include "savedstatuses.h"
102 #include "sslconn.h"
103 #include "util.h"
104 #include "version.h"
105 
106 
107 #if GLIB_MAJOR_VERSION >= 2 && GLIB_MINOR_VERSION >= 12
108 #	define atoll(a) g_ascii_strtoll(a, NULL, 0)
109 #endif
110 
111 
112 #define SKYPEWEB_MAX_MSG_RETRY 2
113 
114 #define SKYPEWEB_PLUGIN_ID "prpl-skypeweb"
115 #define SKYPEWEB_PLUGIN_VERSION "1.7"
116 
117 #define SKYPEWEB_LOCKANDKEY_APPID "msmsgs@msnmsgr.com"
118 #define SKYPEWEB_LOCKANDKEY_SECRET "Q1P7W2E4J9R8U3S5"
119 
120 #define SKYPEWEB_CONTACTS_HOST "api.skype.com"
121 #define SKYPEWEB_NEW_CONTACTS_HOST "contacts.skype.com"
122 #define SKYPEWEB_DEFAULT_MESSAGES_HOST "client-s.gateway.messenger.live.com"
123 #define SKYPEWEB_LOGIN_HOST "login.skype.com"
124 #define SKYPEWEB_VIDEOMAIL_HOST "vm.skype.com"
125 #define SKYPEWEB_XFER_HOST "api.asm.skype.com"
126 #define SKYPEWEB_GRAPH_HOST "skypegraph.skype.com"
127 #define SKYPEWEB_STATIC_HOST "static.asm.skype.com"
128 #define SKYPEWEB_STATIC_CDN_HOST "static-asm.secure.skypeassets.com"
129 #define SKYPEWEB_DEFAULT_CONTACT_SUGGESTIONS_HOST "peoplerecommendations.skype.com"
130 
131 #define SKYPEWEB_VDMS_TTL 300
132 
133 #define SKYPEWEB_CLIENTINFO_NAME "swx-skype.com"
134 #define SKYPEWEB_CLIENTINFO_VERSION "908/1.85.0.29"
135 
136 #define SKYPEWEB_STATUS_ONLINE "Online"
137 #define SKYPEWEB_STATUS_IDLE "Idle"
138 #define SKYPEWEB_STATUS_AWAY "Away"
139 #define SKYPEWEB_STATUS_BUSY "Busy"
140 #define SKYPEWEB_STATUS_HIDDEN "Hidden"
141 #define SKYPEWEB_STATUS_OFFLINE "Offline"
142 
143 
144 #define SKYPEWEB_BUDDY_IS_MSN(a) G_UNLIKELY((a) != NULL && strchr((a), '@') != NULL)
145 #define SKYPEWEB_BUDDY_IS_PHONE(a) G_UNLIKELY((a) != NULL && *(a) == '+')
146 #define SKYPEWEB_BUDDY_IS_S4B(a) G_UNLIKELY((a) != NULL && g_str_has_prefix((a), "2:"))
147 #define SKYPEWEB_BUDDY_IS_BOT(a) G_UNLIKELY((a) != NULL && g_str_has_prefix((a), "28:"))
148 
149 typedef struct _SkypeWebAccount SkypeWebAccount;
150 typedef struct _SkypeWebBuddy SkypeWebBuddy;
151 
152 typedef void (*SkypeWebFunc)(SkypeWebAccount *swa);
153 
154 struct _SkypeWebAccount {
155 	gchar *username;
156 	gchar *primary_member_name;
157 	gchar *self_display_name;
158 
159 	PurpleAccount *account;
160 	PurpleConnection *pc;
161 	PurpleHttpKeepalivePool *keepalive_pool;
162 	PurpleHttpConnectionSet *conns;
163 	PurpleHttpCookieJar *cookie_jar;
164 	gchar *messages_host;
165 
166 	GHashTable *sent_messages_hash;
167 	guint poll_timeout;
168 	guint watchdog_timeout;
169 
170 	guint authcheck_timeout;
171 	time_t last_authrequest;
172 
173 	gchar *skype_token;
174 	gchar *registration_token;
175 	gchar *vdms_token;
176 	gchar *endpoint;
177 	gint registration_expiry;
178 	gint vdms_expiry;
179 };
180 
181 struct _SkypeWebBuddy {
182 	SkypeWebAccount *sa;
183 	PurpleBuddy *buddy;
184 
185 	/** Contact info */
186 	gchar *skypename;
187 	gchar *fullname;
188 	gchar *display_name;
189 	gboolean authorized;
190 	gboolean blocked;
191 
192 	/** Profile info */
193 	gchar *avatar_url;
194 	gchar *mood;
195 };
196 
197 void skypeweb_buddy_free(PurpleBuddy *buddy);
198 
199 void skypeweb_do_all_the_things(SkypeWebAccount *sa);
200 
201 #endif /* LIBSKYPEWEB_H */
202