Changes in / [793cc25:0fbd3a6d]


Ignore:
Files:
23 edited

Legend:

Unmodified
Added
Removed
  • account.c

    r793cc25 r0fbd3a6d  
    9595                g_free( acc->server );
    9696                if( *value )
     97                {
    9798                        acc->server = g_strdup( value );
     99                        return value;
     100                }
    98101                else
     102                {
    99103                        acc->server = NULL;
    100                 return value;
     104                        return g_strdup( set->def );
     105                }
    101106        }
    102107        else if( strcmp( set->key, "auto_connect" ) == 0 )
  • dcc.c

    r793cc25 r0fbd3a6d  
    125125        file = df->ft;
    126126        file->write = dccs_send_write;
    127         file->sending = TRUE;
    128127
    129128        /* listen and request */
  • doc/CREDITS

    r793cc25 r0fbd3a6d  
    5555- Greg (gropeep.org), for updating the Yahoo! module to fix some issues
    5656  that were there for quite some time already.
     57- misc@mandriva.org for lots of Jabber contributions.
    5758
    5859- And all other users who help us by sending useful bug reports, positive
  • doc/user-guide/commands.xml

    r793cc25 r0fbd3a6d  
    1717
    1818                <bitlbee-command name="add">
    19                         <syntax>account add &lt;protocol&gt; &lt;username&gt; &lt;password&gt; [&lt;server&gt;]</syntax>
     19                        <syntax>account add &lt;protocol&gt; &lt;username&gt; &lt;password&gt;</syntax>
    2020
    2121                        <description>
     
    2626                       
    2727                        <bitlbee-command name="jabber">
    28                                 <syntax>account add jabber &lt;handle@server.tld&gt; &lt;password&gt; [&lt;servertag&gt;]</syntax>
     28                                <syntax>account add jabber &lt;handle@server.tld&gt; &lt;password&gt;</syntax>
    2929
    3030                                <description>
     
    5050                       
    5151                        <bitlbee-command name="oscar">
    52                                 <syntax>account add oscar &lt;handle&gt; &lt;password&gt; [&lt;servername&gt;]</syntax>
     52                                <syntax>account add oscar &lt;handle&gt; &lt;password&gt;</syntax>
    5353
    5454                                <description>
    5555                                        <para>
    56                                                 Specifying a server is required for OSCAR, since OSCAR can be used for both ICQ- and AIM-connections. Although these days it's supposed to be possible to connect to ICQ via AIM-servers and vice versa, we like to stick with this separation for now. For ICQ connections, the servername is <emphasis>login.icq.com</emphasis>, for AIM connections it's <emphasis>login.oscar.aol.com</emphasis>.
     56                                                OSCAR is the protocol used to connect to AIM and/or ICQ. The servers will automatically detect if you're using a numeric or non-numeric username so there's no need to tell which network you want to connect to.
    5757                                        </para>
    5858                                </description>
    5959
    6060                                <ircexample>
    61                                         <ircline nick="wilmer">account add oscar 72696705 hobbelmeeuw login.icq.com</ircline>
     61                                        <ircline nick="wilmer">account add oscar 72696705 hobbelmeeuw</ircline>
    6262                                        <ircline nick="root">Account successfully added</ircline>
    6363                                </ircexample>
     
    595595                <description>
    596596                        <para>
    597                                 Can be set for Jabber- and OSCAR-connections. For OSCAR, this must be set to <emphasis>login.icq.com</emphasis> if it's an ICQ connection, or <emphasis>login.oscar.aol.com</emphasis> if it's an AIM connection. For Jabber, you have to set this if the servername isn't equal to the part after the @ in the Jabber handle.
     597                                Can be set for Jabber- and OSCAR-connections. For Jabber, you might have to set this if the servername isn't equal to the part after the @ in the Jabber handle. For OSCAR this shouldn't be necessary anymore in recent BitlBee versions.
    598598                        </para>
    599599                </description>
  • doc/user-guide/quickstart.xml

    r793cc25 r0fbd3a6d  
    3838
    3939<ircexample>
    40         <ircline nick="you">account add oscar 72696705 QuickStart login.icq.com</ircline>
     40        <ircline nick="you">account add jabber bitlbee@jabber.org QuickStart</ircline>
    4141        <ircline nick="root">Account successfully added</ircline>
    4242</ircexample>
    4343
    4444<para>
    45 Other available IM protocols are jabber, msn, and yahoo. Oscar is the protocol used by ICQ and AOL. For oscar, you need to specify the IM-server as a fourth argument (for msn and yahoo there is no fourth argument). For AOL Instant Messenger, the server name is <emphasis>login.oscar.aol.com</emphasis>. For ICQ, the server name is <emphasis>login.icq.com</emphasis>.
     45Other available IM protocols are msn, oscar, and yahoo. Oscar is the protocol used by ICQ and AOL.
    4646</para>
    4747
  • irc_commands.c

    r793cc25 r0fbd3a6d  
    207207                if( c->ic && c->ic->acc->prpl->chat_invite )
    208208                {
    209                         c->ic->acc->prpl->chat_invite( c, "", u->handle );
     209                        c->ic->acc->prpl->chat_invite( c, u->handle, NULL );
    210210                        irc_reply( irc, 341, "%s %s", nick, channel );
    211211                        return;
  • lib/misc.c

    r793cc25 r0fbd3a6d  
    4444#include <resolv.h>
    4545#endif
     46
     47#include "ssl_client.h"
    4648
    4749void strip_linefeed(gchar *text)
     
    591593        return g_string_free( ret, FALSE );
    592594}
     595
     596gboolean ssl_sockerr_again( void *ssl )
     597{
     598        if( ssl )
     599                return ssl_errno == SSL_AGAIN;
     600        else
     601                return sockerr_again();
     602}
  • lib/misc.h

    r793cc25 r0fbd3a6d  
    6666G_MODULE_EXPORT char *word_wrap( char *msg, int line_len );
    6767
     68G_MODULE_EXPORT gboolean ssl_sockerr_again( void *ssl );
     69
    6870#endif
  • lib/ssl_gnutls.c

    r793cc25 r0fbd3a6d  
    223223        closesocket( conn->fd );
    224224       
    225         gnutls_deinit( conn->session );
    226         gnutls_certificate_free_credentials( conn->xcred );
     225        if( conn->session )
     226                gnutls_deinit( conn->session );
     227        if( conn->xcred )
     228                gnutls_certificate_free_credentials( conn->xcred );
    227229        g_free( conn );
    228230}
  • nick.c

    r793cc25 r0fbd3a6d  
    154154   With one difference, we allow dashes. */
    155155
    156 static char *nick_lc_chars = "0123456789abcdefghijklmnopqrstuvwxyz{}^-_|";
    157 static char *nick_uc_chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ[]~-_\\";
    158 
    159 void nick_strip( char * nick )
     156static char *nick_lc_chars = "0123456789abcdefghijklmnopqrstuvwxyz{}^`-_|";
     157static char *nick_uc_chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ[]~`-_\\";
     158
     159void nick_strip( char *nick )
    160160{
    161161        int i, j;
     
    170170                }
    171171        }
     172        if( isdigit( nick[0] ) )
     173        {
     174                char *orig;
     175               
     176                orig = g_strdup( nick );
     177                g_snprintf( nick, MAX_NICK_LENGTH, "_%s", orig );
     178                g_free( orig );
     179                j ++;
     180        }
    172181        while( j <= MAX_NICK_LENGTH )
    173182                nick[j++] = '\0';
     
    178187        const char *s;
    179188       
    180         /* Empty/long nicks are not allowed */
    181         if( !*nick || strlen( nick ) > MAX_NICK_LENGTH )
     189        /* Empty/long nicks are not allowed, nor numbers at [0] */
     190        if( !*nick || isdigit( nick[0] ) || strlen( nick ) > MAX_NICK_LENGTH )
    182191                return( 0 );
    183192       
  • protocols/jabber/conference.c

    r793cc25 r0fbd3a6d  
    174174       
    175175        return 1;
     176}
     177
     178void jabber_chat_invite( struct groupchat *c, char *who, char *message )
     179{
     180        struct xt_node *node;
     181        struct im_connection *ic = c->ic;
     182        struct jabber_chat *jc = c->data;
     183
     184        node = xt_new_node( "reason", message, NULL );
     185
     186        node = xt_new_node( "invite", NULL, node );
     187        xt_add_attr( node, "to", who );
     188
     189        node = xt_new_node( "x", NULL, node );
     190        xt_add_attr( node, "xmlns", XMLNS_MUC_USER );
     191       
     192        node = jabber_make_packet( "message", NULL, jc->name, node );
     193
     194        jabber_write_packet( ic, node );
     195
     196        xt_free_node( node );
    176197}
    177198
  • protocols/jabber/io.c

    r793cc25 r0fbd3a6d  
    120120                return TRUE;
    121121        }
    122         else if( st == 0 || ( st < 0 && !sockerr_again() ) )
     122        else if( st == 0 || ( st < 0 && !ssl_sockerr_again( jd->ssl ) ) )
    123123        {
    124124                /* Set fd to -1 to make sure we won't write to it anymore. */
     
    231231                }
    232232        }
    233         else if( st == 0 || ( st < 0 && !sockerr_again() ) )
     233        else if( st == 0 || ( st < 0 && !ssl_sockerr_again( jd->ssl ) ) )
    234234        {
    235235                closesocket( jd->fd );
  • protocols/jabber/iq.c

    r793cc25 r0fbd3a6d  
    5050        else if( strcmp( type, "get" ) == 0 )
    5151        {
    52                 if( !( c = xt_find_node( node->children, "query" ) ) ||
     52                if( !( ( c = xt_find_node( node->children, "query" ) ) ||
     53                       ( c = xt_find_node( node->children, "ping" ) ) ) || /* O_o WHAT is wrong with just <query/> ????? */
    5354                    !( s = xt_find_attr( c, "xmlns" ) ) )
    5455                {
     
    8182                        xt_add_child( reply, xt_new_node( "tz", buf, NULL ) );
    8283                }
    83                 else if( strcmp( s, XMLNS_DISCOVER ) == 0 )
     84                else if( strcmp( s, XMLNS_PING ) == 0 )
     85                {
     86                        xt_free_node( reply );
     87                        reply = jabber_make_packet( "iq", "result", xt_find_attr( node, "from" ), NULL );
     88                        if( ( s = xt_find_attr( node, "id" ) ) )
     89                                xt_add_attr( reply, "id", s );
     90                        pack = 0;
     91                }
     92                else if( strcmp( s, XMLNS_DISCO_INFO ) == 0 )
    8493                {
    8594                        const char *features[] = { XMLNS_VERSION,
     
    8796                                                   XMLNS_CHATSTATES,
    8897                                                   XMLNS_MUC,
     98                                                   XMLNS_PING,
    8999                                                   XMLNS_SI,
    90100                                                   XMLNS_BYTESTREAMS,
     
    565575        return st;
    566576}
     577
     578xt_status jabber_iq_parse_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
     579
     580xt_status jabber_iq_query_features( struct im_connection *ic, char *bare_jid )
     581{
     582        struct xt_node *node, *query;
     583        struct jabber_buddy *bud;
     584       
     585        if( ( bud = jabber_buddy_by_jid( ic, bare_jid , 0 ) ) == NULL )
     586        {
     587                /* Who cares about the unknown... */
     588                imcb_log( ic, "Couldnt find the man: %s", bare_jid);
     589                return 0;
     590        }
     591       
     592        if( bud->features ) /* been here already */
     593                return XT_HANDLED;
     594       
     595        node = xt_new_node( "query", NULL, NULL );
     596        xt_add_attr( node, "xmlns", XMLNS_DISCO_INFO );
     597       
     598        if( !( query = jabber_make_packet( "iq", "get", bare_jid, node ) ) )
     599        {
     600                imcb_log( ic, "WARNING: Couldn't generate feature query" );
     601                xt_free_node( node );
     602        }
     603
     604        jabber_cache_add( ic, query, jabber_iq_parse_features );
     605
     606        return jabber_write_packet( ic, query );
     607}
     608
     609xt_status jabber_iq_parse_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
     610{
     611        struct xt_node *c;
     612        struct jabber_buddy *bud;
     613        char *feature;
     614
     615        if( !( c = xt_find_node( node->children, "query" ) ) ||
     616            !( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_DISCO_INFO ) == 0 ) )
     617        {
     618                imcb_log( ic, "WARNING: Received incomplete IQ-result packet for discover" );
     619                return XT_HANDLED;
     620        }
     621        if( ( bud = jabber_buddy_by_jid( ic, xt_find_attr( node, "from") , 0 ) ) == NULL )
     622        {
     623                /* Who cares about the unknown... */
     624                imcb_log( ic, "Couldnt find the man: %s", xt_find_attr( node, "from"));
     625                return 0;
     626        }
     627       
     628        c = c->children;
     629        while( ( c = xt_find_node( c, "feature" ) ) ) {
     630                feature = xt_find_attr( c, "var" );
     631                bud->features = g_slist_append(bud->features, g_strdup(feature) );
     632                c = c->next;
     633        }
     634
     635        return XT_HANDLED;
     636}
     637
     638xt_status jabber_iq_parse_server_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
     639
     640xt_status jabber_iq_query_server( struct im_connection *ic, char *jid, char *xmlns )
     641{
     642        struct xt_node *node, *query;
     643        struct jabber_data *jd = ic->proto_data;
     644       
     645        node = xt_new_node( "query", NULL, NULL );
     646        xt_add_attr( node, "xmlns", xmlns );
     647       
     648        if( !( query = jabber_make_packet( "iq", "get", jid, node ) ) )
     649        {
     650                imcb_log( ic, "WARNING: Couldn't generate server query" );
     651                xt_free_node( node );
     652        }
     653
     654        jd->have_streamhosts--;
     655        jabber_cache_add( ic, query, jabber_iq_parse_server_features );
     656
     657        return jabber_write_packet( ic, query );
     658}
     659
     660/*
     661 * Query the server for "items", query each "item" for identities, query each "item" that's a proxy for it's bytestream info
     662 */
     663xt_status jabber_iq_parse_server_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
     664{
     665        struct xt_node *c;
     666        struct jabber_data *jd = ic->proto_data;
     667
     668        if( !( c = xt_find_node( node->children, "query" ) ) ||
     669            !xt_find_attr( node, "from" ) )
     670        {
     671                imcb_log( ic, "WARNING: Received incomplete IQ-result packet for discover" );
     672                return XT_HANDLED;
     673        }
     674
     675        jd->have_streamhosts++;
     676
     677        if( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_DISCO_ITEMS ) == 0 )
     678        {
     679                char *item, *itemjid;
     680
     681                /* answer from server */
     682       
     683                c = c->children;
     684                while( ( c = xt_find_node( c, "item" ) ) )
     685                {
     686                        item = xt_find_attr( c, "name" );
     687                        itemjid = xt_find_attr( c, "jid" );
     688
     689                        jabber_iq_query_server( ic, itemjid, XMLNS_DISCO_INFO );
     690
     691                        c = c->next;
     692                }
     693        } else if( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_DISCO_INFO ) == 0 )
     694        {
     695                char *category, *type;
     696
     697                /* answer from potential proxy */
     698
     699                c = c->children;
     700                while( ( c = xt_find_node( c, "identity" ) ) )
     701                {
     702                        category = xt_find_attr( c, "category" );
     703                        type = xt_find_attr( c, "type" );
     704
     705                        if( type && ( strcmp( type, "bytestreams" ) == 0 ) &&
     706                            category && ( strcmp( category, "proxy" ) == 0 ) )
     707                                jabber_iq_query_server( ic, xt_find_attr( node, "from" ), XMLNS_BYTESTREAMS );
     708
     709                        c = c->next;
     710                }
     711        } else if( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_BYTESTREAMS ) == 0 )
     712        {
     713                char *host, *jid;
     714                int port;
     715
     716                /* answer from proxy */
     717
     718                if( ( c = xt_find_node( c->children, "streamhost" ) ) &&
     719                    ( host = xt_find_attr( c, "host" ) ) &&
     720                    ( port = atoi( xt_find_attr( c, "port" ) ) ) &&
     721                    ( jid = xt_find_attr( c, "jid" ) ) )
     722                {
     723                        jabber_streamhost_t *sh = g_new0( jabber_streamhost_t, 1 );
     724                        sh->jid = g_strdup( jid );
     725                        sh->host = g_strdup( host );
     726                        sprintf( sh->port, "%u", port );
     727
     728                        imcb_log( ic, "Proxy found: jid %s host %s port %u", jid, host, port );
     729                        jd->streamhosts = g_slist_append( jd->streamhosts, sh );
     730                }
     731        }
     732
     733        if( jd->have_streamhosts == 0 )
     734                jd->have_streamhosts++;
     735        return XT_HANDLED;
     736}
  • protocols/jabber/jabber.c

    r793cc25 r0fbd3a6d  
    7676        jd->username = g_strdup( acc->user );
    7777        jd->server = strchr( jd->username, '@' );
     78       
     79        jd->fd = jd->r_inpa = jd->w_inpa = -1;
    7880       
    7981        if( jd->server == NULL )
     
    232234        struct jabber_data *jd = ic->proto_data;
    233235       
    234         jabber_end_stream( ic );
     236        if( jd->fd >= 0 )
     237                jabber_end_stream( ic );
    235238       
    236239        while( ic->groupchats )
     
    250253                g_free( jd->txq );
    251254       
    252         g_hash_table_destroy( jd->node_cache );
     255        if( jd->node_cache )
     256                g_hash_table_destroy( jd->node_cache );
    253257       
    254258        xt_free( jd->xt );
     
    421425        if( c )
    422426                jabber_chat_leave( c, NULL );
     427}
     428
     429static void jabber_chat_invite_( struct groupchat *c, char *who, char *msg )
     430{
     431        struct jabber_chat *jc = c->data;
     432        gchar *msg_alt = NULL;
     433
     434        if( msg == NULL )
     435                msg_alt = g_strdup_printf( "%s invited you to %s", c->ic->acc->user, jc->name );
     436       
     437        if( c && who )
     438                jabber_chat_invite( c, who, msg ? msg : msg_alt );
     439       
     440        g_free( msg_alt );
    423441}
    424442
     
    494512        ret->chat_msg = jabber_chat_msg_;
    495513        ret->chat_topic = jabber_chat_topic_;
    496 //      ret->chat_invite = jabber_chat_invite;
     514        ret->chat_invite = jabber_chat_invite_;
    497515        ret->chat_leave = jabber_chat_leave_;
    498516        ret->chat_join = jabber_chat_join_;
  • protocols/jabber/jabber.h

    r793cc25 r0fbd3a6d  
    5757} jabber_buddy_flags_t;
    5858
     59/* Stores a streamhost's(a.k.a. proxy) data */
     60typedef struct
     61{
     62        char *jid;
     63        char *host;
     64        char port[6];
     65} jabber_streamhost_t;
     66
    5967struct jabber_data
    6068{
     
    8391
    8492        GSList *filetransfers;
     93        GSList *streamhosts;
     94        int have_streamhosts;
    8595};
    8696
     
    111121        struct jabber_away_state *away_state;
    112122        char *away_message;
     123        GSList *features;
    113124       
    114125        time_t last_act;
     
    178189#define XMLNS_VERSION      "jabber:iq:version"                                   /* XEP-0092 */
    179190#define XMLNS_TIME         "jabber:iq:time"                                      /* XEP-0090 */
     191#define XMLNS_PING         "urn:xmpp:ping"                                       /* XEP-0199 */
    180192#define XMLNS_VCARD        "vcard-temp"                                          /* XEP-0054 */
    181193#define XMLNS_DELAY        "jabber:x:delay"                                      /* XEP-0091 */
    182194#define XMLNS_XDATA        "jabber:x:data"                                       /* XEP-0004 */
    183195#define XMLNS_CHATSTATES   "http://jabber.org/protocol/chatstates"               /* XEP-0085 */
    184 #define XMLNS_DISCOVER     "http://jabber.org/protocol/disco#info"               /* XEP-0030 */
     196#define XMLNS_DISCO_INFO   "http://jabber.org/protocol/disco#info"               /* XEP-0030 */
     197#define XMLNS_DISCO_ITEMS  "http://jabber.org/protocol/disco#items"              /* XEP-0030 */
    185198#define XMLNS_MUC          "http://jabber.org/protocol/muc"                      /* XEP-0045 */
    186199#define XMLNS_MUC_USER     "http://jabber.org/protocol/muc#user"                 /* XEP-0045 */
     
    199212int jabber_add_to_roster( struct im_connection *ic, char *handle, char *name );
    200213int jabber_remove_from_roster( struct im_connection *ic, char *handle );
     214xt_status jabber_iq_query_features( struct im_connection *ic, char *bare_jid );
     215xt_status jabber_iq_query_server( struct im_connection *ic, char *jid, char *xmlns );
    201216
    202217/* si.c */
     
    279294void jabber_chat_pkt_presence( struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node );
    280295void jabber_chat_pkt_message( struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node );
     296void jabber_chat_invite( struct groupchat *c, char *who, char *message );
    281297
    282298#endif
  • protocols/jabber/s5bytestream.c

    r793cc25 r0fbd3a6d  
    3030        struct jabber_transfer *tf;
    3131
    32         /* <query> element and <streamhost> elements */
    33         struct xt_node *qnode, *shnode;
     32        jabber_streamhost_t *sh;
     33        GSList *streamhosts;
    3434
    3535        enum
     
    7474gboolean jabber_bs_abort( struct bs_transfer *bt, char *format, ... );
    7575void jabber_bs_canceled( file_transfer_t *ft , char *reason );
    76 void jabber_bs_free_transfer( file_transfer_t *ft);
     76void jabber_bs_free_transfer( file_transfer_t *ft );
    7777gboolean jabber_bs_connect_timeout( gpointer data, gint fd, b_input_condition cond );
    7878gboolean jabber_bs_poll( struct bs_transfer *bt, int fd, short *revents );
     
    8484gboolean jabber_bs_recv_handshake( gpointer data, gint fd, b_input_condition cond );
    8585gboolean jabber_bs_recv_handshake_abort( struct bs_transfer *bt, char *error );
    86 int jabber_bs_recv_request( struct im_connection *ic, struct xt_node *node, struct xt_node *qnode);
     86int jabber_bs_recv_request( struct im_connection *ic, struct xt_node *node, struct xt_node *qnode );
    8787
    8888gboolean jabber_bs_send_handshake_abort( struct bs_transfer *bt, char *error );
    89 gboolean jabber_bs_send_request( struct jabber_transfer *tf, char *host, char *port );
     89gboolean jabber_bs_send_request( struct jabber_transfer *tf, GSList *streamhosts );
    9090gboolean jabber_bs_send_handshake( gpointer data, gint fd, b_input_condition cond );
    9191gboolean jabber_bs_send_listen( struct bs_transfer *bt, struct sockaddr_storage *saddr, char *host, char *port );
     92static xt_status jabber_bs_send_handle_activate( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
     93void jabber_bs_send_activate( struct bs_transfer *bt );
    9294
    9395/*
     
    9799        struct jabber_transfer *tf = ft->data;
    98100        struct bs_transfer *bt = tf->streamhandle;
     101        jabber_streamhost_t *sh;
    99102
    100103        if ( tf->watch_in )
     
    105108       
    106109        g_free( bt->pseudoadr );
    107         xt_free_node( bt->qnode );
     110
     111        while( bt->streamhosts )
     112        {
     113                sh = bt->streamhosts->data;
     114                bt->streamhosts = g_slist_remove( bt->streamhosts, sh );
     115                g_free( sh->jid );
     116                g_free( sh->host );
     117                g_free( sh );
     118        }
     119       
    108120        g_free( bt );
    109121
     
    111123}
    112124
     125/*
     126 * Checks if buflen data is available on the socket and
     127 * writes it to buffer if that's the case.
     128 */
    113129gboolean jabber_bs_peek( struct bs_transfer *bt, void *buffer, int buflen )
    114130{
     
    147163}
    148164
     165/*
     166 * Polls the socket, checks for errors and removes a connect timer
     167 * if there is one.
     168 */
    149169gboolean jabber_bs_poll( struct bs_transfer *bt, int fd, short *revents )
    150170{
     
    181201}
    182202
     203/*
     204 * Used for receive and send path.
     205 */
    183206gboolean jabber_bs_abort( struct bs_transfer *bt, char *format, ... )
    184207{
     
    191214        va_end( params );
    192215        if( bt->tf->ft->sending )
     216                return jabber_bs_send_handshake_abort( bt, error );
     217        else
    193218                return jabber_bs_recv_handshake_abort( bt, error );
    194         else
    195                 return jabber_bs_send_handshake_abort( bt, error );
    196219}
    197220
     
    214237        GSList *tflist;
    215238        struct bs_transfer *bt;
     239        GSList *shlist=NULL;
     240        struct xt_node *shnode;
    216241
    217242        sha1_state_t sha;
     
    233258        {
    234259                imcb_log( ic, "WARNING: Received SI Request for unsupported bytestream mode %s", xt_find_attr( qnode, "mode" ) );
     260                return XT_HANDLED;
     261        }
     262
     263        shnode = qnode->children;
     264        while( ( shnode = xt_find_node( shnode, "streamhost" ) ) )
     265        {
     266                char *jid, *host;
     267                int port;
     268                if( ( jid = xt_find_attr( shnode, "jid" ) ) &&
     269                    ( host = xt_find_attr( shnode, "host" ) ) &&
     270                    ( ( port = atoi( xt_find_attr( shnode, "port" ) ) ) ) )
     271                {
     272                        jabber_streamhost_t *sh = g_new0( jabber_streamhost_t, 1 );
     273                        sh->jid = g_strdup(jid);
     274                        sh->host = g_strdup(host);
     275                        sprintf( sh->port, "%u", port );
     276                        shlist = g_slist_append( shlist, sh );
     277                }
     278                shnode = shnode->next;
     279        }
     280       
     281        if( !shlist )
     282        {
     283                imcb_log( ic, "WARNING: Received incomplete SI bytestream request, no parseable streamhost entries");
    235284                return XT_HANDLED;
    236285        }
     
    274323        bt = g_new0( struct bs_transfer, 1 );
    275324        bt->tf = tf;
    276         bt->qnode = xt_dup( qnode );
    277         bt->shnode = bt->qnode->children;
     325        bt->streamhosts = shlist;
     326        bt->sh = shlist->data;
    278327        bt->phase = BS_PHASE_CONNECT;
    279328        bt->pseudoadr = g_strdup( hash_hex );
     
    285334        return XT_HANDLED;
    286335}
     336
    287337/*
    288338 * This is what a protocol handshake can look like in cooperative multitasking :)
     
    305355        case BS_PHASE_CONNECT:
    306356                {
    307                         struct xt_node *c;
    308                         char *host, *port;
    309357                        struct addrinfo hints, *rp;
    310358
    311                         if( ( c = bt->shnode = xt_find_node( bt->shnode, "streamhost" ) ) &&
    312                             ( port = xt_find_attr( c, "port" ) ) &&
    313                             ( host = xt_find_attr( c, "host" ) ) &&
    314                             xt_find_attr( c, "jid" ) )
    315                         {
    316                                 memset( &hints, 0, sizeof( struct addrinfo ) );
    317                                 hints.ai_socktype = SOCK_STREAM;
    318 
    319                                 if ( getaddrinfo( host, port, &hints, &rp ) != 0 )
    320                                         return jabber_bs_abort( bt, "getaddrinfo() failed: %s", strerror( errno ) );
    321 
    322                                 ASSERTSOCKOP( bt->tf->fd = fd = socket( rp->ai_family, rp->ai_socktype, 0 ), "Opening socket" );
    323 
    324                                 sock_make_nonblocking( fd );
    325 
    326                                 imcb_log( bt->tf->ic, "File %s: Connecting to streamhost %s:%s", bt->tf->ft->file_name, host, port );
    327 
    328                                 if( ( connect( fd, rp->ai_addr, rp->ai_addrlen ) == -1 ) &&
    329                                     ( errno != EINPROGRESS ) )
    330                                         return jabber_bs_abort( bt , "connect() failed: %s", strerror( errno ) );
    331 
    332                                 freeaddrinfo( rp );
    333 
    334                                 bt->phase = BS_PHASE_CONNECTED;
    335                                
    336                                 bt->tf->watch_out = b_input_add( fd, GAIM_INPUT_WRITE, jabber_bs_recv_handshake, bt );
    337 
    338                                 /* since it takes forever(3mins?) till connect() fails on itself we schedule a timeout */
    339                                 bt->connect_timeout = b_timeout_add( JABBER_BS_CONTIMEOUT * 1000, jabber_bs_connect_timeout, bt );
    340 
    341                                 bt->tf->watch_in = 0;
    342                                 return FALSE;
    343                         } else
    344                                 return jabber_bs_abort( bt, c ? "incomplete streamhost entry: host=%s port=%s jid=%s" : NULL,
    345                                                                   host, port, xt_find_attr( c, "jid" ) );
     359                        memset( &hints, 0, sizeof( struct addrinfo ) );
     360                        hints.ai_socktype = SOCK_STREAM;
     361
     362                        if ( getaddrinfo( bt->sh->host, bt->sh->port, &hints, &rp ) != 0 )
     363                                return jabber_bs_abort( bt, "getaddrinfo() failed: %s", strerror( errno ) );
     364
     365                        ASSERTSOCKOP( bt->tf->fd = fd = socket( rp->ai_family, rp->ai_socktype, 0 ), "Opening socket" );
     366
     367                        sock_make_nonblocking( fd );
     368
     369                        imcb_log( bt->tf->ic, "File %s: Connecting to streamhost %s:%s", bt->tf->ft->file_name, bt->sh->host, bt->sh->port );
     370
     371                        if( ( connect( fd, rp->ai_addr, rp->ai_addrlen ) == -1 ) &&
     372                            ( errno != EINPROGRESS ) )
     373                                return jabber_bs_abort( bt , "connect() failed: %s", strerror( errno ) );
     374
     375                        freeaddrinfo( rp );
     376
     377                        bt->phase = BS_PHASE_CONNECTED;
     378                       
     379                        bt->tf->watch_out = b_input_add( fd, GAIM_INPUT_WRITE, jabber_bs_recv_handshake, bt );
     380
     381                        /* since it takes forever(3mins?) till connect() fails on itself we schedule a timeout */
     382                        bt->connect_timeout = b_timeout_add( JABBER_BS_CONTIMEOUT * 1000, jabber_bs_connect_timeout, bt );
     383
     384                        bt->tf->watch_in = 0;
     385                        return FALSE;
    346386                }
    347387        case BS_PHASE_CONNECTED:
     
    422462                                        socks5_reply.addrlen);
    423463
    424                         jabber_bs_recv_answer_request( bt );
     464                        if( bt->tf->ft->sending )
     465                                jabber_bs_send_activate( bt );
     466                        else
     467                                jabber_bs_recv_answer_request( bt );
    425468
    426469                        return FALSE;
     
    447490        struct jabber_transfer *tf = bt->tf;
    448491        struct xt_node *reply, *iqnode;
    449 
    450         if( bt->shnode )
    451         {
    452                 imcb_log( tf->ic, "Transferring file %s: connection to streamhost %s:%s failed (%s)",
    453                           tf->ft->file_name,
    454                           xt_find_attr( bt->shnode, "host" ),
    455                           xt_find_attr( bt->shnode, "port" ),
    456                           error );
    457 
    458                 /* Alright, this streamhost failed, let's try the next... */
    459                 bt->phase = BS_PHASE_CONNECT;
    460                 bt->shnode = bt->shnode->next;
    461                
    462                 /* the if is not neccessary but saves us one recursion */
    463                 if( bt->shnode )
    464                         return jabber_bs_recv_handshake( bt, 0, 0 );
    465         }
     492        GSList *shlist;
     493
     494        imcb_log( tf->ic, "Transferring file %s: connection to streamhost %s:%s failed (%s)",
     495                  tf->ft->file_name,
     496                  bt->sh->host,
     497                  bt->sh->port,
     498                  error );
     499
     500        /* Alright, this streamhost failed, let's try the next... */
     501        bt->phase = BS_PHASE_CONNECT;
     502        shlist = g_slist_find( bt->streamhosts, bt->sh );
     503        if( shlist && shlist->next )
     504        {
     505                bt->sh = shlist->next->data;
     506                return jabber_bs_recv_handshake( bt, 0, 0 );
     507        }
     508
    466509
    467510        /* out of stream hosts */
     
    495538        imcb_log( tf->ic, "File %s: established SOCKS5 connection to %s:%s",
    496539                  tf->ft->file_name,
    497                   xt_find_attr( bt->shnode, "host" ),
    498                   xt_find_attr( bt->shnode, "port" ) );
     540                  bt->sh->host,
     541                  bt->sh->port );
    499542
    500543        tf->ft->data = tf;
    501         tf->ft->started = time( NULL );
    502544        tf->watch_in = b_input_add( tf->fd, GAIM_INPUT_READ, jabber_bs_recv_read, bt );
    503545        tf->ft->write_request = jabber_bs_recv_write_request;
    504546
    505547        reply = xt_new_node( "streamhost-used", NULL, NULL );
    506         xt_add_attr( reply, "jid", xt_find_attr( bt->shnode, "jid" ) );
     548        xt_add_attr( reply, "jid", bt->sh->jid );
    507549
    508550        reply = xt_new_node( "query", NULL, reply );
     
    551593                return jabber_bs_abort( bt, "Remote end closed connection" );
    552594       
     595        if( tf->bytesread == 0 )
     596                tf->ft->started = time( NULL );
     597
    553598        tf->bytesread += ret;
    554599
     
    603648                return jabber_bs_abort( bt, "BUG: write() called while watching " );
    604649       
     650        /* TODO: catch broken pipe */
    605651        ASSERTSOCKOP( ret = send( tf->fd, buffer, len, 0 ), "Sending" );
     652
     653        if( tf->byteswritten == 0 )
     654                tf->ft->started = time( NULL );
    606655
    607656        tf->byteswritten += ret;
     
    665714        tf->accepted = TRUE;
    666715
    667         if( bt->phase == BS_PHASE_REPLY )
    668         {
    669                 /* handshake went through, let's start transferring */
    670                 tf->ft->started = time( NULL );
    671                 tf->ft->write_request( tf->ft );
     716        if( strcmp( jid, tf->ini_jid ) == 0 )
     717        {
     718                /* we're streamhost and target */
     719                if( bt->phase == BS_PHASE_REPLY )
     720                {
     721                        /* handshake went through, let's start transferring */
     722                        tf->ft->write_request( tf->ft );
     723                }
     724        } else
     725        {
     726                /* using a proxy */
     727                GSList *shlist;
     728                for( shlist = jd->streamhosts ; shlist ; shlist = g_slist_next( shlist ) )
     729                {
     730                        jabber_streamhost_t *sh = shlist->data;
     731                        if( strcmp( sh->jid, jid ) == 0 )
     732                        {
     733                                bt->sh = sh;
     734                                jabber_bs_recv_handshake( bt, 0, 0 );
     735                                return XT_HANDLED;
     736                        }
     737                }
     738
     739                imcb_log( ic, "WARNING: Received SOCKS5 bytestream reply with unknown streamhost %s", jid );
    672740        }
    673741
     
    675743}
    676744
     745/*
     746 * Tell the proxy to activate the stream. Looks like this:
     747 *
     748 * <iq type=set>
     749 *      <query xmlns=bs sid=sid>
     750 *              <activate>tgt_jid</activate>
     751 *      </query>
     752 * </iq>
     753 */
     754void jabber_bs_send_activate( struct bs_transfer *bt )
     755{
     756        struct xt_node *node;
     757
     758        node = xt_new_node( "activate", bt->tf->tgt_jid, NULL );
     759        node = xt_new_node( "query", NULL, node );
     760        xt_add_attr( node, "xmlns", XMLNS_BYTESTREAMS );
     761        xt_add_attr( node, "sid", bt->tf->sid );
     762        node = jabber_make_packet( "iq", "set", bt->sh->jid, node );
     763
     764        jabber_cache_add( bt->tf->ic, node, jabber_bs_send_handle_activate );
     765
     766        jabber_write_packet( bt->tf->ic, node );
     767}
     768
     769/*
     770 * The proxy has activated the bytestream.
     771 * We can finally start pushing some data out.
     772 */
     773static xt_status jabber_bs_send_handle_activate( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
     774{
     775        char *sid;
     776        GSList *tflist;
     777        struct jabber_transfer *tf;
     778        struct xt_node *query;
     779        struct jabber_data *jd = ic->proto_data;
     780
     781        query = xt_find_node( orig->children, "query" );
     782        sid = xt_find_attr( query, "sid" );
     783
     784        for( tflist = jd->filetransfers ; tflist; tflist = g_slist_next(tflist) )
     785        {
     786                struct jabber_transfer *tft = tflist->data;
     787                if( ( strcmp( tft->sid, sid ) == 0 ) )
     788                {
     789                        tf = tft;
     790                        break;
     791                }
     792        }
     793
     794        if( !tf )
     795        {
     796                imcb_log( ic, "WARNING: Received SOCKS5 bytestream activation for unknown stream" );
     797                return XT_HANDLED;
     798        }
     799
     800        /* handshake went through, let's start transferring */
     801        tf->ft->write_request( tf->ft );
     802
     803        return XT_HANDLED;
     804}
     805
     806/*
     807 * Starts a bytestream.
     808 */
    677809gboolean jabber_bs_send_start( struct jabber_transfer *tf )
    678810{
    679         char host[INET6_ADDRSTRLEN], port[6];
     811        char host[INET6_ADDRSTRLEN];
    680812        struct bs_transfer *bt;
    681813        sha1_state_t sha;
    682814        char hash_hex[41];
    683815        unsigned char hash[20];
    684         int i;
     816        int i,ret;
     817        struct jabber_data *jd = tf->ic->proto_data;
     818        jabber_streamhost_t sh;
     819        GSList *streamhosts = jd->streamhosts;
    685820
    686821        /* SHA1( SID + Initiator JID + Target JID ) is given to the streamhost which it will match against the initiator's value */
     
    702837        tf->ft->canceled = jabber_bs_canceled;
    703838
    704         if ( !jabber_bs_send_listen( bt, &tf->saddr, host, port ) )
     839        if ( !jabber_bs_send_listen( bt, &tf->saddr, sh.host = host, sh.port ) )
    705840                return FALSE;
    706841
    707842        bt->tf->watch_in = b_input_add( tf->fd, GAIM_INPUT_READ, jabber_bs_send_handshake, bt );
    708843        bt->connect_timeout = b_timeout_add( JABBER_BS_LISTEN_TIMEOUT * 1000, jabber_bs_connect_timeout, bt );
    709         return jabber_bs_send_request( tf, host, port );
    710 }
    711 
    712 gboolean jabber_bs_send_request( struct jabber_transfer *tf, char *host, char *port )
    713 {
    714         struct xt_node *sh, *query, *iq;
    715 
    716         sh = xt_new_node( "streamhost", NULL, NULL );
    717         xt_add_attr( sh, "jid", tf->ini_jid );
    718         xt_add_attr( sh, "host", host );
    719         xt_add_attr( sh, "port", port );
     844
     845        sh.jid = tf->ini_jid;
     846
     847        /* temporarily add listen address to streamhosts, send the request and remove it */
     848        streamhosts = g_slist_prepend( streamhosts, &sh );
     849        ret = jabber_bs_send_request( tf, streamhosts);
     850        streamhosts = g_slist_remove( streamhosts, &sh );
     851
     852        return ret;
     853}
     854
     855gboolean jabber_bs_send_request( struct jabber_transfer *tf, GSList *streamhosts )
     856{
     857        struct xt_node *shnode, *query, *iq;
    720858
    721859        query = xt_new_node( "query", NULL, NULL );
     
    723861        xt_add_attr( query, "sid", tf->sid );
    724862        xt_add_attr( query, "mode", "tcp" );
    725         xt_add_child( query, sh );
     863
     864        while( streamhosts ) {
     865                jabber_streamhost_t *sh = streamhosts->data;
     866                shnode = xt_new_node( "streamhost", NULL, NULL );
     867                xt_add_attr( shnode, "jid", sh->jid );
     868                xt_add_attr( shnode, "host", sh->host );
     869                xt_add_attr( shnode, "port", sh->port );
     870
     871                xt_add_child( query, shnode );
     872
     873                streamhosts = g_slist_next( streamhosts );
     874        }
     875
    726876
    727877        iq = jabber_make_packet( "iq", "set", tf->tgt_jid, query );
     
    739889        struct jabber_transfer *tf = bt->tf;
    740890
     891        /* TODO: did the receiver get here somehow??? */
    741892        imcb_log( tf->ic, "Transferring file %s: SOCKS5 handshake failed: %s",
    742893                  tf->ft->file_name,
     
    9011052                        {
    9021053                                /* streamhost-used message came already in(possible?), let's start sending */
    903                                 tf->ft->started = time( NULL );
    9041054                                tf->ft->write_request( tf->ft );
    9051055                        }
  • protocols/jabber/si.c

    r793cc25 r0fbd3a6d  
    8383        struct jabber_transfer *tf;
    8484        struct jabber_data *jd = ic->proto_data;
     85        char *server  = jd->server;
    8586
    8687        imcb_log( ic, "Trying to send %s(%zd bytes) to %s", ft->file_name, ft->file_size, who );
     
    9798        jd->filetransfers = g_slist_prepend( jd->filetransfers, tf );
    9899
     100        /* query the buddy's features */
     101        jabber_iq_query_features( ic, who );
     102
     103        /* query proxies from the server */
     104        if( !jd->have_streamhosts )
     105                jabber_iq_query_server( ic, server, XMLNS_DISCO_ITEMS );
     106
     107        /* send the request to our buddy */
    99108        jabber_si_send_request( ic, who, tf );
    100109
     110        /* and start the receive logic */
    101111        imcb_file_recv_start( ft );
    102112}
  • protocols/msn/msn.c

    r793cc25 r0fbd3a6d  
    241241}
    242242
    243 static void msn_chat_invite( struct groupchat *c, char *msg, char *who )
     243static void msn_chat_invite( struct groupchat *c, char *who, char *message )
    244244{
    245245        struct msn_switchboard *sb = msn_sb_by_chat( c );
  • protocols/oscar/aim.h

    r793cc25 r0fbd3a6d  
    9494 *
    9595 */
    96 #define AIM_DEFAULT_LOGIN_SERVER "login.oscar.aol.com"
     96#define AIM_DEFAULT_LOGIN_SERVER "login.messaging.aol.com"
    9797#define AIM_LOGIN_PORT 5190
    9898
  • protocols/oscar/oscar.c

    r793cc25 r0fbd3a6d  
    341341        set_t *s;
    342342       
    343         s = set_add( &acc->set, "server", NULL, set_eval_account, acc );
     343        s = set_add( &acc->set, "server", AIM_DEFAULT_LOGIN_SERVER, set_eval_account, acc );
    344344        s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY;
    345345       
     
    356356        struct oscar_data *odata = ic->proto_data = g_new0(struct oscar_data, 1);
    357357
    358         if (isdigit(acc->user[0])) {
    359                 odata->icq = TRUE;
    360                 /* This is odd but it's necessary for a proper do_import and do_export.
    361                    We don't do those anymore, but let's stick with it, just in case
    362                    it accidentally fixes something else too... </bitlbee> */
    363                 /* ic->acc->pass[8] = 0;
    364                    Not touching this anymore now that it belongs to account_t!
    365                    Let's hope nothing will break. ;-) */
    366         } else {
     358        if (!isdigit(acc->user[0])) {
    367359                ic->flags |= OPT_DOES_HTML;
    368360        }
     
    385377        }
    386378       
    387         if (acc->server == NULL) {
    388                 imcb_error(ic, "No servername specified");
    389                 imc_logout(ic, FALSE);
    390                 return;
    391         }
    392        
    393         if (g_strcasecmp(acc->server, "login.icq.com") != 0 &&
    394             g_strcasecmp(acc->server, "login.oscar.aol.com") != 0) {
    395                 imcb_log(ic, "Warning: Unknown OSCAR server: `%s'. Please review your configuration if the connection fails.",acc->server);
    396         }
    397        
    398379        imcb_log(ic, _("Signon: %s"), ic->acc->user);
    399380
     
    402383
    403384        conn->status |= AIM_CONN_STATUS_INPROGRESS;
    404         conn->fd = proxy_connect(acc->server, AIM_LOGIN_PORT, oscar_login_connect, ic);
     385        conn->fd = proxy_connect(set_getstr(&acc->set, "server"),
     386                                 AIM_LOGIN_PORT, oscar_login_connect, ic);
    405387        if (conn->fd < 0) {
    406388                imcb_error(ic, _("Couldn't connect to host"));
     
    25092491}
    25102492
    2511 void oscar_chat_invite(struct groupchat *c, char *message, char *who)
     2493void oscar_chat_invite(struct groupchat *c, char *who, char *message)
    25122494{
    25132495        struct im_connection *ic = c->ic;
  • protocols/yahoo/yahoo.c

    r793cc25 r0fbd3a6d  
    306306}
    307307
    308 static void byahoo_chat_invite( struct groupchat *c, char *msg, char *who )
     308static void byahoo_chat_invite( struct groupchat *c, char *who, char *msg )
    309309{
    310310        struct byahoo_data *yd = (struct byahoo_data *) c->ic->proto_data;
  • root_commands.c

    r793cc25 r0fbd3a6d  
    199199                break;
    200200        default:
    201                 irc_usermsg( irc, "Error: '%d'", status );
     201                irc_usermsg( irc, "Error: `%d'", status );
    202202                break;
    203203        }
     
    234234                a = account_add( irc, prpl, cmd[3], cmd[4] );
    235235                if( cmd[5] )
     236                {
     237                        irc_usermsg( irc, "Warning: Passing a servername/other flags to `account add' "
     238                                          "is now deprecated. Use `account set' instead." );
    236239                        set_setstr( &a->set, "server", cmd[5] );
     240                }
    237241               
    238242                irc_usermsg( irc, "Account successfully added" );
     
    317321                        else
    318322                        {
    319                                 irc_usermsg( irc, "No accounts known. Use 'account add' to add one." );
     323                                irc_usermsg( irc, "No accounts known. Use `account add' to add one." );
    320324                        }
    321325                }
     
    403407                        }
    404408                       
    405                         if( ( strcmp( cmd[3], "=" ) ) == 0 && cmd[4] )
    406                                 irc_usermsg( irc, "Warning: Correct syntax: \002account set <variable> <value>\002 (without =)" );
    407                         else if( g_strncasecmp( cmd[2], "-del", 4 ) == 0 )
     409                        if( g_strncasecmp( cmd[2], "-del", 4 ) == 0 )
    408410                                set_reset( &a->set, set_name );
    409411                        else
     
    745747static void cmd_set( irc_t *irc, char **cmd )
    746748{
    747         char *set_name = NULL;
     749        char *set_name = cmd[1];
    748750       
    749751        if( cmd[1] && cmd[2] )
    750752        {
    751                 if( ( strcmp( cmd[2], "=" ) ) == 0 && cmd[3] )
    752                 {
    753                         irc_usermsg( irc, "Warning: Correct syntax: \002set <variable> <value>\002 (without =)" );
    754                         return;
    755                 }
    756                 else if( g_strncasecmp( cmd[1], "-del", 4 ) == 0 )
     753                if( g_strncasecmp( cmd[1], "-del", 4 ) == 0 )
    757754                {
    758755                        set_reset( &irc->set, cmd[2] );
     
    762759                {
    763760                        set_setstr( &irc->set, cmd[1], cmd[2] );
    764                         set_name = cmd[1];
    765761                }
    766762        }
  • tests/check_nick.c

    r793cc25 r0fbd3a6d  
    1515                "thisisave:ryveryveryverylongnick",
    1616                "t::::est",
     17                "test123",
     18                "123test",
     19                "123",
    1720                NULL };
    1821        const char *expected[] = { "test", "test", "test",
     
    2023                "thisisaveryveryveryveryl",
    2124                "test",
     25                "test123",
     26                "_123test",
     27                "_123",
    2228                NULL };
    2329
     
    3541START_TEST(test_nick_ok_ok)
    3642{
    37         const char *nicks[] = { "foo", "bar", "bla[", "blie]",
    38                                     "BreEZaH", "\\od^~", NULL };
     43        const char *nicks[] = { "foo", "bar123", "bla[", "blie]", "BreEZaH",
     44                                "\\od^~", "_123", "_123test", NULL };
    3945        int i;
    4046
     
    4955{
    5056        const char *nicks[] = { "thisisaveryveryveryveryveryveryverylongnick",
    51                                     "\nillegalchar", "", "nick%", NULL };
     57                                    "\nillegalchar", "", "nick%", "123test", NULL };
    5258        int i;
    5359
Note: See TracChangeset for help on using the changeset viewer.