source: protocols/jabber/jabber.c @ 57b4525

Last change on this file since 57b4525 was 57b4525, checked in by Wilmer van der Gaast <wilmer@…>, at 2011-07-22T18:29:25Z

Nothing useful yet, this just generates an auth URL. Things to do: Ability
to process the answer. This is hard because the GTalk server will time out
very quickly which means we lose our state/scope/etc. (And the ability to
even receive the answer, at least if I'd do this the same way the Twitter
module does it.)

And then, get the access token and use it, of course. :-)

  • Property mode set to 100644
File size: 17.4 KB
RevLine 
[f06894d]1/***************************************************************************\
2*                                                                           *
3*  BitlBee - An IRC to IM gateway                                           *
4*  Jabber module - Main file                                                *
5*                                                                           *
6*  Copyright 2006 Wilmer van der Gaast <wilmer@gaast.net>                   *
7*                                                                           *
8*  This program is free software; you can redistribute it and/or modify     *
9*  it under the terms of the GNU General Public License as published by     *
10*  the Free Software Foundation; either version 2 of the License, or        *
11*  (at your option) any later version.                                      *
12*                                                                           *
13*  This program is distributed in the hope that it will be useful,          *
14*  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
15*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
16*  GNU General Public License for more details.                             *
17*                                                                           *
18*  You should have received a copy of the GNU General Public License along  *
19*  with this program; if not, write to the Free Software Foundation, Inc.,  *
20*  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.              *
21*                                                                           *
22\***************************************************************************/
23
24#include <glib.h>
25#include <string.h>
26#include <unistd.h>
27#include <ctype.h>
28#include <stdio.h>
29
[21167d2]30#include "ssl_client.h"
[f06894d]31#include "xmltree.h"
32#include "bitlbee.h"
33#include "jabber.h"
[608f8cf]34#include "md5.h"
[f06894d]35
[b5c8a34]36GSList *jabber_connections;
37
[7f69740]38/* First enty is the default */
39static const int jabber_port_list[] = {
40        5222,
41        5223,
42        5220,
43        5221,
44        5224,
45        5225,
46        5226,
47        5227,
48        5228,
49        5229,
50        80,
51        443,
52        0
53};
54
[0da65d5]55static void jabber_init( account_t *acc )
[f06894d]56{
57        set_t *s;
[7f69740]58        char str[16];
[f06894d]59       
[76c85b4c]60        s = set_add( &acc->set, "activity_timeout", "600", set_eval_int, acc );
61       
[57b4525]62        s = set_add( &acc->set, "oauth", "false", set_eval_bool, acc );
63
[7f69740]64        g_snprintf( str, sizeof( str ), "%d", jabber_port_list[0] );
65        s = set_add( &acc->set, "port", str, set_eval_int, acc );
[f06894d]66        s->flags |= ACC_SET_OFFLINE_ONLY;
67       
[ebe7b36]68        s = set_add( &acc->set, "priority", "0", set_eval_priority, acc );
[1c3008a]69
70        s = set_add( &acc->set, "proxy", "<local>;<auto>", NULL, acc );
[f06894d]71       
[ebe7b36]72        s = set_add( &acc->set, "resource", "BitlBee", NULL, acc );
73        s->flags |= ACC_SET_OFFLINE_ONLY;
[f06894d]74       
[76c85b4c]75        s = set_add( &acc->set, "resource_select", "activity", NULL, acc );
[a21a8ac]76       
[f06894d]77        s = set_add( &acc->set, "server", NULL, set_eval_account, acc );
[7125cb3]78        s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY | SET_NULL_OK;
[f06894d]79       
80        s = set_add( &acc->set, "ssl", "false", set_eval_bool, acc );
81        s->flags |= ACC_SET_OFFLINE_ONLY;
82       
83        s = set_add( &acc->set, "tls", "try", set_eval_tls, acc );
84        s->flags |= ACC_SET_OFFLINE_ONLY;
[a6df0b5]85       
[4eef271]86        s = set_add( &acc->set, "user_agent", "BitlBee", NULL, acc );
87       
[a6df0b5]88        s = set_add( &acc->set, "xmlconsole", "false", set_eval_bool, acc );
89        s->flags |= ACC_SET_OFFLINE_ONLY;
[840bba8]90       
91        acc->flags |= ACC_FLAG_AWAY_MESSAGE | ACC_FLAG_STATUS_MESSAGE;
[f06894d]92}
93
[608f8cf]94static void jabber_generate_id_hash( struct jabber_data *jd );
95
[f06894d]96static void jabber_login( account_t *acc )
97{
[84b045d]98        struct im_connection *ic = imcb_new( acc );
[21167d2]99        struct jabber_data *jd = g_new0( struct jabber_data, 1 );
[72176c1]100        struct ns_srv_reply **srvl = NULL, *srv = NULL;
[3b3cd693]101        char *connect_to, *s;
[7f69740]102        int i;
[21167d2]103       
[b5c8a34]104        /* For now this is needed in the _connected() handlers if using
105           GLib event handling, to make sure we're not handling events
106           on dead connections. */
107        jabber_connections = g_slist_prepend( jabber_connections, ic );
108       
[0da65d5]109        jd->ic = ic;
110        ic->proto_data = jd;
[21167d2]111       
112        jd->username = g_strdup( acc->user );
113        jd->server = strchr( jd->username, '@' );
114       
[de03374]115        jd->fd = jd->r_inpa = jd->w_inpa = -1;
116       
[21167d2]117        if( jd->server == NULL )
118        {
[84b045d]119                imcb_error( ic, "Incomplete account name (format it like <username@jabberserver.name>)" );
[c2fb3809]120                imc_logout( ic, FALSE );
[21167d2]121                return;
122        }
123       
124        /* So don't think of free()ing jd->server.. :-) */
125        *jd->server = 0;
126        jd->server ++;
127       
[3b3cd693]128        if( ( s = strchr( jd->server, '/' ) ) )
129        {
130                *s = 0;
131                set_setstr( &acc->set, "resource", s + 1 );
132               
133                /* Also remove the /resource from the original variable so we
134                   won't have to do this again every time. */
135                s = strchr( acc->user, '/' );
136                *s = 0;
137        }
138       
139        /* This code isn't really pretty. Backwards compatibility never is... */
140        s = acc->server;
141        while( s )
142        {
143                static int had_port = 0;
144               
145                if( strncmp( s, "ssl", 3 ) == 0 )
146                {
147                        set_setstr( &acc->set, "ssl", "true" );
148                       
149                        /* Flush this part so that (if this was the first
150                           part of the server string) acc->server gets
151                           flushed. We don't want to have to do this another
152                           time. :-) */
153                        *s = 0;
154                        s ++;
155                       
156                        /* Only set this if the user didn't specify a custom
157                           port number already... */
158                        if( !had_port )
159                                set_setint( &acc->set, "port", 5223 );
160                }
161                else if( isdigit( *s ) )
162                {
163                        int i;
164                       
165                        /* The first character is a digit. It could be an
166                           IP address though. Only accept this as a port#
167                           if there are only digits. */
168                        for( i = 0; isdigit( s[i] ); i ++ );
169                       
170                        /* If the first non-digit character is a colon or
171                           the end of the string, save the port number
172                           where it should be. */
173                        if( s[i] == ':' || s[i] == 0 )
174                        {
175                                sscanf( s, "%d", &i );
176                                set_setint( &acc->set, "port", i );
177                               
178                                /* See above. */
179                                *s = 0;
180                                s ++;
181                        }
182                       
183                        had_port = 1;
184                }
185               
186                s = strchr( s, ':' );
187                if( s )
188                {
189                        *s = 0;
190                        s ++;
191                }
192        }
193       
[038d17f]194        jd->node_cache = g_hash_table_new_full( g_str_hash, g_str_equal, NULL, jabber_cache_entry_free );
[6a1128d]195        jd->buddies = g_hash_table_new( g_str_hash, g_str_equal );
[fe7a554]196       
[36e9f62]197        /* Figure out the hostname to connect to. */
[3b3cd693]198        if( acc->server && *acc->server )
[36e9f62]199                connect_to = acc->server;
[ffdf2e7]200        else if( ( srvl = srv_lookup( "xmpp-client", "tcp", jd->server ) ) ||
201                 ( srvl = srv_lookup( "jabber-client", "tcp", jd->server ) ) )
202        {
203                /* Find the lowest-priority one. These usually come
204                   back in random/shuffled order. Not looking at
205                   weights etc for now. */
206                srv = *srvl;
207                for( i = 1; srvl[i]; i ++ )
208                        if( srvl[i]->prio < srv->prio )
209                                srv = srvl[i];
210               
[36e9f62]211                connect_to = srv->name;
[ffdf2e7]212        }
[36e9f62]213        else
214                connect_to = jd->server;
215       
[84b045d]216        imcb_log( ic, "Connecting" );
[35f6677]217       
[7f69740]218        for( i = 0; jabber_port_list[i] > 0; i ++ )
219                if( set_getint( &acc->set, "port" ) == jabber_port_list[i] )
220                        break;
221
222        if( jabber_port_list[i] == 0 )
[0f4c1bb5]223        {
[7f69740]224                imcb_log( ic, "Illegal port number" );
[c2fb3809]225                imc_logout( ic, FALSE );
[0f4c1bb5]226                return;
227        }
228       
[36e9f62]229        /* For non-SSL connections we can try to use the port # from the SRV
230           reply, but let's not do that when using SSL, SSL usually runs on
231           non-standard ports... */
[21167d2]232        if( set_getbool( &acc->set, "ssl" ) )
233        {
[0da65d5]234                jd->ssl = ssl_connect( connect_to, set_getint( &acc->set, "port" ), jabber_connected_ssl, ic );
[3b3cd693]235                jd->fd = jd->ssl ? ssl_getfd( jd->ssl ) : -1;
[21167d2]236        }
237        else
238        {
[0da65d5]239                jd->fd = proxy_connect( connect_to, srv ? srv->port : set_getint( &acc->set, "port" ), jabber_connected_plain, ic );
[21167d2]240        }
[ffdf2e7]241        srv_free( srvl );
[35f6677]242       
243        if( jd->fd == -1 )
244        {
[84b045d]245                imcb_error( ic, "Could not connect to server" );
[c2fb3809]246                imc_logout( ic, TRUE );
[fb4ebcc5]247               
248                return;
[35f6677]249        }
[a6df0b5]250       
251        if( set_getbool( &acc->set, "xmlconsole" ) )
252        {
253                jd->flags |= JFLAG_XMLCONSOLE;
254                /* Shouldn't really do this at this stage already, maybe. But
255                   I think this shouldn't break anything. */
256                imcb_add_buddy( ic, JABBER_XMLCONSOLE_HANDLE, NULL );
257        }
[608f8cf]258       
259        jabber_generate_id_hash( jd );
260}
261
[89d736a]262/* This generates an unfinished md5_state_t variable. Every time we generate
263   an ID, we finish the state by adding a sequence number and take the hash. */
[608f8cf]264static void jabber_generate_id_hash( struct jabber_data *jd )
265{
[89d736a]266        md5_byte_t binbuf[4];
[608f8cf]267        char *s;
268       
[89d736a]269        md5_init( &jd->cached_id_prefix );
270        md5_append( &jd->cached_id_prefix, (unsigned char *) jd->username, strlen( jd->username ) );
271        md5_append( &jd->cached_id_prefix, (unsigned char *) jd->server, strlen( jd->server ) );
[608f8cf]272        s = set_getstr( &jd->ic->acc->set, "resource" );
[89d736a]273        md5_append( &jd->cached_id_prefix, (unsigned char *) s, strlen( s ) );
274        random_bytes( binbuf, 4 );
275        md5_append( &jd->cached_id_prefix, binbuf, 4 );
[f06894d]276}
277
[0da65d5]278static void jabber_logout( struct im_connection *ic )
[f06894d]279{
[0da65d5]280        struct jabber_data *jd = ic->proto_data;
[21167d2]281       
[4ac647d]282        while( jd->filetransfers )
[17a6ee9]283                imcb_file_canceled( ic, ( ( struct jabber_transfer *) jd->filetransfers->data )->ft, "Logging out" );
[4ac647d]284
285        while( jd->streamhosts )
286        {
287                jabber_streamhost_t *sh = jd->streamhosts->data;
288                jd->streamhosts = g_slist_remove( jd->streamhosts, sh );
289                g_free( sh->jid );
290                g_free( sh->host );
291                g_free( sh );
292        }
293
[de03374]294        if( jd->fd >= 0 )
295                jabber_end_stream( ic );
[4a0614e]296       
[c377417]297        while( ic->groupchats )
[aea8b68]298                jabber_chat_free( ic->groupchats->data );
[c377417]299       
[21167d2]300        if( jd->r_inpa >= 0 )
301                b_event_remove( jd->r_inpa );
302        if( jd->w_inpa >= 0 )
303                b_event_remove( jd->w_inpa );
304       
305        if( jd->ssl )
306                ssl_disconnect( jd->ssl );
307        if( jd->fd >= 0 )
308                closesocket( jd->fd );
309       
[fe7a554]310        if( jd->tx_len )
311                g_free( jd->txq );
312       
[de03374]313        if( jd->node_cache )
314                g_hash_table_destroy( jd->node_cache );
[038d17f]315       
[04a927c]316        jabber_buddy_remove_all( ic );
317       
[70f6aab8]318        xt_free( jd->xt );
319       
[5e202b0]320        g_free( jd->away_message );
[21167d2]321        g_free( jd->username );
322        g_free( jd );
[b5c8a34]323       
324        jabber_connections = g_slist_remove( jabber_connections, ic );
[f06894d]325}
326
[f6c963b]327static int jabber_buddy_msg( struct im_connection *ic, char *who, char *message, int flags )
[f06894d]328{
[0da65d5]329        struct jabber_data *jd = ic->proto_data;
[a21a8ac]330        struct jabber_buddy *bud;
[cc2cb2d]331        struct xt_node *node;
[b9f8b87]332        char *s;
[4a0614e]333        int st;
334       
[bb95d43]335        if( g_strcasecmp( who, JABBER_XMLCONSOLE_HANDLE ) == 0 )
336                return jabber_write( ic, message, strlen( message ) );
337       
[5bd21df]338        if( ( s = strchr( who, '=' ) ) && jabber_chat_by_jid( ic, s + 1 ) )
[b9f8b87]339                bud = jabber_buddy_by_ext_jid( ic, who, 0 );
340        else
[76c85b4c]341                bud = jabber_buddy_by_jid( ic, who, GET_BUDDY_BARE_OK );
[a214954]342       
[4a0614e]343        node = xt_new_node( "body", message, NULL );
[788a1af]344        node = jabber_make_packet( "message", "chat", bud ? bud->full_jid : who, node );
[a21a8ac]345       
[0d3f30f]346        if( bud && ( jd->flags & JFLAG_WANT_TYPING ) &&
[788a1af]347            ( ( bud->flags & JBFLAG_DOES_XEP85 ) ||
348             !( bud->flags & JBFLAG_PROBED_XEP85 ) ) )
[a21a8ac]349        {
350                struct xt_node *act;
351               
352                /* If the user likes typing notification and if we don't know
[788a1af]353                   (and didn't probe before) if this resource supports XEP85,
[abbd8ed]354                   include a probe in this packet now. Also, if we know this
355                   buddy does support XEP85, we have to send this <active/>
356                   tag to tell that the user stopped typing (well, that's what
357                   we guess when s/he pressed Enter...). */
[a21a8ac]358                act = xt_new_node( "active", NULL, NULL );
[47d3ac4]359                xt_add_attr( act, "xmlns", XMLNS_CHATSTATES );
[a21a8ac]360                xt_add_child( node, act );
361               
362                /* Just make sure we do this only once. */
[788a1af]363                bud->flags |= JBFLAG_PROBED_XEP85;
[a21a8ac]364        }
365       
[0da65d5]366        st = jabber_write_packet( ic, node );
[4a0614e]367        xt_free_node( node );
368       
369        return st;
[f06894d]370}
371
[0da65d5]372static GList *jabber_away_states( struct im_connection *ic )
[dd788bb]373{
[5e202b0]374        static GList *l = NULL;
375        int i;
[dd788bb]376       
[5e202b0]377        if( l == NULL )
378                for( i = 0; jabber_away_state_list[i].full_name; i ++ )
379                        l = g_list_append( l, (void*) jabber_away_state_list[i].full_name );
[dd788bb]380       
[5e202b0]381        return l;
[dd788bb]382}
383
[0da65d5]384static void jabber_get_info( struct im_connection *ic, char *who )
[038d17f]385{
[6a1128d]386        struct jabber_buddy *bud;
[038d17f]387       
[76c85b4c]388        bud = jabber_buddy_by_jid( ic, who, GET_BUDDY_FIRST );
[7e83adca]389       
[6a1128d]390        while( bud )
391        {
[63770b4]392                imcb_log( ic, "Buddy %s (%d) information:", bud->full_jid, bud->priority );
393                if( bud->away_state )
394                        imcb_log( ic, "Away state: %s", bud->away_state->full_name );
[daae10f]395                imcb_log( ic, "Status message: %s", bud->away_message ? bud->away_message : "(none)" );
[63770b4]396               
[6a1128d]397                bud = bud->next;
398        }
[1991be6]399       
[0da65d5]400        jabber_get_vcard( ic, bud ? bud->full_jid : who );
[038d17f]401}
402
[0da65d5]403static void jabber_set_away( struct im_connection *ic, char *state_txt, char *message )
[dd788bb]404{
[0da65d5]405        struct jabber_data *jd = ic->proto_data;
[5e202b0]406       
[840bba8]407        /* state_txt == NULL -> Not away.
408           Unknown state -> fall back to the first defined away state. */
[daae10f]409        if( state_txt == NULL )
410                jd->away_state = NULL;
411        else if( ( jd->away_state = jabber_away_state_by_name( state_txt ) ) == NULL )
412                jd->away_state = jabber_away_state_list;
[840bba8]413       
[5e202b0]414        g_free( jd->away_message );
415        jd->away_message = ( message && *message ) ? g_strdup( message ) : NULL;
416       
[0da65d5]417        presence_send_update( ic );
[deff040]418}
419
[0da65d5]420static void jabber_add_buddy( struct im_connection *ic, char *who, char *group )
[cfbb3a6]421{
[bb95d43]422        struct jabber_data *jd = ic->proto_data;
423       
424        if( g_strcasecmp( who, JABBER_XMLCONSOLE_HANDLE ) == 0 )
425        {
426                jd->flags |= JFLAG_XMLCONSOLE;
427                imcb_add_buddy( ic, JABBER_XMLCONSOLE_HANDLE, NULL );
428                return;
429        }
430       
[46d215d]431        if( jabber_add_to_roster( ic, who, NULL, group ) )
[0da65d5]432                presence_send_request( ic, who, "subscribe" );
[cfbb3a6]433}
434
[0da65d5]435static void jabber_remove_buddy( struct im_connection *ic, char *who, char *group )
[cfbb3a6]436{
[bb95d43]437        struct jabber_data *jd = ic->proto_data;
438       
439        if( g_strcasecmp( who, JABBER_XMLCONSOLE_HANDLE ) == 0 )
440        {
441                jd->flags &= ~JFLAG_XMLCONSOLE;
[a3d5766]442                /* Not necessary for now. And for now the code isn't too
443                   happy if the buddy is completely gone right after calling
444                   this function already.
[998b103]445                imcb_remove_buddy( ic, JABBER_XMLCONSOLE_HANDLE, NULL );
[a3d5766]446                */
[bb95d43]447                return;
448        }
449       
[788a1af]450        /* We should always do this part. Clean up our administration a little bit. */
[0da65d5]451        jabber_buddy_remove_bare( ic, who );
[788a1af]452       
[0da65d5]453        if( jabber_remove_from_roster( ic, who ) )
454                presence_send_request( ic, who, "unsubscribe" );
[cfbb3a6]455}
456
[03f3828]457static struct groupchat *jabber_chat_join_( struct im_connection *ic, const char *room, const char *nick, const char *password, set_t **sets )
[e35d1a1]458{
459        if( strchr( room, '@' ) == NULL )
460                imcb_error( ic, "Invalid room name: %s", room );
[5bd21df]461        else if( jabber_chat_by_jid( ic, room ) )
[e35d1a1]462                imcb_error( ic, "Already present in chat `%s'", room );
463        else
[6d544a1]464                return jabber_chat_join( ic, room, nick, set_getstr( sets, "password" ) );
[e35d1a1]465       
466        return NULL;
467}
468
[43671b9]469static void jabber_chat_msg_( struct groupchat *c, char *message, int flags )
470{
471        if( c && message )
472                jabber_chat_msg( c, message, flags );
473}
474
[ef5c185]475static void jabber_chat_topic_( struct groupchat *c, char *topic )
476{
477        if( c && topic )
478                jabber_chat_topic( c, topic );
479}
480
[e35d1a1]481static void jabber_chat_leave_( struct groupchat *c )
482{
483        if( c )
484                jabber_chat_leave( c, NULL );
485}
486
[c058ff9]487static void jabber_chat_invite_( struct groupchat *c, char *who, char *msg )
488{
489        struct jabber_chat *jc = c->data;
490        gchar *msg_alt = NULL;
491
492        if( msg == NULL )
493                msg_alt = g_strdup_printf( "%s invited you to %s", c->ic->acc->user, jc->name );
494       
495        if( c && who )
496                jabber_chat_invite( c, who, msg ? msg : msg_alt );
497       
498        g_free( msg_alt );
499}
500
[0da65d5]501static void jabber_keepalive( struct im_connection *ic )
[deff040]502{
503        /* Just any whitespace character is enough as a keepalive for XMPP sessions. */
[38ff846]504        if( !jabber_write( ic, "\n", 1 ) )
505                return;
[a214954]506       
[038d17f]507        /* This runs the garbage collection every minute, which means every packet
508           is in the cache for about a minute (which should be enough AFAIK). */
[0da65d5]509        jabber_cache_clean( ic );
[dd788bb]510}
511
[0da65d5]512static int jabber_send_typing( struct im_connection *ic, char *who, int typing )
[a21a8ac]513{
[0da65d5]514        struct jabber_data *jd = ic->proto_data;
[a21a8ac]515        struct jabber_buddy *bud;
516       
517        /* Enable typing notification related code from now. */
518        jd->flags |= JFLAG_WANT_TYPING;
519       
[0da65d5]520        if( ( bud = jabber_buddy_by_jid( ic, who, 0 ) ) == NULL )
[788a1af]521        {
522                /* Sending typing notifications to unknown buddies is
523                   unsupported for now. Shouldn't be a problem, I think. */
524                return 0;
525        }
526       
527        if( bud->flags & JBFLAG_DOES_XEP85 )
[a21a8ac]528        {
529                /* We're only allowed to send this stuff if we know the other
530                   side supports it. */
531               
532                struct xt_node *node;
533                char *type;
534                int st;
535               
[df1fb67]536                if( typing & OPT_TYPING )
[a21a8ac]537                        type = "composing";
[df1fb67]538                else if( typing & OPT_THINKING )
539                        type = "paused";
540                else
541                        type = "active";
[a21a8ac]542               
543                node = xt_new_node( type, NULL, NULL );
[47d3ac4]544                xt_add_attr( node, "xmlns", XMLNS_CHATSTATES );
[a21a8ac]545                node = jabber_make_packet( "message", "chat", bud->full_jid, node );
546               
[0da65d5]547                st = jabber_write_packet( ic, node );
[a21a8ac]548                xt_free_node( node );
549               
550                return st;
551        }
552       
553        return 1;
554}
555
[6d544a1]556void jabber_chat_add_settings( account_t *acc, set_t **head )
557{
558        /* Meh. Stupid room passwords. Not trying to obfuscate/hide
559           them from the user for now. */
560        set_add( head, "password", NULL, NULL, NULL );
561}
562
563void jabber_chat_free_settings( account_t *acc, set_t **head )
564{
565        set_del( head, "password" );
566}
567
[d88c92a]568GList *jabber_buddy_action_list( bee_user_t *bu )
569{
570        static GList *ret = NULL;
571       
572        if( ret == NULL )
573        {
[a97a336]574                static const struct buddy_action ba[2] = {
[d88c92a]575                        { "VERSION", "Get client (version) information" },
576                };
577               
[a97a336]578                ret = g_list_prepend( ret, (void*) ba + 0 );
[d88c92a]579        }
580       
581        return ret;
582}
583
584void *jabber_buddy_action( struct bee_user *bu, const char *action, char * const args[], void *data )
585{
586        if( g_strcasecmp( action, "VERSION" ) == 0 )
587        {
588                struct jabber_buddy *bud;
589               
590                if( ( bud = jabber_buddy_by_ext_jid( bu->ic, bu->handle, 0 ) ) == NULL )
591                        bud = jabber_buddy_by_jid( bu->ic, bu->handle, GET_BUDDY_FIRST );
592                for( ; bud; bud = bud->next )
593                        jabber_iq_version_send( bu->ic, bud, data );
594        }
595       
596        return NULL;
597}
598
[0da65d5]599void jabber_initmodule()
[f06894d]600{
[deff040]601        struct prpl *ret = g_new0( struct prpl, 1 );
[f06894d]602       
603        ret->name = "jabber";
[6d544a1]604        ret->mms = 0;                        /* no limit */
[f06894d]605        ret->login = jabber_login;
[0da65d5]606        ret->init = jabber_init;
607        ret->logout = jabber_logout;
[f6c963b]608        ret->buddy_msg = jabber_buddy_msg;
[dd788bb]609        ret->away_states = jabber_away_states;
610        ret->set_away = jabber_set_away;
[f06894d]611//      ret->set_info = jabber_set_info;
[038d17f]612        ret->get_info = jabber_get_info;
[cfbb3a6]613        ret->add_buddy = jabber_add_buddy;
614        ret->remove_buddy = jabber_remove_buddy;
[43671b9]615        ret->chat_msg = jabber_chat_msg_;
[ef5c185]616        ret->chat_topic = jabber_chat_topic_;
[c058ff9]617        ret->chat_invite = jabber_chat_invite_;
[e35d1a1]618        ret->chat_leave = jabber_chat_leave_;
619        ret->chat_join = jabber_chat_join_;
[6d544a1]620        ret->chat_add_settings = jabber_chat_add_settings;
621        ret->chat_free_settings = jabber_chat_free_settings;
[deff040]622        ret->keepalive = jabber_keepalive;
[a21a8ac]623        ret->send_typing = jabber_send_typing;
[f06894d]624        ret->handle_cmp = g_strcasecmp;
[2ff2076]625        ret->transfer_request = jabber_si_transfer_request;
[d88c92a]626        ret->buddy_action_list = jabber_buddy_action_list;
627        ret->buddy_action = jabber_buddy_action;
[f06894d]628
[deff040]629        register_protocol( ret );
[f06894d]630}
Note: See TracBrowser for help on using the repository browser.