Changeset 767a148


Ignore:
Timestamp:
2010-03-21T16:06:31Z (14 years ago)
Author:
Wilmer van der Gaast <wilmer@…>
Branches:
master
Children:
1cc0df3, 85693e6
Parents:
545d7c0 (diff), a81d679 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merging in file transfer support. Most important points from my review
are fixed now, time to let it settle in and get people to try it.

Files:
9 added
18 edited

Legend:

Unmodified
Added
Removed
  • Makefile

    r545d7c0 r767a148  
    1010
    1111# Program variables
    12 objects = account.o bitlbee.o chat.o crypting.o help.o ipc.o irc.o irc_commands.o nick.o query.o root_commands.o set.o storage.o $(STORAGE_OBJS) user.o
    13 headers = account.h bitlbee.h commands.h conf.h config.h crypting.h help.h ipc.h irc.h log.h nick.h query.h set.h sock.h storage.h user.h lib/events.h lib/http_client.h lib/ini.h lib/md5.h lib/misc.h lib/proxy.h lib/sha1.h lib/ssl_client.h lib/url.h protocols/nogaim.h
     12objects = account.o bitlbee.o chat.o crypting.o dcc.o help.o ipc.o irc.o irc_commands.o nick.o query.o root_commands.o set.o storage.o $(STORAGE_OBJS) user.o
     13headers = account.h bitlbee.h commands.h conf.h config.h crypting.h help.h ipc.h irc.h log.h nick.h query.h set.h sock.h storage.h user.h lib/events.h lib/ftutil.h lib/http_client.h lib/ini.h lib/md5.h lib/misc.h lib/proxy.h lib/sha1.h lib/ssl_client.h lib/url.h protocols/ft.h protocols/nogaim.h
    1414subdirs = lib protocols
    1515
  • conf.c

    r545d7c0 r767a148  
    6363        conf->ping_timeout = 300;
    6464        conf->user = NULL;
     65        conf->ft_max_size = SIZE_MAX;
     66        conf->ft_max_kbps = G_MAXUINT;
     67        conf->ft_listen = NULL;
    6568        conf->protocols = NULL;
    6669        proxytype = 0;
     
    308311                                conf->user = g_strdup( ini->value );
    309312                        }
     313                        else if( g_strcasecmp( ini->key, "ft_max_size" ) == 0 )
     314                        {
     315                                size_t ft_max_size;
     316                                if( sscanf( ini->value, "%zu", &ft_max_size ) != 1 )
     317                                {
     318                                        fprintf( stderr, "Invalid %s value: %s\n", ini->key, ini->value );
     319                                        return 0;
     320                                }
     321                                conf->ft_max_size = ft_max_size;
     322                        }
     323                        else if( g_strcasecmp( ini->key, "ft_max_kbps" ) == 0 )
     324                        {
     325                                if( sscanf( ini->value, "%d", &i ) != 1 )
     326                                {
     327                                        fprintf( stderr, "Invalid %s value: %s\n", ini->key, ini->value );
     328                                        return 0;
     329                                }
     330                                conf->ft_max_kbps = i;
     331                        }
     332                        else if( g_strcasecmp( ini->key, "ft_listen" ) == 0 )
     333                        {
     334                                g_free( conf->ft_listen );
     335                                conf->ft_listen = g_strdup( ini->value );
     336                        }
    310337                        else if( g_strcasecmp( ini->key, "protocols" ) == 0 )
    311338                        {
  • conf.h

    r545d7c0 r767a148  
    5050        int ping_timeout;
    5151        char *user;
     52        size_t ft_max_size;
     53        int ft_max_kbps;
     54        char *ft_listen;
    5255        char **protocols;
    5356} conf_t;
  • doc/user-guide/commands.xml

    r545d7c0 r767a148  
    10281028
    10291029        </bitlbee-command>
     1030       
     1031        <bitlbee-command name="transfers">
     1032                <short-description>Monitor, cancel, or reject file transfers</short-description>
     1033                <syntax>transfers [&lt;cancel&gt; id | &lt;reject&gt;]</syntax>
     1034               
     1035                <description>
     1036                        <para>
     1037                                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.
     1038                        </para>
     1039
     1040                        <ircexample>
     1041                                <ircline nick="ulim">transfers</ircline>
     1042                        </ircexample>
     1043                </description>
     1044               
     1045                <bitlbee-command name="cancel">
     1046                        <short-description>Cancels the file transfer with the given id</short-description>
     1047                        <syntax>transfers &lt;cancel&gt; id</syntax>
     1048
     1049                        <description>
     1050                                <para>Cancels the file transfer with the given id</para>
     1051                        </description>
     1052
     1053                        <ircexample>
     1054                                <ircline nick="ulim">transfers cancel 1</ircline>
     1055                                <ircline nick="root">Canceling file transfer for test</ircline>
     1056                        </ircexample>
     1057                </bitlbee-command>
     1058
     1059                <bitlbee-command name="reject">
     1060                        <short-description>Rejects all incoming transfers</short-description>
     1061                        <syntax>transfers &lt;reject&gt;</syntax>
     1062
     1063                        <description>
     1064                                <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>
     1065                        </description>
     1066
     1067                        <ircexample>
     1068                                <ircline nick="ulim">transfers reject</ircline>
     1069                        </ircexample>
     1070                </bitlbee-command>
     1071        </bitlbee-command>
     1072       
    10301073</chapter>
  • irc.c

    r545d7c0 r767a148  
    2929#include "crypting.h"
    3030#include "ipc.h"
     31#include "dcc.h"
    3132
    3233static gboolean irc_userping( gpointer _irc, int fd, b_input_condition cond );
     
    11071108                        return( 1 );
    11081109                }
     1110                else if( g_strncasecmp( s + 1, "DCC", 3 ) == 0 )
     1111                {
     1112                        if( u && u->ic && u->ic->acc->prpl->transfer_request )
     1113                        {
     1114                                file_transfer_t *ft = dcc_request( u->ic, s + 5 );
     1115                                if ( ft )
     1116                                        u->ic->acc->prpl->transfer_request( u->ic, ft, u->handle );
     1117                        }
     1118                        return( 1 );
     1119                }               
    11091120                else
    11101121                {
    1111                         irc_usermsg( irc, "Non-ACTION CTCP's aren't supported" );
     1122                        irc_usermsg( irc, "Supported CTCPs are ACTION, VERSION, PING, TYPING, DCC" );
    11121123                        return( 0 );
    11131124                }
  • irc.h

    r545d7c0 r767a148  
    8383        struct query *queries;
    8484        struct account *accounts;
     85        GSList *file_transfers;
    8586        struct chat *chatrooms;
    8687       
  • lib/Makefile

    r545d7c0 r767a148  
    1010
    1111# [SH] Program variables
    12 objects = arc.o base64.o $(EVENT_HANDLER) http_client.o ini.o md5.o misc.o proxy.o sha1.o $(SSL_CLIENT) url.o xmltree.o
     12objects = arc.o base64.o $(EVENT_HANDLER) http_client.o ini.o md5.o misc.o proxy.o sha1.o $(SSL_CLIENT) url.o xmltree.o ftutil.o
    1313
    1414CFLAGS += -Wall
  • protocols/jabber/Makefile

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

    r545d7c0 r767a148  
    9191                        pack = 0;
    9292                }
    93                 else if( strcmp( s, XMLNS_DISCOVER ) == 0 )
    94                 {
    95                         const char *features[] = { XMLNS_DISCOVER,
     93                else if( strcmp( s, XMLNS_DISCO_INFO ) == 0 )
     94                {
     95                        const char *features[] = { XMLNS_DISCO_INFO,
    9696                                                   XMLNS_VERSION,
    9797                                                   XMLNS_TIME,
     
    9999                                                   XMLNS_MUC,
    100100                                                   XMLNS_PING,
     101                                                   XMLNS_SI,
     102                                                   XMLNS_BYTESTREAMS,
     103                                                   XMLNS_FILETRANSFER,
    101104                                                   NULL };
    102105                        const char **f;
     
    118121                {
    119122                        xt_free_node( reply );
    120                         reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel" );
     123                        reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel", NULL );
    121124                        pack = 0;
    122125                }
     
    124127        else if( strcmp( type, "set" ) == 0 )
    125128        {
    126                 if( !( c = xt_find_node( node->children, "query" ) ) ||
    127                     !( s = xt_find_attr( c, "xmlns" ) ) )
     129                if( ( c = xt_find_node( node->children, "si" ) ) &&
     130                    ( s = xt_find_attr( c, "xmlns" ) ) &&
     131                    ( strcmp( s, XMLNS_SI ) == 0 ) )
     132                {
     133                        return jabber_si_handle_request( ic, node, c );
     134                }
     135                else if( !( c = xt_find_node( node->children, "query" ) ) ||
     136                         !( s = xt_find_attr( c, "xmlns" ) ) )
    128137                {
    129138                        imcb_log( ic, "Warning: Received incomplete IQ-%s packet", type );
    130139                        return XT_HANDLED;
    131140                }
    132                
     141                else if( strcmp( s, XMLNS_ROSTER ) == 0 )
     142                {
    133143                /* This is a roster push. XMPP servers send this when someone
    134144                   was added to (or removed from) the buddy list. AFAIK they're
    135145                   sent even if we added this buddy in our own session. */
    136                 if( strcmp( s, XMLNS_ROSTER ) == 0 )
    137                 {
    138146                        int bare_len = strlen( ic->acc->user );
    139147                       
     
    152160                               
    153161                                xt_free_node( reply );
    154                                 reply = jabber_make_error_packet( node, "not-allowed", "cancel" );
     162                                reply = jabber_make_error_packet( node, "not-allowed", "cancel", NULL );
    155163                                pack = 0;
    156164                        }
    157165                }
     166                else if( strcmp( s, XMLNS_BYTESTREAMS ) == 0 )
     167                {
     168                        /* Bytestream Request (stage 2 of file transfer) */
     169                        return jabber_bs_recv_request( ic, node, c );
     170                }
    158171                else
    159172                {
    160173                        xt_free_node( reply );
    161                         reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel" );
     174                        reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel", NULL );
    162175                        pack = 0;
    163176                }
     
    609622        return st;
    610623}
     624
     625xt_status jabber_iq_parse_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
     626
     627xt_status jabber_iq_query_features( struct im_connection *ic, char *bare_jid )
     628{
     629        struct xt_node *node, *query;
     630        struct jabber_buddy *bud;
     631       
     632        if( ( bud = jabber_buddy_by_jid( ic, bare_jid , 0 ) ) == NULL )
     633        {
     634                /* Who cares about the unknown... */
     635                imcb_log( ic, "Couldn't find buddy: %s", bare_jid);
     636                return XT_HANDLED;
     637        }
     638       
     639        if( bud->features ) /* been here already */
     640                return XT_HANDLED;
     641       
     642        node = xt_new_node( "query", NULL, NULL );
     643        xt_add_attr( node, "xmlns", XMLNS_DISCO_INFO );
     644       
     645        if( !( query = jabber_make_packet( "iq", "get", bare_jid, node ) ) )
     646        {
     647                imcb_log( ic, "WARNING: Couldn't generate feature query" );
     648                xt_free_node( node );
     649                return XT_HANDLED;
     650        }
     651
     652        jabber_cache_add( ic, query, jabber_iq_parse_features );
     653
     654        return jabber_write_packet( ic, query ) ? XT_HANDLED : XT_ABORT;
     655}
     656
     657xt_status jabber_iq_parse_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
     658{
     659        struct xt_node *c;
     660        struct jabber_buddy *bud;
     661        char *feature, *xmlns, *from;
     662
     663        if( !( from = xt_find_attr( node, "from" ) ) ||
     664            !( c = xt_find_node( node->children, "query" ) ) ||
     665            !( xmlns = xt_find_attr( c, "xmlns" ) ) ||
     666            !( strcmp( xmlns, XMLNS_DISCO_INFO ) == 0 ) )
     667        {
     668                imcb_log( ic, "WARNING: Received incomplete IQ-result packet for discover" );
     669                return XT_HANDLED;
     670        }
     671        if( ( bud = jabber_buddy_by_jid( ic, from, 0 ) ) == NULL )
     672        {
     673                /* Who cares about the unknown... */
     674                imcb_log( ic, "Couldn't find buddy: %s", from );
     675                return XT_HANDLED;
     676        }
     677       
     678        c = c->children;
     679        while( ( c = xt_find_node( c, "feature" ) ) )
     680        {
     681                feature = xt_find_attr( c, "var" );
     682                if( feature )
     683                        bud->features = g_slist_append( bud->features, g_strdup( feature ) );
     684                c = c->next;
     685        }
     686
     687        return XT_HANDLED;
     688}
     689
     690xt_status jabber_iq_parse_server_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
     691
     692xt_status jabber_iq_query_server( struct im_connection *ic, char *jid, char *xmlns )
     693{
     694        struct xt_node *node, *query;
     695        struct jabber_data *jd = ic->proto_data;
     696       
     697        node = xt_new_node( "query", NULL, NULL );
     698        xt_add_attr( node, "xmlns", xmlns );
     699       
     700        if( !( query = jabber_make_packet( "iq", "get", jid, node ) ) )
     701        {
     702                imcb_log( ic, "WARNING: Couldn't generate server query" );
     703                xt_free_node( node );
     704        }
     705
     706        jd->have_streamhosts--;
     707        jabber_cache_add( ic, query, jabber_iq_parse_server_features );
     708
     709        return jabber_write_packet( ic, query ) ? XT_HANDLED : XT_ABORT;
     710}
     711
     712/*
     713 * Query the server for "items", query each "item" for identities, query each "item" that's a proxy for it's bytestream info
     714 */
     715xt_status jabber_iq_parse_server_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
     716{
     717        struct xt_node *c;
     718        struct jabber_data *jd = ic->proto_data;
     719        char *xmlns, *from;
     720
     721        if( !( c = xt_find_node( node->children, "query" ) ) ||
     722            !( from = xt_find_attr( node, "from" ) ) ||
     723            !( xmlns = xt_find_attr( c, "xmlns" ) ) )
     724        {
     725                imcb_log( ic, "WARNING: Received incomplete IQ-result packet for discover" );
     726                return XT_HANDLED;
     727        }
     728
     729        jd->have_streamhosts++;
     730
     731        if( strcmp( xmlns, XMLNS_DISCO_ITEMS ) == 0 )
     732        {
     733                char *itemjid;
     734
     735                /* answer from server */
     736       
     737                c = c->children;
     738                while( ( c = xt_find_node( c, "item" ) ) )
     739                {
     740                        itemjid = xt_find_attr( c, "jid" );
     741                       
     742                        if( itemjid )
     743                                jabber_iq_query_server( ic, itemjid, XMLNS_DISCO_INFO );
     744
     745                        c = c->next;
     746                }
     747        }
     748        else if( strcmp( xmlns, XMLNS_DISCO_INFO ) == 0 )
     749        {
     750                char *category, *type;
     751
     752                /* answer from potential proxy */
     753
     754                c = c->children;
     755                while( ( c = xt_find_node( c, "identity" ) ) )
     756                {
     757                        category = xt_find_attr( c, "category" );
     758                        type = xt_find_attr( c, "type" );
     759
     760                        if( type && ( strcmp( type, "bytestreams" ) == 0 ) &&
     761                            category && ( strcmp( category, "proxy" ) == 0 ) )
     762                                jabber_iq_query_server( ic, from, XMLNS_BYTESTREAMS );
     763
     764                        c = c->next;
     765                }
     766        }
     767        else if( strcmp( xmlns, XMLNS_BYTESTREAMS ) == 0 )
     768        {
     769                char *host, *jid, *port_s;
     770                int port;
     771
     772                /* answer from proxy */
     773
     774                if( ( c = xt_find_node( c->children, "streamhost" ) ) &&
     775                    ( host = xt_find_attr( c, "host" ) ) &&
     776                    ( port_s = xt_find_attr( c, "port" ) ) &&
     777                    ( sscanf( port_s, "%d", &port ) == 1 ) &&
     778                    ( jid = xt_find_attr( c, "jid" ) ) )
     779                {
     780                        jabber_streamhost_t *sh = g_new0( jabber_streamhost_t, 1 );
     781                       
     782                        sh->jid = g_strdup( jid );
     783                        sh->host = g_strdup( host );
     784                        g_snprintf( sh->port, sizeof( sh->port ), "%u", port );
     785
     786                        imcb_log( ic, "Proxy found: jid %s host %s port %u", jid, host, port );
     787                        jd->streamhosts = g_slist_append( jd->streamhosts, sh );
     788                }
     789        }
     790
     791        if( jd->have_streamhosts == 0 )
     792                jd->have_streamhosts++;
     793
     794        return XT_HANDLED;
     795}
  • protocols/jabber/jabber.c

    r545d7c0 r767a148  
    6565       
    6666        s = set_add( &acc->set, "priority", "0", set_eval_priority, acc );
     67
     68        s = set_add( &acc->set, "proxy", "<local>;<auto>", NULL, acc );
    6769       
    6870        s = set_add( &acc->set, "resource", "BitlBee", NULL, acc );
     
    264266        struct jabber_data *jd = ic->proto_data;
    265267       
     268        while( jd->filetransfers )
     269                imcb_file_canceled( ( ( struct jabber_transfer *) jd->filetransfers->data )->ft, "Logging out" );
     270
     271        while( jd->streamhosts )
     272        {
     273                jabber_streamhost_t *sh = jd->streamhosts->data;
     274                jd->streamhosts = g_slist_remove( jd->streamhosts, sh );
     275                g_free( sh->jid );
     276                g_free( sh->host );
     277                g_free( sh );
     278        }
     279
    266280        if( jd->fd >= 0 )
    267281                jabber_end_stream( ic );
     
    544558        ret->send_typing = jabber_send_typing;
    545559        ret->handle_cmp = g_strcasecmp;
     560        ret->transfer_request = jabber_si_transfer_request;
    546561
    547562        register_protocol( ret );
  • protocols/jabber/jabber.h

    r545d7c0 r767a148  
    6161} jabber_buddy_flags_t;
    6262
     63/* Stores a streamhost's (a.k.a. proxy) data */
     64typedef struct
     65{
     66        char *jid;
     67        char *host;
     68        char port[6];
     69} jabber_streamhost_t;
     70
    6371typedef enum
    6472{
     
    9199        GHashTable *node_cache;
    92100        GHashTable *buddies;
     101
     102        GSList *filetransfers;
     103        GSList *streamhosts;
     104        int have_streamhosts;
    93105};
    94106
     
    127139        struct jabber_away_state *away_state;
    128140        char *away_message;
     141        GSList *features;
    129142       
    130143        time_t last_msg;
     
    140153        char *my_full_jid; /* Separate copy because of case sensitivity. */
    141154        struct jabber_buddy *me;
     155};
     156
     157struct jabber_transfer
     158{
     159        /* bitlbee's handle for this transfer */
     160        file_transfer_t *ft;
     161
     162        /* the stream's private handle */
     163        gpointer streamhandle;
     164
     165        /* timeout for discover queries */
     166        gint disco_timeout;
     167        gint disco_timeout_fired;
     168
     169        struct im_connection *ic;
     170
     171        struct jabber_buddy *bud;
     172
     173        int watch_in;
     174        int watch_out;
     175
     176        char *ini_jid;
     177        char *tgt_jid;
     178        char *iq_id;
     179        char *sid;
     180        int accepted;
     181
     182        size_t bytesread, byteswritten;
     183        int fd;
     184        struct sockaddr_storage saddr;
    142185};
    143186
     
    167210
    168211/* Some supported extensions/legacy stuff */
    169 #define XMLNS_AUTH         "jabber:iq:auth"                     /* XEP-0078 */
    170 #define XMLNS_VERSION      "jabber:iq:version"                  /* XEP-0092 */
    171 #define XMLNS_TIME         "jabber:iq:time"                     /* XEP-0090 */
    172 #define XMLNS_PING         "urn:xmpp:ping"                      /* XEP-0199 */
    173 #define XMLNS_VCARD        "vcard-temp"                         /* XEP-0054 */
    174 #define XMLNS_DELAY        "jabber:x:delay"                     /* XEP-0091 */
    175 #define XMLNS_CHATSTATES   "http://jabber.org/protocol/chatstates"  /* 0085 */
    176 #define XMLNS_DISCOVER     "http://jabber.org/protocol/disco#info"  /* 0030 */
    177 #define XMLNS_MUC          "http://jabber.org/protocol/muc"     /* XEP-0045 */
    178 #define XMLNS_MUC_USER     "http://jabber.org/protocol/muc#user"/* XEP-0045 */
    179 #define XMLNS_CAPS         "http://jabber.org/protocol/caps"    /* XEP-0115 */
     212#define XMLNS_AUTH         "jabber:iq:auth"                                      /* XEP-0078 */
     213#define XMLNS_VERSION      "jabber:iq:version"                                   /* XEP-0092 */
     214#define XMLNS_TIME         "jabber:iq:time"                                      /* XEP-0090 */
     215#define XMLNS_PING         "urn:xmpp:ping"                                       /* XEP-0199 */
     216#define XMLNS_VCARD        "vcard-temp"                                          /* XEP-0054 */
     217#define XMLNS_DELAY        "jabber:x:delay"                                      /* XEP-0091 */
     218#define XMLNS_XDATA        "jabber:x:data"                                       /* XEP-0004 */
     219#define XMLNS_CHATSTATES   "http://jabber.org/protocol/chatstates"               /* XEP-0085 */
     220#define XMLNS_DISCO_INFO   "http://jabber.org/protocol/disco#info"               /* XEP-0030 */
     221#define XMLNS_DISCO_ITEMS  "http://jabber.org/protocol/disco#items"              /* XEP-0030 */
     222#define XMLNS_MUC          "http://jabber.org/protocol/muc"                      /* XEP-0045 */
     223#define XMLNS_MUC_USER     "http://jabber.org/protocol/muc#user"                 /* XEP-0045 */
     224#define XMLNS_CAPS         "http://jabber.org/protocol/caps"                     /* XEP-0115 */
     225#define XMLNS_FEATURE      "http://jabber.org/protocol/feature-neg"              /* XEP-0020 */
     226#define XMLNS_SI           "http://jabber.org/protocol/si"                       /* XEP-0095 */
     227#define XMLNS_FILETRANSFER "http://jabber.org/protocol/si/profile/file-transfer" /* XEP-0096 */
     228#define XMLNS_BYTESTREAMS  "http://jabber.org/protocol/bytestreams"              /* XEP-0065 */
     229#define XMLNS_IBB          "http://jabber.org/protocol/ibb"                      /* XEP-0047 */
    180230
    181231/* iq.c */
     
    187237int jabber_add_to_roster( struct im_connection *ic, char *handle, char *name );
    188238int jabber_remove_from_roster( struct im_connection *ic, char *handle );
     239xt_status jabber_iq_query_features( struct im_connection *ic, char *bare_jid );
     240xt_status jabber_iq_query_server( struct im_connection *ic, char *jid, char *xmlns );
     241
     242/* si.c */
     243int jabber_si_handle_request( struct im_connection *ic, struct xt_node *node, struct xt_node *sinode );
     244void jabber_si_transfer_request( struct im_connection *ic, file_transfer_t *ft, char *who );
     245void jabber_si_free_transfer( file_transfer_t *ft);
     246
     247/* s5bytestream.c */
     248int jabber_bs_recv_request( struct im_connection *ic, struct xt_node *node, struct xt_node *qnode);
     249gboolean jabber_bs_send_start( struct jabber_transfer *tf );
     250gboolean jabber_bs_send_write( file_transfer_t *ft, char *buffer, unsigned int len );
    189251
    190252/* message.c */
     
    200262char *set_eval_tls( set_t *set, char *value );
    201263struct xt_node *jabber_make_packet( char *name, char *type, char *to, struct xt_node *children );
    202 struct xt_node *jabber_make_error_packet( struct xt_node *orig, char *err_cond, char *err_type );
     264struct xt_node *jabber_make_error_packet( struct xt_node *orig, char *err_cond, char *err_type, char *err_code );
    203265void jabber_cache_add( struct im_connection *ic, struct xt_node *node, jabber_cache_event func );
    204266struct xt_node *jabber_cache_get( struct im_connection *ic, char *id );
  • protocols/jabber/jabber_util.c

    r545d7c0 r767a148  
    9999}
    100100
    101 struct xt_node *jabber_make_error_packet( struct xt_node *orig, char *err_cond, char *err_type )
     101struct xt_node *jabber_make_error_packet( struct xt_node *orig, char *err_cond, char *err_type, char *err_code )
    102102{
    103103        struct xt_node *node, *c;
     
    111111        c = xt_new_node( "error", NULL, c );
    112112        xt_add_attr( c, "type", err_type );
     113       
     114        /* Add the error code, if present */
     115        if (err_code)
     116                xt_add_attr( c, "code", err_code );
    113117       
    114118        /* To make the actual error packet, we copy the original packet and
  • protocols/msn/Makefile

    r545d7c0 r767a148  
    1010
    1111# [SH] Program variables
    12 objects = msn.o msn_util.o ns.o passport.o sb.o tables.o
     12objects = invitation.o msn.o msn_util.o ns.o passport.o sb.o tables.o
    1313
    1414CFLAGS += -Wall
  • protocols/msn/msn.c

    r545d7c0 r767a148  
    8181        if( md )
    8282        {
     83                while( md->filetransfers ) {
     84                        imcb_file_canceled( md->filetransfers->data, "Closing connection" );
     85                }
     86               
    8387                if( md->fd >= 0 )
    8488                        closesocket( md->fd );
     
    340344        ret->send_typing = msn_send_typing;
    341345        ret->handle_cmp = g_strcasecmp;
     346        ret->transfer_request = msn_ftp_transfer_request;
    342347
    343348        register_protocol(ret);
  • protocols/msn/msn.h

    r545d7c0 r767a148  
    6969        int sb_failures;
    7070        time_t first_sb_failure;
     71        GSList *filetransfers;
    7172       
    7273        const struct msn_away_state *away_state;
     
    180181int msn_sb_write_msg( struct im_connection *ic, struct msn_message *m );
    181182
     183/* invitation.c */
     184void msn_ftp_transfer_request( struct im_connection *ic, file_transfer_t *ft, char *who );
     185
    182186#endif //_MSN_H
  • protocols/msn/sb.c

    r545d7c0 r767a148  
    2929#include "passport.h"
    3030#include "md5.h"
     31#include "invitation.h"
    3132
    3233static gboolean msn_sb_callback( gpointer data, gint source, b_input_condition cond );
     
    168169               
    169170                /* Build the message. Convert LF to CR-LF for normal messages. */
    170                 if( strcmp( text, TYPING_NOTIFICATION_MESSAGE ) != 0 )
     171                if( strcmp( text, TYPING_NOTIFICATION_MESSAGE ) == 0 )
     172                {
     173                        i = strlen( MSN_TYPING_HEADERS ) + strlen( sb->ic->acc->user );
     174                        buf = g_new0( char, i );
     175                        i = g_snprintf( buf, i, MSN_TYPING_HEADERS, sb->ic->acc->user );
     176                }
     177                else if( strncmp( text, MSN_INVITE_HEADERS, sizeof( MSN_INVITE_HEADERS ) - 1 ) == 0 )
     178                {
     179                        buf = g_strdup( text );
     180                        i = strlen( buf );
     181                }
     182                else
    171183                {
    172184                        buf = g_new0( char, sizeof( MSN_MESSAGE_HEADERS ) + strlen( text ) * 2 + 1 );
     
    181193                                buf[i++] = text[j];
    182194                        }
    183                 }
    184                 else
    185                 {
    186                         i = strlen( MSN_TYPING_HEADERS ) + strlen( sb->ic->acc->user );
    187                         buf = g_new0( char, i );
    188                         i = g_snprintf( buf, i, MSN_TYPING_HEADERS, sb->ic->acc->user );
    189195                }
    190196               
     
    687693                else if( g_strncasecmp( ct, "text/x-msmsgsinvite", 19 ) == 0 )
    688694                {
    689                         char *itype = msn_findheader( body, "Application-GUID:", blen );
    690                         char buf[1024];
     695                        char *command = msn_findheader( body, "Invitation-Command:", blen );
     696                        char *cookie = msn_findheader( body, "Invitation-Cookie:", blen );
     697                        unsigned int icookie;
    691698                       
    692699                        g_free( ct );
    693700                       
    694                         *buf = 0;
    695                        
    696                         if( !itype )
    697                                 return( 1 );
    698                        
    699                         /* File transfer. */
    700                         if( strcmp( itype, "{5D3E02AB-6190-11d3-BBBB-00C04F795683}" ) == 0 )
    701                         {
    702                                 char *name = msn_findheader( body, "Application-File:", blen );
    703                                 char *size = msn_findheader( body, "Application-FileSize:", blen );
    704                                
    705                                 if( name && size )
    706                                 {
    707                                         g_snprintf( buf, sizeof( buf ), "<< \x02""BitlBee\x02"" - Filetransfer: `%s', %s bytes >>\n"
    708                                                     "Filetransfers are not supported by BitlBee for now...", name, size );
    709                                 }
    710                                 else
    711                                 {
    712                                         strcpy( buf, "<< \x02""BitlBee\x02"" - Corrupted MSN filetransfer invitation message >>" );
    713                                 }
    714                                
    715                                 if( name ) g_free( name );
    716                                 if( size ) g_free( size );
    717                         }
    718                         else
    719                         {
    720                                 char *iname = msn_findheader( body, "Application-Name:", blen );
    721                                
    722                                 g_snprintf( buf, sizeof( buf ), "<< \x02""BitlBee\x02"" - Unknown MSN invitation - %s (%s) >>",
    723                                                                 itype, iname ? iname : "no name" );
    724                                
    725                                 if( iname ) g_free( iname );
    726                         }
    727                        
    728                         g_free( itype );
    729                        
    730                         if( !*buf )
    731                                 return( 1 );
    732                        
    733                         if( sb->who )
    734                         {
    735                                 imcb_buddy_msg( ic, cmd[1], buf, 0, 0 );
    736                         }
    737                         else if( sb->chat )
    738                         {
    739                                 imcb_chat_msg( sb->chat, cmd[1], buf, 0, 0 );
    740                         }
    741                         else
    742                         {
    743                                 /* PANIC! */
    744                         }
     701                        /* Every invite should have both a Command and Cookie header */
     702                        if( !command || !cookie ) {
     703                                g_free( command );
     704                                g_free( cookie );
     705                                imcb_log( ic, "Warning: No command or cookie from %s", sb->who );
     706                                return 1;
     707                        }
     708                       
     709                        icookie = strtoul( cookie, NULL, 10 );
     710                        g_free( cookie );
     711                       
     712                        if( g_strncasecmp( command, "INVITE", 6 ) == 0 ) {
     713                                msn_invitation_invite( sb, cmd[1], icookie, body, blen );
     714                        } else if( g_strncasecmp( command, "ACCEPT", 6 ) == 0 ) {
     715                                msn_invitation_accept( sb, cmd[1], icookie, body, blen );
     716                        } else if( g_strncasecmp( command, "CANCEL", 6 ) == 0 ) {
     717                                msn_invitation_cancel( sb, cmd[1], icookie, body, blen );
     718                        } else {
     719                                imcb_log( ic, "Warning: Received invalid invitation with "
     720                                                "command %s from %s", command, sb->who );
     721                        }
     722                       
     723                        g_free( command );
     724                }
     725                else if( g_strncasecmp( ct, "application/x-msnmsgrp2p", 24 ) == 0 )
     726                {
     727                        imcb_error( sb->ic, "Cannot receive file from %s: BitlBee does not "
     728                                        "support msnmsgrp2p yet.", sb->who );
     729                        g_free( ct );
    745730                }
    746731                else if( g_strncasecmp( ct, "text/x-msmsgscontrol", 20 ) == 0 )
  • protocols/nogaim.h

    r545d7c0 r767a148  
    4545#include "proxy.h"
    4646#include "query.h"
     47#include "md5.h"
     48#include "ft.h"
    4749
    4850#define BUDDY_ALIAS_MAXLEN 388   /* because MSN names can be 387 characters */
     
    228230        void (* auth_allow)     (struct im_connection *, const char *who);
    229231        void (* auth_deny)      (struct im_connection *, const char *who);
     232
     233        /* Incoming transfer request */
     234        void (* transfer_request) (struct im_connection *, file_transfer_t *ft, char *handle );
    230235};
    231236
  • root_commands.c

    r545d7c0 r767a148  
    11541154        {
    11551155                irc_usermsg( irc, "Unknown command: %s %s. Please use \x02help commands\x02 to get a list of available commands.", "chat", cmd[1] );
     1156        }
     1157}
     1158
     1159static void cmd_transfer( irc_t *irc, char **cmd )
     1160{
     1161        GSList *files = irc->file_transfers;
     1162        enum { LIST, REJECT, CANCEL };
     1163        int subcmd = LIST;
     1164        int fid;
     1165
     1166        if( !files )
     1167        {
     1168                irc_usermsg( irc, "No pending transfers" );
     1169                return;
     1170        }
     1171
     1172        if( cmd[1] && ( strcmp( cmd[1], "reject" ) == 0 ) )
     1173        {
     1174                subcmd = REJECT;
     1175        }
     1176        else if( cmd[1] && ( strcmp( cmd[1], "cancel" ) == 0 ) &&
     1177                 cmd[2] && ( sscanf( cmd[2], "%d", &fid ) == 1 ) )
     1178        {
     1179                subcmd = CANCEL;
     1180        }
     1181
     1182        for( ; files; files = g_slist_next( files ) )
     1183        {
     1184                file_transfer_t *file = files->data;
     1185               
     1186                switch( subcmd ) {
     1187                case LIST:
     1188                        if ( file->status == FT_STATUS_LISTENING )
     1189                                irc_usermsg( irc,
     1190                                        "Pending file(id %d): %s (Listening...)", file->local_id, file->file_name);
     1191                        else
     1192                        {
     1193                                int kb_per_s = 0;
     1194                                time_t diff = time( NULL ) - file->started ? : 1;
     1195                                if ( ( file->started > 0 ) && ( file->bytes_transferred > 0 ) )
     1196                                        kb_per_s = file->bytes_transferred / 1024 / diff;
     1197                                       
     1198                                irc_usermsg( irc,
     1199                                        "Pending file(id %d): %s (%10zd/%zd kb, %d kb/s)", file->local_id, file->file_name,
     1200                                        file->bytes_transferred/1024, file->file_size/1024, kb_per_s);
     1201                        }
     1202                        break;
     1203                case REJECT:
     1204                        if( file->status == FT_STATUS_LISTENING )
     1205                        {
     1206                                irc_usermsg( irc, "Rejecting file transfer for %s", file->file_name );
     1207                                imcb_file_canceled( file, "Denied by user" );
     1208                        }
     1209                        break;
     1210                case CANCEL:
     1211                        if( file->local_id == fid )
     1212                        {
     1213                                irc_usermsg( irc, "Canceling file transfer for %s", file->file_name );
     1214                                imcb_file_canceled( file, "Canceled by user" );
     1215                        }
     1216                        break;
     1217                }
    11561218        }
    11571219}
     
    11781240        { "join_chat",      2, cmd_join_chat,      0 },
    11791241        { "chat",           1, cmd_chat,           0 },
     1242        { "transfer",       0, cmd_transfer,       0 },
    11801243        { NULL }
    11811244};
Note: See TracChangeset for help on using the changeset viewer.