Changeset 256899f for protocols/jabber


Ignore:
Timestamp:
2007-11-19T23:16:18Z (17 years ago)
Author:
Wilmer van der Gaast <wilmer@…>
Branches:
master
Children:
7df5a08
Parents:
cd428e4 (diff), ef5c185 (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 Jabber groupchat support.

Location:
protocols/jabber
Files:
1 added
11 edited

Legend:

Unmodified
Added
Removed
  • protocols/jabber/Makefile

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

    rcd428e4 r256899f  
    4444        struct jabber_data *jd = ic->proto_data;
    4545        gboolean ret;
     46       
     47        if( jd->flags & JFLAG_XMLCONSOLE )
     48        {
     49                char *msg;
     50               
     51                msg = g_strdup_printf( "TX: %s", buf );
     52                imcb_buddy_msg( ic, JABBER_XMLCONSOLE_HANDLE, msg, 0, 0 );
     53                g_free( msg );
     54        }
    4655       
    4756        if( jd->tx_len == 0 )
     
    427436{
    428437        struct im_connection *ic = data;
    429         struct xt_node *c;
    430         char *s, *type = NULL, *text = NULL;
    431438        int allow_reconnect = TRUE;
    432        
    433         for( c = node->children; c; c = c->next )
    434         {
    435                 if( !( s = xt_find_attr( c, "xmlns" ) ) ||
    436                     strcmp( s, XMLNS_STREAM_ERROR ) != 0 )
    437                         continue;
    438                
    439                 if( strcmp( c->name, "text" ) != 0 )
    440                 {
    441                         type = c->name;
    442                 }
    443                 /* Only use the text if it doesn't have an xml:lang attribute,
    444                    if it's empty or if it's set to something English. */
    445                 else if( !( s = xt_find_attr( c, "xml:lang" ) ) ||
    446                          !*s || strncmp( s, "en", 2 ) == 0 )
    447                 {
    448                         text = c->text;
    449                 }
    450         }
     439        struct jabber_error *err;
     440       
     441        err = jabber_error_parse( node, XMLNS_STREAM_ERROR );
    451442       
    452443        /* Tssk... */
    453         if( type == NULL )
     444        if( err->code == NULL )
    454445        {
    455446                imcb_error( ic, "Unknown stream error reported by server" );
    456447                imc_logout( ic, allow_reconnect );
     448                jabber_error_free( err );
    457449                return XT_ABORT;
    458450        }
     
    461453           should turn off auto-reconnect to make sure we won't get some nasty
    462454           infinite loop! */
    463         if( strcmp( type, "conflict" ) == 0 )
     455        if( strcmp( err->code, "conflict" ) == 0 )
    464456        {
    465457                imcb_error( ic, "Account and resource used from a different location" );
     
    468460        else
    469461        {
    470                 imcb_error( ic, "Stream error: %s%s%s", type, text ? ": " : "", text ? text : "" );
    471         }
    472        
     462                imcb_error( ic, "Stream error: %s%s%s", err->code, err->text ? ": " : "",
     463                            err->text ? err->text : "" );
     464        }
     465       
     466        jabber_error_free( err );
    473467        imc_logout( ic, allow_reconnect );
    474468       
     
    476470}
    477471
     472static xt_status jabber_xmlconsole( struct xt_node *node, gpointer data )
     473{
     474        struct im_connection *ic = data;
     475        struct jabber_data *jd = ic->proto_data;
     476       
     477        if( jd->flags & JFLAG_XMLCONSOLE )
     478        {
     479                char *msg, *pkt;
     480               
     481                pkt = xt_to_string( node );
     482                msg = g_strdup_printf( "RX: %s", pkt );
     483                imcb_buddy_msg( ic, JABBER_XMLCONSOLE_HANDLE, msg, 0, 0 );
     484                g_free( msg );
     485                g_free( pkt );
     486        }
     487       
     488        return XT_NEXT;
     489}
     490
    478491static const struct xt_handler_entry jabber_handlers[] = {
     492        { NULL,                 "stream:stream",        jabber_xmlconsole },
    479493        { "stream:stream",      "<root>",               jabber_end_of_stream },
    480494        { "message",            "stream:stream",        jabber_pkt_message },
  • protocols/jabber/iq.c

    rcd428e4 r256899f  
    9999                else if( strcmp( s, XMLNS_DISCOVER ) == 0 )
    100100                {
     101                        const char *features[] = { XMLNS_VERSION,
     102                                                   XMLNS_TIME,
     103                                                   XMLNS_CHATSTATES,
     104                                                   XMLNS_MUC,
     105                                                   NULL };
     106                        const char **f;
     107                       
    101108                        c = xt_new_node( "identity", NULL, NULL );
    102109                        xt_add_attr( c, "category", "client" );
     
    105112                        xt_add_child( reply, c );
    106113                       
    107                         c = xt_new_node( "feature", NULL, NULL );
    108                         xt_add_attr( c, "var", XMLNS_VERSION );
    109                         xt_add_child( reply, c );
    110                        
    111                         c = xt_new_node( "feature", NULL, NULL );
    112                         xt_add_attr( c, "var", XMLNS_TIME );
    113                         xt_add_child( reply, c );
    114                        
    115                         c = xt_new_node( "feature", NULL, NULL );
    116                         xt_add_attr( c, "var", XMLNS_CHATSTATES );
    117                         xt_add_child( reply, c );
    118                        
    119                         /* Later this can be useful to announce things like
    120                            MUC support. */
     114                        for( f = features; *f; f ++ )
     115                        {
     116                                c = xt_new_node( "feature", NULL, NULL );
     117                                xt_add_attr( c, "var", *f );
     118                                xt_add_child( reply, c );
     119                        }
    121120                }
    122121                else
     
    373372                                                                   group->text : NULL );
    374373                               
    375                                 imcb_rename_buddy( ic, jid, name );
     374                                if( name )
     375                                        imcb_rename_buddy( ic, jid, name );
    376376                        }
    377377                        else if( strcmp( sub, "remove" ) == 0 )
    378378                        {
    379                                 /* Don't have any API call for this yet! So let's
    380                                    just try to handle this as well as we can. */
    381379                                jabber_buddy_remove_bare( ic, jid );
    382                                 imcb_buddy_status( ic, jid, 0, NULL, NULL );
    383                                 /* FIXME! */
     380                                imcb_remove_buddy( ic, jid, NULL );
    384381                        }
    385382                }
  • protocols/jabber/jabber.c

    rcd428e4 r256899f  
    5454       
    5555        s = set_add( &acc->set, "tls", "try", set_eval_tls, acc );
     56        s->flags |= ACC_SET_OFFLINE_ONLY;
     57       
     58        s = set_add( &acc->set, "xmlconsole", "false", set_eval_bool, acc );
    5659        s->flags |= ACC_SET_OFFLINE_ONLY;
    5760}
     
    189192                imc_logout( ic, TRUE );
    190193        }
     194       
     195        if( set_getbool( &acc->set, "xmlconsole" ) )
     196        {
     197                jd->flags |= JFLAG_XMLCONSOLE;
     198                /* Shouldn't really do this at this stage already, maybe. But
     199                   I think this shouldn't break anything. */
     200                imcb_add_buddy( ic, JABBER_XMLCONSOLE_HANDLE, NULL );
     201        }
    191202}
    192203
     
    196207       
    197208        jabber_end_stream( ic );
     209       
     210        while( ic->groupchats )
     211                jabber_chat_free( ic->groupchats );
    198212       
    199213        if( jd->r_inpa >= 0 )
     
    224238        struct jabber_buddy *bud;
    225239        struct xt_node *node;
     240        char *s;
    226241        int st;
    227242       
    228         bud = jabber_buddy_by_jid( ic, who, 0 );
     243        if( g_strcasecmp( who, JABBER_XMLCONSOLE_HANDLE ) == 0 )
     244                return jabber_write( ic, message, strlen( message ) );
     245       
     246        if( ( s = strchr( who, '=' ) ) && jabber_chat_by_name( ic, s + 1 ) )
     247                bud = jabber_buddy_by_ext_jid( ic, who, 0 );
     248        else
     249                bud = jabber_buddy_by_jid( ic, who, 0 );
    229250       
    230251        node = xt_new_node( "body", message, NULL );
     
    311332static void jabber_add_buddy( struct im_connection *ic, char *who, char *group )
    312333{
     334        struct jabber_data *jd = ic->proto_data;
     335       
     336        if( g_strcasecmp( who, JABBER_XMLCONSOLE_HANDLE ) == 0 )
     337        {
     338                jd->flags |= JFLAG_XMLCONSOLE;
     339                imcb_add_buddy( ic, JABBER_XMLCONSOLE_HANDLE, NULL );
     340                return;
     341        }
     342       
    313343        if( jabber_add_to_roster( ic, who, NULL ) )
    314344                presence_send_request( ic, who, "subscribe" );
     
    317347static void jabber_remove_buddy( struct im_connection *ic, char *who, char *group )
    318348{
     349        struct jabber_data *jd = ic->proto_data;
     350       
     351        if( g_strcasecmp( who, JABBER_XMLCONSOLE_HANDLE ) == 0 )
     352        {
     353                jd->flags &= ~JFLAG_XMLCONSOLE;
     354                /* Not necessary for now. And for now the code isn't too
     355                   happy if the buddy is completely gone right after calling
     356                   this function already.
     357                imcb_remove_buddy( ic, JABBER_XMLCONSOLE_HANDLE, NULL );
     358                */
     359                return;
     360        }
     361       
    319362        /* We should always do this part. Clean up our administration a little bit. */
    320363        jabber_buddy_remove_bare( ic, who );
     
    322365        if( jabber_remove_from_roster( ic, who ) )
    323366                presence_send_request( ic, who, "unsubscribe" );
     367}
     368
     369static struct groupchat *jabber_chat_join_( struct im_connection *ic, char *room, char *nick, char *password )
     370{
     371        if( strchr( room, '@' ) == NULL )
     372                imcb_error( ic, "Invalid room name: %s", room );
     373        else if( jabber_chat_by_name( ic, room ) )
     374                imcb_error( ic, "Already present in chat `%s'", room );
     375        else
     376                return jabber_chat_join( ic, room, nick, password );
     377       
     378        return NULL;
     379}
     380
     381static void jabber_chat_msg_( struct groupchat *c, char *message, int flags )
     382{
     383        if( c && message )
     384                jabber_chat_msg( c, message, flags );
     385}
     386
     387static void jabber_chat_topic_( struct groupchat *c, char *topic )
     388{
     389        if( c && topic )
     390                jabber_chat_topic( c, topic );
     391}
     392
     393static void jabber_chat_leave_( struct groupchat *c )
     394{
     395        if( c )
     396                jabber_chat_leave( c, NULL );
    324397}
    325398
     
    388461        ret->buddy_msg = jabber_buddy_msg;
    389462        ret->away_states = jabber_away_states;
    390 //      ret->get_status_string = jabber_get_status_string;
    391463        ret->set_away = jabber_set_away;
    392464//      ret->set_info = jabber_set_info;
     
    394466        ret->add_buddy = jabber_add_buddy;
    395467        ret->remove_buddy = jabber_remove_buddy;
    396 //      ret->chat_msg = jabber_chat_msg;
     468        ret->chat_msg = jabber_chat_msg_;
     469        ret->chat_topic = jabber_chat_topic_;
    397470//      ret->chat_invite = jabber_chat_invite;
    398 //      ret->chat_leave = jabber_chat_leave;
    399 //      ret->chat_open = jabber_chat_open;
     471        ret->chat_leave = jabber_chat_leave_;
     472        ret->chat_join = jabber_chat_join_;
    400473        ret->keepalive = jabber_keepalive;
    401474        ret->send_typing = jabber_send_typing;
  • protocols/jabber/jabber.h

    rcd428e4 r256899f  
    3232typedef enum
    3333{
    34         JFLAG_STREAM_STARTED = 1,       /* Set when we detected the beginning of the stream
     34        JFLAG_STREAM_STARTED = 1,       /* Set when we detected the beginning of the stream
    3535                                           and want to do auth. */
    36         JFLAG_AUTHENTICATED = 2,        /* Set when we're successfully authenticatd. */
    37         JFLAG_STREAM_RESTART = 4,       /* Set when we want to restart the stream (after
     36        JFLAG_AUTHENTICATED = 2,        /* Set when we're successfully authenticatd. */
     37        JFLAG_STREAM_RESTART = 4,       /* Set when we want to restart the stream (after
    3838                                           SASL or TLS). */
    39         JFLAG_WAIT_SESSION = 8,         /* Set if we sent a <session> tag and need a reply
     39        JFLAG_WAIT_SESSION = 8,         /* Set if we sent a <session> tag and need a reply
    4040                                           before we continue. */
    41         JFLAG_WAIT_BIND = 16,           /* ... for <bind> tag. */
    42         JFLAG_WANT_TYPING = 32,         /* Set if we ever sent a typing notification, this
     41        JFLAG_WAIT_BIND = 16,           /* ... for <bind> tag. */
     42        JFLAG_WANT_TYPING = 32,         /* Set if we ever sent a typing notification, this
    4343                                           activates all XEP-85 related code. */
     44        JFLAG_XMLCONSOLE = 64,          /* If the user added an xmlconsole buddy. */
    4445} jabber_flags_t;
    4546
     
    5051        JBFLAG_DOES_XEP85 = 2,          /* Set this when the resource seems to support
    5152                                           XEP85 (typing notification shite). */
     53        JBFLAG_IS_CHATROOM = 4,         /* It's convenient to use this JID thingy for
     54                                           groupchat state info too. */
     55        JBFLAG_IS_ANONYMOUS = 8,        /* For anonymous chatrooms, when we don't have
     56                                           have a real JID. */
    5257} jabber_buddy_flags_t;
    53 
    54 #define JABBER_PORT_DEFAULT "5222"
    55 #define JABBER_PORT_MIN 5220
    56 #define JABBER_PORT_MAX 5229
    5758
    5859struct jabber_data
     
    101102        char *resource;
    102103       
     104        char *ext_jid; /* The JID to use in BitlBee. The real JID if possible, */
     105                       /* otherwise something similar to the conference JID. */
     106       
    103107        int priority;
    104108        struct jabber_away_state *away_state;
     
    110114        struct jabber_buddy *next;
    111115};
     116
     117struct jabber_chat
     118{
     119        int flags;
     120        char *name;
     121        char *my_full_jid; /* Separate copy because of case sensitivity. */
     122        struct jabber_buddy *me;
     123};
     124
     125#define JABBER_XMLCONSOLE_HANDLE "xmlconsole"
     126
     127#define JABBER_PORT_DEFAULT "5222"
     128#define JABBER_PORT_MIN 5220
     129#define JABBER_PORT_MAX 5229
    112130
    113131/* Prefixes to use for packet IDs (mainly for IQ packets ATM). Usually the
     
    132150#define XMLNS_TIME         "jabber:iq:time"                     /* XEP-0090 */
    133151#define XMLNS_VCARD        "vcard-temp"                         /* XEP-0054 */
     152#define XMLNS_DELAY        "jabber:x:delay"                     /* XEP-0091 */
    134153#define XMLNS_CHATSTATES   "http://jabber.org/protocol/chatstates"  /* 0085 */
    135154#define XMLNS_DISCOVER     "http://jabber.org/protocol/disco#info"  /* 0030 */
     155#define XMLNS_MUC          "http://jabber.org/protocol/muc"     /* XEP-0045 */
     156#define XMLNS_MUC_USER     "http://jabber.org/protocol/muc#user"/* XEP-0045 */
    136157
    137158/* iq.c */
     
    164185const struct jabber_away_state *jabber_away_state_by_name( char *name );
    165186void jabber_buddy_ask( struct im_connection *ic, char *handle );
    166 char *jabber_normalize( char *orig );
     187char *jabber_normalize( const char *orig );
    167188
    168189typedef enum
    169190{
    170191        GET_BUDDY_CREAT = 1,    /* Try to create it, if necessary. */
    171         GET_BUDDY_EXACT = 2,    /* Get an exact message (only makes sense with bare JIDs). */
     192        GET_BUDDY_EXACT = 2,    /* Get an exact match (only makes sense with bare JIDs). */
     193        GET_BUDDY_FIRST = 4,    /* No selection, simply get the first resource for this JID. */
    172194} get_buddy_flags_t;
     195
     196struct jabber_error
     197{
     198        char *code, *text, *type;
     199};
    173200
    174201struct jabber_buddy *jabber_buddy_add( struct im_connection *ic, char *full_jid );
    175202struct jabber_buddy *jabber_buddy_by_jid( struct im_connection *ic, char *jid, get_buddy_flags_t flags );
     203struct jabber_buddy *jabber_buddy_by_ext_jid( struct im_connection *ic, char *jid, get_buddy_flags_t flags );
    176204int jabber_buddy_remove( struct im_connection *ic, char *full_jid );
    177205int jabber_buddy_remove_bare( struct im_connection *ic, char *bare_jid );
     206struct groupchat *jabber_chat_by_name( struct im_connection *ic, const char *name );
     207time_t jabber_get_timestamp( struct xt_node *xt );
     208struct jabber_error *jabber_error_parse( struct xt_node *node, char *xmlns );
     209void jabber_error_free( struct jabber_error *err );
    178210
    179211extern const struct jabber_away_state jabber_away_state_list[];
     
    193225gboolean sasl_supported( struct im_connection *ic );
    194226
     227/* conference.c */
     228struct groupchat *jabber_chat_join( struct im_connection *ic, char *room, char *nick, char *password );
     229void jabber_chat_free( struct groupchat *c );
     230int jabber_chat_msg( struct groupchat *ic, char *message, int flags );
     231int jabber_chat_topic( struct groupchat *c, char *topic );
     232int jabber_chat_leave( struct groupchat *c, const char *reason );
     233void jabber_chat_pkt_presence( struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node );
     234void jabber_chat_pkt_message( struct im_connection *ic, struct jabber_buddy *bud, struct xt_node *node );
     235
    195236#endif
  • protocols/jabber/jabber_util.c

    rcd428e4 r256899f  
    4848                   call p_s_u() now to send the new prio setting, it would
    4949                   send the old setting because the set->value gets changed
    50                    when the eval returns a non-NULL value.
     50                   after the (this) eval returns a non-NULL value.
    5151                   
    5252                   So now I can choose between implementing post-set
     
    129129/* Cache a node/packet for later use. Mainly useful for IQ packets if you need
    130130   them when you receive the response. Use this BEFORE sending the packet so
    131    it'll get a new id= tag, and do NOT free() the packet after writing it! */
     131   it'll get a new id= tag, and do NOT free() the packet after sending it! */
    132132void jabber_cache_add( struct im_connection *ic, struct xt_node *node, jabber_cache_event func )
    133133{
     
    252252
    253253/* Returns a new string. Don't leak it! */
    254 char *jabber_normalize( char *orig )
     254char *jabber_normalize( const char *orig )
    255255{
    256256        int len, i;
     
    320320        else
    321321        {
     322                /* Keep in mind that full_jid currently isn't really
     323                   a full JID... */
    322324                new->bare_jid = g_strdup( full_jid );
    323325                g_hash_table_insert( jd->buddies, new->bare_jid, new );
     
    333335        {
    334336                /* Let's waste some more bytes of RAM instead of to make
    335                    memory management a total disaster here.. */
     337                   memory management a total disaster here. And it saves
     338                   me one g_free() call in this function. :-P */
    336339                new->full_jid = full_jid;
    337340        }
     
    353356        if( ( s = strchr( jid, '/' ) ) )
    354357        {
     358                int none_found = 0;
     359               
    355360                *s = 0;
    356361                if( ( bud = g_hash_table_lookup( jd->buddies, jid ) ) )
     
    370375                        }
    371376                }
    372                
    373                 if( bud == NULL && ( flags & GET_BUDDY_CREAT ) && imcb_find_buddy( ic, jid ) )
     377                else
     378                {
     379                        /* This hack is there to make sure that O_CREAT will
     380                           work if there's already another resouce present
     381                           for this JID, even if it's an unknown buddy. This
     382                           is done to handle conferences properly. */
     383                        none_found = 1;
     384                }
     385               
     386                if( bud == NULL && ( flags & GET_BUDDY_CREAT ) && ( imcb_find_buddy( ic, jid ) || !none_found ) )
    374387                {
    375388                        *s = '/';
     
    418431}
    419432
     433/* I'm keeping a separate ext_jid attribute to save a JID that makes sense
     434   to export to BitlBee. This is mainly for groupchats right now. It's
     435   a bit of a hack, but I just think having the user nickname in the hostname
     436   part of the hostmask doesn't look nice on IRC. Normally you can convert
     437   a normal JID to ext_jid by swapping the part before and after the / and
     438   replacing the / with a =. But there should be some stripping (@s are
     439   allowed in Jabber nicks...). */
     440struct jabber_buddy *jabber_buddy_by_ext_jid( struct im_connection *ic, char *jid_, get_buddy_flags_t flags )
     441{
     442        struct jabber_buddy *bud;
     443        char *s, *jid;
     444       
     445        jid = jabber_normalize( jid_ );
     446       
     447        if( ( s = strchr( jid, '=' ) ) == NULL )
     448                return NULL;
     449       
     450        for( bud = jabber_buddy_by_jid( ic, s + 1, GET_BUDDY_FIRST ); bud; bud = bud->next )
     451        {
     452                /* Hmmm, could happen if not all people in the chat are anonymized? */
     453                if( bud->ext_jid == NULL )
     454                        continue;
     455               
     456                if( strcmp( bud->ext_jid, jid ) == 0 )
     457                        break;
     458        }
     459       
     460        g_free( jid );
     461       
     462        return bud;
     463}
     464
    420465/* Remove one specific full JID from our list. Use this when a buddy goes
    421466   off-line (because (s)he can still be online from a different location.
     
    441486                        g_hash_table_remove( jd->buddies, bud->bare_jid );
    442487                        g_free( bud->bare_jid );
     488                        g_free( bud->ext_jid );
    443489                        g_free( bud->full_jid );
    444490                        g_free( bud->away_message );
     
    473519                                        g_hash_table_replace( jd->buddies, bi->bare_jid, bi->next );
    474520                               
     521                                g_free( bi->ext_jid );
    475522                                g_free( bi->full_jid );
    476523                                g_free( bi->away_message );
     
    495542   specified bare JID. Use this when removing someone from the contact
    496543   list, for example. */
    497 int jabber_buddy_remove_bare( struct im_connection *ic, char *bare_jid_ )
     544int jabber_buddy_remove_bare( struct im_connection *ic, char *bare_jid )
    498545{
    499546        struct jabber_data *jd = ic->proto_data;
    500547        struct jabber_buddy *bud, *next;
    501         char *bare_jid;
    502        
    503         if( strchr( bare_jid_, '/' ) )
     548       
     549        if( strchr( bare_jid, '/' ) )
    504550                return 0;
    505551       
    506         bare_jid = jabber_normalize( bare_jid_ );
    507        
    508         if( ( bud = g_hash_table_lookup( jd->buddies, bare_jid ) ) )
     552        if( ( bud = jabber_buddy_by_jid( ic, bare_jid, GET_BUDDY_FIRST ) ) )
    509553        {
    510554                /* Most important: Remove the hash reference. We don't know
    511555                   this buddy anymore. */
    512556                g_hash_table_remove( jd->buddies, bud->bare_jid );
     557                g_free( bud->bare_jid );
    513558               
    514559                /* Deallocate the linked list of resources. */
    515560                while( bud )
    516561                {
     562                        /* ext_jid && anonymous means that this buddy is
     563                           specific to one groupchat (the one we're
     564                           currently cleaning up) so it can be deleted
     565                           completely. */
     566                        if( bud->ext_jid && bud->flags & JBFLAG_IS_ANONYMOUS )
     567                                imcb_remove_buddy( ic, bud->ext_jid, NULL );
     568                       
    517569                        next = bud->next;
     570                        g_free( bud->ext_jid );
    518571                        g_free( bud->full_jid );
    519572                        g_free( bud->away_message );
     
    522575                }
    523576               
    524                 g_free( bare_jid );
    525577                return 1;
    526578        }
    527579        else
    528580        {
    529                 g_free( bare_jid );
    530581                return 0;
    531582        }
    532583}
     584
     585struct groupchat *jabber_chat_by_name( struct im_connection *ic, const char *name )
     586{
     587        char *normalized = jabber_normalize( name );
     588        struct groupchat *ret;
     589        struct jabber_chat *jc;
     590       
     591        for( ret = ic->groupchats; ret; ret = ret->next )
     592        {
     593                jc = ret->data;
     594                if( strcmp( normalized, jc->name ) == 0 )
     595                        break;
     596        }
     597        g_free( normalized );
     598       
     599        return ret;
     600}
     601
     602time_t jabber_get_timestamp( struct xt_node *xt )
     603{
     604        struct tm tp, utc;
     605        struct xt_node *c;
     606        time_t res, tres;
     607        char *s = NULL;
     608       
     609        for( c = xt->children; ( c = xt_find_node( c, "x" ) ); c = c->next )
     610        {
     611                if( ( s = xt_find_attr( c, "xmlns" ) ) && strcmp( s, XMLNS_DELAY ) == 0 )
     612                        break;
     613        }
     614       
     615        if( !c || !( s = xt_find_attr( c, "stamp" ) ) )
     616                return 0;
     617       
     618        memset( &tp, 0, sizeof( tp ) );
     619        if( sscanf( s, "%4d%2d%2dT%2d:%2d:%2d", &tp.tm_year, &tp.tm_mon, &tp.tm_mday,
     620                                                &tp.tm_hour, &tp.tm_min, &tp.tm_sec ) != 6 )
     621                return 0;
     622       
     623        tp.tm_year -= 1900;
     624        tp.tm_mon --;
     625        tp.tm_isdst = -1; /* GRRRRRRRRRRR */
     626       
     627        res = mktime( &tp );
     628        /* Problem is, mktime() just gave us the GMT timestamp for the
     629           given local time... While the given time WAS NOT local. So
     630           we should fix this now.
     631       
     632           Now I could choose between messing with environment variables
     633           (kludgy) or using timegm() (not portable)... Or doing the
     634           following, which I actually prefer... */
     635        gmtime_r( &res, &utc );
     636        utc.tm_isdst = -1; /* Once more: GRRRRRRRRRRRRRRRRRR!!! */
     637        if( utc.tm_hour == tp.tm_hour && utc.tm_min == tp.tm_min )
     638                /* Sweet! We're in UTC right now... */
     639                return res;
     640       
     641        tres = mktime( &utc );
     642        res += res - tres;
     643       
     644        /* Yes, this is a hack. And it will go wrong around DST changes.
     645           BUT this is more likely to be threadsafe than messing with
     646           environment variables, and possibly more portable... */
     647       
     648        return res;
     649}
     650
     651struct jabber_error *jabber_error_parse( struct xt_node *node, char *xmlns )
     652{
     653        struct jabber_error *err = g_new0( struct jabber_error, 1 );
     654        struct xt_node *c;
     655        char *s;
     656       
     657        err->type = xt_find_attr( node, "type" );
     658       
     659        for( c = node->children; c; c = c->next )
     660        {
     661                if( !( s = xt_find_attr( c, "xmlns" ) ) ||
     662                    strcmp( s, xmlns ) != 0 )
     663                        continue;
     664               
     665                if( strcmp( c->name, "text" ) != 0 )
     666                {
     667                        err->code = c->name;
     668                }
     669                /* Only use the text if it doesn't have an xml:lang attribute,
     670                   if it's empty or if it's set to something English. */
     671                else if( !( s = xt_find_attr( c, "xml:lang" ) ) ||
     672                         !*s || strncmp( s, "en", 2 ) == 0 )
     673                {
     674                        err->text = c->text;
     675                }
     676        }
     677       
     678        return err;
     679}
     680
     681void jabber_error_free( struct jabber_error *err )
     682{
     683        g_free( err );
     684}
  • protocols/jabber/message.c

    rcd428e4 r256899f  
    3030        char *type = xt_find_attr( node, "type" );
    3131        struct xt_node *body = xt_find_node( node->children, "body" ), *c;
     32        struct jabber_buddy *bud = NULL;
    3233        char *s;
     34       
     35        if( !from )
     36                return XT_HANDLED; /* Consider this packet corrupted. */
     37       
     38        bud = jabber_buddy_by_jid( ic, from, GET_BUDDY_EXACT );
    3339       
    3440        if( type && strcmp( type, "error" ) == 0 )
     
    3642                /* Handle type=error packet. */
    3743        }
    38         else if( type && strcmp( type, "groupchat" ) == 0 )
     44        else if( type && from && strcmp( type, "groupchat" ) == 0 )
    3945        {
    40                 /* TODO! */
     46                jabber_chat_pkt_message( ic, bud, node );
    4147        }
    4248        else /* "chat", "normal", "headline", no-type or whatever. Should all be pretty similar. */
    4349        {
    44                 struct jabber_buddy *bud = NULL;
    4550                GString *fullmsg = g_string_new( "" );
    4651               
    4752                if( ( s = strchr( from, '/' ) ) )
    4853                {
    49                         if( ( bud = jabber_buddy_by_jid( ic, from, GET_BUDDY_EXACT ) ) )
     54                        if( bud )
     55                        {
    5056                                bud->last_act = time( NULL );
     57                                from = bud->ext_jid ? : bud->bare_jid;
     58                        }
    5159                        else
    5260                                *s = 0; /* We need to generate a bare JID now. */
     
    7684               
    7785                if( fullmsg->len > 0 )
    78                         imcb_buddy_msg( ic, bud ? bud->bare_jid : from, fullmsg->str, 0, 0 );
     86                        imcb_buddy_msg( ic, from, fullmsg->str,
     87                                        0, jabber_get_timestamp( node ) );
    7988               
    8089                g_string_free( fullmsg, TRUE );
    8190               
    8291                /* Handling of incoming typing notifications. */
    83                 if( xt_find_node( node->children, "composing" ) )
     92                if( bud == NULL )
     93                {
     94                        /* Can't handle these for unknown buddies. */
     95                }
     96                else if( xt_find_node( node->children, "composing" ) )
    8497                {
    8598                        bud->flags |= JBFLAG_DOES_XEP85;
    86                         imcb_buddy_typing( ic, bud ? bud->bare_jid : from, OPT_TYPING );
     99                        imcb_buddy_typing( ic, from, OPT_TYPING );
    87100                }
    88101                /* No need to send a "stopped typing" signal when there's a message. */
     
    90103                {
    91104                        bud->flags |= JBFLAG_DOES_XEP85;
    92                         imcb_buddy_typing( ic, bud ? bud->bare_jid : from, 0 );
     105                        imcb_buddy_typing( ic, from, 0 );
    93106                }
    94107                else if( xt_find_node( node->children, "paused" ) )
    95108                {
    96109                        bud->flags |= JBFLAG_DOES_XEP85;
    97                         imcb_buddy_typing( ic, bud ? bud->bare_jid : from, OPT_THINKING );
     110                        imcb_buddy_typing( ic, from, OPT_THINKING );
    98111                }
    99112               
  • protocols/jabber/presence.c

    rcd428e4 r256899f  
    3131        struct xt_node *c;
    3232        struct jabber_buddy *bud;
     33        int is_chat = 0, is_away = 0;
    3334        char *s;
    3435       
     
    3637                return XT_HANDLED;
    3738       
     39        if( ( s = strchr( from, '/' ) ) )
     40        {
     41                *s = 0;
     42                if( jabber_chat_by_name( ic, from ) )
     43                        is_chat = 1;
     44                *s = '/';
     45        }
     46       
    3847        if( type == NULL )
    3948        {
    40                 int is_away = 0;
    41                
    4249                if( !( bud = jabber_buddy_by_jid( ic, from, GET_BUDDY_EXACT | GET_BUDDY_CREAT ) ) )
    4350                {
     
    7279                        bud->priority = 0;
    7380               
    74                 if( bud == jabber_buddy_by_jid( ic, bud->bare_jid, 0 ) )
     81                if( is_chat )
     82                        jabber_chat_pkt_presence( ic, bud, node );
     83                else if( bud == jabber_buddy_by_jid( ic, bud->bare_jid, 0 ) )
    7584                        imcb_buddy_status( ic, bud->bare_jid, OPT_LOGGED_IN | is_away,
    7685                                           ( is_away && bud->away_state ) ? bud->away_state->full_name : NULL,
     
    7988        else if( strcmp( type, "unavailable" ) == 0 )
    8089        {
    81                 if( jabber_buddy_by_jid( ic, from, GET_BUDDY_EXACT ) == NULL )
     90                if( ( bud = jabber_buddy_by_jid( ic, from, GET_BUDDY_EXACT ) ) == NULL )
    8291                {
    8392                        if( set_getbool( &ic->irc->set, "debug" ) )
     
    8695                }
    8796               
     97                /* Handle this before we delete the JID. */
     98                if( is_chat )
     99                {
     100                        jabber_chat_pkt_presence( ic, bud, node );
     101                }
     102               
    88103                jabber_buddy_remove( ic, from );
    89104               
    90                 if( ( s = strchr( from, '/' ) ) )
     105                if( is_chat )
     106                {
     107                        /* Nothing else to do for now? */
     108                }
     109                else if( ( s = strchr( from, '/' ) ) )
    91110                {
    92111                        *s = 0;
    93112               
    94                         /* Only count this as offline if there's no other resource
    95                            available anymore. */
    96                         if( jabber_buddy_by_jid( ic, from, 0 ) == NULL )
     113                        /* If another resource is still available, send its presence
     114                           information. */
     115                        if( ( bud = jabber_buddy_by_jid( ic, from, 0 ) ) )
     116                        {
     117                                if( bud->away_state && ( *bud->away_state->code == 0 ||
     118                                    strcmp( bud->away_state->code, "chat" ) == 0 ) )
     119                                        is_away = OPT_AWAY;
     120                               
     121                                imcb_buddy_status( ic, bud->bare_jid, OPT_LOGGED_IN | is_away,
     122                                                   ( is_away && bud->away_state ) ? bud->away_state->full_name : NULL,
     123                                                   bud->away_message );
     124                        }
     125                        else
     126                        {
     127                                /* Otherwise, count him/her as offline now. */
    97128                                imcb_buddy_status( ic, from, 0, NULL, NULL );
     129                        }
    98130                       
    99131                        *s = '/';
     
    126158        else if( strcmp( type, "error" ) == 0 )
    127159        {
    128                 /* What to do with it? */
     160                struct jabber_error *err;
     161               
     162                if( ( c = xt_find_node( node->children, "error" ) ) )
     163                {
     164                        err = jabber_error_parse( c, XMLNS_STANZA_ERROR );
     165                        imcb_error( ic, "Stanza (%s) error: %s%s%s", node->name,
     166                                    err->code, err->text ? ": " : "",
     167                                    err->text ? err->text : "" );
     168                        jabber_error_free( err );
     169                }
     170                /* What else to do with it? */
    129171        }
    130172       
     
    140182        char *show = jd->away_state->code;
    141183        char *status = jd->away_message;
     184        struct groupchat *c;
    142185        int st;
    143186       
     
    151194        st = jabber_write_packet( ic, node );
    152195       
     196        /* Have to send this update to all groupchats too, the server won't
     197           do this automatically. */
     198        for( c = ic->groupchats; c && st; c = c->next )
     199        {
     200                struct jabber_chat *jc = c->data;
     201               
     202                xt_add_attr( node, "to", jc->my_full_jid );
     203                st = jabber_write_packet( ic, node );
     204        }
     205       
    153206        xt_free_node( node );
    154207        return st;
  • protocols/jabber/sasl.c

    rcd428e4 r256899f  
    332332        struct jabber_data *jd = ic->proto_data;
    333333       
    334         return ( (void*) ( jd->xt && jd->xt->root && xt_find_attr( jd->xt->root, "version" ) ) ) != NULL;
    335 }
     334        return ( jd->xt && jd->xt->root && xt_find_attr( jd->xt->root, "version" ) ) != 0;
     335}
  • protocols/jabber/xmltree.c

    rcd428e4 r256899f  
    444444   list, not the node itself! The reason you have to do this by hand: So
    445445   that you can also use this function as a find-next. */
    446 struct xt_node *xt_find_node( struct xt_node *node, char *name )
     446struct xt_node *xt_find_node( struct xt_node *node, const char *name )
    447447{
    448448        while( node )
     
    457457}
    458458
    459 char *xt_find_attr( struct xt_node *node, char *key )
     459char *xt_find_attr( struct xt_node *node, const char *key )
    460460{
    461461        int i;
     
    526526}
    527527
    528 void xt_add_attr( struct xt_node *node, char *key, char *value )
     528void xt_add_attr( struct xt_node *node, const char *key, const char *value )
    529529{
    530530        int i;
     
    553553}
    554554
    555 int xt_remove_attr( struct xt_node *node, char *key )
     555int xt_remove_attr( struct xt_node *node, const char *key )
    556556{
    557557        int i, last;
  • protocols/jabber/xmltree.h

    rcd428e4 r256899f  
    8787void xt_free_node( struct xt_node *node );
    8888void xt_free( struct xt_parser *xt );
    89 struct xt_node *xt_find_node( struct xt_node *node, char *name );
    90 char *xt_find_attr( struct xt_node *node, char *key );
     89struct xt_node *xt_find_node( struct xt_node *node, const char *name );
     90char *xt_find_attr( struct xt_node *node, const char *key );
    9191
    9292struct xt_node *xt_new_node( char *name, char *text, struct xt_node *children );
    9393void xt_add_child( struct xt_node *parent, struct xt_node *child );
    94 void xt_add_attr( struct xt_node *node, char *key, char *value );
    95 int xt_remove_attr( struct xt_node *node, char *key );
     94void xt_add_attr( struct xt_node *node, const char *key, const char *value );
     95int xt_remove_attr( struct xt_node *node, const char *key );
    9696
    9797#endif
Note: See TracChangeset for help on using the changeset viewer.