source: protocols/msn/gw.c @ 074c9b6

Last change on this file since 074c9b6 was 767b2d1, checked in by dequis <dx@…>, at 2015-05-31T02:40:04Z

msn: Start of SSL over TCP code (required for MSNP24)

  • Property mode set to 100644
File size: 4.2 KB
RevLine 
[cfeadc3]1#include "bitlbee.h"
2#include "lib/http_client.h"
3#include "msn.h"
4
5#define REQUEST_TEMPLATE \
6        "POST /gateway/gateway.dll?SessionID=%s&%s HTTP/1.1\r\n" \
7        "Host: %s\r\n" \
8        "Content-Length: %zd\r\n" \
9        "\r\n" \
10        "%s"
11
12static gboolean msn_gw_poll_timeout(gpointer data, gint source, b_input_condition cond);
13
[951aefd]14struct msn_gw *msn_gw_new(struct im_connection *ic)
[cfeadc3]15{
16        struct msn_gw *gw = g_new0(struct msn_gw, 1);
[767b2d1]17        gw->last_host = g_strdup(MSN_HTTP_HOST);
18        gw->port = MSN_HTTP_PORT;
19        gw->ssl = (MSN_HTTP_PORT == 443);
[cfeadc3]20        gw->poll_timeout = -1;
[951aefd]21        gw->ic = ic;
22        gw->md = ic->proto_data;
[cfeadc3]23        gw->in = g_byte_array_new();
24        gw->out = g_byte_array_new();
25        return gw;
26}
27
28void msn_gw_free(struct msn_gw *gw)
29{
[913a663]30        if (gw->poll_timeout != -1) {
31                b_event_remove(gw->poll_timeout);
32        }
[cfeadc3]33        g_byte_array_free(gw->in, TRUE);
34        g_byte_array_free(gw->out, TRUE);
35        g_free(gw->session_id);
36        g_free(gw->last_host);
37        g_free(gw);
38}
39
[951aefd]40static struct msn_gw *msn_gw_from_ic(struct im_connection *ic)
41{
42        if (g_slist_find(msn_connections, ic) == NULL) {
43                return NULL;
44        } else {
45                struct msn_data *md = ic->proto_data;
46                return md->gw;
47        }
48}
49
[cfeadc3]50static gboolean msn_gw_parse_session_header(struct msn_gw *gw, char *value)
51{
52        int i;
53        char **subvalues;
54        gboolean closed = FALSE;
55
56        subvalues = g_strsplit(value, "; ", 0);
57
58        for (i = 0; subvalues[i]; i++) {
59                if (strcmp(subvalues[i], "Session=close") == 0) {
60                        /* gateway closed, signal the death of the socket */
61                        closed = TRUE;
62                } else if (g_str_has_prefix(subvalues[i], "SessionID=")) {
63                        /* copy the part after the = to session_id*/
64                        g_free(gw->session_id);
65                        gw->session_id = g_strdup(subvalues[i] + 10);
66                }
67        }
68
69        g_strfreev(subvalues);
70
71        return !closed;
72}
73
74void msn_gw_callback(struct http_request *req)
75{
[951aefd]76        struct msn_gw *gw;
[cfeadc3]77        char *value;
[913a663]78
[951aefd]79        if (!(gw = msn_gw_from_ic(req->data))) {
[913a663]80                return;
81        }
82
[951aefd]83        gw->waiting = FALSE;
84        gw->polling = FALSE;
85
[088b070]86        if (req->status_code != 200 || !req->reply_body) {
87                gw->callback(gw->md, -1, B_EV_IO_READ);
88                return;
89        }
90
[913a663]91        if (getenv("BITLBEE_DEBUG")) {
92                fprintf(stderr, "\n\x1b[90mHTTP:%s\n", req->reply_body);
93                fprintf(stderr, "\n\x1b[97m\n");
94        }
95
[cfeadc3]96        if ((value = get_rfc822_header(req->reply_headers, "X-MSN-Messenger", 0))) {
97                if (!msn_gw_parse_session_header(gw, value)) {
[951aefd]98                        gw->callback(gw->md, -1, B_EV_IO_READ);
[913a663]99                        g_free(value);
100                        return;
[cfeadc3]101                }
102                g_free(value);
103        }
104       
105        if ((value = get_rfc822_header(req->reply_headers, "X-MSN-Host", 0))) {
106                g_free(gw->last_host);
107                gw->last_host = value; /* transfer */
108        }
109
[913a663]110        if (req->body_size) {
111                g_byte_array_append(gw->in, (const guint8 *) req->reply_body, req->body_size);
[088b070]112
113                if (!gw->callback(gw->md, -1, B_EV_IO_READ)) {
114                        return;
115                }
[913a663]116        }
[cfeadc3]117
118        if (gw->poll_timeout != -1) {
119                b_event_remove(gw->poll_timeout);
120        }
[951aefd]121        gw->poll_timeout = b_timeout_add(500, msn_gw_poll_timeout, gw->ic);
[cfeadc3]122
123}
124
125void msn_gw_dorequest(struct msn_gw *gw, char *args)
126{
127        char *request = NULL;
128        char *body = NULL;
129        size_t bodylen = 0;
130
131        if (gw->out) {
132                bodylen = gw->out->len;
133                g_byte_array_append(gw->out, (guint8 *) "", 1); /* nullnullnull */
134                body = (char *) g_byte_array_free(gw->out, FALSE);
135                gw->out = g_byte_array_new();
136        }
137
[e59eec0]138        if (!bodylen && !args) {
139                args = "Action=poll&Lifespan=60";
140                gw->polling = TRUE;
141        }
142
[cfeadc3]143        request = g_strdup_printf(REQUEST_TEMPLATE,
144                gw->session_id ? : "", args ? : "", gw->last_host, bodylen, body ? : "");
145
[951aefd]146        http_dorequest(gw->last_host, gw->port, gw->ssl, request, msn_gw_callback, gw->ic);
[913a663]147        gw->open = TRUE;
[cfeadc3]148        gw->waiting = TRUE;
149
150        g_free(body);
151        g_free(request);
152}
153
154void msn_gw_open(struct msn_gw *gw)
155{
156        msn_gw_dorequest(gw, "Action=open&Server=NS");
157}
158
159static gboolean msn_gw_poll_timeout(gpointer data, gint source, b_input_condition cond)
160{
[951aefd]161        struct msn_gw *gw;
162
163        if (!(gw = msn_gw_from_ic(data))) {
164                return FALSE;
165        }
166
[cfeadc3]167        gw->poll_timeout = -1;
168        if (!gw->waiting) {
169                msn_gw_dorequest(gw, NULL);
170        }
171        return FALSE;
172}
[913a663]173
174ssize_t msn_gw_read(struct msn_gw *gw, char **buf)
175{
176        size_t bodylen;
177        if (!gw->open) {
178                return 0;
179        }
180
181        bodylen = gw->in->len;
182        g_byte_array_append(gw->in, (guint8 *) "", 1); /* nullnullnull */
183        *buf = (char *) g_byte_array_free(gw->in, FALSE);
184        gw->in = g_byte_array_new();
185        return bodylen;
186}
187
188void msn_gw_write(struct msn_gw *gw, char *buf, size_t len)
189{
190        g_byte_array_append(gw->out, (const guint8 *) buf, len);
191        if (!gw->open) {
192                msn_gw_open(gw);
[e59eec0]193        } else if (gw->polling || !gw->waiting) {
[913a663]194                msn_gw_dorequest(gw, NULL);
195        }
196}
Note: See TracBrowser for help on using the repository browser.