source: dcc.c @ 2ff2076

Last change on this file since 2ff2076 was 2ff2076, checked in by ulim <a.sporto+bee@…>, at 2007-12-03T14:28:45Z

Intermediate commit. Sending seems to work. TODOs:

  • move from out_of_data to is_writable, eliminate buffers
  • implement "transfers reject [id]"
  • documentation in commands.xml
  • implement throughput and cummulative throughput boundaries
  • feature discovery before sending
  • implement sending over a proxy (proxy discovery, socks5 client handshake for sending, activate message)
  • integrate toxik-mek-ft
  • Property mode set to 100644
File size: 19.2 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/*
33 * Since that might be confusing a note on naming:
34 *
35 * Generic dcc functions start with
36 *
37 *      dcc_
38 *
39 * ,methods specific to DCC SEND start with
40 *
41 *      dccs_
42 *
43 * . Since we can be on both ends of a DCC SEND,
44 * functions specific to one end are called
45 *
46 *      dccs_send and dccs_recv
47 *
48 * ,respectively.
49 */
50
51
52/*
53 * used to generate a unique local transfer id the user
54 * can use to reject/cancel transfers
55 */
56unsigned int local_transfer_id=1;
57
58/*
59 * just for debugging the nr. of chunks we received from im-protocols and the total data
60 */
61unsigned int receivedchunks=0, receiveddata=0;
62
63/*
64 * If using DCC SEND AHEAD this value will be set before the first transfer starts.
65 * Not that in this case it degenerates to the maximum message size to send() and
66 * has nothing to do with packets.
67 */
68#ifdef DCC_SEND_AHEAD
69int max_packet_size = DCC_PACKET_SIZE;
70#else
71int max_packet_size = 0;
72#endif
73
74static void dcc_finish( file_transfer_t *file );
75static void dcc_close( file_transfer_t *file );
76gboolean dccs_send_proto( gpointer data, gint fd, b_input_condition cond );
77gboolean dcc_listen( dcc_file_transfer_t *df, struct sockaddr_storage **saddr_ptr );
78int dccs_send_request( struct dcc_file_transfer *df, char *user_nick, struct sockaddr_storage *saddr );
79gboolean dccs_recv_start( file_transfer_t *ft );
80gboolean dccs_recv_proto( gpointer data, gint fd, b_input_condition cond);
81void dccs_recv_out_of_data( file_transfer_t *ft );
82
83/* As defined in ft.h */
84file_transfer_t *imcb_file_send_start( struct im_connection *ic, char *handle, char *file_name, size_t file_size )
85{
86        user_t *u = user_findhandle( ic, handle );
87        /* one could handle this more intelligent like imcb_buddy_msg.
88         * can't call it directly though cause it does some wrapping.
89         * Maybe give imcb_buddy_msg a parameter NO_WRAPPING? */
90        if (!u) return NULL;
91
92        return dccs_send_start( ic, u->nick, file_name, file_size );
93};
94
95/* As defined in ft.h */
96void imcb_file_canceled( file_transfer_t *file, char *reason )
97{
98        if( file->canceled )
99                file->canceled( file, reason );
100
101        dcc_close( file );
102}
103
104/* As defined in ft.h */
105gboolean imcb_file_write( file_transfer_t *file, gpointer data, size_t data_size )
106{
107        return dccs_send_write( file, data, data_size );
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
142        /* listen and request */
143        if( !dcc_listen( df, &saddr ) ||
144            !dccs_send_request( df, user_nick, saddr ) )
145                return NULL;
146
147        g_free( saddr );
148
149        /* watch */
150        df->watch_in = b_input_add( df->fd, GAIM_INPUT_READ, dccs_send_proto, df );
151
152        df->ic->irc->file_transfers = g_slist_prepend( df->ic->irc->file_transfers, file );
153
154        return file;
155}
156
157/* Used pretty much everywhere in the code to abort a transfer */
158gboolean dcc_abort( dcc_file_transfer_t *df, char *reason, ... )
159{
160        file_transfer_t *file = df->ft;
161        va_list params;
162        va_start( params, reason );
163        char *msg = g_strdup_vprintf( reason, params );
164        va_end( params );
165       
166        file->status |= FT_STATUS_CANCELED;
167       
168        if( file->canceled )
169                file->canceled( file, msg );
170        else 
171                imcb_log( df->ic, "DCC transfer aborted: %s", msg );
172
173        g_free( msg );
174
175        dcc_close( df->ft );
176
177        return FALSE;
178}
179
180/* used extensively for socket operations */
181#define ASSERTSOCKOP(op, msg) \
182        if( (op) == -1 ) \
183                return dcc_abort( df , msg ": %s", strerror( errno ) );
184
185/* Creates the "DCC SEND" line and sends it to the server */
186int dccs_send_request( struct dcc_file_transfer *df, char *user_nick, struct sockaddr_storage *saddr )
187{
188        char ipaddr[INET6_ADDRSTRLEN]; 
189        const void *netaddr;
190        int port;
191        char *cmd;
192
193        if( saddr->ss_family == AF_INET )
194        {
195                struct sockaddr_in *saddr_ipv4 = ( struct sockaddr_in *) saddr;
196
197                /*
198                 * this is so ridiculous. We're supposed to convert the address to
199                 * host byte order!!! Let's exclude anyone running big endian just
200                 * for the fun of it...
201                 */
202                sprintf( ipaddr, "%d", 
203                         htonl( saddr_ipv4->sin_addr.s_addr ) );
204                port = saddr_ipv4->sin_port;
205        } else 
206        {
207                struct sockaddr_in6 *saddr_ipv6 = ( struct sockaddr_in6 *) saddr;
208
209                netaddr = &saddr_ipv6->sin6_addr.s6_addr;
210                port = saddr_ipv6->sin6_port;
211
212                /*
213                 * Didn't find docs about this, but it seems that's the way irssi does it
214                 */
215                if( !inet_ntop( saddr->ss_family, netaddr, ipaddr, sizeof( ipaddr ) ) )
216                        return dcc_abort( df, "inet_ntop failed: %s", strerror( errno ) );
217        }
218
219        port = ntohs( port );
220
221        cmd = g_strdup_printf( "\001DCC SEND %s %s %u %zu\001",
222                                df->ft->file_name, ipaddr, port, df->ft->file_size );
223       
224        if ( !irc_msgfrom( df->ic->irc, user_nick, cmd ) )
225                return dcc_abort( df, "couldn't send 'DCC SEND' message to %s", user_nick );
226
227        g_free( cmd );
228
229        /* message is sortof redundant cause the users client probably informs him about that. remove? */
230        imcb_log( df->ic, "Transferring file %s: Chose local address %s for DCC connection", df->ft->file_name, ipaddr );
231
232        return TRUE;
233}
234
235/*
236 * Creates a listening socket and returns it in saddr_ptr.
237 */
238gboolean dcc_listen( dcc_file_transfer_t *df, struct sockaddr_storage **saddr_ptr )
239{
240        file_transfer_t *file = df->ft;
241        struct sockaddr_storage *saddr;
242        int fd;
243        char hostname[ HOST_NAME_MAX + 1 ];
244        struct addrinfo hints, *rp;
245        socklen_t ssize = sizeof( struct sockaddr_storage );
246
247        /* won't be long till someone asks for this to be configurable :) */
248
249        ASSERTSOCKOP( gethostname( hostname, sizeof( hostname ) ), "gethostname()" );
250
251        memset( &hints, 0, sizeof( struct addrinfo ) );
252        hints.ai_socktype = SOCK_STREAM;
253        hints.ai_flags = AI_NUMERICSERV;
254
255        if ( getaddrinfo( hostname, "0", &hints, &rp ) != 0 )
256                return dcc_abort( df, "getaddrinfo()" );
257
258        saddr = g_new( struct sockaddr_storage, 1 );
259
260        *saddr_ptr = saddr;
261
262        memcpy( saddr, rp->ai_addr, rp->ai_addrlen );
263
264        ASSERTSOCKOP( fd = df->fd = socket( saddr->ss_family, SOCK_STREAM, 0 ), "Opening socket" );
265
266        ASSERTSOCKOP( bind( fd, ( struct sockaddr *)saddr, rp->ai_addrlen ), "Binding socket" );
267       
268        freeaddrinfo( rp );
269
270        ASSERTSOCKOP( getsockname( fd, ( struct sockaddr *)saddr, &ssize ), "Getting socket name" );
271
272        ASSERTSOCKOP( listen( fd, 1 ), "Making socket listen" );
273
274        file->status = FT_STATUS_LISTENING;
275
276        return TRUE;
277}
278
279/*
280 * Checks poll(), same for receiving and sending
281 */
282gboolean dcc_poll( dcc_file_transfer_t *df, int fd, short *revents )
283{
284        struct pollfd pfd = { .fd = fd, .events = POLLHUP|POLLERR|POLLIN|POLLOUT };
285
286        ASSERTSOCKOP( poll( &pfd, 1, 0 ), "poll()" )
287
288        if( pfd.revents & POLLERR )
289        {
290                int sockerror;
291                socklen_t errlen = sizeof( sockerror );
292
293                if ( getsockopt( fd, SOL_SOCKET, SO_ERROR, &sockerror, &errlen ) )
294                        return dcc_abort( df, "getsockopt() failed, unknown socket error (weird!)" );
295
296                return dcc_abort( df, "Socket error: %s", strerror( sockerror ) );
297        }
298       
299        if( pfd.revents & POLLHUP ) 
300                return dcc_abort( df, "Remote end closed connection" );
301       
302        *revents = pfd.revents;
303
304        return TRUE;
305}
306
307gboolean  dcc_check_maxseg( dcc_file_transfer_t *df, int fd )
308{
309#ifdef DCC_SEND_AHEAD
310        /*
311         * use twice the maximum segment size as a maximum for calls to send().
312         */
313        if( max_packet_size == 0 )
314        {
315                unsigned int mpslen = sizeof( max_packet_size );
316                if( getsockopt( fd, IPPROTO_TCP, TCP_MAXSEG, &max_packet_size, &mpslen ) )
317                        return dcc_abort( df, "getsockopt() failed" );
318                max_packet_size *= 2;
319        }
320#endif
321        return TRUE;
322}
323
324/*
325 * After setup, the transfer itself is handled entirely by this function.
326 * There are basically four things to handle: connect, receive, send, and error.
327 */
328gboolean dccs_send_proto( gpointer data, gint fd, b_input_condition cond )
329{
330        dcc_file_transfer_t *df = data;
331        file_transfer_t *file = df->ft;
332        short revents;
333       
334        if( !dcc_poll( df, fd, &revents) )
335                return FALSE;
336
337        if( ( revents & POLLIN ) &&
338            ( file->status & FT_STATUS_LISTENING ) )
339        {       
340                struct sockaddr *clt_addr;
341                socklen_t ssize = sizeof( clt_addr );
342
343                /* Connect */
344
345                ASSERTSOCKOP( df->fd = accept( fd, (struct sockaddr *) &clt_addr, &ssize ), "Accepting connection" );
346
347                closesocket( fd );
348                fd = df->fd;
349                file->status = FT_STATUS_TRANSFERRING;
350                sock_make_nonblocking( fd );
351
352                if ( !dcc_check_maxseg( df, fd ) )
353                        return FALSE;
354
355                /* IM protocol callback */
356
357                if( file->accept )
358                        file->accept( file );
359                /* reschedule for reading on new fd */
360                df->watch_in = b_input_add( fd, GAIM_INPUT_READ, dccs_send_proto, df );
361
362                return FALSE;
363        }
364
365        if( revents & POLLIN ) 
366        {
367                int bytes_received;
368                int ret;
369               
370                ASSERTSOCKOP( ret = recv( fd, &bytes_received, sizeof( bytes_received  ), MSG_PEEK ), "Receiving" );
371
372                if( ret == 0 )
373                        return dcc_abort( df, "Remote end closed connection" );
374                       
375                if( ret < 4 )
376                {
377                        imcb_log( df->ic, "WARNING: DCC SEND: receiver sent only 2 bytes instead of 4, shouldn't happen too often!" );
378                        return TRUE;
379                }
380
381                ASSERTSOCKOP( ret = recv( fd, &bytes_received, sizeof( bytes_received  ), 0 ), "Receiving" );
382                if( ret != 4 )
383                        return dcc_abort( df, "MSG_PEEK'ed 4, but can only dequeue %d bytes", ret );
384
385                bytes_received = ntohl( bytes_received );
386
387                /* If any of this is actually happening, the receiver should buy a new IRC client */
388
389                if ( bytes_received > df->bytes_sent )
390                        return dcc_abort( df, "Receiver magically received more bytes than sent ( %d > %d ) (BUG at receiver?)", bytes_received, df->bytes_sent );
391
392                if ( bytes_received < file->bytes_transferred )
393                        return dcc_abort( df, "Receiver lost bytes? ( has %d, had %d ) (BUG at receiver?)", bytes_received, file->bytes_transferred );
394               
395                file->bytes_transferred = bytes_received;
396       
397                if( file->bytes_transferred >= file->file_size ) {
398                        dcc_finish( file );
399                        return FALSE;
400                }
401       
402#ifndef DCC_SEND_AHEAD
403                /* reschedule writer if neccessary */
404                if( file->bytes_transferred >= df->bytes_sent && 
405                    df->watch_out == 0 && 
406                    df->queued_bytes > 0 ) {
407                        df->watch_out = b_input_add( fd, GAIM_INPUT_WRITE, dcc_send_proto, df );
408                }
409#endif
410                return TRUE;
411        }
412
413        if( revents & POLLOUT )
414        {
415                struct dcc_buffer *dccb;
416                int ret;
417                char *msg;
418
419                if( df->queued_bytes == 0 )
420                {
421                        /* shouldn't happen */
422                        imcb_log( df->ic, "WARNING: DCC SEND: write called with empty queue" );
423
424                        df->watch_out = 0;
425                        return FALSE;
426                }
427
428                /* start where we left off */
429                if( !( df->queued_buffers ) ||
430                    !( dccb = df->queued_buffers->data ) )
431                        return dcc_abort( df, "BUG in DCC SEND: queued data but no buffers" );
432
433                msg = dccb->b + df->buffer_pos;
434
435                int msgsize = MIN( 
436#ifndef DCC_SEND_AHEAD
437                                  file->bytes_transferred + MAX_PACKET_SIZE - df->bytes_sent,
438#else
439                                  max_packet_size,
440#endif
441                                  dccb->len - df->buffer_pos );
442
443                if ( msgsize == 0 )
444                {
445                        df->watch_out = 0;
446                        return FALSE;
447                }
448
449                ASSERTSOCKOP( ret = send( fd, msg, msgsize, 0 ), "Sending data" );
450
451                if( ret == 0 )
452                        return dcc_abort( df, "Remote end closed connection" );
453
454                df->bytes_sent += ret;
455                df->queued_bytes -= ret;
456                df->buffer_pos += ret;
457
458                if( df->buffer_pos == dccb->len )
459                {
460                        df->buffer_pos = 0;
461                        df->queued_buffers = g_slist_remove( df->queued_buffers, dccb );
462                        g_free( dccb->b );
463                        g_free( dccb );
464                }
465
466                if( ( df->queued_bytes < DCC_QUEUE_THRESHOLD_LOW ) && file->out_of_data )
467                        file->out_of_data( file );
468       
469                if( df->queued_bytes > 0 )
470                {
471                        /* Who knows how long the event loop cycle will take,
472                         * let's just try to send some more now. */
473#ifndef DCC_SEND_AHEAD
474                        if( df->bytes_sent < ( file->bytes_transferred + max_packet_size ) )
475#endif
476                                return dccs_send_proto( df, fd, cond );
477                }
478
479                df->watch_out = 0;
480                return FALSE;
481        }
482
483        /* Send buffer full, come back later */
484
485        return TRUE;
486}
487
488gboolean dccs_recv_start( file_transfer_t *ft )
489{
490        dcc_file_transfer_t *df = ft->priv;
491        struct sockaddr_storage *saddr = &df->saddr;
492        int fd;
493        socklen_t sa_len = saddr->ss_family == AF_INET ? 
494                sizeof( struct sockaddr_in ) : sizeof( struct sockaddr_in6 );
495       
496        if( !ft->write )
497                return dcc_abort( df, "Protocol didn't register write()" );
498       
499        ASSERTSOCKOP( fd = df->fd = socket( saddr->ss_family, SOCK_STREAM, 0 ) , "Opening Socket" );
500
501        sock_make_nonblocking( fd );
502
503        if( ( connect( fd, (struct sockaddr *)saddr, sa_len ) == -1 ) &&
504            ( errno != EINPROGRESS ) )
505                return dcc_abort( df, "Connecting" );
506
507        ft->status = FT_STATUS_CONNECTING;
508
509        /* watch */
510        df->watch_out = b_input_add( df->fd, GAIM_INPUT_WRITE, dccs_recv_proto, df );
511        ft->out_of_data = dccs_recv_out_of_data;
512
513        return TRUE;
514}
515
516gboolean dccs_recv_proto( gpointer data, gint fd, b_input_condition cond)
517{
518        dcc_file_transfer_t *df = data;
519        file_transfer_t *ft = df->ft;
520        short revents;
521
522        if( !dcc_poll( df, fd, &revents ) )
523                return FALSE;
524       
525        if( ( revents & POLLOUT ) &&
526            ( ft->status & FT_STATUS_CONNECTING ) )
527        {
528                ft->status = FT_STATUS_TRANSFERRING;
529                if ( !dcc_check_maxseg( df, fd ) )
530                        return FALSE;
531
532                //df->watch_in = b_input_add( df->fd, GAIM_INPUT_READ, dccs_recv_proto, df );
533
534                df->watch_out = 0;
535                return FALSE;
536        }
537
538        if( revents & POLLIN )
539        {
540                char *buffer = g_malloc( 65536 );
541                int ret, done;
542
543                ASSERTSOCKOP( ret = recv( fd, buffer, 65536, 0 ), "Receiving" );
544
545                if( ret == 0 )
546                        return dcc_abort( df, "Remote end closed connection" );
547
548                buffer = g_realloc( buffer, ret );
549
550                df->bytes_sent += ret;
551
552                done = df->bytes_sent >= ft->file_size;
553
554                if( ( ( df->bytes_sent - ft->bytes_transferred ) > DCC_PACKET_SIZE ) ||
555                    done )
556                {
557                        int ack, ackret;
558                        ack = htonl( ft->bytes_transferred = df->bytes_sent );
559
560                        ASSERTSOCKOP( ackret = send( fd, &ack, 4, 0 ), "Sending DCC ACK" );
561                       
562                        if ( ackret != 4 )
563                                return dcc_abort( df, "Error sending DCC ACK, sent %d instead of 4 bytes", ret );
564                }
565               
566                if( !ft->write( df->ft, buffer, ret ) && !done )
567                {
568                        df->watch_in = 0;
569                        return FALSE;
570                }
571
572                if( done )
573                {
574                        closesocket( fd );
575                        dcc_finish( ft );
576
577                        df->watch_in = 0;
578                        return FALSE;
579                }
580
581                return TRUE;
582        }
583
584        return TRUE;
585}
586
587void dccs_recv_out_of_data( file_transfer_t *ft )
588{
589        dcc_file_transfer_t *df = ft->priv;
590
591        if( !df->watch_in )
592                df->watch_in = b_input_add( df->fd, GAIM_INPUT_READ, dccs_recv_proto, df );
593}
594
595/*
596 * Incoming data. Note that the buffer MUST NOT be freed by the caller!
597 * We don't copy the buffer but put it in our queue.
598 *
599 * */
600gboolean dccs_send_write( file_transfer_t *file, gpointer data, unsigned int data_size )
601{
602        dcc_file_transfer_t *df = file->priv;
603        struct dcc_buffer *dccb = g_new0( struct dcc_buffer, 1 );
604
605        receivedchunks++; receiveddata += data_size;
606
607        dccb->b = data;
608        dccb->len = data_size;
609
610        df->queued_buffers = g_slist_append( df->queued_buffers, dccb );
611
612        df->queued_bytes += data_size;
613
614        if( ( file->status & FT_STATUS_TRANSFERRING ) && 
615#ifndef DCC_SEND_AHEAD
616            ( file->bytes_transferred >= df->bytes_sent ) && 
617#endif
618            ( df->watch_out == 0 ) && 
619            ( df->queued_bytes > 0 ) )
620        {
621                df->watch_out = b_input_add( df->fd, GAIM_INPUT_WRITE, dccs_send_proto, df );
622        }
623       
624        return df->queued_bytes > DCC_QUEUE_THRESHOLD_HIGH;
625}
626
627/*
628 * Cleans up after a transfer.
629 */
630static void dcc_close( file_transfer_t *file )
631{
632        dcc_file_transfer_t *df = file->priv;
633
634        if( file->free )
635                file->free( file );
636       
637        closesocket( df->fd );
638
639        if( df->watch_in )
640                b_event_remove( df->watch_in );
641
642        if( df->watch_out )
643                b_event_remove( df->watch_out );
644       
645        if( df->queued_buffers )
646        {
647                struct dcc_buffer *dccb;
648                GSList *gslist = df->queued_buffers;
649
650                for( ; gslist ; gslist = g_slist_next( gslist ) )
651                {
652                        dccb = gslist->data;
653                        g_free( dccb->b );
654                        g_free( dccb );
655                }
656                g_slist_free( df->queued_buffers );
657        }
658
659        df->ic->irc->file_transfers = g_slist_remove( df->ic->irc->file_transfers, file );
660       
661        g_free( df );
662        g_free( file->file_name );
663        g_free( file );
664}
665
666void dcc_finish( file_transfer_t *file )
667{
668        file->status |= FT_STATUS_FINISHED;
669       
670        if( file->finished )
671                file->finished( file );
672
673        dcc_close( file );
674}
675
676/*
677 * DCC SEND <filename> <IP> <port> <filesize>
678 *
679 * filename can be in "" or not. If it is, " can probably be escaped...
680 * IP can be an unsigned int (IPV4) or something else (IPV6)
681 *
682 */
683file_transfer_t *dcc_request( struct im_connection *ic, char *line )
684{
685        char *pattern = "SEND"
686                " (([^\"][^ ]*)|\"([^\"]|\\\")*\")"
687                " (([0-9]*)|([^ ]*))"
688                " ([0-9]*)"
689                " ([0-9]*)\001";
690        regmatch_t pmatch[9];
691        regex_t re;
692        file_transfer_t *ft;
693        dcc_file_transfer_t *df;
694
695        if( regcomp( &re, pattern, REG_EXTENDED ) )
696                return NULL;
697        if( regexec( &re, line, 9, pmatch, 0 ) )
698                return NULL;
699
700        if( ( pmatch[1].rm_so > 0 ) &&
701            ( pmatch[4].rm_so > 0 ) &&
702            ( pmatch[7].rm_so > 0 ) &&
703            ( pmatch[8].rm_so > 0 ) )
704        {
705                char *input = g_strdup( line );
706                char *filename, *host, *port;
707                size_t filesize;
708                struct addrinfo hints, *rp;
709
710                /* "filename" or filename */
711                if ( pmatch[2].rm_so > 0 )
712                {
713                        input[pmatch[2].rm_eo] = '\0';
714                        filename = input + pmatch[2].rm_so;
715                } else
716                {
717                        input[pmatch[3].rm_eo] = '\0';
718                        filename = input + pmatch[3].rm_so;
719                }
720                       
721                input[pmatch[4].rm_eo] = '\0';
722
723                /* number means ipv4, something else means ipv6 */
724                if ( pmatch[5].rm_so > 0 )
725                {
726                        struct in_addr ipaddr = { htonl( atoi( input + pmatch[5].rm_so ) ) };
727                        host = inet_ntoa( ipaddr );
728                } else
729                {
730                        /* Contains non-numbers, hopefully an IPV6 address */
731                        host = input + pmatch[6].rm_so;
732                }
733
734                input[pmatch[7].rm_eo] = '\0';
735                input[pmatch[8].rm_eo] = '\0';
736
737                port = input + pmatch[7].rm_so;
738                filesize = atoll( input + pmatch[8].rm_so );
739
740                memset( &hints, 0, sizeof ( struct addrinfo ) );
741                if ( getaddrinfo( host, port, &hints, &rp ) )
742                {
743                        g_free( input );
744                        return NULL;
745                }
746
747                df = dcc_alloc_transfer( filename, filesize, ic );
748                ft = df->ft;
749                ft->sending = TRUE;
750                memcpy( &df->saddr, rp->ai_addr, rp->ai_addrlen );
751
752                freeaddrinfo( rp );
753                g_free( input );
754
755                df->ic->irc->file_transfers = g_slist_prepend( df->ic->irc->file_transfers, ft );
756
757                return ft;
758        }
759
760        return NULL;
761}
762
Note: See TracBrowser for help on using the repository browser.