Changeset 2288705


Ignore:
Timestamp:
2009-12-07T21:54:19Z (14 years ago)
Author:
Wilmer van der Gaast <wilmer@…>
Branches:
master
Children:
1c3008a
Parents:
aac4017 (diff), 36cf9fd (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merging head.

Files:
3 added
55 edited

Legend:

Unmodified
Added
Removed
  • Makefile

    raac4017 r2288705  
    1010
    1111# Program variables
    12 objects = account.o bitlbee.o crypting.o help.o ipc.o irc.o irc_commands.o nick.o query.o root_commands.o set.o storage.o $(STORAGE_OBJS) user.o dcc.o
    13 headers = account.h bitlbee.h commands.h conf.h config.h crypting.h help.h ipc.h irc.h log.h nick.h query.h set.h sock.h storage.h user.h lib/events.h lib/http_client.h lib/ini.h lib/md5.h lib/misc.h lib/proxy.h lib/sha1.h lib/ssl_client.h lib/url.h protocols/nogaim.h protocols/ft.h lib/ftutil.h
     12objects = account.o bitlbee.o chat.o crypting.o dcc.o help.o ipc.o irc.o irc_commands.o nick.o query.o root_commands.o set.o storage.o $(STORAGE_OBJS) user.o
     13headers = account.h bitlbee.h commands.h conf.h config.h crypting.h help.h ipc.h irc.h log.h nick.h query.h set.h sock.h storage.h user.h lib/events.h lib/ftutil.h lib/http_client.h lib/ini.h lib/md5.h lib/misc.h lib/proxy.h lib/sha1.h lib/ssl_client.h lib/url.h protocols/ft.h protocols/nogaim.h
    1414subdirs = lib protocols
    1515
     
    105105        x=$$(basename $$(pwd)); \
    106106        cd ..; \
    107         tar czf $$x.tar.gz --exclude=debian --exclude=.bzr $$x
     107        tar czf $$x.tar.gz --exclude=debian --exclude=.bzr* $$x
    108108
    109109$(subdirs):
  • account.c

    raac4017 r2288705  
    2727#include "bitlbee.h"
    2828#include "account.h"
     29#include "chat.h"
    2930
    3031account_t *account_add( irc_t *irc, struct prpl *prpl, char *user, char *pass )
     
    5556       
    5657        s = set_add( &a->set, "password", NULL, set_eval_account, a );
    57         s->flags |= ACC_SET_NOSAVE;
     58        s->flags |= ACC_SET_NOSAVE | SET_NULL_OK;
    5859       
    5960        s = set_add( &a->set, "username", NULL, set_eval_account, a );
     
    7778        /* Double-check: We refuse to edit on-line accounts. */
    7879        if( set->flags & ACC_SET_OFFLINE_ONLY && acc->ic )
    79                 return NULL;
    80        
    81         if( strcmp( set->key, "username" ) == 0 )
     80                return SET_INVALID;
     81       
     82        if( strcmp( set->key, "server" ) == 0 )
     83        {
     84                g_free( acc->server );
     85                if( value && *value )
     86                {
     87                        acc->server = g_strdup( value );
     88                        return value;
     89                }
     90                else
     91                {
     92                        acc->server = g_strdup( set->def );
     93                        return g_strdup( set->def );
     94                }
     95        }
     96        else if( strcmp( set->key, "username" ) == 0 )
    8297        {
    8398                g_free( acc->user );
     
    87102        else if( strcmp( set->key, "password" ) == 0 )
    88103        {
    89                 g_free( acc->pass );
    90                 acc->pass = g_strdup( value );
    91                 return NULL;    /* password shouldn't be visible in plaintext! */
    92         }
    93         else if( strcmp( set->key, "server" ) == 0 )
    94         {
    95                 g_free( acc->server );
    96                 if( *value )
    97                 {
    98                         acc->server = g_strdup( value );
    99                         return value;
     104                if( value )
     105                {
     106                        g_free( acc->pass );
     107                        acc->pass = g_strdup( value );
     108                        return NULL;    /* password shouldn't be visible in plaintext! */
    100109                }
    101110                else
    102111                {
    103                         acc->server = NULL;
    104                         return g_strdup( set->def );
     112                        /* NULL can (should) be stored in the set_t
     113                           variable, but is otherwise not correct. */
     114                        return SET_INVALID;
    105115                }
    106116        }
     
    108118        {
    109119                if( !is_bool( value ) )
    110                         return NULL;
     120                        return SET_INVALID;
    111121               
    112122                acc->auto_connect = bool2int( value );
     
    114124        }
    115125       
    116         return NULL;
     126        return SET_INVALID;
    117127}
    118128
     
    181191{
    182192        account_t *a, *l = NULL;
     193        struct chat *c, *nc;
    183194       
    184195        if( acc->ic )
     
    193204                        else
    194205                                irc->accounts = a->next;
     206                       
     207                        for( c = irc->chatrooms; c; c = nc )
     208                        {
     209                                nc = c->next;
     210                                if( acc == c->acc )
     211                                        chat_del( irc, c );
     212                        }
    195213                       
    196214                        while( a->set )
     
    254272       
    255273        /* Sure, call me evil for implementing my own fscanf here, but it's
    256            dead simple and I'm immediately at the next part to parse. */
     274           dead simple and I immediately know where to continue parsing. */
    257275       
    258276        if( *value == 0 )
     
    287305        struct account_reconnect_delay p;
    288306       
    289         return account_reconnect_delay_parse( value, &p ) ? value : NULL;
     307        return account_reconnect_delay_parse( value, &p ) ? value : SET_INVALID;
    290308}
    291309
  • account.h

    raac4017 r2288705  
    5656int account_reconnect_delay( account_t *a );
    5757
    58 #define ACC_SET_NOSAVE          1
    59 #define ACC_SET_OFFLINE_ONLY    2
    60 #define ACC_SET_ONLINE_ONLY     4
     58#define ACC_SET_NOSAVE          0x01
     59#define ACC_SET_OFFLINE_ONLY    0x02
     60#define ACC_SET_ONLINE_ONLY     0x04
    6161
    6262#endif
  • bitlbee.h

    raac4017 r2288705  
    3333
    3434#define PACKAGE "BitlBee"
    35 #define BITLBEE_VERSION "1.2.1"
     35#define BITLBEE_VERSION "1.2.4"
    3636#define VERSION BITLBEE_VERSION
    3737
  • conf.c

    raac4017 r2288705  
    335335                        else
    336336                        {
    337                                 fprintf( stderr, "Error: Unknown setting `%s` in configuration file.\n", ini->key );
     337                                fprintf( stderr, "Error: Unknown setting `%s` in configuration file (line %d).\n", ini->key, ini->line );
    338338                                return 0;
    339339                                /* For now just ignore unknown keys... */
     
    342342                else if( g_strcasecmp( ini->section, "defaults" ) != 0 )
    343343                {
    344                         fprintf( stderr, "Error: Unknown section [%s] in configuration file. "
    345                                          "BitlBee configuration must be put in a [settings] section!\n", ini->section );
     344                        fprintf( stderr, "Error: Unknown section [%s] in configuration file (line %d). "
     345                                         "BitlBee configuration must be put in a [settings] section!\n", ini->section, ini->line );
    346346                        return 0;
    347347                }
  • configure

    raac4017 r2288705  
    267267detect_ldap()
    268268{
    269         TMPFILE=`mktemp`
     269        TMPFILE=$(mktemp)
    270270        if $CC -o $TMPFILE -shared -lldap 2>/dev/null >/dev/null; then
    271271                cat<<EOF>>Makefile.settings
     
    280280                ret=0
    281281        fi
     282}
     283
     284RESOLV_TESTCODE='
     285#include <arpa/nameser.h>
     286#include <resolv.h>
     287
     288int main()
     289{
     290        ns_initparse( NULL, 0, NULL );
     291        ns_parserr( NULL, ns_s_an, 0, NULL );
     292}
     293'
     294
     295detect_resolv_dynamic()
     296{
     297        echo "$RESOLV_TESTCODE" | $CC -o /dev/null -x c - -lresolv >/dev/null 2>/dev/null
     298        if [ "$?" = "0" ]; then
     299                echo 'EFLAGS+=-lresolv' >> Makefile.settings
     300                return 0
     301        fi
     302
     303        return 1
     304}
     305
     306detect_resolv_static()
     307{
     308        for i in $systemlibdirs; do
     309                if [ -f $i/libresolv.a ]; then
     310                        echo "$RESOLV_TESTCODE" | $CC -o /dev/null -x c - -Wl,$i/libresolv.a >/dev/null 2>/dev/null
     311                        if [ "$?" = "0" ]; then
     312                                echo 'EFLAGS+='$i'/libresolv.a' >> Makefile.settings
     313                                return 0
     314                        fi
     315                fi
     316        done
     317
     318        return 1
    282319}
    283320
     
    349386echo 'SSL_CLIENT=ssl_'$ssl'.o' >> Makefile.settings
    350387
    351 for i in $systemlibdirs; do
    352         if [ -f $i/libresolv.a ]; then
    353                 echo '#define HAVE_RESOLV_A' >> config.h
    354                 echo 'EFLAGS+='$i'/libresolv.a' >> Makefile.settings
    355                 break
    356         fi
    357 done
     388if detect_resolv_dynamic || detect_resolv_static; then
     389        echo '#define HAVE_RESOLV_A' >> config.h
     390fi
    358391
    359392STORAGES="text xml"
  • debian/bitlbee.init

    raac4017 r2288705  
    3232fi
    3333
    34 [ "$BITLBEE_DISABLED" = "1" ] && exit 0
    35 
    3634
    3735#
     
    4139        # Make sure BitlBee can actually write its PID...
    4240        touch /var/run/bitlbee.pid
    43         chown bitlbee /var/run/bitlbee.pid
     41        chown bitlbee: /var/run/bitlbee.pid
    4442       
    45         start-stop-daemon --start --quiet --pidfile $PIDFILE \
     43        # Clean up after the bug between 1.2-5 and 1.2.1-2 where BitlBee ran
     44        # as root. (#494656 and #495877) Fixing this in the postinst script
     45        # is not enough since the user will restart his BitlBee after up-
     46        # grading the package, and the BitlBee running as root will then
     47        # save its settings, re-setting ownership of the file to root.
     48        # TODO: Remove this after a few revisions.
     49        find /var/lib/bitlbee -uid 0 -name '*.xml' -exec chown bitlbee: {} \;
     50
     51        start-stop-daemon --start --quiet \
    4652                --exec $DAEMON -- -p $BITLBEE_PORT -P $PIDFILE $BITLBEE_OPTS
    4753}
     
    5864case "$1" in
    5965  start)
     66        [ "$BITLBEE_DISABLED" = "1" ] && exit 0
     67
    6068        echo -n "Starting $DESC: $NAME"
    6169        d_start
  • debian/changelog

    raac4017 r2288705  
    1 bitlbee (1.2-6) UNRELEASED; urgency=low
    2 
    3   * Add Homepage and Vcs-Bzr fields.
    4 
    5  -- Jelmer Vernooij <jelmer@samba.org>  Sun, 11 May 2008 14:18:16 +0200
     1bitlbee (1.2.2-1) unstable; urgency=critical
     2
     3  * New upstream version.
     4  * Fixes a security issue (account hijacking), hence the high priority.
     5  * Using a patch to set the User setting in bitlbee.conf properly to keep
     6    upstream and Debian properly separated in my bzr tree.
     7
     8 -- Wilmer van der Gaast <wilmer@gaast.net>  Wed, 27 Aug 2008 23:59:50 +0100
     9
     10bitlbee (1.2.1-3) unstable; urgency=high
     11
     12  * chown /var/lib/bitlbee/*.xml to bitlbee:bitlbee to clean up after
     13    1.2-5 and the bugfix in 1.2.1-2. (Closes: #495877)
     14  * Moved BITLBEE_DISABLED check to only check when trying to *start*
     15    the daemon. (Closes: #488611)
     16
     17 -- Wilmer van der Gaast <wilmer@gaast.net>  Sat, 23 Aug 2008 18:53:54 +0100
     18
     19bitlbee (1.2.1-2) unstable; urgency=low
     20
     21  * Properly set the User= line to something sensible so BitlBee won't
     22    run as root anymore. 1.2-5 was a bad upload. :-( (Closes: #494656)
     23
     24 -- Wilmer van der Gaast <wilmer@gaast.net>  Tue, 12 Aug 2008 00:36:03 +0100
     25
     26bitlbee (1.2.1-1.1) unstable; urgency=low
     27
     28  * Non-Maintainer Upload
     29  * Use invoke-rc.d as per policy. (Closes: #492637) [Thanks to Matt
     30    Kraai]
     31
     32 -- Don Armstrong <don@debian.org>  Wed, 06 Aug 2008 06:57:18 -0700
     33
     34bitlbee (1.2.1-1) unstable; urgency=low
     35
     36  * New upstream release.
     37  * Add Homepage and Vcs-Bzr fields. (From Jelmer.)
     38
     39 -- Wilmer van der Gaast <wilmer@gaast.net>  Thu, 26 Jun 2008 00:07:50 +0100
    640
    741bitlbee (1.2-5) unstable; urgency=low
  • debian/postinst

    raac4017 r2288705  
    6464fi
    6565
     66if ! grep -qi '^User *= *' /etc/bitlbee/bitlbee.conf; then
     67        echo 'Updating configuration file, enabling User-setting...'
     68        if ! sed -i -e 's/# *User *= *.*/User = bitlbee/i' /etc/bitlbee/bitlbee.conf; then
     69                echo 'Failed! BitlBee may run as root now, please check your configs.'
     70        fi
     71fi
     72
    6673if [ -n "$2" -a "$BITLBEE_UPGRADE_DONT_RESTART" != "1" ]; then
    67         /etc/init.d/bitlbee restart
     74        if which invoke-rc.d >/dev/null 2>&1; then
     75                invoke-rc.d bitlbee restart
     76        else
     77                /etc/init.d/bitlbee restart
     78        fi
    6879fi
    6980
    7081## If we're upgrading, we'll probably skip this next part
    71 if [ -d $CONFDIR ] && chown -R bitlbee $CONFDIR; then
     82if [ -d $CONFDIR ] && chown -R bitlbee: $CONFDIR; then
    7283        echo 'BitlBee (probably) already installed, skipping user/configdir installation'
    7384        exit 0
     
    91102
    92103if [ -z "$2" ]; then
    93         /etc/init.d/bitlbee start
     104        if which invoke-rc.d >/dev/null 2>&1; then
     105                invoke-rc.d bitlbee start
     106        else
     107                /etc/init.d/bitlbee start
     108        fi
    94109fi
  • debian/prerm

    raac4017 r2288705  
    1010        fi
    1111else
    12         /etc/init.d/bitlbee stop || exit 0
     12        if which invoke-rc.d >/dev/null 2>&1; then
     13                invoke-rc.d bitblee stop || exit 0
     14        else
     15                /etc/init.d/bitlbee stop || exit 0
     16        fi
    1317fi
  • debian/rules

    raac4017 r2288705  
    5555        cp utils/* debian/bitlbee/usr/share/doc/bitlbee/examples/
    5656        cp debian/bitlbee.init debian/bitlbee/etc/init.d/bitlbee
     57        patch -p0 < debian/patches/bitlbee.conf.diff
    5758        cd debian/bitlbee/usr/share/; \
    5859                gzip -9 doc/bitlbee/changelog.Debian doc/bitlbee/changelog doc/bitlbee/user-guide.txt \
  • doc/CHANGES

    raac4017 r2288705  
    33
    44http://bugs.bitlbee.org/bitlbee/timeline?daysback=90&changeset=on
     5
     6Version 1.2.4:
     7- Most important change (and main reason for releasing now): Upgraded Yahoo!
     8  module to a newer version to get it working again.
     9- join_chat command replaced with the much better chat command:
     10  * Similar to how account replaced login/slist/logout. Add a chatroom once,
     11    then just /join it like any other room. Also automatic joining at login
     12    time is now possible.
     13  * Note that the old way of starting groupchats (/join #nickname) is now
     14    also deprecated, use "chat with" instead.
     15  * See "help chat" and "help chat add" for more information.
     16- Rewrote bitlbee.conf parser to be less dumb.
     17- Fixed compatibility (hopefully) with AIM mobile messages, certain kinds
     18  of Google Talk chatrooms.
     19- Fixed numerous stability/reliability bugs over the last year.
     20
     21Finished 17 Oct 2009
     22
     23Version 1.2.3:
     24- Fixed one more flaw similar to the previous hijacking bug, caused by incon-
     25  sistent handling of the USTATUS_IDENTIFIED state. All code touching these
     26  variables was reviewed and should be correct now.
     27
     28Finished 7 Sep 2008
     29
     30Version 1.2.2:
     31- Security bugfix: It was possible to hijack accounts (without gaining access
     32  to the old account, it's simply an overwrite)
     33- Some more stability improvements.
     34- Fixed bug where people with non-lowercase nicks couldn't drop their account.
     35- Easier upgrades of non-forking daemon mode servers (using the DEAF
     36  command).
     37- Can be cross-compiled for Win32 now! (No support for SSL yet though, which
     38  makes it less useful for now.)
     39- Exponential backoff on auto-reconnect.
     40- Changing passwords gives less confusing feedback ("password is empty") now.
     41
     42Finished 26 Aug 2008
    543
    644Version 1.2.1:
  • doc/user-guide/Makefile

    raac4017 r2288705  
    1313
    1414%.html: %.db.xml
    15         xsltproc --output $@ http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl $<
     15        xsltproc --output $@ http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl $<
    1616
    1717%.pdf: %.db.xml
  • doc/user-guide/commands.xml

    raac4017 r2288705  
    125125                        <description>
    126126                                <para>
    127                                         This command gives you a list of all the accounts known by BitlBee, including the numbers you'll need for most account commands.
     127                                        This command gives you a list of all the accounts known by BitlBee.
    128128                                </para>
    129129                        </description>
     
    138138                        <description>
    139139                                <para>
    140                                         This account can be used to change various settings for IM accounts. For all protocols, this command can be used to change the handle or the password BitlBee uses to log in and if it should be logged in automatically. Some protocols have additional settings. You can see the settings available for a connection by typing <emphasis>account set &lt;account id&gt;</emphasis>.
     140                                        This command can be used to change various settings for IM accounts. For all protocols, this command can be used to change the handle or the password BitlBee uses to log in and if it should be logged in automatically. Some protocols have additional settings. You can see the settings available for a connection by typing <emphasis>account set &lt;account id&gt;</emphasis>.
    141141                                </para>
    142142                               
    143143                                <para>
    144                                         For more infomation about a setting, see <emphasis>help set &lt;setting&gt;</emphasis>. For details about the syntax of this command, see <emphasis>help set</emphasis>.
     144                                        For more infomation about a setting, see <emphasis>help set &lt;setting&gt;</emphasis>.
    145145                                </para>
    146146                               
    147147                                <para>
    148148                                        The account ID can be a number (see <emphasis>account list</emphasis>), the protocol name or (part of) the screenname, as long as it matches only one connection.
     149                                </para>
     150                        </description>
     151                </bitlbee-command>
     152        </bitlbee-command>
     153
     154        <bitlbee-command name="chat">
     155                <short-description>Chatroom list maintenance</short-description>
     156                <syntax>chat &lt;action&gt; [&lt;arguments&gt;]</syntax>
     157
     158                <description>
     159
     160                        <para>
     161                                Available actions: add, del, list, with and set. See <emphasis>help chat &lt;action&gt;</emphasis> for more information.
     162                        </para>
     163
     164                </description>
     165
     166                <bitlbee-command name="add">
     167                        <syntax>chat add &lt;account&gt; &lt;room&gt; [&lt;channel&gt;]</syntax>
     168
     169                        <description>
     170                                <para>
     171                                        Add a chatroom to the list of chatrooms you're interested in. BitlBee needs this list to map room names to a proper IRC channel name.
     172                                </para>
     173
     174                                <para>
     175                                        After adding a room to your list, you can simply use the IRC /join command to enter the room. Also, you can tell BitlBee to automatically join the room when you log in. (See <emphasis>chat set</emphasis>)
     176                                </para>
     177
     178                                <para>
     179                                        Password-protected rooms work exactly like on IRC, by passing the password as an extra argument to /join.
     180                                </para>
     181                        </description>
     182
     183                </bitlbee-command>
     184
     185                <bitlbee-command name="del">
     186                        <syntax>chat del &lt;chat id&gt;</syntax>
     187
     188                        <description>
     189                                <para>
     190                                        This commands deletes an chatroom from your list.
     191                                </para>
     192
     193                                <para>
     194                                        The room ID can be a number (see <emphasis>chat list</emphasis>), or (part of) the name of the room/channel.
     195                                </para>
     196                        </description>
     197                </bitlbee-command>
     198
     199                <bitlbee-command name="list">
     200                        <syntax>chat list</syntax>
     201
     202                        <description>
     203                                <para>
     204                                        This command gives you a list of all the chatrooms known by BitlBee.
     205                                </para>
     206                        </description>
     207                </bitlbee-command>
     208
     209                <bitlbee-command name="with">
     210                        <syntax>chat with &lt;nickname&gt;</syntax>
     211
     212                        <description>
     213                                <para>
     214                                        While most <emphasis>chat</emphasis> subcommands are about named chatrooms, this command can be used to open an unnamed groupchat with one or more persons. This command is what <emphasis>/join #nickname</emphasis> used to do in older BitlBee versions.
     215                                </para>
     216                        </description>
     217                </bitlbee-command>
     218
     219                <bitlbee-command name="set">
     220                        <syntax>chat set &lt;chat id&gt;</syntax>
     221                        <syntax>chat set &lt;chat id&gt;/&lt;setting&gt;</syntax>
     222                        <syntax>chat set &lt;chat id&gt;/&lt;setting&gt; &lt;value&gt;</syntax>
     223                        <syntax>chat set -del &lt;chat id&gt;/&lt;setting&gt;</syntax>
     224
     225                        <description>
     226                                <para>
     227                                        This command can be used to change various settings for chatrooms.
     228                                </para>
     229                               
     230                                <para>
     231                                        For more infomation about a setting, see <emphasis>help set &lt;setting&gt;</emphasis>.
     232                                </para>
     233                               
     234                                <para>
     235                                        The room ID can be a number (see <emphasis>chat list</emphasis>), or (part of) the name of the room/channel.
    149236                                </para>
    150237                        </description>
     
    303390        </bitlbee-setting>
    304391
     392        <bitlbee-setting name="auto_join" type="boolean" scope="chat">
     393                <default>false</default>
     394
     395                <description>
     396                        <para>
     397                                With this option enabled, BitlBee will automatically join this chatroom when you log in.
     398                        </para>
     399                </description>
     400        </bitlbee-setting>
     401
    305402        <bitlbee-setting name="auto_reconnect" type="boolean" scope="both">
    306403                <default>false</default>
     
    486583        </bitlbee-setting>
    487584
     585        <bitlbee-setting name="nick" type="string" scope="chat">
     586
     587                <description>
     588                        <para>
     589                                You can use this option to set your nickname in a chatroom. You won't see this nickname yourself, but other people in the room will. By default, BitlBee will use your username as the chatroom nickname.
     590                        </para>
     591                </description>
     592        </bitlbee-setting>
     593
    488594        <bitlbee-setting name="ops" type="string" scope="global">
    489595                <default>both</default>
     
    580686        <bitlbee-setting name="resource_select" type="string" scope="account">
    581687                <default>priority</default>
    582                 <possible-values>priority, time</possible-values>
     688                <possible-values>priority, activity</possible-values>
    583689
    584690                <description>
     
    588694
    589695                        <para>
    590                                 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).
     696                                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>activity</emphasis>, messages will be delivered to the resource that was last used to send you a message (or the resource that most recently connected).
    591697                        </para>
    592698                </description>
     
    851957                        <ircline nick="wouter">account set 1/display_name "The majestik møøse"</ircline>
    852958                        <ircline nick="root">display_name = `The majestik møøse'</ircline>
    853                 </ircexample>
    854 
    855         </bitlbee-command>
    856 
    857         <bitlbee-command name="join_chat">
    858                 <short-description>Join a named groupchat/conference room</short-description>
    859                 <syntax>join_chat &lt;connection&gt; &lt;room name&gt; [&lt;channel name&gt;] [&lt;room nickname&gt;] [&lt;password&gt;]</syntax>
    860 
    861                 <description>
    862                         <para>
    863                                 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.
    864                         </para>
    865 
    866                         <para>
    867                                 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.
    868                         </para>
    869 
    870                         <para>
    871                                 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>.
    872                         </para>
    873                 </description>
    874 
    875                 <ircexample>
    876                         <ircline nick="wilmer">join_chat jabber bitlbee@conference.bitlbee.org &amp;bitlbee-help help-me</ircline>
    877959                </ircexample>
    878960
  • doc/user-guide/help.xml

    raac4017 r2288705  
    1 <?xml version="1.0" encoding="iso-8859-1"?>
     1<?xml version="1.0" encoding="utf-8"?>
    22<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
    33
  • doc/user-guide/misc.xml

    raac4017 r2288705  
    6969
    7070<para>
    71 If you want to start a groupchat with the person <emphasis>lisa_msn</emphasis> in it, just join the channel <emphasis>#lisa_msn</emphasis>. BitlBee will refuse to join you to the channel with that name, but it will create a new virtual channel with root, you and lisa_msn in it.
     71To open a groupchat, use the <emphasis>chat with</emphasis> command. For example,  to start a groupchat with the person <emphasis>lisa_msn</emphasis> in it, just type <emphasis>chat with lisa_msn</emphasis>. BitlBee will create a new virtual channel with root, you and lisa_msn in it.
    7272</para>
    7373
    7474<para>
    75 Of course a channel with only two people isn't really exciting yet. So the next step is to invite some other people to the channel. For this, you can use the <emphasis>/invite</emphasis> command of your IRC client. Please do keep in mind that all the people have to be on the same network and contact list! You can't invite Yahoo! buddies into an MSN groupchat.
     75Then, just use the ordinary IRC <emphasis>/invite</emphasis> command to invite more people. Please do keep in mind that all the people have to be on the same network and contact list! You can't invite Yahoo! buddies into an MSN groupchat.
    7676</para>
    7777
    7878<para>
    79 Some protocols (like Jabber) also support named groupchats. BitlBee now supports these too. You can use the <emphasis>join_chat</emphasis> command to join them. See <emphasis>help join_chat</emphasis> for more information.
     79Some protocols (like Jabber) also support named groupchats. BitlBee now supports these too. You can use the <emphasis>chat add</emphasis> command to join them. See <emphasis>help chat add</emphasis> for more information.
    8080</para>
    8181
  • doc/user-guide/user-guide.xml

    raac4017 r2288705  
    1 <?xml version="1.0" encoding="iso-8859-1"?>
     1<?xml version="1.0" encoding="utf-8"?>
    22<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
    33
  • irc.c

    raac4017 r2288705  
    3535GSList *irc_connection_list = NULL;
    3636
    37 static char *passchange( set_t *set, char *value )
     37static char *set_eval_password( set_t *set, char *value )
    3838{
    3939        irc_t *irc = set->data;
    4040       
    41         irc_setpass( irc, value );
    42         irc_usermsg( irc, "Password successfully changed" );
    43         return NULL;
     41        if( irc->status & USTATUS_IDENTIFIED && value )
     42        {
     43                irc_setpass( irc, value );
     44                return NULL;
     45        }
     46        else
     47        {
     48                return SET_INVALID;
     49        }
    4450}
    4551
     
    7884        struct sockaddr_storage sock;
    7985        socklen_t socklen = sizeof( sock );
     86        set_t *s;
    8087       
    8188        irc = g_new0( irc_t, 1 );
     
    137144        irc_connection_list = g_slist_append( irc_connection_list, irc );
    138145       
    139         set_add( &irc->set, "away_devoice", "true",  set_eval_away_devoice, irc );
    140         set_add( &irc->set, "auto_connect", "true", set_eval_bool, irc );
    141         set_add( &irc->set, "auto_reconnect", "false", set_eval_bool, irc );
    142         set_add( &irc->set, "auto_reconnect_delay", "5*3<900", set_eval_account_reconnect_delay, irc );
    143         set_add( &irc->set, "buddy_sendbuffer", "false", set_eval_bool, irc );
    144         set_add( &irc->set, "buddy_sendbuffer_delay", "200", set_eval_int, irc );
    145         set_add( &irc->set, "charset", "utf-8", set_eval_charset, irc );
    146         set_add( &irc->set, "debug", "false", set_eval_bool, irc );
    147         set_add( &irc->set, "default_target", "root", NULL, irc );
    148         set_add( &irc->set, "display_namechanges", "false", set_eval_bool, irc );
    149         set_add( &irc->set, "handle_unknown", "root", NULL, irc );
    150         set_add( &irc->set, "lcnicks", "true", set_eval_bool, irc );
    151         set_add( &irc->set, "ops", "both", set_eval_ops, irc );
    152         set_add( &irc->set, "password", NULL, passchange, irc );
    153         set_add( &irc->set, "private", "true", set_eval_bool, irc );
    154         set_add( &irc->set, "query_order", "lifo", NULL, irc );
    155         set_add( &irc->set, "root_nick", irc->mynick, set_eval_root_nick, irc );
    156         set_add( &irc->set, "save_on_quit", "true", set_eval_bool, irc );
    157         set_add( &irc->set, "simulate_netsplit", "true", set_eval_bool, irc );
    158         set_add( &irc->set, "strip_html", "true", NULL, irc );
    159         set_add( &irc->set, "to_char", ": ", set_eval_to_char, irc );
    160         set_add( &irc->set, "typing_notice", "false", set_eval_bool, irc );
     146        s = set_add( &irc->set, "away_devoice", "true",  set_eval_away_devoice, irc );
     147        s = set_add( &irc->set, "auto_connect", "true", set_eval_bool, irc );
     148        s = set_add( &irc->set, "auto_reconnect", "false", set_eval_bool, irc );
     149        s = set_add( &irc->set, "auto_reconnect_delay", "5*3<900", set_eval_account_reconnect_delay, irc );
     150        s = set_add( &irc->set, "buddy_sendbuffer", "false", set_eval_bool, irc );
     151        s = set_add( &irc->set, "buddy_sendbuffer_delay", "200", set_eval_int, irc );
     152        s = set_add( &irc->set, "charset", "utf-8", set_eval_charset, irc );
     153        s = set_add( &irc->set, "debug", "false", set_eval_bool, irc );
     154        s = set_add( &irc->set, "default_target", "root", NULL, irc );
     155        s = set_add( &irc->set, "display_namechanges", "false", set_eval_bool, irc );
     156        s = set_add( &irc->set, "handle_unknown", "root", NULL, irc );
     157        s = set_add( &irc->set, "lcnicks", "true", set_eval_bool, irc );
     158        s = set_add( &irc->set, "ops", "both", set_eval_ops, irc );
     159        s = set_add( &irc->set, "password", NULL, set_eval_password, irc );
     160        s->flags |= SET_NULL_OK;
     161        s = set_add( &irc->set, "private", "true", set_eval_bool, irc );
     162        s = set_add( &irc->set, "query_order", "lifo", NULL, irc );
     163        s = set_add( &irc->set, "root_nick", irc->mynick, set_eval_root_nick, irc );
     164        s = set_add( &irc->set, "save_on_quit", "true", set_eval_bool, irc );
     165        s = set_add( &irc->set, "simulate_netsplit", "true", set_eval_bool, irc );
     166        s = set_add( &irc->set, "strip_html", "true", NULL, irc );
     167        s = set_add( &irc->set, "to_char", ": ", set_eval_to_char, irc );
     168        s = set_add( &irc->set, "typing_notice", "false", set_eval_bool, irc );
    161169       
    162170        conf_loaddefaults( irc );
     
    232240       
    233241        if( irc->status & USTATUS_IDENTIFIED && set_getbool( &irc->set, "save_on_quit" ) )
    234                 if( storage_save( irc, TRUE ) != STORAGE_OK )
     242                if( storage_save( irc, NULL, TRUE ) != STORAGE_OK )
    235243                        irc_usermsg( irc, "Error while saving settings!" );
    236244       
     
    400408                        }
    401409                       
    402                         if( lines[i] )
    403                         {
    404                                 if( ( cmd = irc_parse_line( lines[i] ) ) == NULL )
    405                                         continue;
     410                        if( lines[i] && ( cmd = irc_parse_line( lines[i] ) ) )
     411                        {
    406412                                irc_exec( irc, cmd );
    407413                                g_free( cmd );
     
    478484        if( line[0] == ':' )
    479485        {
    480                 for( i = 0; line[i] != ' '; i ++ );
     486                for( i = 0; line[i] && line[i] != ' '; i ++ );
    481487                line = line + i;
    482488        }
     
    774780        irc_reply( irc,   3, ":%s", IRCD_INFO );
    775781        irc_reply( irc,   4, "%s %s %s %s", irc->myhost, BITLBEE_VERSION, UMODES UMODES_PRIV, CMODES );
    776         irc_reply( irc,   5, "PREFIX=(ov)@+ CHANTYPES=#& CHANMODES=,,,%s NICKLEN=%d NETWORK=BitlBee CASEMAPPING=rfc1459 MAXTARGETS=1 WATCH=128 :are supported by this server", CMODES, MAX_NICK_LENGTH - 1 );
     782        irc_reply( irc,   5, "PREFIX=(ov)@+ CHANTYPES=%s CHANMODES=,,,%s NICKLEN=%d NETWORK=BitlBee "
     783                             "CASEMAPPING=rfc1459 MAXTARGETS=1 WATCH=128 :are supported by this server",
     784                             CTYPES, CMODES, MAX_NICK_LENGTH - 1 );
    777785        irc_motd( irc );
    778786        irc->umode[0] = '\0';
     
    10151023        user_t *u = NULL;
    10161024       
    1017         if( *nick == '#' || *nick == '&' )
     1025        if( strchr( CTYPES, *nick ) )
    10181026        {
    10191027                if( !( c = irc_chat_by_channel( irc, nick ) ) )
  • irc.h

    raac4017 r2288705  
    3838#define CMODE "t"
    3939#define UMODE "s"
     40#define CTYPES "&#"
    4041
    4142typedef enum
     
    4748        USTATUS_SHUTDOWN = 8
    4849} irc_status_t;
    49 
    50 typedef struct channel
    51 {
    52         char *name;
    53 } channel_t;
    5450
    5551typedef struct irc
     
    8884        struct account *accounts;
    8985        GSList *file_transfers;
     86        struct chat *chatrooms;
    9087       
    9188        struct __USER *users;
     
    10198
    10299#include "user.h"
    103 // #include "nick.h"
    104100
    105101extern GSList *irc_connection_list;
  • irc_commands.c

    raac4017 r2288705  
    2727#include "bitlbee.h"
    2828#include "ipc.h"
     29#include "chat.h"
    2930
    3031static void irc_cmd_pass( irc_t *irc, char **cmd )
     
    125126static void irc_cmd_mode( irc_t *irc, char **cmd )
    126127{
    127         if( *cmd[1] == '#' || *cmd[1] == '&' )
     128        if( strchr( CTYPES, *cmd[1] ) )
    128129        {
    129130                if( cmd[2] )
     
    193194        else if( cmd[1] )
    194195        {
    195                 if( ( cmd[1][0] == '#' || cmd[1][0] == '&' ) && cmd[1][1] )
    196                 {
    197                         user_t *u = user_find( irc, cmd[1] + 1 );
    198                        
    199                         if( u && u->ic && u->ic->acc->prpl->chat_with )
    200                         {
    201                                 irc_reply( irc, 403, "%s :Initializing groupchat in a different channel", cmd[1] );
    202                                
    203                                 if( !u->ic->acc->prpl->chat_with( u->ic, u->handle ) )
    204                                 {
    205                                         irc_usermsg( irc, "Could not open a groupchat with %s.", u->nick );
    206                                 }
    207                         }
    208                         else if( u )
    209                         {
    210                                 irc_reply( irc, 403, "%s :Groupchats are not possible with %s", cmd[1], cmd[1]+1 );
    211                         }
    212                         else
    213                         {
    214                                 irc_reply( irc, 403, "%s :No such nick", cmd[1] );
    215                         }
    216                 }
     196                struct chat *c;
     197               
     198                if( strchr( CTYPES, cmd[1][0] ) == NULL || cmd[1][1] == 0 )
     199                        irc_reply( irc, 479, "%s :Invalid channel name", cmd[1] );
     200                else if( ( c = chat_bychannel( irc, cmd[1] ) ) && c->acc && c->acc->ic )
     201                        chat_join( irc, c, cmd[2] );
    217202                else
    218                 {
    219203                        irc_reply( irc, 403, "%s :No such channel", cmd[1] );
    220                 }
    221204        }
    222205}
     
    433416                        if( g_hash_table_lookup_extended( irc->watches, nick, &okey, &ovalue ) )
    434417                        {
     418                                g_hash_table_remove( irc->watches, okey );
    435419                                g_free( okey );
    436                                 g_hash_table_remove( irc->watches, okey );
    437420                               
    438421                                irc_reply( irc, 602, "%s %s %s %d :%s", nick, "*", "*", 0, "Stopped watching" );
  • lib/events_libevent.c

    raac4017 r2288705  
    3737
    3838static void b_main_restart();
    39 static guint id_next = 1;
     39static guint id_next = 1; /* Next ID to be allocated to an event handler. */
     40static guint id_cur = 0; /* Event ID that we're currently handling. */
     41static guint id_dead; /* Set to 1 if b_event_remove removes id_cur. */
    4042static GHashTable *id_hash;
    41 static int quitting = 0;
     43static int quitting = 0; /* Prepare to quit, stop handling events. */
    4244
    4345/* Since libevent doesn't handle two event handlers for one fd-condition
     
    119121        struct b_event_data *b_ev = data;
    120122        b_input_condition cond = 0;
    121         int id;
     123        gboolean st;
    122124       
    123125        if( fd >= 0 )
     
    133135        /* Since the called function might cancel this handler already
    134136           (which free()s b_ev), we have to remember the ID here. */
    135         id = b_ev->id;
     137        id_cur = b_ev->id;
     138        id_dead = 0;
    136139       
    137140        if( quitting )
    138141        {
    139                 b_event_remove( id );
     142                b_event_remove( id_cur );
    140143                return;
    141144        }
    142145       
    143         if( !b_ev->function( b_ev->data, fd, cond ) )
     146        st = b_ev->function( b_ev->data, fd, cond );
     147        if( id_dead )
     148        {
     149                /* This event was killed already, don't touch it! */
     150                return;
     151        }
     152        else if( !st )
    144153        {
    145154                event_debug( "Handler returned FALSE: " );
    146                 b_event_remove( id );
     155                b_event_remove( id_cur );
    147156        }
    148157        else if( fd == -1 )
    149158        {
     159                /* fd == -1 means it was a timer. These can't be auto-repeated
     160                   so it has to be recreated every time. */
    150161                struct timeval tv;
    151162               
     
    236247        if( b_ev )
    237248        {
     249                if( id == id_cur )
     250                        id_dead = TRUE;
     251               
    238252                g_hash_table_remove( id_hash, &b_ev->id );
    239253                if( b_ev->evinfo.ev_fd >= 0 )
  • lib/http_client.c

    raac4017 r2288705  
    5959        if( error )
    6060        {
    61                 g_free( req );
    62                 return( NULL );
     61                http_free( req );
     62                return NULL;
    6363        }
    6464       
     
    160160       
    161161        req->func( req );
    162        
    163         g_free( req->request );
    164         g_free( req );
    165        
     162        http_free( req );
    166163        return FALSE;
    167164}
     
    444441       
    445442        req->func( req );
    446        
     443        http_free( req );
     444        return FALSE;
     445}
     446
     447void http_free( struct http_request *req )
     448{
    447449        g_free( req->request );
    448450        g_free( req->reply_headers );
    449451        g_free( req->status_string );
    450452        g_free( req );
    451        
    452         return FALSE;
    453 }
     453}
     454
  • lib/http_client.h

    raac4017 r2288705  
    8181void *http_dorequest( char *host, int port, int ssl, char *request, http_input_function func, gpointer data );
    8282void *http_dorequest_url( char *url_string, http_input_function func, gpointer data );
     83
     84void http_free( struct http_request *req );
  • lib/ini.c

    raac4017 r2288705  
    22  * BitlBee -- An IRC to other IM-networks gateway                     *
    33  *                                                                    *
    4   * Copyright 2002-2005 Wilmer van der Gaast and others                *
     4  * Copyright 2002-2008 Wilmer van der Gaast and others                *
    55  \********************************************************************/
    66
     
    2828ini_t *ini_open( char *file )
    2929{
    30         ini_t *ini = g_new0( ini_t, 1 );
     30        int fd;
     31        ini_t *ini = NULL;
     32        struct stat fi;
    3133       
    32         if( ( ini->fp = fopen( file, "r" ) ) == NULL )
     34        if( ( fd = open( file, O_RDONLY ) ) != -1 &&
     35            fstat( fd, &fi ) == 0 &&
     36            fi.st_size <= 16384 &&
     37            ( ini = g_malloc( sizeof( ini_t ) + fi.st_size + 1 ) ) &&
     38            read( fd, ini->file, fi.st_size ) == fi.st_size )
    3339        {
    34                 g_free( ini );
    35                 return( NULL );
     40                memset( ini, 0, sizeof( ini_t ) );
     41                ini->size = fi.st_size;
     42                ini->file[ini->size] = 0;
     43                ini->cur = ini->file;
     44                ini->c_section = "";
     45               
     46                close( fd );
     47               
     48                return ini;
    3649        }
     50
     51        if( fd >= 0 )
     52                close( fd );
    3753       
    38         return( ini );
     54        ini_close( ini );
     55
     56        return NULL;
     57}
     58
     59/* Strips leading and trailing whitespace and returns a pointer to the first
     60   non-ws character of the given string. */
     61static char *ini_strip_whitespace( char *in )
     62{
     63        char *e;
     64
     65        while( isspace( *in ) )
     66                in++;
     67
     68        e = in + strlen( in ) - 1;
     69        while( e > in && isspace( *e ) )
     70                e--;
     71        e[1] = 0;
     72       
     73        return in;
    3974}
    4075
    4176int ini_read( ini_t *file )
    4277{
    43         char key[MAX_STRING], s[MAX_STRING], *t;
    44         int i;
     78        char *s;
    4579       
    46         while( !feof( file->fp ) )
     80        while( file->cur && file->cur < file->file + file->size )
    4781        {
    48                 *s = 0;
    49                 fscanf( file->fp, "%127[^\n#]s", s );
    50                 fscanf( file->fp, "%*[^\n]s" );
    51                 fgetc( file->fp );              /* Skip newline         */
    52                 file->line ++;
    53                 if( strchr( s, '=' ) )
     82                char *e, *next;
     83               
     84                file->line++;
     85
     86                /* Find the end of line */
     87                if( ( e = strchr( file->cur, '\n' ) ) != NULL )
    5488                {
    55                         sscanf( s, "%[^ =]s", key );
    56                         if( ( t = strchr( key, '.' ) ) )
     89                        *e = 0;
     90                        next = e + 1;
     91                }
     92                else
     93                {
     94                        /* No more lines. */
     95                        e = file->cur + strlen( file->cur );
     96                        next = NULL;
     97                }
     98               
     99                /* Comment? */
     100                if( ( s = strchr( file->cur, '#' ) ) != NULL )
     101                        *s = 0;
     102               
     103                file->cur = ini_strip_whitespace( file->cur );
     104               
     105                if( *file->cur == '[' )
     106                {
     107                        file->cur++;
     108                        if( ( s = strchr( file->cur, ']' ) ) != NULL )
    57109                        {
    58                                 *t = 0;
    59                                 strcpy( file->section, key );
    60                                 t ++;
     110                                *s = 0;
     111                                file->c_section = file->cur;
     112                        }
     113                }
     114                else if( ( s = strchr( file->cur, '=' ) ) != NULL )
     115                {
     116                        *s = 0;
     117                        file->key = ini_strip_whitespace( file->cur );
     118                        file->value = ini_strip_whitespace( s + 1 );
     119                       
     120                        if( ( s = strchr( file->key, '.' ) ) != NULL )
     121                        {
     122                                *s = 0;
     123                                file->section = file->key;
     124                                file->key = s + 1;
    61125                        }
    62126                        else
    63127                        {
    64                                 strcpy( file->section, file->c_section );
    65                                 t = key;
     128                                file->section = file->c_section;
    66129                        }
    67                         sscanf( t, "%s", file->key );
    68                         t = strchr( s, '=' ) + 1;
    69                         for( i = 0; t[i] == ' '; i ++ );
    70                         strcpy( file->value, &t[i] );
    71                         for( i = strlen( file->value ) - 1; file->value[i] == 32; i -- )
    72                                 file->value[i] = 0;
    73130                       
    74                         return( 1 );
     131                        file->cur = next;
     132                        return 1;
    75133                }
    76                 else if( ( t = strchr( s, '[' ) ) )
    77                 {
    78                         strcpy( file->c_section, t + 1 );
    79                         t = strchr( file->c_section, ']' );
    80                         *t = 0;
    81                 }
     134                /* else: noise/comment/etc, let's just ignore it. */
     135
     136                file->cur = next;
    82137        }
    83         return( 0 );
     138       
     139        return 0;
    84140}
    85141
    86142void ini_close( ini_t *file )
    87143{
    88         fclose( file->fp );
    89144        g_free( file );
    90145}
  • lib/ini.h

    raac4017 r2288705  
    2929typedef struct
    3030{
    31         FILE *fp;
    3231        int line;
    33         char c_section[MAX_STRING];
    34         char section[MAX_STRING];
    35         char key[MAX_STRING];
    36         char value[MAX_STRING];
     32        char *c_section;
     33        char *section;
     34        char *key;
     35        char *value;
     36        int size;
     37        char *cur, *tok;
     38        char file[];
    3739} ini_t;
    3840
  • lib/misc.c

    raac4017 r2288705  
    4646#endif
    4747
     48#include "md5.h"
    4849#include "ssl_client.h"
    4950
  • lib/proxy.c

    raac4017 r2288705  
    558558                return proxy_connect_socks5(host, port, phb);
    559559       
    560         if (phb->host) g_free(phb);
    561560        g_free(phb);
    562561        return -1;
  • lib/xmltree.c

    raac4017 r2288705  
    472472}
    473473
    474 struct xt_node *xt_new_node( char *name, char *text, struct xt_node *children )
     474struct xt_node *xt_new_node( char *name, const char *text, struct xt_node *children )
    475475{
    476476        struct xt_node *node, *c;
  • lib/xmltree.h

    raac4017 r2288705  
    9090char *xt_find_attr( struct xt_node *node, const char *key );
    9191
    92 struct xt_node *xt_new_node( char *name, char *text, struct xt_node *children );
     92struct xt_node *xt_new_node( char *name, const char *text, struct xt_node *children );
    9393void xt_add_child( struct xt_node *parent, struct xt_node *child );
    9494void xt_add_attr( struct xt_node *node, const char *key, const char *value );
  • protocols/jabber/conference.c

    raac4017 r2288705  
    2626static xt_status jabber_chat_join_failed( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
    2727
    28 struct groupchat *jabber_chat_join( struct im_connection *ic, char *room, char *nick, char *password )
     28struct groupchat *jabber_chat_join( struct im_connection *ic, const char *room, const char *nick, const char *password )
    2929{
    3030        struct jabber_chat *jc;
     
    3636        node = xt_new_node( "x", NULL, NULL );
    3737        xt_add_attr( node, "xmlns", XMLNS_MUC );
    38         node = jabber_make_packet( "presence", NULL, roomjid, node );
    3938        if( password )
    4039                xt_add_child( node, xt_new_node( "password", password, NULL ) );
     40        node = jabber_make_packet( "presence", NULL, roomjid, node );
    4141        jabber_cache_add( ic, node, jabber_chat_join_failed );
    4242       
     
    234234                            ( strcmp( s, XMLNS_MUC_USER ) == 0 ) )
    235235                        {
    236                                 c = xt_find_node( c->children, "item" );
    237                                 if( ( s = xt_find_attr( c, "jid" ) ) )
     236                                struct xt_node *item;
     237                               
     238                                item = xt_find_node( c->children, "item" );
     239                                if( ( s = xt_find_attr( item, "jid" ) ) )
    238240                                {
    239241                                        /* Yay, found what we need. :-) */
     
    283285        else if( type ) /* type can only be NULL or "unavailable" in this function */
    284286        {
    285                 s = strchr( bud->ext_jid, '/' );
    286                 if( s ) *s = 0;
    287                 imcb_chat_remove_buddy( chat, bud->ext_jid, NULL );
    288                 if( bud != jc->me && bud->flags & JBFLAG_IS_ANONYMOUS )
    289                         imcb_remove_buddy( ic, bud->ext_jid, NULL );
    290                 if( s ) *s = '/';
     287                if( ( bud->flags & JBFLAG_IS_CHATROOM ) && bud->ext_jid )
     288                {
     289                        s = strchr( bud->ext_jid, '/' );
     290                        if( s ) *s = 0;
     291                        imcb_chat_remove_buddy( chat, bud->ext_jid, NULL );
     292                        if( bud != jc->me && bud->flags & JBFLAG_IS_ANONYMOUS )
     293                                imcb_remove_buddy( ic, bud->ext_jid, NULL );
     294                        if( s ) *s = '/';
     295                }
    291296               
    292297                if( bud == jc->me )
  • protocols/jabber/iq.c

    raac4017 r2288705  
    5151        {
    5252                if( !( ( c = xt_find_node( node->children, "query" ) ) ||
    53                        ( c = xt_find_node( node->children, "ping" ) ) ) || /* O_o WHAT is wrong with just <query/> ????? */
     53                       ( c = xt_find_node( node->children, "ping" ) ) ) ||
    5454                    !( s = xt_find_attr( c, "xmlns" ) ) )
    5555                {
    56                         imcb_log( ic, "Warning: Received incomplete IQ-%s packet", type );
     56                        /* Sigh. Who decided to suddenly invent new elements
     57                           instead of just sticking with <query/>? */
    5758                        return XT_HANDLED;
    5859                }
  • protocols/jabber/jabber.c

    raac4017 r2288705  
    7070       
    7171        s = set_add( &acc->set, "server", NULL, set_eval_account, acc );
    72         s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY;
     72        s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY | SET_NULL_OK;
    7373       
    7474        s = set_add( &acc->set, "ssl", "false", set_eval_bool, acc );
     
    439439}
    440440
    441 static struct groupchat *jabber_chat_join_( struct im_connection *ic, char *room, char *nick, char *password )
     441static struct groupchat *jabber_chat_join_( struct im_connection *ic, const char *room, const char *nick, const char *password )
    442442{
    443443        if( strchr( room, '@' ) == NULL )
  • protocols/jabber/jabber.h

    raac4017 r2288705  
    2727#include <glib.h>
    2828
     29#include "bitlbee.h"
     30#include "md5.h"
    2931#include "xmltree.h"
    30 #include "bitlbee.h"
    3132
    3233extern GSList *jabber_connections;
     
    302303
    303304/* conference.c */
    304 struct groupchat *jabber_chat_join( struct im_connection *ic, char *room, char *nick, char *password );
     305struct groupchat *jabber_chat_join( struct im_connection *ic, const char *room, const char *nick, const char *password );
    305306struct groupchat *jabber_chat_by_jid( struct im_connection *ic, const char *name );
    306307void jabber_chat_free( struct groupchat *c );
  • protocols/jabber/jabber_util.c

    raac4017 r2288705  
    3737                /* Priority is a signed 8-bit integer, according to RFC 3921. */
    3838                if( i < -128 || i > 127 )
    39                         return NULL;
     39                        return SET_INVALID;
    4040        }
    4141        else
    42                 return NULL;
     42                return SET_INVALID;
    4343       
    4444        /* Only run this stuff if the account is online ATM,
  • protocols/jabber/presence.c

    raac4017 r2288705  
    4949                if( !( bud = jabber_buddy_by_jid( ic, from, GET_BUDDY_EXACT | GET_BUDDY_CREAT ) ) )
    5050                {
    51                         if( set_getbool( &ic->irc->set, "debug" ) )
    52                                 imcb_log( ic, "Warning: Could not handle presence information from JID: %s", from );
     51                        /*
     52                        imcb_log( ic, "Warning: Could not handle presence information from JID: %s", from );
     53                        */
    5354                        return XT_HANDLED;
    5455                }
     
    106107                if( ( bud = jabber_buddy_by_jid( ic, from, 0 ) ) == NULL )
    107108                {
    108                         if( set_getbool( &ic->irc->set, "debug" ) )
    109                                 imcb_log( ic, "Warning: Received presence information from unknown JID: %s", from );
     109                        /*
     110                        imcb_log( ic, "Warning: Received presence information from unknown JID: %s", from );
     111                        */
    110112                        return XT_HANDLED;
    111113                }
  • protocols/nogaim.c

    raac4017 r2288705  
    3333
    3434#define BITLBEE_CORE
     35#include <ctype.h>
     36
    3537#include "nogaim.h"
    36 #include <ctype.h>
     38#include "chat.h"
    3739
    3840static int remove_chat_buddy_silent( struct groupchat *b, const char *handle );
     
    249251void imcb_connected( struct im_connection *ic )
    250252{
     253        irc_t *irc = ic->irc;
     254        struct chat *c;
    251255        user_t *u;
    252256       
     
    271275           exponential backoff timer. */
    272276        ic->acc->auto_reconnect_delay = 0;
     277       
     278        for( c = irc->chatrooms; c; c = c->next )
     279        {
     280                if( c->acc != ic->acc )
     281                        continue;
     282               
     283                if( set_getbool( &c->set, "auto_join" ) )
     284                        chat_join( irc, c, NULL );
     285        }
    273286}
    274287
     
    309322        ic->acc->prpl->logout( ic );
    310323        b_event_remove( ic->inpa );
     324       
     325        g_free( ic->away );
     326        ic->away = NULL;
    311327       
    312328        u = irc->users;
     
    492508}
    493509
    494 /* prpl.c */
    495 
    496 struct show_got_added_data
     510
     511struct imcb_ask_cb_data
    497512{
    498513        struct im_connection *ic;
     
    500515};
    501516
    502 void show_got_added_no( void *data )
    503 {
    504         g_free( ((struct show_got_added_data*)data)->handle );
     517static void imcb_ask_auth_cb_no( void *data )
     518{
     519        struct imcb_ask_cb_data *cbd = data;
     520       
     521        cbd->ic->acc->prpl->auth_deny( cbd->ic, cbd->handle );
     522       
     523        g_free( cbd->handle );
     524        g_free( cbd );
     525}
     526
     527static void imcb_ask_auth_cb_yes( void *data )
     528{
     529        struct imcb_ask_cb_data *cbd = data;
     530       
     531        cbd->ic->acc->prpl->auth_allow( cbd->ic, cbd->handle );
     532       
     533        g_free( cbd->handle );
     534        g_free( cbd );
     535}
     536
     537void imcb_ask_auth( struct im_connection *ic, const char *handle, const char *realname )
     538{
     539        struct imcb_ask_cb_data *data = g_new0( struct imcb_ask_cb_data, 1 );
     540        char *s, *realname_ = NULL;
     541       
     542        if( realname != NULL )
     543                realname_ = g_strdup_printf( " (%s)", realname );
     544       
     545        s = g_strdup_printf( "The user %s%s wants to add you to his/her buddy list.",
     546                             handle, realname_ ?: "" );
     547       
     548        g_free( realname_ );
     549       
     550        data->ic = ic;
     551        data->handle = g_strdup( handle );
     552        query_add( ic->irc, ic, s, imcb_ask_auth_cb_yes, imcb_ask_auth_cb_no, data );
     553}
     554
     555
     556static void imcb_ask_add_cb_no( void *data )
     557{
     558        g_free( ((struct imcb_ask_cb_data*)data)->handle );
    505559        g_free( data );
    506560}
    507561
    508 void show_got_added_yes( void *data )
    509 {
    510         struct show_got_added_data *sga = data;
    511        
    512         sga->ic->acc->prpl->add_buddy( sga->ic, sga->handle, NULL );
    513         /* imcb_add_buddy( sga->ic, NULL, sga->handle, sga->handle ); */
    514        
    515         return show_got_added_no( data );
    516 }
    517 
    518 void imcb_ask_add( struct im_connection *ic, char *handle, const char *realname )
    519 {
    520         struct show_got_added_data *data = g_new0( struct show_got_added_data, 1 );
     562static void imcb_ask_add_cb_yes( void *data )
     563{
     564        struct imcb_ask_cb_data *cbd = data;
     565       
     566        cbd->ic->acc->prpl->add_buddy( cbd->ic, cbd->handle, NULL );
     567       
     568        return imcb_ask_add_cb_no( data );
     569}
     570
     571void imcb_ask_add( struct im_connection *ic, const char *handle, const char *realname )
     572{
     573        struct imcb_ask_cb_data *data = g_new0( struct imcb_ask_cb_data, 1 );
    521574        char *s;
    522575       
     
    529582        data->ic = ic;
    530583        data->handle = g_strdup( handle );
    531         query_add( ic->irc, ic, s, show_got_added_yes, show_got_added_no, data );
     584        query_add( ic->irc, ic, s, imcb_ask_add_cb_yes, imcb_ask_add_cb_no, data );
    532585}
    533586
     
    699752}
    700753
    701 struct groupchat *imcb_chat_new( struct im_connection *ic, char *handle )
     754struct groupchat *imcb_chat_new( struct im_connection *ic, const char *handle )
    702755{
    703756        struct groupchat *c;
     
    928981        int st;
    929982       
    930         if( ( g_strcasecmp( value, "true" ) == 0 ) || ( g_strcasecmp( value, "yes" ) == 0 ) || ( g_strcasecmp( value, "on" ) == 0 ) )
    931                 st = 1;
    932         else if( ( g_strcasecmp( value, "false" ) == 0 ) || ( g_strcasecmp( value, "no" ) == 0 ) || ( g_strcasecmp( value, "off" ) == 0 ) )
    933                 st = 0;
    934         else if( sscanf( value, "%d", &st ) != 1 )
    935                 return( NULL );
    936        
    937         st = st != 0;
     983        if( !is_bool( value ) )
     984                return SET_INVALID;
     985       
     986        st = bool2int( value );
    938987       
    939988        /* Horror.... */
     
    9791028        }
    9801029       
    981         return( set_eval_bool( set, value ) );
     1030        return value;
    9821031}
    9831032
  • protocols/nogaim.h

    raac4017 r2288705  
    3939#define _NOGAIM_H
    4040
     41#include <stdint.h>
     42
    4143#include "bitlbee.h"
    4244#include "account.h"
     
    210212         * not implement this. */
    211213        struct groupchat *
    212              (* chat_join)      (struct im_connection *, char *room, char *nick, char *password);
     214             (* chat_join)      (struct im_connection *, const char *room, const char *nick, const char *password);
    213215        /* Change the topic, if supported. Note that BitlBee expects the IM
    214216           server to confirm the topic change with a regular topic change
     
    225227         * - Most protocols will just want to set this to g_strcasecmp().*/
    226228        int (* handle_cmp) (const char *who1, const char *who2);
     229
     230        /* Implement these callbacks if you want to use imcb_ask_auth() */
     231        void (* auth_allow)     (struct im_connection *, const char *who);
     232        void (* auth_deny)      (struct im_connection *, const char *who);
    227233
    228234        /* Incoming transfer request */
     
    243249 * the account_t parameter. */
    244250G_MODULE_EXPORT struct im_connection *imcb_new( account_t *acc );
    245 G_MODULE_EXPORT void imcb_free( struct im_connection *ic );
     251G_MODULE_EXPORT void imc_free( struct im_connection *ic );
    246252/* Once you're connected, you should call this function, so that the user will
    247253 * see the success. */
     
    256262/* To tell the user an error, ie. before logging out when an error occurs. */
    257263G_MODULE_EXPORT void imcb_error( struct im_connection *ic, char *format, ... ) G_GNUC_PRINTF( 2, 3 );
     264
    258265/* To ask a your about something.
    259266 * - 'msg' is the question.
     
    262269 */
    263270G_MODULE_EXPORT void imcb_ask( struct im_connection *ic, char *msg, void *data, query_callback doit, query_callback dont );
    264 G_MODULE_EXPORT void imcb_ask_add( struct im_connection *ic, char *handle, const char *realname );
     271
     272/* Two common questions you may want to ask:
     273 * - X added you to his contact list, allow?
     274 * - X is not in your contact list, want to add?
     275 */
     276G_MODULE_EXPORT void imcb_ask_auth( struct im_connection *ic, const char *handle, const char *realname );
     277G_MODULE_EXPORT void imcb_ask_add( struct im_connection *ic, const char *handle, const char *realname );
    265278
    266279/* Buddy management */
     
    294307 *   the user her/himself. At that point the group chat will be visible to the
    295308 *   user, too. */
    296 G_MODULE_EXPORT struct groupchat *imcb_chat_new( struct im_connection *ic, char *handle );
     309G_MODULE_EXPORT struct groupchat *imcb_chat_new( struct im_connection *ic, const char *handle );
    297310G_MODULE_EXPORT void imcb_chat_add_buddy( struct groupchat *b, char *handle );
    298311/* To remove a handle from a group chat. Reason can be NULL. */
  • protocols/oscar/aim.h

    raac4017 r2288705  
    144144}
    145145
     146#define AIM_CLIENTINFO_KNOWNGOOD_5_1_3036 { \
     147        "AOL Instant Messenger, version 5.1.3036/WIN32", \
     148        0x0109, \
     149        0x0005, \
     150        0x0001, \
     151        0x0000, \
     152        0x0bdc, \
     153        "us", \
     154        "en", \
     155}
     156
    146157/*
    147158 * I would make 4.1.2010 the default, but they seem to have found
     
    152163 * around. (see login.c::memrequest())
    153164 */
    154 #define AIM_CLIENTINFO_KNOWNGOOD AIM_CLIENTINFO_KNOWNGOOD_3_5_1670
     165#define AIM_CLIENTINFO_KNOWNGOOD AIM_CLIENTINFO_KNOWNGOOD_5_1_3036
    155166
    156167#ifndef TRUE
  • protocols/oscar/oscar.c

    raac4017 r2288705  
    9191        GSList *oscar_chats;
    9292
    93         gboolean killme;
     93        gboolean killme, no_reconnect;
    9494        gboolean icq;
    9595        GSList *evilhack;
     
    181181static int gaim_parse_auth_resp  (aim_session_t *, aim_frame_t *, ...);
    182182static int gaim_parse_login      (aim_session_t *, aim_frame_t *, ...);
     183static int gaim_parse_logout     (aim_session_t *, aim_frame_t *, ...);
    183184static int gaim_handle_redirect  (aim_session_t *, aim_frame_t *, ...);
    184185static int gaim_parse_oncoming   (aim_session_t *, aim_frame_t *, ...);
     
    294295                        aim_rxdispatch(odata->sess);
    295296                               if (odata->killme)
    296                                        imc_logout(ic, TRUE);
     297                                       imc_logout(ic, !odata->no_reconnect);
    297298                } else {
    298299                        if ((conn->type == AIM_CONN_TYPE_BOS) ||
     
    520521                case 0x18:
    521522                        /* connecting too frequently */
     523                        od->no_reconnect = TRUE;
    522524                        imcb_error(ic, _("You have been connecting and disconnecting too frequently. Wait ten minutes and try again. If you continue to try, you will need to wait even longer."));
    523525                        break;
     
    572574        aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO, gaim_parseaiminfo, 0);
    573575        aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_MTN, gaim_parsemtn, 0);
     576        aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, gaim_parse_logout, 0);
    574577
    575578        ((struct oscar_data *)ic->proto_data)->conn = bosconn;
     
    747750
    748751        aim_send_login(sess, fr->conn, ic->acc->user, ic->acc->pass, &info, key);
     752
     753        return 1;
     754}
     755
     756static int gaim_parse_logout(aim_session_t *sess, aim_frame_t *fr, ...) {
     757        struct im_connection *ic = sess->aux_data;
     758        struct oscar_data *odata = ic->proto_data;
     759        int code;
     760        va_list ap;
     761
     762        va_start(ap, fr);
     763        code = va_arg(ap, int);
     764        va_end(ap);
     765       
     766        imcb_error( ic, "Connection aborted by server: %s", code == 1 ?
     767                        "someone else logged in with your account" :
     768                        "unknown reason" );
     769       
     770        /* Tell BitlBee to disable auto_reconnect if code == 1, since that
     771           means a concurrent login somewhere else. */
     772        odata->no_reconnect = code == 1;
     773       
     774        /* DO NOT log out here! Just tell the callback to do it. */
     775        odata->killme = TRUE;
    749776
    750777        return 1;
     
    19391966        aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_NORMAL);
    19401967
    1941         if (ic->away)
    1942                 g_free(ic->away);
     1968        g_free(ic->away);
    19431969        ic->away = NULL;
    19441970
     
    19601986static void oscar_set_away_icq(struct im_connection *ic, struct oscar_data *od, const char *state, const char *message)
    19611987{
    1962     const char *msg = NULL;
     1988        const char *msg = NULL;
    19631989        gboolean no_message = FALSE;
    19641990
    19651991        /* clean old states */
    1966     if (ic->away) {
    1967                 g_free(ic->away);
    1968                 ic->away = NULL;
    1969     }
     1992        g_free(ic->away);
     1993        ic->away = NULL;
    19701994        od->sess->aim_icq_state = 0;
    19711995
    19721996        /* if no message, then use an empty message */
    1973     if (message) {
    1974         msg = message;
    1975     } else {
    1976         msg = "";
     1997        if (message) {
     1998                msg = message;
     1999        } else {
     2000                msg = "";
    19772001                no_message = TRUE;
    1978     }
     2002        }
    19792003
    19802004        if (!g_strcasecmp(state, "Online")) {
     
    19822006        } else if (!g_strcasecmp(state, "Away")) {
    19832007                aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_AWAY);
    1984         ic->away = g_strdup(msg);
     2008                ic->away = g_strdup(msg);
    19852009                od->sess->aim_icq_state = AIM_MTYPE_AUTOAWAY;
    19862010        } else if (!g_strcasecmp(state, "Do Not Disturb")) {
    19872011                aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_AWAY | AIM_ICQ_STATE_DND | AIM_ICQ_STATE_BUSY);
    1988         ic->away = g_strdup(msg);
     2012                ic->away = g_strdup(msg);
    19892013                od->sess->aim_icq_state = AIM_MTYPE_AUTODND;
    19902014        } else if (!g_strcasecmp(state, "Not Available")) {
    19912015                aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_OUT | AIM_ICQ_STATE_AWAY);
    1992         ic->away = g_strdup(msg);
     2016                ic->away = g_strdup(msg);
    19932017                od->sess->aim_icq_state = AIM_MTYPE_AUTONA;
    19942018        } else if (!g_strcasecmp(state, "Occupied")) {
    19952019                aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_AWAY | AIM_ICQ_STATE_BUSY);
    1996         ic->away = g_strdup(msg);
     2020                ic->away = g_strdup(msg);
    19972021                od->sess->aim_icq_state = AIM_MTYPE_AUTOBUSY;
    19982022        } else if (!g_strcasecmp(state, "Free For Chat")) {
    19992023                aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_CHAT);
    2000         ic->away = g_strdup(msg);
     2024                ic->away = g_strdup(msg);
    20012025                od->sess->aim_icq_state = AIM_MTYPE_AUTOFFC;
    20022026        } else if (!g_strcasecmp(state, "Invisible")) {
    20032027                aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_INVISIBLE);
    2004         ic->away = g_strdup(msg);
     2028                ic->away = g_strdup(msg);
    20052029        } else if (!g_strcasecmp(state, GAIM_AWAY_CUSTOM)) {
    20062030                if (no_message) {
     
    20082032                } else {
    20092033                        aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_AWAY);
    2010             ic->away = g_strdup(msg);
     2034                        ic->away = g_strdup(msg);
    20112035                        od->sess->aim_icq_state = AIM_MTYPE_AUTOAWAY;
    20122036                }
     
    20202044        struct oscar_data *od = (struct oscar_data *)ic->proto_data;
    20212045
    2022     oscar_set_away_aim(ic, od, state, message);
     2046        oscar_set_away_aim(ic, od, state, message);
    20232047        if (od->icq)
    20242048                oscar_set_away_icq(ic, od, state, message);
     
    25812605}
    25822606
    2583 struct groupchat *oscar_chat_join(struct im_connection * ic, char * room, char * nick, char * password )
     2607struct groupchat *oscar_chat_join(struct im_connection * ic, const char * room, const char * nick, const char * password )
    25842608{
    25852609        struct oscar_data * od = (struct oscar_data *)ic->proto_data;
  • protocols/yahoo/libyahoo2.c

    raac4017 r2288705  
    8989
    9090#include "base64.h"
     91#include "http_client.h"
    9192
    9293#ifdef USE_STRUCT_CALLBACKS
     
    169170        YAHOO_SERVICE_GOTGROUPRENAME, /* < 1, 36(old), 37(new) */
    170171        YAHOO_SERVICE_SYSMESSAGE = 0x14,
     172        YAHOO_SERVICE_SKINNAME = 0x15,
    171173        YAHOO_SERVICE_PASSTHROUGH2 = 0x16,
    172174        YAHOO_SERVICE_CONFINVITE = 0x18,
     
    192194        YAHOO_SERVICE_LIST,
    193195        YAHOO_SERVICE_AUTH = 0x57,
     196        YAHOO_SERVICE_AUTHBUDDY = 0x6d,
    194197        YAHOO_SERVICE_ADDBUDDY = 0x83,
    195198        YAHOO_SERVICE_REMBUDDY,
     
    197200        YAHOO_SERVICE_REJECTCONTACT,
    198201        YAHOO_SERVICE_GROUPRENAME = 0x89, /* > 1, 65(new), 66(0), 67(old) */
     202        YAHOO_SERVICE_Y7_PING = 0x8A, /* 0 - id and that's it?? */
    199203        YAHOO_SERVICE_CHATONLINE = 0x96, /* > 109(id), 1, 6(abcde) < 0,1*/
    200204        YAHOO_SERVICE_CHATGOTO,
     
    202206        YAHOO_SERVICE_CHATLEAVE,
    203207        YAHOO_SERVICE_CHATEXIT = 0x9b,
     208        YAHOO_SERVICE_CHATADDINVITE = 0x9d,
    204209        YAHOO_SERVICE_CHATLOGOUT = 0xa0,
    205210        YAHOO_SERVICE_CHATPING,
     
    209214        YAHOO_SERVICE_PICTURE = 0xbe,
    210215        YAHOO_SERVICE_PICTURE_UPDATE = 0xc1,
    211         YAHOO_SERVICE_PICTURE_UPLOAD = 0xc2
     216        YAHOO_SERVICE_PICTURE_UPLOAD = 0xc2,
     217        YAHOO_SERVICE_Y6_VISIBILITY=0xc5,
     218        YAHOO_SERVICE_Y6_STATUS_UPDATE=0xc6,
     219        YAHOO_PHOTOSHARE_INIT=0xd2,     
     220        YAHOO_SERVICE_CONTACT_YMSG13=0xd6,
     221        YAHOO_PHOTOSHARE_PREV=0xd7,
     222        YAHOO_PHOTOSHARE_KEY=0xd8,
     223        YAHOO_PHOTOSHARE_TRANS=0xda,
     224        YAHOO_FILE_TRANSFER_INIT_YMSG13=0xdc,
     225        YAHOO_FILE_TRANSFER_GET_YMSG13=0xdd,
     226        YAHOO_FILE_TRANSFER_PUT_YMSG13=0xde,
     227        YAHOO_SERVICE_YMSG15_STATUS=0xf0,
     228        YAHOO_SERVICE_YMSG15_BUDDY_LIST=0xf1,
    212229};
    213230
     
    733750
    734751        memcpy(data + pos, "YMSG", 4); pos += 4;
    735         pos += yahoo_put16(data + pos, 0x000c);
     752        pos += yahoo_put16(data + pos, YAHOO_PROTO_VER);
    736753        pos += yahoo_put16(data + pos, 0x0000);
    737754        pos += yahoo_put16(data + pos, pktlen + extra_pad);
     
    747764                yahoo_send_data(yid->fd, data, len);
    748765        else
    749         yahoo_add_to_send_queue(yid, data, len);
     766                yahoo_add_to_send_queue(yid, data, len);
    750767        FREE(data);
    751768}
     
    14671484
    14681485                if (u->name != NULL) {
    1469                         if (pkt->service == YAHOO_SERVICE_LOGOFF || u->flags == 0) {
     1486                        if (pkt->service == YAHOO_SERVICE_LOGOFF) { /* || u->flags == 0) { Not in YMSG16 */
    14701487                                YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, u->name, YAHOO_STATUS_OFFLINE, NULL, 1, 0, 0);
    14711488                        } else {
     1489                                /* Key 47 always seems to be 1 for YMSG16 */
     1490                                if(!u->state)
     1491                                        u->away = 0;
     1492                                else
     1493                                        u->away = 1;
     1494
    14721495                                YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, u->name, u->state, u->msg, u->away, u->idle, u->mobile);
    14731496                        }
     
    14771500                y_list_free_1(t);
    14781501                FREE(u);
     1502        }
     1503}
     1504
     1505static void yahoo_process_buddy_list(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
     1506{
     1507        struct yahoo_data *yd = yid->yd;
     1508        YList *l;
     1509        int last_packet = 0;
     1510        char *cur_group = NULL;
     1511        struct yahoo_buddy *newbud = NULL;
     1512
     1513        /* we could be getting multiple packets here */
     1514        for (l = pkt->hash; l; l = l->next) {
     1515                struct yahoo_pair *pair = l->data;
     1516
     1517                switch(pair->key) {
     1518                case 300:
     1519                case 301:
     1520                case 302:
     1521                case 303:
     1522                        if ( 315 == atoi(pair->value) )
     1523                                last_packet = 1;
     1524                        break;
     1525                case 65:
     1526                        g_free(cur_group);
     1527                        cur_group = strdup(pair->value);
     1528                        break;
     1529                case 7:
     1530                        newbud = y_new0(struct yahoo_buddy, 1);
     1531                        newbud->id = strdup(pair->value);
     1532                        if(cur_group)
     1533                                newbud->group = strdup(cur_group);
     1534                        else {
     1535                                struct yahoo_buddy *lastbud = (struct yahoo_buddy *)y_list_nth(
     1536                                                                yd->buddies, y_list_length(yd->buddies)-1)->data;
     1537                                newbud->group = strdup(lastbud->group);
     1538                        }
     1539
     1540                        yd->buddies = y_list_append(yd->buddies, newbud);
     1541
     1542                        break;
     1543                }
     1544        }
     1545       
     1546        g_free(cur_group);
     1547
     1548        /* we could be getting multiple packets here */
     1549        if (last_packet)
     1550                return;
     1551
     1552        YAHOO_CALLBACK(ext_yahoo_got_buddies)(yd->client_id, yd->buddies);
     1553
     1554        /*** We login at the very end of the packet communication */
     1555        if (!yd->logged_in) {
     1556                yd->logged_in = TRUE;
     1557                if(yd->current_status < 0)
     1558                        yd->current_status = yd->initial_status;
     1559                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_OK, NULL);
    14791560        }
    14801561}
     
    15491630                        }
    15501631
    1551                         if(yd->cookie_y && yd->cookie_t && yd->cookie_c)
     1632                        if(yd->cookie_y && yd->cookie_t)
    15521633                                YAHOO_CALLBACK(ext_yahoo_got_cookies)(yd->client_id);
    15531634
     
    22262307}
    22272308
     2309struct yahoo_https_auth_data
     2310{
     2311        struct yahoo_input_data *yid;
     2312        char *token;
     2313        char *chal;
     2314};
     2315
     2316static void yahoo_https_auth_token_init(struct yahoo_https_auth_data *had);
     2317static void yahoo_https_auth_token_finish(struct http_request *req);
     2318static void yahoo_https_auth_init(struct yahoo_https_auth_data *had);
     2319static void yahoo_https_auth_finish(struct http_request *req);
     2320
     2321/* Extract a value from a login.yahoo.com response. Assume CRLF-linebreaks
     2322   and FAIL miserably if they're not there... */
     2323static char *yahoo_ha_find_key(char *response, char *key)
     2324{
     2325        char *s, *end;
     2326        int len = strlen(key);
     2327       
     2328        s = response;
     2329        do {
     2330                if (strncmp(s, key, len) == 0 && s[len] == '=') {
     2331                        s += len + 1;
     2332                        if ((end = strchr(s, '\r')))
     2333                                return g_strndup(s, end - s);
     2334                        else
     2335                                return g_strdup(s);
     2336                }
     2337               
     2338                if ((s = strchr(s, '\n')))
     2339                        s ++;
     2340        } while (s && *s);
     2341       
     2342        return NULL;
     2343}
     2344
     2345static enum yahoo_status yahoo_https_status_parse(int code)
     2346{
     2347        switch (code)
     2348        {
     2349                case 1212: return YAHOO_LOGIN_PASSWD;
     2350                case 1213: return YAHOO_LOGIN_LOCK;
     2351                case 1235: return YAHOO_LOGIN_UNAME;
     2352                default: return (enum yahoo_status) code;
     2353        }
     2354}
     2355
     2356static void yahoo_process_auth_0x10(struct yahoo_input_data *yid, const char *seed, const char *sn)
     2357{
     2358        struct yahoo_https_auth_data *had = g_new0(struct yahoo_https_auth_data, 1);
     2359       
     2360        had->yid = yid;
     2361        had->chal = g_strdup(seed);
     2362       
     2363        yahoo_https_auth_token_init(had);
     2364}
     2365
     2366static void yahoo_https_auth_token_init(struct yahoo_https_auth_data *had)
     2367{
     2368        struct yahoo_input_data *yid = had->yid;
     2369        struct yahoo_data *yd = yid->yd;
     2370        struct http_request *req;
     2371        char *login, *passwd, *chal;
     2372        char *url;
     2373       
     2374        login = g_strndup(yd->user, 3 * strlen(yd->user));
     2375        http_encode(login);
     2376        passwd = g_strndup(yd->password, 3 * strlen(yd->password));
     2377        http_encode(passwd);
     2378        chal = g_strndup(had->chal, 3 * strlen(had->chal));
     2379        http_encode(chal);
     2380       
     2381        url = g_strdup_printf("https://login.yahoo.com/config/pwtoken_get?src=ymsgr&ts=%d&login=%s&passwd=%s&chal=%s",
     2382                               (int) time(NULL), login, passwd, chal);
     2383       
     2384        req = http_dorequest_url(url, yahoo_https_auth_token_finish, had);
     2385       
     2386        g_free(url);
     2387        g_free(chal);
     2388        g_free(passwd);
     2389        g_free(login);
     2390}
     2391
     2392static void yahoo_https_auth_token_finish(struct http_request *req)
     2393{
     2394        struct yahoo_https_auth_data *had = req->data;
     2395        struct yahoo_input_data *yid = had->yid;
     2396        struct yahoo_data *yd = yid->yd;
     2397        int st;
     2398       
     2399        if (req->status_code != 200) {
     2400                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, 2000 + req->status_code, NULL);
     2401                goto fail;
     2402        }
     2403       
     2404        if (sscanf(req->reply_body, "%d", &st) != 1 || st != 0) {
     2405                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, yahoo_https_status_parse(st), NULL);
     2406                goto fail;
     2407        }
     2408       
     2409        if ((had->token = yahoo_ha_find_key(req->reply_body, "ymsgr")) == NULL) {
     2410                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, 3001, NULL);
     2411                goto fail;
     2412        }
     2413       
     2414        return yahoo_https_auth_init(had);
     2415       
     2416fail:
     2417        g_free(had->token);
     2418        g_free(had->chal);
     2419        g_free(had);
     2420}
     2421
     2422static void yahoo_https_auth_init(struct yahoo_https_auth_data *had)
     2423{
     2424        struct http_request *req;
     2425        char *url;
     2426       
     2427        url = g_strdup_printf("https://login.yahoo.com/config/pwtoken_login?src=ymsgr&ts=%d&token=%s",
     2428                              (int) time(NULL), had->token);
     2429       
     2430        req = http_dorequest_url(url, yahoo_https_auth_finish, had);
     2431       
     2432        g_free(url);
     2433}
     2434
     2435static void yahoo_https_auth_finish(struct http_request *req)
     2436{
     2437        struct yahoo_https_auth_data *had = req->data;
     2438        struct yahoo_input_data *yid = had->yid;
     2439        struct yahoo_data *yd = yid->yd;
     2440        struct yahoo_packet *pack;
     2441        char *crumb;
     2442        int st;
     2443       
     2444        md5_byte_t result[16];
     2445        md5_state_t ctx;
     2446       
     2447        unsigned char yhash[32];
     2448
     2449        if (req->status_code != 200) {
     2450                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, 2000 + req->status_code, NULL);
     2451                goto fail;
     2452        }
     2453       
     2454        if (sscanf(req->reply_body, "%d", &st) != 1 || st != 0) {
     2455                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, yahoo_https_status_parse(st), NULL);
     2456                goto fail;
     2457        }
     2458       
     2459        if ((yd->cookie_y = yahoo_ha_find_key(req->reply_body, "Y")) == NULL ||
     2460            (yd->cookie_t = yahoo_ha_find_key(req->reply_body, "T")) == NULL ||
     2461            (crumb = yahoo_ha_find_key(req->reply_body, "crumb")) == NULL) {
     2462                YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, 3002, NULL);
     2463                goto fail;
     2464        }
     2465       
     2466        md5_init(&ctx); 
     2467        md5_append(&ctx, (unsigned char*) crumb, 11);
     2468        md5_append(&ctx, (unsigned char*) had->chal, strlen(had->chal));
     2469        md5_finish(&ctx, result);
     2470        to_y64(yhash, result, 16);
     2471
     2472        pack = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP, yd->initial_status, yd->session_id);
     2473        yahoo_packet_hash(pack, 1, yd->user);
     2474        yahoo_packet_hash(pack, 0, yd->user);
     2475        yahoo_packet_hash(pack, 277, yd->cookie_y);
     2476        yahoo_packet_hash(pack, 278, yd->cookie_t);
     2477        yahoo_packet_hash(pack, 307, (char*) yhash);
     2478        yahoo_packet_hash(pack, 244, "524223");
     2479        yahoo_packet_hash(pack, 2, yd->user);
     2480        yahoo_packet_hash(pack, 2, "1");
     2481        yahoo_packet_hash(pack, 98, "us");
     2482        yahoo_packet_hash(pack, 135, "7.5.0.647");
     2483       
     2484        yahoo_send_packet(yid, pack, 0);
     2485               
     2486        yahoo_packet_free(pack);
     2487       
     2488fail:
     2489        g_free(crumb);
     2490        g_free(had->token);
     2491        g_free(had->chal);
     2492        g_free(had);
     2493}
     2494
    22282495static void yahoo_process_auth(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
    22292496{
     
    22532520                case 1:
    22542521                        yahoo_process_auth_0x0b(yid, seed, sn);
     2522                        break;
     2523                case 2:
     2524                        yahoo_process_auth_0x10(yid, seed, sn);
    22552525                        break;
    22562526                default:
     
    24082678               
    24092679                yd->buddies = y_list_append(yd->buddies, bud);
    2410                
     2680       
    24112681                /* Possibly called already, but at least the call above doesn't
    24122682                   seem to happen every time (not anytime I tried). */
     
    24152685
    24162686/*      YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, who, status, NULL, (status==YAHOO_STATUS_AVAILABLE?0:1)); */
     2687}
     2688
     2689static void yahoo_process_contact_ymsg13(struct yahoo_input_data *yid, struct yahoo_packet *pkt)
     2690{
     2691        char* who=NULL;
     2692        char* me=NULL; 
     2693        char* msg=NULL;
     2694        YList *l;
     2695        for (l = pkt->hash; l; l = l->next) {
     2696                struct yahoo_pair *pair = l->data;
     2697                if (pair->key == 4)
     2698                        who = pair->value;
     2699                else if (pair->key == 5)
     2700                        me = pair->value;
     2701                else
     2702                        DEBUG_MSG(("unknown key: %d = %s", pair->key, pair->value));
     2703        }
     2704
     2705        if(pkt->status==3)
     2706                YAHOO_CALLBACK(ext_yahoo_contact_auth_request)(yid->yd->client_id, me, who, msg);
    24172707}
    24182708
     
    26282918
    26292919        YList *l;
    2630         yahoo_dump_unhandled(pkt);
     2920        // yahoo_dump_unhandled(pkt);
    26312921        for (l = pkt->hash; l; l = l->next) {
    26322922                struct yahoo_pair *pair = l->data;
     
    26502940{
    26512941        DEBUG_MSG(("yahoo_packet_process: 0x%02x", pkt->service));
     2942        yahoo_dump_unhandled(pkt);
    26522943        switch (pkt->service)
    26532944        {
     
    26612952        case YAHOO_SERVICE_IDACT:
    26622953        case YAHOO_SERVICE_IDDEACT:
     2954        case YAHOO_SERVICE_Y6_STATUS_UPDATE:
     2955        case YAHOO_SERVICE_YMSG15_STATUS:
    26632956                yahoo_process_status(yid, pkt);
    26642957                break;
     
    26742967                yahoo_process_mail(yid, pkt);
    26752968                break;
     2969        case YAHOO_SERVICE_REJECTCONTACT:
    26762970        case YAHOO_SERVICE_NEWCONTACT:
    26772971                yahoo_process_contact(yid, pkt);
     
    27143008                yahoo_process_buddyadd(yid, pkt);
    27153009                break;
     3010        case YAHOO_SERVICE_CONTACT_YMSG13:
     3011                yahoo_process_contact_ymsg13(yid,pkt);
     3012                break;
    27163013        case YAHOO_SERVICE_REMBUDDY:
    27173014                yahoo_process_buddydel(yid, pkt);
     
    27423039        case YAHOO_SERVICE_CHATLOGOFF:
    27433040        case YAHOO_SERVICE_CHATMSG:
    2744         case YAHOO_SERVICE_REJECTCONTACT:
    27453041        case YAHOO_SERVICE_PEERTOPEER:
    27463042                WARNING(("unhandled service 0x%02x", pkt->service));
     
    27563052                yahoo_process_picture_upload(yid, pkt);
    27573053                break; 
     3054        case YAHOO_SERVICE_YMSG15_BUDDY_LIST:   /* Buddy List */
     3055                yahoo_process_buddy_list(yid, pkt);
    27583056        default:
    27593057                WARNING(("unknown service 0x%02x", pkt->service));
     
    35393837        yahoo_process_webcam_connection,
    35403838        yahoo_process_chatcat_connection,
    3541         yahoo_process_search_connection
     3839        yahoo_process_search_connection,
    35423840};
    35433841
     
    35573855        } while(len == -1 && errno == EINTR);
    35583856
    3559         if(len == -1 && errno == EAGAIN)        /* we'll try again later */
     3857        if(len == -1 && (errno == EAGAIN||errno == EINTR))      /* we'll try again later */
    35603858                return 1;
    35613859
     
    37604058
    37614059        yahoo_packet_hash(pkt, 5, who);
    3762         yahoo_packet_hash(pkt, 4, from?from:yd->user);
     4060        yahoo_packet_hash(pkt, 1, from?from:yd->user);
    37634061        yahoo_packet_hash(pkt, 14, " ");
    37644062        yahoo_packet_hash(pkt, 13, typ ? "1" : "0");
     
    37754073        struct yahoo_data *yd;
    37764074        struct yahoo_packet *pkt = NULL;
    3777         int service;
     4075        int old_status;
    37784076        char s[4];
    37794077
     
    37834081        yd = yid->yd;
    37844082
    3785         if (msg) {
     4083        old_status = yd->current_status;
     4084
     4085        if (msg && strncmp(msg,"Invisible",9)) {
    37864086                yd->current_status = YAHOO_STATUS_CUSTOM;
    37874087        } else {
     
    37894089        }
    37904090
    3791         if (yd->current_status == YAHOO_STATUS_AVAILABLE)
    3792                 service = YAHOO_SERVICE_ISBACK;
    3793         else
    3794                 service = YAHOO_SERVICE_ISAWAY;
     4091        /* Thank you libpurple :) */
     4092        if (yd->current_status == YAHOO_STATUS_INVISIBLE) {
     4093                pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_VISIBILITY, YAHOO_STATUS_AVAILABLE, 0);
     4094                yahoo_packet_hash(pkt, 13, "2");
     4095                yahoo_send_packet(yid, pkt, 0);
     4096                yahoo_packet_free(pkt);
     4097
     4098                return;
     4099        }
     4100
     4101        pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_STATUS_UPDATE, yd->current_status, yd->session_id);
     4102        snprintf(s, sizeof(s), "%d", yd->current_status);
     4103        yahoo_packet_hash(pkt, 10, s);
    37954104         
    3796         if ((away == 2) && (yd->current_status == YAHOO_STATUS_AVAILABLE)) {
    3797                 pkt = yahoo_packet_new(YAHOO_SERVICE_ISAWAY, YAHOO_STATUS_BRB, yd->session_id);
    3798                 yahoo_packet_hash(pkt, 10, "999");
    3799                 yahoo_packet_hash(pkt, 47, "2");
    3800         }else {
    3801                 pkt = yahoo_packet_new(service, YAHOO_STATUS_AVAILABLE, yd->session_id);
    3802                 snprintf(s, sizeof(s), "%d", yd->current_status);
    3803                 yahoo_packet_hash(pkt, 10, s);
    3804                 if (yd->current_status == YAHOO_STATUS_CUSTOM) {
    3805                         yahoo_packet_hash(pkt, 19, msg);
    3806                         yahoo_packet_hash(pkt, 47, (away == 2)? "2": (away) ?"1":"0");
    3807                 } else {
    3808                         yahoo_packet_hash(pkt, 47, (away == 2)? "2": (away) ?"1":"0");
    3809                 }
    3810                
    3811                
    3812                
    3813         }
     4105        if (yd->current_status == YAHOO_STATUS_CUSTOM) {
     4106                yahoo_packet_hash(pkt, 19, msg);
     4107        } else {
     4108                yahoo_packet_hash(pkt, 19, "");
     4109        }
     4110       
     4111        yahoo_packet_hash(pkt, 47, (away == 2)? "2": (away) ?"1":"0");
    38144112
    38154113        yahoo_send_packet(yid, pkt, 0);
    38164114        yahoo_packet_free(pkt);
     4115
     4116        if(old_status == YAHOO_STATUS_INVISIBLE) {
     4117                pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_VISIBILITY, YAHOO_STATUS_AVAILABLE, 0);
     4118                yahoo_packet_hash(pkt, 13, "1");
     4119                yahoo_send_packet(yid, pkt, 0);
     4120                yahoo_packet_free(pkt);
     4121        }
    38174122}
    38184123
     
    38294134        LOG(("yahoo_logoff: current status: %d", yd->current_status));
    38304135
    3831         if(yd->current_status != -1) {
     4136        if(yd->current_status != -1 && 0) {
     4137                /* Meh. Don't send this. The event handlers are not going to
     4138                   get to do this so it'll just leak memory. And the TCP
     4139                   connection reset will hopefully be clear enough. */
    38324140                pkt = yahoo_packet_new(YAHOO_SERVICE_LOGOFF, YAHOO_STATUS_AVAILABLE, yd->session_id);
    38334141                yd->current_status = -1;
     
    40624370                return;
    40634371
    4064         pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YAHOO_STATUS_AVAILABLE, yd->session_id);
    4065         yahoo_packet_hash(pkt, 1, yd->user);
    4066         yahoo_packet_hash(pkt, 7, who);
    4067         yahoo_packet_hash(pkt, 65, group);
     4372        pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YPACKET_STATUS_DEFAULT, yd->session_id);
     4373
    40684374        if (msg != NULL) /* add message/request "it's me add me" */
    40694375                yahoo_packet_hash(pkt, 14, msg);
     4376        else
     4377                yahoo_packet_hash(pkt,14,"");
     4378
     4379        yahoo_packet_hash(pkt, 65, group);
     4380        yahoo_packet_hash(pkt, 97, "1");
     4381        yahoo_packet_hash(pkt, 1, yd->user);
     4382        yahoo_packet_hash(pkt, 302, "319");
     4383        yahoo_packet_hash(pkt, 300, "319");
     4384        yahoo_packet_hash(pkt, 7, who);
     4385        yahoo_packet_hash(pkt, 334, "0");
     4386        yahoo_packet_hash(pkt, 301, "319");
     4387        yahoo_packet_hash(pkt, 303, "319");
     4388
     4389
    40704390        yahoo_send_packet(yid, pkt, 0);
    40714391        yahoo_packet_free(pkt);
     
    40894409        yahoo_send_packet(yid, pkt, 0);
    40904410        yahoo_packet_free(pkt);
     4411}
     4412
     4413void yahoo_accept_buddy_ymsg13(int id,const char* me,const char* who){
     4414        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
     4415        struct yahoo_data *yd;
     4416
     4417        if(!yid)
     4418                return;
     4419        yd = yid->yd;
     4420
     4421        struct yahoo_packet* pkt=NULL;
     4422        pkt= yahoo_packet_new(YAHOO_SERVICE_CONTACT_YMSG13,YAHOO_STATUS_AVAILABLE,0);
     4423
     4424        yahoo_packet_hash(pkt,1,me ?: yd->user);       
     4425        yahoo_packet_hash(pkt,5,who);
     4426        yahoo_packet_hash(pkt,13,"1");
     4427        yahoo_packet_hash(pkt,334,"0");
     4428        yahoo_send_packet(yid, pkt, 0);
     4429        yahoo_packet_free(pkt);
     4430}
     4431
     4432void yahoo_reject_buddy_ymsg13(int id,const char* me,const char* who,const char* msg){
     4433        struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER);
     4434        struct yahoo_data *yd;
     4435
     4436        if(!yid)
     4437                return;
     4438        yd = yid->yd;
     4439
     4440        struct yahoo_packet* pkt=NULL;
     4441        pkt= yahoo_packet_new(YAHOO_SERVICE_CONTACT_YMSG13,YAHOO_STATUS_AVAILABLE,0);
     4442
     4443        yahoo_packet_hash(pkt,1,me ?: yd->user);       
     4444        yahoo_packet_hash(pkt,5,who);
     4445//      yahoo_packet_hash(pkt,241,YAHOO_PROTO_VER);
     4446        yahoo_packet_hash(pkt,13,"2");
     4447        yahoo_packet_hash(pkt,334,"0");
     4448        yahoo_packet_hash(pkt,97,"1");
     4449        yahoo_packet_hash(pkt,14,msg?:"");
     4450
     4451        yahoo_send_packet(yid, pkt, 0);
     4452        yahoo_packet_free(pkt);
     4453
    40914454}
    40924455
  • protocols/yahoo/yahoo.c

    raac4017 r2288705  
    197197{
    198198        struct byahoo_data *yd = (struct byahoo_data *) ic->proto_data;
    199        
    200         ic->away = NULL;
     199        char *away;
     200       
     201        away = NULL;
    201202       
    202203        if( state && msg && g_strcasecmp( state, msg ) != 0 )
    203204        {
    204205                yd->current_status = YAHOO_STATUS_CUSTOM;
    205                 ic->away = "";
     206                away = "";
    206207        }
    207208        else if( state )
     
    212213                msg = NULL;
    213214               
    214                 ic->away = "";
     215                away = "";
    215216                if( g_strcasecmp( state, "Available" ) == 0 )
    216217                {
    217218                        yd->current_status = YAHOO_STATUS_AVAILABLE;
    218                         ic->away = NULL;
     219                        away = NULL;
    219220                }
    220221                else if( g_strcasecmp( state, "Be Right Back" ) == 0 )
     
    242243                        yd->current_status = YAHOO_STATUS_AVAILABLE;
    243244                       
    244                         ic->away = NULL;
     245                        away = NULL;
    245246                }
    246247        }
     
    248249                yd->current_status = YAHOO_STATUS_AVAILABLE;
    249250       
    250         yahoo_set_away( yd->y2_id, yd->current_status, msg, ic->away != NULL ? 2 : 0 );
     251        yahoo_set_away( yd->y2_id, yd->current_status, msg, away != NULL ? 2 : 0 );
    251252}
    252253
    253254static GList *byahoo_away_states( struct im_connection *ic )
    254255{
    255         GList *m = NULL;
    256 
    257         m = g_list_append( m, "Available" );
    258         m = g_list_append( m, "Be Right Back" );
    259         m = g_list_append( m, "Busy" );
    260         m = g_list_append( m, "Not At Home" );
    261         m = g_list_append( m, "Not At Desk" );
    262         m = g_list_append( m, "Not In Office" );
    263         m = g_list_append( m, "On Phone" );
    264         m = g_list_append( m, "On Vacation" );
    265         m = g_list_append( m, "Out To Lunch" );
    266         m = g_list_append( m, "Stepped Out" );
    267         m = g_list_append( m, "Invisible" );
    268         m = g_list_append( m, GAIM_AWAY_CUSTOM );
     256        static GList *m = NULL;
     257
     258        if( m == NULL )
     259        {
     260                m = g_list_append( m, "Available" );
     261                m = g_list_append( m, "Be Right Back" );
     262                m = g_list_append( m, "Busy" );
     263                m = g_list_append( m, "Not At Home" );
     264                m = g_list_append( m, "Not At Desk" );
     265                m = g_list_append( m, "Not In Office" );
     266                m = g_list_append( m, "On Phone" );
     267                m = g_list_append( m, "On Vacation" );
     268                m = g_list_append( m, "Out To Lunch" );
     269                m = g_list_append( m, "Stepped Out" );
     270                m = g_list_append( m, "Invisible" );
     271                m = g_list_append( m, GAIM_AWAY_CUSTOM );
     272        }
    269273       
    270274        return m;
     
    345349       
    346350        return c;
     351}
     352
     353static void byahoo_auth_allow( struct im_connection *ic, const char *who )
     354{
     355        struct byahoo_data *yd = (struct byahoo_data *) ic->proto_data;
     356       
     357        yahoo_accept_buddy_ymsg13( yd->y2_id, NULL, who );
     358}
     359
     360static void byahoo_auth_deny( struct im_connection *ic, const char *who )
     361{
     362        struct byahoo_data *yd = (struct byahoo_data *) ic->proto_data;
     363       
     364        yahoo_reject_buddy_ymsg13( yd->y2_id, NULL, who, NULL );
    347365}
    348366
     
    372390        ret->handle_cmp = g_strcasecmp;
    373391       
     392        ret->auth_allow = byahoo_auth_allow;
     393        ret->auth_deny = byahoo_auth_deny;
     394       
    374395        register_protocol(ret);
    375396}
     
    451472        struct byahoo_write_ready_data *d = data;
    452473       
    453         yahoo_write_ready( d->id, d->fd, d->data );
    454        
    455         return FALSE;
     474        return yahoo_write_ready( d->id, d->fd, d->data );
    456475}
    457476
     
    790809{
    791810        struct byahoo_conf_invitation *inv = data;
    792        
    793         yahoo_conference_logon( inv->yid, NULL, inv->members, inv->name );
    794         imcb_chat_add_buddy( inv->c, inv->ic->acc->user );
     811        struct groupchat *b;
     812       
     813        for( b = inv->ic->groupchats; b; b = b->next )
     814                if( b == inv->c )
     815                        break;
     816       
     817        if( b != NULL )
     818        {
     819                yahoo_conference_logon( inv->yid, NULL, inv->members, inv->name );
     820                imcb_chat_add_buddy( inv->c, inv->ic->acc->user );
     821        }
     822        else
     823        {
     824                imcb_log( inv->ic, "Duplicate/corrupted invitation to `%s'.", inv->name );
     825        }
     826       
    795827        g_free( inv->name );
    796828        g_free( inv );
     
    908940}
    909941
     942void ext_yahoo_contact_auth_request( int id, const char *myid, const char *who, const char *msg )
     943{
     944        struct im_connection *ic = byahoo_get_ic_by_id( id );
     945       
     946        imcb_ask_auth( ic, who, NULL );
     947}
     948
    910949void ext_yahoo_contact_added( int id, const char *myid, const char *who, const char *msg )
    911950{
    912         /* Groups schmoups. If I want to handle groups properly I can get the
    913            buddy data from some internal libyahoo2 structure. */
    914         imcb_add_buddy( byahoo_get_ic_by_id( id ), (char*) who, NULL );
     951        struct im_connection *ic = byahoo_get_ic_by_id( id );
     952       
     953        imcb_add_buddy( ic, (char*) who, NULL );
    915954}
    916955
  • protocols/yahoo/yahoo2.h

    raac4017 r2288705  
    217217void yahoo_buddyicon_request(int id, const char *who);
    218218
     219void yahoo_accept_buddy_ymsg13(int,const char*,const char*);
     220void yahoo_reject_buddy_ymsg13(int,const char*,const char*,const char*);
     221
    219222#include "yahoo_httplib.h"
    220223
  • protocols/yahoo/yahoo2_callbacks.h

    raac4017 r2288705  
    361361
    362362/*
     363 * Name: ext_yahoo_contact_auth_request
     364 *      Called when a contact wants to add you to his/her contact list
     365 * Params:
     366 *      id   - the id that identifies the server connection
     367 *      myid - the identity s/he added
     368 *      who  - who did it
     369 *      msg  - any message sent
     370 */
     371void YAHOO_CALLBACK_TYPE(ext_yahoo_contact_auth_request)(int id, const char *myid, const char *who, const char *msg);
     372
     373
     374/*
    363375 * Name: ext_yahoo_contact_added
    364376 *      Called when a contact is added to your list
  • protocols/yahoo/yahoo2_types.h

    raac4017 r2288705  
    5757        YAHOO_LOGIN_LOCK = 14,
    5858        YAHOO_LOGIN_DUPL = 99,
    59         YAHOO_LOGIN_SOCK = -1
     59        YAHOO_LOGIN_SOCK = -1,
     60};
     61
     62enum ypacket_status {
     63        YPACKET_STATUS_DISCONNECTED = -1,
     64        YPACKET_STATUS_DEFAULT = 0,
     65        YPACKET_STATUS_SERVERACK = 1,
     66        YPACKET_STATUS_GAME     = 0x2,
     67        YPACKET_STATUS_AWAY     = 0x4,
     68        YPACKET_STATUS_CONTINUED = 0x5,
     69        YPACKET_STATUS_INVISIBLE = 12,
     70        YPACKET_STATUS_NOTIFY = 0x16, /* TYPING */
     71        YPACKET_STATUS_WEBLOGIN = 0x5a55aa55,
     72        YPACKET_STATUS_OFFLINE = 0x5a55aa56
    6073};
    6174
     
    8598};
    8699
    87 #define YAHOO_PROTO_VER 0x000b
     100#define YAHOO_PROTO_VER 0x0010
    88101
    89102/* Yahoo style/color directives */
     
    115128        YAHOO_CONNECTION_WEBCAM,
    116129        YAHOO_CONNECTION_CHATCAT,
    117         YAHOO_CONNECTION_SEARCH
     130        YAHOO_CONNECTION_SEARCH,
     131        YAHOO_CONNECTION_AUTH,
    118132};
    119133
     
    131145/* chat member attribs */
    132146#define YAHOO_CHAT_MALE 0x8000
    133 #define YAHOO_CHAT_FEMALE 0x10000
    134147#define YAHOO_CHAT_FEMALE 0x10000
    135148#define YAHOO_CHAT_DUNNO 0x400
  • root_commands.c

    raac4017 r2288705  
    2929#include "bitlbee.h"
    3030#include "help.h"
     31#include "chat.h"
    3132
    3233#include <string.h>
     
    7879}
    7980
     81#define MIN_ARGS( x, y... )                                                    \
     82        do                                                                     \
     83        {                                                                      \
     84                int blaat;                                                     \
     85                for( blaat = 0; blaat <= x; blaat ++ )                         \
     86                        if( cmd[blaat] == NULL )                               \
     87                        {                                                      \
     88                                irc_usermsg( irc, "Not enough parameters given (need %d).", x ); \
     89                                return y;                                      \
     90                        }                                                      \
     91        } while( 0 )
     92
    8093void root_command( irc_t *irc, char *cmd[] )
    8194{       
     
    88101                if( g_strcasecmp( commands[i].command, cmd[0] ) == 0 )
    89102                {
    90                         if( !cmd[commands[i].required_parameters] )
    91                         {
    92                                 irc_usermsg( irc, "Not enough parameters given (need %d)", commands[i].required_parameters );
    93                                 return;
    94                         }
     103                        MIN_ARGS( commands[i].required_parameters );
     104                       
    95105                        commands[i].execute( irc, cmd );
    96106                        return;
     
    131141static void cmd_identify( irc_t *irc, char **cmd )
    132142{
    133         storage_status_t status = storage_load( irc->nick, cmd[1], irc );
     143        storage_status_t status = storage_load( irc, cmd[1] );
    134144        char *account_on[] = { "account", "on", NULL };
    135145       
     
    143153        case STORAGE_OK:
    144154                irc_usermsg( irc, "Password accepted, settings and accounts loaded" );
     155                irc_setpass( irc, cmd[1] );
     156                irc->status |= USTATUS_IDENTIFIED;
    145157                irc_umode_set( irc, "+R", 1 );
    146158                if( set_getbool( &irc->set, "auto_connect" ) )
     
    162174        }
    163175
    164         irc_setpass( irc, cmd[1] );
    165         switch( storage_save( irc, FALSE )) {
     176        switch( storage_save( irc, cmd[1], FALSE ) ) {
    166177                case STORAGE_ALREADY_EXISTS:
    167178                        irc_usermsg( irc, "Nick is already registered" );
     
    170181                case STORAGE_OK:
    171182                        irc_usermsg( irc, "Account successfully created" );
     183                        irc_setpass( irc, cmd[1] );
    172184                        irc->status |= USTATUS_IDENTIFIED;
    173185                        irc_umode_set( irc, "+R", 1 );
     
    238250}
    239251
     252static void cmd_showset( irc_t *irc, set_t **head, char *key )
     253{
     254        char *val;
     255       
     256        if( ( val = set_getstr( head, key ) ) )
     257                irc_usermsg( irc, "%s = `%s'", key, val );
     258        else
     259                irc_usermsg( irc, "%s is empty", key );
     260}
     261
     262typedef set_t** (*cmd_set_findhead)( irc_t*, char* );
     263typedef int (*cmd_set_checkflags)( irc_t*, set_t *set );
     264
     265static int cmd_set_real( irc_t *irc, char **cmd, cmd_set_findhead findhead, cmd_set_checkflags checkflags )
     266{
     267        char *set_full = NULL, *set_name = NULL, *tmp;
     268        set_t **head;
     269       
     270        if( cmd[1] && g_strncasecmp( cmd[1], "-del", 4 ) == 0 )
     271        {
     272                MIN_ARGS( 2, 0 );
     273                set_full = cmd[2];
     274        }
     275        else
     276                set_full = cmd[1];
     277       
     278        if( findhead == NULL )
     279        {
     280                set_name = set_full;
     281               
     282                head = &irc->set;
     283        }
     284        else
     285        {
     286                char *id;
     287               
     288                if( ( tmp = strchr( set_full, '/' ) ) )
     289                {
     290                        id = g_strndup( set_full, ( tmp - set_full ) );
     291                        set_name = tmp + 1;
     292                }
     293                else
     294                {
     295                        id = g_strdup( set_full );
     296                }
     297               
     298                if( ( head = findhead( irc, id ) ) == NULL )
     299                {
     300                        g_free( id );
     301                        irc_usermsg( irc, "Could not find setting." );
     302                        return 0;
     303                }
     304                g_free( id );
     305        }
     306       
     307        if( cmd[1] && cmd[2] && set_name )
     308        {
     309                set_t *s = set_find( head, set_name );
     310                int st;
     311               
     312                if( s && checkflags && checkflags( irc, s ) == 0 )
     313                        return 0;
     314               
     315                if( g_strncasecmp( cmd[1], "-del", 4 ) == 0 )
     316                        st = set_reset( head, set_name );
     317                else
     318                        st = set_setstr( head, set_name, cmd[2] );
     319               
     320                if( set_getstr( head, set_name ) == NULL )
     321                {
     322                        if( st )
     323                                irc_usermsg( irc, "Setting changed successfully" );
     324                        else
     325                                irc_usermsg( irc, "Failed to change setting" );
     326                }
     327                else
     328                {
     329                        cmd_showset( irc, head, set_name );
     330                }
     331        }
     332        else if( set_name )
     333        {
     334                cmd_showset( irc, head, set_name );
     335        }
     336        else
     337        {
     338                set_t *s = *head;
     339                while( s )
     340                {
     341                        cmd_showset( irc, &s, s->key );
     342                        s = s->next;
     343                }
     344        }
     345       
     346        return 1;
     347}
     348
     349static set_t **cmd_account_set_findhead( irc_t *irc, char *id )
     350{
     351        account_t *a;
     352       
     353        if( ( a = account_get( irc, id ) ) )
     354                return &a->set;
     355        else
     356                return NULL;
     357}
     358
     359static int cmd_account_set_checkflags( irc_t *irc, set_t *s )
     360{
     361        account_t *a = s->data;
     362       
     363        if( a->ic && s && s->flags & ACC_SET_OFFLINE_ONLY )
     364        {
     365                irc_usermsg( irc, "This setting can only be changed when the account is %s-line", "off" );
     366                return 0;
     367        }
     368        else if( !a->ic && s && s->flags & ACC_SET_ONLINE_ONLY )
     369        {
     370                irc_usermsg( irc, "This setting can only be changed when the account is %s-line", "on" );
     371                return 0;
     372        }
     373       
     374        return 1;
     375}
     376
    240377static void cmd_account( irc_t *irc, char **cmd )
    241378{
     
    252389                struct prpl *prpl;
    253390               
    254                 if( cmd[2] == NULL || cmd[3] == NULL || cmd[4] == NULL )
    255                 {
    256                         irc_usermsg( irc, "Not enough parameters" );
    257                         return;
    258                 }
    259                
    260                 prpl = find_protocol(cmd[2]);
     391                MIN_ARGS( 4 );
     392               
     393                prpl = find_protocol( cmd[2] );
    261394               
    262395                if( prpl == NULL )
     
    278411        else if( g_strcasecmp( cmd[1], "del" ) == 0 )
    279412        {
    280                 if( !cmd[2] )
    281                 {
    282                         irc_usermsg( irc, "Not enough parameters given (need %d)", 2 );
    283                 }
    284                 else if( !( a = account_get( irc, cmd[2] ) ) )
     413                MIN_ARGS( 2 );
     414
     415                if( !( a = account_get( irc, cmd[2] ) ) )
    285416                {
    286417                        irc_usermsg( irc, "Invalid account" );
     
    410541        else if( g_strcasecmp( cmd[1], "set" ) == 0 )
    411542        {
    412                 char *acc_handle, *set_name = NULL, *tmp;
    413                
    414                 if( !cmd[2] )
    415                 {
    416                         irc_usermsg( irc, "Not enough parameters given (need %d)", 2 );
    417                         return;
    418                 }
    419                
    420                 if( g_strncasecmp( cmd[2], "-del", 4 ) == 0 )
    421                         acc_handle = g_strdup( cmd[3] );
    422                 else
    423                         acc_handle = g_strdup( cmd[2] );
    424                
    425                 if( !acc_handle )
    426                 {
    427                         irc_usermsg( irc, "Not enough parameters given (need %d)", 3 );
    428                         return;
    429                 }
    430                
    431                 if( ( tmp = strchr( acc_handle, '/' ) ) )
    432                 {
    433                         *tmp = 0;
    434                         set_name = tmp + 1;
    435                 }
    436                
    437                 if( ( a = account_get( irc, acc_handle ) ) == NULL )
    438                 {
    439                         g_free( acc_handle );
    440                         irc_usermsg( irc, "Invalid account" );
    441                         return;
    442                 }
    443                
    444                 if( cmd[3] && set_name )
    445                 {
    446                         set_t *s = set_find( &a->set, set_name );
    447                        
    448                         if( a->ic && s && s->flags & ACC_SET_OFFLINE_ONLY )
    449                         {
    450                                 g_free( acc_handle );
    451                                 irc_usermsg( irc, "This setting can only be changed when the account is %s-line", "off" );
    452                                 return;
    453                         }
    454                         else if( !a->ic && s && s->flags & ACC_SET_ONLINE_ONLY )
    455                         {
    456                                 g_free( acc_handle );
    457                                 irc_usermsg( irc, "This setting can only be changed when the account is %s-line", "on" );
    458                                 return;
    459                         }
    460                        
    461                         if( g_strncasecmp( cmd[2], "-del", 4 ) == 0 )
    462                                 set_reset( &a->set, set_name );
    463                         else
    464                                 set_setstr( &a->set, set_name, cmd[3] );
    465                 }
    466                 if( set_name ) /* else 'forgotten' on purpose.. Must show new value after changing */
    467                 {
    468                         char *s = set_getstr( &a->set, set_name );
    469                         if( s )
    470                                 irc_usermsg( irc, "%s = `%s'", set_name, s );
    471                         else
    472                                 irc_usermsg( irc, "%s is empty", set_name );
    473                 }
    474                 else
    475                 {
    476                         set_t *s = a->set;
    477                         while( s )
    478                         {
    479                                 if( s->value || s->def )
    480                                         irc_usermsg( irc, "%s = `%s'", s->key, s->value ? s->value : s->def );
    481                                 else
    482                                         irc_usermsg( irc, "%s is empty", s->key );
    483                                 s = s->next;
    484                         }
    485                 }
    486                
    487                 g_free( acc_handle );
    488         }
    489         else
    490         {
    491                 irc_usermsg( irc, "Unknown command: account %s. Please use \x02help commands\x02 to get a list of available commands.", cmd[1] );
     543                MIN_ARGS( 2 );
     544               
     545                cmd_set_real( irc, cmd + 1, cmd_account_set_findhead, cmd_account_set_checkflags );
     546        }
     547        else
     548        {
     549                irc_usermsg( irc, "Unknown command: %s %s. Please use \x02help commands\x02 to get a list of available commands.", "account", cmd[1] );
    492550        }
    493551}
     
    500558        if( g_strcasecmp( cmd[1], "-tmp" ) == 0 )
    501559        {
     560                MIN_ARGS( 3 );
    502561                add_on_server = 0;
    503562                cmd ++;
     
    610669                        irc->mynick = g_strdup( cmd[2] );
    611670                       
     671                        /* If we're called internally (user did "set root_nick"),
     672                           let's not go O(INF). :-) */
    612673                        if( strcmp( cmd[0], "set_rename" ) != 0 )
    613674                                set_setstr( &irc->set, "root_nick", cmd[2] );
     
    633694        }
    634695       
    635         return strcmp( irc->mynick, new_nick ) == 0 ? new_nick : NULL;
     696        return strcmp( irc->mynick, new_nick ) == 0 ? new_nick : SET_INVALID;
    636697}
    637698
     
    817878static void cmd_set( irc_t *irc, char **cmd )
    818879{
    819         char *set_name = cmd[1];
    820        
    821         if( cmd[1] && cmd[2] )
    822         {
    823                 if( g_strncasecmp( cmd[1], "-del", 4 ) == 0 )
    824                 {
    825                         set_reset( &irc->set, cmd[2] );
    826                         set_name = cmd[2];
    827                 }
    828                 else
    829                 {
    830                         set_setstr( &irc->set, cmd[1], cmd[2] );
    831                 }
    832         }
    833         if( set_name ) /* else 'forgotten' on purpose.. Must show new value after changing */
    834         {
    835                 char *s = set_getstr( &irc->set, set_name );
    836                 if( s )
    837                         irc_usermsg( irc, "%s = `%s'", set_name, s );
    838                 else
    839                         irc_usermsg( irc, "%s is empty", set_name );
    840 
    841                 if( strchr( set_name, '/' ) )
    842                         irc_usermsg( irc, "Warning: / found in setting name, you're probably looking for the `account set' command." );
    843         }
    844         else
    845         {
    846                 set_t *s = irc->set;
    847                 while( s )
    848                 {
    849                         if( s->value || s->def )
    850                                 irc_usermsg( irc, "%s = `%s'", s->key, s->value ? s->value : s->def );
    851                         else
    852                                 irc_usermsg( irc, "%s is empty", s->key );
    853                         s = s->next;
    854                 }
    855         }
     880        cmd_set_real( irc, cmd, NULL, NULL );
    856881}
    857882
    858883static void cmd_save( irc_t *irc, char **cmd )
    859884{
    860         if( storage_save( irc, TRUE ) == STORAGE_OK )
     885        if( ( irc->status & USTATUS_IDENTIFIED ) == 0 )
     886                irc_usermsg( irc, "Please create an account first" );
     887        else if( storage_save( irc, NULL, TRUE ) == STORAGE_OK )
    861888                irc_usermsg( irc, "Configuration saved" );
    862889        else
     
    9741001static void cmd_join_chat( irc_t *irc, char **cmd )
    9751002{
     1003        irc_usermsg( irc, "This command is now obsolete. "
     1004                          "Please try the `chat' command instead." );
     1005}
     1006
     1007static set_t **cmd_chat_set_findhead( irc_t *irc, char *id )
     1008{
     1009        struct chat *c;
     1010       
     1011        if( ( c = chat_get( irc, id ) ) )
     1012                return &c->set;
     1013        else
     1014                return NULL;
     1015}
     1016
     1017static void cmd_chat( irc_t *irc, char **cmd )
     1018{
     1019        account_t *acc;
     1020        struct chat *c;
     1021       
     1022        if( g_strcasecmp( cmd[1], "add" ) == 0 )
     1023        {
     1024                char *channel, *s;
     1025               
     1026                MIN_ARGS( 3 );
     1027               
     1028                if( !( acc = account_get( irc, cmd[2] ) ) )
     1029                {
     1030                        irc_usermsg( irc, "Invalid account" );
     1031                        return;
     1032                }
     1033               
     1034                if( cmd[4] == NULL )
     1035                {
     1036                        channel = g_strdup( cmd[3] );
     1037                        if( ( s = strchr( channel, '@' ) ) )
     1038                                *s = 0;
     1039                }
     1040                else
     1041                {
     1042                        channel = g_strdup( cmd[4] );
     1043                }
     1044               
     1045                if( strchr( CTYPES, channel[0] ) == NULL )
     1046                {
     1047                        s = g_strdup_printf( "%c%s", CTYPES[0], channel );
     1048                        g_free( channel );
     1049                        channel = s;
     1050                }
     1051               
     1052                if( ( c = chat_add( irc, acc, cmd[3], channel ) ) )
     1053                        irc_usermsg( irc, "Chatroom added successfully." );
     1054                else
     1055                        irc_usermsg( irc, "Could not add chatroom." );
     1056               
     1057                g_free( channel );
     1058        }
     1059        else if( g_strcasecmp( cmd[1], "list" ) == 0 )
     1060        {
     1061                int i = 0;
     1062               
     1063                if( strchr( irc->umode, 'b' ) )
     1064                        irc_usermsg( irc, "Chatroom list:" );
     1065               
     1066                for( c = irc->chatrooms; c; c = c->next )
     1067                {
     1068                        irc_usermsg( irc, "%2d. %s(%s) %s, %s", i, c->acc->prpl->name,
     1069                                          c->acc->user, c->handle, c->channel );
     1070                       
     1071                        i ++;
     1072                }
     1073                irc_usermsg( irc, "End of chatroom list" );
     1074        }
     1075        else if( g_strcasecmp( cmd[1], "set" ) == 0 )
     1076        {
     1077                MIN_ARGS( 2 );
     1078               
     1079                cmd_set_real( irc, cmd + 1, cmd_chat_set_findhead, NULL );
     1080        }
     1081        else if( g_strcasecmp( cmd[1], "del" ) == 0 )
     1082        {
     1083                MIN_ARGS( 2 );
     1084               
     1085                if( ( c = chat_get( irc, cmd[2] ) ) )
     1086                {
     1087                        chat_del( irc, c );
     1088                }
     1089                else
     1090                {
     1091                        irc_usermsg( irc, "Could not remove chat." );
     1092                }
     1093        }
     1094        else if( g_strcasecmp( cmd[1], "with" ) == 0 )
     1095        {
     1096                user_t *u;
     1097               
     1098                MIN_ARGS( 2 );
     1099               
     1100                if( ( u = user_find( irc, cmd[2] ) ) && u->ic && u->ic->acc->prpl->chat_with )
     1101                {
     1102                        if( !u->ic->acc->prpl->chat_with( u->ic, u->handle ) )
     1103                        {
     1104                                irc_usermsg( irc, "(Possible) failure while trying to open "
     1105                                                  "a groupchat with %s.", u->nick );
     1106                        }
     1107                }
     1108                else
     1109                {
     1110                        irc_usermsg( irc, "Can't open a groupchat with %s.", cmd[2] );
     1111                }
     1112        }
     1113        else
     1114        {
     1115                irc_usermsg( irc, "Unknown command: %s %s. Please use \x02help commands\x02 to get a list of available commands.", "chat", cmd[1] );
     1116        }
     1117
     1118
     1119
     1120#if 0
    9761121        account_t *a;
    9771122        struct im_connection *ic;
     
    9991144        if( cmd[3] )
    10001145        {
    1001                 if( cmd[3][0] != '#' && cmd[3][0] != '&' )
     1146                if( strchr( CTYPES, cmd[3][0] ) == NULL )
    10021147                        channel = g_strdup_printf( "&%s", cmd[3] );
    10031148                else
     
    10421187                g_free( channel );
    10431188        }
     1189#endif
    10441190}
    10451191
     
    11291275        { "qlist",          0, cmd_qlist,          0 },
    11301276        { "join_chat",      2, cmd_join_chat,      0 },
     1277        { "chat",           1, cmd_chat,           0 },
    11311278        { "transfers",      0, cmd_transfers,      0 },
    11321279        { NULL }
  • set.c

    raac4017 r2288705  
    2525#define BITLBEE_CORE
    2626#include "bitlbee.h"
     27
     28/* Used to use NULL for this, but NULL is actually a "valid" value. */
     29char *SET_INVALID = "nee";
    2730
    2831set_t *set_add( set_t **head, char *key, char *def, set_eval eval, void *data )
     
    114117       
    115118        if( !s )
     119                /*
     120                Used to do this, but it never really made sense.
    116121                s = set_add( head, key, NULL, NULL, NULL );
    117        
    118         if( s->eval && !( nv = s->eval( s, value ) ) )
     122                */
     123                return 0;
     124       
     125        if( value == NULL && ( s->flags & SET_NULL_OK ) == 0 )
     126                return 0;
     127       
     128        /* Call the evaluator. For invalid values, evaluators should now
     129           return SET_INVALID, but previously this was NULL. Try to handle
     130           that too if NULL is not an allowed value for this setting. */
     131        if( s->eval && ( ( nv = s->eval( s, value ) ) == SET_INVALID ||
     132                         ( ( s->flags & SET_NULL_OK ) == 0 && nv == NULL ) ) )
    119133                return 0;
    120134       
     
    168182}
    169183
    170 void set_reset( set_t **head, char *key )
     184int set_reset( set_t **head, char *key )
    171185{
    172186        set_t *s;
     
    174188        s = set_find( head, key );
    175189        if( s )
    176                 set_setstr( head, key, s->def );
     190                return set_setstr( head, key, s->def );
     191       
     192        return 0;
    177193}
    178194
     
    187203        for( ; *s; s ++ )
    188204                if( !isdigit( *s ) )
    189                         return NULL;
     205                        return SET_INVALID;
    190206       
    191207        return value;
     
    194210char *set_eval_bool( set_t *set, char *value )
    195211{
    196         return is_bool( value ) ? value : NULL;
     212        return is_bool( value ) ? value : SET_INVALID;
    197213}
    198214
     
    226242                                                              irc->channel, "-oo", irc->nick, irc->mynick );
    227243        else
    228                 return NULL;
     244                return SET_INVALID;
    229245       
    230246        return value;
  • set.h

    raac4017 r2288705  
    4444typedef char *(*set_eval) ( struct set *set, char *value );
    4545
     46extern char *SET_INVALID;
     47
     48#define SET_NULL_OK        0x0100
     49
    4650typedef struct set
    4751{
     
    6165                           this (yet?). */
    6266       
    63         /* Eval: Returns NULL if the value is incorrect or exactly the
    64            passed value variable. When returning a corrected value,
     67        /* Eval: Returns SET_INVALID if the value is incorrect or exactly
     68           the passed value variable. When returning a corrected value,
    6569           set_setstr() should be able to free() the returned string! */
    6670        set_eval eval;
     
    8892int set_setint( set_t **head, char *key, int value );
    8993void set_del( set_t **head, char *key );
    90 void set_reset( set_t **head, char *key );
     94int set_reset( set_t **head, char *key );
    9195
    9296/* Two very useful generic evaluators. */
  • storage.c

    raac4017 r2288705  
    103103}
    104104
    105 storage_status_t storage_load (const char *nick, const char *password, irc_t * irc)
    106 {
    107         GList *gl;
     105storage_status_t storage_load (irc_t * irc, const char *password)
     106{
     107        GList *gl;
     108       
     109        if (irc && irc->status & USTATUS_IDENTIFIED)
     110                return STORAGE_OTHER_ERROR;
    108111       
    109112        /* Loop until we don't get NO_SUCH_USER */
     
    112115                storage_status_t status;
    113116
    114                 status = st->load(nick, password, irc);
    115                 if (status == STORAGE_OK) {
    116                         irc_setpass(irc, password);
     117                status = st->load(irc, password);
     118                if (status == STORAGE_OK)
    117119                        return status;
    118                 }
    119120               
    120121                if (status != STORAGE_NO_SUCH_USER)
     
    125126}
    126127
    127 storage_status_t storage_save (irc_t *irc, int overwrite)
    128 {
    129         return ((storage_t *)global.storage->data)->save(irc, overwrite);
     128storage_status_t storage_save (irc_t *irc, char *password, int overwrite)
     129{
     130        storage_status_t st;
     131       
     132        if (password != NULL) {
     133                /* Should only use this in the "register" command. */
     134                if (irc->password || overwrite)
     135                        return STORAGE_OTHER_ERROR;
     136               
     137                irc_setpass(irc, password);
     138        } else if ((irc->status & USTATUS_IDENTIFIED) == 0) {
     139                return STORAGE_NO_SUCH_USER;
     140        }
     141       
     142        st = ((storage_t *)global.storage->data)->save(irc, overwrite);
     143       
     144        if (password != NULL) {
     145                irc_setpass(irc, NULL);
     146        }
     147       
     148        return st;
    130149}
    131150
     
    143162
    144163                status = st->remove(nick, password);
    145                 if (status != STORAGE_NO_SUCH_USER &&
    146                         status != STORAGE_OK)
     164                if (status != STORAGE_NO_SUCH_USER && status != STORAGE_OK)
    147165                        ret = status;
    148166        }
     
    150168        return ret;
    151169}
     170
     171#if 0
     172Not using this yet. Test thoroughly before adding UI hooks to this function.
    152173
    153174storage_status_t storage_rename (const char *onick, const char *nnick, const char *password)
     
    189210        return STORAGE_OK;
    190211}
     212#endif
  • storage.h

    raac4017 r2288705  
    4545        storage_status_t (*check_pass) (const char *nick, const char *password);
    4646
    47         storage_status_t (*load) (const char *nick, const char *password, irc_t * irc);
     47        storage_status_t (*load) (irc_t *irc, const char *password);
    4848        storage_status_t (*save) (irc_t *irc, int overwrite);
    4949        storage_status_t (*remove) (const char *nick, const char *password);
     
    5555storage_status_t storage_check_pass (const char *nick, const char *password);
    5656
    57 storage_status_t storage_load (const char *nick, const char *password, irc_t * irc);
    58 storage_status_t storage_save (irc_t *irc, int overwrite);
     57storage_status_t storage_load (irc_t * irc, const char *password);
     58storage_status_t storage_save (irc_t *irc, char *password, int overwrite);
    5959storage_status_t storage_remove (const char *nick, const char *password);
    6060
    61 storage_status_t storage_rename (const char *onick, const char *nnick, const char *password);
     61/* storage_status_t storage_rename (const char *onick, const char *nnick, const char *password); */
    6262
    6363void register_storage_backend(storage_t *);
  • storage_text.c

    raac4017 r2288705  
    4444}
    4545
    46 static storage_status_t text_load ( const char *my_nick, const char* password, irc_t *irc )
     46static storage_status_t text_load( irc_t *irc, const char* password )
    4747{
    4848        char s[512];
     
    5454        account_t *acc, *acc_lookup[9];
    5555       
    56         if( irc->status & USTATUS_IDENTIFIED )
    57                 return( 1 );
    58        
    59         g_snprintf( s, 511, "%s%s%s", global.conf->configdir, my_nick, ".accounts" );
     56        g_snprintf( s, 511, "%s%s%s", global.conf->configdir, irc->nick, ".accounts" );
    6057        fp = fopen( s, "r" );
    6158        if( !fp ) return STORAGE_NO_SUCH_USER;
     
    6865                return STORAGE_INVALID_PASSWORD;
    6966        }
    70        
    71         /* Do this now. If the user runs with AuthMode = Registered, the
    72            account command will not work otherwise. */
    73         irc->status |= USTATUS_IDENTIFIED;
    7467       
    7568        while( fscanf( fp, "%511[^\n]s", s ) > 0 )
     
    10194        }
    10295       
    103         g_snprintf( s, 511, "%s%s%s", global.conf->configdir, my_nick, ".nicks" );
     96        g_snprintf( s, 511, "%s%s%s", global.conf->configdir, irc->nick, ".nicks" );
    10497        fp = fopen( s, "r" );
    10598        if( !fp ) return STORAGE_NO_SUCH_USER;
  • storage_xml.c

    raac4017 r2288705  
    2929#include "arc.h"
    3030#include "md5.h"
     31#include "chat.h"
     32
     33#if GLIB_CHECK_VERSION(2,8,0)
    3134#include <glib/gstdio.h>
    32 
    33 #if !GLIB_CHECK_VERSION(2,8,0)
     35#else
    3436/* GLib < 2.8.0 doesn't have g_access, so just use the system access(). */
     37#include <unistd.h>
    3538#define g_access access
    3639#endif
     
    5255        char *current_setting;
    5356        account_t *current_account;
     57        struct chat *current_chat;
     58        set_t **current_set_head;
    5459        char *given_nick;
    5560        char *given_pass;
     
    170175               
    171176                if( ( setting = xml_attr( attr_names, attr_values, "name" ) ) )
     177                {
     178                        if( xd->current_chat != NULL )
     179                                xd->current_set_head = &xd->current_chat->set;
     180                        else if( xd->current_account != NULL )
     181                                xd->current_set_head = &xd->current_account->set;
     182                        else
     183                                xd->current_set_head = &xd->irc->set;
     184                       
    172185                        xd->current_setting = g_strdup( setting );
     186                }
    173187                else
    174188                        g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
     
    192206                }
    193207        }
     208        else if( g_strcasecmp( element_name, "chat" ) == 0 )
     209        {
     210                char *handle, *channel;
     211               
     212                handle = xml_attr( attr_names, attr_values, "handle" );
     213                channel = xml_attr( attr_names, attr_values, "channel" );
     214               
     215                if( xd->current_account && handle && channel )
     216                {
     217                        xd->current_chat = chat_add( xd->irc, xd->current_account, handle, channel );
     218                }
     219                else
     220                {
     221                        g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
     222                                     "Missing attributes for %s element", element_name );
     223                }
     224        }
    194225        else
    195226        {
     
    212243                xd->current_account = NULL;
    213244        }
     245        else if( g_strcasecmp( element_name, "chat" ) == 0 )
     246        {
     247                xd->current_chat = NULL;
     248        }
    214249}
    215250
     
    218253        char text[text_len+1];
    219254        struct xml_parsedata *xd = data;
    220         irc_t *irc = xd->irc;
    221255       
    222256        strncpy( text, text_orig, text_len );
     
    231265        else if( g_strcasecmp( g_markup_parse_context_get_element( ctx ), "setting" ) == 0 && xd->current_setting )
    232266        {
    233                 set_setstr( xd->current_account ? &xd->current_account->set : &irc->set,
    234                             xd->current_setting, (char*) text );
     267                set_setstr( xd->current_set_head, xd->current_setting, (char*) text );
    235268                g_free( xd->current_setting );
    236269                xd->current_setting = NULL;
     
    256289}
    257290
    258 static storage_status_t xml_load_real( const char *my_nick, const char *password, irc_t *irc, xml_pass_st action )
     291static storage_status_t xml_load_real( irc_t *irc, const char *my_nick, const char *password, xml_pass_st action )
    259292{
    260293        GMarkupParseContext *ctx;
     
    263296        GError *gerr = NULL;
    264297        int fd, st;
    265        
    266         if( irc && irc->status & USTATUS_IDENTIFIED )
    267                 return( 1 );
    268298       
    269299        xd = g_new0( struct xml_parsedata, 1 );
     
    318348                return STORAGE_OK;
    319349       
    320         irc->status |= USTATUS_IDENTIFIED;
    321        
    322350        return STORAGE_OK;
    323351}
    324352
    325 static storage_status_t xml_load( const char *my_nick, const char *password, irc_t *irc )
    326 {
    327         return xml_load_real( my_nick, password, irc, XML_PASS_UNKNOWN );
     353static storage_status_t xml_load( irc_t *irc, const char *password )
     354{
     355        return xml_load_real( irc, irc->nick, password, XML_PASS_UNKNOWN );
    328356}
    329357
     
    332360        /* This is a little bit risky because we have to pass NULL for the
    333361           irc_t argument. This *should* be fine, if I didn't miss anything... */
    334         return xml_load_real( my_nick, password, NULL, XML_PASS_CHECK_ONLY );
     362        return xml_load_real( NULL, my_nick, password, XML_PASS_CHECK_ONLY );
    335363}
    336364
     
    367395        md5_byte_t pass_md5[21];
    368396        md5_state_t md5_state;
    369        
    370         if( irc->password == NULL )
    371         {
    372                 irc_usermsg( irc, "Please register yourself if you want to save your settings." );
    373                 return STORAGE_OTHER_ERROR;
    374         }
    375397       
    376398        path2 = g_strdup( irc->nick );
     
    406428       
    407429        for( set = irc->set; set; set = set->next )
    408                 if( set->value && set->def )
     430                if( set->value )
    409431                        if( !xml_printf( fd, 1, "<setting name=\"%s\">%s</setting>\n", set->key, set->value ) )
    410432                                goto write_error;
     
    415437                char *pass_b64;
    416438                int pass_len;
     439                struct chat *c;
    417440               
    418441                pass_len = arc_encode( acc->pass, strlen( acc->pass ), (unsigned char**) &pass_cr, irc->password, 12 );
     
    433456               
    434457                for( set = acc->set; set; set = set->next )
    435                         if( set->value && set->def && !( set->flags & ACC_SET_NOSAVE ) )
     458                        if( set->value && !( set->flags & ACC_SET_NOSAVE ) )
    436459                                if( !xml_printf( fd, 2, "<setting name=\"%s\">%s</setting>\n", set->key, set->value ) )
    437460                                        goto write_error;
     
    447470                        goto write_error;
    448471               
     472                for( c = irc->chatrooms; c; c = c->next )
     473                {
     474                        if( c->acc != acc )
     475                                continue;
     476                       
     477                        if( !xml_printf( fd, 2, "<chat handle=\"%s\" channel=\"%s\" type=\"%s\">\n",
     478                                                c->handle, c->channel, "room" ) )
     479                                goto write_error;
     480                       
     481                        for( set = c->set; set; set = set->next )
     482                                if( set->value && !( set->flags & ACC_SET_NOSAVE ) )
     483                                        if( !xml_printf( fd, 3, "<setting name=\"%s\">%s</setting>\n",
     484                                                                set->key, set->value ) )
     485                                                goto write_error;
     486
     487                        if( !xml_printf( fd, 2, "</chat>\n" ) )
     488                                goto write_error;
     489                }
     490               
    449491                if( !xml_printf( fd, 1, "</account>\n" ) )
    450492                        goto write_error;
  • tests/Makefile

    raac4017 r2288705  
    1111distclean: clean
    1212
    13 main_objs = 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_xml.o storage_text.o user.o
     13main_objs = account.o bitlbee.o chat.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_xml.o storage_text.o user.o
    1414
    1515test_objs = check.o check_util.o check_nick.o check_md5.o check_arc.o check_irc.o check_help.o check_user.o check_crypting.o check_set.o check_jabber_sasl.o check_jabber_util.o
  • tests/check_set.c

    raac4017 r2288705  
    9696END_TEST
    9797
    98 START_TEST(test_setstr_implicit)
    99         void *data = "data";
    100         set_t *s = NULL, *t;
    101         set_setstr(&s, "name", "bloe");
    102         fail_unless(set_find(&s, "name") != NULL);
    103 END_TEST
    104 
    10598START_TEST(test_set_get_int_unknown)
    10699        set_t *s = NULL;
     
    126119        tcase_add_test (tc_core, test_setint);
    127120        tcase_add_test (tc_core, test_setstr);
    128         tcase_add_test (tc_core, test_setstr_implicit);
    129121        return s;
    130122}
  • user.c

    raac4017 r2288705  
    141141}
    142142
    143 user_t *user_findhandle( struct im_connection *ic, char *handle )
     143user_t *user_findhandle( struct im_connection *ic, const char *handle )
    144144{
    145145        user_t *u;
  • user.h

    raac4017 r2288705  
    5656int user_del( irc_t *irc, char *nick );
    5757G_MODULE_EXPORT user_t *user_find( irc_t *irc, char *nick );
    58 G_MODULE_EXPORT user_t *user_findhandle( struct im_connection *ic, char *handle );
     58G_MODULE_EXPORT user_t *user_findhandle( struct im_connection *ic, const char *handle );
    5959void user_rename( irc_t *irc, char *oldnick, char *newnick );
    6060
Note: See TracChangeset for help on using the changeset viewer.