source: protocols/msn/invitation.c @ 66be784

Last change on this file since 66be784 was 66be784, checked in by ulim <a.sporto+bee@…>, at 2008-08-11T14:31:03Z

copied ulibc/BSD ifdefs over to invitation.c.

I'll have to move these to a generic header file eventually.

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