source: protocols/msn/invitation.c @ 1522faf

Last change on this file since 1522faf was 5ebff60, checked in by dequis <dx@…>, at 2015-02-20T22:50:54Z

Reindent everything to K&R style with tabs

Used uncrustify, with the configuration file in ./doc/uncrustify.cfg

Commit author set to "Indent <please@…>" so that it's easier to
skip while doing git blame.

  • Property mode set to 100644
File size: 19.9 KB
RevLine 
[a2b99ec]1/********************************************************************\
2* BitlBee -- An IRC to other IM-networks gateway                     *
3*                                                                    *
4* Copyright 2008 Uli Meis                                            *
5* Copyright 2006 Marijn Kruisselbrink and others                     *
6\********************************************************************/
7
8/* MSN module - File transfer support             */
9
10/*
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
[5ebff60]15
[a2b99ec]16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 GNU General Public License for more details.
[5ebff60]20
[a2b99ec]21 You should have received a copy of the GNU General Public License with
22 the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
[6f10697]23 if not, write to the Free Software Foundation, Inc., 51 Franklin St.,
24 Fifth Floor, Boston, MA  02110-1301  USA
[a2b99ec]25 */
26
27#include "bitlbee.h"
28#include "invitation.h"
29#include "msn.h"
[a02f34f]30#include "lib/ftutil.h"
[66be784]31
[a2b99ec]32#ifdef debug
33#undef debug
34#endif
[5ebff60]35#define debug(msg ...) log_message(LOGLVL_INFO, msg)
[a2b99ec]36
[5ebff60]37static void msn_ftp_free(file_transfer_t *file);
38static void msn_ftpr_accept(file_transfer_t *file);
39static void msn_ftp_finished(file_transfer_t *file);
40static void msn_ftp_canceled(file_transfer_t *file, char *reason);
41static gboolean msn_ftpr_write_request(file_transfer_t *file);
[a2b99ec]42
[5ebff60]43static gboolean msn_ftp_connected(gpointer data, gint fd, b_input_condition cond);
44static gboolean msn_ftp_read(gpointer data, gint fd, b_input_condition cond);
45gboolean msn_ftps_write(file_transfer_t *file, char *buffer, unsigned int len);
[a2b99ec]46
47/*
48 * Vararg wrapper for imcb_file_canceled().
49 */
[5ebff60]50gboolean msn_ftp_abort(file_transfer_t *file, char *format, ...)
[a2b99ec]51{
[5ebff60]52        va_list params;
53
54        va_start(params, format);
55        char error[128];
56
57        if (vsnprintf(error, 128, format, params) < 0) {
58                sprintf(error, "internal error parsing error string (BUG)");
59        }
60        va_end(params);
61        imcb_file_canceled(file, error);
[a2b99ec]62        return FALSE;
63}
64
65/* very useful */
66#define ASSERTSOCKOP(op, msg) \
[5ebff60]67        if ((op) == -1) { \
68                return msn_ftp_abort(file, msg ": %s", strerror(errno)); }
[a2b99ec]69
[5ebff60]70void msn_ftp_invitation_cmd(struct im_connection *ic, char *who, int cookie, char *icmd,
71                            char *trailer)
[a2b99ec]72{
[5ebff60]73        struct msn_message *m = g_new0(struct msn_message, 1);
74
75        m->text = g_strdup_printf("%s"
76                                  "Invitation-Command: %s\r\n"
77                                  "Invitation-Cookie: %u\r\n"
78                                  "%s",
79                                  MSN_INVITE_HEADERS,
80                                  icmd,
81                                  cookie,
82                                  trailer);
83
84        m->who = g_strdup(who);
85
86        msn_sb_write_msg(ic, m);
[a2b99ec]87}
88
[5ebff60]89void msn_ftp_cancel_invite(struct im_connection *ic, char *who,  int cookie, char *code)
[a2b99ec]90{
91        char buf[64];
92
[5ebff60]93        g_snprintf(buf, sizeof(buf), "Cancel-Code: %s\r\n", code);
94        msn_ftp_invitation_cmd(ic, who, cookie, "CANCEL", buf);
[a2b99ec]95}
96
[5ebff60]97void msn_ftp_transfer_request(struct im_connection *ic, file_transfer_t *file, char *who)
[a2b99ec]98{
[5ebff60]99        unsigned int cookie = time(NULL);   /* TODO: randomize */
[a2b99ec]100        char buf[2048];
101
[5ebff60]102        msn_filetransfer_t *msn_file = g_new0(msn_filetransfer_t, 1);
103
[a2b99ec]104        file->data = msn_file;
105        file->free = msn_ftp_free;
106        file->canceled = msn_ftp_canceled;
107        file->write = msn_ftps_write;
108        msn_file->md = ic->proto_data;
109        msn_file->invite_cookie = cookie;
[5ebff60]110        msn_file->handle = g_strdup(who);
[a2b99ec]111        msn_file->dcc = file;
[5ebff60]112        msn_file->md->filetransfers = g_slist_prepend(msn_file->md->filetransfers, msn_file->dcc);
[a2b99ec]113        msn_file->fd = -1;
114        msn_file->sbufpos = 3;
115
[5ebff60]116        g_snprintf(buf, sizeof(buf),
117                   "Application-Name: File Transfer\r\n"
118                   "Application-GUID: {5D3E02AB-6190-11d3-BBBB-00C04F795683}\r\n"
119                   "Application-File: %s\r\n"
120                   "Application-FileSize: %zd\r\n",
121                   file->file_name,
122                   file->file_size);
[a2b99ec]123
[5ebff60]124        msn_ftp_invitation_cmd(msn_file->md->ic, msn_file->handle, cookie, "INVITE", buf);
[a2b99ec]125
[5ebff60]126        imcb_file_recv_start(file);
[a2b99ec]127}
128
[5ebff60]129void msn_invitation_invite(struct msn_switchboard *sb, char *handle, unsigned int cookie, char *body, int blen)
[a2b99ec]130{
[5ebff60]131        char *itype = msn_findheader(body, "Application-GUID:", blen);
[a2b99ec]132        char *name, *size, *invitecookie, *reject = NULL;
133        user_t *u;
134        size_t isize;
135        file_transfer_t *file;
[5ebff60]136
137        if (!itype || strcmp(itype, "{5D3E02AB-6190-11d3-BBBB-00C04F795683}") != 0) {
[a2b99ec]138                /* Don't know what that is - don't care */
[5ebff60]139                char *iname = msn_findheader(body, "Application-Name:", blen);
140                imcb_log(sb->ic, "Received unknown MSN invitation %s (%s) from %s",
141                         itype ? : "with no GUID", iname ? iname : "no application name", handle);
142                g_free(iname);
[a2b99ec]143                reject = "REJECT_NOT_INSTALLED";
[5ebff60]144        } else if (
145                !(name = msn_findheader(body, "Application-File:", blen)) ||
146                !(size = msn_findheader(body, "Application-FileSize:", blen)) ||
147                !(invitecookie = msn_findheader(body, "Invitation-Cookie:", blen)) ||
148                !(isize = atoll(size))) {
149                imcb_log(sb->ic, "Received corrupted transfer request from %s"
150                         "(name=%s, size=%s, invitecookie=%s)",
151                         handle, name, size, invitecookie);
[a2b99ec]152                reject = "REJECT";
[5ebff60]153        } else if (!(u = user_findhandle(sb->ic, handle))) {
154                imcb_log(sb->ic, "Error in parsing transfer request, User '%s'"
155                         "is not in contact list", handle);
[a2b99ec]156                reject = "REJECT";
[5ebff60]157        } else if (!(file = imcb_file_send_start(sb->ic, handle, name, isize))) {
158                imcb_log(sb->ic, "Error initiating transfer for request from %s for %s",
159                         handle, name);
[a2b99ec]160                reject = "REJECT";
161        } else {
[5ebff60]162                msn_filetransfer_t *msn_file = g_new0(msn_filetransfer_t, 1);
[a2b99ec]163                file->data = msn_file;
164                file->accept = msn_ftpr_accept;
165                file->free = msn_ftp_free;
166                file->finished = msn_ftp_finished;
167                file->canceled = msn_ftp_canceled;
168                file->write_request = msn_ftpr_write_request;
169                msn_file->md = sb->ic->proto_data;
170                msn_file->invite_cookie = cookie;
[5ebff60]171                msn_file->handle = g_strdup(handle);
[a2b99ec]172                msn_file->dcc = file;
[5ebff60]173                msn_file->md->filetransfers = g_slist_prepend(msn_file->md->filetransfers, msn_file->dcc);
[a2b99ec]174                msn_file->fd = -1;
175        }
176
[5ebff60]177        if (reject) {
178                msn_ftp_cancel_invite(sb->ic, sb->who, cookie, reject);
179        }
[a2b99ec]180
[5ebff60]181        g_free(name);
182        g_free(size);
183        g_free(invitecookie);
184        g_free(itype);
[a2b99ec]185}
186
[5ebff60]187msn_filetransfer_t* msn_find_filetransfer(struct msn_data *md, unsigned int cookie, char *handle)
[a2b99ec]188{
189        GSList *l;
[5ebff60]190
191        for (l = md->filetransfers; l; l = l->next) {
192                msn_filetransfer_t *file = ((file_transfer_t *) l->data)->data;
193                if (file->invite_cookie == cookie && strcmp(handle, file->handle) == 0) {
[a2b99ec]194                        return file;
195                }
196        }
197        return NULL;
198}
199
[5ebff60]200gboolean msn_ftps_connected(gpointer data, gint fd, b_input_condition cond)
[a2b99ec]201{
202        file_transfer_t *file = data;
203        msn_filetransfer_t *msn_file = file->data;
204        struct sockaddr_storage clt_addr;
[5ebff60]205        socklen_t ssize = sizeof(clt_addr);
[a2b99ec]206
[5ebff60]207        debug("Connected to MSNFTP client");
208
209        ASSERTSOCKOP(msn_file->fd = accept(fd, (struct sockaddr *) &clt_addr, &ssize), "Accepting connection");
210
211        closesocket(fd);
[a2b99ec]212        fd = msn_file->fd;
[5ebff60]213        sock_make_nonblocking(fd);
[a2b99ec]214
[5ebff60]215        msn_file->r_event_id = b_input_add(fd, B_EV_IO_READ, msn_ftp_read, file);
[a2b99ec]216
217        return FALSE;
218}
219
[5ebff60]220void msn_invitations_accept(msn_filetransfer_t *msn_file, struct msn_switchboard *sb, char *handle, unsigned int cookie,
221                            char *body, int blen)
[a2b99ec]222{
223        file_transfer_t *file = msn_file->dcc;
224        char buf[1024];
[5ebff60]225        unsigned int acookie = time(NULL);
226        char host[HOST_NAME_MAX + 1];
[a2b99ec]227        char port[6];
[a02f34f]228        char *errmsg;
[a2b99ec]229
230        msn_file->auth_cookie = acookie;
231
[5ebff60]232        if ((msn_file->fd = ft_listen(NULL, host, port, FALSE, &errmsg)) == -1) {
233                msn_ftp_abort(file, "Failed to listen locally, check your ft_listen setting in bitlbee.conf: %s",
234                              errmsg);
[a02f34f]235                return;
236        }
[a2b99ec]237
[5ebff60]238        msn_file->r_event_id = b_input_add(msn_file->fd, B_EV_IO_READ, msn_ftps_connected, file);
[a2b99ec]239
[5ebff60]240        g_snprintf(buf, sizeof(buf),
241                   "IP-Address: %s\r\n"
242                   "Port: %s\r\n"
243                   "AuthCookie: %d\r\n"
244                   "Launch-Application: FALSE\r\n"
245                   "Request-Data: IP-Address:\r\n\r\n",
246                   host,
247                   port,
248                   msn_file->auth_cookie);
[a2b99ec]249
[5ebff60]250        msn_ftp_invitation_cmd(msn_file->md->ic, handle, msn_file->invite_cookie, "ACCEPT", buf);
[a2b99ec]251}
252
[5ebff60]253void msn_invitationr_accept(msn_filetransfer_t *msn_file, struct msn_switchboard *sb, char *handle, unsigned int cookie,
254                            char *body, int blen)
255{
[a2b99ec]256        file_transfer_t *file = msn_file->dcc;
257        char *authcookie, *ip, *port;
258
[5ebff60]259        if (!(authcookie = msn_findheader(body, "AuthCookie:", blen)) ||
260            !(ip = msn_findheader(body, "IP-Address:", blen)) ||
261            !(port = msn_findheader(body, "Port:", blen))) {
262                msn_ftp_abort(file, "Received invalid accept reply");
263        } else if (
264                (msn_file->fd = proxy_connect(ip, atoi(port), msn_ftp_connected, file))
265                < 0) {
266                msn_ftp_abort(file, "Error connecting to MSN client");
267        } else {
268                msn_file->auth_cookie = strtoul(authcookie, NULL, 10);
269        }
270
271        g_free(authcookie);
272        g_free(ip);
273        g_free(port);
[a2b99ec]274}
275
[5ebff60]276void msn_invitation_accept(struct msn_switchboard *sb, char *handle, unsigned int cookie, char *body, int blen)
[a2b99ec]277{
[5ebff60]278        msn_filetransfer_t *msn_file = msn_find_filetransfer(sb->ic->proto_data, cookie, handle);
[a2b99ec]279        file_transfer_t *file = msn_file ? msn_file->dcc : NULL;
[5ebff60]280
281        if (!msn_file) {
282                imcb_log(sb->ic, "Received invitation ACCEPT message for unknown invitation (already aborted?)");
283        } else if (file->sending) {
284                msn_invitations_accept(msn_file, sb, handle, cookie, body, blen);
285        } else {
286                msn_invitationr_accept(msn_file, sb, handle, cookie, body, blen);
287        }
[a2b99ec]288}
289
[5ebff60]290void msn_invitation_cancel(struct msn_switchboard *sb, char *handle, unsigned int cookie, char *body, int blen)
[a2b99ec]291{
[5ebff60]292        msn_filetransfer_t *msn_file = msn_find_filetransfer(sb->ic->proto_data, cookie, handle);
293
294        if (!msn_file) {
295                imcb_log(sb->ic, "Received invitation CANCEL message for unknown invitation (already aborted?)");
296        } else {
297                msn_ftp_abort(msn_file->dcc, msn_findheader(body, "Cancel-Code:", blen));
298        }
[a2b99ec]299}
300
[5ebff60]301int msn_ftp_write(file_transfer_t *file, char *format, ...)
[a2b99ec]302{
303        msn_filetransfer_t *msn_file = file->data;
304        va_list params;
305        int st;
306        char *s;
[5ebff60]307
308        va_start(params, format);
309        s = g_strdup_vprintf(format, params);
310        va_end(params);
311
312        st = write(msn_file->fd, s, strlen(s));
313        if (st != strlen(s)) {
314                return msn_ftp_abort(file, "Error sending data over MSNFTP connection: %s",
315                                     strerror(errno));
316        }
317
318        g_free(s);
[a2b99ec]319        return 1;
320}
321
[5ebff60]322gboolean msn_ftp_connected(gpointer data, gint fd, b_input_condition cond)
[a2b99ec]323{
324        file_transfer_t *file = data;
325        msn_filetransfer_t *msn_file = file->data;
[5ebff60]326
327        debug("Connected to MSNFTP server, starting authentication");
328        if (!msn_ftp_write(file, "VER MSNFTP\r\n")) {
[a2b99ec]329                return FALSE;
[5ebff60]330        }
331
332        sock_make_nonblocking(msn_file->fd);
333        msn_file->r_event_id = b_input_add(msn_file->fd, B_EV_IO_READ, msn_ftp_read, file);
334
[a2b99ec]335        return FALSE;
336}
337
[5ebff60]338gboolean msn_ftp_handle_command(file_transfer_t *file, char* line)
[a2b99ec]339{
340        msn_filetransfer_t *msn_file = file->data;
[5ebff60]341        char **cmd = msn_linesplit(line);
[a2b99ec]342        int count = 0;
[5ebff60]343
344        if (cmd[0]) {
345                while (cmd[++count]) {
346                        ;
347                }
348        }
349
350        if (count < 1) {
351                return msn_ftp_abort(file, "Missing command in MSNFTP communication");
352        }
353
354        if (strcmp(cmd[0], "VER") == 0) {
355                if (strcmp(cmd[1], "MSNFTP") != 0) {
356                        return msn_ftp_abort(file, "Unsupported filetransfer protocol: %s", cmd[1]);
357                }
358                if (file->sending) {
359                        msn_ftp_write(file, "VER MSNFTP\r\n");
360                } else {
361                        msn_ftp_write(file, "USR %s %u\r\n", msn_file->md->ic->acc->user, msn_file->auth_cookie);
362                }
363        } else if (strcmp(cmd[0], "FIL") == 0) {
364                if (strtoul(cmd[1], NULL, 10) != file->file_size) {
365                        return msn_ftp_abort(file,
366                                             "FIL reply contains a different file size than the size in the invitation");
367                }
368                msn_ftp_write(file, "TFR\r\n");
[a2b99ec]369                msn_file->status |= MSN_TRANSFER_RECEIVING;
[5ebff60]370        } else if (strcmp(cmd[0], "USR") == 0) {
371                if ((strcmp(cmd[1], msn_file->handle) != 0) ||
372                    (strtoul(cmd[2], NULL, 10) != msn_file->auth_cookie)) {
373                        msn_ftp_abort(file, "Authentication failed. "
374                                      "Expected handle: %s (got %s), cookie: %u (got %s)",
375                                      msn_file->handle, cmd[1],
376                                      msn_file->auth_cookie, cmd[2]);
377                }
378                msn_ftp_write(file, "FIL %zu\r\n", file->file_size);
379        } else if (strcmp(cmd[0], "TFR") == 0) {
380                file->write_request(file);
381        } else if (strcmp(cmd[0], "BYE") == 0) {
[a2b99ec]382                unsigned int retcode = count > 1 ? atoi(cmd[1]) : 1;
383
[5ebff60]384                if ((retcode == 16777989) || (retcode == 16777987)) {
385                        imcb_file_finished(file);
386                } else if (retcode == 2147942405) {
387                        imcb_file_canceled(file, "Failure: receiver is out of disk space");
388                } else if (retcode == 2164261682) {
389                        imcb_file_canceled(file, "Failure: receiver cancelled the transfer");
390                } else if (retcode == 2164261683) {
391                        imcb_file_canceled(file, "Failure: sender has cancelled the transfer");
392                } else if (retcode == 2164261694) {
393                        imcb_file_canceled(file, "Failure: connection is blocked");
394                } else {
[a2b99ec]395                        char buf[128];
396
[5ebff60]397                        sprintf(buf, "Failure: unknown BYE code: %d", retcode);
398                        imcb_file_canceled(file, buf);
[a2b99ec]399                }
[5ebff60]400        } else if (strcmp(cmd[0], "CCL") == 0) {
401                imcb_file_canceled(file, "Failure: receiver cancelled the transfer");
[a2b99ec]402        } else {
[5ebff60]403                msn_ftp_abort(file, "Received invalid command %s from msn client", cmd[0]);
[a2b99ec]404        }
405        return TRUE;
406}
407
[5ebff60]408gboolean msn_ftp_send(gpointer data, gint fd, b_input_condition cond)
[a2b99ec]409{
410        file_transfer_t *file = data;
411        msn_filetransfer_t *msn_file = file->data;
412
413        msn_file->w_event_id = 0;
414
[5ebff60]415        file->write_request(file);
[a2b99ec]416
417        return FALSE;
418}
419
420/*
421 * This should only be called if we can write, so just do it.
422 * Add a write watch so we can write more during the next cycle (if possible).
423 * This got a bit complicated because (at least) amsn expects packets of size 2045.
424 */
[5ebff60]425gboolean msn_ftps_write(file_transfer_t *file, char *buffer, unsigned int len)
[a2b99ec]426{
427        msn_filetransfer_t *msn_file = file->data;
[5ebff60]428        int ret, overflow;
[a2b99ec]429
430        /* what we can't send now */
431        overflow = msn_file->sbufpos + len - MSNFTP_PSIZE;
432
433        /* append what we can do the send buffer */
[5ebff60]434        memcpy(msn_file->sbuf + msn_file->sbufpos, buffer, MIN(len, MSNFTP_PSIZE - msn_file->sbufpos));
435        msn_file->sbufpos += MIN(len, MSNFTP_PSIZE - msn_file->sbufpos);
[a2b99ec]436
437        /* if we don't have enough for a full packet and there's more wait for it */
[5ebff60]438        if ((msn_file->sbufpos < MSNFTP_PSIZE) &&
439            (msn_file->data_sent + msn_file->sbufpos - 3 < file->file_size)) {
440                if (!msn_file->w_event_id) {
441                        msn_file->w_event_id = b_input_add(msn_file->fd, B_EV_IO_WRITE, msn_ftp_send, file);
442                }
[a2b99ec]443                return TRUE;
444        }
445
446        /* Accumulated enough data, lets send something out */
447
448        msn_file->sbuf[0] = 0;
[5ebff60]449        msn_file->sbuf[1] = (msn_file->sbufpos - 3) & 0xff;
450        msn_file->sbuf[2] = ((msn_file->sbufpos - 3) >> 8) & 0xff;
[a2b99ec]451
[5ebff60]452        ASSERTSOCKOP(ret = send(msn_file->fd, msn_file->sbuf, msn_file->sbufpos, 0), "Sending");
[a2b99ec]453
[5ebff60]454        msn_file->data_sent += ret - 3;
[a2b99ec]455
[5ebff60]456        /* TODO: this should really not be fatal */
457        if (ret < msn_file->sbufpos) {
458                return msn_ftp_abort(file, "send() sent %d instead of %d (send buffer full!)", ret, msn_file->sbufpos);
459        }
[a2b99ec]460
461        msn_file->sbufpos = 3;
462
[5ebff60]463        if (overflow > 0) {
464                while (overflow > (MSNFTP_PSIZE - 3)) {
465                        if (!msn_ftps_write(file, buffer + len - overflow, MSNFTP_PSIZE - 3)) {
[a2b99ec]466                                return FALSE;
[5ebff60]467                        }
[a2b99ec]468                        overflow -= MSNFTP_PSIZE - 3;
469                }
[5ebff60]470                return msn_ftps_write(file, buffer + len - overflow, overflow);
[a2b99ec]471        }
472
[5ebff60]473        if (msn_file->data_sent == file->file_size) {
474                if (msn_file->w_event_id) {
475                        b_event_remove(msn_file->w_event_id);
[a2b99ec]476                        msn_file->w_event_id = 0;
477                }
478        } else {
479                /* we might already be listening if this is data from an overflow */
[5ebff60]480                if (!msn_file->w_event_id) {
481                        msn_file->w_event_id = b_input_add(msn_file->fd, B_EV_IO_WRITE, msn_ftp_send, file);
482                }
[a2b99ec]483        }
484
[5ebff60]485        return TRUE;
[a2b99ec]486}
487
488/* Binary part of the file transfer protocol */
[5ebff60]489gboolean msn_ftpr_read(file_transfer_t *file)
[a2b99ec]490{
491        msn_filetransfer_t *msn_file = file->data;
492        int st;
493        unsigned char buf[3];
494
[5ebff60]495        if (msn_file->data_remaining) {
[a2b99ec]496                msn_file->r_event_id = 0;
497
[5ebff60]498                ASSERTSOCKOP(st = read(msn_file->fd, file->buffer, MIN(sizeof(file->buffer),
499                                                                       msn_file->data_remaining)), "Receiving");
[a2b99ec]500
[5ebff60]501                if (st == 0) {
502                        return msn_ftp_abort(file, "Remote end closed connection");
503                }
[a2b99ec]504
505                msn_file->data_sent += st;
506
507                msn_file->data_remaining -= st;
508
[5ebff60]509                file->write(file, file->buffer, st);
[a2b99ec]510
[5ebff60]511                if (msn_file->data_sent >= file->file_size) {
512                        imcb_file_finished(file);
513                }
[a2b99ec]514
515                return FALSE;
516        } else {
[5ebff60]517                ASSERTSOCKOP(st = read(msn_file->fd, buf, 1), "Receiving");
518                if (st == 0) {
519                        return msn_ftp_abort(file, "read returned EOF while reading data header from msn client");
520                } else if (buf[0] == '\r' || buf[0] == '\n') {
521                        debug("Discarding extraneous newline");
522                } else if (buf[0] != 0) {
523                        msn_ftp_abort(file, "Remote end canceled the transfer");
[a2b99ec]524                        /* don't really care about these last 2 (should be 0,0) */
[5ebff60]525                        read(msn_file->fd, buf, 2);
[a2b99ec]526                        return FALSE;
527                } else {
528                        unsigned int size;
[5ebff60]529                        ASSERTSOCKOP(st = read(msn_file->fd, buf, 2), "Receiving");
530                        if (st < 2) {
531                                return msn_ftp_abort(file,
532                                                     "read returned EOF while reading data header from msn client");
533                        }
[a2b99ec]534
535                        size = buf[0] + ((unsigned int) buf[1] << 8);
536                        msn_file->data_remaining = size;
537                }
538        }
539        return TRUE;
540}
541
542/* Text mode part of the file transfer protocol */
[5ebff60]543gboolean msn_ftp_txtproto(file_transfer_t *file)
[a2b99ec]544{
545        msn_filetransfer_t *msn_file = file->data;
546        int i = msn_file->tbufpos, st;
547        char *tbuf = msn_file->tbuf;
548
[5ebff60]549        ASSERTSOCKOP(st = read(msn_file->fd,
550                               tbuf + msn_file->tbufpos,
551                               sizeof(msn_file->tbuf) - msn_file->tbufpos),
552                     "Receiving");
[a2b99ec]553
[5ebff60]554        if (st == 0) {
555                return msn_ftp_abort(file, "read returned EOF while reading text from msn client");
556        }
[a2b99ec]557
558        msn_file->tbufpos += st;
559
560        do {
[5ebff60]561                for (; i < msn_file->tbufpos; i++) {
562                        if (tbuf[i] == '\n' || tbuf[i] == '\r') {
[a2b99ec]563                                tbuf[i] = '\0';
[5ebff60]564                                if (i > 0) {
565                                        msn_ftp_handle_command(file, tbuf);
566                                } else {
567                                        while (tbuf[i] == '\n' || tbuf[i] == '\r') {
568                                                i++;
569                                        }
570                                }
571                                memmove(tbuf, tbuf + i + 1, msn_file->tbufpos - i - 1);
[a2b99ec]572                                msn_file->tbufpos -= i + 1;
573                                i = 0;
574                                break;
575                        }
576                }
[5ebff60]577        } while (i < msn_file->tbufpos);
[a2b99ec]578
[5ebff60]579        if (msn_file->tbufpos == sizeof(msn_file->tbuf)) {
580                return msn_ftp_abort(file,
581                                     "Line exceeded %d bytes in text protocol",
582                                     sizeof(msn_file->tbuf));
583        }
[a2b99ec]584        return TRUE;
585}
586
[5ebff60]587gboolean msn_ftp_read(gpointer data, gint fd, b_input_condition cond)
[a2b99ec]588{
589        file_transfer_t *file = data;
590        msn_filetransfer_t *msn_file = file->data;
[5ebff60]591
592        if (msn_file->status & MSN_TRANSFER_RECEIVING) {
593                return msn_ftpr_read(file);
594        } else {
595                return msn_ftp_txtproto(file);
596        }
[a2b99ec]597}
598
[5ebff60]599void msn_ftp_free(file_transfer_t *file)
[a2b99ec]600{
601        msn_filetransfer_t *msn_file = file->data;
602
[5ebff60]603        if (msn_file->r_event_id) {
604                b_event_remove(msn_file->r_event_id);
605        }
606
607        if (msn_file->w_event_id) {
608                b_event_remove(msn_file->w_event_id);
609        }
610
611        if (msn_file->fd != -1) {
612                closesocket(msn_file->fd);
613        }
614
615        msn_file->md->filetransfers = g_slist_remove(msn_file->md->filetransfers, msn_file->dcc);
[a2b99ec]616
[5ebff60]617        g_free(msn_file->handle);
[a2b99ec]618
[5ebff60]619        g_free(msn_file);
[a2b99ec]620}
621
[5ebff60]622void msn_ftpr_accept(file_transfer_t *file)
[a2b99ec]623{
624        msn_filetransfer_t *msn_file = file->data;
625
[5ebff60]626        msn_ftp_invitation_cmd(msn_file->md->ic, msn_file->handle, msn_file->invite_cookie, "ACCEPT",
627                               "Launch-Application: FALSE\r\n"
628                               "Request-Data: IP-Address:\r\n");
[a2b99ec]629}
630
[5ebff60]631void msn_ftp_finished(file_transfer_t *file)
[a2b99ec]632{
[5ebff60]633        msn_ftp_write(file, "BYE 16777989\r\n");
[a2b99ec]634}
635
[5ebff60]636void msn_ftp_canceled(file_transfer_t *file, char *reason)
[a2b99ec]637{
638        msn_filetransfer_t *msn_file = file->data;
639
[5ebff60]640        msn_ftp_cancel_invite(msn_file->md->ic, msn_file->handle,
641                              msn_file->invite_cookie,
642                              file->status & FT_STATUS_TRANSFERRING ?
643                              "FTTIMEOUT" :
644                              "FAIL");
[a2b99ec]645
[5ebff60]646        imcb_log(msn_file->md->ic, "File transfer aborted: %s", reason);
[a2b99ec]647}
648
[5ebff60]649gboolean msn_ftpr_write_request(file_transfer_t *file)
[a2b99ec]650{
651        msn_filetransfer_t *msn_file = file->data;
[5ebff60]652
653        if (msn_file->r_event_id != 0) {
654                msn_ftp_abort(file,
655                              "BUG in MSN file transfer:"
656                              "write_request called when"
657                              "already watching for input");
[a2b99ec]658                return FALSE;
659        }
660
[5ebff60]661        msn_file->r_event_id =
662                b_input_add(msn_file->fd, B_EV_IO_READ, msn_ftp_read, file);
[a2b99ec]663
664        return TRUE;
665}
Note: See TracBrowser for help on using the repository browser.