source: dcc.c @ 3355a82

Last change on this file since 3355a82 was b043ad5, checked in by ulim <a.sporto+bee@…>, at 2008-05-08T21:20:36Z

allow dcc optimization in progress watcher.

Apparently, irssi doesn't send any DCC ACKs if it "feels" that the sender
doesn't expect any(no idea how exactly it does that). Anyway, the progress
watcher used to check whether the ACKed bytes have increased which it shouldn't
do if there aren't any ACKs.

  • Property mode set to 100644
File size: 18.5 KB
Line 
1/********************************************************************\
2* BitlBee -- An IRC to other IM-networks gateway                     *
3*                                                                    *
4* Copyright 2007 Uli Meis <a.sporto+bee@gmail.com>                   *
5\********************************************************************/
6
7/*
8  This program is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 2 of the License, or
11  (at your option) any later version.
12
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  GNU General Public License for more details.
17
18  You should have received a copy of the GNU General Public License with
19  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
20  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
21  Suite 330, Boston, MA  02111-1307  USA
22*/
23
24#define BITLBEE_CORE
25#include "bitlbee.h"
26#include "ft.h"
27#include "dcc.h"
28#include <poll.h>
29#include <netinet/tcp.h>
30#include <regex.h>
31
32/* Some ifdefs for ulibc (Thanks to Whoopie) */
33#ifndef HOST_NAME_MAX
34#include <sys/param.h>
35#ifdef MAXHOSTNAMELEN
36#define HOST_NAME_MAX MAXHOSTNAMELEN
37#else
38#define HOST_NAME_MAX 255
39#endif
40#endif
41
42#ifndef AI_NUMERICSERV
43#define AI_NUMERICSERV 0x0400   /* Don't use name resolution.  */
44#endif
45
46/*
47 * Since that might be confusing a note on naming:
48 *
49 * Generic dcc functions start with
50 *
51 *      dcc_
52 *
53 * ,methods specific to DCC SEND start with
54 *
55 *      dccs_
56 *
57 * . Since we can be on both ends of a DCC SEND,
58 * functions specific to one end are called
59 *
60 *      dccs_send and dccs_recv
61 *
62 * ,respectively.
63 */
64
65
66/*
67 * used to generate a unique local transfer id the user
68 * can use to reject/cancel transfers
69 */
70unsigned int local_transfer_id=1;
71
72/*
73 * just for debugging the nr. of chunks we received from im-protocols and the total data
74 */
75unsigned int receivedchunks=0, receiveddata=0;
76
77int max_packet_size = 0;
78
79static void dcc_finish( file_transfer_t *file );
80static void dcc_close( file_transfer_t *file );
81gboolean dccs_send_proto( gpointer data, gint fd, b_input_condition cond );
82gboolean dcc_listen( dcc_file_transfer_t *df, struct sockaddr_storage **saddr_ptr );
83int dccs_send_request( struct dcc_file_transfer *df, char *user_nick, struct sockaddr_storage *saddr );
84gboolean dccs_recv_start( file_transfer_t *ft );
85gboolean dccs_recv_proto( gpointer data, gint fd, b_input_condition cond);
86gboolean dccs_recv_write_request( file_transfer_t *ft );
87gboolean dcc_progress( gpointer data, gint fd, b_input_condition cond );
88
89/* As defined in ft.h */
90file_transfer_t *imcb_file_send_start( struct im_connection *ic, char *handle, char *file_name, size_t file_size )
91{
92        user_t *u = user_findhandle( ic, handle );
93        /* one could handle this more intelligent like imcb_buddy_msg.
94         * can't call it directly though cause it does some wrapping.
95         * Maybe give imcb_buddy_msg a parameter NO_WRAPPING? */
96        if (!u) return NULL;
97
98        return dccs_send_start( ic, u->nick, file_name, file_size );
99};
100
101/* As defined in ft.h */
102void imcb_file_canceled( file_transfer_t *file, char *reason )
103{
104        if( file->canceled )
105                file->canceled( file, reason );
106
107        dcc_close( file );
108}
109
110/* As defined in ft.h */
111gboolean imcb_file_recv_start( file_transfer_t *ft )
112{
113        return dccs_recv_start( ft );
114}
115
116dcc_file_transfer_t *dcc_alloc_transfer( char *file_name, size_t file_size, struct im_connection *ic )
117{
118        file_transfer_t *file = g_new0( file_transfer_t, 1 );
119        dcc_file_transfer_t *df = file->priv = g_new0( dcc_file_transfer_t, 1);
120        file->file_size = file_size;
121        file->file_name = g_strdup( file_name );
122        file->local_id = local_transfer_id++;
123        df->ic = ic;
124        df->ft = file;
125       
126        return df;
127}
128
129/* This is where the sending magic starts... */
130file_transfer_t *dccs_send_start( struct im_connection *ic, char *user_nick, char *file_name, size_t file_size )
131{
132        file_transfer_t *file;
133        dcc_file_transfer_t *df;
134        struct sockaddr_storage *saddr;
135
136        if( file_size > global.conf->max_filetransfer_size )
137                return NULL;
138       
139        df = dcc_alloc_transfer( file_name, file_size, ic );
140        file = df->ft;
141        file->write = dccs_send_write;
142
143        /* listen and request */
144        if( !dcc_listen( df, &saddr ) ||
145            !dccs_send_request( df, user_nick, saddr ) )
146                return NULL;
147
148        g_free( saddr );
149
150        /* watch */
151        df->watch_in = b_input_add( df->fd, GAIM_INPUT_READ, dccs_send_proto, df );
152
153        df->ic->irc->file_transfers = g_slist_prepend( df->ic->irc->file_transfers, file );
154
155        df->progress_timeout = b_timeout_add( DCC_MAX_STALL * 1000, dcc_progress, df );
156
157        return file;
158}
159
160/* Used pretty much everywhere in the code to abort a transfer */
161gboolean dcc_abort( dcc_file_transfer_t *df, char *reason, ... )
162{
163        file_transfer_t *file = df->ft;
164        va_list params;
165        va_start( params, reason );
166        char *msg = g_strdup_vprintf( reason, params );
167        va_end( params );
168       
169        file->status |= FT_STATUS_CANCELED;
170       
171        if( file->canceled )
172                file->canceled( file, msg );
173
174        imcb_log( df->ic, "File %s: DCC transfer aborted: %s", file->file_name, msg );
175
176        g_free( msg );
177
178        dcc_close( df->ft );
179
180        return FALSE;
181}
182
183gboolean dcc_progress( gpointer data, gint fd, b_input_condition cond )
184{
185        struct dcc_file_transfer *df = data;
186
187        if( df->bytes_sent == df->progress_bytes_last )
188        {
189                /* no progress. cancel */
190                if( df->bytes_sent == 0 )
191                        return dcc_abort( df, "Couldnt establish transfer within %d seconds", DCC_MAX_STALL );
192                else 
193                        return dcc_abort( df, "Transfer stalled for %d seconds at %d kb", DCC_MAX_STALL, df->bytes_sent / 1024 );
194
195        }
196
197        df->progress_bytes_last = df->bytes_sent;
198
199        return TRUE;
200}
201
202/* used extensively for socket operations */
203#define ASSERTSOCKOP(op, msg) \
204        if( (op) == -1 ) \
205                return dcc_abort( df , msg ": %s", strerror( errno ) );
206
207/* Creates the "DCC SEND" line and sends it to the server */
208int dccs_send_request( struct dcc_file_transfer *df, char *user_nick, struct sockaddr_storage *saddr )
209{
210        char ipaddr[INET6_ADDRSTRLEN]; 
211        const void *netaddr;
212        int port;
213        char *cmd;
214
215        if( saddr->ss_family == AF_INET )
216        {
217                struct sockaddr_in *saddr_ipv4 = ( struct sockaddr_in *) saddr;
218
219                sprintf( ipaddr, "%d", 
220                         ntohl( saddr_ipv4->sin_addr.s_addr ) );
221                port = saddr_ipv4->sin_port;
222        } else 
223        {
224                struct sockaddr_in6 *saddr_ipv6 = ( struct sockaddr_in6 *) saddr;
225
226                netaddr = &saddr_ipv6->sin6_addr.s6_addr;
227                port = saddr_ipv6->sin6_port;
228
229                /*
230                 * Didn't find docs about this, but it seems that's the way irssi does it
231                 */
232                if( !inet_ntop( saddr->ss_family, netaddr, ipaddr, sizeof( ipaddr ) ) )
233                        return dcc_abort( df, "inet_ntop failed: %s", strerror( errno ) );
234        }
235
236        port = ntohs( port );
237
238        cmd = g_strdup_printf( "\001DCC SEND %s %s %u %zu\001",
239                                df->ft->file_name, ipaddr, port, df->ft->file_size );
240       
241        if ( !irc_msgfrom( df->ic->irc, user_nick, cmd ) )
242                return dcc_abort( df, "couldn't send 'DCC SEND' message to %s", user_nick );
243
244        g_free( cmd );
245
246        return TRUE;
247}
248
249/*
250 * Creates a listening socket and returns it in saddr_ptr.
251 */
252gboolean dcc_listen( dcc_file_transfer_t *df, struct sockaddr_storage **saddr_ptr )
253{
254        file_transfer_t *file = df->ft;
255        struct sockaddr_storage *saddr;
256        int fd,gret;
257        char hostname[ HOST_NAME_MAX + 1 ];
258        struct addrinfo hints, *rp;
259        socklen_t ssize = sizeof( struct sockaddr_storage );
260
261        /* won't be long till someone asks for this to be configurable :) */
262
263        ASSERTSOCKOP( gethostname( hostname, sizeof( hostname ) ), "gethostname()" );
264
265        memset( &hints, 0, sizeof( struct addrinfo ) );
266        hints.ai_socktype = SOCK_STREAM;
267        hints.ai_flags = AI_NUMERICSERV;
268
269        if ( ( gret = getaddrinfo( hostname, "0", &hints, &rp ) != 0 ) )
270                return dcc_abort( df, "getaddrinfo(): %s", gai_strerror( gret ) );
271
272        saddr = g_new( struct sockaddr_storage, 1 );
273
274        *saddr_ptr = saddr;
275
276        memcpy( saddr, rp->ai_addr, rp->ai_addrlen );
277
278        ASSERTSOCKOP( fd = df->fd = socket( saddr->ss_family, SOCK_STREAM, 0 ), "Opening socket" );
279
280        ASSERTSOCKOP( bind( fd, ( struct sockaddr *)saddr, rp->ai_addrlen ), "Binding socket" );
281       
282        freeaddrinfo( rp );
283
284        ASSERTSOCKOP( getsockname( fd, ( struct sockaddr *)saddr, &ssize ), "Getting socket name" );
285
286        ASSERTSOCKOP( listen( fd, 1 ), "Making socket listen" );
287
288        file->status = FT_STATUS_LISTENING;
289
290        return TRUE;
291}
292
293/*
294 * Checks poll(), same for receiving and sending
295 */
296gboolean dcc_poll( dcc_file_transfer_t *df, int fd, short *revents )
297{
298        struct pollfd pfd = { .fd = fd, .events = POLLHUP|POLLERR|POLLIN|POLLOUT };
299
300        ASSERTSOCKOP( poll( &pfd, 1, 0 ), "poll()" )
301
302        if( pfd.revents & POLLERR )
303        {
304                int sockerror;
305                socklen_t errlen = sizeof( sockerror );
306
307                if ( getsockopt( fd, SOL_SOCKET, SO_ERROR, &sockerror, &errlen ) )
308                        return dcc_abort( df, "getsockopt() failed, unknown socket error (weird!)" );
309
310                return dcc_abort( df, "Socket error: %s", strerror( sockerror ) );
311        }
312       
313        if( pfd.revents & POLLHUP ) 
314                return dcc_abort( df, "Remote end closed connection" );
315       
316        *revents = pfd.revents;
317
318        return TRUE;
319}
320
321/*
322 * fills max_packet_size with twice the TCP maximum segment size
323 */
324gboolean  dcc_check_maxseg( dcc_file_transfer_t *df, int fd )
325{
326        /*
327         * use twice the maximum segment size as a maximum for calls to send().
328         */
329        if( max_packet_size == 0 )
330        {
331                unsigned int mpslen = sizeof( max_packet_size );
332                if( getsockopt( fd, IPPROTO_TCP, TCP_MAXSEG, &max_packet_size, &mpslen ) )
333                        return dcc_abort( df, "getsockopt() failed" );
334                max_packet_size *= 2;
335        }
336        return TRUE;
337}
338
339/*
340 * After setup, the transfer itself is handled entirely by this function.
341 * There are basically four things to handle: connect, receive, send, and error.
342 */
343gboolean dccs_send_proto( gpointer data, gint fd, b_input_condition cond )
344{
345        dcc_file_transfer_t *df = data;
346        file_transfer_t *file = df->ft;
347        short revents;
348       
349        if( !dcc_poll( df, fd, &revents) )
350                return FALSE;
351
352        if( ( revents & POLLIN ) &&
353            ( file->status & FT_STATUS_LISTENING ) )
354        {       
355                struct sockaddr *clt_addr;
356                socklen_t ssize = sizeof( clt_addr );
357
358                /* Connect */
359
360                ASSERTSOCKOP( df->fd = accept( fd, (struct sockaddr *) &clt_addr, &ssize ), "Accepting connection" );
361
362                closesocket( fd );
363                fd = df->fd;
364                file->status = FT_STATUS_TRANSFERRING;
365                sock_make_nonblocking( fd );
366
367                if ( !dcc_check_maxseg( df, fd ) )
368                        return FALSE;
369
370                /* IM protocol callback */
371                if( file->accept )
372                        file->accept( file );
373
374                /* reschedule for reading on new fd */
375                df->watch_in = b_input_add( fd, GAIM_INPUT_READ, dccs_send_proto, df );
376
377                return FALSE;
378        }
379
380        if( revents & POLLIN ) 
381        {
382                int bytes_received;
383                int ret;
384               
385                ASSERTSOCKOP( ret = recv( fd, &bytes_received, sizeof( bytes_received  ), MSG_PEEK ), "Receiving" );
386
387                if( ret == 0 )
388                        return dcc_abort( df, "Remote end closed connection" );
389                       
390                if( ret < 4 )
391                {
392                        imcb_log( df->ic, "WARNING: DCC SEND: receiver sent only 2 bytes instead of 4, shouldn't happen too often!" );
393                        return TRUE;
394                }
395
396                ASSERTSOCKOP( ret = recv( fd, &bytes_received, sizeof( bytes_received  ), 0 ), "Receiving" );
397                if( ret != 4 )
398                        return dcc_abort( df, "MSG_PEEK'ed 4, but can only dequeue %d bytes", ret );
399
400                bytes_received = ntohl( bytes_received );
401
402                /* If any of this is actually happening, the receiver should buy a new IRC client */
403
404                if ( bytes_received > df->bytes_sent )
405                        return dcc_abort( df, "Receiver magically received more bytes than sent ( %d > %d ) (BUG at receiver?)", bytes_received, df->bytes_sent );
406
407                if ( bytes_received < file->bytes_transferred )
408                        return dcc_abort( df, "Receiver lost bytes? ( has %d, had %d ) (BUG at receiver?)", bytes_received, file->bytes_transferred );
409               
410                file->bytes_transferred = bytes_received;
411       
412                if( file->bytes_transferred >= file->file_size ) {
413                        dcc_finish( file );
414                        return FALSE;
415                }
416       
417                return TRUE;
418        }
419
420        return TRUE;
421}
422
423gboolean dccs_recv_start( file_transfer_t *ft )
424{
425        dcc_file_transfer_t *df = ft->priv;
426        struct sockaddr_storage *saddr = &df->saddr;
427        int fd;
428        char ipaddr[INET6_ADDRSTRLEN]; 
429        socklen_t sa_len = saddr->ss_family == AF_INET ? 
430                sizeof( struct sockaddr_in ) : sizeof( struct sockaddr_in6 );
431       
432        if( !ft->write )
433                return dcc_abort( df, "BUG: protocol didn't register write()" );
434       
435        ASSERTSOCKOP( fd = df->fd = socket( saddr->ss_family, SOCK_STREAM, 0 ) , "Opening Socket" );
436
437        sock_make_nonblocking( fd );
438
439        if( ( connect( fd, (struct sockaddr *)saddr, sa_len ) == -1 ) &&
440            ( errno != EINPROGRESS ) )
441                return dcc_abort( df, "Connecting to %s:%d : %s", 
442                        inet_ntop( saddr->ss_family, 
443                                saddr->ss_family == AF_INET ? 
444                                    ( void* ) &( ( struct sockaddr_in *) saddr )->sin_addr.s_addr :
445                                    ( void* ) &( ( struct sockaddr_in6 *) saddr )->sin6_addr.s6_addr,
446                                ipaddr, 
447                                sizeof( ipaddr ) ),
448                        ntohs( saddr->ss_family == AF_INET ?
449                            ( ( struct sockaddr_in *) saddr )->sin_port :
450                            ( ( struct sockaddr_in6 *) saddr )->sin6_port ),
451                        strerror( errno ) );
452
453        ft->status = FT_STATUS_CONNECTING;
454
455        /* watch */
456        df->watch_out = b_input_add( df->fd, GAIM_INPUT_WRITE, dccs_recv_proto, df );
457        ft->write_request = dccs_recv_write_request;
458
459        df->progress_timeout = b_timeout_add( DCC_MAX_STALL * 1000, dcc_progress, df );
460
461        return TRUE;
462}
463
464gboolean dccs_recv_proto( gpointer data, gint fd, b_input_condition cond)
465{
466        dcc_file_transfer_t *df = data;
467        file_transfer_t *ft = df->ft;
468        short revents;
469
470        if( !dcc_poll( df, fd, &revents ) )
471                return FALSE;
472       
473        if( ( revents & POLLOUT ) &&
474            ( ft->status & FT_STATUS_CONNECTING ) )
475        {
476                ft->status = FT_STATUS_TRANSFERRING;
477                if ( !dcc_check_maxseg( df, fd ) )
478                        return FALSE;
479
480                //df->watch_in = b_input_add( df->fd, GAIM_INPUT_READ, dccs_recv_proto, df );
481
482                df->watch_out = 0;
483                return FALSE;
484        }
485
486        if( revents & POLLIN )
487        {
488                int ret, done;
489
490                ASSERTSOCKOP( ret = recv( fd, ft->buffer, sizeof( ft->buffer ), 0 ), "Receiving" );
491
492                if( ret == 0 )
493                        return dcc_abort( df, "Remote end closed connection" );
494
495                df->bytes_sent += ret;
496
497                done = df->bytes_sent >= ft->file_size;
498
499                if( ( ( df->bytes_sent - ft->bytes_transferred ) > DCC_PACKET_SIZE ) ||
500                    done )
501                {
502                        int ack, ackret;
503                        ack = htonl( ft->bytes_transferred = df->bytes_sent );
504
505                        ASSERTSOCKOP( ackret = send( fd, &ack, 4, 0 ), "Sending DCC ACK" );
506                       
507                        if ( ackret != 4 )
508                                return dcc_abort( df, "Error sending DCC ACK, sent %d instead of 4 bytes", ackret );
509                }
510               
511                if( !ft->write( df->ft, ft->buffer, ret ) )
512                        return FALSE;
513
514                if( done )
515                {
516                        closesocket( fd );
517                        dcc_finish( ft );
518
519                        df->watch_in = 0;
520                        return FALSE;
521                }
522
523                df->watch_in = 0;
524                return FALSE;
525        }
526
527        return TRUE;
528}
529
530gboolean dccs_recv_write_request( file_transfer_t *ft )
531{
532        dcc_file_transfer_t *df = ft->priv;
533
534        if( df->watch_in )
535                return dcc_abort( df, "BUG: write_request() called while watching" );
536
537        df->watch_in = b_input_add( df->fd, GAIM_INPUT_READ, dccs_recv_proto, df );
538
539        return TRUE;
540}
541
542gboolean dccs_send_can_write( gpointer data, gint fd, b_input_condition cond )
543{
544        struct dcc_file_transfer *df = data;
545        df->watch_out = 0;
546
547        df->ft->write_request( df->ft );
548        return FALSE;
549}
550
551/*
552 * Incoming data.
553 *
554 */
555gboolean dccs_send_write( file_transfer_t *file, char *data, unsigned int data_len )
556{
557        dcc_file_transfer_t *df = file->priv;
558        int ret;
559
560        receivedchunks++; receiveddata += data_len;
561
562        if( df->watch_out )
563                return dcc_abort( df, "BUG: write() called while watching" );
564
565        ASSERTSOCKOP( ret = send( df->fd, data, data_len, 0 ), "Sending data" );
566
567        if( ret == 0 )
568                return dcc_abort( df, "Remote end closed connection" );
569
570        /* TODO: this should really not be fatal */
571        if( ret < data_len )
572                return dcc_abort( df, "send() sent %d instead of %d", ret, data_len );
573
574        df->bytes_sent += ret;
575
576        if( df->bytes_sent < df->ft->file_size )
577                df->watch_out = b_input_add( df->fd, GAIM_INPUT_WRITE, dccs_send_can_write, df );
578
579        return TRUE;
580}
581
582/*
583 * Cleans up after a transfer.
584 */
585static void dcc_close( file_transfer_t *file )
586{
587        dcc_file_transfer_t *df = file->priv;
588
589        if( file->free )
590                file->free( file );
591       
592        closesocket( df->fd );
593
594        if( df->watch_in )
595                b_event_remove( df->watch_in );
596
597        if( df->watch_out )
598                b_event_remove( df->watch_out );
599       
600        if( df->progress_timeout )
601                b_event_remove( df->progress_timeout );
602       
603        df->ic->irc->file_transfers = g_slist_remove( df->ic->irc->file_transfers, file );
604       
605        g_free( df );
606        g_free( file->file_name );
607        g_free( file );
608}
609
610void dcc_finish( file_transfer_t *file )
611{
612        file->status |= FT_STATUS_FINISHED;
613       
614        if( file->finished )
615                file->finished( file );
616
617        dcc_close( file );
618}
619
620/*
621 * DCC SEND <filename> <IP> <port> <filesize>
622 *
623 * filename can be in "" or not. If it is, " can probably be escaped...
624 * IP can be an unsigned int (IPV4) or something else (IPV6)
625 *
626 */
627file_transfer_t *dcc_request( struct im_connection *ic, char *line )
628{
629        char *pattern = "SEND"
630                " (([^\"][^ ]*)|\"([^\"]|\\\")*\")"
631                " (([0-9]*)|([^ ]*))"
632                " ([0-9]*)"
633                " ([0-9]*)\001";
634        regmatch_t pmatch[9];
635        regex_t re;
636        file_transfer_t *ft;
637        dcc_file_transfer_t *df;
638        char errbuf[256];
639        int regerrcode, gret;
640
641        if( ( regerrcode = regcomp( &re, pattern, REG_EXTENDED ) ) ||
642            ( regerrcode = regexec( &re, line, 9, pmatch, 0 ) ) ) {
643                regerror( regerrcode,&re,errbuf,sizeof( errbuf ) );
644                imcb_log( ic, 
645                          "DCC: error parsing 'DCC SEND': %s, line: %s", 
646                          errbuf, line );
647                return NULL;
648        }
649
650        if( ( pmatch[1].rm_so > 0 ) &&
651            ( pmatch[4].rm_so > 0 ) &&
652            ( pmatch[7].rm_so > 0 ) &&
653            ( pmatch[8].rm_so > 0 ) )
654        {
655                char *input = g_strdup( line );
656                char *filename, *host, *port;
657                size_t filesize;
658                struct addrinfo hints, *rp;
659
660                /* "filename" or filename */
661                if ( pmatch[2].rm_so > 0 )
662                {
663                        input[pmatch[2].rm_eo] = '\0';
664                        filename = input + pmatch[2].rm_so;
665                } else
666                {
667                        input[pmatch[3].rm_eo] = '\0';
668                        filename = input + pmatch[3].rm_so;
669                }
670                       
671                input[pmatch[4].rm_eo] = '\0';
672
673                /* number means ipv4, something else means ipv6 */
674                if ( pmatch[5].rm_so > 0 )
675                {
676                        struct in_addr ipaddr = { .s_addr = htonl( atoi( input + pmatch[5].rm_so ) ) };
677                        host = inet_ntoa( ipaddr );
678                } else
679                {
680                        /* Contains non-numbers, hopefully an IPV6 address */
681                        host = input + pmatch[6].rm_so;
682                }
683
684                input[pmatch[7].rm_eo] = '\0';
685                input[pmatch[8].rm_eo] = '\0';
686
687                port = input + pmatch[7].rm_so;
688                filesize = atoll( input + pmatch[8].rm_so );
689
690                memset( &hints, 0, sizeof ( struct addrinfo ) );
691                if ( ( gret = getaddrinfo( host, port, &hints, &rp ) ) )
692                {
693                        g_free( input );
694                        imcb_log( ic, "DCC: getaddrinfo() failed with %s "
695                                  "when parsing incoming 'DCC SEND': "
696                                  "host %s, port %s", 
697                                  gai_strerror( gret ), host, port );
698                        return NULL;
699                }
700
701                df = dcc_alloc_transfer( filename, filesize, ic );
702                ft = df->ft;
703                ft->sending = TRUE;
704                memcpy( &df->saddr, rp->ai_addr, rp->ai_addrlen );
705
706                freeaddrinfo( rp );
707                g_free( input );
708
709                df->ic->irc->file_transfers = g_slist_prepend( df->ic->irc->file_transfers, ft );
710
711                return ft;
712        }
713
714        imcb_log( ic, "DCC: couldnt parse 'DCC SEND' line: %s", line );
715
716        return NULL;
717}
718
Note: See TracBrowser for help on using the repository browser.