Changes in / [a830512:87f525e]


Ignore:
Files:
5 added
13 edited

Legend:

Unmodified
Added
Removed
  • Makefile

    ra830512 r87f525e  
    1010
    1111# Program variables
    12 objects = account.o bitlbee.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 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 dcc.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/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 protocols/ft.h
    1414subdirs = lib protocols
    1515
  • conf.c

    ra830512 r87f525e  
    6363        conf->ping_timeout = 300;
    6464        conf->user = NULL;
     65        conf->max_filetransfer_size = G_MAXUINT;
    6566        proxytype = 0;
    6667       
  • conf.h

    ra830512 r87f525e  
    5050        int ping_timeout;
    5151        char *user;
     52        size_t max_filetransfer_size;
    5253} conf_t;
    5354
  • doc/user-guide/commands.xml

    ra830512 r87f525e  
    878878
    879879        </bitlbee-command>
     880       
     881        <bitlbee-command name="transfers">
     882                <short-description>Monitor, cancel, or reject file transfers</short-description>
     883                <syntax>transfers [&lt;cancel&gt; id | &lt;reject&gt;]</syntax>
     884               
     885                <description>
     886                        <para>
     887                                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.
     888                        </para>
     889
     890                        <ircexample>
     891                                <ircline nick="ulim">transfers</ircline>
     892                        </ircexample>
     893                </description>
     894               
     895                <bitlbee-command name="cancel">
     896                        <short-description>Cancels the file transfer with the given id</short-description>
     897                        <syntax>transfers &lt;cancel&gt; id</syntax>
     898
     899                        <description>
     900                                <para>Cancels the file transfer with the given id</para>
     901                        </description>
     902
     903                        <ircexample>
     904                                <ircline nick="ulim">transfers cancel 1</ircline>
     905                                <ircline nick="root">Canceling file transfer for test</ircline>
     906                        </ircexample>
     907                </bitlbee-command>
     908
     909                <bitlbee-command name="reject">
     910                        <short-description>Rejects all incoming transfers</short-description>
     911                        <syntax>transfers &lt;reject&gt;</syntax>
     912
     913                        <description>
     914                                <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>
     915                        </description>
     916
     917                        <ircexample>
     918                                <ircline nick="ulim">transfers reject</ircline>
     919                        </ircexample>
     920                </bitlbee-command>
     921        </bitlbee-command>
     922       
    880923</chapter>
  • irc.c

    ra830512 r87f525e  
    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 );
     
    10751076                        return( 1 );
    10761077                }
     1078                else if( g_strncasecmp( s + 1, "DCC", 3 ) == 0 )
     1079                {
     1080                        if( u && u->ic && u->ic->acc->prpl->transfer_request )
     1081                        {
     1082                                file_transfer_t *ft = dcc_request( u->ic, s + 5 );
     1083                                if ( ft )
     1084                                        u->ic->acc->prpl->transfer_request( u->ic, ft, u->handle );
     1085                        }
     1086                        return( 1 );
     1087                }               
    10771088                else
    10781089                {
    1079                         irc_usermsg( irc, "Non-ACTION CTCP's aren't supported" );
     1090                        irc_usermsg( irc, "Supported CTCPs are ACTION, VERSION, PING, TYPING, DCC" );
    10801091                        return( 0 );
    10811092                }
  • irc.h

    ra830512 r87f525e  
    8787        struct query *queries;
    8888        struct account *accounts;
     89        GSList *file_transfers;
    8990       
    9091        struct __USER *users;
  • protocols/jabber/Makefile

    ra830512 r87f525e  
    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 sasl.o si.o s5bytestream.o
    1313
    1414CFLAGS += -Wall
  • protocols/jabber/iq.c

    ra830512 r87f525e  
    9090                        pack = 0;
    9191                }
    92                 else if( strcmp( s, XMLNS_DISCOVER ) == 0 )
    93                 {
    94                         const char *features[] = { XMLNS_DISCOVER,
     92                else if( strcmp( s, XMLNS_DISCO_INFO ) == 0 )
     93                {
     94                        const char *features[] = { XMLNS_DISCO_INFO,
    9595                                                   XMLNS_VERSION,
    9696                                                   XMLNS_TIME,
     
    9898                                                   XMLNS_MUC,
    9999                                                   XMLNS_PING,
     100                                                   XMLNS_SI,
     101                                                   XMLNS_BYTESTREAMS,
     102                                                   XMLNS_FILETRANSFER,
    100103                                                   NULL };
    101104                        const char **f;
     
    117120                {
    118121                        xt_free_node( reply );
    119                         reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel" );
     122                        reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel", NULL );
    120123                        pack = 0;
    121124                }
     
    123126        else if( strcmp( type, "set" ) == 0 )
    124127        {
    125                 if( !( c = xt_find_node( node->children, "query" ) ) ||
     128                if(  ( c = xt_find_node( node->children, "si" ) ) &&
     129                     ( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_SI ) == 0 ) )
     130                {
     131                        return jabber_si_handle_request( ic, node, c );
     132                } else if( !( c = xt_find_node( node->children, "query" ) ) ||
    126133                    !( s = xt_find_attr( c, "xmlns" ) ) )
    127134                {
    128135                        imcb_log( ic, "Warning: Received incomplete IQ-%s packet", type );
    129136                        return XT_HANDLED;
    130                 }
    131                
     137                } else if( strcmp( s, XMLNS_ROSTER ) == 0 )
     138                {
    132139                /* This is a roster push. XMPP servers send this when someone
    133140                   was added to (or removed from) the buddy list. AFAIK they're
    134141                   sent even if we added this buddy in our own session. */
    135                 if( strcmp( s, XMLNS_ROSTER ) == 0 )
    136                 {
    137142                        int bare_len = strlen( ic->acc->user );
    138143                       
     
    151156                               
    152157                                xt_free_node( reply );
    153                                 reply = jabber_make_error_packet( node, "not-allowed", "cancel" );
     158                                reply = jabber_make_error_packet( node, "not-allowed", "cancel", NULL );
    154159                                pack = 0;
    155160                        }
    156                 }
    157                 else
     161                } else if( strcmp( s, XMLNS_BYTESTREAMS ) == 0 )
     162                {
     163                        /* Bytestream Request (stage 2 of file transfer) */
     164                        return jabber_bs_recv_request( ic, node, c );
     165                } else
    158166                {
    159167                        xt_free_node( reply );
    160                         reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel" );
     168                        reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel", NULL );
    161169                        pack = 0;
    162170                }
     
    593601        return st;
    594602}
     603
     604xt_status jabber_iq_parse_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
     605
     606xt_status jabber_iq_query_features( struct im_connection *ic, char *bare_jid )
     607{
     608        struct xt_node *node, *query;
     609        struct jabber_buddy *bud;
     610       
     611        if( ( bud = jabber_buddy_by_jid( ic, bare_jid , 0 ) ) == NULL )
     612        {
     613                /* Who cares about the unknown... */
     614                imcb_log( ic, "Couldn't find buddy: %s", bare_jid);
     615                return 0;
     616        }
     617       
     618        if( bud->features ) /* been here already */
     619                return XT_HANDLED;
     620       
     621        node = xt_new_node( "query", NULL, NULL );
     622        xt_add_attr( node, "xmlns", XMLNS_DISCO_INFO );
     623       
     624        if( !( query = jabber_make_packet( "iq", "get", bare_jid, node ) ) )
     625        {
     626                imcb_log( ic, "WARNING: Couldn't generate feature query" );
     627                xt_free_node( node );
     628                return 0;
     629        }
     630
     631        jabber_cache_add( ic, query, jabber_iq_parse_features );
     632
     633        return jabber_write_packet( ic, query );
     634}
     635
     636xt_status jabber_iq_parse_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
     637{
     638        struct xt_node *c;
     639        struct jabber_buddy *bud;
     640        char *feature;
     641
     642        if( !( c = xt_find_node( node->children, "query" ) ) ||
     643            !( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_DISCO_INFO ) == 0 ) )
     644        {
     645                imcb_log( ic, "WARNING: Received incomplete IQ-result packet for discover" );
     646                return XT_HANDLED;
     647        }
     648        if( ( bud = jabber_buddy_by_jid( ic, xt_find_attr( node, "from") , 0 ) ) == NULL )
     649        {
     650                /* Who cares about the unknown... */
     651                imcb_log( ic, "Couldn't find buddy: %s", xt_find_attr( node, "from"));
     652                return 0;
     653        }
     654       
     655        c = c->children;
     656        while( ( c = xt_find_node( c, "feature" ) ) ) {
     657                feature = xt_find_attr( c, "var" );
     658                bud->features = g_slist_append(bud->features, g_strdup(feature) );
     659                c = c->next;
     660        }
     661
     662        return XT_HANDLED;
     663}
     664
     665xt_status jabber_iq_parse_server_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
     666
     667xt_status jabber_iq_query_server( struct im_connection *ic, char *jid, char *xmlns )
     668{
     669        struct xt_node *node, *query;
     670        struct jabber_data *jd = ic->proto_data;
     671       
     672        node = xt_new_node( "query", NULL, NULL );
     673        xt_add_attr( node, "xmlns", xmlns );
     674       
     675        if( !( query = jabber_make_packet( "iq", "get", jid, node ) ) )
     676        {
     677                imcb_log( ic, "WARNING: Couldn't generate server query" );
     678                xt_free_node( node );
     679        }
     680
     681        jd->have_streamhosts--;
     682        jabber_cache_add( ic, query, jabber_iq_parse_server_features );
     683
     684        return jabber_write_packet( ic, query );
     685}
     686
     687/*
     688 * Query the server for "items", query each "item" for identities, query each "item" that's a proxy for it's bytestream info
     689 */
     690xt_status jabber_iq_parse_server_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
     691{
     692        struct xt_node *c;
     693        struct jabber_data *jd = ic->proto_data;
     694
     695        if( !( c = xt_find_node( node->children, "query" ) ) ||
     696            !xt_find_attr( node, "from" ) )
     697        {
     698                imcb_log( ic, "WARNING: Received incomplete IQ-result packet for discover" );
     699                return XT_HANDLED;
     700        }
     701
     702        jd->have_streamhosts++;
     703
     704        if( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_DISCO_ITEMS ) == 0 )
     705        {
     706                char *item, *itemjid;
     707
     708                /* answer from server */
     709       
     710                c = c->children;
     711                while( ( c = xt_find_node( c, "item" ) ) )
     712                {
     713                        item = xt_find_attr( c, "name" );
     714                        itemjid = xt_find_attr( c, "jid" );
     715
     716                        jabber_iq_query_server( ic, itemjid, XMLNS_DISCO_INFO );
     717
     718                        c = c->next;
     719                }
     720        } else if( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_DISCO_INFO ) == 0 )
     721        {
     722                char *category, *type;
     723
     724                /* answer from potential proxy */
     725
     726                c = c->children;
     727                while( ( c = xt_find_node( c, "identity" ) ) )
     728                {
     729                        category = xt_find_attr( c, "category" );
     730                        type = xt_find_attr( c, "type" );
     731
     732                        if( type && ( strcmp( type, "bytestreams" ) == 0 ) &&
     733                            category && ( strcmp( category, "proxy" ) == 0 ) )
     734                                jabber_iq_query_server( ic, xt_find_attr( node, "from" ), XMLNS_BYTESTREAMS );
     735
     736                        c = c->next;
     737                }
     738        } else if( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_BYTESTREAMS ) == 0 )
     739        {
     740                char *host, *jid;
     741                int port;
     742
     743                /* answer from proxy */
     744
     745                if( ( c = xt_find_node( c->children, "streamhost" ) ) &&
     746                    ( host = xt_find_attr( c, "host" ) ) &&
     747                    ( port = atoi( xt_find_attr( c, "port" ) ) ) &&
     748                    ( jid = xt_find_attr( c, "jid" ) ) )
     749                {
     750                        jabber_streamhost_t *sh = g_new0( jabber_streamhost_t, 1 );
     751                        sh->jid = g_strdup( jid );
     752                        sh->host = g_strdup( host );
     753                        sprintf( sh->port, "%u", port );
     754
     755                        imcb_log( ic, "Proxy found: jid %s host %s port %u", jid, host, port );
     756                        jd->streamhosts = g_slist_append( jd->streamhosts, sh );
     757                }
     758        }
     759
     760        if( jd->have_streamhosts == 0 )
     761                jd->have_streamhosts++;
     762        return XT_HANDLED;
     763}
  • protocols/jabber/jabber.c

    ra830512 r87f525e  
    8080        s = set_add( &acc->set, "xmlconsole", "false", set_eval_bool, acc );
    8181        s->flags |= ACC_SET_OFFLINE_ONLY;
     82
     83        s = set_add( &acc->set, "proxy", "<local>;<auto>", NULL, acc );
    8284}
    8385
     
    260262        struct jabber_data *jd = ic->proto_data;
    261263       
     264        while( jd->filetransfers )
     265                imcb_file_canceled( ( ( struct jabber_transfer *) jd->filetransfers->data )->ft, "Logging out" );
     266
     267        while( jd->streamhosts )
     268        {
     269                jabber_streamhost_t *sh = jd->streamhosts->data;
     270                jd->streamhosts = g_slist_remove( jd->streamhosts, sh );
     271                g_free( sh->jid );
     272                g_free( sh->host );
     273                g_free( sh );
     274        }
     275
    262276        if( jd->fd >= 0 )
    263277                jabber_end_stream( ic );
     
    546560        ret->send_typing = jabber_send_typing;
    547561        ret->handle_cmp = g_strcasecmp;
     562        ret->transfer_request = jabber_si_transfer_request;
    548563
    549564        register_protocol( ret );
  • protocols/jabber/jabber.h

    ra830512 r87f525e  
    5959} jabber_buddy_flags_t;
    6060
     61/* Stores a streamhost's(a.k.a. proxy) data */
     62typedef struct
     63{
     64        char *jid;
     65        char *host;
     66        char port[6];
     67} jabber_streamhost_t;
     68
    6169typedef enum
    6270{
     
    8997        GHashTable *node_cache;
    9098        GHashTable *buddies;
     99
     100        GSList *filetransfers;
     101        GSList *streamhosts;
     102        int have_streamhosts;
    91103};
    92104
     
    118130        struct jabber_away_state *away_state;
    119131        char *away_message;
     132        GSList *features;
    120133       
    121134        time_t last_act;
     
    131144        char *my_full_jid; /* Separate copy because of case sensitivity. */
    132145        struct jabber_buddy *me;
     146};
     147
     148struct jabber_transfer
     149{
     150        /* bitlbee's handle for this transfer */
     151        file_transfer_t *ft;
     152
     153        /* the stream's private handle */
     154        gpointer streamhandle;
     155
     156        /* timeout for discover queries */
     157        gint disco_timeout;
     158        gint disco_timeout_fired;
     159
     160        struct im_connection *ic;
     161
     162        struct jabber_buddy *bud;
     163
     164        int watch_in;
     165        int watch_out;
     166
     167        char *ini_jid;
     168        char *tgt_jid;
     169        char *iq_id;
     170        char *sid;
     171        int accepted;
     172
     173        size_t bytesread, byteswritten;
     174        int fd;
     175        struct sockaddr_storage saddr;
    133176};
    134177
     
    158201
    159202/* Some supported extensions/legacy stuff */
    160 #define XMLNS_AUTH         "jabber:iq:auth"                     /* XEP-0078 */
    161 #define XMLNS_VERSION      "jabber:iq:version"                  /* XEP-0092 */
    162 #define XMLNS_TIME         "jabber:iq:time"                     /* XEP-0090 */
    163 #define XMLNS_PING         "urn:xmpp:ping"                      /* XEP-0199 */
    164 #define XMLNS_VCARD        "vcard-temp"                         /* XEP-0054 */
    165 #define XMLNS_DELAY        "jabber:x:delay"                     /* XEP-0091 */
    166 #define XMLNS_CHATSTATES   "http://jabber.org/protocol/chatstates"  /* 0085 */
    167 #define XMLNS_DISCOVER     "http://jabber.org/protocol/disco#info"  /* 0030 */
    168 #define XMLNS_MUC          "http://jabber.org/protocol/muc"     /* XEP-0045 */
    169 #define XMLNS_MUC_USER     "http://jabber.org/protocol/muc#user"/* XEP-0045 */
    170 #define XMLNS_CAPS         "http://jabber.org/protocol/caps"    /* XEP-0115 */
     203#define XMLNS_AUTH         "jabber:iq:auth"                                      /* XEP-0078 */
     204#define XMLNS_VERSION      "jabber:iq:version"                                   /* XEP-0092 */
     205#define XMLNS_TIME         "jabber:iq:time"                                      /* XEP-0090 */
     206#define XMLNS_PING         "urn:xmpp:ping"                                       /* XEP-0199 */
     207#define XMLNS_VCARD        "vcard-temp"                                          /* XEP-0054 */
     208#define XMLNS_DELAY        "jabber:x:delay"                                      /* XEP-0091 */
     209#define XMLNS_XDATA        "jabber:x:data"                                       /* XEP-0004 */
     210#define XMLNS_CHATSTATES   "http://jabber.org/protocol/chatstates"               /* XEP-0085 */
     211#define XMLNS_DISCO_INFO   "http://jabber.org/protocol/disco#info"               /* XEP-0030 */
     212#define XMLNS_DISCO_ITEMS  "http://jabber.org/protocol/disco#items"              /* XEP-0030 */
     213#define XMLNS_MUC          "http://jabber.org/protocol/muc"                      /* XEP-0045 */
     214#define XMLNS_MUC_USER     "http://jabber.org/protocol/muc#user"                 /* XEP-0045 */
     215#define XMLNS_CAPS         "http://jabber.org/protocol/caps"                     /* XEP-0115 */
     216#define XMLNS_FEATURE      "http://jabber.org/protocol/feature-neg"              /* XEP-0020 */
     217#define XMLNS_SI           "http://jabber.org/protocol/si"                       /* XEP-0095 */
     218#define XMLNS_FILETRANSFER "http://jabber.org/protocol/si/profile/file-transfer" /* XEP-0096 */
     219#define XMLNS_BYTESTREAMS  "http://jabber.org/protocol/bytestreams"              /* XEP-0065 */
     220#define XMLNS_IBB          "http://jabber.org/protocol/ibb"                      /* XEP-0047 */
    171221
    172222/* iq.c */
     
    178228int jabber_add_to_roster( struct im_connection *ic, char *handle, char *name );
    179229int jabber_remove_from_roster( struct im_connection *ic, char *handle );
     230xt_status jabber_iq_query_features( struct im_connection *ic, char *bare_jid );
     231xt_status jabber_iq_query_server( struct im_connection *ic, char *jid, char *xmlns );
     232
     233/* si.c */
     234int jabber_si_handle_request( struct im_connection *ic, struct xt_node *node, struct xt_node *sinode );
     235void jabber_si_transfer_request( struct im_connection *ic, file_transfer_t *ft, char *who );
     236void jabber_si_free_transfer( file_transfer_t *ft);
     237
     238/* s5bytestream.c */
     239int jabber_bs_recv_request( struct im_connection *ic, struct xt_node *node, struct xt_node *qnode);
     240gboolean jabber_bs_send_start( struct jabber_transfer *tf );
     241gboolean jabber_bs_send_write( file_transfer_t *ft, char *buffer, unsigned int len );
    180242
    181243/* message.c */
     
    191253char *set_eval_tls( set_t *set, char *value );
    192254struct xt_node *jabber_make_packet( char *name, char *type, char *to, struct xt_node *children );
    193 struct xt_node *jabber_make_error_packet( struct xt_node *orig, char *err_cond, char *err_type );
     255struct xt_node *jabber_make_error_packet( struct xt_node *orig, char *err_cond, char *err_type, char *err_code );
    194256void jabber_cache_add( struct im_connection *ic, struct xt_node *node, jabber_cache_event func );
    195257struct xt_node *jabber_cache_get( struct im_connection *ic, char *id );
  • protocols/jabber/jabber_util.c

    ra830512 r87f525e  
    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/nogaim.h

    ra830512 r87f525e  
    4444#include "query.h"
    4545#include "md5.h"
     46#include "ft.h"
    4647
    4748#define BUDDY_ALIAS_MAXLEN 388   /* because MSN names can be 387 characters */
     
    224225         * - Most protocols will just want to set this to g_strcasecmp().*/
    225226        int (* handle_cmp) (const char *who1, const char *who2);
     227
     228        /* Incoming transfer request */
     229        void (* transfer_request) (struct im_connection *, file_transfer_t *ft, char *handle );
    226230};
    227231
  • root_commands.c

    ra830512 r87f525e  
    10411041                irc_usermsg( irc, "Tried to join chat, not sure if this was successful" );
    10421042                g_free( channel );
     1043        }
     1044}
     1045
     1046static void cmd_transfers( irc_t *irc, char **cmd )
     1047{
     1048        GSList *files = irc->file_transfers;
     1049        enum { LIST, REJECT, CANCEL };
     1050        int subcmd = LIST;
     1051        int fid;
     1052
     1053        if( !files )
     1054        {
     1055                irc_usermsg( irc, "No pending transfers" );
     1056                return;
     1057        }
     1058
     1059        if( cmd[1] &&
     1060            ( strcmp( cmd[1], "reject" ) == 0 ) )
     1061        {
     1062                subcmd = REJECT;
     1063        }
     1064        else if( cmd[1] &&
     1065                 ( strcmp( cmd[1], "cancel" ) == 0 ) &&
     1066                 cmd[2] &&
     1067                 ( fid = atoi( cmd[2] ) ) )
     1068        {
     1069                subcmd = CANCEL;
     1070        }
     1071
     1072        for( ; files; files = g_slist_next( files ) )
     1073        {
     1074                file_transfer_t *file = files->data;
     1075               
     1076                switch( subcmd ) {
     1077                case LIST:
     1078                        if ( file->status == FT_STATUS_LISTENING )
     1079                                irc_usermsg( irc,
     1080                                        "Pending file(id %d): %s (Listening...)", file->local_id, file->file_name);
     1081                        else
     1082                        {
     1083                                int kb_per_s = 0;
     1084                                time_t diff = time( NULL ) - file->started ? : 1;
     1085                                if ( ( file->started > 0 ) && ( file->bytes_transferred > 0 ) )
     1086                                        kb_per_s = file->bytes_transferred / 1024 / diff;
     1087                                       
     1088                                irc_usermsg( irc,
     1089                                        "Pending file(id %d): %s (%10zd/%zd kb, %d kb/s)", file->local_id, file->file_name,
     1090                                        file->bytes_transferred/1024, file->file_size/1024, kb_per_s);
     1091                        }
     1092                        break;
     1093                case REJECT:
     1094                        if( file->status == FT_STATUS_LISTENING )
     1095                        {
     1096                                irc_usermsg( irc, "Rejecting file transfer for %s", file->file_name );
     1097                                imcb_file_canceled( file, "Denied by user" );
     1098                        }
     1099                        break;
     1100                case CANCEL:
     1101                        if( file->local_id == fid )
     1102                        {
     1103                                irc_usermsg( irc, "Canceling file transfer for %s", file->file_name );
     1104                                imcb_file_canceled( file, "Canceled by user" );
     1105                        }
     1106                        break;
     1107                }
    10431108        }
    10441109}
     
    10641129        { "qlist",          0, cmd_qlist,          0 },
    10651130        { "join_chat",      2, cmd_join_chat,      0 },
     1131        { "transfers",      0, cmd_transfers,      0 },
    10661132        { NULL }
    10671133};
Note: See TracChangeset for help on using the changeset viewer.