Changeset 2ff2076


Ignore:
Timestamp:
2007-12-03T14:28:45Z (13 years ago)
Author:
ulim <a.sporto+bee@…>
Branches:
master
Children:
dce3903
Parents:
2c2df7d
Message:

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
Files:
1 added
1 deleted
12 edited

Legend:

Unmodified
Added
Removed
  • dcc.c

    r2c2df7d r2ff2076  
    2828#include <poll.h>
    2929#include <netinet/tcp.h>
     30#include <regex.h>
    3031
    3132/*
     
    7677gboolean dcc_listen( dcc_file_transfer_t *df, struct sockaddr_storage **saddr_ptr );
    7778int 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 );
    7882
    7983/* As defined in ft.h */
     
    104108}
    105109
    106 /* This is where the sending magic starts... */
    107 file_transfer_t *dccs_send_start( struct im_connection *ic, char *user_nick, char *file_name, size_t file_size )
    108 {
    109         file_transfer_t *file;
    110         dcc_file_transfer_t *df;
    111         struct sockaddr_storage **saddr;
    112 
    113         if( file_size > global.conf->max_filetransfer_size )
    114                 return NULL;
    115        
    116         /* alloc stuff */
    117         file = g_new0( file_transfer_t, 1 );
    118         file->priv = df = g_new0( dcc_file_transfer_t, 1);
     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);
    119120        file->file_size = file_size;
    120121        file->file_name = g_strdup( file_name );
     
    123124        df->ft = file;
    124125       
     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
    125142        /* listen and request */
    126         if( !dcc_listen( df, saddr ) ||
    127             !dccs_send_request( df, user_nick, *saddr ) )
     143        if( !dcc_listen( df, &saddr ) ||
     144            !dccs_send_request( df, user_nick, saddr ) )
    128145                return NULL;
    129146
    130         g_free( *saddr );
     147        g_free( saddr );
    131148
    132149        /* watch */
     
    261278
    262279/*
     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/*
    263325 * After setup, the transfer itself is handled entirely by this function.
    264326 * There are basically four things to handle: connect, receive, send, and error.
     
    268330        dcc_file_transfer_t *df = data;
    269331        file_transfer_t *file = df->ft;
    270         struct pollfd pfd = { .fd = fd, .events = POLLHUP|POLLERR|POLLIN|POLLOUT };
    271332        short revents;
    272333       
    273         if ( poll( &pfd, 1, 0 ) == -1 )
    274         {
    275                 imcb_log( df->ic, "poll() failed, weird!" );
    276                 revents = 0;
    277         };
    278 
    279         revents = pfd.revents;
    280 
    281         if( revents & POLLERR )
    282         {
    283                 int sockerror;
    284                 socklen_t errlen = sizeof( sockerror );
    285 
    286                 if ( getsockopt( fd, SOL_SOCKET, SO_ERROR, &sockerror, &errlen ) )
    287                         return dcc_abort( df, "getsockopt() failed, unknown socket error (weird!)" );
    288 
    289                 return dcc_abort( df, "Socket error: %s", strerror( sockerror ) );
    290         }
    291        
    292         if( revents & POLLHUP )
    293                 return dcc_abort( df, "Remote end closed connection" );
    294        
     334        if( !dcc_poll( df, fd, &revents) )
     335                return FALSE;
     336
    295337        if( ( revents & POLLIN ) &&
    296338            ( file->status & FT_STATUS_LISTENING ) )
     
    305347                closesocket( fd );
    306348                fd = df->fd;
    307                 file->status = FT_STATUS_TRANSFERING;
     349                file->status = FT_STATUS_TRANSFERRING;
    308350                sock_make_nonblocking( fd );
    309351
    310 #ifdef DCC_SEND_AHEAD
    311                 /*
    312                  * use twice the maximum segment size as a maximum for calls to send().
    313                  */
    314                 if( max_packet_size == 0 )
    315                 {
    316                         unsigned int mpslen = sizeof( max_packet_size );
    317                         if( getsockopt( fd, IPPROTO_TCP, TCP_MAXSEG, &max_packet_size, &mpslen ) )
    318                                 return dcc_abort( df, "getsockopt() failed" );
    319                         max_packet_size *= 2;
    320                 }
    321 #endif
     352                if ( !dcc_check_maxseg( df, fd ) )
     353                        return FALSE;
     354
    322355                /* IM protocol callback */
    323356
     
    453486}
    454487
     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
    455595/*
    456596 * Incoming data. Note that the buffer MUST NOT be freed by the caller!
     
    472612        df->queued_bytes += data_size;
    473613
    474         if( ( file->status & FT_STATUS_TRANSFERING ) &&
     614        if( ( file->status & FT_STATUS_TRANSFERRING ) &&
    475615#ifndef DCC_SEND_AHEAD
    476616            ( file->bytes_transferred >= df->bytes_sent ) &&
     
    533673        dcc_close( file );
    534674}
     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
  • dcc.h

    r2c2df7d r2ff2076  
    112112        size_t bytes_sent;
    113113       
    114         /* imcb's handle */
     114        /* imc's handle */
    115115        file_transfer_t *ft;
     116
     117        /* if we're receiving, this is the sender's socket address */
     118        struct sockaddr_storage saddr;
    116119
    117120} dcc_file_transfer_t;
     
    123126gboolean dccs_send_write( file_transfer_t *file, gpointer data, unsigned int data_size );
    124127
     128file_transfer_t *dcc_request( struct im_connection *ic, char *line );
    125129#endif
  • doc/user-guide/commands.xml

    r2c2df7d r2ff2076  
    861861
    862862        </bitlbee-command>
     863       
     864        <bitlbee-command name="transfers">
     865                <short-description>Monitor, cancel, or reject file transfers</short-description>
     866                <syntax>transfers [&lt;cancel&gt; id | &lt;reject&gt;]</syntax>
     867               
     868                <description>
     869                        <para>
     870                                Without parameters the currently pending file transfers and their status will be listed. Available actions are <emphasis>cancel</emphasis> and <emphasis>reject</emphasis>. See <emphasis>help transfers &lt;action&gt;</emphasis> for more information.
     871                        </para>
     872
     873                        <ircexample>
     874                                <ircline nick="ulim">transfers</ircline>
     875                        </ircexample>
     876                </description>
     877               
     878                <bitlbee-command name="cancel">
     879                        <short-description>Cancels the file transfer with the given id</short-description>
     880                        <syntax>transfers &lt;cancel&gt; id</syntax>
     881
     882                        <description>
     883                                <para>Cancels the file transfer with the given id</para>
     884                        </description>
     885
     886                        <ircexample>
     887                                <ircline nick="ulim">transfers cancel 1</ircline>
     888                                <ircline nick="root">Canceling file transfer for test</ircline>
     889                        </ircexample>
     890                </bitlbee-command>
     891
     892                <bitlbee-command name="reject">
     893                        <short-description>Rejects all incoming transfers</short-description>
     894                        <syntax>transfers &lt;reject&gt;</syntax>
     895
     896                        <description>
     897                                <para>Rejects all incoming (not already transferring) file transfers. Since you probably have only one incoming transfer at a time, no id is neccessary. Or is it?</para>
     898                        </description>
     899
     900                        <ircexample>
     901                                <ircline nick="ulim">transfers reject</ircline>
     902                        </ircexample>
     903                </bitlbee-command>
     904        </bitlbee-command>
     905       
    863906</chapter>
  • irc.c

    r2c2df7d r2ff2076  
    2828#include "crypting.h"
    2929#include "ipc.h"
     30#include "dcc.h"
     31
     32#include <regex.h>
     33#include <netinet/in.h>
    3034
    3135static gboolean irc_userping( gpointer _irc, int fd, b_input_condition cond );
     
    981985                        return( 1 );
    982986                }
     987                else if( g_strncasecmp( s + 1, "DCC", 3 ) == 0 )
     988                {
     989                        if( u && u->ic && u->ic->acc->prpl->transfer_request )
     990                        {
     991                                file_transfer_t *ft = dcc_request( u->ic, s + 5 );
     992                                if ( ft )
     993                                        u->ic->acc->prpl->transfer_request( u->ic, ft, u->handle );
     994                        }
     995                        return( 1 );
     996                }               
    983997                else
    984998                {
    985                         irc_usermsg( irc, "Non-ACTION CTCP's aren't supported" );
     999                        irc_usermsg( irc, "Supported CTCPs are ACTION, VERSION, PING, TYPING, DCC" );
    9861000                        return( 0 );
    9871001                }
  • protocols/ft.h

    r2c2df7d r2ff2076  
    2929typedef enum {
    3030        FT_STATUS_LISTENING     = 1,
    31         FT_STATUS_TRANSFERING   = 2,
     31        FT_STATUS_TRANSFERRING  = 2,
    3232        FT_STATUS_FINISHED      = 4,
    33         FT_STATUS_CANCELED      = 8
     33        FT_STATUS_CANCELED      = 8,
     34        FT_STATUS_CONNECTING    = 16
    3435} file_status_t;
    3536
     
    6162 */
    6263typedef struct file_transfer {
     64
     65        /* Are we sending something? */
     66        int sending;
     67
    6368        /*
    6469         * The current status of this file transfer.
     
    131136        void (*out_of_data) ( struct file_transfer *file );
    132137
     138        /*
     139         * When sending files, protocols register this function to receive data.
     140         */
     141        gboolean (*write) (struct file_transfer *file, char *buffer, int len );
     142
    133143} file_transfer_t;
    134144
     
    151161gboolean imcb_file_write( file_transfer_t *file, gpointer data, size_t data_size );
    152162
     163gboolean imcb_file_recv_start( file_transfer_t *ft );
    153164#endif
  • protocols/jabber/Makefile

    r2c2df7d r2ff2076  
    1010
    1111# [SH] Program variables
    12 objects = conference.o io.o iq.o jabber.o jabber_util.o message.o presence.o sasl.o xmltree.o si.o stream.o
     12objects = conference.o io.o iq.o jabber.o jabber_util.o message.o presence.o sasl.o xmltree.o si.o s5bytestream.o
    1313
    1414CFLAGS += -Wall
  • protocols/jabber/iq.c

    r2c2df7d r2ff2076  
    168168                {
    169169                        /* Bytestream Request (stage 2 of file transfer) */
    170                         return jabber_bs_request( ic, node, c );
     170                        return jabber_bs_recv_request( ic, node, c );
    171171                } else
    172172                {
  • protocols/jabber/jabber.c

    r2c2df7d r2ff2076  
    502502        ret->send_typing = jabber_send_typing;
    503503        ret->handle_cmp = g_strcasecmp;
     504        ret->transfer_request = jabber_si_transfer_request;
    504505
    505506        register_protocol( ret );
  • protocols/jabber/jabber.h

    r2c2df7d r2ff2076  
    148148        int receiver_overflow;
    149149        int fd;
     150        struct sockaddr_storage saddr;
    150151};
    151152
     
    201202
    202203/* si.c */
    203 int jabber_si_handle_request( struct im_connection *ic, struct xt_node *node, struct xt_node *sinode);
    204 
    205 /* stream.c */
    206 int jabber_bs_request( struct im_connection *ic, struct xt_node *node, struct xt_node *qnode);
     204int jabber_si_handle_request( struct im_connection *ic, struct xt_node *node, struct xt_node *sinode );
     205void jabber_si_transfer_request( struct im_connection *ic, file_transfer_t *ft, char *who );
     206void jabber_si_free_transfer( file_transfer_t *ft);
     207
     208/* s5bytestream.c */
     209int jabber_bs_recv_request( struct im_connection *ic, struct xt_node *node, struct xt_node *qnode);
     210gboolean jabber_bs_send_start( struct jabber_transfer *tf );
     211gboolean jabber_bs_send_write( file_transfer_t *ft, char *buffer, int len );
    207212
    208213/* message.c */
  • protocols/jabber/jabber_util.c

    r2c2df7d r2ff2076  
    265265        new = g_new( char, len + 1 );
    266266        for( i = 0; i < len; i ++ )
     267        {
     268                /* don't normalize the resource */
     269                if( orig[i] == '/' )
     270                        break;
    267271                new[i] = tolower( orig[i] );
     272        }
     273        for( ; i < len; i ++ )
     274                new[i] = orig[i];
    268275       
    269276        new[i] = 0;
  • protocols/jabber/si.c

    r2c2df7d r2ff2076  
    2626
    2727void jabber_si_answer_request( file_transfer_t *ft );
    28 
    29 /* imcb callback */
     28int jabber_si_send_request(struct im_connection *ic, char *who, struct jabber_transfer *tf );
     29
     30/* file_transfer free() callback */
    3031void jabber_si_free_transfer( file_transfer_t *ft)
    3132{
     
    5051}
    5152
    52 /* imcb callback */
     53/* file_transfer finished() callback */
    5354void jabber_si_finished( file_transfer_t *ft )
    5455{
     
    5859}
    5960
    60 /* imcb callback */
     61/* file_transfer canceled() callback */
    6162void jabber_si_canceled( file_transfer_t *ft, char *reason )
    6263{
     
    7677        xt_free_node( reply );
    7778
     79}
     80
     81void jabber_si_transfer_request( struct im_connection *ic, file_transfer_t *ft, char *who )
     82{
     83        struct jabber_transfer *tf;
     84        struct jabber_data *jd = ic->proto_data;
     85
     86        imcb_log( ic, "Incoming file from %s : %s %zd bytes", ic->irc->nick, ft->file_name, ft->file_size );
     87
     88        tf = g_new0( struct jabber_transfer, 1 );
     89
     90        tf->ic = ic;
     91        tf->ft = ft;
     92        tf->ft->data = tf;
     93        tf->ft->free = jabber_si_free_transfer;
     94        tf->ft->finished = jabber_si_finished;
     95        ft->write = jabber_bs_send_write;
     96
     97        jd->filetransfers = g_slist_prepend( jd->filetransfers, tf );
     98
     99        jabber_si_send_request( ic, who, tf );
     100
     101        imcb_file_recv_start( ft );
    78102}
    79103
     
    136160                                break;
    137161                        }
     162
     163                if ( !requestok )
     164                        imcb_log( ic, "WARNING: Unsupported file transfer request from %s", ini_jid);
    138165        }
    139166       
     
    160187
    161188                *s = '/';
    162         } else
    163                 imcb_log( ic, "WARNING: Unsupported file transfer request from %s", ini_jid);
     189        }
    164190
    165191        if ( !requestok )
     
    245271        xt_free_node( reply );
    246272}
     273
     274static xt_status jabber_si_handle_response(struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
     275{
     276        struct xt_node *c, *d;
     277        char *ini_jid, *tgt_jid;
     278        GSList *tflist;
     279        struct jabber_transfer *tf=NULL;
     280        struct jabber_data *jd = ic->proto_data;
     281        char *sid;
     282
     283        if( !( tgt_jid = xt_find_attr( node, "from" ) ) ||
     284            !( ini_jid = xt_find_attr( node, "to" ) ) )
     285        {
     286                imcb_log( ic, "Invalid SI response from=%s to=%s", tgt_jid, ini_jid );
     287                return XT_HANDLED;
     288        }
     289       
     290        imcb_log( ic, "GOT RESPONSE TO FILE" );
     291        /* All this means we expect something like this: ( I think )
     292         * <iq from=... to=...>
     293         *      <si xmlns=si>
     294         *              <file xmlns=ft/>
     295         *              <feature xmlns=feature>
     296         *                      <x xmlns=xdata type=submit>
     297         *                              <field var=stream-method>
     298         *                                      <value>
     299         */
     300        if( !( tgt_jid = xt_find_attr( node, "from" ) ) ||
     301            !( ini_jid = xt_find_attr( node, "to" ) ) ||
     302            !( c = xt_find_node( node->children, "si" ) ) ||
     303            !( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_SI ) == 0 ) ||
     304            !( sid = xt_find_attr( c, "id" ) )||
     305            !( d = xt_find_node( c->children, "file" ) ) ||
     306            !( strcmp( xt_find_attr( d, "xmlns" ), XMLNS_FILETRANSFER ) == 0 ) ||
     307            !( d = xt_find_node( c->children, "feature" ) ) ||
     308            !( strcmp( xt_find_attr( d, "xmlns" ), XMLNS_FEATURE ) == 0 ) ||
     309            !( d = xt_find_node( d->children, "x" ) ) ||
     310            !( strcmp( xt_find_attr( d, "xmlns" ), XMLNS_XDATA ) == 0 ) ||
     311            !( strcmp( xt_find_attr( d, "type" ), "submit" ) == 0 ) ||
     312            !( d = xt_find_node( d->children, "field" ) ) ||
     313            !( strcmp( xt_find_attr( d, "var" ), "stream-method" ) == 0 ) ||
     314            !( d = xt_find_node( d->children, "value" ) ) )
     315        {
     316                imcb_log( ic, "WARNING: Received incomplete Stream Initiation response" );
     317                return XT_HANDLED;
     318        }
     319
     320        if( !( strcmp( d->text, XMLNS_BYTESTREAMS ) == 0 ) ) {
     321                /* since we should only have advertised what we can do and the peer should
     322                 * only have chosen what we offered, this should never happen */
     323                imcb_log( ic, "WARNING: Received invalid Stream Initiation response, method %s", d->text );
     324                       
     325                return XT_HANDLED;
     326        }
     327       
     328        /* Let's see if we can find out what this bytestream should be for... */
     329
     330        for( tflist = jd->filetransfers ; tflist; tflist = g_slist_next(tflist) )
     331        {
     332                struct jabber_transfer *tft = tflist->data;
     333                if( ( strcmp( tft->sid, sid ) == 0 ) )
     334                {
     335                        tf = tft;
     336                        break;
     337                }
     338        }
     339
     340        if (!tf)
     341        {
     342                imcb_log( ic, "WARNING: Received bytestream request from %s that doesn't match an SI request", ini_jid );
     343                return XT_HANDLED;
     344        }
     345
     346        tf->ini_jid = g_strdup( ini_jid );
     347        tf->tgt_jid = g_strdup( tgt_jid );
     348
     349        jabber_bs_send_start( tf );
     350
     351        return XT_HANDLED;
     352}
     353
     354int jabber_si_send_request(struct im_connection *ic, char *who, struct jabber_transfer *tf )
     355{
     356        struct xt_node *node, *sinode;
     357        struct jabber_buddy *bud;
     358
     359        /* who knows how many bits the future holds :) */
     360        char filesizestr[ 1 + ( int ) ( 0.301029995663981198f * sizeof( size_t ) * 8 ) ];
     361
     362        const char *methods[] =
     363        {       
     364                XMLNS_BYTESTREAMS,
     365                //XMLNS_IBB,
     366                NULL
     367        };
     368        const char **m;
     369        char *s;
     370
     371        /* Maybe we should hash this? */
     372        tf->sid = g_strdup_printf( "BitlBeeJabberSID%d", tf->ft->local_id );
     373       
     374        if( ( s = strchr( who, '=' ) ) && jabber_chat_by_name( ic, s + 1 ) )
     375                bud = jabber_buddy_by_ext_jid( ic, who, 0 );
     376        else
     377                bud = jabber_buddy_by_jid( ic, who, 0 );
     378
     379        /* start with the SI tag */
     380        sinode = xt_new_node( "si", NULL, NULL );
     381        xt_add_attr( sinode, "xmlns", XMLNS_SI );
     382        xt_add_attr( sinode, "profile", XMLNS_FILETRANSFER );
     383        xt_add_attr( sinode, "id", tf->sid );
     384
     385/*      if( mimetype )
     386                xt_add_attr( node, "mime-type", mimetype ); */
     387
     388        /* now the file tag */
     389/*      if( desc )
     390                node = xt_new_node( "desc", descr, NULL ); */
     391        node = xt_new_node( "range", NULL, NULL );
     392
     393        sprintf( filesizestr, "%zd", tf->ft->file_size );
     394        node = xt_new_node( "file", NULL, node );
     395        xt_add_attr( node, "xmlns", XMLNS_FILETRANSFER );
     396        xt_add_attr( node, "name", tf->ft->file_name );
     397        xt_add_attr( node, "size", filesizestr );
     398/*      if (hash)
     399                xt_add_attr( node, "hash", hash );
     400        if (date)
     401                xt_add_attr( node, "date", date ); */
     402
     403        xt_add_child( sinode, node );
     404
     405        /* and finally the feature tag */
     406        node = xt_new_node( "field", NULL, NULL );
     407        xt_add_attr( node, "var", "stream-method" );
     408        xt_add_attr( node, "type", "list-single" );
     409
     410        for ( m = methods ; *m ; m ++ )
     411                xt_add_child( node, xt_new_node( "option", NULL, xt_new_node( "value", (char *)*m, NULL ) ) );
     412
     413        node = xt_new_node( "x", NULL, node );
     414        xt_add_attr( node, "xmlns", XMLNS_XDATA );
     415        xt_add_attr( node, "type", "form" );
     416
     417        node = xt_new_node( "feature", NULL, node );
     418        xt_add_attr( node, "xmlns", XMLNS_FEATURE );
     419
     420        xt_add_child( sinode, node );
     421
     422        /* and we are there... */
     423        node = jabber_make_packet( "iq", "set", bud ? bud->full_jid : who, sinode );
     424        jabber_cache_add( ic, node, jabber_si_handle_response );
     425       
     426        return jabber_write_packet( ic, node );
     427}
  • protocols/nogaim.h

    r2c2df7d r2ff2076  
    229229         * - Most protocols will just want to set this to g_strcasecmp().*/
    230230        int (* handle_cmp) (const char *who1, const char *who2);
     231
     232        /* Incoming transfer request */
     233        void (* transfer_request) (struct im_connection *, file_transfer_t *ft, char *handle );
    231234};
    232235
Note: See TracChangeset for help on using the changeset viewer.