source: dcc.c @ 8a90001

Last change on this file since 8a90001 was 9afeefa, checked in by ulim <a.sporto+bee@…>, at 2008-07-22T12:36:56Z

fixes bug in handling file names with spaces.

  • 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[10];
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, 10, 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[5].rm_so > 0 ) &&
652            ( pmatch[8].rm_so > 0 ) &&
653            ( pmatch[9].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[5].rm_eo] = '\0';
672
673                /* number means ipv4, something else means ipv6 */
674                if ( pmatch[6].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[7].rm_so;
682                }
683
684                input[pmatch[8].rm_eo] = '\0';
685                input[pmatch[9].rm_eo] = '\0';
686
687                port = input + pmatch[8].rm_so;
688                filesize = atoll( input + pmatch[9].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.