source: dcc.c @ 60e4df3

Last change on this file since 60e4df3 was 60e4df3, checked in by Wilmer van der Gaast <wilmer@…>, at 2010-03-17T23:23:27Z

Small cleanup. The max_packet_size variable doesn't seem to be read
anywhere, and reworked string handling in ft_listen() a little bit.

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