1 /*
2 * libokcupid
3 *
4 * libokcupid is the property of its developers. See the COPYRIGHT file
5 * for more details.
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "okc_connection.h"
22
23 static void okc_attempt_connection(OkCupidConnection *);
24 static void okc_next_connection(OkCupidAccount *oca);
25
okc_gunzip(const guchar * gzip_data,ssize_t * len_ptr)26 static gchar *okc_gunzip(const guchar *gzip_data, ssize_t *len_ptr)
27 {
28 gsize gzip_data_len = *len_ptr;
29 z_stream zstr;
30 int gzip_err = 0;
31 gchar *data_buffer;
32 gulong gzip_len = G_MAXUINT16;
33 GString *output_string = NULL;
34
35 data_buffer = g_new0(gchar, gzip_len);
36
37 zstr.next_in = NULL;
38 zstr.avail_in = 0;
39 zstr.zalloc = Z_NULL;
40 zstr.zfree = Z_NULL;
41 zstr.opaque = 0;
42 gzip_err = inflateInit2(&zstr, MAX_WBITS+32);
43 if (gzip_err != Z_OK)
44 {
45 g_free(data_buffer);
46 purple_debug_error("okcupid", "no built-in gzip support in zlib\n");
47 return NULL;
48 }
49
50 zstr.next_in = (Bytef *)gzip_data;
51 zstr.avail_in = gzip_data_len;
52
53 zstr.next_out = (Bytef *)data_buffer;
54 zstr.avail_out = gzip_len;
55
56 gzip_err = inflate(&zstr, Z_SYNC_FLUSH);
57
58 if (gzip_err == Z_DATA_ERROR)
59 {
60 inflateEnd(&zstr);
61 inflateInit2(&zstr, -MAX_WBITS);
62 if (gzip_err != Z_OK)
63 {
64 g_free(data_buffer);
65 purple_debug_error("okcupid", "Cannot decode gzip header\n");
66 return NULL;
67 }
68 zstr.next_in = (Bytef *)gzip_data;
69 zstr.avail_in = gzip_data_len;
70 zstr.next_out = (Bytef *)data_buffer;
71 zstr.avail_out = gzip_len;
72 gzip_err = inflate(&zstr, Z_SYNC_FLUSH);
73 }
74 output_string = g_string_new("");
75 while (gzip_err == Z_OK)
76 {
77 //append data to buffer
78 output_string = g_string_append_len(output_string, data_buffer, gzip_len - zstr.avail_out);
79 //reset buffer pointer
80 zstr.next_out = (Bytef *)data_buffer;
81 zstr.avail_out = gzip_len;
82 gzip_err = inflate(&zstr, Z_SYNC_FLUSH);
83 }
84 if (gzip_err == Z_STREAM_END)
85 {
86 output_string = g_string_append_len(output_string, data_buffer, gzip_len - zstr.avail_out);
87 } else {
88 purple_debug_error("okcupid", "gzip inflate error\n");
89 }
90 inflateEnd(&zstr);
91
92 g_free(data_buffer);
93
94 gchar *output_data = g_strdup(output_string->str);
95 *len_ptr = output_string->len;
96
97 g_string_free(output_string, TRUE);
98
99 return output_data;
100 }
101
okc_connection_destroy(OkCupidConnection * okconn)102 void okc_connection_destroy(OkCupidConnection *okconn)
103 {
104 okconn->oca->conns = g_slist_remove(okconn->oca->conns, okconn);
105
106 if (okconn->request != NULL)
107 g_string_free(okconn->request, TRUE);
108
109 g_free(okconn->rx_buf);
110
111 if (okconn->connect_data != NULL)
112 purple_proxy_connect_cancel(okconn->connect_data);
113
114 if (okconn->ssl_conn != NULL)
115 purple_ssl_close(okconn->ssl_conn);
116
117 if (okconn->fd >= 0) {
118 close(okconn->fd);
119 }
120
121 if (okconn->input_watcher > 0)
122 purple_input_remove(okconn->input_watcher);
123
124 g_free(okconn->hostname);
125 g_free(okconn);
126 }
127
okc_update_cookies(OkCupidAccount * oca,const gchar * headers)128 static void okc_update_cookies(OkCupidAccount *oca, const gchar *headers)
129 {
130 const gchar *cookie_start;
131 const gchar *cookie_end;
132 gchar *cookie_name;
133 gchar *cookie_value;
134 int header_len;
135
136 g_return_if_fail(headers != NULL);
137
138 header_len = strlen(headers);
139
140 /* look for the next "Set-Cookie: " */
141 /* grab the data up until ';' */
142 cookie_start = headers;
143 while ((cookie_start = strstr(cookie_start, "\r\nSet-Cookie: ")) &&
144 (headers-cookie_start) < header_len)
145 {
146 cookie_start += 14;
147 cookie_end = strchr(cookie_start, '=');
148 cookie_name = g_strndup(cookie_start, cookie_end-cookie_start);
149 cookie_start = cookie_end + 1;
150 cookie_end = strchr(cookie_start, ';');
151 cookie_value= g_strndup(cookie_start, cookie_end-cookie_start);
152 cookie_start = cookie_end;
153
154 purple_debug_info("okcupid", "got cookie %s=%s\n",
155 cookie_name, cookie_value);
156
157 g_hash_table_replace(oca->cookie_table, cookie_name,
158 cookie_value);
159 }
160 }
161
okc_connection_process_data(OkCupidConnection * okconn)162 static void okc_connection_process_data(OkCupidConnection *okconn)
163 {
164 ssize_t len;
165 gchar *tmp;
166
167 len = okconn->rx_len;
168 tmp = g_strstr_len(okconn->rx_buf, len, "\r\n\r\n");
169 if (tmp == NULL) {
170 /* This is a corner case that occurs when the connection is
171 * prematurely closed either on the client or the server.
172 * This can either be no data at all or a partial set of
173 * headers. We pass along the data to be good, but don't
174 * do any fancy massaging. In all likelihood the result will
175 * be tossed by the connection callback func anyways
176 */
177 tmp = g_strndup(okconn->rx_buf, len);
178 } else {
179 tmp += 4;
180 len -= g_strstr_len(okconn->rx_buf, len, "\r\n\r\n") -
181 okconn->rx_buf + 4;
182 tmp = g_memdup(tmp, len + 1);
183 tmp[len] = '\0';
184 okconn->rx_buf[okconn->rx_len - len] = '\0';
185 //purple_debug_misc("okcupid", "response headers\n%s\n",
186 // okconn->rx_buf);
187 okc_update_cookies(okconn->oca, okconn->rx_buf);
188
189 if (strstr(okconn->rx_buf, "Content-Encoding: gzip"))
190 {
191 /* we've received compressed gzip data, decompress */
192 gchar *gunzipped;
193 gunzipped = okc_gunzip((const guchar *)tmp, &len);
194 g_free(tmp);
195 tmp = gunzipped;
196 }
197 }
198
199 g_free(okconn->rx_buf);
200 okconn->rx_buf = NULL;
201
202 if (okconn->callback != NULL)
203 okconn->callback(okconn->oca, tmp, len, okconn->user_data);
204
205 g_free(tmp);
206 }
207
okc_fatal_connection_cb(OkCupidConnection * okconn)208 static void okc_fatal_connection_cb(OkCupidConnection *okconn)
209 {
210 PurpleConnection *pc = okconn->oca->pc;
211
212 purple_debug_error("okcupid", "fatal connection error\n");
213
214 okc_connection_destroy(okconn);
215
216 /* We died. Do not pass Go. Do not collect $200 */
217 /* In all seriousness, don't attempt to call the normal callback here.
218 * That may lead to the wrong error message being displayed */
219 purple_connection_error_reason(pc,
220 PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
221 _("Server closed the connection."));
222
223 }
224
okc_post_or_get_readdata_cb(gpointer data,gint source,PurpleInputCondition cond)225 static void okc_post_or_get_readdata_cb(gpointer data, gint source,
226 PurpleInputCondition cond)
227 {
228 OkCupidAccount *oca;
229 OkCupidConnection *okconn;
230 gchar buf[4096];
231 ssize_t len;
232
233 okconn = data;
234 oca = okconn->oca;
235
236 if (okconn->method & OKC_METHOD_SSL) {
237 len = purple_ssl_read(okconn->ssl_conn,
238 buf, sizeof(buf) - 1);
239 } else {
240 len = recv(okconn->fd, buf, sizeof(buf) - 1, 0);
241 }
242
243 if (len < 0)
244 {
245 if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
246 /* Try again later */
247 return;
248 }
249
250 if (okconn->method & OKC_METHOD_SSL && okconn->rx_len > 0) {
251 /*
252 * This is a slightly hacky workaround for a bug in either
253 * GNU TLS or in the SSL implementation on Facebook's web
254 * servers. The sequence of events is:
255 * 1. We attempt to read the first time and successfully read
256 * the server's response.
257 * 2. We attempt to read a second time and libpurple's call
258 * to gnutls_record_recv() returns the error
259 * GNUTLS_E_UNEXPECTED_PACKET_LENGTH, or
260 * "A TLS packet with unexpected length was received."
261 *
262 * Normally the server would have closed the connection
263 * cleanly and this second read() request would have returned
264 * 0. Or maybe it's normal for SSL connections to be severed
265 * in this manner? In any case, this differs from the behavior
266 * of the standard recv() system call.
267 */
268 purple_debug_warning("okcupid",
269 "ssl error, but data received. attempting to continue\n");
270 } else {
271 /* TODO: Is this a regular occurrence? If so then maybe resend the request? */
272 okc_fatal_connection_cb(okconn);
273 return;
274 }
275 }
276
277 if (len > 0)
278 {
279 buf[len] = '\0';
280
281 okconn->rx_buf = g_realloc(okconn->rx_buf,
282 okconn->rx_len + len + 1);
283 memcpy(okconn->rx_buf + okconn->rx_len, buf, len + 1);
284 okconn->rx_len += len;
285
286 /* Wait for more data before processing */
287 return;
288 }
289
290 /* The server closed the connection, let's parse the data */
291 okc_connection_process_data(okconn);
292
293 okc_connection_destroy(okconn);
294
295 okc_next_connection(oca);
296 }
297
okc_post_or_get_ssl_readdata_cb(gpointer data,PurpleSslConnection * ssl,PurpleInputCondition cond)298 static void okc_post_or_get_ssl_readdata_cb (gpointer data,
299 PurpleSslConnection *ssl, PurpleInputCondition cond)
300 {
301 okc_post_or_get_readdata_cb(data, -1, cond);
302 }
303
okc_post_or_get_connect_cb(gpointer data,gint source,const gchar * error_message)304 static void okc_post_or_get_connect_cb(gpointer data, gint source,
305 const gchar *error_message)
306 {
307 OkCupidConnection *okconn;
308 ssize_t len;
309
310 okconn = data;
311 okconn->connect_data = NULL;
312
313 if (error_message)
314 {
315 purple_debug_error("okcupid", "post_or_get_connect_cb %s\n",
316 error_message);
317 okc_fatal_connection_cb(okconn);
318 return;
319 }
320
321 purple_debug_info("okcupid", "post_or_get_connect_cb\n");
322 okconn->fd = source;
323
324 len = write(okconn->fd, okconn->request->str,
325 okconn->request->len);
326 if(len != okconn->request->len) {
327 purple_debug_error("okcupid", "post_or_get_connect_cb failed to write request\n");
328 okc_fatal_connection_cb(okconn);
329 return;
330 }
331
332 okconn->input_watcher = purple_input_add(okconn->fd,
333 PURPLE_INPUT_READ,
334 okc_post_or_get_readdata_cb, okconn);
335 }
336
okc_post_or_get_ssl_connect_cb(gpointer data,PurpleSslConnection * ssl,PurpleInputCondition cond)337 static void okc_post_or_get_ssl_connect_cb(gpointer data,
338 PurpleSslConnection *ssl, PurpleInputCondition cond)
339 {
340 OkCupidConnection *okconn;
341 ssize_t len;
342
343 okconn = data;
344
345 purple_debug_info("okcupid", "post_or_get_ssl_connect_cb\n");
346
347 len = purple_ssl_write(okconn->ssl_conn,
348 okconn->request->str, okconn->request->len);
349 if(len != okconn->request->len) {
350 purple_debug_error("okcupid", "post_or_get_ssl_connect_cb failed to write request\n");
351 okc_fatal_connection_cb(okconn);
352 return;
353 }
354
355 purple_ssl_input_add(okconn->ssl_conn,
356 okc_post_or_get_ssl_readdata_cb, okconn);
357 }
358
okc_host_lookup_cb(GSList * hosts,gpointer data,const char * error_message)359 static void okc_host_lookup_cb(GSList *hosts, gpointer data,
360 const char *error_message)
361 {
362 GSList *host_lookup_list;
363 struct sockaddr_in *addr;
364 gchar *hostname;
365 gchar *ip_address;
366 OkCupidAccount *oca;
367 PurpleDnsQueryData *query;
368
369 purple_debug_info("okcupid", "updating cache of dns addresses\n");
370
371 /* Extract variables */
372 host_lookup_list = data;
373
374 oca = host_lookup_list->data;
375 host_lookup_list =
376 g_slist_delete_link(host_lookup_list, host_lookup_list);
377 hostname = host_lookup_list->data;
378 host_lookup_list =
379 g_slist_delete_link(host_lookup_list, host_lookup_list);
380 query = host_lookup_list->data;
381 host_lookup_list =
382 g_slist_delete_link(host_lookup_list, host_lookup_list);
383
384 /* The callback has executed, so we no longer need to keep track of
385 * the original query. This always needs to run when the cb is
386 * executed. */
387 oca->dns_queries = g_slist_remove(oca->dns_queries, query);
388
389 /* Any problems, capt'n? */
390 if (error_message != NULL)
391 {
392 purple_debug_warning("okcupid",
393 "Error doing host lookup: %s\n", error_message);
394 return;
395 }
396
397 if (hosts == NULL)
398 {
399 purple_debug_warning("okcupid",
400 "Could not resolve host name\n");
401 return;
402 }
403
404 /* Discard the length... */
405 hosts = g_slist_delete_link(hosts, hosts);
406 /* Copy the address then free it... */
407 addr = hosts->data;
408 ip_address = g_strdup(inet_ntoa(addr->sin_addr));
409 g_free(addr);
410 hosts = g_slist_delete_link(hosts, hosts);
411
412 /*
413 * DNS lookups can return a list of IP addresses, but we only cache
414 * the first one. So free the rest.
415 */
416 while (hosts != NULL)
417 {
418 /* Discard the length... */
419 hosts = g_slist_delete_link(hosts, hosts);
420 /* Free the address... */
421 g_free(hosts->data);
422 hosts = g_slist_delete_link(hosts, hosts);
423 }
424
425 purple_debug_info("okcupid", "Host %s has IP %s\n",
426 hostname, ip_address);
427
428 g_hash_table_insert(oca->hostname_ip_cache, hostname, ip_address);
429 }
430
okc_cookie_foreach_cb(gchar * cookie_name,gchar * cookie_value,GString * str)431 static void okc_cookie_foreach_cb(gchar *cookie_name,
432 gchar *cookie_value, GString *str)
433 {
434 /* TODO: Need to escape name and value? */
435 g_string_append_printf(str, "%s=%s;", cookie_name, cookie_value);
436 }
437
okc_cookies_to_string(OkCupidAccount * oca)438 static gchar *okc_cookies_to_string(OkCupidAccount *oca)
439 {
440 GString *str;
441
442 str = g_string_new(NULL);
443
444 g_hash_table_foreach(oca->cookie_table,
445 (GHFunc)okc_cookie_foreach_cb, str);
446
447 return g_string_free(str, FALSE);
448 }
449
okc_ssl_connection_error(PurpleSslConnection * ssl,PurpleSslErrorType errortype,gpointer data)450 static void okc_ssl_connection_error(PurpleSslConnection *ssl,
451 PurpleSslErrorType errortype, gpointer data)
452 {
453 OkCupidConnection *okconn = data;
454 PurpleConnection *pc = okconn->oca->pc;
455
456 okconn->ssl_conn = NULL;
457 okc_connection_destroy(okconn);
458 purple_connection_ssl_error(pc, errortype);
459 }
460
okc_post_or_get(OkCupidAccount * oca,OkCupidMethod method,const gchar * host,const gchar * url,const gchar * postdata,OkCupidProxyCallbackFunc callback_func,gpointer user_data,gboolean keepalive)461 void okc_post_or_get(OkCupidAccount *oca, OkCupidMethod method,
462 const gchar *host, const gchar *url, const gchar *postdata,
463 OkCupidProxyCallbackFunc callback_func, gpointer user_data,
464 gboolean keepalive)
465 {
466 GString *request;
467 gchar *cookies;
468 OkCupidConnection *okconn;
469 gchar *real_url;
470 gboolean is_proxy = FALSE;
471 const gchar* const *languages;
472 gchar *language_names;
473 PurpleProxyInfo *proxy_info = NULL;
474 gchar *proxy_auth;
475 gchar *proxy_auth_base64;
476
477 /* TODO: Fix keepalive and use it as much as possible */
478 keepalive = FALSE;
479
480 if (purple_account_get_bool(oca->account, "force_https", TRUE) && !(method & OKC_METHOD_SSL) &&
481 (!host || g_str_equal(host, "www.okcupid.com") || g_str_equal(host, "api.okcupid.com")))
482 {
483 method |= OKC_METHOD_SSL;
484 }
485
486 if (method & OKC_METHOD_SSL)
487 host = "www.okcupid.com";
488 if (host == NULL && oca && oca->account)
489 host = purple_account_get_string(oca->account, "host", "api.okcupid.com");
490 if (host == NULL)
491 host = "api.okcupid.com";
492
493 if (oca && oca->account && !(method & OKC_METHOD_SSL))
494 {
495 proxy_info = purple_proxy_get_setup(oca->account);
496 if (purple_proxy_info_get_type(proxy_info) == PURPLE_PROXY_USE_GLOBAL)
497 proxy_info = purple_global_proxy_get_info();
498 if (purple_proxy_info_get_type(proxy_info) == PURPLE_PROXY_HTTP)
499 {
500 is_proxy = TRUE;
501 }
502 }
503 if (is_proxy == TRUE)
504 {
505 real_url = g_strdup_printf("http://%s%s", host, url);
506 } else {
507 real_url = g_strdup(url);
508 }
509
510 cookies = okc_cookies_to_string(oca);
511
512 if (method & OKC_METHOD_POST && !postdata)
513 postdata = "";
514
515 /* Build the request */
516 request = g_string_new(NULL);
517 g_string_append_printf(request, "%s %s HTTP/1.0\r\n",
518 (method & OKC_METHOD_POST) ? "POST" : "GET",
519 real_url);
520
521 if (is_proxy == FALSE)
522 g_string_append_printf(request, "Host: %s\r\n", host);
523 g_string_append_printf(request, "Connection: %s\r\n",
524 (keepalive ? "Keep-Alive" : "close"));
525 g_string_append_printf(request, "User-Agent: %s (libpurple %s)\r\n", purple_core_get_ui(), purple_core_get_version());
526 if (method & OKC_METHOD_POST) {
527 g_string_append_printf(request,
528 "Content-Type: application/x-www-form-urlencoded\r\n");
529 g_string_append_printf(request,
530 "Content-length: %zu\r\n", strlen(postdata));
531 }
532 g_string_append_printf(request, "Accept: */*\r\n");
533 g_string_append_printf(request, "Cookie: %s\r\n", cookies);
534 g_string_append_printf(request, "Accept-Encoding: gzip\r\n");
535 g_string_append_printf(request, "X-OkCupid-Api-Version: 1\r\n");
536
537 if (is_proxy == TRUE)
538 {
539 if (purple_proxy_info_get_username(proxy_info) &&
540 purple_proxy_info_get_password(proxy_info))
541 {
542 proxy_auth = g_strdup_printf("%s:%s", purple_proxy_info_get_username(proxy_info), purple_proxy_info_get_password(proxy_info));
543 proxy_auth_base64 = purple_base64_encode((guchar *)proxy_auth, strlen(proxy_auth));
544 g_string_append_printf(request, "Proxy-Authorization: Basic %s\r\n", proxy_auth_base64);
545 g_free(proxy_auth_base64);
546 g_free(proxy_auth);
547 }
548 }
549 /* Tell the server what language we accept, so that we get error messages in our language (rather than our IP's) */
550 languages = g_get_language_names();
551 language_names = g_strjoinv(", ", (gchar **)languages);
552 purple_util_chrreplace(language_names, '_', '-');
553 g_string_append_printf(request, "Accept-Language: %s\r\n", language_names);
554 g_free(language_names);
555
556 purple_debug_misc("okcupid", "requesting url %s\n", url);
557
558 g_string_append_printf(request, "\r\n");
559 if (method & OKC_METHOD_POST)
560 g_string_append_printf(request, "%s", postdata);
561
562 /* If it needs to go over a SSL connection, we probably shouldn't print
563 * it in the debug log. Without this condition a user's password is
564 * printed in the debug log */
565 if (method == OKC_METHOD_POST)
566 purple_debug_misc("okcupid", "sending request data:\n%s\n",
567 postdata);
568
569 g_free(cookies);
570 g_free(real_url);
571 /*
572 * Do a separate DNS lookup for the given host name and cache it
573 * for next time.
574 *
575 * TODO: It would be better if we did this before we call
576 * purple_proxy_connect(), so we could re-use the result.
577 * Or even better: Use persistent HTTP connections for servers
578 * that we access continually.
579 *
580 * TODO: This cache of the hostname<-->IP address does not respect
581 * the TTL returned by the DNS server. We should expire things
582 * from the cache after some amount of time.
583 */
584 if (!is_proxy && !g_hostname_is_ip_address(host) && !(method & OKC_METHOD_SSL))
585 {
586 /* Don't do this for proxy connections, since proxies do the DNS lookup */
587 gchar *host_ip;
588
589 host_ip = g_hash_table_lookup(oca->hostname_ip_cache, host);
590 if (host_ip != NULL) {
591 purple_debug_info("okcupid",
592 "swapping original host %s with cached value of %s\n",
593 host, host_ip);
594 host = host_ip;
595 } else if (oca->account && !oca->account->disconnecting) {
596 GSList *host_lookup_list = NULL;
597 PurpleDnsQueryData *query;
598
599 host_lookup_list = g_slist_prepend(
600 host_lookup_list, g_strdup(host));
601 host_lookup_list = g_slist_prepend(
602 host_lookup_list, oca);
603
604 query = purple_dnsquery_a(host, 80,
605 okc_host_lookup_cb, host_lookup_list);
606 oca->dns_queries = g_slist_prepend(oca->dns_queries, query);
607 host_lookup_list = g_slist_append(host_lookup_list, query);
608 }
609 }
610
611 okconn = g_new0(OkCupidConnection, 1);
612 okconn->oca = oca;
613 okconn->method = method;
614 okconn->hostname = g_strdup(host);
615 okconn->request = request;
616 okconn->callback = callback_func;
617 okconn->user_data = user_data;
618 okconn->fd = -1;
619 okconn->connection_keepalive = keepalive;
620 okconn->request_time = time(NULL);
621
622 g_queue_push_head(oca->waiting_conns, okconn);
623 okc_next_connection(oca);
624 }
625
okc_next_connection(OkCupidAccount * oca)626 static void okc_next_connection(OkCupidAccount *oca)
627 {
628 OkCupidConnection *okconn;
629
630 g_return_if_fail(oca != NULL);
631
632 if (!g_queue_is_empty(oca->waiting_conns))
633 {
634 if(g_slist_length(oca->conns) < OKC_MAX_CONNECTIONS)
635 {
636 okconn = g_queue_pop_tail(oca->waiting_conns);
637 okc_attempt_connection(okconn);
638 }
639 }
640 }
641
okc_attempt_connection(OkCupidConnection * okconn)642 static void okc_attempt_connection(OkCupidConnection *okconn)
643 {
644 OkCupidAccount *oca = okconn->oca;
645
646 oca->conns = g_slist_prepend(oca->conns, okconn);
647
648 if (okconn->method & OKC_METHOD_SSL) {
649 okconn->ssl_conn = purple_ssl_connect(oca->account, okconn->hostname,
650 443, okc_post_or_get_ssl_connect_cb,
651 okc_ssl_connection_error, okconn);
652 } else {
653 okconn->connect_data = purple_proxy_connect(NULL, oca->account,
654 okconn->hostname, 80, okc_post_or_get_connect_cb, okconn);
655 }
656
657 return;
658 }
659
660