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 "skypeweb_connection.h"
20 
21 #include "http.h"
22 
23 static void
skypeweb_destroy_connection(SkypeWebConnection * conn)24 skypeweb_destroy_connection(SkypeWebConnection *conn)
25 {
26 	g_free(conn->url);
27 	g_free(conn);
28 }
29 
30 static void
skypeweb_post_or_get_cb(PurpleHttpConnection * http_conn,PurpleHttpResponse * response,gpointer user_data)31 skypeweb_post_or_get_cb(PurpleHttpConnection *http_conn, PurpleHttpResponse *response, gpointer user_data)
32 {
33 	SkypeWebConnection *conn = user_data;
34 	const gchar *data;
35 	gsize len;
36 
37 	data = purple_http_response_get_data(response, &len);
38 
39 	if (conn->callback != NULL) {
40 		if (!len)
41 		{
42 			purple_debug_info("skypeweb", "No data in response\n");
43 			conn->callback(conn->sa, NULL, conn->user_data);
44 		} else {
45 			JsonParser *parser = json_parser_new();
46 			if (!json_parser_load_from_data(parser, data, len, NULL))
47 			{
48 				if (conn->error_callback != NULL) {
49 					conn->error_callback(conn->sa, data, len, conn->user_data);
50 				} else {
51 					purple_debug_error("skypeweb", "Error parsing response: %s\n", data);
52 				}
53 			} else {
54 				JsonNode *root = json_parser_get_root(parser);
55 
56 				purple_debug_info("skypeweb", "executing callback for %s\n", conn->url);
57 				conn->callback(conn->sa, root, conn->user_data);
58 			}
59 			g_object_unref(parser);
60 		}
61 	}
62 
63 	skypeweb_destroy_connection(conn);
64 }
65 
skypeweb_post_or_get(SkypeWebAccount * sa,SkypeWebMethod method,const gchar * host,const gchar * url,const gchar * postdata,SkypeWebProxyCallbackFunc callback_func,gpointer user_data,gboolean keepalive)66 SkypeWebConnection *skypeweb_post_or_get(SkypeWebAccount *sa, SkypeWebMethod method,
67 		const gchar *host, const gchar *url, const gchar *postdata,
68 		SkypeWebProxyCallbackFunc callback_func, gpointer user_data,
69 		gboolean keepalive)
70 {
71 	SkypeWebConnection *conn;
72 	PurpleHttpRequest *request;
73 	const gchar* const *languages;
74 	gchar *language_names;
75 	gchar *real_url;
76 
77 	g_return_val_if_fail(host != NULL, NULL);
78 	g_return_val_if_fail(url != NULL, NULL);
79 
80 	real_url = g_strdup_printf("%s://%s%s", method & SKYPEWEB_METHOD_SSL ? "https" : "http", host, url);
81 
82 	request = purple_http_request_new(real_url);
83 	if (method & SKYPEWEB_METHOD_POST) {
84 		purple_http_request_set_method(request, "POST");
85 	} else if (method & SKYPEWEB_METHOD_PUT) {
86 		purple_http_request_set_method(request, "PUT");
87 	} else if (method & SKYPEWEB_METHOD_DELETE) {
88 		purple_http_request_set_method(request, "DELETE");
89 	}
90 	if (keepalive) {
91 		purple_http_request_set_keepalive_pool(request, sa->keepalive_pool);
92 	}
93 
94 	purple_http_request_set_max_redirects(request, 0);
95 	purple_http_request_set_timeout(request, 120);
96 
97 	if (method & (SKYPEWEB_METHOD_POST | SKYPEWEB_METHOD_PUT)) {
98 		if (postdata && (postdata[0] == '[' || postdata[0] == '{')) {
99 			purple_http_request_header_set(request, "Content-Type", "application/json"); // hax
100 		} else {
101 			purple_http_request_header_set(request, "Content-Type", "application/x-www-form-urlencoded");
102 		}
103 		purple_http_request_set_contents(request, postdata, -1);
104 
105 		//Zero-length PUT's dont get the content-length header set
106 		if ((method & SKYPEWEB_METHOD_PUT) && (!postdata || !*postdata)) {
107 			purple_http_request_header_set(request, "Content-Length", "0");
108 		}
109 	}
110 
111 	if (g_str_equal(host, SKYPEWEB_CONTACTS_HOST) || g_str_equal(host, SKYPEWEB_VIDEOMAIL_HOST) || g_str_equal(host, SKYPEWEB_NEW_CONTACTS_HOST)) {
112 		purple_http_request_header_set(request, "X-Skypetoken", sa->skype_token);
113 		purple_http_request_header_set(request, "X-Stratus-Caller", SKYPEWEB_CLIENTINFO_NAME);
114 		purple_http_request_header_set(request, "X-Stratus-Request", "abcd1234");
115 		purple_http_request_header_set(request, "Origin", "https://web.skype.com");
116 		purple_http_request_header_set(request, "Referer", "https://web.skype.com/main");
117 		purple_http_request_header_set(request, "Accept", "application/json; ver=1.0;");
118 	} else if (g_str_equal(host, SKYPEWEB_GRAPH_HOST)) {
119 		purple_http_request_header_set(request, "X-Skypetoken", sa->skype_token);
120 		purple_http_request_header_set(request, "Accept", "application/json");
121 	} else if (g_str_equal(host, sa->messages_host)) {
122 		purple_http_request_header_set(request, "RegistrationToken", sa->registration_token);
123 		purple_http_request_header_set(request, "Referer", "https://web.skype.com/main");
124 		purple_http_request_header_set(request, "Accept", "application/json; ver=1.0");
125 		purple_http_request_header_set(request, "ClientInfo", "os=Windows; osVer=8.1; proc=Win32; lcid=en-us; deviceType=1; country=n/a; clientName=" SKYPEWEB_CLIENTINFO_NAME "; clientVer=" SKYPEWEB_CLIENTINFO_VERSION);
126 	} else if (g_str_equal(host, SKYPEWEB_DEFAULT_CONTACT_SUGGESTIONS_HOST)) {
127 		purple_http_request_header_set(request, "X-RecommenderServiceSettings", "{\"experiment\":\"default\",\"recommend\":\"true\"}");
128 		purple_http_request_header_set(request, "X-ECS-ETag", SKYPEWEB_CLIENTINFO_NAME);
129 		purple_http_request_header_set(request, "X-Skypetoken", sa->skype_token);
130 		purple_http_request_header_set(request, "Accept", "application/json");
131 		purple_http_request_header_set(request, "X-Skype-Client", SKYPEWEB_CLIENTINFO_VERSION);
132 	} else {
133 		purple_http_request_header_set(request, "Accept", "*/*");
134 		purple_http_request_set_cookie_jar(request, sa->cookie_jar);
135 	}
136 
137 	/* Tell the server what language we accept, so that we get error messages in our language (rather than our IP's) */
138 	languages = g_get_language_names();
139 	language_names = g_strjoinv(", ", (gchar **)languages);
140 	purple_util_chrreplace(language_names, '_', '-');
141 	purple_http_request_header_set(request, "Accept-Language", language_names);
142 	g_free(language_names);
143 
144 	conn = g_new0(SkypeWebConnection, 1);
145 	conn->sa = sa;
146 	conn->user_data = user_data;
147 	conn->url = real_url;
148 	conn->callback = callback_func;
149 
150 	conn->http_conn = purple_http_request(sa->pc, request, skypeweb_post_or_get_cb, conn);
151 	purple_http_connection_set_add(sa->conns, conn->http_conn);
152 
153 	purple_http_request_unref(request);
154 
155 	return conn;
156 }
157