Changes in / [348c11b:ae3c4fa]


Ignore:
Files:
8 added
28 deleted
58 edited

Legend:

Unmodified
Added
Removed
  • Makefile

    r348c11b rae3c4fa  
    1212objects = account.o bitlbee.o conf.o crypting.o help.o ipc.o irc.o irc_commands.o log.o nick.o query.o root_commands.o set.o storage.o $(STORAGE_OBJS) unix.o user.o
    1313headers = account.h bitlbee.h commands.h conf.h config.h crypting.h help.h ini.h ipc.h irc.h log.h nick.h query.h set.h sock.h storage.h url.h user.h protocols/http_client.h protocols/md5.h protocols/nogaim.h protocols/proxy.h protocols/sha.h protocols/ssl_client.h
    14 subdirs = protocols lib
     14subdirs = lib protocols
    1515
    1616# Expansion of variables
     
    4545        rm -f Makefile.settings config.h bitlbee.pc
    4646        find . -name 'DEADJOE' -o -name '*.orig' -o -name '*.rej' -o -name '*~' -exec rm -f {} \;
    47         $(MAKE) -C test distclean
     47        $(MAKE) -C tests distclean
    4848
    4949check: all
  • account.c

    r348c11b rae3c4fa  
    6565        /* This function adds some more settings (and might want to do more
    6666           things that have to be done now, although I can't think of anything. */
    67         if( prpl->acc_init )
    68                 prpl->acc_init( a );
     67        if( prpl->init )
     68                prpl->init( a );
    6969       
    7070        return( a );
     
    7676       
    7777        /* Double-check: We refuse to edit on-line accounts. */
    78         if( set->flags & ACC_SET_OFFLINE_ONLY && acc->gc )
     78        if( set->flags & ACC_SET_OFFLINE_ONLY && acc->ic )
    7979                return NULL;
    8080       
     
    180180                if( a == acc )
    181181                {
    182                         if( a->gc ) return; /* Caller should have checked, accounts still in use can't be deleted. */
     182                        if( a->ic ) return; /* Caller should have checked, accounts still in use can't be deleted. */
    183183                       
    184184                        if( l )
     
    209209void account_on( irc_t *irc, account_t *a )
    210210{
    211         if( a->gc )
     211        if( a->ic )
    212212        {
    213213                /* Trying to enable an already-enabled account */
     
    223223void account_off( irc_t *irc, account_t *a )
    224224{
    225         a->gc->wants_to_die = TRUE;
    226         signoff( a->gc );
    227         a->gc = NULL;
     225        imc_logout( a->ic, FALSE );
     226        a->ic = NULL;
    228227        if( a->reconnect )
    229228        {
  • account.h

    r348c11b rae3c4fa  
    4141       
    4242        struct irc *irc;
    43         struct gaim_connection *gc;
     43        struct im_connection *ic;
    4444        struct account *next;
    4545} account_t;
  • bitlbee.c

    r348c11b rae3c4fa  
    6969       
    7070#ifdef IPV6
     71        memset( &listen_addr6, 0, sizeof( listen_addr6 ) );
    7172        listen_addr6.sin6_family = AF_INET6;
    7273        listen_addr6.sin6_port = htons( global.conf->port );
     
    7677                use_ipv6 = 0;
    7778#endif
     79                memset( &listen_addr, 0, sizeof( listen_addr ) );
    7880                listen_addr.sin_family = AF_INET;
    7981                listen_addr.sin_port = htons( global.conf->port );
  • bitlbee.h

    r348c11b rae3c4fa  
    3030
    3131#define PACKAGE "BitlBee"
    32 #define BITLBEE_VERSION "BZR"
     32#define BITLBEE_VERSION "1.1dev"
    3333#define VERSION BITLBEE_VERSION
    3434
  • conf.c

    r348c11b rae3c4fa  
    6363        conf->configdir = g_strdup( CONFIG );
    6464        conf->plugindir = g_strdup( PLUGINDIR );
    65         conf->pidfile = g_strdup( "/var/run/bitlbee.pid" );
     65        conf->pidfile = g_strdup( PIDFILE );
    6666        conf->motdfile = g_strdup( ETCDIR "/motd.txt" );
    6767        conf->ping_interval = 180;
     
    132132                else if( opt == 'h' )
    133133                {
    134                         printf( "Usage: bitlbee [-D [-i <interface>] [-p <port>] [-n] [-v]] [-I]\n"
     134                        printf( "Usage: bitlbee [-D/-F [-i <interface>] [-p <port>] [-n] [-v]] [-I]\n"
    135135                                "               [-c <file>] [-d <dir>] [-h]\n"
    136136                                "\n"
  • configure

    r348c11b rae3c4fa  
    1818libevent='/usr/'
    1919pidfile='/var/run/bitlbee.pid'
    20 ipcsocket='/var/run/bitlbee'
     20ipcsocket='/var/run/bitlbee.sock'
    2121pcdir='$prefix/lib/pkgconfig'
    2222
     
    107107PLUGINDIR=$plugindir
    108108CONFIG=$config
    109 IPCSOCKET=$ipcsocket
    110109INCLUDEDIR=$includedir
    111110PCDIR=$pcdir
     
    330329echo 'SSL_CLIENT=ssl_'$ssl'.o' >> Makefile.settings
    331330
     331for i in /lib /usr/lib /usr/local/lib; do
     332        if [ -e $i/libresolv.a ]; then
     333                echo '#define HAVE_RESOLV_A' >> config.h
     334                echo 'EFLAGS+='$i'/libresolv.a' >> Makefile.settings
     335                break
     336        fi
     337done
     338
    332339STORAGES="text xml"
    333340
     
    339346        echo "#undef WITH_LDAP" >> config.h
    340347elif [ "$ldap" = 1 ]; then
     348        echo
     349        echo 'LDAP support is a work in progress and does NOT work AT ALL right now.'
     350        echo
     351        exit 1
     352       
    341353        echo "#define WITH_LDAP 1" >> config.h
    342354        STORAGES="$STORAGES ldap"
     
    465477        echo 'STRIP=\# skip strip' >> Makefile.settings
    466478;;
     479AIX )
     480        echo 'EFLAGS+=-Wl,-brtl' >> Makefile.settings
     481;;
    467482CYGWIN* )
    468483        echo 'Cygwin is not officially supported.'
  • doc/CHANGES

    r348c11b rae3c4fa  
    1 Version x.x:
     1Version 1.1dev:
     2- First BitlBee development/testing RELEASE. This should be quite stable
     3  though (and for most people more stable than 1.0.x). It just has a couple
     4  of rough edges and needs a bit more testing.
    25- Added ForkDaemon mode next to the existing Daemon- and inetd modes. With
    36  ForkDaemon you can run BitlBee as a stand-alone daemon and every connection
     
    1922  I/O as much as possible, fixed lots of little bugs (including bugs that
    2023  affected daemon mode stability). See the bzr logs for more information.
     24- Added units tests, will have to add some more before the real release.
    2125- Most important change: New file format for user data (accounts, nicks and
    2226  settings). Migration to the new format should happen transparently,
     
    4145    and password for the existing connection.
    4246  * Per-account settings (see the new "account set" command).
     47- A brand new Jabber module. Besides the major code cleanup, it also has
     48  has these new features:
     49  * Pretty complete XMPP support: RFC3920, RFC3921 plus a number of XEPs
     50    including XEP73 and XEP85. (See http://www.xmpp.org/ for what all these
     51    things mean exactly.) Privacy lists are not supported for obvious
     52    reasons.
     53  * This complete support also includes TLS and SASL support and SRV record
     54    lookup. This means that specifying a server tag for connections should
     55    (almost) never be necessary anymore, BitlBee can find the server and can
     56    automatically convert plaintext connections to TLS-encrypted ones.
     57  * XEP85 means typing notifications. The older XEP22 (still used by some
     58    clients including Gaim <2.0) is not supported.
     59  * Better handling of buddies who have more than one resource on-line. As
     60    long as one resource is on-line (and visible), BitlBee will show this.
     61    (The previous module didn't keep track of resources and sent an offline
     62    event as soon as any resource disappears.)
     63  * You can now set your resource priority.
     64  * The info command now gives away state/message information for all
     65    resources available for that buddy. (Of course this only works if the
     66    buddy is in your contact list.)
    4367
    4468Version 1.0.3:
  • doc/CREDITS

    r348c11b rae3c4fa  
    5050- Frank Thieme, for the info-command enhancements and other patches.
    5151- Marcus Dennis, for some bitlbeed enhancements.
    52 - 1nfamus, for security auditing BitlBee code.
     52- infamous41md, for security auditing BitlBee code.
    5353- Tijmen Ruizendaal, for some useful BitlBee-related irssi scripts.
    5454- Ed Schouten, for reporting bugs.
     55- Greg (gropeep.org), for updating the Yahoo! module to fix some issues
     56  that were there for quite some time already.
    5557
    5658- And all other users who help us by sending useful bug reports, positive
  • doc/README

    r348c11b rae3c4fa  
    4747
    4848BitlBee's only real dependency is GLib. This is available on virtually every
    49 platform. Any recent version of GLib (2.0 or higher) will work.
     49platform. Any recent version of GLib (2.4 or higher) will work.
    5050
    5151These days, MSN Messenger clients have to connect to the MS Passport servers
     
    184184file COPYING for this license.
    185185
    186 Unfortunately some parts of the Gaim Jabber plugin (most notably the XML
    187 code) were licensed under the MPL (Mozilla Public License) version 1.1. We
    188 could not relicense this code under the GPL. As such it is still licensed
    189 under the MPL. The parts of the code to which this applies are marked as
    190 such.
    191 
    192 The MPL is provided in the file MPL-1.1.txt. This license is not GPL
    193 compatible. It is however a free software license.
    194 
    195 Another part (the md5 algorithm) is licensed under the Aladdin license.
    196 This license can be found in the files, to which this applies.
     186The MD5 algorithm code is licensed under the Aladdin license. This license
     187can be found in the files, to which this applies. The SHA1 algorithm code
     188is licensed under the Mozilla Public License, see http://www.mozilla.org/MPL/
     189for details.
    197190
    198191The Yahoo! library used by BitlBee is libyahoo2 <http://libyahoo2.sf.net/>,
     
    202195        BitlBee - An IRC to other chat networks gateway
    203196                  <http://www.bitlbee.org/>
    204         Copyright (C) 2002-2006  Wilmer van der Gaast <wilmer@gaast.net>
     197        Copyright (C) 2002-2007  Wilmer van der Gaast <wilmer@gaast.net>
    205198                                 and others
  • doc/bitlbee.8

    r348c11b rae3c4fa  
    6363waits for new connections. All clients will be served from one process.
    6464This is still experimental. See the note above for more information.
     65.IP "-F"
     66Run in ForkDaemon mode. This is similar to ordinary daemon mode, but every
     67client gets its own process. Easier to set up than inetd mode, but without
     68the possible stability issues.
    6569.IP "-i \fIaddress\fP"
    6670Only useful when running in daemon mode, to specify the network interface
  • doc/user-guide/commands.xml

    r348c11b rae3c4fa  
    3030                                <description>
    3131                                        <para>
    32                                                 Note that the servertag argument is optional. You only have to use it if the part after the @ in your handle isn't the hostname of your Jabber server, or if you want to use SSL/connect to a non-standard port number. The format is simple: [&lt;servername&gt;[:&lt;portnumber&gt;][:ssl]].
     32                                                The handle should be a full handle, including the domain name. You can specify a servername if necessary. Normally BitlBee doesn't need this though, since it's able to find out the server by doing DNS SRV lookups.
     33                                        </para>
     34
     35                                        <para>
     36                                                In previous versions it was also possible to specify port numbers and/or SSL in the server tag. This is deprecated and should now be done using the <emphasis>account set</emphasis> command. This also applies to specifying a resource in the handle (like <emphasis>wilmer@bitlbee.org/work</emphasis>).
    3337                                        </para>
    3438                                </description>
    35 
    36                                 <description>
    37                                         <para>
    38                                                 Google Talk uses the Jabber protocol. Please note that Google talk is SSL-only, but officially reachable over both port 5222 and 5223. Usually BitlBee users have to connect via port 5223, for example like this:
    39                                         </para>
    40                                 </description>
    41 
    42                                 <ircexample>
    43                                         <ircline nick="wilmer">account add jabber example@gmail.com hobbelmeeuw talk.google.com:5223:ssl</ircline>
    44                                         <ircline nick="root">Account successfully added</ircline>
    45                                 </ircexample>
    4639                        </bitlbee-command>
    4740
     
    517510        </bitlbee-setting>
    518511
     512        <bitlbee-setting name="priority" type="integer" scope="account">
     513                <default>0</default>
     514
     515                <description>
     516                        <para>
     517                                Can be set for Jabber connections. When connecting to one account from multiple places, this priority value will help the server to determine where to deliver incoming messages (that aren't addressed to a specific resource already).
     518                        </para>
     519
     520                        <para>
     521                                According to RFC 3921 servers will always deliver messages to the server with the highest priority value. Mmessages will not be delivered to resources with a negative priority setting (and should be saved as an off-line message if all available resources have a negative priority value).
     522                        </para>
     523                </description>
     524        </bitlbee-setting>
     525
    519526        <bitlbee-setting name="private" type="boolean" scope="global">
    520527                <default>true</default>
     
    556563        </bitlbee-setting>
    557564
     565        <bitlbee-setting name="resource_select" type="string" scope="account">
     566                <default>priority</default>
     567                <possible-values>priority, time</possible-values>
     568
     569                <description>
     570                        <para>
     571                                Because the IRC interface makes it pretty hard to specify the resource to talk to (when a buddy is online through different resources), this setting was added.
     572                        </para>
     573
     574                        <para>
     575                                Normally it's set to <emphasis>priority</emphasis> which means messages will always be delivered to the buddy's resource with the highest priority. If the setting is set to <emphasis>time</emphasis>, messages will be delivered to the resource that was last used to send you a message (or the resource that most recently connected).
     576                        </para>
     577                </description>
     578        </bitlbee-setting>
     579
    558580        <bitlbee-setting name="save_on_quit" type="boolean" scope="global">
    559581                <default>true</default>
     
    593615                        <para>
    594616                                If BitlBee fails to detect this sometimes (most likely in AIM messages over an ICQ connection), you can set this setting to <emphasis>always</emphasis>, but this might sometimes accidentally strip non-HTML things too.
     617                        </para>
     618                </description>
     619        </bitlbee-setting>
     620
     621        <bitlbee-setting name="tls" type="boolean" scope="account">
     622                <default>try</default>
     623
     624                <description>
     625                        <para>
     626                                Newer Jabber servers allow clients to convert a plain-text session to a TLS/SSL-encrypted session. Normally (with this setting set to <emphasis>try</emphasis>) BitlBee will do this, if possible.
     627                        </para>
     628
     629                        <para>
     630                                If you want to force BitlBee to use TLS sessions only (and to give up if that doesn't seem to be possible) you can set this setting to <emphasis>true</emphasis>. Set it to <emphasis>false</emphasis> if you want the session to remain plain-text.
    595631                        </para>
    596632                </description>
     
    775811        </bitlbee-command>
    776812
    777         <bitlbee-command name="import_buddies">
    778                 <short-description>Copy local buddy list to server (normally only needed when upgrading)</short-description>
    779                 <syntax>import_buddies &lt;connection&gt; [clear]</syntax>
    780 
    781                 <description>
    782                         <para>
    783                                 This command copies the locally stored buddy list to the server. This command exists for upgrading purposes. Previous versions of BitlBee didn't support server-side buddy lists for ICQ, so the list was stored locally.
    784                         </para>
    785 
    786                         <para>
    787                                 Since version 0.91 however, server-side contact lists are supported for all protocols, so the local list is now ignored. When upgrading from an older BitlBee to version 0.91, you might need this command to get your buddy list back.
    788                         </para>
    789 
    790                         <para>
    791                                 The only argument this command needs is your ICQ account identification. If your serverside buddy list contains some old buddies you don't want anymore, you can pass <emphasis>clear</emphasis> as a second argument.
    792                         </para>
    793 
    794                         <para>
    795                                 After giving this command, you have to wait for a while before all the adds are handled, because of ICQ's rate limiting. If your buddy list is very large and the ICQ server starts complaining, you might have to reconnect and enter this command again.
    796                         </para>
    797                 </description>
     813        <bitlbee-command name="join_chat">
     814                <short-description>Join a named groupchat/conference room</short-description>
     815                <syntax>import_buddies &lt;connection&gt; &lt;room name&gt; [&lt;channel name&gt;] [&lt;room nickname&gt;] [&lt;password&gt;]</syntax>
     816
     817                <description>
     818                        <para>
     819                                On most IM-networks groupchats can be started using the /join command. (<emphasis>/join #foo</emphasis> to start a chatroom with you and <emphasis>foo</emphasis>) This doesn't work with names groupchats though (which exist on Jabber networks and AIM, for example), instead you can use this command.
     820                        </para>
     821
     822                        <para>
     823                                The first two arguments are required. <emphasis>room name</emphasis> is the name of the chatroom on the IM-network. <emphasis>channel name</emphasis> is the IRC channel name BitlBee should map this to. <emphasis>room nickname</emphasis> is the nickname you want to have in this channel. If you don't give these options, BitlBee will do the right guesses.
     824                        </para>
     825
     826                        <para>
     827                                The following command will join you to the chatroom called <emphasis>bitlbee@conference.bitlbee.org</emphasis>. The channel will be called <emphasis>&amp;bitlbee-help</emphasis> because <emphasis>&amp;bitlbee</emphasis> will already be in use. Your nickname will be <emphasis>help-me</emphasis>.
     828                        </para>
     829                </description>
     830
     831                <ircexample>
     832                        <ircline nick="wilmer">join_chat jabber bitlbee@conference.bitlbee.org &amp;bitlbee-help help-me</ircline>
     833                </ircexample>
    798834
    799835        </bitlbee-command>
  • irc.c

    r348c11b rae3c4fa  
    230230       
    231231        for (account = irc->accounts; account; account = account->next) {
    232                 if (account->gc) {
    233                         account->gc->wants_to_die = TRUE;
    234                         signoff(account->gc);
     232                if (account->ic) {
     233                        imc_logout(account->ic, TRUE);
    235234                } else if (account->reconnect) {
    236235                        cancel_auto_reconnect(account);
     
    256255       
    257256        while (irc->accounts)
    258                 account_del(irc, irc->accounts);
     257                if (irc->accounts->ic == NULL)
     258                        account_del(irc, irc->accounts);
     259                else
     260                        /* Nasty hack, but account_del() doesn't work in this
     261                           case and we don't want infinite loops, do we? ;-) */
     262                        irc->accounts = irc->accounts->next;
    259263       
    260264        while (irc->set)
     
    628632        user_t *u;
    629633        char namelist[385] = "";
    630         struct conversation *c = NULL;
     634        struct groupchat *c = NULL;
    631635        char *ops = set_getstr( &irc->set, "ops" );
    632636       
     
    644648                        }
    645649                       
    646                         if( u->gc && !u->away && set_getbool( &irc->set, "away_devoice" ) )
     650                        if( u->ic && !u->away && set_getbool( &irc->set, "away_devoice" ) )
    647651                                strcat( namelist, "+" );
    648652                        else if( ( strcmp( u->nick, irc->mynick ) == 0 && ( strcmp( ops, "root" ) == 0 || strcmp( ops, "both" ) == 0 ) ) ||
     
    654658                }
    655659        }
    656         else if( ( c = conv_findchannel( channel ) ) )
     660        else if( ( c = chat_by_channel( channel ) ) )
    657661        {
    658662                GList *l;
     
    663667                                                 strcmp( ops, "user" ) == 0 || strcmp( ops, "both" ) ? "@" : "", irc->nick );
    664668               
    665                 for( l = c->in_room; l; l = l->next ) if( ( u = user_findhandle( c->gc, l->data ) ) )
     669                for( l = c->in_room; l; l = l->next ) if( ( u = user_findhandle( c->ic, l->data ) ) )
    666670                {
    667671                        if( strlen( namelist ) + strlen( u->nick ) > sizeof( namelist ) - 4 )
     
    807811        else
    808812        {
    809                 struct conversation *c = conv_findchannel( channel );
     813                struct groupchat *c = chat_by_channel( channel );
    810814               
    811815                if( c )
     
    906910        char reason[128];
    907911       
    908         if( u->gc && u->gc->flags & OPT_LOGGING_OUT )
    909         {
    910                 if( u->gc->acc->server )
     912        if( u->ic && u->ic->flags & OPT_LOGGING_OUT )
     913        {
     914                if( u->ic->acc->server )
    911915                        g_snprintf( reason, sizeof( reason ), "%s %s", irc->myhost,
    912                                     u->gc->acc->server );
    913                 else if( ( s = strchr( u->gc->username, '@' ) ) )
     916                                    u->ic->acc->server );
     917                else if( ( s = strchr( u->ic->acc->user, '@' ) ) )
    914918                        g_snprintf( reason, sizeof( reason ), "%s %s", irc->myhost,
    915919                                    s + 1 );
    916920                else
    917921                        g_snprintf( reason, sizeof( reason ), "%s %s.%s", irc->myhost,
    918                                     u->gc->acc->prpl->name, irc->myhost );
     922                                    u->ic->acc->prpl->name, irc->myhost );
    919923               
    920924                /* proto_opt might contain garbage after the : */
     
    940944int irc_send( irc_t *irc, char *nick, char *s, int flags )
    941945{
    942         struct conversation *c = NULL;
     946        struct groupchat *c = NULL;
    943947        user_t *u = NULL;
    944948       
    945949        if( *nick == '#' || *nick == '&' )
    946950        {
    947                 if( !( c = conv_findchannel( nick ) ) )
     951                if( !( c = chat_by_channel( nick ) ) )
    948952                {
    949953                        irc_reply( irc, 403, "%s :Channel does not exist", nick );
     
    992996                else if( g_strncasecmp( s + 1, "TYPING", 6 ) == 0 )
    993997                {
    994                         if( u && u->gc && u->gc->acc->prpl->send_typing && strlen( s ) >= 10 )
     998                        if( u && u->ic && u->ic->acc->prpl->send_typing && strlen( s ) >= 10 )
    995999                        {
    9961000                                time_t current_typing_notice = time( NULL );
     
    9981002                                if( current_typing_notice - u->last_typing_notice >= 5 )
    9991003                                {
    1000                                         u->gc->acc->prpl->send_typing( u->gc, u->handle, s[8] == '1' );
     1004                                        u->ic->acc->prpl->send_typing( u->ic, u->handle, ( s[8] - '0' ) << 8 );
    10011005                                        u->last_typing_notice = current_typing_notice;
    10021006                                }
     
    10311035                }
    10321036        }
    1033         else if( c && c->gc && c->gc->acc && c->gc->acc->prpl )
    1034         {
    1035                 return( bim_chat_msg( c->gc, c->id, s ) );
     1037        else if( c && c->ic && c->ic->acc && c->ic->acc->prpl )
     1038        {
     1039                return( imc_chat_msg( c, s, 0 ) );
    10361040        }
    10371041       
     
    10481052       
    10491053        u->sendbuf[u->sendbuf_len-2] = 0; /* Cut off the last newline */
    1050         bim_buddy_msg( u->gc, u->handle, u->sendbuf, u->sendbuf_flags );
     1054        imc_buddy_msg( u->ic, u->handle, u->sendbuf, u->sendbuf_flags );
    10511055       
    10521056        g_free( u->sendbuf );
     
    10611065void buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags )
    10621066{
    1063         if( !u || !u->gc ) return;
     1067        if( !u || !u->ic ) return;
    10641068       
    10651069        if( set_getbool( &irc->set, "buddy_sendbuffer" ) && set_getint( &irc->set, "buddy_sendbuffer_delay" ) > 0 )
     
    11001104        else
    11011105        {
    1102                 bim_buddy_msg( u->gc, u->handle, msg, flags );
     1106                imc_buddy_msg( u->ic, u->handle, msg, flags );
    11031107        }
    11041108}
  • irc_commands.c

    r348c11b rae3c4fa  
    134134static void irc_cmd_part( irc_t *irc, char **cmd )
    135135{
    136         struct conversation *c;
     136        struct groupchat *c;
    137137       
    138138        if( g_strcasecmp( cmd[1], irc->channel ) == 0 )
     
    144144                irc_join( irc, u, irc->channel );
    145145        }
    146         else if( ( c = conv_findchannel( cmd[1] ) ) )
     146        else if( ( c = chat_by_channel( cmd[1] ) ) )
    147147        {
    148148                user_t *u = user_find( irc, irc->nick );
     
    150150                irc_part( irc, u, c->channel );
    151151               
    152                 if( c->gc )
     152                if( c->ic )
    153153                {
    154154                        c->joined = 0;
    155                         c->gc->acc->prpl->chat_leave( c->gc, c->id );
     155                        c->ic->acc->prpl->chat_leave( c );
    156156                }
    157157        }
     
    173173                        user_t *u = user_find( irc, cmd[1] + 1 );
    174174                       
    175                         if( u && u->gc && u->gc->acc->prpl->chat_open )
     175                        if( u && u->ic && u->ic->acc->prpl->chat_with )
    176176                        {
    177177                                irc_reply( irc, 403, "%s :Initializing groupchat in a different channel", cmd[1] );
    178178                               
    179                                 if( !u->gc->acc->prpl->chat_open( u->gc, u->handle ) )
     179                                if( !u->ic->acc->prpl->chat_with( u->ic, u->handle ) )
    180180                                {
    181181                                        irc_usermsg( irc, "Could not open a groupchat with %s.", u->nick );
     
    201201{
    202202        char *nick = cmd[1], *channel = cmd[2];
    203         struct conversation *c = conv_findchannel( channel );
     203        struct groupchat *c = chat_by_channel( channel );
    204204        user_t *u = user_find( irc, nick );
    205205       
    206         if( u && c && ( u->gc == c->gc ) )
    207                 if( c->gc && c->gc->acc->prpl->chat_invite )
    208                 {
    209                         c->gc->acc->prpl->chat_invite( c->gc, c->id, "", u->handle );
     206        if( u && c && ( u->ic == c->ic ) )
     207                if( c->ic && c->ic->acc->prpl->chat_invite )
     208                {
     209                        c->ic->acc->prpl->chat_invite( c, "", u->handle );
    210210                        irc_reply( irc, 341, "%s %s", nick, channel );
    211211                        return;
     
    263263                        irc->is_private = 1;
    264264                }
    265                 irc_send( irc, cmd[1], cmd[2], ( g_strcasecmp( cmd[0], "NOTICE" ) == 0 ) ? IM_FLAG_AWAY : 0 );
     265                irc_send( irc, cmd[1], cmd[2], ( g_strcasecmp( cmd[0], "NOTICE" ) == 0 ) ? OPT_AWAY : 0 );
    266266        }
    267267}
     
    271271        char *channel = cmd[1];
    272272        user_t *u = irc->users;
    273         struct conversation *c;
     273        struct groupchat *c;
    274274        GList *l;
    275275       
     
    287287                        u = u->next;
    288288                }
    289         else if( ( c = conv_findchannel( channel ) ) )
     289        else if( ( c = chat_by_channel( channel ) ) )
    290290                for( l = c->in_room; l; l = l->next )
    291291                {
    292                         if( ( u = user_findhandle( c->gc, l->data ) ) )
     292                        if( ( u = user_findhandle( c->ic, l->data ) ) )
    293293                                irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->away ? 'G' : 'H', u->realname );
    294294                }
     
    460460        for( a = irc->accounts; a; a = a->next )
    461461        {
    462                 struct gaim_connection *gc = a->gc;
    463                
    464                 if( gc && gc->flags & OPT_LOGGED_IN )
    465                         bim_set_away( gc, u->away );
     462                struct im_connection *ic = a->ic;
     463               
     464                if( ic && ic->flags & OPT_LOGGED_IN )
     465                        imc_set_away( ic, u->away );
    466466        }
    467467}
     
    476476                irc_reply( irc, 311, "%s %s %s * :%s", u->nick, u->user, u->host, u->realname );
    477477               
    478                 if( u->gc )
    479                         irc_reply( irc, 312, "%s %s.%s :%s network", u->nick, u->gc->acc->user,
    480                                    u->gc->acc->server && *u->gc->acc->server ? u->gc->acc->server : "",
    481                                    u->gc->acc->prpl->name );
     478                if( u->ic )
     479                        irc_reply( irc, 312, "%s %s.%s :%s network", u->nick, u->ic->acc->user,
     480                                   u->ic->acc->server && *u->ic->acc->server ? u->ic->acc->server : "",
     481                                   u->ic->acc->prpl->name );
    482482                else
    483483                        irc_reply( irc, 312, "%s %s :%s", u->nick, irc->myhost, IRCD_INFO );
  • lib/misc.c

    r348c11b rae3c4fa  
    3939#include <glib.h>
    4040#include <time.h>
     41
     42#ifdef HAVE_RESOLV_A
     43#include <arpa/nameser.h>
     44#include <resolv.h>
     45#endif
    4146
    4247void strip_linefeed(gchar *text)
     
    488493        return 0;
    489494}
     495
     496struct ns_srv_reply *srv_lookup( char *service, char *protocol, char *domain )
     497{       
     498        struct ns_srv_reply *reply = NULL;
     499#ifdef HAVE_RESOLV_A
     500        char name[1024];
     501        unsigned char querybuf[1024];
     502        const unsigned char *buf;
     503        ns_msg nsh;
     504        ns_rr rr;
     505        int i, len, size;
     506       
     507        g_snprintf( name, sizeof( name ), "_%s._%s.%s", service, protocol, domain );
     508       
     509        if( ( size = res_query( name, ns_c_in, ns_t_srv, querybuf, sizeof( querybuf ) ) ) <= 0 )
     510                return NULL;
     511       
     512        if( ns_initparse( querybuf, size, &nsh ) != 0 )
     513                return NULL;
     514       
     515        if( ns_parserr( &nsh, ns_s_an, 0, &rr ) != 0 )
     516                return NULL;
     517       
     518        size = ns_rr_rdlen( rr );
     519        buf = ns_rr_rdata( rr );
     520       
     521        len = 0;
     522        for( i = 6; i < size && buf[i]; i += buf[i] + 1 )
     523                len += buf[i] + 1;
     524       
     525        if( i > size )
     526                return NULL;
     527       
     528        reply = g_malloc( sizeof( struct ns_srv_reply ) + len );
     529        memcpy( reply->name, buf + 7, len );
     530       
     531        for( i = buf[6]; i < len && buf[7+i]; i += buf[7+i] + 1 )
     532                reply->name[i] = '.';
     533       
     534        if( i > len )
     535        {
     536                g_free( reply );
     537                return NULL;
     538        }
     539       
     540        reply->prio = ( buf[0] << 8 ) | buf[1];
     541        reply->weight = ( buf[2] << 8 ) | buf[3];
     542        reply->port = ( buf[4] << 8 ) | buf[5];
     543#endif
     544       
     545        return reply;
     546}
  • lib/misc.h

    r348c11b rae3c4fa  
    3030#include <time.h>
    3131
     32struct ns_srv_reply
     33{
     34        int prio;
     35        int weight;
     36        int port;
     37        char name[];
     38};
     39
    3240G_MODULE_EXPORT void strip_linefeed( gchar *text );
    3341G_MODULE_EXPORT char *add_cr( char *text );
     
    5462G_MODULE_EXPORT int bool2int( char *value );
    5563
     64G_MODULE_EXPORT struct ns_srv_reply *srv_lookup( char *service, char *protocol, char *domain );
     65
    5666#endif
  • lib/ssl_client.h

    r348c11b rae3c4fa  
    5252G_MODULE_EXPORT void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data );
    5353
     54/* Start an SSL session on an existing fd. Useful for STARTTLS functionality,
     55   for example in Jabber. */
     56G_MODULE_EXPORT void *ssl_starttls( int fd, ssl_input_function func, gpointer data );
     57
    5458/* Obviously you need special read/write functions to read data. */
    5559G_MODULE_EXPORT int ssl_read( void *conn, char *buf, int len );
  • lib/ssl_gnutls.c

    r348c11b rae3c4fa  
    4949
    5050static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond );
     51static gboolean ssl_starttls_real( gpointer data, gint source, b_input_condition cond );
     52static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond );
    5153
    5254
     
    6365        {
    6466                g_free( conn );
    65                 return( NULL );
     67                return NULL;
     68        }
     69       
     70        return conn;
     71}
     72
     73void *ssl_starttls( int fd, ssl_input_function func, gpointer data )
     74{
     75        struct scd *conn = g_new0( struct scd, 1 );
     76       
     77        conn->fd = fd;
     78        conn->func = func;
     79        conn->data = data;
     80        conn->inpa = -1;
     81       
     82        /* This function should be called via a (short) timeout instead of
     83           directly from here, because these SSL calls are *supposed* to be
     84           *completely* asynchronous and not ready yet when this function
     85           (or *_connect, for examle) returns. Also, errors are reported via
     86           the callback function, not via this function's return value.
     87           
     88           In short, doing things like this makes the rest of the code a lot
     89           simpler. */
     90       
     91        b_timeout_add( 1, ssl_starttls_real, conn );
     92       
     93        return conn;
     94}
     95
     96static gboolean ssl_starttls_real( gpointer data, gint source, b_input_condition cond )
     97{
     98        struct scd *conn = data;
     99       
     100        return ssl_connected( conn, conn->fd, GAIM_INPUT_WRITE );
     101}
     102
     103static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond )
     104{
     105        struct scd *conn = data;
     106       
     107        if( source == -1 )
     108        {
     109                conn->func( conn->data, NULL, cond );
     110                g_free( conn );
     111                return FALSE;
    66112        }
    67113       
     
    77123        gnutls_set_default_priority( conn->session );
    78124        gnutls_credentials_set( conn->session, GNUTLS_CRD_CERTIFICATE, conn->xcred );
    79        
    80         return( conn );
    81 }
    82 
    83 static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond );
    84 
    85 static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond )
    86 {
    87         struct scd *conn = data;
    88        
    89         if( source == -1 )
    90         {
    91                 conn->func( conn->data, NULL, cond );
    92                
    93                 gnutls_deinit( conn->session );
    94                 gnutls_certificate_free_credentials( conn->xcred );
    95                
    96                 g_free( conn );
    97                
    98                 return FALSE;
    99         }
    100125       
    101126        sock_make_nonblocking( conn->fd );
  • lib/ssl_openssl.c

    r348c11b rae3c4fa  
    5353
    5454static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond );
     55static gboolean ssl_starttls_real( gpointer data, gint source, b_input_condition cond );
     56static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond );
    5557
    5658
     
    5860{
    5961        struct scd *conn = g_new0( struct scd, 1 );
    60         SSL_METHOD *meth;
    6162       
    6263        conn->fd = proxy_connect( host, port, ssl_connected, conn );
    6364        conn->func = func;
    6465        conn->data = data;
     66        conn->inpa = -1;
    6567       
    6668        if( conn->fd < 0 )
    6769        {
    6870                g_free( conn );
    69                 return( NULL );
    70         }
     71                return NULL;
     72        }
     73       
     74        return conn;
     75}
     76
     77void *ssl_starttls( int fd, ssl_input_function func, gpointer data )
     78{
     79        struct scd *conn = g_new0( struct scd, 1 );
     80       
     81        conn->fd = fd;
     82        conn->func = func;
     83        conn->data = data;
     84        conn->inpa = -1;
     85       
     86        /* This function should be called via a (short) timeout instead of
     87           directly from here, because these SSL calls are *supposed* to be
     88           *completely* asynchronous and not ready yet when this function
     89           (or *_connect, for examle) returns. Also, errors are reported via
     90           the callback function, not via this function's return value.
     91           
     92           In short, doing things like this makes the rest of the code a lot
     93           simpler. */
     94       
     95        b_timeout_add( 1, ssl_starttls_real, conn );
     96       
     97        return conn;
     98}
     99
     100static gboolean ssl_starttls_real( gpointer data, gint source, b_input_condition cond )
     101{
     102        struct scd *conn = data;
     103       
     104        return ssl_connected( conn, conn->fd, GAIM_INPUT_WRITE );
     105}
     106
     107static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond )
     108{
     109        struct scd *conn = data;
     110        SSL_METHOD *meth;
     111       
     112        if( source == -1 )
     113                goto ssl_connected_failure;
    71114       
    72115        if( !initialized )
     
    79122        conn->ssl_ctx = SSL_CTX_new( meth );
    80123        if( conn->ssl_ctx == NULL )
    81         {
    82                 conn->fd = -1;
    83                 return( NULL );
    84         }
     124                goto ssl_connected_failure;
    85125       
    86126        conn->ssl = SSL_new( conn->ssl_ctx );
    87127        if( conn->ssl == NULL )
    88         {
    89                 conn->fd = -1;
    90                 return( NULL );
    91         }
    92        
    93         return( conn );
    94 }
    95 
    96 static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond );
    97 
    98 static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond )
    99 {
    100         struct scd *conn = data;
    101        
    102         if( source == -1 )
    103                 return ssl_handshake( data, -1, cond );
     128                goto ssl_connected_failure;
    104129       
    105130        /* We can do at least the handshake with non-blocking I/O */
     
    108133       
    109134        return ssl_handshake( data, source, cond );
     135
     136ssl_connected_failure:
     137        conn->func( conn->data, NULL, cond );
     138       
     139        if( conn->ssl )
     140        {
     141                SSL_shutdown( conn->ssl );
     142                SSL_free( conn->ssl );
     143        }
     144        if( conn->ssl_ctx )
     145        {
     146                SSL_CTX_free( conn->ssl_ctx );
     147        }
     148        if( source >= 0 ) closesocket( source );
     149        g_free( conn );
     150       
     151        return FALSE;
     152
    110153}       
    111154
     
    119162                conn->lasterr = SSL_get_error( conn->ssl, st );
    120163                if( conn->lasterr != SSL_ERROR_WANT_READ && conn->lasterr != SSL_ERROR_WANT_WRITE )
    121                         goto ssl_connected_failure;
     164                {
     165                        conn->func( conn->data, NULL, cond );
     166                       
     167                        SSL_shutdown( conn->ssl );
     168                        SSL_free( conn->ssl );
     169                        SSL_CTX_free( conn->ssl_ctx );
     170                       
     171                        if( source >= 0 ) closesocket( source );
     172                        g_free( conn );
     173                       
     174                        return FALSE;
     175                }
    122176               
    123177                conn->inpa = b_input_add( conn->fd, ssl_getdirection( conn ), ssl_handshake, data );
     
    129183        conn->func( conn->data, conn, cond );
    130184        return FALSE;
    131        
    132 ssl_connected_failure:
    133         conn->func( conn->data, NULL, cond );
    134        
    135         if( conn->ssl )
    136         {
    137                 SSL_shutdown( conn->ssl );
    138                 SSL_free( conn->ssl );
    139         }
    140         if( conn->ssl_ctx )
    141         {
    142                 SSL_CTX_free( conn->ssl_ctx );
    143         }
    144         if( source >= 0 ) closesocket( source );
    145         g_free( conn );
    146        
    147         return FALSE;
    148185}
    149186
  • motd.txt

    r348c11b rae3c4fa  
    1414The developers of the Bee hope you have a buzzing time.
    1515
    16 * BitlBee development team: wilmer, ctrlsoft, Maurits
     16* BitlBee development team: wilmer, jelmer, Maurits
    1717 
    1818... Buzzing, haha, get it?
  • nick.c

    r348c11b rae3c4fa  
    22  * BitlBee -- An IRC to other IM-networks gateway                     *
    33  *                                                                    *
    4   * Copyright 2002-2006 Wilmer van der Gaast and others                *
     4  * Copyright 2002-2007 Wilmer van der Gaast and others                *
    55  \********************************************************************/
    66
     
    5353}
    5454
    55 char *nick_get( account_t *acc, const char *handle, const char *realname )
     55char *nick_get( account_t *acc, const char *handle )
    5656{
    5757        static char nick[MAX_NICK_LENGTH+1];
     
    7676                        while( *s )
    7777                                *(s++) = 0;
    78                
    79                 /* All-digit handles (mainly ICQ UINs) aren't cool, try to
    80                    use the realname instead. */
    81                 for( s = nick; *s && isdigit( *s ); s ++ );
    82                 if( !*s && realname && *realname )
    83                         g_snprintf( nick, MAX_NICK_LENGTH, "%s", realname );
    8478               
    8579                nick_strip( nick );
     
    130124}
    131125
     126/* Just check if there is a nickname set for this buddy or if we'd have to
     127   generate one. */
     128int nick_saved( account_t *acc, const char *handle )
     129{
     130        char *store_handle, *found;
     131       
     132        store_handle = clean_handle( handle );
     133        found = g_hash_table_lookup( acc->nicks, store_handle );
     134        g_free( store_handle );
     135       
     136        return found != NULL;
     137}
     138
    132139void nick_del( account_t *acc, const char *handle )
    133140{
     
    176183int nick_lc( char *nick )
    177184{
    178         static char tab[256] = { 0 };
     185        static char tab[128] = { 0 };
    179186        int i;
    180187       
  • nick.h

    r348c11b rae3c4fa  
    2525
    2626void nick_set( account_t *acc, const char *handle, const char *nick );
    27 char *nick_get( account_t *acc, const char *handle, const char *realname );
     27char *nick_get( account_t *acc, const char *handle );
     28int nick_saved( account_t *acc, const char *handle );
    2829void nick_del( account_t *acc, const char *handle );
    2930void nick_strip( char *nick );
  • protocols/jabber/Makefile

    r348c11b rae3c4fa  
    1010
    1111# [SH] Program variables
    12 objects = expat.o hashtable.o jid.o jpacket.o jutil.o log.o pool.o str.o xmlnode.o xmlparse.o xmlrole.o xmltok.o jabber.o
     12objects = io.o iq.o jabber.o jabber_util.o message.o presence.o sasl.o xmltree.o
    1313
    1414CFLAGS += -Wall
  • protocols/jabber/jabber.c

    r348c11b rae3c4fa  
    1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
    2 /*
    3  * gaim
    4  *
    5  * Some code copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
    6  * libfaim code copyright 1998, 1999 Adam Fritzler <afritz@auk.cx>
    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
    19  * along with this program; if not, write to the Free Software
    20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    21  *
    22  */
    23 
    24 #ifndef _WIN32
    25 #include <sys/utsname.h>
    26 #endif
    27 #include <errno.h>
     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>
    2825#include <string.h>
    29 #include <stdlib.h>
     26#include <unistd.h>
     27#include <ctype.h>
    3028#include <stdio.h>
    31 #include <time.h>
    32 #include <sys/stat.h>
     29
     30#include "ssl_client.h"
     31#include "xmltree.h"
     32#include "bitlbee.h"
    3333#include "jabber.h"
    34 #include "nogaim.h"
    35 #include "bitlbee.h"
    36 #include "proxy.h"
    37 #include "ssl_client.h"
    38 
    39 /* The priv member of gjconn's is a gaim_connection for now. */
    40 #define GJ_GC(x) ((struct gaim_connection *)(x)->priv)
    41 
    42 #define IQID_AUTH "__AUTH__"
    43 
    44 #define IQ_NONE -1
    45 #define IQ_AUTH 0
    46 #define IQ_ROSTER 1
    47 
    48 #define UC_AWAY (0x02 | UC_UNAVAILABLE)
    49 #define UC_CHAT  0x04
    50 #define UC_XA   (0x08 | UC_UNAVAILABLE)
    51 #define UC_DND  (0x10 | UC_UNAVAILABLE)
    52 
    53 #define DEFAULT_SERVER "jabber.org"
    54 #define DEFAULT_GROUPCHAT "conference.jabber.org"
    55 #define DEFAULT_PORT 5222
    56 #define DEFAULT_PORT_SSL 5223
    57 #define JABBER_PORT_MIN 5220
    58 #define JABBER_PORT_MAX 5229
    59 
    60 #define JABBER_GROUP "Friends"
    61 
    62 /* i18n disabled - Bitlbee */
    63 #define N_(String) String
    64 
    65 /*
    66  * Note: "was_connected" may seem redundant, but it was needed and I
    67  * didn't want to touch the Jabber state stuff not specific to Gaim.
    68  */
    69 typedef struct gjconn_struct {
    70         /* Core structure */
    71         pool p;                 /* Memory allocation pool */
    72         int state;              /* Connection state flag */
    73         int was_connected;      /* We were once connected */
    74         int fd;                 /* Connection file descriptor */
    75         void *ssl;              /* SSL connection */
    76         jid user;               /* User info */
    77         char *pass;             /* User passwd */
    78 
    79         /* Stream stuff */
    80         int id;                 /* id counter for jab_getid() function */
    81         char idbuf[9];          /* temporary storage for jab_getid() */
    82         char *sid;              /* stream id from server, for digest auth */
    83         XML_Parser parser;      /* Parser instance */
    84         xmlnode current;        /* Current node in parsing instance.. */
    85 
    86         /* Event callback ptrs */
    87         void (*on_state)(struct gjconn_struct *gjc, int state);
    88         void (*on_packet)(struct gjconn_struct *gjc, jpacket p);
    89 
    90         GHashTable *queries;    /* query tracker */
    91 
    92         void *priv;
    93 } *gjconn, gjconn_struct;
    94 
    95 typedef void (*gjconn_state_h)(gjconn gjc, int state);
    96 typedef void (*gjconn_packet_h)(gjconn gjc, jpacket p);
    97 
    98 static gjconn gjab_new(char *user, char *pass, void *priv);
    99 static void gjab_delete(gjconn gjc);
    100 static void gjab_state_handler(gjconn gjc, gjconn_state_h h);
    101 static void gjab_packet_handler(gjconn gjc, gjconn_packet_h h);
    102 static void gjab_start(gjconn gjc);
    103 static void gjab_stop(gjconn gjc);
    104 /*
    105 static int gjab_getfd(gjconn gjc);
    106 static jid gjab_getjid(gjconn gjc);
    107 static char *gjab_getsid(gjconn gjc);
    108 */
    109 static char *gjab_getid(gjconn gjc);
    110 static void gjab_send(gjconn gjc, xmlnode x);
    111 static void gjab_send_raw(gjconn gjc, const char *str);
    112 static void gjab_recv(gjconn gjc);
    113 static void gjab_auth(gjconn gjc);
    114 
    115 /*
    116  * It is *this* to which we point the gaim_connection proto_data
    117  */
    118 struct jabber_data {
    119         gjconn gjc;
    120         gboolean did_import;
    121         GSList *chats;
    122         GHashTable *hash;
    123         time_t idle;
    124         gboolean die;
    125 };
    126 
    127 /*
    128  * Jabber "chat group" info.  Pointers to these go in jabber_data
    129  * pending and existing chats lists.
    130  */
    131 struct jabber_chat {
    132         jid Jid;
    133         struct gaim_connection *gc;
    134         struct conversation *b;
    135         int id;
    136         int state;
    137 };
    138 
    139 /*
    140  * Jabber chat states...
    141  *
    142  * Note: due to a bug in one version of the Jabber server, subscriptions
    143  * to chat groups aren't (always?) properly removed at the server.  The
    144  * result is clients receive Jabber "presence" notifications for JIDs
    145  * they no longer care about.  The problem with such vestigial notifies is
    146  * that we really have no way of telling if it's vestigial or if it's a
    147  * valid "buddy" presence notification.  So we keep jabber_chat structs
    148  * around after leaving a chat group and simply mark them "closed."  That
    149  * way we can test for such errant presence notifications.  I.e.: if we
    150  * get a presence notfication from a JID that matches a chat group JID,
    151  * we disregard it.
    152  */
    153 #define JCS_PENDING 1   /* pending */
    154 #define JCS_ACTIVE  2   /* active */
    155 #define JCS_CLOSED  3   /* closed */
    156 
    157 
    158 #define STATE_EVT(arg) if(gjc->on_state) { (gjc->on_state)(gjc, (arg) ); }
    159 
    160 static void jabber_remove_buddy(struct gaim_connection *gc, char *name, char *group);
    161 static void jabber_handlevcard(gjconn gjc, xmlnode querynode, char *from);
    162 
    163 static char *create_valid_jid(const char *given, char *server, char *resource)
    164 {
    165         char *valid;
    166 
    167         if (!strchr(given, '@'))
    168                 valid = g_strdup_printf("%s@%s/%s", given, server, resource);
    169         else if (!strchr(strchr(given, '@'), '/'))
    170                 valid = g_strdup_printf("%s/%s", given, resource);
    171         else
    172                 valid = g_strdup(given);
    173 
    174         return valid;
    175 }
    176 
    177 static gjconn gjab_new(char *user, char *pass, void *priv)
    178 {
    179         pool p;
    180         gjconn gjc;
    181 
    182         if (!user)
    183                 return (NULL);
    184 
    185         p = pool_new();
    186         if (!p)
    187                 return (NULL);
    188         gjc = pmalloc_x(p, sizeof(gjconn_struct), 0);
    189         if (!gjc) {
    190                 pool_free(p);   /* no need for this anymore! */
    191                 return (NULL);
    192         }
    193         gjc->p = p;
    194 
    195         if((gjc->user = jid_new(p, user)) == NULL) {
    196                 pool_free(p);   /* no need for this anymore! */
    197                 return (NULL);
    198         }
    199         gjc->pass = pstrdup(p, pass);
    200 
    201         gjc->state = JCONN_STATE_OFF;
    202         gjc->was_connected = 0;
    203         gjc->id = 1;
    204         gjc->fd = -1;
    205 
    206         gjc->priv = priv;
    207 
    208         return gjc;
    209 }
    210 
    211 static void gjab_delete(gjconn gjc)
    212 {
    213         if (!gjc)
     34
     35static void jabber_init( account_t *acc )
     36{
     37        set_t *s;
     38       
     39        s = set_add( &acc->set, "port", JABBER_PORT_DEFAULT, set_eval_int, acc );
     40        s->flags |= ACC_SET_OFFLINE_ONLY;
     41       
     42        s = set_add( &acc->set, "priority", "0", set_eval_priority, acc );
     43       
     44        s = set_add( &acc->set, "resource", "BitlBee", NULL, acc );
     45        s->flags |= ACC_SET_OFFLINE_ONLY;
     46       
     47        s = set_add( &acc->set, "resource_select", "priority", NULL, acc );
     48       
     49        s = set_add( &acc->set, "server", NULL, set_eval_account, acc );
     50        s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY;
     51       
     52        s = set_add( &acc->set, "ssl", "false", set_eval_bool, acc );
     53        s->flags |= ACC_SET_OFFLINE_ONLY;
     54       
     55        s = set_add( &acc->set, "tls", "try", set_eval_tls, acc );
     56        s->flags |= ACC_SET_OFFLINE_ONLY;
     57}
     58
     59static void jabber_login( account_t *acc )
     60{
     61        struct im_connection *ic = imcb_new( acc );
     62        struct jabber_data *jd = g_new0( struct jabber_data, 1 );
     63        struct ns_srv_reply *srv = NULL;
     64        char *connect_to, *s;
     65       
     66        jd->ic = ic;
     67        ic->proto_data = jd;
     68       
     69        jd->username = g_strdup( acc->user );
     70        jd->server = strchr( jd->username, '@' );
     71       
     72        if( jd->server == NULL )
     73        {
     74                imcb_error( ic, "Incomplete account name (format it like <username@jabberserver.name>)" );
     75                imc_logout( ic, FALSE );
    21476                return;
    215 
    216         gjab_stop(gjc);
    217         pool_free(gjc->p);
    218 }
    219 
    220 static void gjab_state_handler(gjconn gjc, gjconn_state_h h)
    221 {
    222         if (!gjc)
    223                 return;
    224 
    225         gjc->on_state = h;
    226 }
    227 
    228 static void gjab_packet_handler(gjconn gjc, gjconn_packet_h h)
    229 {
    230         if (!gjc)
    231                 return;
    232 
    233         gjc->on_packet = h;
    234 }
    235 
    236 static void gjab_stop(gjconn gjc)
    237 {
    238         if (!gjc || gjc->state == JCONN_STATE_OFF)
    239                 return;
    240 
    241         gjab_send_raw(gjc, "</stream:stream>");
    242         gjc->state = JCONN_STATE_OFF;
    243         gjc->was_connected = 0;
    244         if (gjc->ssl) {
    245                 ssl_disconnect(gjc->ssl);
    246                 gjc->ssl = NULL;
    247         } else {
    248                 closesocket(gjc->fd);
    249         }
    250         gjc->fd = -1;
    251         XML_ParserFree(gjc->parser);
    252         gjc->parser = NULL;
    253 }
    254 
    255 /*
    256 static int gjab_getfd(gjconn gjc)
    257 {
    258         if (gjc)
    259                 return gjc->fd;
    260         else
    261                 return -1;
    262 }
    263 
    264 static jid gjab_getjid(gjconn gjc)
    265 {
    266         if (gjc)
    267                 return (gjc->user);
    268         else
    269                 return NULL;
    270 }
    271 
    272 static char *gjab_getsid(gjconn gjc)
    273 {
    274         if (gjc)
    275                 return (gjc->sid);
    276         else
    277                 return NULL;
    278 }
    279 */
    280 
    281 static char *gjab_getid(gjconn gjc)
    282 {
    283         g_snprintf(gjc->idbuf, 8, "%d", gjc->id++);
    284         return &gjc->idbuf[0];
    285 }
    286 
    287 static void gjab_send(gjconn gjc, xmlnode x)
    288 {
    289         if (gjc && gjc->state != JCONN_STATE_OFF) {
    290                 char *buf = xmlnode2str(x);
    291                 if (!buf)
    292                         return;
    293                 else if (gjc->ssl)
    294                         ssl_write(gjc->ssl, buf, strlen(buf));
    295                 else
    296                         write(gjc->fd, buf, strlen(buf));
    297         }
    298 }
    299 
    300 static void gjab_send_raw(gjconn gjc, const char *str)
    301 {
    302         if (gjc && gjc->state != JCONN_STATE_OFF) {
    303                 int len;
    304                
    305                 /*
    306                  * JFIXME: No error detection?!?!
    307                  */
    308                 if (gjc->ssl)
    309                         len = ssl_write(gjc->ssl, str, strlen(str));
    310                 else
    311                         len = write(gjc->fd, str, strlen(str));
     77        }
     78       
     79        /* So don't think of free()ing jd->server.. :-) */
     80        *jd->server = 0;
     81        jd->server ++;
     82       
     83        if( ( s = strchr( jd->server, '/' ) ) )
     84        {
     85                *s = 0;
     86                set_setstr( &acc->set, "resource", s + 1 );
     87               
     88                /* Also remove the /resource from the original variable so we
     89                   won't have to do this again every time. */
     90                s = strchr( acc->user, '/' );
     91                *s = 0;
     92        }
     93       
     94        /* This code isn't really pretty. Backwards compatibility never is... */
     95        s = acc->server;
     96        while( s )
     97        {
     98                static int had_port = 0;
     99               
     100                if( strncmp( s, "ssl", 3 ) == 0 )
     101                {
     102                        set_setstr( &acc->set, "ssl", "true" );
    312103                       
    313                 if(len < 0) {
    314                         /* Do NOT write to stdout/stderr directly, IRC clients
    315                            might get confused, and we don't want that...
    316                         fprintf(stderr, "DBG: Problem sending.  Error: %d\n", errno);
    317                         fflush(stderr); */
     104                        /* Flush this part so that (if this was the first
     105                           part of the server string) acc->server gets
     106                           flushed. We don't want to have to do this another
     107                           time. :-) */
     108                        *s = 0;
     109                        s ++;
     110                       
     111                        /* Only set this if the user didn't specify a custom
     112                           port number already... */
     113                        if( !had_port )
     114                                set_setint( &acc->set, "port", 5223 );
    318115                }
    319         }
    320 }
    321 
    322 static void gjab_reqroster(gjconn gjc)
    323 {
    324         xmlnode x;
    325 
    326         x = jutil_iqnew(JPACKET__GET, NS_ROSTER);
    327         xmlnode_put_attrib(x, "id", gjab_getid(gjc));
    328 
    329         gjab_send(gjc, x);
    330         xmlnode_free(x);
    331 }
    332 
    333 static void gjab_reqauth(gjconn gjc)
    334 {
    335         xmlnode x, y, z;
    336         char *user;
    337 
    338         if (!gjc)
    339                 return;
    340 
    341         x = jutil_iqnew(JPACKET__GET, NS_AUTH);
    342         xmlnode_put_attrib(x, "id", IQID_AUTH);
    343         y = xmlnode_get_tag(x, "query");
    344 
    345         user = gjc->user->user;
    346 
    347         if (user) {
    348                 z = xmlnode_insert_tag(y, "username");
    349                 xmlnode_insert_cdata(z, user, -1);
    350         }
    351 
    352         gjab_send(gjc, x);
    353         xmlnode_free(x);
    354 }
    355 
    356 static void gjab_auth(gjconn gjc)
    357 {
    358         xmlnode x, y, z;
    359         char *hash, *user;
    360 
    361         if (!gjc)
    362                 return;
    363 
    364         x = jutil_iqnew(JPACKET__SET, NS_AUTH);
    365         xmlnode_put_attrib(x, "id", IQID_AUTH);
    366         y = xmlnode_get_tag(x, "query");
    367 
    368         user = gjc->user->user;
    369 
    370         if (user) {
    371                 z = xmlnode_insert_tag(y, "username");
    372                 xmlnode_insert_cdata(z, user, -1);
    373         }
    374 
    375         z = xmlnode_insert_tag(y, "resource");
    376         xmlnode_insert_cdata(z, gjc->user->resource, -1);
    377 
    378         if (gjc->sid) {
    379                 z = xmlnode_insert_tag(y, "digest");
    380                 hash = pmalloc(x->p, strlen(gjc->sid) + strlen(gjc->pass) + 1);
    381                 strcpy(hash, gjc->sid);
    382                 strcat(hash, gjc->pass);
    383                 hash = shahash(hash);
    384                 xmlnode_insert_cdata(z, hash, 40);
    385         } else {
    386                 z = xmlnode_insert_tag(y, "password");
    387                 xmlnode_insert_cdata(z, gjc->pass, -1);
    388         }
    389 
    390         gjab_send(gjc, x);
    391         xmlnode_free(x);
    392 
    393         return;
    394 }
    395 
    396 static void gjab_recv(gjconn gjc)
    397 {
    398         static char buf[4096];
    399         int len;
    400 
    401         if (!gjc || gjc->state == JCONN_STATE_OFF)
    402                 return;
    403        
    404         if (gjc->ssl)
    405                 len = ssl_read(gjc->ssl, buf, sizeof(buf) - 1);
    406         else
    407                 len = read(gjc->fd, buf, sizeof(buf) - 1);
    408        
    409         if (len > 0) {
    410                 struct jabber_data *jd = GJ_GC(gjc)->proto_data;
    411                 buf[len] = '\0';
    412                 XML_Parse(gjc->parser, buf, len, 0);
    413                 if (jd->die)
    414                         signoff(GJ_GC(gjc));
    415         } else if (len == 0 || (len < 0 && (!sockerr_again() || gjc->ssl))) {
    416                 STATE_EVT(JCONN_STATE_OFF)
    417         }
    418 }
    419 
    420 static void startElement(void *userdata, const char *name, const char **attribs)
    421 {
    422         xmlnode x;
    423         gjconn gjc = (gjconn) userdata;
    424 
    425         if (gjc->current) {
    426                 /* Append the node to the current one */
    427                 x = xmlnode_insert_tag(gjc->current, name);
    428                 xmlnode_put_expat_attribs(x, attribs);
    429 
    430                 gjc->current = x;
    431         } else {
    432                 x = xmlnode_new_tag(name);
    433                 xmlnode_put_expat_attribs(x, attribs);
    434                 if (strcmp(name, "stream:stream") == 0) {
    435                         /* special case: name == stream:stream */
    436                         /* id attrib of stream is stored for digest auth */
    437                         gjc->sid = g_strdup(xmlnode_get_attrib(x, "id"));
    438                         /* STATE_EVT(JCONN_STATE_AUTH) */
    439                         xmlnode_free(x);
    440                 } else {
    441                         gjc->current = x;
    442                 }
    443         }
    444 }
    445 
    446 static void endElement(void *userdata, const char *name)
    447 {
    448         gjconn gjc = (gjconn) userdata;
    449         xmlnode x;
    450         jpacket p;
    451 
    452         if (gjc->current == NULL) {
    453                 /* we got </stream:stream> */
    454                 STATE_EVT(JCONN_STATE_OFF)
    455                     return;
    456         }
    457 
    458         x = xmlnode_get_parent(gjc->current);
    459 
    460         if (!x) {
    461                 /* it is time to fire the event */
    462                 p = jpacket_new(gjc->current);
    463 
    464                 if (gjc->on_packet)
    465                         (gjc->on_packet) (gjc, p);
    466                 else
    467                         xmlnode_free(gjc->current);
    468         }
    469 
    470         gjc->current = x;
    471 }
    472 
    473 static gboolean jabber_callback(gpointer data, gint source, b_input_condition condition)
    474 {
    475         struct gaim_connection *gc = (struct gaim_connection *)data;
    476         struct jabber_data *jd = (struct jabber_data *)gc->proto_data;
    477 
    478         gjab_recv(jd->gjc);
    479        
    480         return TRUE;
    481 }
    482 
    483 static void charData(void *userdata, const char *s, int slen)
    484 {
    485         gjconn gjc = (gjconn) userdata;
    486 
    487         if (gjc->current)
    488                 xmlnode_insert_cdata(gjc->current, s, slen);
    489 }
    490 
    491 static gboolean gjab_connected(gpointer data, gint source, b_input_condition cond)
    492 {
    493         xmlnode x;
    494         char *t, *t2;
    495         struct gaim_connection *gc = data;
    496         struct jabber_data *jd;
    497         gjconn gjc;
    498 
    499         if (!g_slist_find(get_connections(), gc)) {
    500                 closesocket(source);
    501                 return FALSE;
    502         }
    503 
    504         jd = gc->proto_data;
    505         gjc = jd->gjc;
    506 
    507         if (gjc->fd != source)
    508                 gjc->fd = source;
    509 
    510         if (source == -1) {
    511                 STATE_EVT(JCONN_STATE_OFF)
    512                 return FALSE;
    513         }
    514 
    515         gjc->state = JCONN_STATE_CONNECTED;
    516         STATE_EVT(JCONN_STATE_CONNECTED)
    517 
    518         /* start stream */
    519         x = jutil_header(NS_CLIENT, gjc->user->server);
    520         t = xmlnode2str(x);
    521         /* this is ugly, we can create the string here instead of jutil_header */
    522         /* what do you think about it? -madcat */
    523         t2 = strstr(t, "/>");
    524         *t2++ = '>';
    525         *t2 = '\0';
    526         gjab_send_raw(gjc, "<?xml version='1.0'?>");
    527         gjab_send_raw(gjc, t);
    528         xmlnode_free(x);
    529 
    530         gjc->state = JCONN_STATE_ON;
    531         STATE_EVT(JCONN_STATE_ON);
    532 
    533         gc = GJ_GC(gjc);
    534         gc->inpa = b_input_add(gjc->fd, GAIM_INPUT_READ, jabber_callback, gc);
    535        
    536         return FALSE;
    537 }
    538 
    539 static gboolean gjab_connected_ssl(gpointer data, void *source, b_input_condition cond)
    540 {
    541         struct gaim_connection *gc = data;
    542         struct jabber_data *jd;
    543         gjconn gjc;
    544        
    545         jd = gc->proto_data;
    546         gjc = jd->gjc;
    547        
    548         if (source == NULL) {
    549                 STATE_EVT(JCONN_STATE_OFF)
    550                 return FALSE;
    551         }
    552        
    553         if (!g_slist_find(get_connections(), gc)) {
    554                 ssl_disconnect(source);
    555                 return FALSE;
    556         }
    557        
    558         return gjab_connected(data, gjc->fd, cond);
    559 }
    560 
    561 static void gjab_start(gjconn gjc)
    562 {
    563         account_t *acc;
    564         int port = -1, ssl = 0;
    565         char *server = NULL;
    566 
    567         if (!gjc || gjc->state != JCONN_STATE_OFF)
    568                 return;
    569 
    570         acc = GJ_GC(gjc)->acc;
    571         server = acc->server;
    572         port = set_getint(&acc->set, "port");
    573         ssl = set_getbool(&acc->set, "ssl");
    574        
    575         if (port < JABBER_PORT_MIN || port > JABBER_PORT_MAX) {
    576                 serv_got_crap(GJ_GC(gjc), "For security reasons, the Jabber port number must be in the %d-%d range.", JABBER_PORT_MIN, JABBER_PORT_MAX);
    577                 STATE_EVT(JCONN_STATE_OFF)
    578                 return;
    579         }
    580        
    581         if (server == NULL)
    582                 server = g_strdup(gjc->user->server);
    583 
    584         gjc->parser = XML_ParserCreate(NULL);
    585         XML_SetUserData(gjc->parser, (void *)gjc);
    586         XML_SetElementHandler(gjc->parser, startElement, endElement);
    587         XML_SetCharacterDataHandler(gjc->parser, charData);
    588        
    589         if (ssl) {
    590                 if ((gjc->ssl = ssl_connect(server, port, gjab_connected_ssl, GJ_GC(gjc))))
    591                         gjc->fd = ssl_getfd(gjc->ssl);
    592                 else
    593                         gjc->fd = -1;
    594         } else {
    595                 gjc->fd = proxy_connect(server, port, gjab_connected, GJ_GC(gjc));
    596         }
    597        
    598         if (!acc->gc || (gjc->fd < 0)) {
    599                 STATE_EVT(JCONN_STATE_OFF)
    600                 return;
    601         }
    602 }
    603 
    604 /*
    605  * Find existing/active Jabber chat
    606  */
    607 static struct jabber_chat *find_existing_chat(struct gaim_connection *gc, jid chat)
    608 {
    609         GSList *jcs = ((struct jabber_data *)gc->proto_data)->chats;
    610         struct jabber_chat *jc = NULL;
    611 
    612         while (jcs) {
    613                 jc = jcs->data;
    614                 if (jc->state == JCS_ACTIVE && !jid_cmpx(chat, jc->Jid, JID_USER | JID_SERVER))
    615                         break;
    616                 jc = NULL;
    617                 jcs = jcs->next;
    618         }
    619 
    620         return jc;
    621 }
    622 
    623 /*
    624  * Find pending chat
    625  */
    626 static struct jabber_chat *find_pending_chat(struct gaim_connection *gc, jid chat)
    627 {
    628         GSList *jcs = ((struct jabber_data *)gc->proto_data)->chats;
    629         struct jabber_chat *jc = NULL;
    630 
    631         while (jcs) {
    632                 jc = jcs->data;
    633                 if (jc->state == JCS_PENDING && !jid_cmpx(chat, jc->Jid, JID_USER | JID_SERVER))
    634                         break;
    635                 jc = NULL;
    636                 jcs = jcs->next;
    637         }
    638 
    639         return jc;
    640 }
    641 
    642 static gboolean find_chat_buddy(struct conversation *b, char *name)
    643 {
    644         GList *m = b->in_room;
    645 
    646         while (m) {
    647                 if (!strcmp(m->data, name))
    648                         return TRUE;
    649                 m = m->next;
    650         }
    651 
    652         return FALSE;
    653 }
    654 
    655 /*
    656  * Remove a buddy from the (gaim) buddylist (if he's on it)
    657  */
    658 static void jabber_remove_gaim_buddy(struct gaim_connection *gc, char *buddyname)
    659 {
    660         struct buddy *b;
    661 
    662         if ((b = find_buddy(gc, buddyname)) != NULL) {
    663                 /* struct group *group;
    664 
    665                 group = find_group_by_buddy(gc, buddyname);
    666                 remove_buddy(gc, group, b); */
    667                 jabber_remove_buddy(gc, b->name, JABBER_GROUP);
    668         }
    669 }
    670 
    671 /*
    672  * keep track of away msg same as yahoo plugin
    673  */
    674 static void jabber_track_away(gjconn gjc, jpacket p, char *name, char *type)
    675 {
    676         struct jabber_data *jd = GJ_GC(gjc)->proto_data;
    677         gpointer val = g_hash_table_lookup(jd->hash, name);
    678         char *show;
    679         char *vshow = NULL;
    680         char *status = NULL;
    681         char *msg = NULL;
    682 
    683         if (type && (g_strcasecmp(type, "unavailable") == 0)) {
    684                 vshow = _("Unavailable");
    685         } else {
    686                 if((show = xmlnode_get_tag_data(p->x, "show")) != NULL) {
    687                         if (!g_strcasecmp(show, "away")) {
    688                                 vshow = _("Away");
    689                         } else if (!g_strcasecmp(show, "chat")) {
    690                                 vshow = _("Online");
    691                         } else if (!g_strcasecmp(show, "xa")) {
    692                                 vshow = _("Extended Away");
    693                         } else if (!g_strcasecmp(show, "dnd")) {
    694                                 vshow = _("Do Not Disturb");
    695                         }
    696                 }
    697         }
    698 
    699         status = xmlnode_get_tag_data(p->x, "status");
    700 
    701         if(vshow != NULL || status != NULL ) {
    702                 /* kinda hokey, but it works :-) */
    703                 msg = g_strdup_printf("%s%s%s",
    704                         (vshow == NULL? "" : vshow),
    705                         (vshow == NULL || status == NULL? "" : ": "),
    706                         (status == NULL? "" : status));
    707         } else {
    708                 msg = g_strdup(_("Online"));
    709         }
    710 
    711         if (val) {
    712                 g_free(val);
    713                 g_hash_table_insert(jd->hash, name, msg);
    714         } else {
    715                 g_hash_table_insert(jd->hash, g_strdup(name), msg);
    716         }
    717 }
    718 
    719 static time_t iso8601_to_time(char *timestamp)
    720 {
    721         struct tm t;
    722         time_t retval = 0;
    723 
    724         if(sscanf(timestamp,"%04d%02d%02dT%02d:%02d:%02d",
    725                 &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec))
    726         {
    727                 t.tm_year -= 1900;
    728                 t.tm_mon -= 1;
    729                 t.tm_isdst = 0;
    730                 retval = mktime(&t);
    731 #               ifdef HAVE_TM_GMTOFF
    732                         retval += t.tm_gmtoff;
    733 #               else
    734 #                       ifdef HAVE_TIMEZONE
    735                                 tzset();        /* making sure */
    736                                 retval -= timezone;
    737 #                       endif
    738 #               endif
    739         }
    740 
    741         return retval;
    742 }
    743 
    744 static void jabber_handlemessage(gjconn gjc, jpacket p)
    745 {
    746         xmlnode y, xmlns, z;
    747         time_t time_sent = time(NULL);
    748 
    749         char *from = NULL, *msg = NULL, *type = NULL;
    750         char m[BUF_LONG * 2];
    751 
    752         type = xmlnode_get_attrib(p->x, "type");
    753 
    754         z = xmlnode_get_firstchild(p->x);
    755 
    756         while(z)
    757         {
    758            if(NSCHECK(z,NS_DELAY))
    759            {
    760               char *timestamp = xmlnode_get_attrib(z,"stamp");
    761               time_sent = iso8601_to_time(timestamp);
    762            }
    763            z = xmlnode_get_nextsibling(z);
    764         }
    765 
    766         if (!type || !g_strcasecmp(type, "normal") || !g_strcasecmp(type, "chat")) {
    767 
    768                 /* XXX namespaces could be handled better. (mid) */
    769                 if ((xmlns = xmlnode_get_tag(p->x, "x")))
    770                         type = xmlnode_get_attrib(xmlns, "xmlns");
    771 
    772                 from = jid_full(p->from);
    773                 /*
    774                 if ((y = xmlnode_get_tag(p->x, "html"))) {
    775                         msg = xmlnode_get_data(y);
    776                 } else
    777                 */
    778                 if ((y = xmlnode_get_tag(p->x, "body"))) {
    779                         msg = xmlnode_get_data(y);
    780                 }
    781 
    782 
    783                 if (!from)
    784                         return;
    785 
    786                 if (type && !g_strcasecmp(type, "jabber:x:conference")) {
    787                         /* do nothing */
    788                 } else if (msg) { /* whisper */
    789                         struct jabber_chat *jc;
    790                         g_snprintf(m, sizeof(m), "%s", msg);
    791                         if (((jc = find_existing_chat(GJ_GC(gjc), p->from)) != NULL) && jc->b)
    792                                 serv_got_chat_in(GJ_GC(gjc), jc->b->id, p->from->resource, 1, m, time_sent);
    793                         else {
    794                                 int flags = 0;
     116                else if( isdigit( *s ) )
     117                {
     118                        int i;
     119                       
     120                        /* The first character is a digit. It could be an
     121                           IP address though. Only accept this as a port#
     122                           if there are only digits. */
     123                        for( i = 0; isdigit( s[i] ); i ++ );
     124                       
     125                        /* If the first non-digit character is a colon or
     126                           the end of the string, save the port number
     127                           where it should be. */
     128                        if( s[i] == ':' || s[i] == 0 )
     129                        {
     130                                sscanf( s, "%d", &i );
     131                                set_setint( &acc->set, "port", i );
    795132                               
    796                                 if(p->from->user) {
    797                                     from = g_strdup_printf("%s@%s", p->from->user, p->from->server);
    798                                 } else {
    799                                     /* server message? */
    800                                     from = g_strdup(p->from->server);
    801                                 }
    802                                 serv_got_im(GJ_GC(gjc), from, m, flags, time_sent, -1);
    803                                 g_free(from);
    804                         }
    805                 }
    806 
    807         } else if (!g_strcasecmp(type, "error")) {
    808                 if ((y = xmlnode_get_tag(p->x, "error"))) {
    809                         type = xmlnode_get_attrib(y, "code");
    810                         msg = xmlnode_get_data(y);
    811                 }
    812 
    813                 if (msg) {
    814                         from = g_strdup_printf("Error %s", type ? type : "");
    815                         do_error_dialog(GJ_GC(gjc), msg, from);
    816                         g_free(from);
    817                 }
    818         } else if (!g_strcasecmp(type, "headline")) {
    819                 char *subject, *body, *url;
    820                
    821                 y = xmlnode_get_tag( p->x, "body" );
    822                 body = y ? g_strdup( xmlnode_get_data( y ) ) : NULL;
    823                
    824                 y = xmlnode_get_tag( p->x, "subject" );
    825                 subject = y ? g_strdup( xmlnode_get_data( y ) ) : NULL;
    826                
    827                 url = NULL;
    828                 z = xmlnode_get_firstchild(p->x);
    829                 while( z )
    830                 {
    831                         char *xtype = xmlnode_get_attrib( z, "xmlns" );
    832                        
    833                         if( xtype && g_strcasecmp( xtype, "jabber:x:oob" ) == 0 &&
    834                                      ( y = xmlnode_get_tag( z, "url" ) ) )
    835                         {
    836                                 url = g_strdup( xmlnode_get_data( y ) );
    837                                 break;
     133                                /* See above. */
     134                                *s = 0;
     135                                s ++;
    838136                        }
    839137                       
    840                         z = xmlnode_get_nextsibling( z );
     138                        had_port = 1;
    841139                }
    842140               
    843                 g_snprintf( m, BUF_LONG, "Subject: %s\nURL: %s\nMessage:\n%s", subject ? subject : "(none)",
    844                                      url ? url : "(none)", body ? body : "(none)" );
    845 
    846                 if( p->from->user )
    847                         from = g_strdup_printf( "%s@%s", p->from->user, p->from->server );
     141                s = strchr( s, ':' );
     142                if( s )
     143                {
     144                        *s = 0;
     145                        s ++;
     146                }
     147        }
     148       
     149        jd->node_cache = g_hash_table_new_full( g_str_hash, g_str_equal, NULL, jabber_cache_entry_free );
     150        jd->buddies = g_hash_table_new( g_str_hash, g_str_equal );
     151       
     152        /* Figure out the hostname to connect to. */
     153        if( acc->server && *acc->server )
     154                connect_to = acc->server;
     155        else if( ( srv = srv_lookup( "xmpp-client", "tcp", jd->server ) ) ||
     156                 ( srv = srv_lookup( "jabber-client", "tcp", jd->server ) ) )
     157                connect_to = srv->name;
     158        else
     159                connect_to = jd->server;
     160       
     161        imcb_log( ic, "Connecting" );
     162       
     163        if( set_getint( &acc->set, "port" ) < JABBER_PORT_MIN ||
     164            set_getint( &acc->set, "port" ) > JABBER_PORT_MAX )
     165        {
     166                imcb_log( ic, "Incorrect port number, must be in the %d-%d range",
     167                               JABBER_PORT_MIN, JABBER_PORT_MAX );
     168                imc_logout( ic, FALSE );
     169                return;
     170        }
     171       
     172        /* For non-SSL connections we can try to use the port # from the SRV
     173           reply, but let's not do that when using SSL, SSL usually runs on
     174           non-standard ports... */
     175        if( set_getbool( &acc->set, "ssl" ) )
     176        {
     177                jd->ssl = ssl_connect( connect_to, set_getint( &acc->set, "port" ), jabber_connected_ssl, ic );
     178                jd->fd = jd->ssl ? ssl_getfd( jd->ssl ) : -1;
     179        }
     180        else
     181        {
     182                jd->fd = proxy_connect( connect_to, srv ? srv->port : set_getint( &acc->set, "port" ), jabber_connected_plain, ic );
     183        }
     184        g_free( srv );
     185       
     186        if( jd->fd == -1 )
     187        {
     188                imcb_error( ic, "Could not connect to server" );
     189                imc_logout( ic, TRUE );
     190        }
     191}
     192
     193static void jabber_logout( struct im_connection *ic )
     194{
     195        struct jabber_data *jd = ic->proto_data;
     196       
     197        jabber_end_stream( ic );
     198       
     199        if( jd->r_inpa >= 0 )
     200                b_event_remove( jd->r_inpa );
     201        if( jd->w_inpa >= 0 )
     202                b_event_remove( jd->w_inpa );
     203       
     204        if( jd->ssl )
     205                ssl_disconnect( jd->ssl );
     206        if( jd->fd >= 0 )
     207                closesocket( jd->fd );
     208       
     209        if( jd->tx_len )
     210                g_free( jd->txq );
     211       
     212        g_hash_table_destroy( jd->node_cache );
     213       
     214        xt_free( jd->xt );
     215       
     216        g_free( jd->away_message );
     217        g_free( jd->username );
     218        g_free( jd );
     219}
     220
     221static int jabber_buddy_msg( struct im_connection *ic, char *who, char *message, int flags )
     222{
     223        struct jabber_data *jd = ic->proto_data;
     224        struct jabber_buddy *bud;
     225        struct xt_node *node;
     226        int st;
     227       
     228        bud = jabber_buddy_by_jid( ic, who, 0 );
     229       
     230        node = xt_new_node( "body", message, NULL );
     231        node = jabber_make_packet( "message", "chat", bud ? bud->full_jid : who, node );
     232       
     233        if( bud && ( jd->flags & JFLAG_WANT_TYPING ) &&
     234            ( ( bud->flags & JBFLAG_DOES_XEP85 ) ||
     235             !( bud->flags & JBFLAG_PROBED_XEP85 ) ) )
     236        {
     237                struct xt_node *act;
     238               
     239                /* If the user likes typing notification and if we don't know
     240                   (and didn't probe before) if this resource supports XEP85,
     241                   include a probe in this packet now. Also, if we know this
     242                   buddy does support XEP85, we have to send this <active/>
     243                   tag to tell that the user stopped typing (well, that's what
     244                   we guess when s/he pressed Enter...). */
     245                act = xt_new_node( "active", NULL, NULL );
     246                xt_add_attr( act, "xmlns", XMLNS_CHATSTATES );
     247                xt_add_child( node, act );
     248               
     249                /* Just make sure we do this only once. */
     250                bud->flags |= JBFLAG_PROBED_XEP85;
     251        }
     252       
     253        st = jabber_write_packet( ic, node );
     254        xt_free_node( node );
     255       
     256        return st;
     257}
     258
     259static GList *jabber_away_states( struct im_connection *ic )
     260{
     261        static GList *l = NULL;
     262        int i;
     263       
     264        if( l == NULL )
     265                for( i = 0; jabber_away_state_list[i].full_name; i ++ )
     266                        l = g_list_append( l, (void*) jabber_away_state_list[i].full_name );
     267       
     268        return l;
     269}
     270
     271static void jabber_get_info( struct im_connection *ic, char *who )
     272{
     273        struct jabber_data *jd = ic->proto_data;
     274        struct jabber_buddy *bud;
     275       
     276        if( strchr( who, '/' ) )
     277                bud = jabber_buddy_by_jid( ic, who, 0 );
     278        else
     279        {
     280                char *s = jabber_normalize( who );
     281                bud = g_hash_table_lookup( jd->buddies, s );
     282                g_free( s );
     283        }
     284       
     285        while( bud )
     286        {
     287                imcb_log( ic, "Buddy %s (%d) information:\nAway state: %s\nAway message: %s",
     288                                   bud->full_jid, bud->priority,
     289                                   bud->away_state ? bud->away_state->full_name : "(none)",
     290                                   bud->away_message ? : "(none)" );
     291                bud = bud->next;
     292        }
     293       
     294        jabber_get_vcard( ic, bud ? bud->full_jid : who );
     295}
     296
     297static void jabber_set_away( struct im_connection *ic, char *state_txt, char *message )
     298{
     299        struct jabber_data *jd = ic->proto_data;
     300        struct jabber_away_state *state;
     301       
     302        /* Save all this info. We need it, for example, when changing the priority setting. */
     303        state = (void *) jabber_away_state_by_name( state_txt );
     304        jd->away_state = state ? state : (void *) jabber_away_state_list; /* Fall back to "Away" if necessary. */
     305        g_free( jd->away_message );
     306        jd->away_message = ( message && *message ) ? g_strdup( message ) : NULL;
     307       
     308        presence_send_update( ic );
     309}
     310
     311static void jabber_add_buddy( struct im_connection *ic, char *who, char *group )
     312{
     313        if( jabber_add_to_roster( ic, who, NULL ) )
     314                presence_send_request( ic, who, "subscribe" );
     315}
     316
     317static void jabber_remove_buddy( struct im_connection *ic, char *who, char *group )
     318{
     319        /* We should always do this part. Clean up our administration a little bit. */
     320        jabber_buddy_remove_bare( ic, who );
     321       
     322        if( jabber_remove_from_roster( ic, who ) )
     323                presence_send_request( ic, who, "unsubscribe" );
     324}
     325
     326static void jabber_keepalive( struct im_connection *ic )
     327{
     328        /* Just any whitespace character is enough as a keepalive for XMPP sessions. */
     329        jabber_write( ic, "\n", 1 );
     330       
     331        /* This runs the garbage collection every minute, which means every packet
     332           is in the cache for about a minute (which should be enough AFAIK). */
     333        jabber_cache_clean( ic );
     334}
     335
     336static int jabber_send_typing( struct im_connection *ic, char *who, int typing )
     337{
     338        struct jabber_data *jd = ic->proto_data;
     339        struct jabber_buddy *bud;
     340       
     341        /* Enable typing notification related code from now. */
     342        jd->flags |= JFLAG_WANT_TYPING;
     343       
     344        if( ( bud = jabber_buddy_by_jid( ic, who, 0 ) ) == NULL )
     345        {
     346                /* Sending typing notifications to unknown buddies is
     347                   unsupported for now. Shouldn't be a problem, I think. */
     348                return 0;
     349        }
     350       
     351        if( bud->flags & JBFLAG_DOES_XEP85 )
     352        {
     353                /* We're only allowed to send this stuff if we know the other
     354                   side supports it. */
     355               
     356                struct xt_node *node;
     357                char *type;
     358                int st;
     359               
     360                if( typing & OPT_TYPING )
     361                        type = "composing";
     362                else if( typing & OPT_THINKING )
     363                        type = "paused";
    848364                else
    849                         from = g_strdup( p->from->server );
    850                
    851                 serv_got_im( GJ_GC(gjc), from, m, 0, time_sent, -1 );
    852                
    853                 g_free( from );
    854                 g_free( subject );
    855                 g_free( body );
    856                 g_free( url );
    857         }
    858 }
    859            
    860 static void jabber_handlepresence(gjconn gjc, jpacket p)
    861 {
    862         char *to, *from, *type;
    863         struct buddy *b = NULL;
    864         jid who;
    865         char *buddy;
    866         xmlnode y;
    867         char *show;
    868         int state = 0;
    869         GSList *resources;
    870         char *res;
    871         struct conversation *cnv = NULL;
    872         struct jabber_chat *jc = NULL;
    873 
    874         to = xmlnode_get_attrib(p->x, "to");
    875         from = xmlnode_get_attrib(p->x, "from");
    876         type = xmlnode_get_attrib(p->x, "type");
    877        
    878         if (type && g_strcasecmp(type, "error") == 0) {
    879                 return;
    880         }
    881         else if ((y = xmlnode_get_tag(p->x, "show"))) {
    882                 show = xmlnode_get_data(y);
    883                 if (!show) {
    884                         state = 0;
    885                 } else if (!g_strcasecmp(show, "away")) {
    886                         state = UC_AWAY;
    887                 } else if (!g_strcasecmp(show, "chat")) {
    888                         state = UC_CHAT;
    889                 } else if (!g_strcasecmp(show, "xa")) {
    890                         state = UC_XA;
    891                 } else if (!g_strcasecmp(show, "dnd")) {
    892                         state = UC_DND;
    893                 }
    894         } else {
    895                 state = 0;
    896         }
    897 
    898         who = jid_new(gjc->p, from);
    899         if (who->user == NULL) {
    900                 /* FIXME: transport */
    901                 return;
    902         }
    903 
    904         buddy = g_strdup_printf("%s@%s", who->user, who->server);
    905 
    906         /* um. we're going to check if it's a chat. if it isn't, and there are pending
    907          * chats, create the chat. if there aren't pending chats and we don't have the
    908          * buddy on our list, simply bail out. */
    909         if ((cnv = NULL) == NULL) {
    910                 static int i = 0x70;
    911                 if ((jc = find_pending_chat(GJ_GC(gjc), who)) != NULL) {
    912                         jc->b = cnv = serv_got_joined_chat(GJ_GC(gjc), i++, who->user);
    913                         jc->id = jc->b->id;
    914                         jc->state = JCS_ACTIVE;
    915                 } else if ((b = find_buddy(GJ_GC(gjc), buddy)) == NULL) {
    916                         g_free(buddy);
    917                         return;
    918                 }
    919         }
    920 
    921         if (!cnv) {
    922                 resources = b->proto_data;
    923                 res = who->resource;
    924                 if (res)
    925                         while (resources) {
    926                                 if (!strcmp(res, resources->data))
    927                                         break;
    928                                 resources = resources->next;
    929                         }
    930 
    931                 /* keep track of away msg same as yahoo plugin */
    932                 jabber_track_away(gjc, p, normalize(b->name), type);
    933 
    934                 if (type && (g_strcasecmp(type, "unavailable") == 0)) {
    935                         if (resources) {
    936                                 g_free(resources->data);
    937                                 b->proto_data = g_slist_remove(b->proto_data, resources->data);
    938                         }
    939                         if (!b->proto_data) {
    940                                 serv_got_update(GJ_GC(gjc), buddy, 0, 0, 0, 0, 0, 0);
    941                         }
    942                 } else {
    943                         if (!resources) {
    944                                 b->proto_data = g_slist_append(b->proto_data, g_strdup(res));
    945                         }
    946 
    947                         serv_got_update(GJ_GC(gjc), buddy, 1, 0, b->signon, b->idle, state, 0);
    948 
    949                 }
    950         } else {
    951                 if (who->resource) {
    952                         char *buf;
    953 
    954                         buf = g_strdup_printf("%s@%s/%s", who->user, who->server, who->resource);
    955                         jabber_track_away(gjc, p, buf, type);
    956                         g_free(buf);
    957 
    958                         if (type && !g_strcasecmp(type, "unavailable")) {
    959                                 struct jabber_data *jd;
    960                                 if (!jc && !(jc = find_existing_chat(GJ_GC(gjc), who))) {
    961                                         g_free(buddy);
    962                                         return;
    963                                 }
    964                                 jd = jc->gc->proto_data;
    965                                 /* if it's not ourselves...*/
    966                                 if (strcmp(who->resource, jc->Jid->resource) && jc->b) {
    967                                         remove_chat_buddy(jc->b, who->resource, NULL);
    968                                         g_free(buddy);
    969                                         return;
    970                                 }
    971 
    972                                 jc->state = JCS_CLOSED;
    973                                 serv_got_chat_left(GJ_GC(gjc), jc->id);
    974                                 /*
    975                                  * TBD: put back some day?
    976                                 jd->chats = g_slist_remove(jd->chats, jc);
    977                                 g_free(jc);
    978                                  */
    979                         } else {
    980                                 if ((!jc && !(jc = find_existing_chat(GJ_GC(gjc), who))) || !jc->b) {
    981                                         g_free(buddy);
    982                                         return;
    983                                 }
    984                                 if (!find_chat_buddy(jc->b, who->resource)) {
    985                                         add_chat_buddy(jc->b, who->resource);
    986                                 }
    987                         }
    988                 }
    989         }
    990 
    991         g_free(buddy);
    992 
    993         return;
    994 }
    995 
    996 /*
    997  * Used only by Jabber accept/deny add stuff just below
    998  */
    999 struct jabber_add_permit {
    1000         gjconn gjc;
    1001         gchar *user;
    1002 };
    1003 
    1004 /*
    1005  * Common part for Jabber accept/deny adds
    1006  *
    1007  * "type" says whether we'll permit/deny the subscribe request
    1008  */
    1009 static void jabber_accept_deny_add(struct jabber_add_permit *jap, const char *type)
    1010 {
    1011         xmlnode g = xmlnode_new_tag("presence");
    1012 
    1013         xmlnode_put_attrib(g, "to", jap->user);
    1014         xmlnode_put_attrib(g, "type", type);
    1015         gjab_send(jap->gjc, g);
    1016 
    1017         xmlnode_free(g);
    1018 }
    1019 
    1020 /*
    1021  * Callback from "accept" in do_ask_dialog() invoked by jabber_handles10n()
    1022  */
    1023 static void jabber_accept_add(gpointer w, struct jabber_add_permit *jap)
    1024 {
    1025         jabber_accept_deny_add(jap, "subscribed");
    1026         /*
    1027          * If we don't already have the buddy on *our* buddylist,
    1028          * ask if we want him or her added.
    1029          */
    1030         if(find_buddy(GJ_GC(jap->gjc), jap->user) == NULL) {
    1031                 show_got_added(GJ_GC(jap->gjc), jap->user, NULL);
    1032         }
    1033         g_free(jap->user);
    1034         g_free(jap);
    1035 }
    1036 
    1037 /*
    1038  * Callback from "deny/cancel" in do_ask_dialog() invoked by jabber_handles10n()
    1039  */
    1040 static void jabber_deny_add(gpointer w, struct jabber_add_permit *jap)
    1041 {
    1042         jabber_accept_deny_add(jap, "unsubscribed");
    1043         g_free(jap->user);
    1044         g_free(jap);
    1045 }
    1046 
    1047 /*
    1048  * Handle subscription requests
    1049  */
    1050 static void jabber_handles10n(gjconn gjc, jpacket p)
    1051 {
    1052         xmlnode g;
    1053         char *Jid = xmlnode_get_attrib(p->x, "from");
    1054         char *type = xmlnode_get_attrib(p->x, "type");
    1055 
    1056         g = xmlnode_new_tag("presence");
    1057         xmlnode_put_attrib(g, "to", Jid);
    1058 
    1059         if (!strcmp(type, "subscribe")) {
    1060                 /*
    1061                  * A "subscribe to us" request was received - put up the approval dialog
    1062                  */
    1063                 struct jabber_add_permit *jap = g_new0(struct jabber_add_permit, 1);
    1064                 gchar *msg = g_strdup_printf(_("The user %s wants to add you to his/her buddy list."),
    1065                                 Jid);
    1066 
    1067                 jap->gjc = gjc;
    1068                 jap->user = g_strdup(Jid);
    1069                 do_ask_dialog(GJ_GC(gjc), msg, jap, jabber_accept_add, jabber_deny_add);
    1070 
    1071                 g_free(msg);
    1072                 xmlnode_free(g);        /* Never needed it here anyway */
    1073                 return;
    1074 
    1075         } else if (!strcmp(type, "unsubscribe")) {
    1076                 /*
    1077                  * An "unsubscribe to us" was received - simply "approve" it
    1078                  */
    1079                 xmlnode_put_attrib(g, "type", "unsubscribed");
    1080         } else {
    1081                 /*
    1082                  * Did we attempt to subscribe to somebody and they do not exist?
    1083                  */
    1084                 if (!strcmp(type, "unsubscribed")) {
    1085                         xmlnode y;
    1086                         char *status;
    1087                         if((y = xmlnode_get_tag(p->x, "status")) && (status = xmlnode_get_data(y)) &&
    1088                                         !strcmp(status, "Not Found")) {
    1089                                 char *msg = g_strdup_printf("%s: \"%s\"", _("No such user"),
    1090                                         xmlnode_get_attrib(p->x, "from"));
    1091                                 do_error_dialog(GJ_GC(gjc), msg, _("Jabber Error"));
    1092                                 g_free(msg);
    1093                         }
    1094                 }
    1095 
    1096                 xmlnode_free(g);
    1097                 return;
    1098         }
    1099 
    1100         gjab_send(gjc, g);
    1101         xmlnode_free(g);
    1102 }
    1103 
    1104 /*
    1105  * Pending subscription to a buddy?
    1106  */
    1107 #define BUD_SUB_TO_PEND(sub, ask) ((!g_strcasecmp((sub), "none") || !g_strcasecmp((sub), "from")) && \
    1108                                         (ask) != NULL && !g_strcasecmp((ask), "subscribe"))
    1109 
    1110 /*
    1111  * Subscribed to a buddy?
    1112  */
    1113 #define BUD_SUBD_TO(sub, ask) ((!g_strcasecmp((sub), "to") || !g_strcasecmp((sub), "both")) && \
    1114                                         ((ask) == NULL || !g_strcasecmp((ask), "subscribe")))
    1115 
    1116 /*
    1117  * Pending unsubscription to a buddy?
    1118  */
    1119 #define BUD_USUB_TO_PEND(sub, ask) ((!g_strcasecmp((sub), "to") || !g_strcasecmp((sub), "both")) && \
    1120                                         (ask) != NULL && !g_strcasecmp((ask), "unsubscribe"))
    1121 
    1122 /*
    1123  * Unsubscribed to a buddy?
    1124  */
    1125 #define BUD_USUBD_TO(sub, ask) ((!g_strcasecmp((sub), "none") || !g_strcasecmp((sub), "from")) && \
    1126                                         ((ask) == NULL || !g_strcasecmp((ask), "unsubscribe")))
    1127 
    1128 /*
    1129  * If a buddy is added or removed from the roster on another resource
    1130  * jabber_handlebuddy is called
    1131  *
    1132  * Called with roster item node.
    1133  */
    1134 static void jabber_handlebuddy(gjconn gjc, xmlnode x)
    1135 {
    1136         xmlnode g;
    1137         char *Jid, *name, *sub, *ask;
    1138         jid who;
    1139         struct buddy *b = NULL;
    1140         char *buddyname, *groupname = NULL;
    1141 
    1142         Jid = xmlnode_get_attrib(x, "jid");
    1143         name = xmlnode_get_attrib(x, "name");
    1144         sub = xmlnode_get_attrib(x, "subscription");
    1145         ask = xmlnode_get_attrib(x, "ask");
    1146         who = jid_new(gjc->p, Jid);
    1147 
    1148         /* JFIXME: jabber_handleroster() had a "FIXME: transport" at this
    1149          * equivilent point.  So...
    1150          *
    1151          * We haven't allocated any memory or done anything interesting to
    1152          * this point, so we'll violate Good Coding Structure here by
    1153          * simply bailing out.
    1154          */
    1155         if (!who || !who->user) {
    1156                 return;
    1157         }
    1158 
    1159         buddyname = g_strdup_printf("%s@%s", who->user, who->server);
    1160 
    1161         if((g = xmlnode_get_tag(x, "group")) != NULL) {
    1162                 groupname = xmlnode_get_data(g);
    1163         }
    1164 
    1165         /*
    1166          * Add or remove a buddy?  Change buddy's alias or group?
    1167          */
    1168         if (BUD_SUB_TO_PEND(sub, ask) || BUD_SUBD_TO(sub, ask)) {
    1169                 if ((b = find_buddy(GJ_GC(gjc), buddyname)) == NULL) {
    1170                         add_buddy(GJ_GC(gjc), groupname ? groupname : _("Buddies"), buddyname,
    1171                                 name ? name : buddyname);
    1172                 } else {
    1173                         /* struct group *c_grp = find_group_by_buddy(GJ_GC(gjc), buddyname); */
    1174 
    1175                         /*
    1176                          * If the buddy's in a new group or his/her alias is changed...
    1177                          */
    1178                         if(groupname) {
    1179                                 int present = b->present;       /* save presence state */
    1180                                 int uc = b->uc;                 /* and away state (?) */
    1181                                 int idle = b->idle;
    1182                                 int signon = b->signon;
    1183 
    1184                                 /*
    1185                                  * seems rude, but it seems to be the only way...
    1186                                  */
    1187                                 /* remove_buddy(GJ_GC(gjc), c_grp, b); */
    1188                                 jabber_remove_buddy(GJ_GC(gjc), b->name, JABBER_GROUP);
    1189                                
    1190                                 add_buddy(GJ_GC(gjc), groupname, buddyname,
    1191                                         name ? name : buddyname);
    1192                                 if(present) {
    1193                                         serv_got_update(GJ_GC(gjc), buddyname, 1, 0, signon, idle, uc, 0);
    1194                                 }
    1195                         } else if(name != NULL && strcmp(b->show, name)) {
    1196                                 strncpy(b->show, name, BUDDY_ALIAS_MAXLEN);
    1197                                 b->show[BUDDY_ALIAS_MAXLEN - 1] = '\0'; /* cheap safety feature */
    1198                                 serv_buddy_rename(GJ_GC(gjc), buddyname, b->show);
    1199                         }
    1200                 }
    1201         }  else if (BUD_USUB_TO_PEND(sub, ask) || BUD_USUBD_TO(sub, ask) || !g_strcasecmp(sub, "remove")) {
    1202                 jabber_remove_gaim_buddy(GJ_GC(gjc), buddyname);
    1203         }
    1204         g_free(buddyname);
    1205 
    1206 }
    1207 
    1208 static void jabber_handleroster(gjconn gjc, xmlnode querynode)
    1209 {
    1210         xmlnode x;
    1211 
    1212         x = xmlnode_get_firstchild(querynode);
    1213         while (x) {
    1214                 jabber_handlebuddy(gjc, x);
    1215                 x = xmlnode_get_nextsibling(x);
    1216         }
    1217 
    1218         account_online(GJ_GC(gjc));
    1219 }
    1220 
    1221 static void jabber_handleauthresp(gjconn gjc, jpacket p)
    1222 {
    1223         if (jpacket_subtype(p) == JPACKET__RESULT) {
    1224                 if (xmlnode_has_children(p->x)) {
    1225                         xmlnode query = xmlnode_get_tag(p->x, "query");
    1226                         set_login_progress(GJ_GC(gjc), 4, _("Authenticating"));
    1227                         if (!xmlnode_get_tag(query, "digest")) {
    1228                                 g_free(gjc->sid);
    1229                                 gjc->sid = NULL;
    1230                         }
    1231                         gjab_auth(gjc);
    1232                 } else {
    1233                         gjab_reqroster(gjc);
    1234                        
    1235                         ((struct jabber_data *)GJ_GC(gjc)->proto_data)->did_import = TRUE;
    1236                 }
    1237         } else {
    1238                 xmlnode xerr;
    1239                 char *errmsg = NULL;
    1240                 int errcode = 0;
    1241                 struct jabber_data *jd = GJ_GC(gjc)->proto_data;
    1242 
    1243                 xerr = xmlnode_get_tag(p->x, "error");
    1244                 if (xerr) {
    1245                         char msg[BUF_LONG];
    1246                         errmsg = xmlnode_get_data(xerr);
    1247                         if (xmlnode_get_attrib(xerr, "code")) {
    1248                                 errcode = atoi(xmlnode_get_attrib(xerr, "code"));
    1249                                 g_snprintf(msg, sizeof(msg), "Error %d: %s", errcode, errmsg ? errmsg : "Unknown error");
    1250                         } else
    1251                                 g_snprintf(msg, sizeof(msg), "%s", errmsg);
    1252                         hide_login_progress(GJ_GC(gjc), msg);
    1253                 } else {
    1254                         hide_login_progress(GJ_GC(gjc), _("Unknown login error"));
    1255                 }
    1256 
    1257                 jd->die = TRUE;
    1258         }
    1259 }
    1260 
    1261 static void jabber_handleversion(gjconn gjc, xmlnode iqnode) {
    1262         xmlnode querynode, x;
    1263         char *id, *from;
    1264         char os[1024];
    1265 #ifndef _WIN32
    1266         struct utsname osinfo;
    1267 
    1268         uname(&osinfo);
    1269         g_snprintf(os, sizeof os, "%s %s %s", osinfo.sysname, osinfo.release, osinfo.machine);
    1270 #else
    1271         g_snprintf(os, sizeof os, "Windows %d %d", _winmajor, _winminor);
    1272 #endif
    1273 
    1274 
    1275         id = xmlnode_get_attrib(iqnode, "id");
    1276         from = xmlnode_get_attrib(iqnode, "from");
    1277 
    1278         x = jutil_iqnew(JPACKET__RESULT, NS_VERSION);
    1279 
    1280         xmlnode_put_attrib(x, "to", from);
    1281         xmlnode_put_attrib(x, "id", id);
    1282         querynode = xmlnode_get_tag(x, "query");
    1283         xmlnode_insert_cdata(xmlnode_insert_tag(querynode, "name"), PACKAGE, -1);
    1284         xmlnode_insert_cdata(xmlnode_insert_tag(querynode, "version"), BITLBEE_VERSION, -1);
    1285         xmlnode_insert_cdata(xmlnode_insert_tag(querynode, "os"), os, -1);
    1286 
    1287         gjab_send(gjc, x);
    1288 
    1289         xmlnode_free(x);
    1290 }
    1291 
    1292 static void jabber_handletime(gjconn gjc, xmlnode iqnode) {
    1293         xmlnode querynode, x;
    1294         char *id, *from;
    1295         time_t now_t;
    1296         struct tm *now;
    1297         char buf[1024];
    1298 
    1299         time(&now_t);
    1300         now = localtime(&now_t);
    1301 
    1302         id = xmlnode_get_attrib(iqnode, "id");
    1303         from = xmlnode_get_attrib(iqnode, "from");
    1304 
    1305         x = jutil_iqnew(JPACKET__RESULT, NS_TIME);
    1306 
    1307         xmlnode_put_attrib(x, "to", from);
    1308         xmlnode_put_attrib(x, "id", id);
    1309         querynode = xmlnode_get_tag(x, "query");
    1310 
    1311         strftime(buf, 1024, "%Y%m%dT%T", now);
    1312         xmlnode_insert_cdata(xmlnode_insert_tag(querynode, "utc"), buf, -1);
    1313         strftime(buf, 1024, "%Z", now);
    1314         xmlnode_insert_cdata(xmlnode_insert_tag(querynode, "tz"), buf, -1);
    1315         strftime(buf, 1024, "%d %b %Y %T", now);
    1316         xmlnode_insert_cdata(xmlnode_insert_tag(querynode, "display"), buf, -1);
    1317        
    1318         gjab_send(gjc, x);
    1319 
    1320         xmlnode_free(x);
    1321 }
    1322 
    1323 static void jabber_handlelast(gjconn gjc, xmlnode iqnode) {
    1324         xmlnode x, querytag;
    1325         char *id, *from;
    1326         struct jabber_data *jd = GJ_GC(gjc)->proto_data;
    1327         char idle_time[32];
    1328        
    1329         id = xmlnode_get_attrib(iqnode, "id");
    1330         from = xmlnode_get_attrib(iqnode, "from");
    1331 
    1332         x = jutil_iqnew(JPACKET__RESULT, "jabber:iq:last");
    1333 
    1334         xmlnode_put_attrib(x, "to", from);
    1335         xmlnode_put_attrib(x, "id", id);
    1336         querytag = xmlnode_get_tag(x, "query");
    1337         g_snprintf(idle_time, sizeof idle_time, "%ld", jd->idle ? time(NULL) - jd->idle : 0);
    1338         xmlnode_put_attrib(querytag, "seconds", idle_time);
    1339 
    1340         gjab_send(gjc, x);
    1341         xmlnode_free(x);
    1342 }
    1343 
    1344 /*
    1345  * delete == TRUE: delete found entry
    1346  *
    1347  * returns pointer to (local) copy of value if found, NULL otherwise
    1348  *
    1349  * Note: non-reentrant!  Local static storage re-used on subsequent calls.
    1350  * If you're going to need to keep the returned value, make a copy!
    1351  */
    1352 static gchar *jabber_track_queries(GHashTable *queries, gchar *key, gboolean delete)
    1353 {
    1354         gpointer my_key, my_val;
    1355         static gchar *ret_val = NULL;
    1356 
    1357         if(ret_val != NULL) {
    1358                 g_free(ret_val);
    1359                 ret_val = NULL;
    1360         }
    1361 
    1362         /* self-protection */
    1363         if(queries != NULL && key != NULL) {
    1364                 if(g_hash_table_lookup_extended(queries, key, &my_key, &my_val)) {
    1365                         ret_val = g_strdup((gchar *) my_val);
    1366                         if(delete) {
    1367                                 g_hash_table_remove(queries, key);
    1368                                 g_free(my_key);
    1369                                 g_free(my_val);
    1370                         }
    1371                 }
    1372         }
    1373 
    1374         return(ret_val);
    1375 }
    1376 
    1377 static void jabber_handlepacket(gjconn gjc, jpacket p)
    1378 {
    1379         char *id;
    1380         switch (p->type) {
    1381         case JPACKET_MESSAGE:
    1382                 jabber_handlemessage(gjc, p);
    1383                 break;
    1384         case JPACKET_PRESENCE:
    1385                 jabber_handlepresence(gjc, p);
    1386                 break;
    1387         case JPACKET_IQ:
    1388                 id = xmlnode_get_attrib(p->x, "id");
    1389                 if (id != NULL && !strcmp(id, IQID_AUTH)) {
    1390                         jabber_handleauthresp(gjc, p);
    1391                         break;
    1392                 }
    1393 
    1394                 if (jpacket_subtype(p) == JPACKET__SET) {
    1395                         xmlnode querynode;
    1396                         querynode = xmlnode_get_tag(p->x, "query");
    1397                         if (NSCHECK(querynode, "jabber:iq:roster")) {
    1398                                 jabber_handlebuddy(gjc, xmlnode_get_firstchild(querynode));
    1399                         }
    1400                 } else if (jpacket_subtype(p) == JPACKET__GET) {
    1401                         xmlnode querynode;
    1402                         querynode = xmlnode_get_tag(p->x, "query");
    1403                         if (NSCHECK(querynode, NS_VERSION)) {
    1404                                 jabber_handleversion(gjc, p->x);
    1405                         } else if (NSCHECK(querynode, NS_TIME)) {
    1406                                 jabber_handletime(gjc, p->x);
    1407                         } else if (NSCHECK(querynode, "jabber:iq:last")) {
    1408                                 jabber_handlelast(gjc, p->x);
    1409                         }
    1410                 } else if (jpacket_subtype(p) == JPACKET__RESULT) {
    1411                         xmlnode querynode, vcard;
    1412                         /* char *xmlns; */
    1413                         char *from;
    1414 
    1415                         /*
    1416                          * TBD: ISTM maybe this part could use a serious re-work?
    1417                          */
    1418                         from = xmlnode_get_attrib(p->x, "from");
    1419                         querynode = xmlnode_get_tag(p->x, "query");
    1420                         vcard = xmlnode_get_tag(p->x, "vCard");
    1421                         if (!vcard)
    1422                                 vcard = xmlnode_get_tag(p->x, "VCARD");
    1423 
    1424                         if (NSCHECK(querynode, NS_ROSTER)) {
    1425                                 jabber_handleroster(gjc, querynode);
    1426                         } else if (NSCHECK(querynode, NS_VCARD)) {
    1427                                 jabber_track_queries(gjc->queries, id, TRUE);   /* delete query track */
    1428                                 jabber_handlevcard(gjc, querynode, from);
    1429                         } else if (vcard) {
    1430                                 jabber_track_queries(gjc->queries, id, TRUE);   /* delete query track */
    1431                                 jabber_handlevcard(gjc, vcard, from);
    1432                         } else {
    1433                                 char *val;
    1434 
    1435                                 /* handle "null" query results */
    1436                                 if((val = jabber_track_queries(gjc->queries, id, TRUE)) != NULL) {
    1437                                         if (!g_strncasecmp(val, "vcard", 5)) {
    1438                                                 jabber_handlevcard(gjc, NULL, from);
    1439                                         }
    1440 
    1441                                         /* No-op */
    1442                                 }
    1443                         }
    1444 
    1445                 } else if (jpacket_subtype(p) == JPACKET__ERROR) {
    1446                         xmlnode xerr;
    1447                         char *from, *errmsg = NULL;
    1448                         int errcode = 0;
    1449 
    1450                         from = xmlnode_get_attrib(p->x, "from");
    1451                         xerr = xmlnode_get_tag(p->x, "error");
    1452                         if (xerr) {
    1453                                 errmsg = xmlnode_get_data(xerr);
    1454                                 if (xmlnode_get_attrib(xerr, "code"))
    1455                                         errcode = atoi(xmlnode_get_attrib(xerr, "code"));
    1456                         }
    1457 
    1458                         from = g_strdup_printf("Error %d (%s)", errcode, from);
    1459                         do_error_dialog(GJ_GC(gjc), errmsg, from);
    1460                         g_free(from);
    1461 
    1462                 }
    1463 
    1464                 break;
    1465         case JPACKET_S10N:
    1466                 jabber_handles10n(gjc, p);
    1467                 break;
    1468         }
    1469 
    1470         xmlnode_free(p->x);
    1471 
    1472         return;
    1473 }
    1474 
    1475 static void jabber_handlestate(gjconn gjc, int state)
    1476 {
    1477         switch (state) {
    1478         case JCONN_STATE_OFF:
    1479                 if(gjc->was_connected) {
    1480                         hide_login_progress_error(GJ_GC(gjc), _("Connection lost"));
    1481                 } else {
    1482                         hide_login_progress(GJ_GC(gjc), _("Unable to connect"));
    1483                 }
    1484                 signoff(GJ_GC(gjc));
    1485                 break;
    1486         case JCONN_STATE_CONNECTED:
    1487                 gjc->was_connected = 1;
    1488                 set_login_progress(GJ_GC(gjc), 2, _("Connected"));
    1489                 break;
    1490         case JCONN_STATE_ON:
    1491                 set_login_progress(GJ_GC(gjc), 3, _("Requesting Authentication Method"));
    1492                 gjab_reqauth(gjc);
    1493                 break;
    1494         }
    1495         return;
    1496 }
    1497 
    1498 static void jabber_acc_init(account_t *acc)
    1499 {
    1500         set_t *s;
    1501        
    1502         s = set_add( &acc->set, "port", "5222", set_eval_int, acc );
    1503         s->flags |= ACC_SET_OFFLINE_ONLY;
    1504        
    1505         s = set_add( &acc->set, "resource", "BitlBee", NULL, acc );
    1506         s->flags |= ACC_SET_OFFLINE_ONLY;
    1507        
    1508         s = set_add( &acc->set, "server", NULL, set_eval_account, acc );
    1509         s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY;
    1510        
    1511         s = set_add( &acc->set, "ssl", "false", set_eval_bool, acc );
    1512         s->flags |= ACC_SET_OFFLINE_ONLY;
    1513 }
    1514 
    1515 static void jabber_login(account_t *acc)
    1516 {
    1517         struct gaim_connection *gc;
    1518         struct jabber_data *jd;
    1519         char *resource, *loginname;
    1520        
    1521         /* Time to move some data/things from the old syntax to the new one: */
    1522         if (acc->server) {
    1523                 char *s, *tmp_server;
    1524                 int port;
    1525                
    1526                 if (g_strcasecmp(acc->server, "ssl") == 0) {
    1527                         set_setstr(&acc->set, "server", "");
    1528                         set_setint(&acc->set, "port", DEFAULT_PORT_SSL);
    1529                         set_setstr(&acc->set, "ssl", "true");
    1530                        
    1531                         g_free(acc->server);
    1532                         acc->server = NULL;
    1533                 } else if ((s = strchr(acc->server, ':'))) {
    1534                         if (strstr(acc->server, ":ssl")) {
    1535                                 set_setint(&acc->set, "port", DEFAULT_PORT_SSL);
    1536                                 set_setstr(&acc->set, "ssl", "true");
    1537                         }
    1538                         if (isdigit(s[1])) {
    1539                                 if (sscanf(s + 1, "%d", &port) == 1)
    1540                                         set_setint(&acc->set, "port", port);
    1541                         }
    1542                         tmp_server = g_strndup(acc->server, s - acc->server);
    1543                         set_setstr(&acc->set, "server", tmp_server);
    1544                         g_free(tmp_server);
    1545                 }
    1546         }
    1547        
    1548         gc = new_gaim_conn(acc);
    1549         jd = gc->proto_data = g_new0(struct jabber_data, 1);
    1550        
    1551         if( strchr( acc->user, '@' ) == NULL )
    1552         {
    1553                 hide_login_progress( gc, "Invalid account name" );
    1554                 signoff( gc );
    1555                 return;
    1556         }
    1557        
    1558         resource = set_getstr(&acc->set, "resource");
    1559         loginname = create_valid_jid(acc->user, DEFAULT_SERVER, resource);
    1560        
    1561         jd->hash = g_hash_table_new(g_str_hash, g_str_equal);
    1562         jd->chats = NULL;       /* we have no chats yet */
    1563 
    1564         set_login_progress(gc, 1, _("Connecting"));
    1565 
    1566         if (!(jd->gjc = gjab_new(loginname, acc->pass, gc))) {
    1567                 g_free(loginname);
    1568                 hide_login_progress(gc, _("Unable to connect"));
    1569                 signoff(gc);
    1570                 return;
    1571         }
    1572 
    1573         g_free(loginname);
    1574         gjab_state_handler(jd->gjc, jabber_handlestate);
    1575         gjab_packet_handler(jd->gjc, jabber_handlepacket);
    1576         jd->gjc->queries = g_hash_table_new(g_str_hash, g_str_equal);
    1577         gjab_start(jd->gjc);
    1578 }
    1579 
    1580 static gboolean jabber_destroy_hash(gpointer key, gpointer val, gpointer data) {
    1581         g_free(key);
    1582         g_free(val);
    1583         return TRUE;
    1584 }
    1585 
    1586 static gboolean jabber_free(gpointer data, gint fd, b_input_condition cond)
    1587 {
    1588         struct jabber_data *jd = data;
    1589 
    1590         if(jd->gjc != NULL) {
    1591                 gjab_delete(jd->gjc);
    1592                 /* YAY for modules with their own memory pool managers!...
    1593                 g_free(jd->gjc->sid);
    1594                 And a less sarcastic yay for valgrind. :-) */
    1595                 jd->gjc = NULL;
    1596         }
    1597         g_free(jd);
    1598 
    1599         return FALSE;
    1600 }
    1601 
    1602 static void jabber_close(struct gaim_connection *gc)
    1603 {
    1604         struct jabber_data *jd = gc->proto_data;
    1605 
    1606         if(jd) {
    1607                 GSList *jcs = jd->chats;
    1608 
    1609                 /* Free-up the jabber_chat struct allocs and the list */
    1610                 while (jcs) {
    1611                         g_free(jcs->data);
    1612                         jcs = jcs->next;
    1613                 }
    1614                 g_slist_free(jd->chats);
    1615 
    1616                 /* Free-up the away status memories and the list */
    1617                 if(jd->hash != NULL) {
    1618                         g_hash_table_foreach_remove(jd->hash, jabber_destroy_hash, NULL);
    1619                         g_hash_table_destroy(jd->hash);
    1620                         jd->hash = NULL;
    1621                 }
    1622 
    1623                 /* Free-up the pending queries memories and the list */
    1624                 if(jd->gjc != NULL && jd->gjc->queries != NULL) {
    1625                         g_hash_table_foreach_remove(jd->gjc->queries, jabber_destroy_hash, NULL);
    1626                         g_hash_table_destroy(jd->gjc->queries);
    1627                         jd->gjc->queries = NULL;
    1628                 }
    1629         }
    1630         if (gc->inpa)
    1631                 b_event_remove(gc->inpa);
    1632 
    1633         if(jd) {
    1634                 b_timeout_add(50, jabber_free, jd);
    1635                 if(jd->gjc != NULL)
    1636                         xmlnode_free(jd->gjc->current);
    1637         }
    1638         gc->proto_data = NULL;
    1639 }
    1640 
    1641 static int jabber_send_im(struct gaim_connection *gc, char *who, char *message, int len, int flags)
    1642 {
    1643         xmlnode x, y;
    1644         char *realwho;
    1645         gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc;
    1646 
    1647         if (!who || !message)
    1648                 return 0;
    1649 
    1650         x = xmlnode_new_tag("message");
    1651         /* Bare username and "username" not the server itself? */
    1652         if (!strchr(who, '@') && strcmp(who, gjc->user->server) != 0)
    1653                 realwho = g_strdup_printf("%s@%s", who, gjc->user->server);
    1654         else
    1655                 realwho = g_strdup(who);
    1656         xmlnode_put_attrib(x, "to", realwho);
    1657         g_free(realwho);
    1658 
    1659         xmlnode_insert_tag(x, "bitlbee");
    1660         xmlnode_put_attrib(x, "type", "chat");
    1661 
    1662         if (message && strlen(message)) {
    1663                 y = xmlnode_insert_tag(x, "body");
    1664                 xmlnode_insert_cdata(y, message, -1);
    1665         }
    1666 
    1667         gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x);
    1668         xmlnode_free(x);
     365                        type = "active";
     366               
     367                node = xt_new_node( type, NULL, NULL );
     368                xt_add_attr( node, "xmlns", XMLNS_CHATSTATES );
     369                node = jabber_make_packet( "message", "chat", bud->full_jid, node );
     370               
     371                st = jabber_write_packet( ic, node );
     372                xt_free_node( node );
     373               
     374                return st;
     375        }
     376       
    1669377        return 1;
    1670378}
    1671379
    1672 /*
    1673  * Add/update buddy's roster entry on server
    1674  */
    1675 static void jabber_roster_update(struct gaim_connection *gc, char *name)
    1676 {
    1677         xmlnode x, y;
    1678         char *realwho;
    1679         gjconn gjc;
    1680         struct buddy *buddy = NULL;
    1681         /* struct group *buddy_group = NULL; */
    1682        
    1683         if(gc && gc->proto_data && ((struct jabber_data *)gc->proto_data)->gjc && name) {
    1684                 gjc = ((struct jabber_data *)gc->proto_data)->gjc;
    1685 
    1686                 if (!strchr(name, '@'))
    1687                         realwho = g_strdup_printf("%s@%s", name, gjc->user->server);
    1688                 else {
    1689                         jid who = jid_new(gjc->p, name);
    1690                         if (who->user == NULL) {
    1691                                 /* FIXME: transport */
    1692                                 return;
    1693                         }
    1694                         realwho = g_strdup_printf("%s@%s", who->user, who->server);
    1695                 }
    1696 
    1697 
    1698                 x = jutil_iqnew(JPACKET__SET, NS_ROSTER);
    1699                 y = xmlnode_insert_tag(xmlnode_get_tag(x, "query"), "item");
    1700                 xmlnode_put_attrib(y, "jid", realwho);
    1701 
    1702 
    1703                 /* If we can find the buddy, there's an alias for him, it's not 0-length
    1704                  * and it doesn't match his JID, add the "name" attribute.
    1705                  */
    1706                 if((buddy = find_buddy(gc, realwho)) != NULL &&
    1707                         buddy->show != NULL && buddy->show[0] != '\0' && strcmp(realwho, buddy->show)) {
    1708 
    1709                         xmlnode_put_attrib(y, "name", buddy->show);
    1710                 }
    1711 
    1712                 /*
    1713                  * Find out what group the buddy's in and send that along
    1714                  * with the roster item.
    1715                  */
    1716                 /* ** Bitlbee disabled **
    1717                 if((buddy_group = NULL) != NULL) {
    1718                         xmlnode z;
    1719                         z = xmlnode_insert_tag(y, "group");
    1720                         xmlnode_insert_cdata(z, buddy_group->name, -1);
    1721                 }
    1722                 ** End - Bitlbee ** */
    1723 
    1724                 gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x);
    1725 
    1726                 xmlnode_free(x);
    1727                 g_free(realwho);
    1728         }
    1729 }
    1730 
    1731 /*
    1732  * Change buddy's group on server roster
    1733  */
    1734 static void jabber_group_change(struct gaim_connection *gc, char *name, char *old_group, char *new_group)
    1735 {
    1736         if(strcmp(old_group, new_group)) {
    1737                 jabber_roster_update(gc, name);
    1738         }
    1739 }
    1740 
    1741 static void jabber_add_buddy(struct gaim_connection *gc, char *name)
    1742 {
    1743         xmlnode x;
    1744         char *realwho;
    1745         gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc;
    1746 
    1747         if (!((struct jabber_data *)gc->proto_data)->did_import)
    1748                 return;
    1749 
    1750         if (!name)
    1751                 return;
    1752 
    1753         if (!strcmp(gc->username, name))
    1754                 return;
    1755 
    1756         if (!strchr(name, '@'))
    1757                 realwho = g_strdup_printf("%s@%s", name, gjc->user->server);
    1758         else {
    1759                 jid who;
    1760                
    1761                 if((who = jid_new(gjc->p, name)) == NULL) {
    1762                         char *msg = g_strdup_printf("%s: \"%s\"", _("Invalid Jabber I.D."), name);
    1763                         do_error_dialog(GJ_GC(gjc), msg, _("Jabber Error"));
    1764                         g_free(msg);
    1765                         jabber_remove_gaim_buddy(gc, name);
    1766                         return;
    1767                 }
    1768                 if (who->user == NULL) {
    1769                         /* FIXME: transport */
    1770                         return;
    1771                 }
    1772                 realwho = g_strdup_printf("%s@%s", who->user, who->server);
    1773         }
    1774 
    1775         x = xmlnode_new_tag("presence");
    1776         xmlnode_put_attrib(x, "to", realwho);
    1777         xmlnode_put_attrib(x, "type", "subscribe");
    1778         gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x);
    1779         xmlnode_free(x);
    1780 
    1781         jabber_roster_update(gc, realwho);
    1782 
    1783         g_free(realwho);
    1784 }
    1785 
    1786 static void jabber_remove_buddy(struct gaim_connection *gc, char *name, char *group)
    1787 {
    1788         xmlnode x;
    1789         char *realwho;
    1790         gjconn gjc = ((struct jabber_data *)gc->proto_data)->gjc;
    1791 
    1792         if (!name)
    1793                 return;
    1794 
    1795         if (!strchr(name, '@'))
    1796                 realwho = g_strdup_printf("%s@%s", name, gjc->user->server);
    1797         else
    1798                 realwho = g_strdup(name);
    1799 
    1800         x = xmlnode_new_tag("presence");
    1801         xmlnode_put_attrib(x, "to", realwho);
    1802         xmlnode_put_attrib(x, "type", "unsubscribe");
    1803         gjab_send(((struct jabber_data *)gc->proto_data)->gjc, x);
    1804         g_free(realwho);
    1805         xmlnode_free(x);
    1806 }
    1807 
    1808 static void jabber_get_info(struct gaim_connection *gc, char *who) {
    1809         xmlnode x;
    1810         char *id;
    1811         char *realwho;
    1812         struct jabber_data *jd = gc->proto_data;
    1813         gjconn gjc = jd->gjc;
    1814 
    1815         x = jutil_iqnew(JPACKET__GET, NS_VCARD);
    1816         /* Bare username? */
    1817         if (!strchr(who, '@')) {
    1818                 realwho = g_strdup_printf("%s@%s", who, gjc->user->server);
    1819         } else {
    1820                 realwho = g_strdup(who);
    1821         }
    1822         xmlnode_put_attrib(x, "to", realwho);
    1823         g_free(realwho);
    1824 
    1825         id = gjab_getid(gjc);
    1826         xmlnode_put_attrib(x, "id", id);
    1827 
    1828         g_hash_table_insert(jd->gjc->queries, g_strdup(id), g_strdup("vCard"));
    1829 
    1830         gjab_send(gjc, x);
    1831 
    1832         xmlnode_free(x);
    1833        
    1834 }
    1835 
    1836 static void jabber_get_away_msg(struct gaim_connection *gc, char *who) {
    1837         struct jabber_data *jd = gc->proto_data;
    1838         gjconn gjc = jd->gjc;
    1839         char *status;
    1840 
    1841         /* space for all elements: Jabber I.D. + "status" + NULL (list terminator) */
    1842         gchar **str_arr = (gchar **) g_new(gpointer, 3);
    1843         gchar **ap = str_arr;
    1844         gchar *realwho, *final;
    1845 
    1846         /* Bare username? */
    1847         if (!strchr(who, '@')) {
    1848                 realwho = g_strdup_printf("%s@%s", who, gjc->user->server);
    1849         } else {
    1850                 realwho = g_strdup(who);
    1851         }
    1852         *ap++ = g_strdup_printf("<B>Jabber ID:</B> %s<BR>\n", realwho);
    1853 
    1854         if((status = g_hash_table_lookup(jd->hash, realwho)) == NULL) {
    1855                 status = _("Unknown");
    1856         }
    1857         *ap++ = g_strdup_printf("<B>Status:</B> %s<BR>\n", status);
    1858 
    1859         *ap = NULL;
    1860 
    1861         final= g_strjoinv(NULL, str_arr);
    1862         g_strfreev(str_arr);
    1863 
    1864         g_free(realwho);
    1865         g_free(final);
    1866        
    1867 }
    1868 
    1869 static GList *jabber_away_states(struct gaim_connection *gc) {
    1870         GList *m = NULL;
    1871 
    1872         m = g_list_append(m, "Online");
    1873         m = g_list_append(m, "Chatty");
    1874         m = g_list_append(m, "Away");
    1875         m = g_list_append(m, "Extended Away");
    1876         m = g_list_append(m, "Do Not Disturb");
    1877 
    1878         return m;
    1879 }
    1880 
    1881 static void jabber_set_away(struct gaim_connection *gc, char *state, char *message)
    1882 {
    1883         xmlnode x, y;
    1884         struct jabber_data *jd = gc->proto_data;
    1885         gjconn gjc = jd->gjc;
    1886 
    1887         gc->away = NULL; /* never send an auto-response */
    1888 
    1889         x = xmlnode_new_tag("presence");
    1890 
    1891         if (!strcmp(state, GAIM_AWAY_CUSTOM)) {
    1892                 /* oh goody. Gaim is telling us what to do. */
    1893                 if (message) {
    1894                         /* Gaim wants us to be away */
    1895                         y = xmlnode_insert_tag(x, "show");
    1896                         xmlnode_insert_cdata(y, "away", -1);
    1897                         y = xmlnode_insert_tag(x, "status");
    1898                         xmlnode_insert_cdata(y, message, -1);
    1899                         gc->away = "";
    1900                 } else {
    1901                         /* Gaim wants us to not be away */
    1902                         /* but for Jabber, we can just send presence with no other information. */
    1903                 }
    1904         } else {
    1905                 /* state is one of our own strings. it won't be NULL. */
    1906                 if (!g_strcasecmp(state, "Online")) {
    1907                         /* once again, we don't have to put anything here */
    1908                 } else if (!g_strcasecmp(state, "Chatty")) {
    1909                         y = xmlnode_insert_tag(x, "show");
    1910                         xmlnode_insert_cdata(y, "chat", -1);
    1911                 } else if (!g_strcasecmp(state, "Away")) {
    1912                         y = xmlnode_insert_tag(x, "show");
    1913                         xmlnode_insert_cdata(y, "away", -1);
    1914                         gc->away = "";
    1915                 } else if (!g_strcasecmp(state, "Extended Away")) {
    1916                         y = xmlnode_insert_tag(x, "show");
    1917                         xmlnode_insert_cdata(y, "xa", -1);
    1918                         gc->away = "";
    1919                 } else if (!g_strcasecmp(state, "Do Not Disturb")) {
    1920                         y = xmlnode_insert_tag(x, "show");
    1921                         xmlnode_insert_cdata(y, "dnd", -1);
    1922                         gc->away = "";
    1923                 }
    1924         }
    1925 
    1926         gjab_send(gjc, x);
    1927         xmlnode_free(x);
    1928 }
    1929 
    1930 static void jabber_keepalive(struct gaim_connection *gc) {
    1931         struct jabber_data *jd = (struct jabber_data *)gc->proto_data;
    1932         gjab_send_raw(jd->gjc, "  \t  ");
    1933 }
    1934 
    1935 /*---------------------------------------*/
    1936 /* Jabber "set info" (vCard) support     */
    1937 /*---------------------------------------*/
    1938 
    1939 /*
    1940  * V-Card format:
    1941  *
    1942  *  <vCard prodid='' version='' xmlns=''>
    1943  *    <FN></FN>
    1944  *    <N>
    1945  *      <FAMILY/>
    1946  *      <GIVEN/>
    1947  *    </N>
    1948  *    <NICKNAME/>
    1949  *    <URL/>
    1950  *    <ADR>
    1951  *      <STREET/>
    1952  *      <EXTADD/>
    1953  *      <LOCALITY/>
    1954  *      <REGION/>
    1955  *      <PCODE/>
    1956  *      <COUNTRY/>
    1957  *    </ADR>
    1958  *    <TEL/>
    1959  *    <EMAIL/>
    1960  *    <ORG>
    1961  *      <ORGNAME/>
    1962  *      <ORGUNIT/>
    1963  *    </ORG>
    1964  *    <TITLE/>
    1965  *    <ROLE/>
    1966  *    <DESC/>
    1967  *    <BDAY/>
    1968  *  </vCard>
    1969  *
    1970  * See also:
    1971  *
    1972  *      http://docs.jabber.org/proto/html/vcard-temp.html
    1973  *      http://www.vcard-xml.org/dtd/vCard-XML-v2-20010520.dtd
    1974  */
    1975 
    1976 /*
    1977  * Cross-reference user-friendly V-Card entry labels to vCard XML tags
    1978  * and attributes.
    1979  *
    1980  * Order is (or should be) unimportant.  For example: we have no way of
    1981  * knowing in what order real data will arrive.
    1982  *
    1983  * Format: Label, Pre-set text, "visible" flag, "editable" flag, XML tag
    1984  *         name, XML tag's parent tag "path" (relative to vCard node).
    1985  *
    1986  *         List is terminated by a NULL label pointer.
    1987  *
    1988  *         Entries with no label text, but with XML tag and parent tag
    1989  *         entries, are used by V-Card XML construction routines to
    1990  *         "automagically" construct the appropriate XML node tree.
    1991  *
    1992  * Thoughts on future direction/expansion
    1993  *
    1994  *      This is a "simple" vCard.
    1995  *
    1996  *      It is possible for nodes other than the "vCard" node to have
    1997  *      attributes.  Should that prove necessary/desirable, add an
    1998  *      "attributes" pointer to the vcard_template struct, create the
    1999  *      necessary tag_attr structs, and add 'em to the vcard_dflt_data
    2000  *      array.
    2001  *
    2002  *      The above changes will (obviously) require changes to the vCard
    2003  *      construction routines.
    2004  */
    2005 
    2006 static struct vcard_template {
    2007         char *label;                    /* label text pointer */
    2008         char *text;                     /* entry text pointer */
    2009         int  visible;                   /* should entry field be "visible?" */
    2010         int  editable;                  /* should entry field be editable? */
    2011         char *tag;                      /* tag text */
    2012         char *ptag;                     /* parent tag "path" text */
    2013         char *url;                      /* vCard display format if URL */
    2014 } vcard_template_data[] = {
    2015         {N_("Full Name"),          NULL, TRUE, TRUE, "FN",        NULL,  NULL},
    2016         {N_("Family Name"),        NULL, TRUE, TRUE, "FAMILY",    "N",   NULL},
    2017         {N_("Given Name"),         NULL, TRUE, TRUE, "GIVEN",     "N",   NULL},
    2018         {N_("Nickname"),           NULL, TRUE, TRUE, "NICKNAME",  NULL,  NULL},
    2019         {N_("URL"),                NULL, TRUE, TRUE, "URL",       NULL,  "<A HREF=\"%s\">%s</A>"},
    2020         {N_("Street Address"),     NULL, TRUE, TRUE, "STREET",    "ADR", NULL},
    2021         {N_("Extended Address"),   NULL, TRUE, TRUE, "EXTADD",    "ADR", NULL},
    2022         {N_("Locality"),           NULL, TRUE, TRUE, "LOCALITY",  "ADR", NULL},
    2023         {N_("Region"),             NULL, TRUE, TRUE, "REGION",    "ADR", NULL},
    2024         {N_("Postal Code"),        NULL, TRUE, TRUE, "PCODE",     "ADR", NULL},
    2025         {N_("Country"),            NULL, TRUE, TRUE, "COUNTRY",   "ADR", NULL},
    2026         {N_("Telephone"),          NULL, TRUE, TRUE, "TELEPHONE", NULL,  NULL},
    2027         {N_("Email"),              NULL, TRUE, TRUE, "EMAIL",     NULL,  "<A HREF=\"mailto:%s\">%s</A>"},
    2028         {N_("Organization Name"),  NULL, TRUE, TRUE, "ORGNAME",   "ORG", NULL},
    2029         {N_("Organization Unit"),  NULL, TRUE, TRUE, "ORGUNIT",   "ORG", NULL},
    2030         {N_("Title"),              NULL, TRUE, TRUE, "TITLE",     NULL,  NULL},
    2031         {N_("Role"),               NULL, TRUE, TRUE, "ROLE",      NULL,  NULL},
    2032         {N_("Birthday"),           NULL, TRUE, TRUE, "BDAY",      NULL,  NULL},
    2033         {N_("Description"),        NULL, TRUE, TRUE, "DESC",      NULL,  NULL},
    2034         {"", NULL, TRUE, TRUE, "N",     NULL, NULL},
    2035         {"", NULL, TRUE, TRUE, "ADR",   NULL, NULL},
    2036         {"", NULL, TRUE, TRUE, "ORG",   NULL, NULL},
    2037         {NULL, NULL, 0, 0, NULL, NULL, NULL}
    2038 };
    2039 
    2040 /*
    2041  * Used by routines to parse an XML-encoded string into an xmlnode tree
    2042  */
    2043 typedef struct {
    2044         XML_Parser parser;
    2045         xmlnode current;
    2046 } *xmlstr2xmlnode_parser, xmlstr2xmlnode_parser_struct;
    2047 
    2048 
    2049 /*
    2050  * Used by XML_Parse on parsing CDATA
    2051  */
    2052 static void xmlstr2xmlnode_charData(void *userdata, const char *s, int slen)
    2053 {
    2054         xmlstr2xmlnode_parser xmlp = (xmlstr2xmlnode_parser) userdata;
    2055 
    2056         if (xmlp->current)
    2057                 xmlnode_insert_cdata(xmlp->current, s, slen);
    2058 }
    2059 
    2060 /*
    2061  * Used by XML_Parse to start or append to an xmlnode
    2062  */
    2063 static void xmlstr2xmlnode_startElement(void *userdata, const char *name, const char **attribs)
    2064 {
    2065         xmlnode x;
    2066         xmlstr2xmlnode_parser xmlp = (xmlstr2xmlnode_parser) userdata;
    2067 
    2068         if (xmlp->current) {
    2069                 /* Append the node to the current one */
    2070                 x = xmlnode_insert_tag(xmlp->current, name);
    2071                 xmlnode_put_expat_attribs(x, attribs);
    2072 
    2073                 xmlp->current = x;
    2074         } else {
    2075                 x = xmlnode_new_tag(name);
    2076                 xmlnode_put_expat_attribs(x, attribs);
    2077                 xmlp->current = x;
    2078         }
    2079 }
    2080 
    2081 /*
    2082  * Used by XML_Parse to end an xmlnode
    2083  */
    2084 static void xmlstr2xmlnode_endElement(void *userdata, const char *name)
    2085 {
    2086         xmlstr2xmlnode_parser xmlp = (xmlstr2xmlnode_parser) userdata;
    2087         xmlnode x;
    2088 
    2089         if (xmlp->current != NULL && (x = xmlnode_get_parent(xmlp->current)) != NULL) {
    2090                 xmlp->current = x;
    2091         }
    2092 }
    2093 
    2094 /*
    2095  * Parse an XML-encoded string into an xmlnode tree
    2096  *
    2097  * Caller is responsible for freeing the returned xmlnode
    2098  */
    2099 static xmlnode xmlstr2xmlnode(char *xmlstring)
    2100 {
    2101         xmlstr2xmlnode_parser my_parser = g_new(xmlstr2xmlnode_parser_struct, 1);
    2102         xmlnode x = NULL;
    2103 
    2104         my_parser->parser = XML_ParserCreate(NULL);
    2105         my_parser->current = NULL;
    2106 
    2107         XML_SetUserData(my_parser->parser, (void *)my_parser);
    2108         XML_SetElementHandler(my_parser->parser, xmlstr2xmlnode_startElement, xmlstr2xmlnode_endElement);
    2109         XML_SetCharacterDataHandler(my_parser->parser, xmlstr2xmlnode_charData);
    2110         XML_Parse(my_parser->parser, xmlstring, strlen(xmlstring), 0);
    2111 
    2112         x = my_parser->current;
    2113 
    2114         XML_ParserFree(my_parser->parser);
    2115         g_free(my_parser);
    2116 
    2117         return(x);
    2118 }
    2119 
    2120 /*
    2121  * Insert a tag node into an xmlnode tree, recursively inserting parent tag
    2122  * nodes as necessary
    2123  *
    2124  * Returns pointer to inserted node
    2125  *
    2126  * Note to hackers: this code is designed to be re-entrant (it's recursive--it
    2127  * calls itself), so don't put any "static"s in here!
    2128  */
    2129 static xmlnode insert_tag_to_parent_tag(xmlnode start, const char *parent_tag, const char *new_tag)
    2130 {
    2131         xmlnode x = NULL;
    2132 
    2133         /*
    2134          * If the parent tag wasn't specified, see if we can get it
    2135          * from the vCard template struct.
    2136          */
    2137         if(parent_tag == NULL) {
    2138                 struct vcard_template *vc_tp = vcard_template_data;
    2139 
    2140                 while(vc_tp->label != NULL) {
    2141                         if(strcmp(vc_tp->tag, new_tag) == 0) {
    2142                                 parent_tag = vc_tp->ptag;
    2143                                 break;
    2144                         }
    2145                         ++vc_tp;
    2146                 }
    2147         }
    2148 
    2149         /*
    2150          * If we have a parent tag...
    2151          */
    2152         if(parent_tag != NULL ) {
    2153                 /*
    2154                  * Try to get the parent node for a tag
    2155                  */
    2156                 if((x = xmlnode_get_tag(start, parent_tag)) == NULL) {
    2157                         /*
    2158                          * Descend?
    2159                          */
    2160                         char *grand_parent = strcpy(g_malloc(strlen(parent_tag) + 1), parent_tag);
    2161                         char *parent;
    2162 
    2163                         if((parent = strrchr(grand_parent, '/')) != NULL) {
    2164                                 *(parent++) = '\0';
    2165                                 x = insert_tag_to_parent_tag(start, grand_parent, parent);
    2166                         } else {
    2167                                 x = xmlnode_insert_tag(start, grand_parent);
    2168                         }
    2169                         g_free(grand_parent);
    2170                 } else {
    2171                         /*
    2172                          * We found *something* to be the parent node.
    2173                          * Note: may be the "root" node!
    2174                          */
    2175                         xmlnode y;
    2176                         if((y = xmlnode_get_tag(x, new_tag)) != NULL) {
    2177                                 return(y);
    2178                         }
    2179                 }
    2180         }
    2181 
    2182         /*
    2183          * insert the new tag into its parent node
    2184          */
    2185         return(xmlnode_insert_tag((x == NULL? start : x), new_tag));
    2186 }
    2187 
    2188 /*
    2189  * Send vCard info to Jabber server
    2190  */
    2191 static void jabber_set_info(struct gaim_connection *gc, char *info)
    2192 {
    2193         xmlnode x, vc_node;
    2194         char *id;
    2195         struct jabber_data *jd = gc->proto_data;
    2196         gjconn gjc = jd->gjc;
    2197 
    2198         x = xmlnode_new_tag("iq");
    2199         xmlnode_put_attrib(x,"type","set");
    2200 
    2201         id = gjab_getid(gjc);
    2202        
    2203         xmlnode_put_attrib(x, "id", id);
    2204 
    2205         /*
    2206          * Send only if there's actually any *information* to send
    2207          */
    2208         if((vc_node = xmlstr2xmlnode(info)) != NULL && xmlnode_get_name(vc_node) != NULL &&
    2209                         g_strncasecmp(xmlnode_get_name(vc_node), "vcard", 5) == 0) {
    2210                 xmlnode_insert_tag_node(x, vc_node);
    2211                 gjab_send(gjc, x);
    2212         }
    2213 
    2214         xmlnode_free(x);
    2215 }
    2216 
    2217 /*
    2218  * displays a Jabber vCard
    2219  */
    2220 static void jabber_handlevcard(gjconn gjc, xmlnode querynode, char *from)
    2221 {
    2222         struct jabber_data *jd = GJ_GC(gjc)->proto_data;
    2223         jid who = jid_new(gjc->p, from);
    2224         char *status = NULL, *text = NULL;
    2225         GString *str = g_string_sized_new(100);
    2226         xmlnode child;
    2227 
    2228         gchar *buddy = NULL;
    2229        
    2230         if(querynode == NULL) {
    2231                 serv_got_crap(GJ_GC(gjc), "%s - Received empty info reply from %s", _("User Info"), from);
    2232                 return;
    2233         }
    2234 
    2235         if(who->resource != NULL && (who->resource)[0] != '\0') {
    2236                 buddy = g_strdup_printf("%s@%s/%s", who->user, who->server, who->resource);
    2237         } else {
    2238                 buddy = g_strdup_printf("%s@%s", who->user, who->server);
    2239         }
    2240 
    2241         if((status = g_hash_table_lookup(jd->hash, buddy)) == NULL) {
    2242                 status = _("Unknown");
    2243         }
    2244 
    2245         g_string_sprintfa(str, "%s: %s - %s: %s", _("Jabber ID"), buddy, _("Status"),
    2246                                status);
    2247 
    2248         for(child = querynode->firstchild; child; child = child->next)
    2249         {
    2250                 xmlnode child2;
    2251 
    2252                 if(child->type != NTYPE_TAG)
    2253                         continue;
    2254 
    2255                 text = xmlnode_get_data(child);
    2256                 if(text && !strcmp(child->name, "FN")) {
    2257                         info_string_append(str, "\n", _("Full Name"), text);
    2258                 } else if (!strcmp(child->name, "N")) {
    2259                         for (child2 = child->firstchild; child2; child2 = child2->next) {
    2260                                 char *text2 = NULL;
    2261 
    2262                                 if (child2->type != NTYPE_TAG)
    2263                                         continue;
    2264 
    2265                                 text2 = xmlnode_get_data(child2);
    2266                                 if (text2 && !strcmp(child2->name, "FAMILY")) {
    2267                                         info_string_append(str, "\n", _("Family Name"), text2);
    2268                                 } else if (text2 && !strcmp(child2->name, "GIVEN")) {
    2269                                         info_string_append(str, "\n", _("Given Name"), text2);
    2270                                 } else if (text2 && !strcmp(child2->name, "MIDDLE")) {
    2271                                         info_string_append(str, "\n", _("Middle Name"), text2);
    2272                                 }
    2273                         }
    2274                 } else if (text && !strcmp(child->name, "NICKNAME")) {
    2275                         info_string_append(str, "\n", _("Nickname"), text);
    2276                 } else if (text && !strcmp(child->name, "BDAY")) {
    2277                         info_string_append(str, "\n", _("Birthday"), text);
    2278                 } else if (!strcmp(child->name, "ADR")) {
    2279                         /* show wich address it is */
    2280                         /* Just for the beauty of bitlbee
    2281                         if (child->firstchild)
    2282                                 g_string_sprintfa(str, "%s:\n", _("Address"));
    2283                         */
    2284                         for(child2 = child->firstchild; child2; child2 = child2->next) {
    2285                                 char *text2 = NULL;
    2286 
    2287                                 if(child2->type != NTYPE_TAG)
    2288                                         continue;
    2289 
    2290                                 text2 = xmlnode_get_data(child2);
    2291                                 if(text2 && !strcmp(child2->name, "POBOX")) {
    2292                                         info_string_append(str, "\n",
    2293                                                         _("P.O. Box"), text2);
    2294                                 } else if(text2 && !strcmp(child2->name, "EXTADR")) {
    2295                                         info_string_append(str, "\n",
    2296                                                         _("Extended Address"), text2);
    2297                                 } else if(text2 && !strcmp(child2->name, "STREET")) {
    2298                                         info_string_append(str, "\n",
    2299                                                         _("Street Address"), text2);
    2300                                 } else if(text2 && !strcmp(child2->name, "LOCALITY")) {
    2301                                         info_string_append(str, "\n",
    2302                                                         _("Locality"), text2);
    2303                                 } else if(text2 && !strcmp(child2->name, "REGION")) {
    2304                                         info_string_append(str, "\n",
    2305                                                         _("Region"), text2);
    2306                                 } else if(text2 && !strcmp(child2->name, "PCODE")) {
    2307                                         info_string_append(str, "\n",
    2308                                                         _("Postal Code"), text2);
    2309                                 } else if(text2 && (!strcmp(child2->name, "CTRY")
    2310                                                         || !strcmp(child2->name, "COUNTRY"))) {
    2311                                         info_string_append(str, "\n", _("Country"), text2);
    2312                                 }
    2313                         }
    2314                 } else if(!strcmp(child->name, "TEL")) {
    2315                         char *number = NULL;
    2316                         if ((child2 = xmlnode_get_tag(child, "NUMBER"))) {
    2317                                 /* show what kind of number it is */
    2318                                 number = xmlnode_get_data(child2);
    2319                                 if(number) {
    2320                                         info_string_append(str, "\n", _("Telephone"), number);
    2321                                 }
    2322                         } else if((number = xmlnode_get_data(child))) {
    2323                                 /* lots of clients (including gaim) do this,
    2324                                  * but it's out of spec */
    2325                                 info_string_append(str, "\n", _("Telephone"), number);
    2326                         }
    2327                 } else if(!strcmp(child->name, "EMAIL")) {
    2328                         char *userid = NULL;
    2329                         if((child2 = xmlnode_get_tag(child, "USERID"))) {
    2330                                 /* show what kind of email it is */
    2331                                 userid = xmlnode_get_data(child2);
    2332                                 if(userid) {
    2333                                         info_string_append(str, "\n", _("Email"), userid);
    2334                                 }
    2335                         } else if((userid = xmlnode_get_data(child))) {
    2336                                 /* lots of clients (including gaim) do this,
    2337                                  * but it's out of spec */
    2338                                 info_string_append(str, "\n", _("Email"), userid);
    2339                         }
    2340                 } else if(!strcmp(child->name, "ORG")) {
    2341                         for(child2 = child->firstchild; child2; child2 = child2->next) {
    2342                                 char *text2 = NULL;
    2343 
    2344                                 if(child2->type != NTYPE_TAG)
    2345                                         continue;
    2346 
    2347                                 text2 = xmlnode_get_data(child2);
    2348                                 if(text2 && !strcmp(child2->name, "ORGNAME")) {
    2349                                         info_string_append(str, "\n", _("Organization Name"), text2);
    2350                                 } else if(text2 && !strcmp(child2->name, "ORGUNIT")) {
    2351                                         info_string_append(str, "\n", _("Organization Unit"), text2);
    2352                                 }
    2353                         }
    2354                 } else if(text && !strcmp(child->name, "TITLE")) {
    2355                         info_string_append(str, "\n", _("Title"), text);
    2356                 } else if(text && !strcmp(child->name, "ROLE")) {
    2357                         info_string_append(str, "\n", _("Role"), text);
    2358                 } else if(text && !strcmp(child->name, "DESC")) {
    2359                         g_string_sprintfa(str, "\n%s:\n%s\n%s", _("Description"),
    2360                                         text, _("End of Description"));
    2361                 }
    2362         }
    2363 
    2364         serv_got_crap(GJ_GC(gjc), "%s\n%s", _("User Info"), str->str);
    2365 
    2366         g_free(buddy);
    2367         g_string_free(str, TRUE);
    2368 }
    2369 
    2370 void jabber_init()
    2371 {
    2372         struct prpl *ret = g_new0(struct prpl, 1);
    2373 
     380void jabber_initmodule()
     381{
     382        struct prpl *ret = g_new0( struct prpl, 1 );
     383       
    2374384        ret->name = "jabber";
     385        ret->login = jabber_login;
     386        ret->init = jabber_init;
     387        ret->logout = jabber_logout;
     388        ret->buddy_msg = jabber_buddy_msg;
    2375389        ret->away_states = jabber_away_states;
    2376         ret->acc_init = jabber_acc_init;
    2377         ret->login = jabber_login;
    2378         ret->close = jabber_close;
    2379         ret->send_im = jabber_send_im;
    2380         ret->set_info = jabber_set_info;
     390//      ret->get_status_string = jabber_get_status_string;
     391        ret->set_away = jabber_set_away;
     392//      ret->set_info = jabber_set_info;
    2381393        ret->get_info = jabber_get_info;
    2382         ret->set_away = jabber_set_away;
    2383         ret->get_away = jabber_get_away_msg;
    2384394        ret->add_buddy = jabber_add_buddy;
    2385395        ret->remove_buddy = jabber_remove_buddy;
     396//      ret->chat_msg = jabber_chat_msg;
     397//      ret->chat_invite = jabber_chat_invite;
     398//      ret->chat_leave = jabber_chat_leave;
     399//      ret->chat_open = jabber_chat_open;
    2386400        ret->keepalive = jabber_keepalive;
    2387         ret->alias_buddy = jabber_roster_update;
    2388         ret->group_buddy = jabber_group_change;
     401        ret->send_typing = jabber_send_typing;
    2389402        ret->handle_cmp = g_strcasecmp;
    2390403
    2391         register_protocol (ret);
    2392 }
     404        register_protocol( ret );
     405}
  • protocols/jabber/jabber.h

    r348c11b rae3c4fa  
    1 /*
    2  *  This program is free software; you can redistribute it and/or modify
    3  *  it under the terms of the GNU General Public License as published by
    4  *  the Free Software Foundation; either version 2 of the License, or
    5  *  (at your option) any later version.
    6  *
    7  *  This program is distributed in the hope that it will be useful,
    8  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    9  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    10  *  GNU General Public License for more details.
    11  *
    12  *  You should have received a copy of the GNU General Public License
    13  *  along with this program; if not, write to the Free Software
    14  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    15  *
    16  *  Jabber
    17  *  Copyright (C) 1998-1999 The Jabber Team http://jabber.org/
    18  */
     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\***************************************************************************/
    1923
    20 #include <string.h>
    21 #include <stdlib.h>
    22 #include <sys/types.h>
    23 #include <stdio.h>
    24 #include <setjmp.h>
    25 #include <sys/stat.h>
    26 #include <fcntl.h>
    27 #include <errno.h>
    28 #include <signal.h>
    29 #include <stdarg.h>
    30 #include <time.h>
    31 #include <ctype.h>
    32 #ifdef _WIN32
    33 #undef DATADIR
    34 #include "sock.h"
     24#ifndef _JABBER_H
     25#define _JABBER_H
     26
     27#include <glib.h>
     28
     29#include "xmltree.h"
     30#include "bitlbee.h"
     31
     32typedef enum
     33{
     34        JFLAG_STREAM_STARTED = 1,       /* Set when we detected the beginning of the stream
     35                                           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
     38                                           SASL or TLS). */
     39        JFLAG_WAIT_SESSION = 8,         /* Set if we sent a <session> tag and need a reply
     40                                           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
     43                                           activates all XEP-85 related code. */
     44} jabber_flags_t;
     45
     46typedef enum
     47{
     48        JBFLAG_PROBED_XEP85 = 1,        /* Set this when we sent our probe packet to make
     49                                           sure it gets sent only once. */
     50        JBFLAG_DOES_XEP85 = 2,          /* Set this when the resource seems to support
     51                                           XEP85 (typing notification shite). */
     52} jabber_buddy_flags_t;
     53
     54#define JABBER_PORT_DEFAULT "5222"
     55#define JABBER_PORT_MIN 5220
     56#define JABBER_PORT_MAX 5229
     57
     58struct jabber_data
     59{
     60        struct im_connection *ic;
     61       
     62        int fd;
     63        void *ssl;
     64        char *txq;
     65        int tx_len;
     66        int r_inpa, w_inpa;
     67       
     68        struct xt_parser *xt;
     69        jabber_flags_t flags;
     70       
     71        char *username;         /* USERNAME@server */
     72        char *server;           /* username@SERVER -=> server/domain, not hostname */
     73       
     74        /* After changing one of these two (or the priority setting), call
     75           presence_send_update() to inform the server about the changes. */
     76        struct jabber_away_state *away_state;
     77        char *away_message;
     78       
     79        GHashTable *node_cache;
     80        GHashTable *buddies;
     81};
     82
     83struct jabber_away_state
     84{
     85        char code[5];
     86        char *full_name;
     87};
     88
     89typedef xt_status (*jabber_cache_event) ( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
     90
     91struct jabber_cache_entry
     92{
     93        struct xt_node *node;
     94        jabber_cache_event func;
     95};
     96
     97struct jabber_buddy
     98{
     99        char *bare_jid;
     100        char *full_jid;
     101        char *resource;
     102       
     103        int priority;
     104        struct jabber_away_state *away_state;
     105        char *away_message;
     106       
     107        time_t last_act;
     108        jabber_buddy_flags_t flags;
     109       
     110        struct jabber_buddy *next;
     111};
     112
     113/* Prefixes to use for packet IDs (mainly for IQ packets ATM). Usually the
     114   first one should be used, but when storing a packet in the cache, a
     115   "special" kind of ID is assigned to make it easier later to figure out
     116   if we have to do call an event handler for the response packet. */
     117#define JABBER_PACKET_ID "BeeP"
     118#define JABBER_CACHED_ID "BeeC"
     119
     120/* RFC 392[01] stuff */
     121#define XMLNS_TLS          "urn:ietf:params:xml:ns:xmpp-tls"
     122#define XMLNS_SASL         "urn:ietf:params:xml:ns:xmpp-sasl"
     123#define XMLNS_BIND         "urn:ietf:params:xml:ns:xmpp-bind"
     124#define XMLNS_SESSION      "urn:ietf:params:xml:ns:xmpp-session"
     125#define XMLNS_STANZA_ERROR "urn:ietf:params:xml:ns:xmpp-stanzas"
     126#define XMLNS_STREAM_ERROR "urn:ietf:params:xml:ns:xmpp-streams"
     127#define XMLNS_ROSTER       "jabber:iq:roster"
     128
     129/* Some supported extensions/legacy stuff */
     130#define XMLNS_AUTH         "jabber:iq:auth"                     /* XEP-0078 */
     131#define XMLNS_VERSION      "jabber:iq:version"                  /* XEP-0092 */
     132#define XMLNS_TIME         "jabber:iq:time"                     /* XEP-0090 */
     133#define XMLNS_VCARD        "vcard-temp"                         /* XEP-0054 */
     134#define XMLNS_CHATSTATES   "http://jabber.org/protocol/chatstates"  /* 0085 */
     135#define XMLNS_DISCOVER     "http://jabber.org/protocol/disco#info"  /* 0030 */
     136
     137/* iq.c */
     138xt_status jabber_pkt_iq( struct xt_node *node, gpointer data );
     139int jabber_init_iq_auth( struct im_connection *ic );
     140xt_status jabber_pkt_bind_sess( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
     141int jabber_get_roster( struct im_connection *ic );
     142int jabber_get_vcard( struct im_connection *ic, char *bare_jid );
     143int jabber_add_to_roster( struct im_connection *ic, char *handle, char *name );
     144int jabber_remove_from_roster( struct im_connection *ic, char *handle );
     145
     146/* message.c */
     147xt_status jabber_pkt_message( struct xt_node *node, gpointer data );
     148
     149/* presence.c */
     150xt_status jabber_pkt_presence( struct xt_node *node, gpointer data );
     151int presence_send_update( struct im_connection *ic );
     152int presence_send_request( struct im_connection *ic, char *handle, char *request );
     153
     154/* jabber_util.c */
     155char *set_eval_priority( set_t *set, char *value );
     156char *set_eval_tls( set_t *set, char *value );
     157struct xt_node *jabber_make_packet( char *name, char *type, char *to, struct xt_node *children );
     158struct xt_node *jabber_make_error_packet( struct xt_node *orig, char *err_cond, char *err_type );
     159void jabber_cache_add( struct im_connection *ic, struct xt_node *node, jabber_cache_event func );
     160struct xt_node *jabber_cache_get( struct im_connection *ic, char *id );
     161void jabber_cache_entry_free( gpointer entry );
     162void jabber_cache_clean( struct im_connection *ic );
     163const struct jabber_away_state *jabber_away_state_by_code( char *code );
     164const struct jabber_away_state *jabber_away_state_by_name( char *name );
     165void jabber_buddy_ask( struct im_connection *ic, char *handle );
     166char *jabber_normalize( char *orig );
     167
     168typedef enum
     169{
     170        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). */
     172} get_buddy_flags_t;
     173
     174struct jabber_buddy *jabber_buddy_add( struct im_connection *ic, char *full_jid );
     175struct jabber_buddy *jabber_buddy_by_jid( struct im_connection *ic, char *jid, get_buddy_flags_t flags );
     176int jabber_buddy_remove( struct im_connection *ic, char *full_jid );
     177int jabber_buddy_remove_bare( struct im_connection *ic, char *bare_jid );
     178
     179extern const struct jabber_away_state jabber_away_state_list[];
     180
     181/* io.c */
     182int jabber_write_packet( struct im_connection *ic, struct xt_node *node );
     183int jabber_write( struct im_connection *ic, char *buf, int len );
     184gboolean jabber_connected_plain( gpointer data, gint source, b_input_condition cond );
     185gboolean jabber_connected_ssl( gpointer data, void *source, b_input_condition cond );
     186gboolean jabber_start_stream( struct im_connection *ic );
     187void jabber_end_stream( struct im_connection *ic );
     188
     189/* sasl.c */
     190xt_status sasl_pkt_mechanisms( struct xt_node *node, gpointer data );
     191xt_status sasl_pkt_challenge( struct xt_node *node, gpointer data );
     192xt_status sasl_pkt_result( struct xt_node *node, gpointer data );
     193gboolean sasl_supported( struct im_connection *ic );
     194
    35195#endif
    36 
    37 #include "lib.h"
    38 
    39 
    40 #ifndef INCL_JABBER_H
    41 #define INCL_JABBER_H
    42 
    43 #ifdef __cplusplus
    44 extern "C" {
    45 #endif
    46 
    47 /* --------------------------------------------------------- */
    48 /*                                                           */
    49 /* JID structures & constants                                */
    50 /*                                                           */
    51 /* --------------------------------------------------------- */
    52 #define JID_RESOURCE 1
    53 #define JID_USER     2
    54 #define JID_SERVER   4
    55 
    56 typedef struct jid_struct
    57 {
    58     pool               p;
    59     char*              resource;
    60     char*              user;
    61     char*              server;
    62     char*              full;
    63     struct jid_struct *next; /* for lists of jids */
    64 } *jid;
    65  
    66 jid     jid_new(pool p, char *idstr);          /* Creates a jabber id from the idstr */
    67 void    jid_set(jid id, char *str, int item);  /* Individually sets jid components */
    68 char*   jid_full(jid id);                      /* Builds a string type=user/resource@server from the jid data */
    69 int     jid_cmp(jid a, jid b);                 /* Compares two jid's, returns 0 for perfect match */
    70 int     jid_cmpx(jid a, jid b, int parts);     /* Compares just the parts specified as JID_|JID_ */
    71 jid     jid_append(jid a, jid b);              /* Appending b to a (list), no dups */
    72 xmlnode jid_xres(jid id);                      /* Returns xmlnode representation of the resource?query=string */
    73 xmlnode jid_nodescan(jid id, xmlnode x);       /* Scans the children of the node for a matching jid attribute */
    74 jid     jid_user(jid a);                       /* returns the same jid but just of the user@host part */
    75 
    76 
    77 /* --------------------------------------------------------- */
    78 /*                                                           */
    79 /* JPacket structures & constants                            */
    80 /*                                                           */
    81 /* --------------------------------------------------------- */
    82 #define JPACKET_UNKNOWN   0x00
    83 #define JPACKET_MESSAGE   0x01
    84 #define JPACKET_PRESENCE  0x02
    85 #define JPACKET_IQ        0x04
    86 #define JPACKET_S10N      0x08
    87 
    88 #define JPACKET__UNKNOWN      0
    89 #define JPACKET__NONE         1
    90 #define JPACKET__ERROR        2
    91 #define JPACKET__CHAT         3
    92 #define JPACKET__GROUPCHAT    4
    93 #define JPACKET__GET          5
    94 #define JPACKET__SET          6
    95 #define JPACKET__RESULT       7
    96 #define JPACKET__SUBSCRIBE    8
    97 #define JPACKET__SUBSCRIBED   9
    98 #define JPACKET__UNSUBSCRIBE  10
    99 #define JPACKET__UNSUBSCRIBED 11
    100 #define JPACKET__AVAILABLE    12
    101 #define JPACKET__UNAVAILABLE  13
    102 #define JPACKET__PROBE        14
    103 #define JPACKET__HEADLINE     15
    104 #define JPACKET__INVISIBLE    16
    105 
    106 typedef struct jpacket_struct
    107 {
    108     unsigned char type;
    109     int           subtype;
    110     int           flag;
    111     void*         aux1;
    112     xmlnode       x;
    113     jid           to;
    114     jid           from;
    115     char*         iqns;
    116     xmlnode       iq;
    117     pool          p;
    118 } *jpacket, _jpacket;
    119  
    120 jpacket jpacket_new(xmlnode x);     /* Creates a jabber packet from the xmlnode */
    121 int     jpacket_subtype(jpacket p); /* Returns the subtype value (looks at xmlnode for it) */
    122 
    123 
    124 /* --------------------------------------------------------- */
    125 /*                                                           */
    126 /* Presence Proxy DB structures & constants                  */
    127 /*                                                           */
    128 /* --------------------------------------------------------- */
    129 typedef struct ppdb_struct
    130 {                             
    131     jid     id;                /* entry data */
    132     int     pri;
    133     xmlnode x;
    134     struct ppdb_struct* user;  /* linked list for user@server */
    135     pool                p;     /* db-level data */
    136     struct ppdb_struct* next;
    137 } _ppdb, *ppdb;
    138 
    139 ppdb    ppdb_insert(ppdb db, jid id, xmlnode x); /* Inserts presence into the proxy */
    140 xmlnode ppdb_primary(ppdb db, jid id);           /* Fetches the matching primary presence for the id */
    141 void    ppdb_free(ppdb db);                      /* Frees the db and all entries */
    142 xmlnode ppdb_get(ppdb db, jid id);               /* Called successively to return each presence xmlnode */
    143                                                  /*   for the id and children, returns NULL at the end */
    144 
    145 
    146 /* --------------------------------------------------------- */
    147 /*                                                           */
    148 /* Simple Jabber Rate limit functions                        */
    149 /*                                                           */
    150 /* --------------------------------------------------------- */
    151 typedef struct jlimit_struct
    152 {
    153     char *key;
    154     int start;
    155     int points;
    156     int maxt, maxp;
    157     pool p;
    158 } *jlimit, _jlimit;
    159  
    160 jlimit jlimit_new(int maxt, int maxp);
    161 void jlimit_free(jlimit r);
    162 int jlimit_check(jlimit r, char *key, int points);
    163 
    164 
    165 /* --------------------------------------------------------- */
    166 /*                                                           */
    167 /* Error structures & constants                              */
    168 /*                                                           */
    169 /* --------------------------------------------------------- */
    170 typedef struct terror_struct
    171 {
    172     int  code;
    173     char msg[64];
    174 } terror;
    175 
    176 #define TERROR_BAD           (terror){400,"Bad Request"}
    177 #define TERROR_AUTH          (terror){401,"Unauthorized"}
    178 #define TERROR_PAY           (terror){402,"Payment Required"}
    179 #define TERROR_FORBIDDEN     (terror){403,"Forbidden"}
    180 #define TERROR_NOTFOUND      (terror){404,"Not Found"}
    181 #define TERROR_NOTALLOWED    (terror){405,"Not Allowed"}
    182 #define TERROR_NOTACCEPTABLE (terror){406,"Not Acceptable"}
    183 #define TERROR_REGISTER      (terror){407,"Registration Required"}
    184 #define TERROR_REQTIMEOUT    (terror){408,"Request Timeout"}
    185 #define TERROR_CONFLICT      (terror){409,"Conflict"}
    186 
    187 #define TERROR_INTERNAL   (terror){500,"Internal Server Error"}
    188 #define TERROR_NOTIMPL    (terror){501,"Not Implemented"}
    189 #define TERROR_EXTERNAL   (terror){502,"Remote Server Error"}
    190 #define TERROR_UNAVAIL    (terror){503,"Service Unavailable"}
    191 #define TERROR_EXTTIMEOUT (terror){504,"Remote Server Timeout"}
    192 #define TERROR_DISCONNECTED (terror){510,"Disconnected"}
    193 
    194 /* --------------------------------------------------------- */
    195 /*                                                           */
    196 /* Namespace constants                                       */
    197 /*                                                           */
    198 /* --------------------------------------------------------- */
    199 #define NSCHECK(x,n) (j_strcmp(xmlnode_get_attrib(x,"xmlns"),n) == 0)
    200 
    201 #define NS_CLIENT    "jabber:client"
    202 #define NS_SERVER    "jabber:server"
    203 #define NS_AUTH      "jabber:iq:auth"
    204 #define NS_REGISTER  "jabber:iq:register"
    205 #define NS_ROSTER    "jabber:iq:roster"
    206 #define NS_OFFLINE   "jabber:x:offline"
    207 #define NS_AGENT     "jabber:iq:agent"
    208 #define NS_AGENTS    "jabber:iq:agents"
    209 #define NS_DELAY     "jabber:x:delay"
    210 #define NS_VERSION   "jabber:iq:version"
    211 #define NS_TIME      "jabber:iq:time"
    212 #define NS_VCARD     "vcard-temp"
    213 #define NS_PRIVATE   "jabber:iq:private"
    214 #define NS_SEARCH    "jabber:iq:search"
    215 #define NS_OOB       "jabber:iq:oob"
    216 #define NS_XOOB      "jabber:x:oob"
    217 #define NS_ADMIN     "jabber:iq:admin"
    218 #define NS_FILTER    "jabber:iq:filter"
    219 #define NS_AUTH_0K   "jabber:iq:auth:0k"
    220 
    221 
    222 /* --------------------------------------------------------- */
    223 /*                                                           */
    224 /* Message Types                                             */
    225 /*                                                           */
    226 /* --------------------------------------------------------- */
    227 #define TMSG_NORMAL     "normal"
    228 #define TMSG_ERROR      "error"
    229 #define TMSG_CHAT       "chat"
    230 #define TMSG_GROUPCHAT  "groupchat"
    231 #define TMSG_HEADLINE   "headline"
    232 
    233 
    234 /* --------------------------------------------------------- */
    235 /*                                                           */
    236 /* JUtil functions                                           */
    237 /*                                                           */
    238 /* --------------------------------------------------------- */
    239 xmlnode jutil_presnew(int type, char *to, char *status); /* Create a skeleton presence packet */
    240 xmlnode jutil_iqnew(int type, char *ns);                 /* Create a skeleton iq packet */
    241 xmlnode jutil_msgnew(char *type, char *to, char *subj, char *body);
    242                                                          /* Create a skeleton message packet */
    243 xmlnode jutil_header(char* xmlns, char* server);         /* Create a skeleton stream packet */
    244 int     jutil_priority(xmlnode x);                       /* Determine priority of this packet */
    245 void    jutil_tofrom(xmlnode x);                         /* Swaps to/from fields on a packet */
    246 xmlnode jutil_iqresult(xmlnode x);                       /* Generate a skeleton iq/result, given a iq/query */
    247 char*   jutil_timestamp(void);                           /* Get stringified timestamp */
    248 void    jutil_error(xmlnode x, terror E);                /* Append an <error> node to x */
    249 void    jutil_delay(xmlnode msg, char *reason);          /* Append a delay packet to msg */
    250 char*   jutil_regkey(char *key, char *seed);             /* pass a seed to generate a key, pass the key again to validate (returns it) */
    251 
    252 
    253 /* --------------------------------------------------------- */
    254 /*                                                           */
    255 /* JConn structures & functions                              */
    256 /*                                                           */
    257 /* --------------------------------------------------------- */
    258 #define JCONN_STATE_OFF       0
    259 #define JCONN_STATE_CONNECTED 1
    260 #define JCONN_STATE_ON        2
    261 #define JCONN_STATE_AUTH      3
    262 
    263 typedef struct jconn_struct
    264 {
    265     /* Core structure */
    266     pool        p;             /* Memory allocation pool */
    267     int         state;     /* Connection state flag */
    268     int         fd;            /* Connection file descriptor */
    269     jid         user;      /* User info */
    270     char        *pass;     /* User passwd */
    271 
    272     /* Stream stuff */
    273     int         id;        /* id counter for jab_getid() function */
    274     char        idbuf[9];  /* temporary storage for jab_getid() */
    275     char        *sid;      /* stream id from server, for digest auth */
    276     XML_Parser  parser;    /* Parser instance */
    277     xmlnode     current;   /* Current node in parsing instance.. */
    278 
    279     /* Event callback ptrs */
    280     void (*on_state)(struct jconn_struct *j, int state);
    281     void (*on_packet)(struct jconn_struct *j, jpacket p);
    282 
    283 } *jconn, jconn_struct;
    284 
    285 typedef void (*jconn_state_h)(jconn j, int state);
    286 typedef void (*jconn_packet_h)(jconn j, jpacket p);
    287 
    288 
    289 jconn jab_new(char *user, char *pass);
    290 void jab_delete(jconn j);
    291 void jab_state_handler(jconn j, jconn_state_h h);
    292 void jab_packet_handler(jconn j, jconn_packet_h h);
    293 void jab_start(jconn j);
    294 void jab_stop(jconn j);
    295 
    296 int jab_getfd(jconn j);
    297 jid jab_getjid(jconn j);
    298 char *jab_getsid(jconn j);
    299 char *jab_getid(jconn j);
    300 
    301 void jab_send(jconn j, xmlnode x);
    302 void jab_send_raw(jconn j, const char *str);
    303 void jab_recv(jconn j);
    304 void jab_poll(jconn j, int timeout);
    305 
    306 char *jab_auth(jconn j);
    307 char *jab_reg(jconn j);
    308 
    309 
    310 
    311 #ifdef __cplusplus
    312 }
    313 #endif
    314 
    315 #endif  /* INCL_JABBER_H */
  • protocols/msn/msn.c

    r348c11b rae3c4fa  
    2929static char *msn_set_display_name( set_t *set, char *value );
    3030
    31 static void msn_acc_init( account_t *acc )
     31static void msn_init( account_t *acc )
    3232{
    3333        set_t *s;
     
    3939static void msn_login( account_t *acc )
    4040{
    41         struct gaim_connection *gc = new_gaim_conn( acc );
     41        struct im_connection *ic = imcb_new( acc );
    4242        struct msn_data *md = g_new0( struct msn_data, 1 );
    4343       
    44         gc->proto_data = md;
     44        ic->proto_data = md;
    4545        md->fd = -1;
    4646       
    4747        if( strchr( acc->user, '@' ) == NULL )
    4848        {
    49                 hide_login_progress( gc, "Invalid account name" );
    50                 signoff( gc );
     49                imcb_error( ic, "Invalid account name" );
     50                imc_logout( ic, FALSE );
    5151                return;
    5252        }
    5353       
    54         set_login_progress( gc, 1, "Connecting" );
    55        
    56         md->fd = proxy_connect( "messenger.hotmail.com", 1863, msn_ns_connected, gc );
     54        imcb_log( ic, "Connecting" );
     55       
     56        md->fd = proxy_connect( "messenger.hotmail.com", 1863, msn_ns_connected, ic );
    5757        if( md->fd < 0 )
    5858        {
    59                 hide_login_progress( gc, "Could not connect to server" );
    60                 signoff( gc );
     59                imcb_error( ic, "Could not connect to server" );
     60                imc_logout( ic, TRUE );
    6161                return;
    6262        }
    6363       
    64         md->gc = gc;
     64        md->ic = ic;
    6565        md->away_state = msn_away_state_list;
    6666       
    67         msn_connections = g_slist_append( msn_connections, gc );
    68 }
    69 
    70 static void msn_close( struct gaim_connection *gc )
    71 {
    72         struct msn_data *md = gc->proto_data;
     67        msn_connections = g_slist_append( msn_connections, ic );
     68}
     69
     70static void msn_logout( struct im_connection *ic )
     71{
     72        struct msn_data *md = ic->proto_data;
    7373        GSList *l;
    7474       
     
    9696                                m = l->data;
    9797                       
    98                                 serv_got_crap( gc, "Warning: Closing down MSN connection with unsent message to %s, you'll have to resend it.", m->who );
     98                                imcb_log( ic, "Warning: Closing down MSN connection with unsent message to %s, you'll have to resend it.", m->who );
    9999                                g_free( m->who );
    100100                                g_free( m->text );
     
    111111        }
    112112       
    113         for( l = gc->permit; l; l = l->next )
     113        for( l = ic->permit; l; l = l->next )
    114114                g_free( l->data );
    115         g_slist_free( gc->permit );
    116        
    117         for( l = gc->deny; l; l = l->next )
     115        g_slist_free( ic->permit );
     116       
     117        for( l = ic->deny; l; l = l->next )
    118118                g_free( l->data );
    119         g_slist_free( gc->deny );
    120        
    121         msn_connections = g_slist_remove( msn_connections, gc );
    122 }
    123 
    124 static int msn_send_im( struct gaim_connection *gc, char *who, char *message, int len, int away )
     119        g_slist_free( ic->deny );
     120       
     121        msn_connections = g_slist_remove( msn_connections, ic );
     122}
     123
     124static int msn_buddy_msg( struct im_connection *ic, char *who, char *message, int away )
    125125{
    126126        struct msn_switchboard *sb;
    127         struct msn_data *md = gc->proto_data;
    128        
    129         if( ( sb = msn_sb_by_handle( gc, who ) ) )
     127        struct msn_data *md = ic->proto_data;
     128       
     129        if( ( sb = msn_sb_by_handle( ic, who ) ) )
    130130        {
    131131                return( msn_sb_sendmessage( sb, message ) );
     
    142142               
    143143                /* FIXME: *CHECK* the reliability of using spare sb's! */
    144                 if( ( sb = msn_sb_spare( gc ) ) )
     144                if( ( sb = msn_sb_spare( ic ) ) )
    145145                {
    146146                        debug( "Trying to use a spare switchboard to message %s", who );
     
    160160                /* If we reach this line, there was no spare switchboard, so let's make one. */
    161161                g_snprintf( buf, sizeof( buf ), "XFR %d SB\r\n", ++md->trId );
    162                 if( !msn_write( gc, buf, strlen( buf ) ) )
     162                if( !msn_write( ic, buf, strlen( buf ) ) )
    163163                {
    164164                        g_free( m->who );
     
    180180}
    181181
    182 static GList *msn_away_states( struct gaim_connection *gc )
    183 {
    184         GList *l = NULL;
     182static GList *msn_away_states( struct im_connection *ic )
     183{
     184        static GList *l = NULL;
    185185        int i;
    186186       
    187         for( i = 0; msn_away_state_list[i].number > -1; i ++ )
    188                 l = g_list_append( l, (void*) msn_away_state_list[i].name );
    189        
    190         return( l );
    191 }
    192 
    193 static char *msn_get_status_string( struct gaim_connection *gc, int number )
    194 {
    195         const struct msn_away_state *st = msn_away_state_by_number( number );
    196        
    197         if( st )
    198                 return( (char*) st->name );
    199         else
    200                 return( "" );
    201 }
    202 
    203 static void msn_set_away( struct gaim_connection *gc, char *state, char *message )
     187        if( l == NULL )
     188                for( i = 0; msn_away_state_list[i].number > -1; i ++ )
     189                        l = g_list_append( l, (void*) msn_away_state_list[i].name );
     190       
     191        return l;
     192}
     193
     194static void msn_set_away( struct im_connection *ic, char *state, char *message )
    204195{
    205196        char buf[1024];
    206         struct msn_data *md = gc->proto_data;
     197        struct msn_data *md = ic->proto_data;
    207198        const struct msn_away_state *st;
    208199       
     
    216207       
    217208        g_snprintf( buf, sizeof( buf ), "CHG %d %s\r\n", ++md->trId, st->code );
    218         msn_write( gc, buf, strlen( buf ) );
    219 }
    220 
    221 static void msn_set_info( struct gaim_connection *gc, char *info )
    222 {
    223         msn_set_display_name( set_find( &gc->acc->set, "display_name" ), info );
    224 }
    225 
    226 static void msn_get_info(struct gaim_connection *gc, char *who)
     209        msn_write( ic, buf, strlen( buf ) );
     210}
     211
     212static void msn_set_my_name( struct im_connection *ic, char *info )
     213{
     214        msn_set_display_name( set_find( &ic->acc->set, "display_name" ), info );
     215}
     216
     217static void msn_get_info(struct im_connection *ic, char *who)
    227218{
    228219        /* Just make an URL and let the user fetch the info */
    229         serv_got_crap( gc, "%s\n%s: %s%s", _("User Info"), _("For now, fetch yourself"), PROFILE_URL, who );
    230 }
    231 
    232 static void msn_add_buddy( struct gaim_connection *gc, char *who )
    233 {
    234         msn_buddy_list_add( gc, "FL", who, who );
    235 }
    236 
    237 static void msn_remove_buddy( struct gaim_connection *gc, char *who, char *group )
    238 {
    239         msn_buddy_list_remove( gc, "FL", who );
    240 }
    241 
    242 static int msn_chat_send( struct gaim_connection *gc, int id, char *message )
    243 {
    244         struct msn_switchboard *sb = msn_sb_by_id( gc, id );
     220        imcb_log( ic, "%s\n%s: %s%s", _("User Info"), _("For now, fetch yourself"), PROFILE_URL, who );
     221}
     222
     223static void msn_add_buddy( struct im_connection *ic, char *who, char *group )
     224{
     225        msn_buddy_list_add( ic, "FL", who, who );
     226}
     227
     228static void msn_remove_buddy( struct im_connection *ic, char *who, char *group )
     229{
     230        msn_buddy_list_remove( ic, "FL", who );
     231}
     232
     233static void msn_chat_msg( struct groupchat *c, char *message, int flags )
     234{
     235        struct msn_switchboard *sb = msn_sb_by_chat( c );
    245236       
    246237        if( sb )
    247                 return( msn_sb_sendmessage( sb, message ) );
    248         else
    249                 return( 0 );
    250 }
    251 
    252 static void msn_chat_invite( struct gaim_connection *gc, int id, char *msg, char *who )
    253 {
    254         struct msn_switchboard *sb = msn_sb_by_id( gc, id );
     238                msn_sb_sendmessage( sb, message );
     239        /* FIXME: Error handling (although this can't happen unless something's
     240           already severely broken) disappeared here! */
     241}
     242
     243static void msn_chat_invite( struct groupchat *c, char *msg, char *who )
     244{
     245        struct msn_switchboard *sb = msn_sb_by_chat( c );
    255246        char buf[1024];
    256247       
     
    262253}
    263254
    264 static void msn_chat_leave( struct gaim_connection *gc, int id )
    265 {
    266         struct msn_switchboard *sb = msn_sb_by_id( gc, id );
     255static void msn_chat_leave( struct groupchat *c )
     256{
     257        struct msn_switchboard *sb = msn_sb_by_chat( c );
    267258       
    268259        if( sb )
     
    270261}
    271262
    272 static int msn_chat_open( struct gaim_connection *gc, char *who )
     263static struct groupchat *msn_chat_with( struct im_connection *ic, char *who )
    273264{
    274265        struct msn_switchboard *sb;
    275         struct msn_data *md = gc->proto_data;
     266        struct msn_data *md = ic->proto_data;
    276267        char buf[1024];
    277268       
    278         if( ( sb = msn_sb_by_handle( gc, who ) ) )
     269        if( ( sb = msn_sb_by_handle( ic, who ) ) )
    279270        {
    280271                debug( "Converting existing switchboard to %s to a groupchat", who );
    281                 msn_sb_to_chat( sb );
    282                 return( 1 );
     272                return msn_sb_to_chat( sb );
    283273        }
    284274        else
     
    286276                struct msn_message *m;
    287277               
    288                 if( ( sb = msn_sb_spare( gc ) ) )
     278                if( ( sb = msn_sb_spare( ic ) ) )
    289279                {
    290280                        debug( "Trying to reuse an existing switchboard as a groupchat with %s", who );
    291281                        g_snprintf( buf, sizeof( buf ), "CAL %d %s\r\n", ++sb->trId, who );
    292282                        if( msn_sb_write( sb, buf, strlen( buf ) ) )
    293                         {
    294                                 msn_sb_to_chat( sb );
    295                                 return( 1 );
    296                         }
     283                                return msn_sb_to_chat( sb );
    297284                }
    298285               
     
    302289                /* Request a new switchboard. */
    303290                g_snprintf( buf, sizeof( buf ), "XFR %d SB\r\n", ++md->trId );
    304                 if( !msn_write( gc, buf, strlen( buf ) ) )
     291                if( !msn_write( ic, buf, strlen( buf ) ) )
    305292                        return( 0 );
    306293               
     
    313300                md->msgq = g_slist_append( md->msgq, m );
    314301               
    315                 return( 1 );
    316         }
    317        
    318         return( 0 );
    319 }
    320 
    321 static void msn_keepalive( struct gaim_connection *gc )
    322 {
    323         msn_write( gc, "PNG\r\n", strlen( "PNG\r\n" ) );
    324 }
    325 
    326 static void msn_add_permit( struct gaim_connection *gc, char *who )
    327 {
    328         msn_buddy_list_add( gc, "AL", who, who );
    329 }
    330 
    331 static void msn_rem_permit( struct gaim_connection *gc, char *who )
    332 {
    333         msn_buddy_list_remove( gc, "AL", who );
    334 }
    335 
    336 static void msn_add_deny( struct gaim_connection *gc, char *who )
     302                /* FIXME: Can I try to return something here already? */
     303                return NULL;
     304        }
     305       
     306        return NULL;
     307}
     308
     309static void msn_keepalive( struct im_connection *ic )
     310{
     311        msn_write( ic, "PNG\r\n", strlen( "PNG\r\n" ) );
     312}
     313
     314static void msn_add_permit( struct im_connection *ic, char *who )
     315{
     316        msn_buddy_list_add( ic, "AL", who, who );
     317}
     318
     319static void msn_rem_permit( struct im_connection *ic, char *who )
     320{
     321        msn_buddy_list_remove( ic, "AL", who );
     322}
     323
     324static void msn_add_deny( struct im_connection *ic, char *who )
    337325{
    338326        struct msn_switchboard *sb;
    339327       
    340         msn_buddy_list_add( gc, "BL", who, who );
     328        msn_buddy_list_add( ic, "BL", who, who );
    341329       
    342330        /* If there's still a conversation with this person, close it. */
    343         if( ( sb = msn_sb_by_handle( gc, who ) ) )
     331        if( ( sb = msn_sb_by_handle( ic, who ) ) )
    344332        {
    345333                msn_sb_destroy( sb );
     
    347335}
    348336
    349 static void msn_rem_deny( struct gaim_connection *gc, char *who )
    350 {
    351         msn_buddy_list_remove( gc, "BL", who );
    352 }
    353 
    354 static int msn_send_typing( struct gaim_connection *gc, char *who, int typing )
    355 {
    356         if( typing )
    357                 return( msn_send_im( gc, who, TYPING_NOTIFICATION_MESSAGE, strlen( TYPING_NOTIFICATION_MESSAGE ), 0 ) );
     337static void msn_rem_deny( struct im_connection *ic, char *who )
     338{
     339        msn_buddy_list_remove( ic, "BL", who );
     340}
     341
     342static int msn_send_typing( struct im_connection *ic, char *who, int typing )
     343{
     344        if( typing & OPT_TYPING )
     345                return( msn_buddy_msg( ic, who, TYPING_NOTIFICATION_MESSAGE, 0 ) );
    358346        else
    359347                return( 1 );
     
    363351{
    364352        account_t *acc = set->data;
    365         struct gaim_connection *gc = acc->gc;
     353        struct im_connection *ic = acc->ic;
    366354        struct msn_data *md;
    367355        char buf[1024], *fn;
    368356       
    369357        /* Double-check. */
    370         if( gc == NULL )
     358        if( ic == NULL )
    371359                return NULL;
    372360       
    373         md = gc->proto_data;
     361        md = ic->proto_data;
    374362       
    375363        if( strlen( value ) > 129 )
    376364        {
    377                 serv_got_crap( gc, "Maximum name length exceeded" );
     365                imcb_log( ic, "Maximum name length exceeded" );
    378366                return NULL;
    379367        }
     
    381369        fn = msn_http_encode( value );
    382370       
    383         g_snprintf( buf, sizeof( buf ), "REA %d %s %s\r\n", ++md->trId, gc->username, fn );
    384         msn_write( gc, buf, strlen( buf ) );
     371        g_snprintf( buf, sizeof( buf ), "REA %d %s %s\r\n", ++md->trId, ic->acc->user, fn );
     372        msn_write( ic, buf, strlen( buf ) );
    385373        g_free( fn );
    386374       
     
    391379}
    392380
    393 void msn_init()
     381void msn_initmodule()
    394382{
    395383        struct prpl *ret = g_new0(struct prpl, 1);
     
    397385        ret->name = "msn";
    398386        ret->login = msn_login;
    399         ret->acc_init = msn_acc_init;
    400         ret->close = msn_close;
    401         ret->send_im = msn_send_im;
     387        ret->init = msn_init;
     388        ret->logout = msn_logout;
     389        ret->buddy_msg = msn_buddy_msg;
    402390        ret->away_states = msn_away_states;
    403         ret->get_status_string = msn_get_status_string;
    404391        ret->set_away = msn_set_away;
    405         ret->set_info = msn_set_info;
    406392        ret->get_info = msn_get_info;
     393        ret->set_my_name = msn_set_my_name;
    407394        ret->add_buddy = msn_add_buddy;
    408395        ret->remove_buddy = msn_remove_buddy;
    409         ret->chat_send = msn_chat_send;
     396        ret->chat_msg = msn_chat_msg;
    410397        ret->chat_invite = msn_chat_invite;
    411398        ret->chat_leave = msn_chat_leave;
    412         ret->chat_open = msn_chat_open;
     399        ret->chat_with = msn_chat_with;
    413400        ret->keepalive = msn_keepalive;
    414401        ret->add_permit = msn_add_permit;
  • protocols/msn/msn.h

    r348c11b rae3c4fa  
    5757struct msn_data
    5858{
    59         struct gaim_connection *gc;
     59        struct im_connection *ic;
    6060       
    6161        int fd;
     
    7575struct msn_switchboard
    7676{
    77         struct gaim_connection *gc;
     77        struct im_connection *ic;
    7878       
    7979        int fd;
     
    8989        GSList *msgq;
    9090        char *who;
    91         struct conversation *chat;
     91        struct groupchat *chat;
    9292};
    9393
     
    149149
    150150/* msn_util.c */
    151 int msn_write( struct gaim_connection *gc, char *s, int len );
    152 int msn_logged_in( struct gaim_connection *gc );
    153 int msn_buddy_list_add( struct gaim_connection *gc, char *list, char *who, char *realname );
    154 int msn_buddy_list_remove( struct gaim_connection *gc, char *list, char *who );
    155 void msn_buddy_ask( struct gaim_connection *gc, char *handle, char *realname );
     151int msn_write( struct im_connection *ic, char *s, int len );
     152int msn_logged_in( struct im_connection *ic );
     153int msn_buddy_list_add( struct im_connection *ic, char *list, char *who, char *realname );
     154int msn_buddy_list_remove( struct im_connection *ic, char *list, char *who );
     155void msn_buddy_ask( struct im_connection *ic, char *handle, char *realname );
    156156char *msn_findheader( char *text, char *header, int len );
    157157char **msn_linesplit( char *line );
     
    167167/* sb.c */
    168168int msn_sb_write( struct msn_switchboard *sb, char *s, int len );
    169 struct msn_switchboard *msn_sb_create( struct gaim_connection *gc, char *host, int port, char *key, int session );
    170 struct msn_switchboard *msn_sb_by_handle( struct gaim_connection *gc, char *handle );
    171 struct msn_switchboard *msn_sb_by_id( struct gaim_connection *gc, int id );
    172 struct msn_switchboard *msn_sb_spare( struct gaim_connection *gc );
     169struct msn_switchboard *msn_sb_create( struct im_connection *ic, char *host, int port, char *key, int session );
     170struct msn_switchboard *msn_sb_by_handle( struct im_connection *ic, char *handle );
     171struct msn_switchboard *msn_sb_by_chat( struct groupchat *c );
     172struct msn_switchboard *msn_sb_spare( struct im_connection *ic );
    173173int msn_sb_sendmessage( struct msn_switchboard *sb, char *text );
    174 void msn_sb_to_chat( struct msn_switchboard *sb );
     174struct groupchat *msn_sb_to_chat( struct msn_switchboard *sb );
    175175void msn_sb_destroy( struct msn_switchboard *sb );
    176176gboolean msn_sb_connected( gpointer data, gint source, b_input_condition cond );
  • protocols/msn/msn_util.c

    r348c11b rae3c4fa  
    2828#include <ctype.h>
    2929
    30 int msn_write( struct gaim_connection *gc, char *s, int len )
    31 {
    32         struct msn_data *md = gc->proto_data;
     30int msn_write( struct im_connection *ic, char *s, int len )
     31{
     32        struct msn_data *md = ic->proto_data;
    3333        int st;
    3434       
     
    3636        if( st != len )
    3737        {
    38                 hide_login_progress_error( gc, "Short write() to main server" );
    39                 signoff( gc );
     38                imcb_error( ic, "Short write() to main server" );
     39                imc_logout( ic, TRUE );
    4040                return( 0 );
    4141        }
     
    4444}
    4545
    46 int msn_logged_in( struct gaim_connection *gc )
    47 {
    48         account_online( gc );
     46int msn_logged_in( struct im_connection *ic )
     47{
     48        imcb_connected( ic );
    4949       
    5050        return( 0 );
    5151}
    5252
    53 int msn_buddy_list_add( struct gaim_connection *gc, char *list, char *who, char *realname_ )
    54 {
    55         struct msn_data *md = gc->proto_data;
     53int msn_buddy_list_add( struct im_connection *ic, char *list, char *who, char *realname_ )
     54{
     55        struct msn_data *md = ic->proto_data;
    5656        char buf[1024], *realname;
    5757       
     
    5959       
    6060        g_snprintf( buf, sizeof( buf ), "ADD %d %s %s %s\r\n", ++md->trId, list, who, realname );
    61         if( msn_write( gc, buf, strlen( buf ) ) )
     61        if( msn_write( ic, buf, strlen( buf ) ) )
    6262        {
    6363                g_free( realname );
     
    7171}
    7272
    73 int msn_buddy_list_remove( struct gaim_connection *gc, char *list, char *who )
    74 {
    75         struct msn_data *md = gc->proto_data;
     73int msn_buddy_list_remove( struct im_connection *ic, char *list, char *who )
     74{
     75        struct msn_data *md = ic->proto_data;
    7676        char buf[1024];
    7777       
    7878        g_snprintf( buf, sizeof( buf ), "REM %d %s %s\r\n", ++md->trId, list, who );
    79         if( msn_write( gc, buf, strlen( buf ) ) )
     79        if( msn_write( ic, buf, strlen( buf ) ) )
    8080                return( 1 );
    8181       
     
    8585struct msn_buddy_ask_data
    8686{
    87         struct gaim_connection *gc;
     87        struct im_connection *ic;
    8888        char *handle;
    8989        char *realname;
     
    9292static void msn_buddy_ask_yes( gpointer w, struct msn_buddy_ask_data *bla )
    9393{
    94         msn_buddy_list_add( bla->gc, "AL", bla->handle, bla->realname );
    95        
    96         if( find_buddy( bla->gc, bla->handle ) == NULL )
    97                 show_got_added( bla->gc, bla->handle, NULL );
     94        msn_buddy_list_add( bla->ic, "AL", bla->handle, bla->realname );
     95       
     96        if( imcb_find_buddy( bla->ic, bla->handle ) == NULL )
     97                imcb_ask_add( bla->ic, bla->handle, NULL );
    9898       
    9999        g_free( bla->handle );
     
    104104static void msn_buddy_ask_no( gpointer w, struct msn_buddy_ask_data *bla )
    105105{
    106         msn_buddy_list_add( bla->gc, "BL", bla->handle, bla->realname );
     106        msn_buddy_list_add( bla->ic, "BL", bla->handle, bla->realname );
    107107       
    108108        g_free( bla->handle );
     
    111111}
    112112
    113 void msn_buddy_ask( struct gaim_connection *gc, char *handle, char *realname )
     113void msn_buddy_ask( struct im_connection *ic, char *handle, char *realname )
    114114{
    115115        struct msn_buddy_ask_data *bla = g_new0( struct msn_buddy_ask_data, 1 );
    116116        char buf[1024];
    117117       
    118         bla->gc = gc;
     118        bla->ic = ic;
    119119        bla->handle = g_strdup( handle );
    120120        bla->realname = g_strdup( realname );
     
    123123                    "The user %s (%s) wants to add you to his/her buddy list.",
    124124                    handle, realname );
    125         do_ask_dialog( gc, buf, bla, msn_buddy_ask_yes, msn_buddy_ask_no );
     125        imcb_ask( ic, buf, bla, msn_buddy_ask_yes, msn_buddy_ask_no );
    126126}
    127127
  • protocols/msn/ns.c

    r348c11b rae3c4fa  
    3838gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond )
    3939{
    40         struct gaim_connection *gc = data;
     40        struct im_connection *ic = data;
    4141        struct msn_data *md;
    4242        char s[1024];
    4343       
    44         if( !g_slist_find( msn_connections, gc ) )
     44        if( !g_slist_find( msn_connections, ic ) )
    4545                return FALSE;
    4646       
    4747        if( source == -1 )
    4848        {
    49                 hide_login_progress( gc, "Could not connect to server" );
    50                 signoff( gc );
     49                imcb_error( ic, "Could not connect to server" );
     50                imc_logout( ic, TRUE );
    5151                return FALSE;
    5252        }
    5353       
    54         md = gc->proto_data;
     54        md = ic->proto_data;
    5555       
    5656        if( !md->handler )
    5757        {
    5858                md->handler = g_new0( struct msn_handler_data, 1 );
    59                 md->handler->data = gc;
     59                md->handler->data = ic;
    6060                md->handler->exec_command = msn_ns_command;
    6161                md->handler->exec_message = msn_ns_message;
     
    7373       
    7474        g_snprintf( s, sizeof( s ), "VER %d MSNP8 CVR0\r\n", ++md->trId );
    75         if( msn_write( gc, s, strlen( s ) ) )
    76         {
    77                 gc->inpa = b_input_add( md->fd, GAIM_INPUT_READ, msn_ns_callback, gc );
    78                 set_login_progress( gc, 1, "Connected to server, waiting for reply" );
     75        if( msn_write( ic, s, strlen( s ) ) )
     76        {
     77                ic->inpa = b_input_add( md->fd, GAIM_INPUT_READ, msn_ns_callback, ic );
     78                imcb_log( ic, "Connected to server, waiting for reply" );
    7979        }
    8080       
     
    8484static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition cond )
    8585{
    86         struct gaim_connection *gc = data;
    87         struct msn_data *md = gc->proto_data;
     86        struct im_connection *ic = data;
     87        struct msn_data *md = ic->proto_data;
    8888       
    8989        if( msn_handler( md->handler ) == -1 ) /* Don't do this on ret == 0, it's already done then. */
    9090        {
    91                 hide_login_progress( gc, "Error while reading from server" );
    92                 signoff( gc );
     91                imcb_error( ic, "Error while reading from server" );
     92                imc_logout( ic, TRUE );
    9393               
    9494                return FALSE;
     
    100100static int msn_ns_command( gpointer data, char **cmd, int num_parts )
    101101{
    102         struct gaim_connection *gc = data;
    103         struct msn_data *md = gc->proto_data;
     102        struct im_connection *ic = data;
     103        struct msn_data *md = ic->proto_data;
    104104        char buf[1024];
    105105       
     
    114114                if( cmd[2] && strncmp( cmd[2], "MSNP8", 5 ) != 0 )
    115115                {
    116                         hide_login_progress( gc, "Unsupported protocol" );
    117                         signoff( gc );
     116                        imcb_error( ic, "Unsupported protocol" );
     117                        imc_logout( ic, FALSE );
    118118                        return( 0 );
    119119                }
    120120               
    121121                g_snprintf( buf, sizeof( buf ), "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s\r\n",
    122                                                 ++md->trId, gc->username );
    123                 return( msn_write( gc, buf, strlen( buf ) ) );
     122                                                ++md->trId, ic->acc->user );
     123                return( msn_write( ic, buf, strlen( buf ) ) );
    124124        }
    125125        else if( strcmp( cmd[0], "CVR" ) == 0 )
    126126        {
    127127                /* We don't give a damn about the information we just received */
    128                 g_snprintf( buf, sizeof( buf ), "USR %d TWN I %s\r\n", ++md->trId, gc->username );
    129                 return( msn_write( gc, buf, strlen( buf ) ) );
     128                g_snprintf( buf, sizeof( buf ), "USR %d TWN I %s\r\n", ++md->trId, ic->acc->user );
     129                return( msn_write( ic, buf, strlen( buf ) ) );
    130130        }
    131131        else if( strcmp( cmd[0], "XFR" ) == 0 )
     
    136136                if( num_parts == 6 && strcmp( cmd[2], "NS" ) == 0 )
    137137                {
    138                         b_event_remove( gc->inpa );
    139                         gc->inpa = 0;
     138                        b_event_remove( ic->inpa );
     139                        ic->inpa = 0;
    140140                        closesocket( md->fd );
    141141                       
     
    143143                        if( !server )
    144144                        {
    145                                 hide_login_progress_error( gc, "Syntax error" );
    146                                 signoff( gc );
     145                                imcb_error( ic, "Syntax error" );
     146                                imc_logout( ic, TRUE );
    147147                                return( 0 );
    148148                        }
     
    151151                        server = cmd[3];
    152152                       
    153                         set_login_progress( gc, 1, "Transferring to other server" );
    154                        
    155                         md->fd = proxy_connect( server, port, msn_ns_connected, gc );
     153                        imcb_log( ic, "Transferring to other server" );
     154                       
     155                        md->fd = proxy_connect( server, port, msn_ns_connected, ic );
    156156                }
    157157                else if( num_parts == 6 && strcmp( cmd[2], "SB" ) == 0 )
     
    162162                        if( !server )
    163163                        {
    164                                 hide_login_progress_error( gc, "Syntax error" );
    165                                 signoff( gc );
     164                                imcb_error( ic, "Syntax error" );
     165                                imc_logout( ic, TRUE );
    166166                                return( 0 );
    167167                        }
     
    172172                        if( strcmp( cmd[4], "CKI" ) != 0 )
    173173                        {
    174                                 hide_login_progress_error( gc, "Unknown authentication method for switchboard" );
    175                                 signoff( gc );
     174                                imcb_error( ic, "Unknown authentication method for switchboard" );
     175                                imc_logout( ic, TRUE );
    176176                                return( 0 );
    177177                        }
    178178                       
    179179                        debug( "Connecting to a new switchboard with key %s", cmd[5] );
    180                         sb = msn_sb_create( gc, server, port, cmd[5], MSN_SB_NEW );
     180                        sb = msn_sb_create( ic, server, port, cmd[5], MSN_SB_NEW );
    181181                       
    182182                        if( md->msgq )
     
    204204                else
    205205                {
    206                         hide_login_progress_error( gc, "Syntax error" );
    207                         signoff( gc );
     206                        imcb_error( ic, "Syntax error" );
     207                        imc_logout( ic, TRUE );
    208208                        return( 0 );
    209209                }
     
    214214                {
    215215                        /* Time for some Passport black magic... */
    216                         if( !passport_get_id( msn_auth_got_passport_id, gc, gc->username, gc->password, cmd[4] ) )
    217                         {
    218                                 hide_login_progress_error( gc, "Error while contacting Passport server" );
    219                                 signoff( gc );
     216                        if( !passport_get_id( msn_auth_got_passport_id, ic, ic->acc->user, ic->acc->pass, cmd[4] ) )
     217                        {
     218                                imcb_error( ic, "Error while contacting Passport server" );
     219                                imc_logout( ic, TRUE );
    220220                                return( 0 );
    221221                        }
     
    227227                        http_decode( cmd[4] );
    228228                       
    229                         strncpy( gc->displayname, cmd[4], sizeof( gc->displayname ) );
    230                         gc->displayname[sizeof(gc->displayname)-1] = 0;
    231                        
    232                         if( ( s = set_find( &gc->acc->set, "display_name" ) ) )
     229                        strncpy( ic->displayname, cmd[4], sizeof( ic->displayname ) );
     230                        ic->displayname[sizeof(ic->displayname)-1] = 0;
     231                       
     232                        if( ( s = set_find( &ic->acc->set, "display_name" ) ) )
    233233                        {
    234234                                g_free( s->value );
     
    236236                        }
    237237                       
    238                         set_login_progress( gc, 1, "Authenticated, getting buddy list" );
     238                        imcb_log( ic, "Authenticated, getting buddy list" );
    239239                       
    240240                        g_snprintf( buf, sizeof( buf ), "SYN %d 0\r\n", ++md->trId );
    241                         return( msn_write( gc, buf, strlen( buf ) ) );
     241                        return( msn_write( ic, buf, strlen( buf ) ) );
    242242                }
    243243                else
    244244                {
    245                         hide_login_progress( gc, "Unknown authentication type" );
    246                         signoff( gc );
     245                        imcb_error( ic, "Unknown authentication type" );
     246                        imc_logout( ic, FALSE );
    247247                        return( 0 );
    248248                }
     
    252252                if( num_parts != 4 )
    253253                {
    254                         hide_login_progress_error( gc, "Syntax error" );
    255                         signoff( gc );
     254                        imcb_error( ic, "Syntax error" );
     255                        imc_logout( ic, TRUE );
    256256                        return( 0 );
    257257                }
     
    261261                if( md->handler->msglen <= 0 )
    262262                {
    263                         hide_login_progress_error( gc, "Syntax error" );
    264                         signoff( gc );
     263                        imcb_error( ic, "Syntax error" );
     264                        imc_logout( ic, TRUE );
    265265                        return( 0 );
    266266                }
     
    276276                       
    277277                        if( !*cmd[3] || md->buddycount == 0 )
    278                                 msn_logged_in( gc );
     278                                msn_logged_in( ic );
    279279                }
    280280                else
     
    283283                           Let's assume everything is okay. */
    284284                       
    285                         msn_logged_in( gc );
     285                        msn_logged_in( ic );
    286286                }
    287287        }
     
    292292                if( num_parts != 4 && num_parts != 5 )
    293293                {
    294                         hide_login_progress( gc, "Syntax error" );
    295                         signoff( gc );
     294                        imcb_error( ic, "Syntax error" );
     295                        imc_logout( ic, TRUE );
    296296                        return( 0 );
    297297                }
     
    305305                        int num;
    306306                       
    307                         if( cmd[4] != NULL && sscanf( cmd[4], "%d", &num ) == 1 )
     307                        if( cmd[4] != NULL && sscanf( cmd[4], "%d", &num ) == 1 && num < md->groupcount )
    308308                                group = md->grouplist[num];
    309309                       
    310                         add_buddy( gc, group, cmd[1], cmd[2] );
     310                        imcb_add_buddy( ic, cmd[1], group );
     311                        imcb_rename_buddy( ic, cmd[1], cmd[2] );
    311312                }
    312313                if( list & 2 ) /* AL */
    313314                {
    314