source: protocols/msn/gw.c @ 767b2d1

Last change on this file since 767b2d1 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
Line 
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
14struct msn_gw *msn_gw_new(struct im_connection *ic)
15{
16        struct msn_gw *gw = g_new0(struct msn_gw, 1);
17        gw->last_host = g_strdup(MSN_HTTP_HOST);
18        gw->port = MSN_HTTP_PORT;
19        gw->ssl = (MSN_HTTP_PORT == 443);
20        gw->poll_timeout = -1;
21        gw->ic = ic;
22        gw->md = ic->proto_data;
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{
30        if (gw->poll_timeout != -1) {
31                b_event_remove(gw->poll_timeout);
32        }
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
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
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{
76        struct msn_gw *gw;
77        char *value;
78
79        if (!(gw = msn_gw_from_ic(req->data))) {
80                return;
81        }
82
83        gw->waiting = FALSE;
84        gw->polling = FALSE;
85
86        if (req->status_code != 200 || !req->reply_body) {
87                gw->callback(gw->md, -1, B_EV_IO_READ);
88                return;
89        }
90
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
96        if ((value = get_rfc822_header(req->reply_headers, "X-MSN-Messenger", 0))) {
97                if (!msn_gw_parse_session_header(gw, value)) {
98                        gw->callback(gw->md, -1, B_EV_IO_READ);
99                        g_free(value);
100                        return;
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
110        if (req->body_size) {
111                g_byte_array_append(gw->in, (const guint8 *) req->reply_body, req->body_size);
112
113                if (!gw->callback(gw->md, -1, B_EV_IO_READ)) {
114                        return;
115                }
116        }
117
118        if (gw->poll_timeout != -1) {
119                b_event_remove(gw->poll_timeout);
120        }
121        gw->poll_timeout = b_timeout_add(500, msn_gw_poll_timeout, gw->ic);
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
138        if (!bodylen && !args) {
139                args = "Action=poll&Lifespan=60";
140                gw->polling = TRUE;
141        }
142
143        request = g_strdup_printf(REQUEST_TEMPLATE,
144                gw->session_id ? : "", args ? : "", gw->last_host, bodylen, body ? : "");
145
146        http_dorequest(gw->last_host, gw->port, gw->ssl, request, msn_gw_callback, gw->ic);
147        gw->open = TRUE;
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{
161        struct msn_gw *gw;
162
163        if (!(gw = msn_gw_from_ic(data))) {
164                return FALSE;
165        }
166
167        gw->poll_timeout = -1;
168        if (!gw->waiting) {
169                msn_gw_dorequest(gw, NULL);
170        }
171        return FALSE;
172}
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);
193        } else if (gw->polling || !gw->waiting) {
194                msn_gw_dorequest(gw, NULL);
195        }
196}
Note: See TracBrowser for help on using the repository browser.