source: protocols/msn/gw.c @ cb1b973

Last change on this file since cb1b973 was 951aefd, checked in by dequis <dx@…>, at 2015-04-12T15:27:31Z

msn/gw.c: ensure that the im_connection still exists in callbacks

  • Property mode set to 100644
File size: 4.3 KB
RevLine 
[cfeadc3]1#include "bitlbee.h"
2#include "lib/http_client.h"
3#include "msn.h"
4
5#define GATEWAY_HOST "geo.gateway.messenger.live.com"
6#define GATEWAY_PORT 443
7
8#define REQUEST_TEMPLATE \
9        "POST /gateway/gateway.dll?SessionID=%s&%s HTTP/1.1\r\n" \
10        "Host: %s\r\n" \
11        "Content-Length: %zd\r\n" \
12        "\r\n" \
13        "%s"
14
15static gboolean msn_gw_poll_timeout(gpointer data, gint source, b_input_condition cond);
16
[951aefd]17struct msn_gw *msn_gw_new(struct im_connection *ic)
[cfeadc3]18{
19        struct msn_gw *gw = g_new0(struct msn_gw, 1);
20        gw->last_host = g_strdup(GATEWAY_HOST);
21        gw->port = GATEWAY_PORT;
22        gw->ssl = (GATEWAY_PORT == 443);
23        gw->poll_timeout = -1;
[951aefd]24        gw->ic = ic;
25        gw->md = ic->proto_data;
[cfeadc3]26        gw->in = g_byte_array_new();
27        gw->out = g_byte_array_new();
28        return gw;
29}
30
31void msn_gw_free(struct msn_gw *gw)
32{
[913a663]33        if (gw->poll_timeout != -1) {
34                b_event_remove(gw->poll_timeout);
35        }
[cfeadc3]36        g_byte_array_free(gw->in, TRUE);
37        g_byte_array_free(gw->out, TRUE);
38        g_free(gw->session_id);
39        g_free(gw->last_host);
40        g_free(gw);
41}
42
[951aefd]43static struct msn_gw *msn_gw_from_ic(struct im_connection *ic)
44{
45        if (g_slist_find(msn_connections, ic) == NULL) {
46                return NULL;
47        } else {
48                struct msn_data *md = ic->proto_data;
49                return md->gw;
50        }
51}
52
[cfeadc3]53static gboolean msn_gw_parse_session_header(struct msn_gw *gw, char *value)
54{
55        int i;
56        char **subvalues;
57        gboolean closed = FALSE;
58
59        subvalues = g_strsplit(value, "; ", 0);
60
61        for (i = 0; subvalues[i]; i++) {
62                if (strcmp(subvalues[i], "Session=close") == 0) {
63                        /* gateway closed, signal the death of the socket */
64                        closed = TRUE;
65                } else if (g_str_has_prefix(subvalues[i], "SessionID=")) {
66                        /* copy the part after the = to session_id*/
67                        g_free(gw->session_id);
68                        gw->session_id = g_strdup(subvalues[i] + 10);
69                }
70        }
71
72        g_strfreev(subvalues);
73
74        return !closed;
75}
76
77void msn_gw_callback(struct http_request *req)
78{
[951aefd]79        struct msn_gw *gw;
[cfeadc3]80        char *value;
[913a663]81
[951aefd]82        if (!(gw = msn_gw_from_ic(req->data))) {
[913a663]83                return;
84        }
85
[951aefd]86        gw->waiting = FALSE;
87        gw->polling = FALSE;
88
[913a663]89        if (getenv("BITLBEE_DEBUG")) {
90                fprintf(stderr, "\n\x1b[90mHTTP:%s\n", req->reply_body);
91                fprintf(stderr, "\n\x1b[97m\n");
92        }
93
94        if (req->status_code != 200) {
[951aefd]95                gw->callback(gw->md, -1, B_EV_IO_READ);
[913a663]96                return;
97        }
98
[cfeadc3]99        if ((value = get_rfc822_header(req->reply_headers, "X-MSN-Messenger", 0))) {
100                if (!msn_gw_parse_session_header(gw, value)) {
[951aefd]101                        gw->callback(gw->md, -1, B_EV_IO_READ);
[913a663]102                        g_free(value);
103                        return;
[cfeadc3]104                }
105                g_free(value);
106        }
107       
108        if ((value = get_rfc822_header(req->reply_headers, "X-MSN-Host", 0))) {
109                g_free(gw->last_host);
110                gw->last_host = value; /* transfer */
111        }
112
[913a663]113        if (req->body_size) {
114                g_byte_array_append(gw->in, (const guint8 *) req->reply_body, req->body_size);
[951aefd]115                gw->callback(gw->md, -1, B_EV_IO_READ);
[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.