source: protocols/msn/invitation.c @ a2b99ec

Last change on this file since a2b99ec was a2b99ec, checked in by ulim <a.sporto+bee@…>, at 2008-08-10T22:17:58Z

Added MSN file transfer of type MSNFTP.

Transfer is direct and the sender can not be firewalled.

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