source: protocols/msn/invitation.c @ 4c225f0

Last change on this file since 4c225f0 was d25ebea, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-05-25T22:04:55Z

GAIM_INPUT_* were renamed, at last.

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