Changes in / [38ff846:8b8def58]


Ignore:
Files:
35 added
15 deleted
70 edited

Legend:

Unmodified
Added
Removed
  • Makefile

    r38ff846 r8b8def58  
    1010
    1111# Program variables
    12 objects = account.o bitlbee.o chat.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
    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
     12objects = bitlbee.o dcc.o help.o ipc.o irc.o irc_im.o irc_channel.o irc_commands.o irc_send.o irc_user.o irc_util.o nick.o query.o root_commands.o set.o storage.o $(STORAGE_OBJS)
     13headers = account.h bitlbee.h commands.h conf.h config.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
     
    8282install-dev:
    8383        mkdir -p $(DESTDIR)$(INCLUDEDIR)
    84         install -m 0644 $(headers) $(DESTDIR)$(INCLUDEDIR)
     84        install -m 0644 config.h $(DESTDIR)$(INCLUDEDIR)
     85        for i in $(headers); do install -m 0644 $(SRCDIR)$$i $(DESTDIR)$(INCLUDEDIR); done
    8586        mkdir -p $(DESTDIR)$(PCDIR)
    8687        install -m 0644 bitlbee.pc $(DESTDIR)$(PCDIR)
     
    9394install-etc:
    9495        mkdir -p $(DESTDIR)$(ETCDIR)
    95         install -m 0644 motd.txt $(DESTDIR)$(ETCDIR)/motd.txt
    96         install -m 0644 bitlbee.conf $(DESTDIR)$(ETCDIR)/bitlbee.conf
     96        install -m 0644 $(SRCDIR)motd.txt $(DESTDIR)$(ETCDIR)/motd.txt
     97        install -m 0644 $(SRCDIR)bitlbee.conf $(DESTDIR)$(ETCDIR)/bitlbee.conf
    9798
    9899uninstall-etc:
     
    110111        @$(MAKE) -C $@ $(MAKECMDGOALS)
    111112
    112 $(objects): %.o: %.c
     113$(objects): %.o: $(SRCDIR)%.c
    113114        @echo '*' Compiling $<
    114115        @$(CC) -c $(CFLAGS) $< -o $@
  • bitlbee.c

    r38ff846 r8b8def58  
    121121        }
    122122       
    123         global.listen_watch_source_id = b_input_add( global.listen_socket, GAIM_INPUT_READ, bitlbee_io_new_client, NULL );
     123        global.listen_watch_source_id = b_input_add( global.listen_socket, B_EV_IO_READ, bitlbee_io_new_client, NULL );
    124124       
    125125#ifndef _WIN32
     
    321321                        child->pid = client_pid;
    322322                        child->ipc_fd = fds[0];
    323                         child->ipc_inpa = b_input_add( child->ipc_fd, GAIM_INPUT_READ, ipc_master_read, child );
     323                        child->ipc_inpa = b_input_add( child->ipc_fd, B_EV_IO_READ, ipc_master_read, child );
    324324                        child_list = g_slist_append( child_list, child );
    325325                       
     
    349349                        /* We can store the IPC fd there now. */
    350350                        global.listen_socket = fds[1];
    351                         global.listen_watch_source_id = b_input_add( fds[1], GAIM_INPUT_READ, ipc_child_read, irc );
     351                        global.listen_watch_source_id = b_input_add( fds[1], B_EV_IO_READ, ipc_child_read, irc );
    352352                       
    353353                        close( fds[0] );
  • bitlbee.h

    r38ff846 r8b8def58  
    4343
    4444#if HAVE_CONFIG_H
    45 #include "config.h"
     45#include <config.h>
    4646#endif
    4747
     
    126126#define CONF_FILE_DEF ETCDIR "bitlbee.conf"
    127127
     128#include "bee.h"
    128129#include "irc.h"
    129130#include "storage.h"
     
    160161gboolean bitlbee_io_current_client_write( gpointer data, gint source, b_input_condition cond );
    161162
    162 void root_command_string( irc_t *irc, user_t *u, char *command, int flags );
     163void root_command_string( irc_t *irc, char *command );
    163164void root_command( irc_t *irc, char *command[] );
    164165gboolean bitlbee_shutdown( gpointer data, gint fd, b_input_condition cond );
  • conf.c

    r38ff846 r8b8def58  
    6363        conf->ping_timeout = 300;
    6464        conf->user = NULL;
     65        conf->ft_max_size = SIZE_MAX;
     66        conf->ft_max_kbps = G_MAXUINT;
     67        conf->ft_listen = NULL;
    6568        conf->protocols = NULL;
    6669        proxytype = 0;
     
    315318                                conf->user = g_strdup( ini->value );
    316319                        }
     320                        else if( g_strcasecmp( ini->key, "ft_max_size" ) == 0 )
     321                        {
     322                                size_t ft_max_size;
     323                                if( sscanf( ini->value, "%zu", &ft_max_size ) != 1 )
     324                                {
     325                                        fprintf( stderr, "Invalid %s value: %s\n", ini->key, ini->value );
     326                                        return 0;
     327                                }
     328                                conf->ft_max_size = ft_max_size;
     329                        }
     330                        else if( g_strcasecmp( ini->key, "ft_max_kbps" ) == 0 )
     331                        {
     332                                if( sscanf( ini->value, "%d", &i ) != 1 )
     333                                {
     334                                        fprintf( stderr, "Invalid %s value: %s\n", ini->key, ini->value );
     335                                        return 0;
     336                                }
     337                                conf->ft_max_kbps = i;
     338                        }
     339                        else if( g_strcasecmp( ini->key, "ft_listen" ) == 0 )
     340                        {
     341                                g_free( conf->ft_listen );
     342                                conf->ft_listen = g_strdup( ini->value );
     343                        }
    317344                        else if( g_strcasecmp( ini->key, "protocols" ) == 0 )
    318345                        {
     
    349376                if( g_strcasecmp( ini->section, "defaults" ) == 0 )
    350377                {
    351                         set_t *s = set_find( &irc->set, ini->key );
     378                        set_t *s = set_find( &irc->b->set, ini->key );
    352379                       
    353380                        if( s )
  • conf.h

    r38ff846 r8b8def58  
    5050        int ping_timeout;
    5151        char *user;
     52        size_t ft_max_size;
     53        int ft_max_kbps;
     54        char *ft_listen;
    5255        char **protocols;
    5356} conf_t;
  • configure

    r38ff846 r8b8def58  
    2727yahoo=1
    2828twitter=1
     29twitter=1
     30purple=0
    2931
    3032debug=0
     
    6769--oscar=0/1     Disable/enable Oscar part (ICQ, AIM)    $oscar
    6870--yahoo=0/1     Disable/enable Yahoo part               $yahoo
    69 --twitter=0/1 Disable/enable Twitter part               $twitter
     71--twitter=0/1   Disable/enable Twitter part             $twitter
     72
     73--purple=0/1    Disable/enable libpurple support        $purple
    7074
    7175--debug=0/1     Disable/enable debugging                $debug
     
    121125EOF
    122126
     127srcdir="$(dirname $0)"
     128if [ "$srcdir" != "." ]; then
     129        echo
     130        echo "configure script run from a different directory. Will create some symlinks..."
     131        if [ ! -e Makefile -o -L Makefile ]; then
     132                COPYDIRS="doc lib protocols tests utils"
     133                mkdir -p $(cd "$srcdir"; find $COPYDIRS -type d)
     134                find . -name Makefile -type l -print0 | xargs -0 rm 2> /dev/null
     135                dst="$PWD"
     136                cd "$srcdir"
     137                for i in $(find . -name Makefile -type f); do
     138                        ln -s "$PWD${i#.}" "$dst/$i";
     139                done
     140                cd "$dst"
     141                rm -rf .bzr
     142        fi
     143       
     144        echo "SRCDIR=$srcdir/" >> Makefile.settings
     145        CFLAGS="$CFLAGS -I${dst}"
     146else
     147        srcdir=$PWD
     148fi
     149
    123150cat<<EOF>config.h
    124151/* BitlBee settings, generated by configure
     
    158185
    159186echo CFLAGS=$CFLAGS >> Makefile.settings
    160 echo CFLAGS+=-I`pwd` -I`pwd`/lib -I`pwd`/protocols -I. >> Makefile.settings
     187echo CFLAGS+=-I${srcdir} -I${srcdir}/lib -I${srcdir}/protocols -I. >> Makefile.settings
    161188
    162189echo CFLAGS+=-DHAVE_CONFIG_H >> Makefile.settings
     
    398425fi
    399426
    400 STORAGES="text xml"
     427STORAGES="xml"
    401428
    402429if [ "$ldap" = "auto" ]; then
     
    508535protoobjs=''
    509536
     537if [ "$purple" = 0 ]; then
     538        echo '#undef WITH_PURPLE' >> config.h
     539else
     540        if ! $PKG_CONFIG purple; then
     541                echo
     542                echo 'Cannot find libpurple development libraries, aborting. (Install libpurple-dev?)'
     543                exit 1
     544        fi
     545        echo '#define WITH_PURPLE' >> config.h
     546        cat<<EOF>>Makefile.settings
     547EFLAGS += $($PKG_CONFIG purple --libs)
     548PURPLE_CFLAGS += $($PKG_CONFIG purple --cflags)
     549EOF
     550        protocols=$protocols'purple '
     551        protoobjs=$protoobjs'purple_mod.o '
     552
     553        # Having both libpurple and native IM modules in one binary may
     554        # do strange things. Let's not do that.
     555        msn=0
     556        jabber=0
     557        oscar=0
     558        yahoo=0
     559        twitter=0
     560       
     561        if [ "$events" = "libevent" ]; then
     562                echo
     563                echo 'Warning: Some libpurple modules (including msn-pecan) do their event handling'
     564                echo 'outside libpurple, talking to GLib directly. At least for now the combination'
     565                echo 'libpurple + libevent is *not* recommended!'
     566        fi
     567fi
     568
    510569if [ "$msn" = 0 ]; then
    511570        echo '#undef WITH_MSN' >> config.h
  • debian/bitlbee.init

    • Property mode changed from 100755 to 100644
  • debian/changelog

    r38ff846 r8b8def58  
     1bitlbee (1.3-0) unstable; urgency=low
     2
     3  * Setting some bogus version number, fix that later.
     4  * Now using debhelper to improve maintainability.
     5  * Added a bitlbee-libpurple package, and split off docs and stuff into
     6    bitlbee-common.
     7
     8 -- Wilmer van der Gaast <wilmer@gaast.net>  Sat, 05 Jun 2010 15:16:38 +0100
     9
    110bitlbee (1.2.7-1) unstable; urgency=high
    211
  • debian/control

    r38ff846 r8b8def58  
    44Maintainer: Wilmer van der Gaast <wilmer@gaast.net>
    55Uploaders: Jelmer Vernooij <jelmer@samba.org>
    6 Standards-Version: 3.8.0
    7 Build-Depends: libglib2.0-dev (>= 2.4), libevent-dev, libgnutls-dev | libnss-dev (>= 1.6), debconf-2.0, po-debconf
     6Standards-Version: 3.8.4
     7Build-Depends: libglib2.0-dev (>= 2.4), libevent-dev, libgnutls-dev | libnss-dev (>= 1.6), po-debconf, libpurple-dev, debhelper (>= 6)
    88Homepage: http://www.bitlbee.org/
    99Vcs-Bzr: http://code.bitlbee.org/bitlbee/
     
    1212Package: bitlbee
    1313Architecture: any
    14 Depends: ${shlibs:Depends}, adduser, net-tools, ${debconf-depends}, debianutils (>= 1.16)
    15 Description: An IRC to other chat networks gateway
     14Depends: ${shlibs:Depends}, adduser, debianutils (>= 1.16), bitlbee-common (= ${bee:Version})
     15Conflicts: bitlbee-libpurple
     16Replaces: bitlbee-libpurple
     17Description: An IRC to other chat networks gateway (default version)
    1618 This program can be used as an IRC server which forwards everything you
    1719 say to people on other chat networks: Jabber, ICQ, AIM, MSN, Yahoo! and
    1820 Twitter.
    1921
     22Package: bitlbee-libpurple
     23Architecture: any
     24Depends: ${shlibs:Depends}, adduser, debianutils (>= 1.16), bitlbee-common (= ${bee:Version})
     25Conflicts: bitlbee
     26Replaces: bitlbee
     27Description: An IRC to other chat networks gateway (using libpurple)
     28 This program can be used as an IRC server which forwards everything you
     29 say to people on other chat networks: Jabber, ICQ, AIM, MSN, Yahoo! and
     30 Twitter.
     31 .
     32 This package contains a version of BitlBee that uses the libpurple instant
     33 messaging library instead of built-in code, which adds support for more IM
     34 protocols (all protocols supported by Pidgin/Finch) and features (like file
     35 transfers), at the price of being less lightweight.
     36 .
     37 This variant may not be very suitable for BitlBee instances used by many
     38 (tens or hundreds) of clients.
     39
     40Package: bitlbee-common
     41Architecture: all
     42Depends: ${misc:Depends}, net-tools
     43Replaces: bitlbee
     44Description: An IRC to other chat networks gateway (common files/docs)
     45 This program can be used as an IRC server which forwards everything you
     46 say to people on other chat networks: Jabber, ICQ, AIM, MSN, Yahoo! and
     47 Twitter.
     48 .
     49 This package contains common files (mostly documentation) for bitlbee and
     50 bitlbee-libpurple.
     51
    2052Package: bitlbee-dev
    2153Architecture: all
    22 Depends: bitlbee (>= ${source:Version}), bitlbee (<< ${source:Version}.1~)
    23 Description: An IRC to other chat networks gateway
     54Depends: ${misc:Depends}, bitlbee (>= ${bee:Version}), bitlbee (<< ${bee:Version}.1~)
     55Description: An IRC to other chat networks gateway (dev files)
    2456 This program can be used as an IRC server which forwards everything you
    2557 say to people on other chat networks: Jabber, ICQ, AIM, MSN, Yahoo! and
  • debian/patches/bitlbee.conf.diff

    r38ff846 r8b8def58  
    1 --- debian/bitlbee/etc/bitlbee/bitlbee.conf     2009-06-01 00:20:24.000000000 +0100
    2 +++ debian/bitlbee/etc/bitlbee/bitlbee.conf     2009-06-07 21:16:19.000000000 +0100
     1--- bitlbee.conf        2009-06-01 00:20:24.000000000 +0100
     2+++ bitlbee.conf        2009-06-07 21:16:19.000000000 +0100
    33@@ -23,13 +23,18 @@
    44 ## If BitlBee is started by root as a daemon, it can drop root privileges,
  • debian/po/POTFILES.in

    r38ff846 r8b8def58  
    1 [type: gettext/rfc822deb] templates
     1[type: gettext/rfc822deb] bitlbee-common.templates
  • debian/rules

    r38ff846 r8b8def58  
    11#!/usr/bin/make -f
     2#
     3# Finally switching to debhelper.
     4#
     5# Not using debhelper was an exercise suggested to me by my AM (Gergely
     6# Nagy). It was educating at the time but I finally decided that the
     7# exercise is over now.
     8#
    29
     10BITLBEE_CONFIGURE_FLAGS ?=
    311DEBUG ?= 0
    412
    5 ifdef BITLBEE_VERSION
    6 BITLBEE_FORCE_VERSION=1
    7 else
     13ifndef BITLBEE_VERSION
    814# Want to use the full package version number instead of just the release.
    9 BITLBEE_VERSION ?= "$(shell dpkg-parsechangelog | grep ^Version: | awk '{print $$2}')"
    10 export BITLBEE_VERSION
     15BITLBEE_CONFIGURE_VERSION ?= BITLBEE_VERSION=\"$(shell dpkg-parsechangelog | grep ^Version: | awk '{print $$2}')\"
    1116endif
    1217
    13 build-arch: build-arch-stamp
    14 build-arch-stamp:
    15         [ -d debian ]
    16         ./configure --debug=$(DEBUG) --prefix=/usr --etcdir=/etc/bitlbee --events=libevent
    17         $(MAKE)
    18 #       $(MAKE) -C doc/ all
    19         touch build-arch-stamp
     18build: build-stamp
     19build-stamp:
     20        dh_testdir
     21
     22        mkdir -p debian/build-native
     23        ROOT=$$PWD; cd debian/build-native; $(BITLBEE_CONFIGURE_VERSION) $$ROOT/configure --debug=$(DEBUG) --prefix=/usr --etcdir=/etc/bitlbee --events=libevent $(BITLBEE_CONFIGURE_FLAGS)
     24        $(MAKE) -C debian/build-native
     25
     26        mkdir -p debian/build-libpurple
     27        ROOT=$$PWD; cd debian/build-libpurple; $(BITLBEE_CONFIGURE_VERSION) $$ROOT/configure --debug=$(DEBUG) --prefix=/usr --etcdir=/etc/bitlbee --purple=1 $(BITLBEE_CONFIGURE_FLAGS)
     28        $(MAKE) -C debian/build-libpurple
     29
     30        $(MAKE) -C doc
     31
     32        touch build-stamp
    2033
    2134clean:
    22         [ "`whoami`" = "root" -a -d debian ]
    23         rm -rf build-arch-stamp debian/bitlbee debian/*.substvars debian/files debian/bitlbee-dev
     35        dh_testdir
     36        dh_testroot
     37        rm -f build-stamp
     38
     39        rm -rf build-arch-stamp debian/build-*
    2440        $(MAKE) distclean
    25 #       -$(MAKE) -C doc/ clean
    26                                
    2741
    28 install-arch: build-arch
    29         [ "`whoami`" = "root" -a -d debian ]
    30         mkdir -p debian/bitlbee/DEBIAN/
    31         $(MAKE) install install-etc DESTDIR=`pwd`/debian/bitlbee
     42        dh_clean
    3243
    33         mkdir -p debian/bitlbee/usr/share/doc/bitlbee/
    34         cp doc/user-guide/user-guide.txt debian/bitlbee/usr/share/doc/bitlbee/
    35         cp doc/user-guide/user-guide.html debian/bitlbee/usr/share/doc/bitlbee/
     44install: build
     45        dh_testdir
     46        dh_testroot
     47        dh_clean -k
     48        dh_installdirs
    3649
    37 install-indep: install-arch
    38         [ "`whoami`" = "root" -a -d debian ]
    39         mkdir -p debian/bitlbee-dev/DEBIAN/
    40         $(MAKE) install-dev DESTDIR=`pwd`/debian/bitlbee-dev
     50        $(MAKE) -C debian/build-native install install-etc DESTDIR=`pwd`/debian/bitlbee
     51        $(MAKE) -C debian/build-libpurple install install-etc DESTDIR=`pwd`/debian/bitlbee-libpurple
     52        $(MAKE) -C debian/build-native install-dev DESTDIR=`pwd`/debian/bitlbee-dev
    4153
    42         mkdir -p debian/bitlbee-dev/usr/share/doc/bitlbee-dev/
     54        patch debian/bitlbee/etc/bitlbee/bitlbee.conf debian/patches/bitlbee.conf.diff
     55        patch debian/bitlbee-libpurple/etc/bitlbee/bitlbee.conf debian/patches/bitlbee.conf.diff
    4356
    44 binary-arch: build-arch install-arch
    45         [ "`whoami`" = "root" -a -d debian ]
     57        mkdir -p debian/bitlbee-common/usr
     58        mv debian/bitlbee/usr/share debian/bitlbee-common/usr
     59        rm -rf debian/bitlbee-libpurple/usr/share
    4660
    47         chmod 755 debian/post* debian/pre* debian/config debian/bitlbee.init
     61binary-common:
     62        dh_testdir
     63        dh_testroot
    4864
    49         mkdir -p debian/bitlbee/usr/share/doc/bitlbee/examples/ debian/bitlbee/etc/init.d/
    50         -cp doc/RELEASE-SPEECH* debian/bitlbee/usr/share/doc/bitlbee/ && gzip -9 debian/bitlbee/usr/share/doc/bitlbee/RELEASE-SPEECH*
    51         cp doc/CREDITS doc/AUTHORS doc/README doc/FAQ debian/README.Debian debian/bitlbee/usr/share/doc/bitlbee/
    52         cp debian/changelog debian/bitlbee/usr/share/doc/bitlbee/changelog.Debian
    53         cp debian/copyright debian/bitlbee/usr/share/doc/bitlbee/copyright
    54         cp doc/CHANGES debian/bitlbee/usr/share/doc/bitlbee/changelog
    55         cp utils/* debian/bitlbee/usr/share/doc/bitlbee/examples/
    56         cp debian/bitlbee.init debian/bitlbee/etc/init.d/bitlbee
    57         patch -p0 < debian/patches/bitlbee.conf.diff
    58         cd debian/bitlbee/usr/share/; \
    59                 gzip -9 doc/bitlbee/changelog.Debian doc/bitlbee/changelog doc/bitlbee/user-guide.txt \
    60                         doc/bitlbee/examples/* man/man8/bitlbee.8 man/man5/bitlbee.conf.5
    61        
    62         chown -R root:root debian/bitlbee/
    63         find debian/bitlbee/usr/share/ -type d -exec chmod 755 {} \;
    64         find debian/bitlbee/usr/share/ -type f -exec chmod 644 {} \;
    65        
    66         cp debian/prerm debian/bitlbee/DEBIAN/
    67         cp debian/postinst debian/bitlbee/DEBIAN/
    68         cp debian/postrm debian/bitlbee/DEBIAN/
    69         cp debian/config debian/bitlbee/DEBIAN/
     65        dh_installchangelogs doc/CHANGES
     66        dh_installexamples
     67        dh_installdocs #--link-doc=bitlbee-common
     68        # TODO: Restore --link-doc up here and remove the hack below once
     69        # Hardy and Lenny are deprecated.
     70        for p in bitlbee bitlbee-libpurple bitlbee-dev; do rm -rf debian/$$p/usr/share/doc/$$p; ln -s bitlbee-common debian/$$p/usr/share/doc/$$p; done
     71        dh_installdebconf
     72        dh_installinit
     73ifeq ($(DH_OPTIONS),-a)
     74        cp -a debian/bitlbee/etc debian/bitlbee-libpurple
     75endif
     76        dh_installman
     77        dh_strip
     78        dh_link
     79        dh_compress
     80        dh_fixperms
     81        dh_installdeb
     82ifeq ($(DH_OPTIONS),-a)
     83        cp -a debian/bitlbee/DEBIAN/post* debian/bitlbee/DEBIAN/pre* debian/bitlbee-libpurple/DEBIAN
     84endif
     85        dh_shlibdeps
     86ifdef BITLBEE_VERSION
     87        dh_gencontrol -- -v1:$(BITLBEE_VERSION)-0  -Vbee:Version=1:$(BITLBEE_VERSION)-0
     88else
     89        dh_gencontrol -- -Vbee:Version=$(shell dpkg-parsechangelog | grep ^Version: | awk '{print $$2}' | sed -e 's/+[^+]*$$//')
     90endif
     91        dh_md5sums
     92        dh_builddeb
    7093
    71         po2debconf debian/templates > debian/bitlbee/DEBIAN/templates
    72         cp debian/conffiles debian/bitlbee/DEBIAN/
    73        
    74         if [ "$(DEBUG)" = "0" ]; then strip -R .comment -R .note debian/bitlbee/usr/sbin/bitlbee; fi
     94binary-indep: build install
     95        $(MAKE) -f debian/rules DH_OPTIONS=-i binary-common
    7596
    76         cd debian/bitlbee; \
    77                 find usr -type f -exec md5sum {} \; > DEBIAN/md5sums
    78         dpkg-shlibdeps -Tdebian/bitlbee.substvars -dDepends debian/bitlbee/usr/sbin/bitlbee
    79 ifdef BITLBEE_FORCE_VERSION
    80         dpkg-gencontrol -ldebian/changelog -isp -pbitlbee -Tdebian/bitlbee.substvars -Pdebian/bitlbee -v1:$(BITLBEE_VERSION)-0 -V'debconf-depends=debconf (>= 1.2.0) | debconf-2.0'
    81 else
    82         dpkg-gencontrol -ldebian/changelog -isp -pbitlbee -Tdebian/bitlbee.substvars -Pdebian/bitlbee -V'debconf-depends=debconf (>= 1.2.0) | debconf-2.0'
    83 endif
     97binary-arch: build install
     98        $(MAKE) -f debian/rules DH_OPTIONS=-a binary-common
    8499
    85         dpkg --build debian/bitlbee ..
     100binary-%: build install
     101        make -f debian/rules binary-common DH_OPTIONS=-p$*
    86102
    87 binary-indep: install-indep
    88         [ "`whoami`" = "root" -a -d debian ]
    89 
    90         chown -R root.root debian/bitlbee-dev/
    91         find debian/bitlbee-dev/usr/share/ -type d -exec chmod 755 {} \;
    92         find debian/bitlbee-dev/usr/share/ -type f -exec chmod 644 {} \;
    93 
    94         cp debian/changelog debian/bitlbee-dev/usr/share/doc/bitlbee-dev/changelog.Debian
    95         gzip -9 debian/bitlbee-dev/usr/share/doc/bitlbee-dev/changelog.Debian
    96         cp debian/copyright debian/bitlbee-dev/usr/share/doc/bitlbee-dev/copyright
    97 
    98         cd debian/bitlbee-dev; \
    99                 find usr -type f -exec md5sum {} \; > DEBIAN/md5sums
    100 
    101 ifdef BITLBEE_FORCE_VERSION
    102         dpkg-gencontrol -ldebian/changelog -isp -pbitlbee-dev -Pdebian/bitlbee-dev -v1:$(BITLBEE_VERSION)-0
    103 else
    104         dpkg-gencontrol -ldebian/changelog -isp -pbitlbee-dev -Pdebian/bitlbee-dev
    105 endif
    106 
    107         dpkg --build debian/bitlbee-dev ..
    108 
    109 binary: binary-arch binary-indep
    110 build: build-arch
    111 install: install-arch install-indep
    112 
    113 .PHONY: build-arch build clean binary-arch binary install-arch install binary-indep install-indep
     103binary: binary-indep binary-arch
     104.PHONY: build clean binary-indep binary-arch binary-common binary install
  • doc/Makefile

    r38ff846 r8b8def58  
    11-include ../Makefile.settings
     2ifdef SRCDIR
     3SRCDIR := $(SRCDIR)doc/
     4endif
    25
    36all:
     
    710install:
    811        mkdir -p $(DESTDIR)$(MANDIR)/man8/ $(DESTDIR)$(MANDIR)/man5/
    9         install -m 0644 bitlbee.8 $(DESTDIR)$(MANDIR)/man8/
    10         install -m 0644 bitlbee.conf.5 $(DESTDIR)$(MANDIR)/man5/
     12        install -m 0644 $(SRCDIR)bitlbee.8 $(DESTDIR)$(MANDIR)/man8/
     13        install -m 0644 $(SRCDIR)bitlbee.conf.5 $(DESTDIR)$(MANDIR)/man5/
    1114        $(MAKE) -C user-guide $@
    1215
  • doc/user-guide/Makefile

    r38ff846 r8b8def58  
    11-include ../../Makefile.settings
     2ifdef SRCDIR
     3SRCDIR := $(SRCDIR)doc/user-guide/
     4endif
     5
    26EXTRAPARANEWLINE = 1
    37# EXTRAPARANEWLINE = 0
     
    3842        chmod 0755 $(DESTDIR)$(DATADIR)
    3943        rm -f $(DESTDIR)$(DATADIR)/help.txt # Prevent help function from breaking in running sessions
    40         install -m 0644 help.txt $(DESTDIR)$(DATADIR)/help.txt
     44        install -m 0644 $(SRCDIR)help.txt $(DESTDIR)$(DATADIR)/help.txt
    4145
    4246uninstall:
  • doc/user-guide/commands.xml

    r38ff846 r8b8def58  
    484484        </bitlbee-setting>
    485485
    486         <bitlbee-setting name="buddy_sendbuffer" type="boolean" scope="global">
    487                 <default>false</default>
    488 
    489                 <description>
    490                         <para>
    491                                 By default, when you send a message to someone, BitlBee forwards this message to the user immediately. When you paste a large number of lines, the lines will be sent in separate messages, which might not be very nice to read. If you enable this setting, BitlBee will buffer your messages and wait for more data.
    492                         </para>
    493 
    494                         <para>
    495                                 Using the <emphasis>buddy_sendbuffer_delay</emphasis> setting you can specify the number of seconds BitlBee should wait for more data before the complete message is sent.
    496                         </para>
    497 
    498                         <para>
    499                                 Please note that if you remove a buddy from your list (or if the connection to that user drops) and there's still data in the buffer, this data will be lost. BitlBee will not try to send the message to the user in those cases.
    500                         </para>
    501                 </description>
    502         </bitlbee-setting>
    503 
    504         <bitlbee-setting name="buddy_sendbuffer_delay" type="integer" scope="global">
    505                 <default>200</default>
    506 
    507                 <description>
    508 
    509                         <para>
    510                                 Tell BitlBee after how many (mili)seconds a buffered message should be sent. Values greater than 5 will be interpreted as miliseconds, 5 and lower as seconds.
    511                         </para>
    512 
    513                         <para>
    514                                 See also the <emphasis>buddy_sendbuffer</emphasis> setting.
     486        <bitlbee-setting name="away_reply_timeout" type="integer" scope="global">
     487                <default>3600</default>
     488
     489                <description>
     490                        <para>
     491                                Most IRC servers send a user's away message every time s/he gets a private message, to inform the sender that they may not get a response immediately. With this setting set to 0, BitlBee will also behave like this.
     492                        </para>
     493
     494                        <para>
     495                                Since not all IRC clients do an excellent job at suppressing these messages, this setting lets BitlBee do it instead. BitlBee will wait this many seconds (or until the away state/message changes) before re-informing you that the person's away.
    515496                        </para>
    516497                </description>
     
    593574
    594575        <bitlbee-setting name="handle_unknown" type="string" scope="global">
    595                 <default>root</default>
     576                <default>add_channel</default>
    596577                <possible-values>root, add, add_private, add_channel, ignore</possible-values>
    597578
     
    771752                </description>
    772753        </bitlbee-setting>
     754
     755        <bitlbee-setting name="paste_buffer" type="boolean" scope="global">
     756                <default>false</default>
     757
     758                <description>
     759                        <para>
     760                                By default, when you send a message to someone, BitlBee forwards this message to the user immediately. When you paste a large number of lines, the lines will be sent in separate messages, which might not be very nice to read. If you enable this setting, BitlBee will buffer your messages and wait for more data.
     761                        </para>
     762
     763                        <para>
     764                                Using the <emphasis>paste_buffer_delay</emphasis> setting you can specify the number of seconds BitlBee should wait for more data before the complete message is sent.
     765                        </para>
     766
     767                        <para>
     768                                Please note that if you remove a buddy from your list (or if the connection to that user drops) and there's still data in the buffer, this data will be lost. BitlBee will not try to send the message to the user in those cases.
     769                        </para>
     770                </description>
     771        </bitlbee-setting>
     772
     773        <bitlbee-setting name="paste_buffer_delay" type="integer" scope="global">
     774                <default>200</default>
     775
     776                <description>
     777
     778                        <para>
     779                                Tell BitlBee after how many (mili)seconds a buffered message should be sent. Values greater than 5 will be interpreted as miliseconds, 5 and lower as seconds.
     780                        </para>
     781
     782                        <para>
     783                                See also the <emphasis>paste_buffer</emphasis> setting.
     784                        </para>
     785                </description>
     786        </bitlbee-setting>
    773787       
    774788        <bitlbee-setting name="port" type="integer" scope="account">
     
    11281142
    11291143        <bitlbee-command name="identify">
    1130                 <syntax>identify &lt;password&gt;</syntax>
     1144                <syntax>identify [-noload|-force] &lt;password&gt;</syntax>
    11311145                <short-description>Identify yourself with your password</short-description>
    11321146
     
    11381152                        <para>
    11391153                                Once you're registered, you can change your password using <emphasis>set password &lt;password&gt;</emphasis>.
     1154                        </para>
     1155
     1156                        <para>
     1157                                The <emphasis>-noload</emphasis> and <emphasis>-force</emphasis> flags can be used to identify when you're logged into some IM accounts already. <emphasis>-force</emphasis> will let you identify yourself and load all saved accounts (and keep the accounts you're logged into already).
     1158                        </para>
     1159                       
     1160                        <para>
     1161                                <emphasis>-noload</emphasis> will log you in but not load any accounts and settings saved under your current nickname. These will be overwritten once you save your settings (i.e. when you disconnect).
    11401162                        </para>
    11411163                </description>
     
    11821204
    11831205        </bitlbee-command>
     1206       
     1207        <bitlbee-command name="transfers">
     1208                <short-description>Monitor, cancel, or reject file transfers</short-description>
     1209                <syntax>transfers [&lt;cancel&gt; id | &lt;reject&gt;]</syntax>
     1210               
     1211                <description>
     1212                        <para>
     1213                                Without parameters the currently pending file transfers and their status will be listed. Available actions are <emphasis>cancel</emphasis> and <emphasis>reject</emphasis>. See <emphasis>help transfers &lt;action&gt;</emphasis> for more information.
     1214                        </para>
     1215
     1216                        <ircexample>
     1217                                <ircline nick="ulim">transfers</ircline>
     1218                        </ircexample>
     1219                </description>
     1220               
     1221                <bitlbee-command name="cancel">
     1222                        <short-description>Cancels the file transfer with the given id</short-description>
     1223                        <syntax>transfers &lt;cancel&gt; id</syntax>
     1224
     1225                        <description>
     1226                                <para>Cancels the file transfer with the given id</para>
     1227                        </description>
     1228
     1229                        <ircexample>
     1230                                <ircline nick="ulim">transfers cancel 1</ircline>
     1231                                <ircline nick="root">Canceling file transfer for test</ircline>
     1232                        </ircexample>
     1233                </bitlbee-command>
     1234
     1235                <bitlbee-command name="reject">
     1236                        <short-description>Rejects all incoming transfers</short-description>
     1237                        <syntax>transfers &lt;reject&gt;</syntax>
     1238
     1239                        <description>
     1240                                <para>Rejects all incoming (not already transferring) file transfers. Since you probably have only one incoming transfer at a time, no id is neccessary. Or is it?</para>
     1241                        </description>
     1242
     1243                        <ircexample>
     1244                                <ircline nick="ulim">transfers reject</ircline>
     1245                        </ircexample>
     1246                </bitlbee-command>
     1247        </bitlbee-command>
     1248       
    11841249</chapter>
  • doc/user-guide/help.xml

    r38ff846 r8b8def58  
    1414  <varlistentry><term>quickstart</term><listitem><para>A short introduction into BitlBee</para></listitem></varlistentry>
    1515  <varlistentry><term>commands</term><listitem><para>All available commands and settings</para></listitem></varlistentry>
     16  <varlistentry><term>channels</term><listitem><para>About creating and customizing channels</para></listitem></varlistentry>
    1617  <varlistentry><term>away</term><listitem><para>About setting away states</para></listitem></varlistentry>
    1718  <varlistentry><term>smileys</term><listitem><para>A summary of some non-standard smileys you might find and fail to understand</para></listitem></varlistentry>
  • doc/user-guide/misc.xml

    r38ff846 r8b8def58  
    117117</sect1>
    118118
     119<sect1 id="nick_changes">
     120<title>Changing your nickname</title>
     121
     122<para>
     123BitlBee now allows you to change your nickname. So far this was not possible because it made managing saved accounts more complicated.
     124</para>
     125
     126<para>
     127The restriction no longer exists now though. When you change your nick (just using the <emphasis>/nick</emphasis> command), your logged-in status will be reset, which means any changes made to your settings/accounts will not be saved.
     128</para>
     129
     130<para>
     131To restore your logged-in status, you need to either use the <emphasis>register</emphasis> command to create an account under the new nickname, or use <emphasis>identify -noload</emphasis> to re-identify yourself under the new nickname. The <emphasis>-noload</emphasis> flag tells the command to verify your password and log you in, but not load any new settings. See <emphasis>help identify</emphasis> for more information.
     132</para>
     133
     134</sect1>
     135
     136<sect1 id="channels">
     137<title>Dealing with channels</title>
     138
     139<para>
     140You can have as many channels in BitlBee as you want. You maintain your channel list using the <emphasis>channel</emphasis> command. You can create new channels by just joining them, like on regular IRC networks.
     141</para>
     142
     143<para>
     144You can create two kinds of channels. Control channels, and groupchat channels. By default, BitlBee will set up new channels as control channels if their name starts with an &amp;, and as chat channels if it starts with a #.
     145</para>
     146
     147<para>
     148Control channels are where you see your contacts. By default, you will have one control channel called &amp;bitlbee, containing all your contacts. But you can create more, if you want, and divide your contact list accross several channels.
     149</para>
     150
     151<para>
     152For example, you can have one channel with all contacts from your MSN Messenger account in it. Or all contacts from the group called "Work".
     153</para>
     154
     155<para>
     156Type <emphasis>help channels2</emphasis> to read more.
     157</para>
     158
     159</sect1>
     160
     161<sect1 id="channels2">
     162<title>Creating a channel</title>
     163
     164<para>
     165When you create a new channel, BitlBee will try to guess from its name which contacts to fill it with. For example, if the channel name (excluding the &amp;) matches the name of a group in which you have one or more contacts, the channel will contain all those contacts.
     166</para>
     167
     168<para>
     169Any valid account ID (so a number, protocol name or part of screenname, as long as it's unique) can also be used as a channel name. So if you just join &amp;msn, it will contain all your MSN contacts (as long as you have only one MSN account set up). And if you have a Facebook account set up, you can see its contacts by just joining &amp;facebook.
     170</para>
     171
     172<para>
     173To start a simple group chat, you simply join a channel which a name starting with #, and invite people into it. All people you invite have to be on the same IM network and contact list.
     174</para>
     175
     176<para>
     177If you want to configure your own channels, you can use the <emphasis>channel set</emphasis>.
     178</para>
     179
     180</sect1>
     181
    119182</chapter>
  • help.c

    r38ff846 r8b8def58  
    22  * BitlBee -- An IRC to other IM-networks gateway                     *
    33  *                                                                    *
    4   * Copyright 2002-2005 Wilmer van der Gaast and others                *
     4  * Copyright 2002-2009 Wilmer van der Gaast and others                *
    55  \********************************************************************/
    66
     
    169169        return NULL;
    170170}
     171
     172int help_add_mem( help_t **help, const char *title, const char *content )
     173{
     174        help_t *h, *l = NULL;
     175       
     176        for( h = *help; h; h = h->next )
     177        {
     178                if( g_strcasecmp( h->title, title ) == 0 )
     179                        return 0;
     180               
     181                l = h;
     182        }
     183       
     184        if( l )
     185                h = l->next = g_new0( struct help, 1 );
     186        else
     187                *help = h = g_new0( struct help, 1 );
     188        h->fd = -1;
     189        h->title = g_strdup( title );
     190        h->length = strlen( content );
     191        h->offset.mem_offset = g_strdup( content );
     192       
     193        return 1;
     194}
  • help.h

    r38ff846 r8b8def58  
    4646void help_free( help_t **help );
    4747char *help_get( help_t **help, char *title );
     48int help_add_mem( help_t **help, const char *title, const char *content_ );
    4849
    4950#endif
  • ipc.c

    r38ff846 r8b8def58  
    138138       
    139139        if( strchr( irc->umode, 'w' ) )
    140                 irc_write( irc, ":%s WALLOPS :%s", irc->myhost, cmd[1] );
     140                irc_write( irc, ":%s WALLOPS :%s", irc->root->host, cmd[1] );
    141141}
    142142
     
    147147       
    148148        if( strchr( irc->umode, 's' ) )
    149                 irc_write( irc, ":%s NOTICE %s :%s", irc->myhost, irc->nick, cmd[1] );
     149                irc_write( irc, ":%s NOTICE %s :%s", irc->root->host, irc->user->nick, cmd[1] );
    150150}
    151151
     
    156156       
    157157        if( strchr( irc->umode, 'o' ) )
    158                 irc_write( irc, ":%s NOTICE %s :*** OperMsg *** %s", irc->myhost, irc->nick, cmd[1] );
     158                irc_write( irc, ":%s NOTICE %s :*** OperMsg *** %s", irc->root->host, irc->user->nick, cmd[1] );
    159159}
    160160
     
    176176                return;
    177177       
    178         if( nick_cmp( cmd[1], irc->nick ) != 0 )
     178        if( nick_cmp( cmd[1], irc->user->nick ) != 0 )
    179179                return;         /* It's not for us. */
    180180       
    181         irc_write( irc, ":%s!%s@%s KILL %s :%s", irc->mynick, irc->mynick, irc->myhost, irc->nick, cmd[2] );
     181        irc_write( irc, ":%s!%s@%s KILL %s :%s", irc->root->nick, irc->root->nick, irc->root->host, irc->user->nick, cmd[2] );
    182182        irc_abort( irc, 0, "Killed by operator: %s", cmd[2] );
    183183}
     
    188188                ipc_to_master_str( "HELLO\r\n" );
    189189        else
    190                 ipc_to_master_str( "HELLO %s %s :%s\r\n", irc->host, irc->nick, irc->realname );
     190                ipc_to_master_str( "HELLO %s %s :%s\r\n", irc->user->host, irc->user->nick, irc->user->fullname );
    191191}
    192192
     
    514514        }
    515515               
    516         child->ipc_inpa = b_input_add( child->ipc_fd, GAIM_INPUT_READ, ipc_master_read, child );
     516        child->ipc_inpa = b_input_add( child->ipc_fd, B_EV_IO_READ, ipc_master_read, child );
    517517       
    518518        child_list = g_slist_append( child_list, child );
     
    552552        }
    553553       
    554         b_input_add( serversock, GAIM_INPUT_READ, new_ipc_client, NULL );
     554        b_input_add( serversock, B_EV_IO_READ, new_ipc_client, NULL );
    555555       
    556556        return 1;
     
    597597                        return 0;
    598598                }
    599                 child->ipc_inpa = b_input_add( child->ipc_fd, GAIM_INPUT_READ, ipc_master_read, child );
     599                child->ipc_inpa = b_input_add( child->ipc_fd, B_EV_IO_READ, ipc_master_read, child );
    600600               
    601601                child_list = g_slist_append( child_list, child );
  • irc.c

    r38ff846 r8b8def58  
    55  \********************************************************************/
    66
    7 /* The big hairy IRCd part of the project                               */
     7/* The IRC-based UI (for now the only one)                              */
    88
    99/*
     
    2424*/
    2525
    26 #define BITLBEE_CORE
    2726#include "bitlbee.h"
    28 #include "sock.h"
    29 #include "crypting.h"
    3027#include "ipc.h"
    31 
    32 static gboolean irc_userping( gpointer _irc, int fd, b_input_condition cond );
    33 
    34 GSList *irc_connection_list = NULL;
    35 
    36 static char *set_eval_password( set_t *set, char *value )
    37 {
    38         irc_t *irc = set->data;
    39        
    40         if( irc->status & USTATUS_IDENTIFIED && value )
    41         {
    42                 irc_setpass( irc, value );
    43                 return NULL;
    44         }
    45         else
    46         {
    47                 return SET_INVALID;
    48         }
    49 }
    50 
    51 static char *set_eval_charset( set_t *set, char *value )
    52 {
    53         irc_t *irc = set->data;
    54         char *test;
    55         gsize test_bytes = 0;
    56         GIConv ic, oc;
    57 
    58         if( g_strcasecmp( value, "none" ) == 0 )
    59                 value = g_strdup( "utf-8" );
    60 
    61         if( ( oc = g_iconv_open( value, "utf-8" ) ) == (GIConv) -1 )
    62         {
    63                 return NULL;
    64         }
    65        
    66         /* Do a test iconv to see if the user picked an IRC-compatible
    67            charset (for example utf-16 goes *horribly* wrong). */
    68         if( ( test = g_convert_with_iconv( " ", 1, oc, NULL, &test_bytes, NULL ) ) == NULL ||
    69             test_bytes > 1 )
    70         {
    71                 g_free( test );
    72                 g_iconv_close( oc );
    73                 irc_usermsg( irc, "Unsupported character set: The IRC protocol "
    74                                   "only supports 8-bit character sets." );
    75                 return NULL;
    76         }
    77         g_free( test );
    78        
    79         if( ( ic = g_iconv_open( "utf-8", value ) ) == (GIConv) -1 )
    80         {
    81                 g_iconv_close( oc );
    82                 return NULL;
    83         }
    84        
    85         if( irc->iconv != (GIConv) -1 )
    86                 g_iconv_close( irc->iconv );
    87         if( irc->oconv != (GIConv) -1 )
    88                 g_iconv_close( irc->oconv );
    89        
    90         irc->iconv = ic;
    91         irc->oconv = oc;
    92 
    93         return value;
    94 }
    95 
    96 static char *set_eval_away_status( set_t *set, char *value )
    97 {
    98         irc_t *irc = set->data;
    99         account_t *a;
    100        
    101         g_free( set->value );
    102         set->value = g_strdup( value );
    103        
    104         for( a = irc->accounts; a; a = a->next )
    105         {
    106                 struct im_connection *ic = a->ic;
    107                
    108                 if( ic && ic->flags & OPT_LOGGED_IN )
    109                         imc_away_send_update( ic );
    110         }
    111        
    112         return value;
    113 }
     28#include "dcc.h"
     29
     30GSList *irc_connection_list;
     31
     32static gboolean irc_userping( gpointer _irc, gint fd, b_input_condition cond );
     33static char *set_eval_charset( set_t *set, char *value );
     34static char *set_eval_password( set_t *set, char *value );
    11435
    11536irc_t *irc_new( int fd )
     
    11839        struct sockaddr_storage sock;
    11940        socklen_t socklen = sizeof( sock );
     41        char *host = NULL, *myhost = NULL;
     42        irc_user_t *iu;
    12043        set_t *s;
     44        bee_t *b;
    12145       
    12246        irc = g_new0( irc_t, 1 );
     
    12549        sock_make_nonblocking( irc->fd );
    12650       
    127         irc->r_watch_source_id = b_input_add( irc->fd, GAIM_INPUT_READ, bitlbee_io_current_client_read, irc );
     51        irc->r_watch_source_id = b_input_add( irc->fd, B_EV_IO_READ, bitlbee_io_current_client_read, irc );
    12852       
    12953        irc->status = USTATUS_OFFLINE;
    13054        irc->last_pong = gettime();
    13155       
    132         irc->userhash = g_hash_table_new( g_str_hash, g_str_equal );
     56        irc->nick_user_hash = g_hash_table_new( g_str_hash, g_str_equal );
    13357        irc->watches = g_hash_table_new( g_str_hash, g_str_equal );
    134        
    135         strcpy( irc->umode, UMODE );
    136         irc->mynick = g_strdup( ROOT_NICK );
    137         irc->channel = g_strdup( ROOT_CHAN );
    13858       
    13959        irc->iconv = (GIConv) -1;
     
    14262        if( global.conf->hostname )
    14363        {
    144                 irc->myhost = g_strdup( global.conf->hostname );
     64                myhost = g_strdup( global.conf->hostname );
    14565        }
    14666        else if( getsockname( irc->fd, (struct sockaddr*) &sock, &socklen ) == 0 )
     
    15171                                 NI_MAXHOST, NULL, 0, 0 ) == 0 )
    15272                {
    153                         irc->myhost = g_strdup( ipv6_unwrap( buf ) );
     73                        myhost = g_strdup( ipv6_unwrap( buf ) );
    15474                }
    15575        }
     
    16282                                 NI_MAXHOST, NULL, 0, 0 ) == 0 )
    16383                {
    164                         irc->host = g_strdup( ipv6_unwrap( buf ) );
    165                 }
    166         }
    167        
    168         if( irc->host == NULL )
    169                 irc->host = g_strdup( "localhost.localdomain" );
    170         if( irc->myhost == NULL )
    171                 irc->myhost = g_strdup( "localhost.localdomain" );
     84                        host = g_strdup( ipv6_unwrap( buf ) );
     85                }
     86        }
     87       
     88        if( host == NULL )
     89                host = g_strdup( "localhost.localdomain" );
     90        if( myhost == NULL )
     91                myhost = g_strdup( "localhost.localdomain" );
    17292       
    17393        if( global.conf->ping_interval > 0 && global.conf->ping_timeout > 0 )
    17494                irc->ping_source_id = b_timeout_add( global.conf->ping_interval * 1000, irc_userping, irc );
    175        
    176         irc_write( irc, ":%s NOTICE AUTH :%s", irc->myhost, "BitlBee-IRCd initialized, please go on" );
    17795
    17896        irc_connection_list = g_slist_append( irc_connection_list, irc );
    17997       
    180         s = set_add( &irc->set, "away", NULL,  set_eval_away_status, irc );
     98        b = irc->b = bee_new();
     99        b->ui_data = irc;
     100        b->ui = &irc_ui_funcs;
     101       
     102        s = set_add( &b->set, "away_devoice", "true", set_eval_away_devoice, irc );
     103        s = set_add( &b->set, "away_reply_timeout", "3600", set_eval_int, irc );
     104        s = set_add( &b->set, "charset", "utf-8", set_eval_charset, irc );
     105        s = set_add( &b->set, "default_target", "root", NULL, irc );
     106        s = set_add( &b->set, "display_namechanges", "false", set_eval_bool, irc );
     107        s = set_add( &b->set, "display_timestamps", "true", set_eval_bool, irc );
     108        s = set_add( &b->set, "handle_unknown", "add_channel", NULL, irc );
     109        s = set_add( &b->set, "lcnicks", "true", set_eval_bool, irc );
     110        s = set_add( &b->set, "ops", "both", set_eval_irc_channel_ops, irc );
     111        s = set_add( &b->set, "paste_buffer", "false", set_eval_bool, irc );
     112        s->old_key = g_strdup( "buddy_sendbuffer" );
     113        s = set_add( &b->set, "paste_buffer_delay", "200", set_eval_int, irc );
     114        s->old_key = g_strdup( "buddy_sendbuffer_delay" );
     115        s = set_add( &b->set, "password", NULL, set_eval_password, irc );
    181116        s->flags |= SET_NULL_OK;
    182         s = set_add( &irc->set, "away_devoice", "true",  set_eval_away_devoice, irc );
    183         s = set_add( &irc->set, "auto_connect", "true", set_eval_bool, irc );
    184         s = set_add( &irc->set, "auto_reconnect", "true", set_eval_bool, irc );
    185         s = set_add( &irc->set, "auto_reconnect_delay", "5*3<900", set_eval_account_reconnect_delay, irc );
    186         s = set_add( &irc->set, "buddy_sendbuffer", "false", set_eval_bool, irc );
    187         s = set_add( &irc->set, "buddy_sendbuffer_delay", "200", set_eval_int, irc );
    188         s = set_add( &irc->set, "charset", "utf-8", set_eval_charset, irc );
    189         s = set_add( &irc->set, "control_channel", irc->channel, set_eval_control_channel, irc );
    190         s = set_add( &irc->set, "debug", "false", set_eval_bool, irc );
    191         s = set_add( &irc->set, "default_target", "root", NULL, irc );
    192         s = set_add( &irc->set, "display_namechanges", "false", set_eval_bool, irc );
    193         s = set_add( &irc->set, "display_timestamps", "true", set_eval_bool, irc );
    194         s = set_add( &irc->set, "handle_unknown", "root", NULL, irc );
    195         s = set_add( &irc->set, "lcnicks", "true", set_eval_bool, irc );
    196         s = set_add( &irc->set, "ops", "both", set_eval_ops, irc );
    197         s = set_add( &irc->set, "password", NULL, set_eval_password, irc );
    198         s->flags |= SET_NULL_OK;
    199         s = set_add( &irc->set, "private", "true", set_eval_bool, irc );
    200         s = set_add( &irc->set, "query_order", "lifo", NULL, irc );
    201         s = set_add( &irc->set, "root_nick", irc->mynick, set_eval_root_nick, irc );
    202         s = set_add( &irc->set, "save_on_quit", "true", set_eval_bool, irc );
    203         s = set_add( &irc->set, "show_offline", "false", set_eval_bool, irc );
    204         s = set_add( &irc->set, "simulate_netsplit", "true", set_eval_bool, irc );
    205         s = set_add( &irc->set, "status", NULL,  set_eval_away_status, irc );
    206         s->flags |= SET_NULL_OK;
    207         s = set_add( &irc->set, "strip_html", "true", NULL, irc );
    208         s = set_add( &irc->set, "timezone", "local", set_eval_timezone, irc );
    209         s = set_add( &irc->set, "to_char", ": ", set_eval_to_char, irc );
    210         s = set_add( &irc->set, "typing_notice", "false", set_eval_bool, irc );
     117        s = set_add( &b->set, "private", "true", set_eval_bool, irc );
     118        s = set_add( &b->set, "query_order", "lifo", NULL, irc );
     119        s = set_add( &b->set, "root_nick", ROOT_NICK, set_eval_root_nick, irc );
     120        s = set_add( &b->set, "simulate_netsplit", "true", set_eval_bool, irc );
     121        s = set_add( &b->set, "timezone", "local", set_eval_timezone, irc );
     122        s = set_add( &b->set, "to_char", ": ", set_eval_to_char, irc );
     123        s = set_add( &b->set, "typing_notice", "false", set_eval_bool, irc );
     124
     125        irc->root = iu = irc_user_new( irc, ROOT_NICK );
     126        iu->host = g_strdup( myhost );
     127        iu->fullname = g_strdup( ROOT_FN );
     128        iu->f = &irc_user_root_funcs;
     129       
     130        iu = irc_user_new( irc, NS_NICK );
     131        iu->host = g_strdup( myhost );
     132        iu->fullname = g_strdup( ROOT_FN );
     133        iu->f = &irc_user_root_funcs;
     134       
     135        irc->user = g_new0( irc_user_t, 1 );
     136        irc->user->host = g_strdup( host );
    211137       
    212138        conf_loaddefaults( irc );
    213139       
    214140        /* Evaluator sets the iconv/oconv structures. */
    215         set_eval_charset( set_find( &irc->set, "charset" ), set_getstr( &irc->set, "charset" ) );
    216        
    217         return( irc );
     141        set_eval_charset( set_find( &b->set, "charset" ), set_getstr( &b->set, "charset" ) );
     142       
     143        irc_write( irc, ":%s NOTICE AUTH :%s", irc->root->host, "BitlBee-IRCd initialized, please go on" );
     144       
     145        g_free( myhost );
     146        g_free( host );
     147       
     148        nogaim_init();
     149       
     150        return irc;
    218151}
    219152
     
    236169               
    237170                ipc_to_master_str( "OPERMSG :Client exiting: %s@%s [%s]\r\n",
    238                                    irc->nick ? irc->nick : "(NONE)", irc->host, reason );
     171                                   irc->user->nick ? irc->user->nick : "(NONE)", irc->user->host, reason );
    239172               
    240173                g_free( reason );
     
    246179               
    247180                ipc_to_master_str( "OPERMSG :Client exiting: %s@%s [%s]\r\n",
    248                                    irc->nick ? irc->nick : "(NONE)", irc->host, "No reason given" );
     181                                   irc->user->nick ? irc->user->nick : "(NONE)", irc->user->host, "No reason given" );
    249182        }
    250183       
     
    267200}
    268201
    269 static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data )
    270 {
    271         g_free( key );
    272        
    273         return( TRUE );
    274 }
    275 
    276 /* Because we have no garbage collection, this is quite annoying */
     202static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data );
     203
    277204void irc_free( irc_t * irc )
    278205{
    279         user_t *user, *usertmp;
    280        
    281206        log_message( LOGLVL_INFO, "Destroying connection with fd %d", irc->fd );
    282207       
    283         if( irc->status & USTATUS_IDENTIFIED && set_getbool( &irc->set, "save_on_quit" ) )
     208        if( irc->status & USTATUS_IDENTIFIED && set_getbool( &irc->b->set, "save_on_quit" ) )
    284209                if( storage_save( irc, NULL, TRUE ) != STORAGE_OK )
    285                         irc_usermsg( irc, "Error while saving settings!" );
     210                        log_message( LOGLVL_WARNING, "Error while saving settings for user %s", irc->user->nick );
    286211       
    287212        irc_connection_list = g_slist_remove( irc_connection_list, irc );
    288        
    289         while( irc->accounts )
    290         {
    291                 if( irc->accounts->ic )
    292                         imc_logout( irc->accounts->ic, FALSE );
    293                 else if( irc->accounts->reconnect )
    294                         cancel_auto_reconnect( irc->accounts );
    295                
    296                 if( irc->accounts->ic == NULL )
    297                         account_del( irc, irc->accounts );
    298                 else
    299                         /* Nasty hack, but account_del() doesn't work in this
    300                            case and we don't want infinite loops, do we? ;-) */
    301                         irc->accounts = irc->accounts->next;
    302         }
    303213       
    304214        while( irc->queries != NULL )
    305215                query_del( irc, irc->queries );
    306216       
    307         while( irc->set )
    308                 set_del( &irc->set, irc->set->key );
    309        
    310         if (irc->users != NULL)
    311         {
    312                 user = irc->users;
    313                 while( user != NULL )
    314                 {
    315                         g_free( user->nick );
    316                         g_free( user->away );
    317                         g_free( user->handle );
    318                         if( user->user != user->nick ) g_free( user->user );
    319                         if( user->host != user->nick ) g_free( user->host );
    320                         if( user->realname != user->nick ) g_free( user->realname );
    321                         b_event_remove( user->sendbuf_timer );
    322                                        
    323                         usertmp = user;
    324                         user = user->next;
    325                         g_free( usertmp );
    326                 }
    327         }
     217        /* This is a little bit messy: bee_free() frees all b->users which
     218           calls us back to free the corresponding irc->users. So do this
     219           before we clear the remaining ones ourselves. */
     220        bee_free( irc->b );
     221       
     222        while( irc->users )
     223                irc_user_free( irc, (irc_user_t *) irc->users->data );
     224       
     225        while( irc->channels )
     226                irc_channel_free( irc->channels->data );
    328227       
    329228        if( irc->ping_source_id > 0 )
     
    337236        irc->fd = -1;
    338237       
    339         g_hash_table_foreach_remove( irc->userhash, irc_free_hashkey, NULL );
    340         g_hash_table_destroy( irc->userhash );
     238        g_hash_table_foreach_remove( irc->nick_user_hash, irc_free_hashkey, NULL );
     239        g_hash_table_destroy( irc->nick_user_hash );
    341240       
    342241        g_hash_table_foreach_remove( irc->watches, irc_free_hashkey, NULL );
     
    350249        g_free( irc->sendbuffer );
    351250        g_free( irc->readbuffer );
    352        
    353         g_free( irc->nick );
    354         g_free( irc->user );
    355         g_free( irc->host );
    356         g_free( irc->realname );
    357251        g_free( irc->password );
    358        
    359         g_free( irc->myhost );
    360         g_free( irc->mynick );
    361        
    362         g_free( irc->channel );
    363        
    364         g_free( irc->last_target );
     252        g_free( irc->last_root_cmd );
    365253       
    366254        g_free( irc );
     
    374262}
    375263
     264static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data )
     265{
     266        g_free( key );
     267       
     268        return( TRUE );
     269}
     270
    376271/* USE WITH CAUTION!
    377272   Sets pass without checking */
    378 void irc_setpass (irc_t *irc, const char *pass) 
     273void irc_setpass (irc_t *irc, const char *pass)
    379274{
    380275        g_free (irc->password);
     
    387282}
    388283
     284static char *set_eval_password( set_t *set, char *value )
     285{
     286        irc_t *irc = set->data;
     287       
     288        if( irc->status & USTATUS_IDENTIFIED && value )
     289        {
     290                irc_setpass( irc, value );
     291                return NULL;
     292        }
     293        else
     294        {
     295                return SET_INVALID;
     296        }
     297}
     298
     299static char **irc_splitlines( char *buffer );
     300
    389301void irc_process( irc_t *irc )
    390302{
     
    394306        if( irc->readbuffer != NULL )
    395307        {
    396                 lines = irc_tokenize( irc->readbuffer );
     308                lines = irc_splitlines( irc->readbuffer );
    397309               
    398310                for( i = 0; *lines[i] != '\0'; i ++ )
     
    431343                                                                  "`help set charset' for more information. Your "
    432344                                                                  "message was ignored.",
    433                                                                   set_getstr( &irc->set, "charset" ) );
     345                                                                  set_getstr( &irc->b->set, "charset" ) );
    434346                                               
    435347                                                g_free( conv );
     
    438350                                        else
    439351                                        {
    440                                                 irc_write( irc, ":%s NOTICE AUTH :%s", irc->myhost,
     352                                                irc_write( irc, ":%s NOTICE AUTH :%s", irc->root->host,
    441353                                                           "Warning: invalid characters received at login time." );
    442354                                               
     
    476388}
    477389
    478 /* Splits a long string into separate lines. The array is NULL-terminated and, unless the string
    479    contains an incomplete line at the end, ends with an empty string. */
    480 char **irc_tokenize( char *buffer )
     390/* Splits a long string into separate lines. The array is NULL-terminated
     391   and, unless the string contains an incomplete line at the end, ends with
     392   an empty string. Could use g_strsplit() but this one does it in-place.
     393   (So yes, it's destructive.) */
     394static char **irc_splitlines( char *buffer )
    481395{
    482396        int i, j, n = 3;
     
    609523}
    610524
    611 void irc_reply( irc_t *irc, int code, char *format, ... )
    612 {
    613         char text[IRC_MAX_LINE];
    614         va_list params;
    615        
    616         va_start( params, format );
    617         g_vsnprintf( text, IRC_MAX_LINE, format, params );
    618         va_end( params );
    619         irc_write( irc, ":%s %03d %s %s", irc->myhost, code, irc->nick?irc->nick:"*", text );
    620        
    621         return;
    622 }
    623 
    624 int irc_usermsg( irc_t *irc, char *format, ... )
    625 {
    626         char text[1024];
    627         va_list params;
    628         char is_private = 0;
    629         user_t *u;
    630        
    631         u = user_find( irc, irc->mynick );
    632         is_private = u->is_private;
    633        
    634         va_start( params, format );
    635         g_vsnprintf( text, sizeof( text ), format, params );
    636         va_end( params );
    637        
    638         return( irc_msgfrom( irc, u->nick, text ) );
    639 }
    640 
    641525void irc_write( irc_t *irc, char *format, ... )
    642526{
     
    649533        return;
    650534}
     535
     536void irc_write_all( int now, char *format, ... )
     537{
     538        va_list params;
     539        GSList *temp;   
     540       
     541        va_start( params, format );
     542       
     543        temp = irc_connection_list;
     544        while( temp != NULL )
     545        {
     546                irc_t *irc = temp->data;
     547               
     548                if( now )
     549                {
     550                        g_free( irc->sendbuffer );
     551                        irc->sendbuffer = g_strdup( "\r\n" );
     552                }
     553                irc_vawrite( temp->data, format, params );
     554                if( now )
     555                {
     556                        bitlbee_io_current_client_write( irc, irc->fd, B_EV_IO_WRITE );
     557                }
     558                temp = temp->next;
     559        }
     560       
     561        va_end( params );
     562        return;
     563}
    651564
    652565void irc_vawrite( irc_t *irc, char *format, va_list params )
     
    696609                   in the event queue. */
    697610                /* Really can't be done as long as the code doesn't do error checking very well:
    698                 if( bitlbee_io_current_client_write( irc, irc->fd, GAIM_INPUT_WRITE ) ) */
     611                if( bitlbee_io_current_client_write( irc, irc->fd, B_EV_IO_WRITE ) ) */
    699612               
    700613                /* So just always do it via the event handler. */
    701                 irc->w_watch_source_id = b_input_add( irc->fd, GAIM_INPUT_WRITE, bitlbee_io_current_client_write, irc );
     614                irc->w_watch_source_id = b_input_add( irc->fd, B_EV_IO_WRITE, bitlbee_io_current_client_write, irc );
    702615        }
    703616       
     
    705618}
    706619
    707 void irc_write_all( int now, char *format, ... )
    708 {
    709         va_list params;
    710         GSList *temp;   
    711        
    712         va_start( params, format );
    713        
    714         temp = irc_connection_list;
    715         while( temp != NULL )
    716         {
    717                 irc_t *irc = temp->data;
    718                
    719                 if( now )
    720                 {
    721                         g_free( irc->sendbuffer );
    722                         irc->sendbuffer = g_strdup( "\r\n" );
    723                 }
    724                 irc_vawrite( temp->data, format, params );
    725                 if( now )
    726                 {
    727                         bitlbee_io_current_client_write( irc, irc->fd, GAIM_INPUT_WRITE );
    728                 }
    729                 temp = temp->next;
    730         }
    731        
    732         va_end( params );
    733         return;
    734 }
    735 
    736 void irc_names( irc_t *irc, char *channel )
    737 {
    738         user_t *u;
    739         char namelist[385] = "";
    740         struct groupchat *c = NULL;
    741         char *ops = set_getstr( &irc->set, "ops" );
    742        
    743         /* RFCs say there is no error reply allowed on NAMES, so when the
    744            channel is invalid, just give an empty reply. */
    745        
    746         if( g_strcasecmp( channel, irc->channel ) == 0 )
    747         {
    748                 for( u = irc->users; u; u = u->next ) if( u->online )
    749                 {
    750                         if( strlen( namelist ) + strlen( u->nick ) > sizeof( namelist ) - 4 )
     620int irc_check_login( irc_t *irc )
     621{
     622        if( irc->user->user && irc->user->nick )
     623        {
     624                if( global.conf->authmode == AUTHMODE_CLOSED && !( irc->status & USTATUS_AUTHORIZED ) )
     625                {
     626                        irc_send_num( irc, 464, ":This server is password-protected." );
     627                        return 0;
     628                }
     629                else
     630                {
     631                        irc_channel_t *ic;
     632                        irc_user_t *iu = irc->user;
     633                       
     634                        irc->user = irc_user_new( irc, iu->nick );
     635                        irc->user->user = iu->user;
     636                        irc->user->host = iu->host;
     637                        irc->user->fullname = iu->fullname;
     638                        irc->user->f = &irc_user_self_funcs;
     639                        g_free( iu->nick );
     640                        g_free( iu );
     641                       
     642                        if( global.conf->runmode == RUNMODE_FORKDAEMON || global.conf->runmode == RUNMODE_DAEMON )
     643                                ipc_to_master_str( "CLIENT %s %s :%s\r\n", irc->user->host, irc->user->nick, irc->user->fullname );
     644                       
     645                        irc->status |= USTATUS_LOGGED_IN;
     646                       
     647                        irc_send_login( irc );
     648                       
     649                        irc->umode[0] = '\0';
     650                        irc_umode_set( irc, "+" UMODE, TRUE );
     651                       
     652                        ic = irc->default_channel = irc_channel_new( irc, ROOT_CHAN );
     653                        irc_channel_set_topic( ic, CONTROL_TOPIC, irc->root );
     654                        irc_channel_add_user( ic, irc->user );
     655                       
     656                        irc->last_root_cmd = g_strdup( ROOT_CHAN );
     657                       
     658                        irc_send_msg( irc->root, "PRIVMSG", ROOT_CHAN,
     659                                      "Welcome to the BitlBee gateway!\n\n"
     660                                      "If you've never used BitlBee before, please do read the help "
     661                                      "information using the \x02help\x02 command. Lots of FAQs are "
     662                                      "answered there.\n"
     663                                      "If you already have an account on this server, just use the "
     664                                      "\x02identify\x02 command to identify yourself.", NULL );
     665                       
     666                        /* This is for bug #209 (use PASS to identify to NickServ). */
     667                        if( irc->password != NULL )
    751668                        {
    752                                 irc_reply( irc, 353, "= %s :%s", channel, namelist );
    753                                 *namelist = 0;
     669                                char *send_cmd[] = { "identify", g_strdup( irc->password ), NULL };
     670                               
     671                                irc_setpass( irc, NULL );
     672                                root_command( irc, send_cmd );
     673                                g_free( send_cmd[1] );
    754674                        }
    755675                       
    756                         if( u->ic && !u->away && set_getbool( &irc->set, "away_devoice" ) )
    757                                 strcat( namelist, "+" );
    758                         else if( ( strcmp( u->nick, irc->mynick ) == 0 && ( strcmp( ops, "root" ) == 0 || strcmp( ops, "both" ) == 0 ) ) ||
    759                                  ( strcmp( u->nick, irc->nick ) == 0 && ( strcmp( ops, "user" ) == 0 || strcmp( ops, "both" ) == 0 ) ) )
    760                                 strcat( namelist, "@" );
    761                        
    762                         strcat( namelist, u->nick );
    763                         strcat( namelist, " " );
    764                 }
    765         }
    766         else if( ( c = irc_chat_by_channel( irc, channel ) ) )
    767         {
    768                 GList *l;
    769                
    770                 /* root and the user aren't in the channel userlist but should
    771                    show up in /NAMES, so list them first: */
    772                 sprintf( namelist, "%s%s %s%s ", strcmp( ops, "root" ) == 0 || strcmp( ops, "both" ) ? "@" : "", irc->mynick,
    773                                                  strcmp( ops, "user" ) == 0 || strcmp( ops, "both" ) ? "@" : "", irc->nick );
    774                
    775                 for( l = c->in_room; l; l = l->next ) if( ( u = user_findhandle( c->ic, l->data ) ) )
    776                 {
    777                         if( strlen( namelist ) + strlen( u->nick ) > sizeof( namelist ) - 4 )
    778                         {
    779                                 irc_reply( irc, 353, "= %s :%s", channel, namelist );
    780                                 *namelist = 0;
    781                         }
    782                        
    783                         strcat( namelist, u->nick );
    784                         strcat( namelist, " " );
    785                 }
    786         }
    787        
    788         if( *namelist )
    789                 irc_reply( irc, 353, "= %s :%s", channel, namelist );
    790        
    791         irc_reply( irc, 366, "%s :End of /NAMES list", channel );
    792 }
    793 
    794 int irc_check_login( irc_t *irc )
    795 {
    796         if( irc->user && irc->nick )
    797         {
    798                 if( global.conf->authmode == AUTHMODE_CLOSED && !( irc->status & USTATUS_AUTHORIZED ) )
    799                 {
    800                         irc_reply( irc, 464, ":This server is password-protected." );
    801                         return 0;
    802                 }
    803                 else
    804                 {
    805                         irc_login( irc );
    806676                        return 1;
    807677                }
     
    814684}
    815685
    816 void irc_login( irc_t *irc )
    817 {
    818         user_t *u;
    819        
    820         irc_reply( irc,   1, ":Welcome to the BitlBee gateway, %s", irc->nick );
    821         irc_reply( irc,   2, ":Host %s is running BitlBee " BITLBEE_VERSION " " ARCH "/" CPU ".", irc->myhost );
    822         irc_reply( irc,   3, ":%s", IRCD_INFO );
    823         irc_reply( irc,   4, "%s %s %s %s", irc->myhost, BITLBEE_VERSION, UMODES UMODES_PRIV, CMODES );
    824         irc_reply( irc,   5, "PREFIX=(ov)@+ CHANTYPES=%s CHANMODES=,,,%s NICKLEN=%d NETWORK=BitlBee "
    825                              "CASEMAPPING=rfc1459 MAXTARGETS=1 WATCH=128 :are supported by this server",
    826                              CTYPES, CMODES, MAX_NICK_LENGTH - 1 );
    827         irc_motd( irc );
    828         irc->umode[0] = '\0';
    829         irc_umode_set( irc, "+" UMODE, 1 );
    830 
    831         u = user_add( irc, irc->mynick );
    832         u->host = g_strdup( irc->myhost );
    833         u->realname = g_strdup( ROOT_FN );
    834         u->online = 1;
    835         u->send_handler = root_command_string;
    836         u->is_private = 0; /* [SH] The channel is root's personal playground. */
    837         irc_spawn( irc, u );
    838        
    839         u = user_add( irc, NS_NICK );
    840         u->host = g_strdup( irc->myhost );
    841         u->realname = g_strdup( ROOT_FN );
    842         u->online = 0;
    843         u->send_handler = root_command_string;
    844         u->is_private = 1; /* [SH] NickServ is not in the channel, so should always /query. */
    845        
    846         u = user_add( irc, irc->nick );
    847         u->user = g_strdup( irc->user );
    848         u->host = g_strdup( irc->host );
    849         u->realname = g_strdup( irc->realname );
    850         u->online = 1;
    851         irc_spawn( irc, u );
    852        
    853         irc_usermsg( irc, "Welcome to the BitlBee gateway!\n\n"
    854                           "If you've never used BitlBee before, please do read the help "
    855                           "information using the \x02help\x02 command. Lots of FAQs are "
    856                           "answered there.\n"
    857                           "If you already have an account on this server, just use the "
    858                           "\x02identify\x02 command to identify yourself." );
    859        
    860         if( global.conf->runmode == RUNMODE_FORKDAEMON || global.conf->runmode == RUNMODE_DAEMON )
    861                 ipc_to_master_str( "CLIENT %s %s :%s\r\n", irc->host, irc->nick, irc->realname );
    862        
    863         irc->status |= USTATUS_LOGGED_IN;
    864        
    865         /* This is for bug #209 (use PASS to identify to NickServ). */
    866         if( irc->password != NULL )
    867         {
    868                 char *send_cmd[] = { "identify", g_strdup( irc->password ), NULL };
    869                
    870                 irc_setpass( irc, NULL );
    871                 root_command( irc, send_cmd );
    872                 g_free( send_cmd[1] );
    873         }
    874 }
    875 
    876 void irc_motd( irc_t *irc )
    877 {
    878         int fd;
    879        
    880         fd = open( global.conf->motdfile, O_RDONLY );
    881         if( fd == -1 )
    882         {
    883                 irc_reply( irc, 422, ":We don't need MOTDs." );
    884         }
    885         else
    886         {
    887                 char linebuf[80];       /* Max. line length for MOTD's is 79 chars. It's what most IRC networks seem to do. */
    888                 char *add, max;
    889                 int len;
    890                
    891                 linebuf[79] = len = 0;
    892                 max = sizeof( linebuf ) - 1;
    893                
    894                 irc_reply( irc, 375, ":- %s Message Of The Day - ", irc->myhost );
    895                 while( read( fd, linebuf + len, 1 ) == 1 )
    896                 {
    897                         if( linebuf[len] == '\n' || len == max )
    898                         {
    899                                 linebuf[len] = 0;
    900                                 irc_reply( irc, 372, ":- %s", linebuf );
    901                                 len = 0;
    902                         }
    903                         else if( linebuf[len] == '%' )
    904                         {
    905                                 read( fd, linebuf + len, 1 );
    906                                 if( linebuf[len] == 'h' )
    907                                         add = irc->myhost;
    908                                 else if( linebuf[len] == 'v' )
    909                                         add = BITLBEE_VERSION;
    910                                 else if( linebuf[len] == 'n' )
    911                                         add = irc->nick;
    912                                 else
    913                                         add = "%";
    914                                
    915                                 strncpy( linebuf + len, add, max - len );
    916                                 while( linebuf[++len] );
    917                         }
    918                         else if( len < max )
    919                         {
    920                                 len ++;
    921                         }
    922                 }
    923                 irc_reply( irc, 376, ":End of MOTD" );
    924                 close( fd );
    925         }
    926 }
    927 
    928 void irc_topic( irc_t *irc, char *channel )
    929 {
    930         struct groupchat *c = irc_chat_by_channel( irc, channel );
    931        
    932         if( c && c->topic )
    933                 irc_reply( irc, 332, "%s :%s", channel, c->topic );
    934         else if( g_strcasecmp( channel, irc->channel ) == 0 )
    935                 irc_reply( irc, 332, "%s :%s", channel, CONTROL_TOPIC );
    936         else
    937                 irc_reply( irc, 331, "%s :No topic for this channel", channel );
    938 }
    939 
    940 void irc_umode_set( irc_t *irc, char *s, int allow_priv )
     686void irc_umode_set( irc_t *irc, const char *s, gboolean allow_priv )
    941687{
    942688        /* allow_priv: Set to 0 if s contains user input, 1 if you want
    943689           to set a "privileged" mode (+o, +R, etc). */
    944         char m[256], st = 1, *t;
     690        char m[128], st = 1;
     691        const char *t;
    945692        int i;
    946693        char changes[512], *p, st2 = 2;
     
    950697       
    951698        for( t = irc->umode; *t; t ++ )
    952                 m[(int)*t] = 1;
    953 
     699                if( *t < sizeof( m ) )
     700                        m[(int)*t] = 1;
     701       
    954702        p = changes;
    955703        for( t = s; *t; t ++ )
     
    957705                if( *t == '+' || *t == '-' )
    958706                        st = *t == '+';
    959                 else if( st == 0 || ( strchr( UMODES, *t ) || ( allow_priv && strchr( UMODES_PRIV, *t ) ) ) )
     707                else if( ( st == 0 && ( !strchr( UMODES_KEEP, *t ) || allow_priv ) ) ||
     708                         ( st == 1 && strchr( UMODES, *t ) ) ||
     709                         ( st == 1 && allow_priv && strchr( UMODES_PRIV, *t ) ) )
    960710                {
    961711                        if( m[(int)*t] != st)
     
    974724        memset( irc->umode, 0, sizeof( irc->umode ) );
    975725       
    976         for( i = 0; i < 256 && strlen( irc->umode ) < ( sizeof( irc->umode ) - 1 ); i ++ )
     726        for( i = 'A'; i <= 'z' && strlen( irc->umode ) < ( sizeof( irc->umode ) - 1 ); i ++ )
    977727                if( m[i] )
    978728                        irc->umode[strlen(irc->umode)] = i;
    979729       
    980730        if( badflag )
    981                 irc_reply( irc, 501, ":Unknown MODE flag" );
    982         /* Deliberately no !user@host on the prefix here */
     731                irc_send_num( irc, 501, ":Unknown MODE flag" );
    983732        if( *changes )
    984                 irc_write( irc, ":%s MODE %s %s", irc->nick, irc->nick, changes );
    985 }
    986 
    987 void irc_spawn( irc_t *irc, user_t *u )
    988 {
    989         irc_join( irc, u, irc->channel );
    990 }
    991 
    992 void irc_join( irc_t *irc, user_t *u, char *channel )
    993 {
    994         char *nick;
    995        
    996         if( ( g_strcasecmp( channel, irc->channel ) != 0 ) || user_find( irc, irc->nick ) )
    997                 irc_write( irc, ":%s!%s@%s JOIN :%s", u->nick, u->user, u->host, channel );
    998        
    999         if( nick_cmp( u->nick, irc->nick ) == 0 )
    1000         {
    1001                 irc_write( irc, ":%s MODE %s +%s", irc->myhost, channel, CMODE );
    1002                 irc_names( irc, channel );
    1003                 irc_topic( irc, channel );
    1004         }
    1005        
    1006         nick = g_strdup( u->nick );
    1007         nick_lc( nick );
    1008         if( g_hash_table_lookup( irc->watches, nick ) )
    1009         {
    1010                 irc_reply( irc, 600, "%s %s %s %d :%s", u->nick, u->user, u->host, (int) time( NULL ), "logged online" );
    1011         }
    1012         g_free( nick );
    1013 }
    1014 
    1015 void irc_part( irc_t *irc, user_t *u, char *channel )
    1016 {
    1017         irc_write( irc, ":%s!%s@%s PART %s :%s", u->nick, u->user, u->host, channel, "" );
    1018 }
    1019 
    1020 void irc_kick( irc_t *irc, user_t *u, char *channel, user_t *kicker )
    1021 {
    1022         irc_write( irc, ":%s!%s@%s KICK %s %s :%s", kicker->nick, kicker->user, kicker->host, channel, u->nick, "" );
    1023 }
    1024 
    1025 void irc_kill( irc_t *irc, user_t *u )
    1026 {
    1027         char *nick, *s;
    1028         char reason[128];
    1029        
    1030         if( u->ic && u->ic->flags & OPT_LOGGING_OUT && set_getbool( &irc->set, "simulate_netsplit" ) )
    1031         {
    1032                 if( u->ic->acc->server )
    1033                         g_snprintf( reason, sizeof( reason ), "%s %s", irc->myhost,
    1034                                     u->ic->acc->server );
    1035                 else if( ( s = strchr( u->ic->acc->user, '@' ) ) )
    1036                         g_snprintf( reason, sizeof( reason ), "%s %s", irc->myhost,
    1037                                     s + 1 );
    1038                 else
    1039                         g_snprintf( reason, sizeof( reason ), "%s %s.%s", irc->myhost,
    1040                                     u->ic->acc->prpl->name, irc->myhost );
    1041                
    1042                 /* proto_opt might contain garbage after the : */
    1043                 if( ( s = strchr( reason, ':' ) ) )
    1044                         *s = 0;
    1045         }
    1046         else
    1047         {
    1048                 strcpy( reason, "Leaving..." );
    1049         }
    1050        
    1051         irc_write( irc, ":%s!%s@%s QUIT :%s", u->nick, u->user, u->host, reason );
    1052        
    1053         nick = g_strdup( u->nick );
    1054         nick_lc( nick );
    1055         if( g_hash_table_lookup( irc->watches, nick ) )
    1056         {
    1057                 irc_reply( irc, 601, "%s %s %s %d :%s", u->nick, u->user, u->host, (int) time( NULL ), "logged offline" );
    1058         }
    1059         g_free( nick );
    1060 }
    1061 
    1062 int irc_send( irc_t *irc, char *nick, char *s, int flags )
    1063 {
    1064         struct groupchat *c = NULL;
    1065         user_t *u = NULL;
    1066        
    1067         if( strchr( CTYPES, *nick ) )
    1068         {
    1069                 if( !( c = irc_chat_by_channel( irc, nick ) ) )
    1070                 {
    1071                         irc_reply( irc, 403, "%s :Channel does not exist", nick );
    1072                         return( 0 );
    1073                 }
    1074         }
    1075         else
    1076         {
    1077                 u = user_find( irc, nick );
    1078                
    1079                 if( !u )
    1080                 {
    1081                         if( irc->is_private )
    1082                                 irc_reply( irc, 401, "%s :Nick does not exist", nick );
    1083                         else
    1084                                 irc_usermsg( irc, "Nick `%s' does not exist!", nick );
    1085                         return( 0 );
    1086                 }
    1087         }
    1088        
    1089         if( *s == 1 && s[strlen(s)-1] == 1 )
    1090         {
    1091                 if( g_strncasecmp( s + 1, "ACTION", 6 ) == 0 )
    1092                 {
    1093                         if( s[7] == ' ' ) s ++;
    1094                         s += 3;
    1095                         *(s++) = '/';
    1096                         *(s++) = 'm';
    1097                         *(s++) = 'e';
    1098                         *(s++) = ' ';
    1099                         s -= 4;
    1100                         s[strlen(s)-1] = 0;
    1101                 }
    1102                 else if( g_strncasecmp( s + 1, "VERSION", 7 ) == 0 )
    1103                 {
    1104                         u = user_find( irc, irc->mynick );
    1105                         irc_privmsg( irc, u, "NOTICE", irc->nick, "", "\001VERSION BitlBee " BITLBEE_VERSION " " ARCH "/" CPU "\001" );
    1106                         return( 1 );
    1107                 }
    1108                 else if( g_strncasecmp( s + 1, "PING", 4 ) == 0 )
    1109                 {
    1110                         u = user_find( irc, irc->mynick );
    1111                         irc_privmsg( irc, u, "NOTICE", irc->nick, "", s );
    1112                         return( 1 );
    1113                 }
    1114                 else if( g_strncasecmp( s + 1, "TYPING", 6 ) == 0 )
    1115                 {
    1116                         if( u && u->ic && u->ic->acc->prpl->send_typing && strlen( s ) >= 10 )
    1117                         {
    1118                                 time_t current_typing_notice = time( NULL );
    1119                                
    1120                                 if( current_typing_notice - u->last_typing_notice >= 5 )
    1121                                 {
    1122                                         u->ic->acc->prpl->send_typing( u->ic, u->handle, ( s[8] - '0' ) << 8 );
    1123                                         u->last_typing_notice = current_typing_notice;
    1124                                 }
    1125                         }
    1126                         return( 1 );
    1127                 }
    1128                 else
    1129                 {
    1130                         irc_usermsg( irc, "Non-ACTION CTCP's aren't supported" );
    1131                         return( 0 );
    1132                 }
    1133         }
    1134        
    1135         if( u )
    1136         {
    1137                 /* For the next message, we probably do have to send new notices... */
    1138                 u->last_typing_notice = 0;
    1139                 u->is_private = irc->is_private;
    1140                
    1141                 if( u->is_private )
    1142                 {
    1143                         if( !u->online )
    1144                                 irc_reply( irc, 301, "%s :%s", u->nick, "User is offline" );
    1145                         else if( u->away )
    1146                                 irc_reply( irc, 301, "%s :%s", u->nick, u->away );
    1147                 }
    1148                
    1149                 if( u->send_handler )
    1150                 {
    1151                         u->send_handler( irc, u, s, flags );
    1152                         return 1;
    1153                 }
    1154         }
    1155         else if( c && c->ic && c->ic->acc && c->ic->acc->prpl )
    1156         {
    1157                 return( imc_chat_msg( c, s, 0 ) );
    1158         }
    1159        
    1160         return( 0 );
    1161 }
    1162 
    1163 static gboolean buddy_send_handler_delayed( gpointer data, gint fd, b_input_condition cond )
    1164 {
    1165         user_t *u = data;
    1166        
    1167         /* Shouldn't happen, but just to be sure. */
    1168         if( u->sendbuf_len < 2 )
    1169                 return FALSE;
    1170        
    1171         u->sendbuf[u->sendbuf_len-2] = 0; /* Cut off the last newline */
    1172         imc_buddy_msg( u->ic, u->handle, u->sendbuf, u->sendbuf_flags );
    1173        
    1174         g_free( u->sendbuf );
    1175         u->sendbuf = NULL;
    1176         u->sendbuf_len = 0;
    1177         u->sendbuf_timer = 0;
    1178         u->sendbuf_flags = 0;
    1179        
    1180         return FALSE;
    1181 }
    1182 
    1183 void buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags )
    1184 {
    1185         if( !u || !u->ic ) return;
    1186        
    1187         if( set_getbool( &irc->set, "buddy_sendbuffer" ) && set_getint( &irc->set, "buddy_sendbuffer_delay" ) > 0 )
    1188         {
    1189                 int delay;
    1190                
    1191                 if( u->sendbuf_len > 0 && u->sendbuf_flags != flags)
    1192                 {
    1193                         /* Flush the buffer */
    1194                         b_event_remove( u->sendbuf_timer );
    1195                         buddy_send_handler_delayed( u, -1, 0 );
    1196                 }
    1197 
    1198                 if( u->sendbuf_len == 0 )
    1199                 {
    1200                         u->sendbuf_len = strlen( msg ) + 2;
    1201                         u->sendbuf = g_new( char, u->sendbuf_len );
    1202                         u->sendbuf[0] = 0;
    1203                         u->sendbuf_flags = flags;
    1204                 }
    1205                 else
    1206                 {
    1207                         u->sendbuf_len += strlen( msg ) + 1;
    1208                         u->sendbuf = g_renew( char, u->sendbuf, u->sendbuf_len );
    1209                 }
    1210                
    1211                 strcat( u->sendbuf, msg );
    1212                 strcat( u->sendbuf, "\n" );
    1213                
    1214                 delay = set_getint( &irc->set, "buddy_sendbuffer_delay" );
    1215                 if( delay <= 5 )
    1216                         delay *= 1000;
    1217                
    1218                 if( u->sendbuf_timer > 0 )
    1219                         b_event_remove( u->sendbuf_timer );
    1220                 u->sendbuf_timer = b_timeout_add( delay, buddy_send_handler_delayed, u );
    1221         }
    1222         else
    1223         {
    1224                 imc_buddy_msg( u->ic, u->handle, msg, flags );
    1225         }
    1226 }
    1227 
    1228 int irc_privmsg( irc_t *irc, user_t *u, char *type, char *to, char *prefix, char *msg )
    1229 {
    1230         char last = 0;
    1231         char *s = msg, *line = msg;
    1232        
    1233         /* The almighty linesplitter .. woohoo!! */
    1234         while( !last )
    1235         {
    1236                 if( *s == '\r' && *(s+1) == '\n' )
    1237                         *(s++) = 0;
    1238                 if( *s == '\n' )
    1239                 {
    1240                         last = s[1] == 0;
    1241                         *s = 0;
    1242                 }
    1243                 else
    1244                 {
    1245                         last = s[0] == 0;
    1246                 }
    1247                 if( *s == 0 )
    1248                 {
    1249                         if( g_strncasecmp( line, "/me ", 4 ) == 0 && ( !prefix || !*prefix ) && g_strcasecmp( type, "PRIVMSG" ) == 0 )
    1250                         {
    1251                                 irc_write( irc, ":%s!%s@%s %s %s :\001ACTION %s\001", u->nick, u->user, u->host,
    1252                                            type, to, line + 4 );
    1253                         }
    1254                         else
    1255                         {
    1256                                 irc_write( irc, ":%s!%s@%s %s %s :%s%s", u->nick, u->user, u->host,
    1257                                            type, to, prefix ? prefix : "", line );
    1258                         }
    1259                         line = s + 1;
    1260                 }
    1261                 s ++;
    1262         }
    1263        
    1264         return( 1 );
    1265 }
    1266 
    1267 int irc_msgfrom( irc_t *irc, char *nick, char *msg )
    1268 {
    1269         user_t *u = user_find( irc, nick );
    1270         static char *prefix = NULL;
    1271        
    1272         if( !u ) return( 0 );
    1273         if( prefix && *prefix ) g_free( prefix );
    1274        
    1275         if( !u->is_private && nick_cmp( u->nick, irc->mynick ) != 0 )
    1276         {
    1277                 int len = strlen( irc->nick) + 3;
    1278                 prefix = g_new (char, len );
    1279                 g_snprintf( prefix, len, "%s%s", irc->nick, set_getstr( &irc->set, "to_char" ) );
    1280                 prefix[len-1] = 0;
    1281         }
    1282         else
    1283         {
    1284                 prefix = "";
    1285         }
    1286        
    1287         return( irc_privmsg( irc, u, "PRIVMSG", u->is_private ? irc->nick : irc->channel, prefix, msg ) );
    1288 }
    1289 
    1290 int irc_noticefrom( irc_t *irc, char *nick, char *msg )
    1291 {
    1292         user_t *u = user_find( irc, nick );
    1293        
    1294         if( u )
    1295                 return( irc_privmsg( irc, u, "NOTICE", irc->nick, "", msg ) );
    1296         else
    1297                 return( 0 );
     733                irc_write( irc, ":%s!%s@%s MODE %s :%s", irc->user->nick,
     734                           irc->user->user, irc->user->host, irc->user->nick,
     735                           changes );
    1298736}
    1299737
     
    1334772}
    1335773
    1336 struct groupchat *irc_chat_by_channel( irc_t *irc, char *channel )
    1337 {
    1338         struct groupchat *c;
    1339         account_t *a;
    1340        
    1341         /* This finds the connection which has a conversation which belongs to this channel */
    1342         for( a = irc->accounts; a; a = a->next )
    1343         {
    1344                 if( a->ic == NULL )
    1345                         continue;
    1346                
    1347                 c = a->ic->groupchats;
    1348                 while( c )
    1349                 {
    1350                         if( c->channel && g_strcasecmp( c->channel, channel ) == 0 )
    1351                                 return c;
    1352                        
    1353                         c = c->next;
    1354                 }
    1355         }
    1356        
    1357         return NULL;
    1358 }
     774static char *set_eval_charset( set_t *set, char *value )
     775{
     776        irc_t *irc = (irc_t*) set->data;
     777        char *test;
     778        gsize test_bytes = 0;
     779        GIConv ic, oc;
     780
     781        if( g_strcasecmp( value, "none" ) == 0 )
     782                value = g_strdup( "utf-8" );
     783
     784        if( ( oc = g_iconv_open( value, "utf-8" ) ) == (GIConv) -1 )
     785        {
     786                return NULL;
     787        }
     788       
     789        /* Do a test iconv to see if the user picked an IRC-compatible
     790           charset (for example utf-16 goes *horribly* wrong). */
     791        if( ( test = g_convert_with_iconv( " ", 1, oc, NULL, &test_bytes, NULL ) ) == NULL ||
     792            test_bytes > 1 )
     793        {
     794                g_free( test );
     795                g_iconv_close( oc );
     796                irc_usermsg( irc, "Unsupported character set: The IRC protocol "
     797                                  "only supports 8-bit character sets." );
     798                return NULL;
     799        }
     800        g_free( test );
     801       
     802        if( ( ic = g_iconv_open( "utf-8", value ) ) == (GIConv) -1 )
     803        {
     804                g_iconv_close( oc );
     805                return NULL;
     806        }
     807       
     808        if( irc->iconv != (GIConv) -1 )
     809                g_iconv_close( irc->iconv );
     810        if( irc->oconv != (GIConv) -1 )
     811                g_iconv_close( irc->oconv );
     812       
     813        irc->iconv = ic;
     814        irc->oconv = oc;
     815
     816        return value;
     817}
     818
     819char *set_eval_away_devoice( set_t *set, char *value )
     820{
     821        irc_t *irc = set->data;
     822       
     823        if( !is_bool( value ) )
     824                return SET_INVALID;
     825       
     826        /* The usual problem: The setting isn't actually changed at this
     827           point and we need it to be, so do it by hand. */
     828        g_free( set->value );
     829        set->value = g_strdup( value );
     830       
     831        bee_irc_channel_update( irc, NULL, NULL );
     832       
     833        return value;
     834}
  • irc.h

    r38ff846 r8b8def58  
    55  \********************************************************************/
    66
    7 /* The big hairy IRCd part of the project                               */
     7/* The IRC-based UI (for now the only one)                              */
    88
    99/*
     
    3333#define IRC_PING_STRING "PinglBee"
    3434
    35 #define UMODES "abisw"
    36 #define UMODES_PRIV "Ro"
    37 #define CMODES "nt"
    38 #define CMODE "t"
    39 #define UMODE "s"
    40 #define CTYPES "&#"
     35#define UMODES "abisw"     /* Allowed umodes (although they mostly do nothing) */
     36#define UMODES_PRIV "Ro"   /* Allowed, but not by user directly */
     37#define UMODES_KEEP "R"    /* Don't allow unsetting using /MODE */
     38#define CMODES "nt"        /* Allowed modes */
     39#define CMODE "t"          /* Default mode */
     40#define UMODE "s"          /* Default mode */
     41
     42#define CTYPES "&#"        /* Valid channel name prefixes */
    4143
    4244typedef enum
     
    4850        USTATUS_SHUTDOWN = 8
    4951} irc_status_t;
     52
     53struct irc_user;
    5054
    5155typedef struct irc
     
    5963        GIConv iconv, oconv;
    6064
    61         int sentbytes;
    62         time_t oldtime;
    63 
     65        struct irc_user *root;
     66        struct irc_user *user;
     67       
     68        char *last_root_cmd;
     69
     70        char *password; /* HACK: Used to save the user's password, but before
     71                           logging in, this may contain a password we should
     72                           send to identify after USER/NICK are received. */
     73
     74        char umode[8];
     75       
     76        struct query *queries;
     77        GSList *file_transfers;
     78       
     79        GSList *users, *channels;
     80        struct irc_channel *default_channel;
     81        GHashTable *nick_user_hash;
     82        GHashTable *watches;
     83
     84        gint r_watch_source_id;
     85        gint w_watch_source_id;
     86        gint ping_source_id;
     87       
     88        struct bee *b;
     89} irc_t;
     90
     91typedef enum
     92{
     93        IRC_USER_PRIVATE = 1,
     94        IRC_USER_AWAY = 2,
     95} irc_user_flags_t;
     96
     97typedef struct irc_user
     98{
     99        irc_t *irc;
     100       
    64101        char *nick;
    65102        char *user;
    66103        char *host;
    67         char *realname;
    68         char *password; /* HACK: Used to save the user's password, but before
    69                            logging in, this may contain a password we should
    70                            send to identify after USER/NICK are received. */
    71 
    72         char umode[8];
    73        
    74         char *myhost;
    75         char *mynick;
    76 
    77         char *channel;
    78         int c_id;
    79 
    80         char is_private;                /* Not too nice... */
    81         char *last_target;
    82        
    83         struct query *queries;
    84         struct account *accounts;
    85         struct chat *chatrooms;
    86        
    87         struct __USER *users;
    88         GHashTable *userhash;
    89         GHashTable *watches;
    90         struct __NICK *nicks;
     104        char *fullname;
     105       
     106        /* Nickname in lowercase for case sensitive searches */
     107        char *key;
     108       
     109        irc_user_flags_t flags;
     110       
     111        GString *pastebuf; /* Paste buffer (combine lines into a multiline msg). */
     112        guint pastebuf_timer;
     113        time_t away_reply_timeout; /* Only send a 301 if this time passed. */
     114       
     115        struct bee_user *bu;
     116       
     117        const struct irc_user_funcs *f;
     118} irc_user_t;
     119
     120struct irc_user_funcs
     121{
     122        gboolean (*privmsg)( irc_user_t *iu, const char *msg );
     123        gboolean (*ctcp)( irc_user_t *iu, char * const* ctcp );
     124};
     125
     126extern const struct irc_user_funcs irc_user_root_funcs;
     127extern const struct irc_user_funcs irc_user_self_funcs;
     128
     129typedef enum
     130{
     131        IRC_CHANNEL_JOINED = 1,
     132       
     133        /* Hack: Set this flag right before jumping into IM when we expect
     134           a call to imcb_chat_new(). */
     135        IRC_CHANNEL_CHAT_PICKME = 0x10000,
     136} irc_channel_flags_t;
     137
     138typedef struct irc_channel
     139{
     140        irc_t *irc;
     141        char *name;
     142        char mode[8];
     143        int flags;
     144       
     145        char *topic;
     146        char *topic_who;
     147        time_t topic_time;
     148       
     149        GSList *users; /* struct irc_channel_user */
    91150        struct set *set;
    92 
    93         gint r_watch_source_id;
    94         gint w_watch_source_id;
    95         gint ping_source_id;
    96 } irc_t;
    97 
    98 #include "user.h"
    99 
     151       
     152        GString *pastebuf; /* Paste buffer (combine lines into a multiline msg). */
     153        guint pastebuf_timer;
     154       
     155        const struct irc_channel_funcs *f;
     156        void *data;
     157} irc_channel_t;
     158
     159struct irc_channel_funcs
     160{
     161        gboolean (*privmsg)( irc_channel_t *ic, const char *msg );
     162        gboolean (*join)( irc_channel_t *ic );
     163        gboolean (*part)( irc_channel_t *ic, const char *msg );
     164        gboolean (*topic)( irc_channel_t *ic, const char *new );
     165        gboolean (*invite)( irc_channel_t *ic, irc_user_t *iu );
     166       
     167        gboolean (*_init)( irc_channel_t *ic );
     168        gboolean (*_free)( irc_channel_t *ic );
     169};
     170
     171typedef enum
     172{
     173        IRC_CHANNEL_USER_OP = 1,
     174        IRC_CHANNEL_USER_HALFOP = 2,
     175        IRC_CHANNEL_USER_VOICE = 4,
     176} irc_channel_user_flags_t;
     177
     178typedef struct irc_channel_user
     179{
     180        irc_user_t *iu;
     181        int flags;
     182} irc_channel_user_t;
     183
     184typedef enum
     185{
     186        IRC_CC_TYPE_DEFAULT,
     187        IRC_CC_TYPE_REST,
     188        IRC_CC_TYPE_GROUP,
     189        IRC_CC_TYPE_ACCOUNT,
     190} irc_control_channel_type_t;
     191
     192struct irc_control_channel
     193{
     194        irc_control_channel_type_t type;
     195        struct bee_group *group;
     196        struct account *account;
     197};
     198
     199extern const struct bee_ui_funcs irc_ui_funcs;
     200
     201/* irc.c */
    100202extern GSList *irc_connection_list;
    101203
     
    103205void irc_abort( irc_t *irc, int immed, char *format, ... ) G_GNUC_PRINTF( 3, 4 );
    104206void irc_free( irc_t *irc );
    105 
    106 void irc_exec( irc_t *irc, char **cmd );
     207void irc_setpass (irc_t *irc, const char *pass);
     208
    107209void irc_process( irc_t *irc );
    108210char **irc_parse_line( char *line );
    109211char *irc_build_line( char **cmd );
    110212
    111 void irc_vawrite( irc_t *irc, char *format, va_list params );
    112213void irc_write( irc_t *irc, char *format, ... ) G_GNUC_PRINTF( 2, 3 );
    113214void irc_write_all( int now, char *format, ... ) G_GNUC_PRINTF( 2, 3 );
    114 void irc_reply( irc_t *irc, int code, char *format, ... ) G_GNUC_PRINTF( 3, 4 );
    115 G_MODULE_EXPORT int irc_usermsg( irc_t *irc, char *format, ... ) G_GNUC_PRINTF( 2, 3 );
    116 char **irc_tokenize( char *buffer );
    117 
    118 void irc_login( irc_t *irc );
     215void irc_vawrite( irc_t *irc, char *format, va_list params );
     216
    119217int irc_check_login( irc_t *irc );
    120 void irc_motd( irc_t *irc );
    121 void irc_names( irc_t *irc, char *channel );
    122 void irc_topic( irc_t *irc, char *channel );
    123 void irc_umode_set( irc_t *irc, char *s, int allow_priv );
    124 void irc_who( irc_t *irc, char *channel );
    125 void irc_spawn( irc_t *irc, user_t *u );
    126 void irc_join( irc_t *irc, user_t *u, char *channel );
    127 void irc_part( irc_t *irc, user_t *u, char *channel );
    128 void irc_kick( irc_t *irc, user_t *u, char *channel, user_t *kicker );
    129 void irc_kill( irc_t *irc, user_t *u );
    130 void irc_invite( irc_t *irc, char *nick, char *channel );
    131 void irc_whois( irc_t *irc, char *nick );
    132 void irc_setpass( irc_t *irc, const char *pass ); /* USE WITH CAUTION! */
    133 
    134 int irc_send( irc_t *irc, char *nick, char *s, int flags );
    135 int irc_privmsg( irc_t *irc, user_t *u, char *type, char *to, char *prefix, char *msg );
    136 int irc_msgfrom( irc_t *irc, char *nick, char *msg );
    137 int irc_noticefrom( irc_t *irc, char *nick, char *msg );
    138 
    139 void buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags );
    140 struct groupchat *irc_chat_by_channel( irc_t *irc, char *channel );
     218
     219void irc_umode_set( irc_t *irc, const char *s, gboolean allow_priv );
     220
     221/* irc_channel.c */
     222irc_channel_t *irc_channel_new( irc_t *irc, const char *name );
     223irc_channel_t *irc_channel_by_name( irc_t *irc, const char *name );
     224irc_channel_t *irc_channel_get( irc_t *irc, char *id );
     225int irc_channel_free( irc_channel_t *ic );
     226int irc_channel_add_user( irc_channel_t *ic, irc_user_t *iu );
     227int irc_channel_del_user( irc_channel_t *ic, irc_user_t *iu, gboolean silent, const char *msg );
     228irc_channel_user_t *irc_channel_has_user( irc_channel_t *ic, irc_user_t *iu );
     229int irc_channel_set_topic( irc_channel_t *ic, const char *topic, const irc_user_t *who );
     230void irc_channel_user_set_mode( irc_channel_t *ic, irc_user_t *iu, irc_channel_user_flags_t flags );
     231void irc_channel_printf( irc_channel_t *ic, char *format, ... );
     232gboolean irc_channel_name_ok( const char *name );
     233int irc_channel_name_cmp( const char *a_, const char *b_ );
     234void irc_channel_update_ops( irc_channel_t *ic, char *value );
     235char *set_eval_irc_channel_ops( struct set *set, char *value );
     236
     237/* irc_commands.c */
     238void irc_exec( irc_t *irc, char **cmd );
     239
     240/* irc_send.c */
     241void irc_send_num( irc_t *irc, int code, char *format, ... ) G_GNUC_PRINTF( 3, 4 );
     242void irc_send_login( irc_t *irc );
     243void irc_send_motd( irc_t *irc );
     244void irc_usermsg( irc_t *irc, char *format, ... );
     245void irc_send_join( irc_channel_t *ic, irc_user_t *iu );
     246void irc_send_part( irc_channel_t *ic, irc_user_t *iu, const char *reason );
     247void irc_send_quit( irc_user_t *iu, const char *reason );
     248void irc_send_names( irc_channel_t *ic );
     249void irc_send_topic( irc_channel_t *ic, gboolean topic_change );
     250void irc_send_whois( irc_user_t *iu );
     251void irc_send_who( irc_t *irc, GSList *l, const char *channel );
     252void irc_send_msg( irc_user_t *iu, const char *type, const char *dst, const char *msg, const char *prefix );
     253void irc_send_msg_raw( irc_user_t *iu, const char *type, const char *dst, const char *msg );
     254void irc_send_msg_f( irc_user_t *iu, const char *type, const char *dst, const char *format, ... ) G_GNUC_PRINTF( 4, 5 );
     255void irc_send_nick( irc_user_t *iu, const char *new );
     256void irc_send_channel_user_mode_diff( irc_channel_t *ic, irc_user_t *iu,
     257                                      irc_channel_user_flags_t old, irc_channel_user_flags_t new );
     258
     259/* irc_user.c */
     260irc_user_t *irc_user_new( irc_t *irc, const char *nick );
     261int irc_user_free( irc_t *irc, irc_user_t *iu );
     262irc_user_t *irc_user_by_name( irc_t *irc, const char *nick );
     263int irc_user_set_nick( irc_user_t *iu, const char *new );
     264gint irc_user_cmp( gconstpointer a_, gconstpointer b_ );
     265const char *irc_user_get_away( irc_user_t *iu );
     266
     267/* irc_util.c */
     268char *set_eval_timezone( struct set *set, char *value );
     269char *irc_format_timestamp( irc_t *irc, time_t msg_ts );
     270
     271/* irc_im.c */
     272void bee_irc_channel_update( irc_t *irc, irc_channel_t *ic, irc_user_t *iu );
    141273
    142274#endif
  • irc_commands.c

    r38ff846 r8b8def58  
    22  * BitlBee -- An IRC to other IM-networks gateway                     *
    33  *                                                                    *
    4   * Copyright 2002-2006 Wilmer van der Gaast and others                *
     4  * Copyright 2002-2010 Wilmer van der Gaast and others                *
    55  \********************************************************************/
    66
     
    5353        else if( global.conf->auth_pass )
    5454        {
    55                 irc_reply( irc, 464, ":Incorrect password" );
     55                irc_send_num( irc, 464, ":Incorrect password" );
    5656        }
    5757        else
     
    6565static void irc_cmd_user( irc_t *irc, char **cmd )
    6666{
    67         irc->user = g_strdup( cmd[1] );
    68         irc->realname = g_strdup( cmd[4] );
     67        irc->user->user = g_strdup( cmd[1] );
     68        irc->user->fullname = g_strdup( cmd[4] );
    6969       
    7070        irc_check_login( irc );
     
    7373static void irc_cmd_nick( irc_t *irc, char **cmd )
    7474{
    75         if( irc->status & USTATUS_IDENTIFIED && irc->nick )
    76         {
    77                 irc_reply( irc, 438, "%s %s :You can only change your nick if you're not "
    78                            "logged in (i.e. pre-identify)", irc->nick, cmd[1] );
    79         }
    80         /* This is not clean, but for now it'll have to be like this... */
    81         else if( ( nick_cmp( cmd[1], irc->mynick ) == 0 ) || ( nick_cmp( cmd[1], NS_NICK ) == 0 ) || ( user_find( irc, cmd[1] ) != NULL ) )
    82         {
    83                 irc_reply( irc, 433, "%s :This nick is already in use", cmd[1] );
     75        if( irc_user_by_name( irc, cmd[1] ) )
     76        {
     77                irc_send_num( irc, 433, ":This nick is already in use" );
    8478        }
    8579        else if( !nick_ok( cmd[1] ) )
    8680        {
    8781                /* [SH] Invalid characters. */
    88                 irc_reply( irc, 432, "%s :This nick contains invalid characters", cmd[1] );
    89         }
    90         else if(irc->nick)
    91         {
    92                 if( user_find( irc, irc->nick ) )
    93                         user_rename(irc, irc->nick, cmd[1]);
    94 
    95                 irc_write( irc, ":%s!%s@%s NICK %s", irc->nick, irc->user, irc->host, cmd[1] );
    96                 g_free(irc->nick);
    97                 irc->nick = g_strdup( cmd[1] );
    98         }
    99         else
    100         {
    101                 irc->nick = g_strdup( cmd[1] );
     82                irc_send_num( irc, 432, ":This nick contains invalid characters" );
     83        }
     84        else if( irc->user->nick )
     85        {
     86                if( irc->status & USTATUS_IDENTIFIED )
     87                {
     88                        irc_setpass( irc, NULL );
     89                        irc->status &= ~USTATUS_IDENTIFIED;
     90                        irc_umode_set( irc, "-R", 1 );
     91                        irc_usermsg( irc, "Changing nicks resets your identify status. "
     92                                     "Re-identify or register a new account if you want "
     93                                     "your configuration to be saved. See \x02help "
     94                                     "nick_changes\x02." );
     95                }
     96               
     97                irc_user_set_nick( irc->user, cmd[1] );
     98        }
     99        else
     100        {
     101                irc->user->nick = g_strdup( cmd[1] );
    102102               
    103103                irc_check_login( irc );
     
    115115static void irc_cmd_ping( irc_t *irc, char **cmd )
    116116{
    117         irc_write( irc, ":%s PONG %s :%s", irc->myhost, irc->myhost, cmd[1]?cmd[1]:irc->myhost );
    118 }
     117        irc_write( irc, ":%s PONG %s :%s", irc->root->host,
     118                   irc->root->host, cmd[1]?cmd[1]:irc->root->host );
     119}
     120
     121static void irc_cmd_pong( irc_t *irc, char **cmd )
     122{
     123        /* We could check the value we get back from the user, but in
     124           fact we don't care, we're just happy s/he's still alive. */
     125        irc->last_pong = gettime();
     126        irc->pinging = 0;
     127}
     128
     129static void irc_cmd_join( irc_t *irc, char **cmd )
     130{
     131        irc_channel_t *ic;
     132       
     133        if( ( ic = irc_channel_by_name( irc, cmd[1] ) ) == NULL )
     134                ic = irc_channel_new( irc, cmd[1] );
     135       
     136        if( ic == NULL )
     137        {
     138                irc_send_num( irc, 479, "%s :Invalid channel name", cmd[1] );
     139                return;
     140        }
     141       
     142        if( ic->flags & IRC_CHANNEL_JOINED )
     143                return; /* Dude, you're already there...
     144                           RFC doesn't have any reply for that though? */
     145       
     146        if( ic->f->join && !ic->f->join( ic ) )
     147                /* The story is: FALSE either means the handler showed an error
     148                   message, or is doing some work before the join should be
     149                   confirmed. (In the latter case, the caller should take care
     150                   of that confirmation.)
     151                   TRUE means all's good, let the user join the channel right away. */
     152                return;
     153       
     154        irc_channel_add_user( ic, irc->user );
     155}
     156
     157static void irc_cmd_names( irc_t *irc, char **cmd )
     158{
     159        irc_channel_t *ic;
     160       
     161        if( cmd[1] && ( ic = irc_channel_by_name( irc, cmd[1] ) ) )
     162                irc_send_names( ic );
     163        /* With no args, we should show /names of all chans. Make the code
     164           below work well if necessary.
     165        else
     166        {
     167                GSList *l;
     168               
     169                for( l = irc->channels; l; l = l->next )
     170                        irc_send_names( l->data );
     171        }
     172        */
     173}
     174
     175static void irc_cmd_part( irc_t *irc, char **cmd )
     176{
     177        irc_channel_t *ic;
     178       
     179        if( ( ic = irc_channel_by_name( irc, cmd[1] ) ) == NULL )
     180        {
     181                irc_send_num( irc, 403, "%s :No such channel", cmd[1] );
     182        }
     183        else if( irc_channel_del_user( ic, irc->user, FALSE, cmd[2] ) )
     184        {
     185                if( ic->f->part )
     186                        ic->f->part( ic, NULL );
     187        }
     188        else
     189        {
     190                irc_send_num( irc, 442, "%s :You're not on that channel", cmd[1] );
     191        }
     192}
     193
     194static void irc_cmd_whois( irc_t *irc, char **cmd )
     195{
     196        char *nick = cmd[1];
     197        irc_user_t *iu = irc_user_by_name( irc, nick );
     198       
     199        if( iu )
     200                irc_send_whois( iu );
     201        else
     202                irc_send_num( irc, 401, "%s :Nick does not exist", nick );
     203}
     204
     205static void irc_cmd_whowas( irc_t *irc, char **cmd )
     206{
     207        /* For some reason irssi tries a whowas when whois fails. We can
     208           ignore this, but then the user never gets a "user not found"
     209           message from irssi which is a bit annoying. So just respond
     210           with not-found and irssi users will get better error messages */
     211       
     212        irc_send_num( irc, 406, "%s :Nick does not exist", cmd[1] );
     213        irc_send_num( irc, 369, "%s :End of WHOWAS", cmd[1] );
     214}
     215
     216static void irc_cmd_motd( irc_t *irc, char **cmd )
     217{
     218        irc_send_motd( irc );
     219}
     220
     221static void irc_cmd_mode( irc_t *irc, char **cmd )
     222{
     223        if( irc_channel_name_ok( cmd[1] ) )
     224        {
     225                irc_channel_t *ic;
     226               
     227                if( ( ic = irc_channel_by_name( irc, cmd[1] ) ) == NULL )
     228                        irc_send_num( irc, 403, "%s :No such channel", cmd[1] );
     229                else if( cmd[2] )
     230                {
     231                        if( *cmd[2] == '+' || *cmd[2] == '-' )
     232                                irc_send_num( irc, 477, "%s :Can't change channel modes", cmd[1] );
     233                        else if( *cmd[2] == 'b' )
     234                                irc_send_num( irc, 368, "%s :No bans possible", cmd[1] );
     235                }
     236                else
     237                        irc_send_num( irc, 324, "%s +%s", cmd[1], ic->mode );
     238        }
     239        else
     240        {
     241                if( nick_cmp( cmd[1], irc->user->nick ) == 0 )
     242                {
     243                        if( cmd[2] )
     244                                irc_umode_set( irc, cmd[2], 0 );
     245                        else
     246                                irc_send_num( irc, 221, "+%s", irc->umode );
     247                }
     248                else
     249                        irc_send_num( irc, 502, ":Don't touch their modes" );
     250        }
     251}
     252
     253static void irc_cmd_who( irc_t *irc, char **cmd )
     254{
     255        char *channel = cmd[1];
     256        irc_channel_t *ic;
     257       
     258        if( !channel || *channel == '0' || *channel == '*' || !*channel )
     259                irc_send_who( irc, irc->users, "**" );
     260        else if( ( ic = irc_channel_by_name( irc, channel ) ) )
     261                irc_send_who( irc, ic->users, channel );
     262        else
     263                irc_send_num( irc, 403, "%s :No such channel", channel );
     264}
     265
     266static void irc_cmd_privmsg( irc_t *irc, char **cmd )
     267{
     268        irc_channel_t *ic;
     269        irc_user_t *iu;
     270       
     271        if( !cmd[2] )
     272        {
     273                irc_send_num( irc, 412, ":No text to send" );
     274                return;
     275        }
     276       
     277        /* Don't treat CTCP actions as real CTCPs, just convert them right now. */
     278        if( g_strncasecmp( cmd[2], "\001ACTION", 7 ) == 0 )
     279        {
     280                cmd[2] += 4;
     281                strcpy( cmd[2], "/me" );
     282                if( cmd[2][strlen(cmd[2])-1] == '\001' )
     283                        cmd[2][strlen(cmd[2])-1] = '\0';
     284        }
     285       
     286        if( irc_channel_name_ok( cmd[1] ) &&
     287            ( ic = irc_channel_by_name( irc, cmd[1] ) ) )
     288        {
     289                if( ic->f->privmsg )
     290                        ic->f->privmsg( ic, cmd[2] );
     291        }
     292        else if( ( iu = irc_user_by_name( irc, cmd[1] ) ) )
     293        {
     294                if( cmd[2][0] == '\001' )
     295                {
     296                        char **ctcp;
     297                       
     298                        if( iu->f->ctcp == NULL )
     299                                return;
     300                        if( cmd[2][strlen(cmd[2])-1] == '\001' )
     301                                cmd[2][strlen(cmd[2])-1] = '\0';
     302                       
     303                        ctcp = split_command_parts( cmd[2] + 1 );
     304                        iu->f->ctcp( iu, ctcp );
     305                }
     306                else if( iu->f->privmsg )
     307                {
     308                        iu->flags |= IRC_USER_PRIVATE;
     309                        iu->f->privmsg( iu, cmd[2] );
     310                }
     311        }
     312        else
     313        {
     314                irc_send_num( irc, 401, "%s :No such nick/channel", cmd[1] );
     315        }
     316}
     317
     318static void irc_cmd_nickserv( irc_t *irc, char **cmd )
     319{
     320        /* [SH] This aliases the NickServ command to PRIVMSG root */
     321        /* [TV] This aliases the NS command to PRIVMSG root as well */
     322        root_command( irc, cmd + 1 );
     323}
     324
     325
    119326
    120327static void irc_cmd_oper( irc_t *irc, char **cmd )
     
    126333        {
    127334                irc_umode_set( irc, "+o", 1 );
    128                 irc_reply( irc, 381, ":Password accepted" );
    129         }
    130         else
    131         {
    132                 irc_reply( irc, 432, ":Incorrect password" );
    133         }
    134 }
    135 
    136 static void irc_cmd_mode( irc_t *irc, char **cmd )
    137 {
    138         if( strchr( CTYPES, *cmd[1] ) )
    139         {
    140                 if( cmd[2] )
    141                 {
    142                         if( *cmd[2] == '+' || *cmd[2] == '-' )
    143                                 irc_reply( irc, 477, "%s :Can't change channel modes", cmd[1] );
    144                         else if( *cmd[2] == 'b' )
    145                                 irc_reply( irc, 368, "%s :No bans possible", cmd[1] );
    146                 }
    147                 else
    148                         irc_reply( irc, 324, "%s +%s", cmd[1], CMODE );
    149         }
    150         else
    151         {
    152                 if( nick_cmp( cmd[1], irc->nick ) == 0 )
    153                 {
    154                         if( cmd[2] )
    155                                 irc_umode_set( irc, cmd[2], 0 );
    156                         else
    157                                 irc_reply( irc, 221, "+%s", irc->umode );
    158                 }
    159                 else
    160                         irc_reply( irc, 502, ":Don't touch their modes" );
    161         }
    162 }
    163 
    164 static void irc_cmd_names( irc_t *irc, char **cmd )
    165 {
    166         irc_names( irc, cmd[1]?cmd[1]:irc->channel );
    167 }
    168 
    169 static void irc_cmd_part( irc_t *irc, char **cmd )
    170 {
    171         struct groupchat *c;
    172        
    173         if( g_strcasecmp( cmd[1], irc->channel ) == 0 )
    174         {
    175                 user_t *u = user_find( irc, irc->nick );
    176                
    177                 /* Not allowed to leave control channel */
    178                 irc_part( irc, u, irc->channel );
    179                 irc_join( irc, u, irc->channel );
    180         }
    181         else if( ( c = irc_chat_by_channel( irc, cmd[1] ) ) )
    182         {
    183                 user_t *u = user_find( irc, irc->nick );
    184                
    185                 irc_part( irc, u, c->channel );
    186                
    187                 if( c->ic )
    188                 {
    189                         c->joined = 0;
    190                         c->ic->acc->prpl->chat_leave( c );
    191                 }
    192         }
    193         else
    194         {
    195                 irc_reply( irc, 403, "%s :No such channel", cmd[1] );
    196         }
    197 }
    198 
    199 static void irc_cmd_join( irc_t *irc, char **cmd )
    200 {
    201         if( g_strcasecmp( cmd[1], irc->channel ) == 0 )
    202                 ; /* Dude, you're already there...
    203                      RFC doesn't have any reply for that though? */
    204         else if( cmd[1] )
    205         {
    206                 struct chat *c;
    207                
    208                 if( strchr( CTYPES, cmd[1][0] ) == NULL || cmd[1][1] == 0 )
    209                         irc_reply( irc, 479, "%s :Invalid channel name", cmd[1] );
    210                 else if( ( c = chat_bychannel( irc, cmd[1] ) ) && c->acc && c->acc->ic )
    211                         chat_join( irc, c, cmd[2] );
    212                 else
    213                         irc_reply( irc, 403, "%s :No such channel", cmd[1] );
     335                irc_send_num( irc, 381, ":Password accepted" );
     336        }
     337        else
     338        {
     339                irc_send_num( irc, 432, ":Incorrect password" );
    214340        }
    215341}
     
    217343static void irc_cmd_invite( irc_t *irc, char **cmd )
    218344{
    219         char *nick = cmd[1], *channel = cmd[2];
    220         struct groupchat *c = irc_chat_by_channel( irc, channel );
    221         user_t *u = user_find( irc, nick );
    222        
    223         if( u && c && ( u->ic == c->ic ) )
    224                 if( c->ic && c->ic->acc->prpl->chat_invite )
    225                 {
    226                         c->ic->acc->prpl->chat_invite( c, u->handle, NULL );
    227                         irc_reply( irc, 341, "%s %s", nick, channel );
    228                         return;
    229                 }
    230        
    231         irc_reply( irc, 482, "%s :Invite impossible; User/Channel non-existent or incompatible", channel );
    232 }
    233 
    234 static void irc_cmd_privmsg( irc_t *irc, char **cmd )
    235 {
    236         if ( !cmd[2] )
    237         {
    238                 irc_reply( irc, 412, ":No text to send" );
    239         }
    240         else if ( irc->nick && g_strcasecmp( cmd[1], irc->nick ) == 0 )
    241         {
    242                 irc_write( irc, ":%s!%s@%s %s %s :%s", irc->nick, irc->user, irc->host, cmd[0], cmd[1], cmd[2] );
    243         }
    244         else
    245         {
    246                 if( g_strcasecmp( cmd[1], irc->channel ) == 0 )
    247                 {
    248                         unsigned int i;
    249                         char *t = set_getstr( &irc->set, "default_target" );
    250                        
    251                         if( g_strcasecmp( t, "last" ) == 0 && irc->last_target )
    252                                 cmd[1] = irc->last_target;
    253                         else if( g_strcasecmp( t, "root" ) == 0 )
    254                                 cmd[1] = irc->mynick;
    255                        
    256                         for( i = 0; i < strlen( cmd[2] ); i ++ )
    257                         {
    258                                 if( cmd[2][i] == ' ' ) break;
    259                                 if( cmd[2][i] == ':' || cmd[2][i] == ',' )
    260                                 {
    261                                         cmd[1] = cmd[2];
    262                                         cmd[2] += i;
    263                                         *cmd[2] = 0;
    264                                         while( *(++cmd[2]) == ' ' );
    265                                         break;
    266                                 }
    267                         }
    268                        
    269                         irc->is_private = 0;
    270                        
    271                         if( cmd[1] != irc->last_target )
    272                         {
    273                                 g_free( irc->last_target );
    274                                 irc->last_target = g_strdup( cmd[1] );
    275                         }
    276                 }
    277                 else
    278                 {
    279                         irc->is_private = 1;
    280                 }
    281                 irc_send( irc, cmd[1], cmd[2], ( g_strcasecmp( cmd[0], "NOTICE" ) == 0 ) ? OPT_AWAY : 0 );
    282         }
    283 }
    284 
    285 static void irc_cmd_who( irc_t *irc, char **cmd )
    286 {
    287         char *channel = cmd[1];
    288         user_t *u = irc->users;
    289         struct groupchat *c;
    290         GList *l;
    291        
    292         if( !channel || *channel == '0' || *channel == '*' || !*channel )
    293                 while( u )
    294                 {
    295                         irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", u->online ? irc->channel : "*", u->user, u->host, irc->myhost, u->nick, u->online ? ( u->away ? 'G' : 'H' ) : 'G', u->realname );
    296                         u = u->next;
    297                 }
    298         else if( g_strcasecmp( channel, irc->channel ) == 0 )
    299                 while( u )
    300                 {
    301                         if( u->online )
    302                                 irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->away ? 'G' : 'H', u->realname );
    303                         u = u->next;
    304                 }
    305         else if( ( c = irc_chat_by_channel( irc, channel ) ) )
    306                 for( l = c->in_room; l; l = l->next )
    307                 {
    308                         if( ( u = user_findhandle( c->ic, l->data ) ) )
    309                                 irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->away ? 'G' : 'H', u->realname );
    310                 }
    311         else if( ( u = user_find( irc, channel ) ) )
    312                 irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->online ? ( u->away ? 'G' : 'H' ) : 'G', u->realname );
    313        
    314         irc_reply( irc, 315, "%s :End of /WHO list", channel?channel:"**" );
     345        irc_channel_t *ic;
     346        irc_user_t *iu;
     347       
     348        if( ( iu = irc_user_by_name( irc, cmd[1] ) ) == NULL )
     349        {
     350                irc_send_num( irc, 401, "%s :No such nick", cmd[1] );
     351                return;
     352        }
     353        else if( ( ic = irc_channel_by_name( irc, cmd[2] ) ) == NULL )
     354        {
     355                irc_send_num( irc, 403, "%s :No such channel", cmd[2] );
     356                return;
     357        }
     358       
     359        if( !ic->f->invite )
     360                irc_send_num( irc, 482, "%s :Can't invite people here", cmd[2] );
     361        else if( ic->f->invite( ic, iu ) )
     362                irc_send_num( irc, 341, "%s %s", iu->nick, ic->name );
    315363}
    316364
    317365static void irc_cmd_userhost( irc_t *irc, char **cmd )
    318366{
    319         user_t *u;
    320367        int i;
    321368       
     
    327374       
    328375        for( i = 1; cmd[i]; i ++ )
    329                 if( ( u = user_find( irc, cmd[i] ) ) )
    330                 {
    331                         if( u->online && u->away )
    332                                 irc_reply( irc, 302, ":%s=-%s@%s", u->nick, u->user, u->host );
    333                         else
    334                                 irc_reply( irc, 302, ":%s=+%s@%s", u->nick, u->user, u->host );
    335                 }
     376        {
     377                irc_user_t *iu = irc_user_by_name( irc, cmd[i] );
     378               
     379                if( iu )
     380                        irc_send_num( irc, 302, ":%s=%c%s@%s", iu->nick,
     381                                      irc_user_get_away( iu ) ? '-' : '+',
     382                                      iu->user, iu->host );
     383        }
    336384}
    337385
    338386static void irc_cmd_ison( irc_t *irc, char **cmd )
    339387{
    340         user_t *u;
    341388        char buff[IRC_MAX_LINE];
    342389        int lenleft, i;
     
    354401                while( *this )
    355402                {
     403                        irc_user_t *iu;
     404                       
    356405                        if( ( next = strchr( this, ' ' ) ) )
    357406                                *next = 0;
    358407                       
    359                         if( ( u = user_find( irc, this ) ) && u->online )
    360                         {
    361                                 lenleft -= strlen( u->nick ) + 1;
     408                        if( ( iu = irc_user_by_name( irc, this ) ) &&
     409                            iu->bu && iu->bu->flags & BEE_USER_ONLINE )
     410                        {
     411                                lenleft -= strlen( iu->nick ) + 1;
    362412                               
    363413                                if( lenleft < 0 )
    364414                                        break;
    365415                               
    366                                 strcat( buff, u->nick );
     416                                strcat( buff, iu->nick );
    367417                                strcat( buff, " " );
    368418                        }
     
    387437                buff[strlen(buff)-1] = '\0';
    388438       
    389         irc_reply( irc, 303, ":%s", buff );
     439        irc_send_num( irc, 303, ":%s", buff );
    390440}
    391441
     
    400450        {
    401451                char *nick;
    402                 user_t *u;
     452                irc_user_t *iu;
    403453               
    404454                if( !cmd[i][0] || !cmd[i][1] )
     
    408458                nick_lc( nick );
    409459               
    410                 u = user_find( irc, nick );
     460                iu = irc_user_by_name( irc, nick );
    411461               
    412462                if( cmd[i][0] == '+' )
     
    415465                                g_hash_table_insert( irc->watches, nick, nick );
    416466                       
    417                         if( u && u->online )
    418                                 irc_reply( irc, 604, "%s %s %s %d :%s", u->nick, u->user, u->host, (int) time( NULL ), "is online" );
     467                        if( iu && iu->bu && iu->bu->flags & BEE_USER_ONLINE )
     468                                irc_send_num( irc, 604, "%s %s %s %d :%s", iu->nick, iu->user,
     469                                              iu->host, (int) time( NULL ), "is online" );
    419470                        else
    420                                 irc_reply( irc, 605, "%s %s %s %d :%s", nick, "*", "*", (int) time( NULL ), "is offline" );
     471                                irc_send_num( irc, 605, "%s %s %s %d :%s", nick, "*", "*",
     472                                              (int) time( NULL ), "is offline" );
    421473                }
    422474                else if( cmd[i][0] == '-' )
     
    429481                                g_free( okey );
    430482                               
    431                                 irc_reply( irc, 602, "%s %s %s %d :%s", nick, "*", "*", 0, "Stopped watching" );
     483                                irc_send_num( irc, 602, "%s %s %s %d :%s", nick, "*", "*", 0, "Stopped watching" );
    432484                        }
    433485                }
     
    437489static void irc_cmd_topic( irc_t *irc, char **cmd )
    438490{
    439         char *channel = cmd[1];
    440         char *topic = cmd[2];
    441        
    442         if( topic )
    443         {
    444                 /* Send the topic */
    445                 struct groupchat *c = irc_chat_by_channel( irc, channel );
    446                 if( c && c->ic && c->ic->acc->prpl->chat_topic )
    447                         c->ic->acc->prpl->chat_topic( c, topic );
    448         }
    449         else
    450         {
    451                 /* Get the topic */
    452                 irc_topic( irc, channel );
     491        irc_channel_t *ic = irc_channel_by_name( irc, cmd[1] );
     492        const char *new = cmd[2];
     493       
     494        if( ic == NULL )
     495        {
     496                irc_send_num( irc, 403, "%s :No such channel", cmd[1] );
     497        }
     498        else if( new )
     499        {
     500                if( ic->f->topic == NULL )
     501                        irc_send_num( irc, 482, "%s :Can't change this channel's topic", ic->name );
     502                else if( ic->f->topic( ic, new ) )
     503                        irc_send_topic( ic, TRUE );
     504        }
     505        else
     506        {
     507                irc_send_topic( ic, FALSE );
    453508        }
    454509}
     
    456511static void irc_cmd_away( irc_t *irc, char **cmd )
    457512{
    458         user_t *u = user_find( irc, irc->nick );
    459         char *away = cmd[1];
    460        
    461         if( !u ) return;
    462        
    463         if( away && *away )
    464         {
     513        if( cmd[1] && *cmd[1] )
     514        {
     515                char away[strlen(cmd[1])+1];
    465516                int i, j;
    466517               
    467518                /* Copy away string, but skip control chars. Mainly because
    468519                   Jabber really doesn't like them. */
    469                 u->away = g_malloc( strlen( away ) + 1 );
    470                 for( i = j = 0; away[i]; i ++ )
    471                         if( ( u->away[j] = away[i] ) >= ' ' )
     520                for( i = j = 0; cmd[1][i]; i ++ )
     521                        if( ( away[j] = cmd[1][i] ) >= ' ' )
    472522                                j ++;
    473                 u->away[j] = 0;
    474                
    475                 irc_reply( irc, 306, ":You're now away: %s", u->away );
    476                 /* irc_umode_set( irc, irc->myhost, "+a" ); */
    477         }
    478         else
    479         {
    480                 if( u->away ) g_free( u->away );
    481                 u->away = NULL;
    482                 /* irc_umode_set( irc, irc->myhost, "-a" ); */
    483                 irc_reply( irc, 305, ":Welcome back" );
    484         }
    485        
    486         set_setstr( &irc->set, "away", u->away );
    487 }
    488 
    489 static void irc_cmd_whois( irc_t *irc, char **cmd )
    490 {
    491         char *nick = cmd[1];
    492         user_t *u = user_find( irc, nick );
    493        
    494         if( u )
    495         {
    496                 irc_reply( irc, 311, "%s %s %s * :%s", u->nick, u->user, u->host, u->realname );
    497                
    498                 if( u->ic )
    499                         irc_reply( irc, 312, "%s %s.%s :%s network", u->nick, u->ic->acc->user,
    500                                    u->ic->acc->server && *u->ic->acc->server ? u->ic->acc->server : "",
    501                                    u->ic->acc->prpl->name );
    502                 else
    503                         irc_reply( irc, 312, "%s %s :%s", u->nick, irc->myhost, IRCD_INFO );
    504                
    505                 if( !u->online )
    506                         irc_reply( irc, 301, "%s :%s", u->nick, "User is offline" );
    507                 else if( u->away )
    508                         irc_reply( irc, 301, "%s :%s", u->nick, u->away );
    509                 if( u->status_msg )
    510                         irc_reply( irc, 320, "%s :%s", u->nick, u->status_msg );
    511                
    512                 irc_reply( irc, 318, "%s :End of /WHOIS list", nick );
    513         }
    514         else
    515         {
    516                 irc_reply( irc, 401, "%s :Nick does not exist", nick );
    517         }
    518 }
    519 
    520 static void irc_cmd_whowas( irc_t *irc, char **cmd )
    521 {
    522         /* For some reason irssi tries a whowas when whois fails. We can
    523            ignore this, but then the user never gets a "user not found"
    524            message from irssi which is a bit annoying. So just respond
    525            with not-found and irssi users will get better error messages */
    526        
    527         irc_reply( irc, 406, "%s :Nick does not exist", cmd[1] );
    528         irc_reply( irc, 369, "%s :End of WHOWAS", cmd[1] );
    529 }
    530 
    531 static void irc_cmd_nickserv( irc_t *irc, char **cmd )
    532 {
    533         /* [SH] This aliases the NickServ command to PRIVMSG root */
    534         /* [TV] This aliases the NS command to PRIVMSG root as well */
    535         root_command( irc, cmd + 1 );
    536 }
    537 
    538 static void irc_cmd_motd( irc_t *irc, char **cmd )
    539 {
    540         irc_motd( irc );
    541 }
    542 
    543 static void irc_cmd_pong( irc_t *irc, char **cmd )
    544 {
    545         /* We could check the value we get back from the user, but in
    546            fact we don't care, we're just happy he's still alive. */
    547         irc->last_pong = gettime();
    548         irc->pinging = 0;
     523                away[j] = '\0';
     524               
     525                irc_send_num( irc, 306, ":You're now away: %s", away );
     526                set_setstr( &irc->b->set, "away", away );
     527        }
     528        else
     529        {
     530                irc_send_num( irc, 305, ":Welcome back" );
     531                set_setstr( &irc->b->set, "away", NULL );
     532        }
    549533}
    550534
    551535static void irc_cmd_version( irc_t *irc, char **cmd )
    552536{
    553         irc_reply( irc, 351, "bitlbee-%s. %s :%s/%s ", BITLBEE_VERSION, irc->myhost, ARCH, CPU );
     537        irc_send_num( irc, 351, "bitlbee-%s. %s :%s/%s ",
     538                      BITLBEE_VERSION, irc->root->host, ARCH, CPU );
    554539}
    555540
    556541static void irc_cmd_completions( irc_t *irc, char **cmd )
    557542{
    558         user_t *u = user_find( irc, irc->mynick );
    559543        help_t *h;
    560544        set_t *s;
    561545        int i;
    562546       
    563         irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", "OK" );
     547        irc_send_msg_raw( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS OK" );
    564548       
    565549        for( i = 0; commands[i].command; i ++ )
    566                 irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", commands[i].command );
     550                irc_send_msg_f( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS %s", commands[i].command );
    567551       
    568552        for( h = global.help; h; h = h->next )
    569                 irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS help ", h->title );
    570        
    571         for( s = irc->set; s; s = s->next )
    572                 irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS set ", s->key );
    573        
    574         irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", "END" );
     553                irc_send_msg_f( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS help %s", h->title );
     554       
     555        for( s = irc->b->set; s; s = s->next )
     556                irc_send_msg_f( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS set %s", s->key );
     557       
     558        irc_send_msg_raw( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS END" );
    575559}
    576560
     
    582566                ipc_to_master( cmd );
    583567       
    584         irc_reply( irc, 382, "%s :Rehashing", global.conf_file );
     568        irc_send_num( irc, 382, "%s :Rehashing", global.conf_file );
    585569}
    586570
     
    591575        { "quit",        0, irc_cmd_quit,        0 },
    592576        { "ping",        0, irc_cmd_ping,        0 },
    593         { "oper",        2, irc_cmd_oper,        IRC_CMD_LOGGED_IN },
     577        { "pong",        0, irc_cmd_pong,        IRC_CMD_LOGGED_IN },
     578        { "join",        1, irc_cmd_join,        IRC_CMD_LOGGED_IN },
     579        { "names",       1, irc_cmd_names,       IRC_CMD_LOGGED_IN },
     580        { "part",        1, irc_cmd_part,        IRC_CMD_LOGGED_IN },
     581        { "whois",       1, irc_cmd_whois,       IRC_CMD_LOGGED_IN },
     582        { "whowas",      1, irc_cmd_whowas,      IRC_CMD_LOGGED_IN },
     583        { "motd",        0, irc_cmd_motd,        IRC_CMD_LOGGED_IN },
    594584        { "mode",        1, irc_cmd_mode,        IRC_CMD_LOGGED_IN },
    595         { "names",       0, irc_cmd_names,       IRC_CMD_LOGGED_IN },
    596         { "part",        1, irc_cmd_part,        IRC_CMD_LOGGED_IN },
    597         { "join",        1, irc_cmd_join,        IRC_CMD_LOGGED_IN },
    598         { "invite",      2, irc_cmd_invite,      IRC_CMD_LOGGED_IN },
     585        { "who",         0, irc_cmd_who,         IRC_CMD_LOGGED_IN },
    599586        { "privmsg",     1, irc_cmd_privmsg,     IRC_CMD_LOGGED_IN },
    600         { "notice",      1, irc_cmd_privmsg,     IRC_CMD_LOGGED_IN },
    601         { "who",         0, irc_cmd_who,         IRC_CMD_LOGGED_IN },
     587        { "nickserv",    1, irc_cmd_nickserv,    IRC_CMD_LOGGED_IN },
     588        { "ns",          1, irc_cmd_nickserv,    IRC_CMD_LOGGED_IN },
     589        { "away",        0, irc_cmd_away,        IRC_CMD_LOGGED_IN },
     590        { "version",     0, irc_cmd_version,     IRC_CMD_LOGGED_IN },
     591        { "completions", 0, irc_cmd_completions, IRC_CMD_LOGGED_IN },
    602592        { "userhost",    1, irc_cmd_userhost,    IRC_CMD_LOGGED_IN },
    603593        { "ison",        1, irc_cmd_ison,        IRC_CMD_LOGGED_IN },
    604594        { "watch",       1, irc_cmd_watch,       IRC_CMD_LOGGED_IN },
     595        { "invite",      2, irc_cmd_invite,      IRC_CMD_LOGGED_IN },
     596#if 0
     597        { "notice",      1, irc_cmd_privmsg,     IRC_CMD_LOGGED_IN },
     598#endif
    605599        { "topic",       1, irc_cmd_topic,       IRC_CMD_LOGGED_IN },
    606         { "away",        0, irc_cmd_away,        IRC_CMD_LOGGED_IN },
    607         { "whois",       1, irc_cmd_whois,       IRC_CMD_LOGGED_IN },
    608         { "whowas",      1, irc_cmd_whowas,      IRC_CMD_LOGGED_IN },
    609         { "nickserv",    1, irc_cmd_nickserv,    IRC_CMD_LOGGED_IN },
    610         { "ns",          1, irc_cmd_nickserv,    IRC_CMD_LOGGED_IN },
    611         { "motd",        0, irc_cmd_motd,        IRC_CMD_LOGGED_IN },
    612         { "pong",        0, irc_cmd_pong,        IRC_CMD_LOGGED_IN },
    613         { "version",     0, irc_cmd_version,     IRC_CMD_LOGGED_IN },
    614         { "completions", 0, irc_cmd_completions, IRC_CMD_LOGGED_IN },
     600        { "oper",        2, irc_cmd_oper,        IRC_CMD_LOGGED_IN },
    615601        { "die",         0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
    616602        { "deaf",        0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
     
    638624                        if( irc_commands[i].flags & IRC_CMD_PRE_LOGIN && irc->status & USTATUS_LOGGED_IN )
    639625                        {
    640                                 irc_reply( irc, 462, ":Only allowed before logging in" );
     626                                irc_send_num( irc, 462, ":Only allowed before logging in" );
    641627                        }
    642628                        else if( irc_commands[i].flags & IRC_CMD_LOGGED_IN && !( irc->status & USTATUS_LOGGED_IN ) )
    643629                        {
    644                                 irc_reply( irc, 451, ":Register first" );
     630                                irc_send_num( irc, 451, ":Register first" );
    645631                        }
    646632                        else if( irc_commands[i].flags & IRC_CMD_OPER_ONLY && !strchr( irc->umode, 'o' ) )
    647633                        {
    648                                 irc_reply( irc, 481, ":Permission denied - You're not an IRC operator" );
     634                                irc_send_num( irc, 481, ":Permission denied - You're not an IRC operator" );
    649635                        }
    650636                        else if( n_arg < irc_commands[i].required_parameters )
    651637                        {
    652                                 irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
     638                                irc_send_num( irc, 461, "%s :Need more parameters", cmd[0] );
    653639                        }
    654640                        else if( irc_commands[i].flags & IRC_CMD_TO_MASTER )
     
    667653       
    668654        if( irc->status >= USTATUS_LOGGED_IN )
    669                 irc_reply( irc, 421, "%s :Unknown command", cmd[0] );
    670 }
     655                irc_send_num( irc, 421, "%s :Unknown command", cmd[0] );
     656}
  • lib/Makefile

    r38ff846 r8b8def58  
    88
    99-include ../Makefile.settings
     10ifdef SRCDIR
     11SRCDIR := $(SRCDIR)lib/
     12endif
    1013
    1114# [SH] Program variables
    12 objects = arc.o base64.o $(EVENT_HANDLER) http_client.o ini.o md5.o misc.o oauth.o proxy.o sha1.o $(SSL_CLIENT) url.o xmltree.o
     15objects = arc.o base64.o $(EVENT_HANDLER) ftutil.o http_client.o ini.o md5.o misc.o oauth.o proxy.o sha1.o $(SSL_CLIENT) url.o xmltree.o
    1316
    1417CFLAGS += -Wall
     
    3740$(objects): ../Makefile.settings Makefile
    3841
    39 $(objects): %.o: %.c
     42$(objects): %.o: $(SRCDIR)%.c
    4043        @echo '*' Compiling $<
    4144        @$(CC) -c $(CFLAGS) $< -o $@
  • lib/events.h

    r38ff846 r8b8def58  
    4848   the given callback function. */
    4949typedef enum {
    50         GAIM_INPUT_READ = 1 << 1,
    51         GAIM_INPUT_WRITE = 1 << 2
     50        B_EV_IO_READ = 1 << 0,
     51        B_EV_IO_WRITE = 1 << 1,
     52        B_EV_FLAG_FORCE_ONCE = 1 << 16,
     53        B_EV_FLAG_FORCE_REPEAT = 1 << 17,
    5254} b_input_condition;
    5355typedef gboolean (*b_event_handler)(gpointer data, gint fd, b_input_condition cond);
  • lib/events_glib.c

    r38ff846 r8b8def58  
    4949        b_event_handler function;
    5050        gpointer data;
     51        guint flags;
    5152} GaimIOClosure;
    5253
     
    7677
    7778        if (condition & GAIM_READ_COND)
    78                 gaim_cond |= GAIM_INPUT_READ;
     79                gaim_cond |= B_EV_IO_READ;
    7980        if (condition & GAIM_WRITE_COND)
    80                 gaim_cond |= GAIM_INPUT_WRITE;
     81                gaim_cond |= B_EV_IO_WRITE;
    8182       
    8283        event_debug( "gaim_io_invoke( %d, %d, 0x%x )\n", g_io_channel_unix_get_fd(source), condition, data );
     
    8788                event_debug( "Returned FALSE, cancelling.\n" );
    8889       
    89         return st;
     90        if (closure->flags & B_EV_FLAG_FORCE_ONCE)
     91                return FALSE;
     92        else if (closure->flags & B_EV_FLAG_FORCE_REPEAT)
     93                return TRUE;
     94        else
     95                return st;
    9096}
    9197
     
    105111        closure->function = function;
    106112        closure->data = data;
     113        closure->flags = condition;
    107114       
    108         if (condition & GAIM_INPUT_READ)
     115        if (condition & B_EV_IO_READ)
    109116                cond |= GAIM_READ_COND;
    110         if (condition & GAIM_INPUT_WRITE)
     117        if (condition & B_EV_IO_WRITE)
    111118                cond |= GAIM_WRITE_COND;
    112119       
  • lib/events_libevent.c

    r38ff846 r8b8def58  
    6060        b_event_handler function;
    6161        void *data;
     62        guint flags;
    6263};
    6364
     
    126127        {
    127128                if( event & EV_READ )
    128                         cond |= GAIM_INPUT_READ;
     129                        cond |= B_EV_IO_READ;
    129130                if( event & EV_WRITE )
    130                         cond |= GAIM_INPUT_WRITE;
     131                        cond |= B_EV_IO_WRITE;
    131132        }
    132133       
     
    150151                return;
    151152        }
    152         else if( !st )
     153        else if( !st && !( b_ev->flags & B_EV_FLAG_FORCE_REPEAT ) )
    153154        {
    154155                event_debug( "Handler returned FALSE: " );
     
    174175        event_debug( "b_input_add( %d, %d, 0x%x, 0x%x ) ", fd, condition, function, data );
    175176       
    176         if( ( condition & GAIM_INPUT_READ  && ( b_ev = g_hash_table_lookup( read_hash,  &fd ) ) ) ||
    177             ( condition & GAIM_INPUT_WRITE && ( b_ev = g_hash_table_lookup( write_hash, &fd ) ) ) )
     177        if( ( condition & B_EV_IO_READ  && ( b_ev = g_hash_table_lookup( read_hash,  &fd ) ) ) ||
     178            ( condition & B_EV_IO_WRITE && ( b_ev = g_hash_table_lookup( write_hash, &fd ) ) ) )
    178179        {
    179180                /* We'll stick with this libevent entry, but give it a new BitlBee id. */
     
    198199               
    199200                out_cond = EV_PERSIST;
    200                 if( condition & GAIM_INPUT_READ )
     201                if( condition & B_EV_IO_READ )
    201202                        out_cond |= EV_READ;
    202                 if( condition & GAIM_INPUT_WRITE )
     203                if( condition & B_EV_IO_WRITE )
    203204                        out_cond |= EV_WRITE;
    204205               
     
    212213        }
    213214       
     215        b_ev->flags = condition;
    214216        g_hash_table_insert( id_hash, &b_ev->id, b_ev );
    215217        return b_ev->id;
  • lib/http_client.c

    r38ff846 r8b8def58  
    149149        if( req->bytes_written < req->request_length )
    150150                req->inpa = b_input_add( source,
    151                                          req->ssl ? ssl_getdirection( req->ssl ) : GAIM_INPUT_WRITE,
     151                                         req->ssl ? ssl_getdirection( req->ssl ) : B_EV_IO_WRITE,
    152152                                         http_connected, req );
    153153        else
    154                 req->inpa = b_input_add( source, GAIM_INPUT_READ, http_incoming_data, req );
     154                req->inpa = b_input_add( source, B_EV_IO_READ, http_incoming_data, req );
    155155       
    156156        return FALSE;
     
    234234        /* There will be more! */
    235235        req->inpa = b_input_add( req->fd,
    236                                  req->ssl ? ssl_getdirection( req->ssl ) : GAIM_INPUT_READ,
     236                                 req->ssl ? ssl_getdirection( req->ssl ) : B_EV_IO_READ,
    237237                                 http_incoming_data, req );
    238238       
  • lib/misc.c

    r38ff846 r8b8def58  
    647647        return ret;
    648648}
     649
     650char **split_command_parts( char *command )
     651{
     652        static char *cmd[IRC_MAX_ARGS+1];
     653        char *s, q = 0;
     654        int k;
     655       
     656        memset( cmd, 0, sizeof( cmd ) );
     657        cmd[0] = command;
     658        k = 1;
     659        for( s = command; *s && k < IRC_MAX_ARGS; s ++ )
     660                if( *s == ' ' && !q )
     661                {
     662                        *s = 0;
     663                        while( *++s == ' ' );
     664                        if( *s == '"' || *s == '\'' )
     665                        {
     666                                q = *s;
     667                                s ++;
     668                        }
     669                        if( *s )
     670                        {
     671                                cmd[k++] = s;
     672                                s --;
     673                        }
     674                        else
     675                        {
     676                                break;
     677                        }
     678                }
     679                else if( *s == '\\' && ( ( !q && s[1] ) || ( q && q == s[1] ) ) )
     680                {
     681                        char *cpy;
     682                       
     683                        for( cpy = s; *cpy; cpy ++ )
     684                                cpy[0] = cpy[1];
     685                }
     686                else if( *s == q )
     687                {
     688                        q = *s = 0;
     689                }
     690       
     691        /* Full zero-padding for easier argc checking. */
     692        while( k <= IRC_MAX_ARGS )
     693                cmd[k++] = NULL;
     694       
     695        return cmd;
     696}
  • lib/misc.h

    r38ff846 r8b8def58  
    6969G_MODULE_EXPORT int md5_verify_password( char *password, char *hash );
    7070
     71G_MODULE_EXPORT char **split_command_parts( char *command );
     72
    7173#endif
  • lib/proxy.c

    r38ff846 r8b8def58  
    9191                b_event_remove(phb->inpa);
    9292                if( phb->proxy_func )
    93                         phb->proxy_func(phb->proxy_data, -1, GAIM_INPUT_READ);
     93                        phb->proxy_func(phb->proxy_data, -1, B_EV_IO_READ);
    9494                else {
    95                         phb->func(phb->data, -1, GAIM_INPUT_READ);
     95                        phb->func(phb->data, -1, B_EV_IO_READ);
    9696                        g_free(phb);
    9797                }
     
    102102        b_event_remove(phb->inpa);
    103103        if( phb->proxy_func )
    104                 phb->proxy_func(phb->proxy_data, source, GAIM_INPUT_READ);
     104                phb->proxy_func(phb->proxy_data, source, B_EV_IO_READ);
    105105        else {
    106                 phb->func(phb->data, source, GAIM_INPUT_READ);
     106                phb->func(phb->data, source, B_EV_IO_READ);
    107107                g_free(phb);
    108108        }
     
    147147                return -1;
    148148        } else {
    149                 phb->inpa = b_input_add(fd, GAIM_INPUT_WRITE, gaim_io_connected, phb);
     149                phb->inpa = b_input_add(fd, B_EV_IO_WRITE, gaim_io_connected, phb);
    150150                phb->fd = fd;
    151151               
     
    179179        if ((memcmp(HTTP_GOODSTRING, inputline, strlen(HTTP_GOODSTRING)) == 0) ||
    180180            (memcmp(HTTP_GOODSTRING2, inputline, strlen(HTTP_GOODSTRING2)) == 0)) {
    181                 phb->func(phb->data, source, GAIM_INPUT_READ);
     181                phb->func(phb->data, source, B_EV_IO_READ);
    182182                g_free(phb->host);
    183183                g_free(phb);
     
    186186
    187187        close(source);
    188         phb->func(phb->data, -1, GAIM_INPUT_READ);
     188        phb->func(phb->data, -1, B_EV_IO_READ);
    189189        g_free(phb->host);
    190190        g_free(phb);
     
    204204        if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
    205205                close(source);
    206                 phb->func(phb->data, -1, GAIM_INPUT_READ);
     206                phb->func(phb->data, -1, B_EV_IO_READ);
    207207                g_free(phb->host);
    208208                g_free(phb);
     
    215215        if (send(source, cmd, strlen(cmd), 0) < 0) {
    216216                close(source);
    217                 phb->func(phb->data, -1, GAIM_INPUT_READ);
     217                phb->func(phb->data, -1, B_EV_IO_READ);
    218218                g_free(phb->host);
    219219                g_free(phb);
     
    230230                if (send(source, cmd, strlen(cmd), 0) < 0) {
    231231                        close(source);
    232                         phb->func(phb->data, -1, GAIM_INPUT_READ);
     232                        phb->func(phb->data, -1, B_EV_IO_READ);
    233233                        g_free(phb->host);
    234234                        g_free(phb);
     
    240240        if (send(source, cmd, strlen(cmd), 0) < 0) {
    241241                close(source);
    242                 phb->func(phb->data, -1, GAIM_INPUT_READ);
    243                 g_free(phb->host);
    244                 g_free(phb);
    245                 return FALSE;
    246         }
    247 
    248         phb->inpa = b_input_add(source, GAIM_INPUT_READ, http_canread, phb);
     242                phb->func(phb->data, -1, B_EV_IO_READ);
     243                g_free(phb->host);
     244                g_free(phb);
     245                return FALSE;
     246        }
     247
     248        phb->inpa = b_input_add(source, B_EV_IO_READ, http_canread, phb);
    249249       
    250250        return FALSE;
     
    273273        memset(packet, 0, sizeof(packet));
    274274        if (read(source, packet, 9) >= 4 && packet[1] == 90) {
    275                 phb->func(phb->data, source, GAIM_INPUT_READ);
     275                phb->func(phb->data, source, B_EV_IO_READ);
    276276                g_free(phb->host);
    277277                g_free(phb);
     
    280280
    281281        close(source);
    282         phb->func(phb->data, -1, GAIM_INPUT_READ);
     282        phb->func(phb->data, -1, B_EV_IO_READ);
    283283        g_free(phb->host);
    284284        g_free(phb);
     
    299299        if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
    300300                close(source);
    301                 phb->func(phb->data, -1, GAIM_INPUT_READ);
     301                phb->func(phb->data, -1, B_EV_IO_READ);
    302302                g_free(phb->host);
    303303                g_free(phb);
     
    309309        if (!(hp = gethostbyname(phb->host))) {
    310310                close(source);
    311                 phb->func(phb->data, -1, GAIM_INPUT_READ);
     311                phb->func(phb->data, -1, B_EV_IO_READ);
    312312                g_free(phb->host);
    313313                g_free(phb);
     
    326326        if (write(source, packet, 9) != 9) {
    327327                close(source);
    328                 phb->func(phb->data, -1, GAIM_INPUT_READ);
    329                 g_free(phb->host);
    330                 g_free(phb);
    331                 return FALSE;
    332         }
    333 
    334         phb->inpa = b_input_add(source, GAIM_INPUT_READ, s4_canread, phb);
     328                phb->func(phb->data, -1, B_EV_IO_READ);
     329                g_free(phb->host);
     330                g_free(phb);
     331                return FALSE;
     332        }
     333
     334        phb->inpa = b_input_add(source, B_EV_IO_READ, s4_canread, phb);
    335335       
    336336        return FALSE;
     
    359359        if (read(source, buf, 10) < 10) {
    360360                close(source);
    361                 phb->func(phb->data, -1, GAIM_INPUT_READ);
     361                phb->func(phb->data, -1, B_EV_IO_READ);
    362362                g_free(phb->host);
    363363                g_free(phb);
     
    366366        if ((buf[0] != 0x05) || (buf[1] != 0x00)) {
    367367                close(source);
    368                 phb->func(phb->data, -1, GAIM_INPUT_READ);
    369                 g_free(phb->host);
    370                 g_free(phb);
    371                 return FALSE;
    372         }
    373 
    374         phb->func(phb->data, source, GAIM_INPUT_READ);
     368                phb->func(phb->data, -1, B_EV_IO_READ);
     369                g_free(phb->host);
     370                g_free(phb);
     371                return FALSE;
     372        }
     373
     374        phb->func(phb->data, source, B_EV_IO_READ);
    375375        g_free(phb->host);
    376376        g_free(phb);
     
    396396        if (write(source, buf, (5 + strlen(phb->host) + 2)) < (5 + strlen(phb->host) + 2)) {
    397397                close(source);
    398                 phb->func(phb->data, -1, GAIM_INPUT_READ);
     398                phb->func(phb->data, -1, B_EV_IO_READ);
    399399                g_free(phb->host);
    400400                g_free(phb);
     
    402402        }
    403403
    404         phb->inpa = b_input_add(source, GAIM_INPUT_READ, s5_canread_again, phb);
     404        phb->inpa = b_input_add(source, B_EV_IO_READ, s5_canread_again, phb);
    405405}
    406406
     
    414414        if (read(source, buf, 2) < 2) {
    415415                close(source);
    416                 phb->func(phb->data, -1, GAIM_INPUT_READ);
     416                phb->func(phb->data, -1, B_EV_IO_READ);
    417417                g_free(phb->host);
    418418                g_free(phb);
     
    422422        if ((buf[0] != 0x01) || (buf[1] != 0x00)) {
    423423                close(source);
    424                 phb->func(phb->data, -1, GAIM_INPUT_READ);
     424                phb->func(phb->data, -1, B_EV_IO_READ);
    425425                g_free(phb->host);
    426426                g_free(phb);
     
    442442        if (read(source, buf, 2) < 2) {
    443443                close(source);
    444                 phb->func(phb->data, -1, GAIM_INPUT_READ);
     444                phb->func(phb->data, -1, B_EV_IO_READ);
    445445                g_free(phb->host);
    446446                g_free(phb);
     
    450450        if ((buf[0] != 0x05) || (buf[1] == 0xff)) {
    451451                close(source);
    452                 phb->func(phb->data, -1, GAIM_INPUT_READ);
     452                phb->func(phb->data, -1, B_EV_IO_READ);
    453453                g_free(phb->host);
    454454                g_free(phb);
     
    465465                if (write(source, buf, 3 + i + j) < 3 + i + j) {
    466466                        close(source);
    467                         phb->func(phb->data, -1, GAIM_INPUT_READ);
     467                        phb->func(phb->data, -1, B_EV_IO_READ);
    468468                        g_free(phb->host);
    469469                        g_free(phb);
     
    471471                }
    472472
    473                 phb->inpa = b_input_add(source, GAIM_INPUT_READ, s5_readauth, phb);
     473                phb->inpa = b_input_add(source, B_EV_IO_READ, s5_readauth, phb);
    474474        } else {
    475475                s5_sendconnect(phb, source);
     
    491491        if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
    492492                close(source);
    493                 phb->func(phb->data, -1, GAIM_INPUT_READ);
     493                phb->func(phb->data, -1, B_EV_IO_READ);
    494494                g_free(phb->host);
    495495                g_free(phb);
     
    513513        if (write(source, buf, i) < i) {
    514514                close(source);
    515                 phb->func(phb->data, -1, GAIM_INPUT_READ);
    516                 g_free(phb->host);
    517                 g_free(phb);
    518                 return FALSE;
    519         }
    520 
    521         phb->inpa = b_input_add(source, GAIM_INPUT_READ, s5_canread, phb);
     515                phb->func(phb->data, -1, B_EV_IO_READ);
     516                g_free(phb->host);
     517                g_free(phb);
     518                return FALSE;
     519        }
     520
     521        phb->inpa = b_input_add(source, B_EV_IO_READ, s5_canread, phb);
    522522       
    523523        return FALSE;
  • lib/ssl_bogus.c

    r38ff846 r8b8def58  
    5959b_input_condition ssl_getdirection( void *conn )
    6060{
    61         return GAIM_INPUT_READ;
     61        return B_EV_IO_READ;
    6262}
    6363
  • lib/ssl_client.h

    r38ff846 r8b8def58  
    7171G_MODULE_EXPORT int ssl_getfd( void *conn );
    7272
    73 /* This function returns GAIM_INPUT_READ/WRITE. With SSL connections it's
     73/* This function returns B_EV_IO_READ/WRITE. With SSL connections it's
    7474   possible that something has to be read while actually were trying to
    7575   write something (think about key exchange/refresh/etc). So when an
  • lib/ssl_gnutls.c

    r38ff846 r8b8def58  
    106106        struct scd *conn = data;
    107107       
    108         return ssl_connected( conn, conn->fd, GAIM_INPUT_WRITE );
     108        return ssl_connected( conn, conn->fd, B_EV_IO_WRITE );
    109109}
    110110
     
    244244{
    245245        return( gnutls_record_get_direction( ((struct scd*)conn)->session ) ?
    246                 GAIM_INPUT_WRITE : GAIM_INPUT_READ );
    247 }
     246                B_EV_IO_WRITE : B_EV_IO_READ );
     247}
  • lib/ssl_nss.c

    r38ff846 r8b8def58  
    193193{
    194194        /* Just in case someone calls us, let's return the most likely case: */
    195         return GAIM_INPUT_READ;
     195        return B_EV_IO_READ;
    196196}
  • lib/ssl_openssl.c

    r38ff846 r8b8def58  
    102102        struct scd *conn = data;
    103103       
    104         return ssl_connected( conn, conn->fd, GAIM_INPUT_WRITE );
     104        return ssl_connected( conn, conn->fd, B_EV_IO_WRITE );
    105105}
    106106
     
    270270b_input_condition ssl_getdirection( void *conn )
    271271{
    272         return( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ? GAIM_INPUT_WRITE : GAIM_INPUT_READ );
    273 }
     272        return( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ? B_EV_IO_WRITE : B_EV_IO_READ );
     273}
  • lib/ssl_sspi.c

    r38ff846 r8b8def58  
    275275GaimInputCondition ssl_getdirection( void *conn )
    276276{
    277         return GAIM_INPUT_WRITE; /* FIXME: or GAIM_INPUT_READ */
    278 }
     277        return B_EV_IO_WRITE; /* FIXME: or B_EV_IO_READ */
     278}
  • nick.c

    r38ff846 r8b8def58  
    7878               
    7979                nick_strip( nick );
    80                 if( set_getbool( &acc->irc->set, "lcnicks" ) )
     80                if( set_getbool( &acc->bee->set, "lcnicks" ) )
    8181                        nick_lc( nick );
    8282        }
     
    9292void nick_dedupe( account_t *acc, const char *handle, char nick[MAX_NICK_LENGTH+1] )
    9393{
     94        irc_t *irc = (irc_t*) acc->bee->ui_data;
    9495        int inf_protection = 256;
    9596       
    9697        /* Now, find out if the nick is already in use at the moment, and make
    9798           subtle changes to make it unique. */
    98         while( !nick_ok( nick ) || user_find( acc->irc, nick ) )
     99        while( !nick_ok( nick ) || irc_user_by_name( irc, nick ) )
    99100        {
    100101                if( strlen( nick ) < ( MAX_NICK_LENGTH - 1 ) )
     
    112113                        int i;
    113114                       
    114                         irc_usermsg( acc->irc, "Warning: Almost had an infinite loop in nick_get()! "
    115                                                "This used to be a fatal BitlBee bug, but we tried to fix it. "
    116                                                "This message should *never* appear anymore. "
    117                                                "If it does, please *do* send us a bug report! "
    118                                                "Please send all the following lines in your report:" );
    119                        
    120                         irc_usermsg( acc->irc, "Trying to get a sane nick for handle %s", handle );
     115                        irc_usermsg( irc, "Warning: Almost had an infinite loop in nick_get()! "
     116                                          "This used to be a fatal BitlBee bug, but we tried to fix it. "
     117                                          "This message should *never* appear anymore. "
     118                                          "If it does, please *do* send us a bug report! "
     119                                          "Please send all the following lines in your report:" );
     120                       
     121                        irc_usermsg( irc, "Trying to get a sane nick for handle %s", handle );
    121122                        for( i = 0; i < MAX_NICK_LENGTH; i ++ )
    122                                 irc_usermsg( acc->irc, "Char %d: %c/%d", i, nick[i], nick[i] );
    123                        
    124                         irc_usermsg( acc->irc, "FAILED. Returning an insane nick now. Things might break. "
    125                                                "Good luck, and please don't forget to paste the lines up here "
    126                                                "in #bitlbee on OFTC or in a mail to wilmer@gaast.net" );
     123                                irc_usermsg( irc, "Char %d: %c/%d", i, nick[i], nick[i] );
     124                       
     125                        irc_usermsg( irc, "FAILED. Returning an insane nick now. Things might break. "
     126                                          "Good luck, and please don't forget to paste the lines up here "
     127                                          "in #bitlbee on OFTC or in a mail to wilmer@gaast.net" );
    127128                       
    128129                        g_snprintf( nick, MAX_NICK_LENGTH + 1, "xx%x", rand() );
  • protocols/Makefile

    r38ff846 r8b8def58  
    88
    99-include ../Makefile.settings
     10ifdef SRCDIR
     11SRCDIR := $(SRCDIR)protocols/
     12endif
    1013
    1114# [SH] Program variables
    12 objects = nogaim.o
     15objects = account.o bee.o bee_chat.o bee_ft.o bee_user.o nogaim.o
     16
    1317
    1418# [SH] The next two lines should contain the directory name (in $(subdirs))
     
    4953$(objects): ../Makefile.settings Makefile
    5054
    51 $(objects): %.o: %.c
     55$(objects): %.o: $(SRCDIR)%.c
    5256        @echo '*' Compiling $<
    5357        @$(CC) -c $(CFLAGS) $< -o $@
  • protocols/jabber/Makefile

    r38ff846 r8b8def58  
    88
    99-include ../../Makefile.settings
     10ifdef SRCDIR
     11SRCDIR := $(SRCDIR)protocols/jabber/
     12endif
    1013
    1114# [SH] Program variables
    12 objects = conference.o io.o iq.o jabber.o jabber_util.o message.o presence.o sasl.o
     15objects = conference.o io.o iq.o jabber.o jabber_util.o message.o presence.o s5bytestream.o sasl.o si.o
    1316
    1417CFLAGS += -Wall
     
    3336$(objects): ../../Makefile.settings Makefile
    3437
    35 $(objects): %.o: %.c
     38$(objects): %.o: $(SRCDIR)%.c
    3639        @echo '*' Compiling $<
    3740        @$(CC) -c $(CFLAGS) $< -o $@
  • protocols/jabber/conference.c

    r38ff846 r8b8def58  
    9292{
    9393        char *normalized = jabber_normalize( name );
     94        GSList *l;
    9495        struct groupchat *ret;
    9596        struct jabber_chat *jc;
    9697       
    97         for( ret = ic->groupchats; ret; ret = ret->next )
    98         {
     98        for( l = ic->groupchats; l; l = l->next )
     99        {
     100                ret = l->data;
    99101                jc = ret->data;
    100102                if( strcmp( normalized, jc->name ) == 0 )
     
    103105        g_free( normalized );
    104106       
    105         return ret;
     107        return l ? ret : NULL;
    106108}
    107109
  • protocols/jabber/io.c

    r38ff846 r8b8def58  
    6464                   most cases it probably won't be necessary.) */
    6565                if( ( ret = jabber_write_queue( ic ) ) && jd->tx_len > 0 )
    66                         jd->w_inpa = b_input_add( jd->fd, GAIM_INPUT_WRITE, jabber_write_callback, ic );
     66                        jd->w_inpa = b_input_add( jd->fd, B_EV_IO_WRITE, jabber_write_callback, ic );
    6767        }
    6868        else
     
    504504       
    505505        if( jd->r_inpa <= 0 )
    506                 jd->r_inpa = b_input_add( jd->fd, GAIM_INPUT_READ, jabber_read_callback, ic );
     506                jd->r_inpa = b_input_add( jd->fd, B_EV_IO_READ, jabber_read_callback, ic );
    507507       
    508508        greet = g_strdup_printf( "%s<stream:stream to=\"%s\" xmlns=\"jabber:client\" "
  • protocols/jabber/iq.c

    r38ff846 r8b8def58  
    9191                        pack = 0;
    9292                }
    93                 else if( strcmp( s, XMLNS_DISCOVER ) == 0 )
    94                 {
    95                         const char *features[] = { XMLNS_DISCOVER,
     93                else if( strcmp( s, XMLNS_DISCO_INFO ) == 0 )
     94                {
     95                        const char *features[] = { XMLNS_DISCO_INFO,
    9696                                                   XMLNS_VERSION,
    9797                                                   XMLNS_TIME,
     
    9999                                                   XMLNS_MUC,
    100100                                                   XMLNS_PING,
     101                                                   XMLNS_SI,
     102                                                   XMLNS_BYTESTREAMS,
     103                                                   XMLNS_FILETRANSFER,
    101104                                                   NULL };
    102105                        const char **f;
     
    118121                {
    119122                        xt_free_node( reply );
    120                         reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel" );
     123                        reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel", NULL );
    121124                        pack = 0;
    122125                }
     
    124127        else if( strcmp( type, "set" ) == 0 )
    125128        {
    126                 if( !( c = xt_find_node( node->children, "query" ) ) ||
    127                     !( s = xt_find_attr( c, "xmlns" ) ) )
     129                if( ( c = xt_find_node( node->children, "si" ) ) &&
     130                    ( s = xt_find_attr( c, "xmlns" ) ) &&
     131                    ( strcmp( s, XMLNS_SI ) == 0 ) )
     132                {
     133                        return jabber_si_handle_request( ic, node, c );
     134                }
     135                else if( !( c = xt_find_node( node->children, "query" ) ) ||
     136                         !( s = xt_find_attr( c, "xmlns" ) ) )
    128137                {
    129138                        return XT_HANDLED;
    130139                }
    131                
     140                else if( strcmp( s, XMLNS_ROSTER ) == 0 )
     141                {
    132142                /* This is a roster push. XMPP servers send this when someone
    133143                   was added to (or removed from) the buddy list. AFAIK they're
    134144                   sent even if we added this buddy in our own session. */
    135                 if( strcmp( s, XMLNS_ROSTER ) == 0 )
    136                 {
    137145                        int bare_len = strlen( ic->acc->user );
    138146                       
     
    151159                               
    152160                                xt_free_node( reply );
    153                                 reply = jabber_make_error_packet( node, "not-allowed", "cancel" );
     161                                reply = jabber_make_error_packet( node, "not-allowed", "cancel", NULL );
    154162                                pack = 0;
    155163                        }
    156164                }
     165                else if( strcmp( s, XMLNS_BYTESTREAMS ) == 0 )
     166                {
     167                        /* Bytestream Request (stage 2 of file transfer) */
     168                        return jabber_bs_recv_request( ic, node, c );
     169                }
    157170                else
    158171                {
    159172                        xt_free_node( reply );
    160                         reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel" );
     173                        reply = jabber_make_error_packet( node, "feature-not-implemented", "cancel", NULL );
    161174                        pack = 0;
    162175                }
     
    369382        while( ( c = xt_find_node( c, "item" ) ) )
    370383        {
    371                 struct xt_node *group = xt_find_node( node->children, "group" );
     384                struct xt_node *group = xt_find_node( c->children, "group" );
    372385                char *jid = xt_find_attr( c, "jid" );
    373386                char *name = xt_find_attr( c, "name" );
     
    378391                        if( ( strcmp( sub, "both" ) == 0 || strcmp( sub, "to" ) == 0 ) )
    379392                        {
    380                                 if( initial || imcb_find_buddy( ic, jid ) == NULL )
    381                                         imcb_add_buddy( ic, jid, ( group && group->text_len ) ?
    382                                                                    group->text : NULL );
     393                                imcb_add_buddy( ic, jid, ( group && group->text_len ) ?
     394                                                           group->text : NULL );
    383395                               
    384396                                if( name )
     
    543555static xt_status jabber_add_to_roster_callback( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
    544556
    545 int jabber_add_to_roster( struct im_connection *ic, char *handle, char *name )
     557int jabber_add_to_roster( struct im_connection *ic, const char *handle, const char *name, const char *group )
    546558{
    547559        struct xt_node *node;
     
    553565        if( name )
    554566                xt_add_attr( node, "name", name );
     567        if( group )
     568                xt_add_child( node, xt_new_node( "group", group, NULL ) );
    555569       
    556570        /* And pack it into a roster-add packet */
     
    576590            strcmp( s, "result" ) == 0 )
    577591        {
    578                 if( imcb_find_buddy( ic, jid ) == NULL )
     592                if( bee_user_by_handle( ic->bee, ic, jid ) == NULL )
    579593                        imcb_add_buddy( ic, jid, NULL );
    580594        }
     
    608622        return st;
    609623}
     624
     625xt_status jabber_iq_parse_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
     626
     627xt_status jabber_iq_query_features( struct im_connection *ic, char *bare_jid )
     628{
     629        struct xt_node *node, *query;
     630        struct jabber_buddy *bud;
     631       
     632        if( ( bud = jabber_buddy_by_jid( ic, bare_jid , 0 ) ) == NULL )
     633        {
     634                /* Who cares about the unknown... */
     635                imcb_log( ic, "Couldn't find buddy: %s", bare_jid);
     636                return XT_HANDLED;
     637        }
     638       
     639        if( bud->features ) /* been here already */
     640                return XT_HANDLED;
     641       
     642        node = xt_new_node( "query", NULL, NULL );
     643        xt_add_attr( node, "xmlns", XMLNS_DISCO_INFO );
     644       
     645        if( !( query = jabber_make_packet( "iq", "get", bare_jid, node ) ) )
     646        {
     647                imcb_log( ic, "WARNING: Couldn't generate feature query" );
     648                xt_free_node( node );
     649                return XT_HANDLED;
     650        }
     651
     652        jabber_cache_add( ic, query, jabber_iq_parse_features );
     653
     654        return jabber_write_packet( ic, query ) ? XT_HANDLED : XT_ABORT;
     655}
     656
     657xt_status jabber_iq_parse_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
     658{
     659        struct xt_node *c;
     660        struct jabber_buddy *bud;
     661        char *feature, *xmlns, *from;
     662
     663        if( !( from = xt_find_attr( node, "from" ) ) ||
     664            !( c = xt_find_node( node->children, "query" ) ) ||
     665            !( xmlns = xt_find_attr( c, "xmlns" ) ) ||
     666            !( strcmp( xmlns, XMLNS_DISCO_INFO ) == 0 ) )
     667        {
     668                imcb_log( ic, "WARNING: Received incomplete IQ-result packet for discover" );
     669                return XT_HANDLED;
     670        }
     671        if( ( bud = jabber_buddy_by_jid( ic, from, 0 ) ) == NULL )
     672        {
     673                /* Who cares about the unknown... */
     674                imcb_log( ic, "Couldn't find buddy: %s", from );
     675                return XT_HANDLED;
     676        }
     677       
     678        c = c->children;
     679        while( ( c = xt_find_node( c, "feature" ) ) )
     680        {
     681                feature = xt_find_attr( c, "var" );
     682                if( feature )
     683                        bud->features = g_slist_append( bud->features, g_strdup( feature ) );
     684                c = c->next;
     685        }
     686
     687        return XT_HANDLED;
     688}
     689
     690xt_status jabber_iq_parse_server_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
     691
     692xt_status jabber_iq_query_server( struct im_connection *ic, char *jid, char *xmlns )
     693{
     694        struct xt_node *node, *query;
     695        struct jabber_data *jd = ic->proto_data;
     696       
     697        node = xt_new_node( "query", NULL, NULL );
     698        xt_add_attr( node, "xmlns", xmlns );
     699       
     700        if( !( query = jabber_make_packet( "iq", "get", jid, node ) ) )
     701        {
     702                imcb_log( ic, "WARNING: Couldn't generate server query" );
     703                xt_free_node( node );
     704        }
     705
     706        jd->have_streamhosts--;
     707        jabber_cache_add( ic, query, jabber_iq_parse_server_features );
     708
     709        return jabber_write_packet( ic, query ) ? XT_HANDLED : XT_ABORT;
     710}
     711
     712/*
     713 * Query the server for "items", query each "item" for identities, query each "item" that's a proxy for it's bytestream info
     714 */
     715xt_status jabber_iq_parse_server_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
     716{
     717        struct xt_node *c;
     718        struct jabber_data *jd = ic->proto_data;
     719        char *xmlns, *from;
     720
     721        if( !( c = xt_find_node( node->children, "query" ) ) ||
     722            !( from = xt_find_attr( node, "from" ) ) ||
     723            !( xmlns = xt_find_attr( c, "xmlns" ) ) )
     724        {
     725                imcb_log( ic, "WARNING: Received incomplete IQ-result packet for discover" );
     726                return XT_HANDLED;
     727        }
     728
     729        jd->have_streamhosts++;
     730
     731        if( strcmp( xmlns, XMLNS_DISCO_ITEMS ) == 0 )
     732        {
     733                char *itemjid;
     734
     735                /* answer from server */
     736       
     737                c = c->children;
     738                while( ( c = xt_find_node( c, "item" ) ) )
     739                {
     740                        itemjid = xt_find_attr( c, "jid" );
     741                       
     742                        if( itemjid )
     743                                jabber_iq_query_server( ic, itemjid, XMLNS_DISCO_INFO );
     744
     745                        c = c->next;
     746                }
     747        }
     748        else if( strcmp( xmlns, XMLNS_DISCO_INFO ) == 0 )
     749        {
     750                char *category, *type;
     751
     752                /* answer from potential proxy */
     753
     754                c = c->children;
     755                while( ( c = xt_find_node( c, "identity" ) ) )
     756                {
     757                        category = xt_find_attr( c, "category" );
     758                        type = xt_find_attr( c, "type" );
     759
     760                        if( type && ( strcmp( type, "bytestreams" ) == 0 ) &&
     761                            category && ( strcmp( category, "proxy" ) == 0 ) )
     762                                jabber_iq_query_server( ic, from, XMLNS_BYTESTREAMS );
     763
     764                        c = c->next;
     765                }
     766        }
     767        else if( strcmp( xmlns, XMLNS_BYTESTREAMS ) == 0 )
     768        {
     769                char *host, *jid, *port_s;
     770                int port;
     771
     772                /* answer from proxy */
     773
     774                if( ( c = xt_find_node( c->children, "streamhost" ) ) &&
     775                    ( host = xt_find_attr( c, "host" ) ) &&
     776                    ( port_s = xt_find_attr( c, "port" ) ) &&
     777                    ( sscanf( port_s, "%d", &port ) == 1 ) &&
     778                    ( jid = xt_find_attr( c, "jid" ) ) )
     779                {
     780                        jabber_streamhost_t *sh = g_new0( jabber_streamhost_t, 1 );
     781                       
     782                        sh->jid = g_strdup( jid );
     783                        sh->host = g_strdup( host );
     784                        g_snprintf( sh->port, sizeof( sh->port ), "%u", port );
     785
     786                        imcb_log( ic, "Proxy found: jid %s host %s port %u", jid, host, port );
     787                        jd->streamhosts = g_slist_append( jd->streamhosts, sh );
     788                }
     789        }
     790
     791        if( jd->have_streamhosts == 0 )
     792                jd->have_streamhosts++;
     793
     794        return XT_HANDLED;
     795}
  • protocols/jabber/jabber.c

    r38ff846 r8b8def58  
    6565       
    6666        s = set_add( &acc->set, "priority", "0", set_eval_priority, acc );
     67
     68        s = set_add( &acc->set, "proxy", "<local>;<auto>", NULL, acc );
    6769       
    6870        s = set_add( &acc->set, "resource", "BitlBee", NULL, acc );
     
    266268        struct jabber_data *jd = ic->proto_data;
    267269       
     270        while( jd->filetransfers )
     271                imcb_file_canceled( ic, ( ( struct jabber_transfer *) jd->filetransfers->data )->ft, "Logging out" );
     272
     273        while( jd->streamhosts )
     274        {
     275                jabber_streamhost_t *sh = jd->streamhosts->data;
     276                jd->streamhosts = g_slist_remove( jd->streamhosts, sh );
     277                g_free( sh->jid );
     278                g_free( sh->host );
     279                g_free( sh );
     280        }
     281
    268282        if( jd->fd >= 0 )
    269283                jabber_end_stream( ic );
    270284       
    271285        while( ic->groupchats )
    272                 jabber_chat_free( ic->groupchats );
     286                jabber_chat_free( ic->groupchats->data );
    273287       
    274288        if( jd->r_inpa >= 0 )
     
    401415        }
    402416       
    403         if( jabber_add_to_roster( ic, who, NULL ) )
     417        if( jabber_add_to_roster( ic, who, NULL, group ) )
    404418                presence_send_request( ic, who, "subscribe" );
    405419}
     
    549563        ret->send_typing = jabber_send_typing;
    550564        ret->handle_cmp = g_strcasecmp;
     565        ret->transfer_request = jabber_si_transfer_request;
    551566
    552567        register_protocol( ret );
  • protocols/jabber/jabber.h

    r38ff846 r8b8def58  
    6161} jabber_buddy_flags_t;
    6262
     63/* Stores a streamhost's (a.k.a. proxy) data */
     64typedef struct
     65{
     66        char *jid;
     67        char *host;
     68        char port[6];
     69} jabber_streamhost_t;
     70
    6371typedef enum
    6472{
     
    9199        GHashTable *node_cache;
    92100        GHashTable *buddies;
     101
     102        GSList *filetransfers;
     103        GSList *streamhosts;
     104        int have_streamhosts;
    93105};
    94106
     
    127139        struct jabber_away_state *away_state;
    128140        char *away_message;
     141        GSList *features;
    129142       
    130143        time_t last_msg;
     
    140153        char *my_full_jid; /* Separate copy because of case sensitivity. */
    141154        struct jabber_buddy *me;
     155};
     156
     157struct jabber_transfer
     158{
     159        /* bitlbee's handle for this transfer */
     160        file_transfer_t *ft;
     161
     162        /* the stream's private handle */
     163        gpointer streamhandle;
     164
     165        /* timeout for discover queries */
     166        gint disco_timeout;
     167        gint disco_timeout_fired;
     168
     169        struct im_connection *ic;
     170
     171        struct jabber_buddy *bud;
     172
     173        int watch_in;
     174        int watch_out;
     175
     176        char *ini_jid;
     177        char *tgt_jid;
     178        char *iq_id;
     179        char *sid;
     180        int accepted;
     181
     182        size_t bytesread, byteswritten;
     183        int fd;
     184        struct sockaddr_storage saddr;
    142185};
    143186
     
    167210
    168211/* Some supported extensions/legacy stuff */
    169 #define XMLNS_AUTH         "jabber:iq:auth"                     /* XEP-0078 */
    170 #define XMLNS_VERSION      "jabber:iq:version"                  /* XEP-0092 */
    171 #define XMLNS_TIME         "jabber:iq:time"                     /* XEP-0090 */
    172 #define XMLNS_PING         "urn:xmpp:ping"                      /* XEP-0199 */
    173 #define XMLNS_VCARD        "vcard-temp"                         /* XEP-0054 */
    174 #define XMLNS_DELAY        "jabber:x:delay"                     /* XEP-0091 */
    175 #define XMLNS_CHATSTATES   "http://jabber.org/protocol/chatstates"  /* 0085 */
    176 #define XMLNS_DISCOVER     "http://jabber.org/protocol/disco#info"  /* 0030 */
    177 #define XMLNS_MUC          "http://jabber.org/protocol/muc"     /* XEP-0045 */
    178 #define XMLNS_MUC_USER     "http://jabber.org/protocol/muc#user"/* XEP-0045 */
    179 #define XMLNS_CAPS         "http://jabber.org/protocol/caps"    /* XEP-0115 */
     212#define XMLNS_AUTH         "jabber:iq:auth"                                      /* XEP-0078 */
     213#define XMLNS_VERSION      "jabber:iq:version"                                   /* XEP-0092 */
     214#define XMLNS_TIME         "jabber:iq:time"                                      /* XEP-0090 */
     215#define XMLNS_PING         "urn:xmpp:ping"                                       /* XEP-0199 */
     216#define XMLNS_VCARD        "vcard-temp"                                          /* XEP-0054 */
     217#define XMLNS_DELAY        "jabber:x:delay"                                      /* XEP-0091 */
     218#define XMLNS_XDATA        "jabber:x:data"                                       /* XEP-0004 */
     219#define XMLNS_CHATSTATES   "http://jabber.org/protocol/chatstates"               /* XEP-0085 */
     220#define XMLNS_DISCO_INFO   "http://jabber.org/protocol/disco#info"               /* XEP-0030 */
     221#define XMLNS_DISCO_ITEMS  "http://jabber.org/protocol/disco#items"              /* XEP-0030 */
     222#define XMLNS_MUC          "http://jabber.org/protocol/muc"                      /* XEP-0045 */
     223#define XMLNS_MUC_USER     "http://jabber.org/protocol/muc#user"                 /* XEP-0045 */
     224#define XMLNS_CAPS         "http://jabber.org/protocol/caps"                     /* XEP-0115 */
     225#define XMLNS_FEATURE      "http://jabber.org/protocol/feature-neg"              /* XEP-0020 */
     226#define XMLNS_SI           "http://jabber.org/protocol/si"                       /* XEP-0095 */
     227#define XMLNS_FILETRANSFER "http://jabber.org/protocol/si/profile/file-transfer" /* XEP-0096 */
     228#define XMLNS_BYTESTREAMS  "http://jabber.org/protocol/bytestreams"              /* XEP-0065 */
     229#define XMLNS_IBB          "http://jabber.org/protocol/ibb"                      /* XEP-0047 */
    180230
    181231/* iq.c */
     
    185235int jabber_get_roster( struct im_connection *ic );
    186236int jabber_get_vcard( struct im_connection *ic, char *bare_jid );
    187 int jabber_add_to_roster( struct im_connection *ic, char *handle, char *name );
     237int jabber_add_to_roster( struct im_connection *ic, const char *handle, const char *name, const char *group );
    188238int jabber_remove_from_roster( struct im_connection *ic, char *handle );
     239xt_status jabber_iq_query_features( struct im_connection *ic, char *bare_jid );
     240xt_status jabber_iq_query_server( struct im_connection *ic, char *jid, char *xmlns );
     241
     242/* si.c */
     243int jabber_si_handle_request( struct im_connection *ic, struct xt_node *node, struct xt_node *sinode );
     244void jabber_si_transfer_request( struct im_connection *ic, file_transfer_t *ft, char *who );
     245void jabber_si_free_transfer( file_transfer_t *ft);
     246
     247/* s5bytestream.c */
     248int jabber_bs_recv_request( struct im_connection *ic, struct xt_node *node, struct xt_node *qnode);
     249gboolean jabber_bs_send_start( struct jabber_transfer *tf );
     250gboolean jabber_bs_send_write( file_transfer_t *ft, char *buffer, unsigned int len );
    189251
    190252/* message.c */
     
    200262char *set_eval_tls( set_t *set, char *value );
    201263struct xt_node *jabber_make_packet( char *name, char *type, char *to, struct xt_node *children );
    202 struct xt_node *jabber_make_error_packet( struct xt_node *orig, char *err_cond, char *err_type );
     264struct xt_node *jabber_make_error_packet( struct xt_node *orig, char *err_cond, char *err_type, char *err_code );
    203265void jabber_cache_add( struct im_connection *ic, struct xt_node *node, jabber_cache_event func );
    204266struct xt_node *jabber_cache_get( struct im_connection *ic, char *id );
  • protocols/jabber/jabber_util.c

    r38ff846 r8b8def58  
    9999}
    100100
    101 struct xt_node *jabber_make_error_packet( struct xt_node *orig, char *err_cond, char *err_type )
     101struct xt_node *jabber_make_error_packet( struct xt_node *orig, char *err_cond, char *err_type, char *err_code )
    102102{
    103103        struct xt_node *node, *c;
     
    111111        c = xt_new_node( "error", NULL, c );
    112112        xt_add_attr( c, "type", err_type );
     113       
     114        /* Add the error code, if present */
     115        if (err_code)
     116                xt_add_attr( c, "code", err_code );
    113117       
    114118        /* To make the actual error packet, we copy the original packet and
     
    275279        presence_send_request( bla->ic, bla->handle, "subscribed" );
    276280       
    277         if( imcb_find_buddy( bla->ic, bla->handle ) == NULL )
    278                 imcb_ask_add( bla->ic, bla->handle, NULL );
     281        imcb_ask_add( bla->ic, bla->handle, NULL );
    279282       
    280283        g_free( bla->handle );
     
    458461               
    459462                if( bud == NULL && ( flags & GET_BUDDY_CREAT ) &&
    460                     ( bare_exists || imcb_find_buddy( ic, jid ) ) )
     463                    ( bare_exists || bee_user_by_handle( ic->bee, ic, jid ) ) )
    461464                {
    462465                        *s = '/';
     
    479482                if( bud == NULL )
    480483                        /* No match. Create it now? */
    481                         return ( ( flags & GET_BUDDY_CREAT ) && imcb_find_buddy( ic, jid_ ) ) ?
     484                        return ( ( flags & GET_BUDDY_CREAT ) &&
     485                                 bee_user_by_handle( ic->bee, ic, jid_ ) ) ?
    482486                                   jabber_buddy_add( ic, jid_ ) : NULL;
    483487                else if( bud->resource && ( flags & GET_BUDDY_EXACT ) )
  • protocols/jabber/presence.c

    r38ff846 r8b8def58  
    205205        struct jabber_data *jd = ic->proto_data;
    206206        struct xt_node *node, *cap;
    207         struct groupchat *c;
     207        GSList *l;
    208208        int st;
    209209       
     
    229229        /* Have to send this update to all groupchats too, the server won't
    230230           do this automatically. */
    231         for( c = ic->groupchats; c && st; c = c->next )
    232         {
     231        for( l = ic->groupchats; l && st; l = l->next )
     232        {
     233                struct groupchat *c = l->data;
    233234                struct jabber_chat *jc = c->data;
    234235               
  • protocols/msn/Makefile

    r38ff846 r8b8def58  
    88
    99-include ../../Makefile.settings
     10ifdef SRCDIR
     11SRCDIR := $(SRCDIR)protocols/msn/
     12endif
    1013
    1114# [SH] Program variables
     
    3336$(objects): ../../Makefile.settings Makefile
    3437
    35 $(objects): %.o: %.c
     38$(objects): %.o: $(SRCDIR)%.c
    3639        @echo '*' Compiling $<
    3740        @$(CC) -c $(CFLAGS) $< -o $@
  • protocols/msn/msn.c

    r38ff846 r8b8def58  
    7979        if( md )
    8080        {
     81                /** Disabling MSN ft support for now.
     82                while( md->filetransfers ) {
     83                        imcb_file_canceled( md->filetransfers->data, "Closing connection" );
     84                }
     85                */
     86               
    8187                if( md->fd >= 0 )
    8288                        closesocket( md->fd );
     
    98104                g_free( md->grouplist );
    99105               
     106                while( md->grpq )
     107                {
     108                        struct msn_groupadd *ga = md->grpq->data;
     109                        g_free( ga->group );
     110                        g_free( ga->who );
     111                        g_free( ga );
     112                        md->grpq = g_slist_remove( md->grpq, ga );
     113                }
     114               
    100115                g_free( md );
    101116        }
     
    116131        struct msn_switchboard *sb;
    117132       
     133#ifdef DEBUG
     134        if( strcmp( who, "raw" ) == 0 )
     135        {
     136                msn_write( ic, message, strlen( message ) );
     137                msn_write( ic, "\r\n", 2 );
     138        }
     139        else
     140#endif
    118141        if( ( sb = msn_sb_by_handle( ic, who ) ) )
    119142        {
     
    176199static void msn_add_buddy( struct im_connection *ic, char *who, char *group )
    177200{
    178         msn_buddy_list_add( ic, "FL", who, who );
     201        msn_buddy_list_add( ic, "FL", who, who, group );
    179202}
    180203
     
    217240{
    218241        struct msn_switchboard *sb;
     242        struct groupchat *c = imcb_chat_new( ic, who );
    219243       
    220244        if( ( sb = msn_sb_by_handle( ic, who ) ) )
     
    234258                msn_sb_write_msg( ic, m );
    235259
    236                 return NULL;
    237         }
    238        
    239         return NULL;
     260                return c;
     261        }
    240262}
    241263
     
    247269static void msn_add_permit( struct im_connection *ic, char *who )
    248270{
    249         msn_buddy_list_add( ic, "AL", who, who );
     271        msn_buddy_list_add( ic, "AL", who, who, NULL );
    250272}
    251273
     
    259281        struct msn_switchboard *sb;
    260282       
    261         msn_buddy_list_add( ic, "BL", who, who );
     283        msn_buddy_list_add( ic, "BL", who, who, NULL );
    262284       
    263285        /* If there's still a conversation with this person, close it. */
     
    328350        ret->send_typing = msn_send_typing;
    329351        ret->handle_cmp = g_strcasecmp;
     352        //ret->transfer_request = msn_ftp_transfer_request;
    330353
    331354        register_protocol(ret);
  • protocols/msn/msn.h

    r38ff846 r8b8def58  
    7070        int trId;
    7171       
    72         GSList *msgq;
     72        GSList *msgq, *grpq;
    7373        GSList *switchboards;
    7474        int sb_failures;
    7575        time_t first_sb_failure;
     76        GSList *filetransfers;
    7677       
    7778        const struct msn_away_state *away_state;
     
    118119        char *who;
    119120        char *text;
     121};
     122
     123struct msn_groupadd
     124{
     125        char *who;
     126        char *group;
    120127};
    121128
     
    159166int msn_write( struct im_connection *ic, char *s, int len );
    160167int msn_logged_in( struct im_connection *ic );
    161 int msn_buddy_list_add( struct im_connection *ic, char *list, char *who, char *realname );
     168int msn_buddy_list_add( struct im_connection *ic, const char *list, const char *who, const char *realname_, const char *group );
    162169int msn_buddy_list_remove( struct im_connection *ic, char *list, char *who );
    163170void msn_buddy_ask( struct im_connection *ic, char *handle, char *realname );
     
    189196void msn_sb_stop_keepalives( struct msn_switchboard *sb );
    190197
     198/* invitation.c */
     199void msn_ftp_transfer_request( struct im_connection *ic, file_transfer_t *ft, char *who );
     200
    191201#endif //_MSN_H
  • protocols/msn/msn_util.c

    r38ff846 r8b8def58  
    5151}
    5252
    53 int msn_buddy_list_add( struct im_connection *ic, char *list, char *who, char *realname_ )
     53int msn_buddy_list_add( struct im_connection *ic, const char *list, const char *who, const char *realname_, const char *group )
    5454{
    5555        struct msn_data *md = ic->proto_data;
    56         char buf[1024], *realname;
     56        char buf[1024], *realname, groupid[8];
     57       
     58        *groupid = '\0';
     59        if( group )
     60        {
     61                int i;
     62                for( i = 0; i < md->groupcount; i ++ )
     63                        if( g_strcasecmp( md->grouplist[i], group ) == 0 )
     64                        {
     65                                g_snprintf( groupid, sizeof( groupid ), " %d", i );
     66                                break;
     67                        }
     68               
     69                if( *groupid == '\0' )
     70                {
     71                        /* Have to create this group, it doesn't exist yet. */
     72                        struct msn_groupadd *ga;
     73                        GSList *l;
     74                       
     75                        for( l = md->grpq; l; l = l->next )
     76                        {
     77                                ga = l->data;
     78                                if( g_strcasecmp( ga->group, group ) == 0 )
     79                                        break;
     80                        }
     81                       
     82                        ga = g_new0( struct msn_groupadd, 1 );
     83                        ga->who = g_strdup( who );
     84                        ga->group = g_strdup( group );
     85                        md->grpq = g_slist_prepend( md->grpq, ga );
     86                       
     87                        if( l == NULL )
     88                        {
     89                                char *groupname = msn_http_encode( group );
     90                                g_snprintf( buf, sizeof( buf ), "ADG %d %s %d\r\n", ++md->trId, groupname, 0 );
     91                                g_free( groupname );
     92                                return msn_write( ic, buf, strlen( buf ) );
     93                        }
     94                        else
     95                        {
     96                                /* This can happen if the user's doing lots of adds to a
     97                                   new group at once; we're still waiting for the server
     98                                   to confirm group creation. */
     99                                return 1;
     100                        }
     101                }
     102        }
    57103       
    58104        realname = msn_http_encode( realname_ );
    59        
    60         g_snprintf( buf, sizeof( buf ), "ADD %d %s %s %s\r\n", ++md->trId, list, who, realname );
    61         if( msn_write( ic, buf, strlen( buf ) ) )
    62         {
    63                 g_free( realname );
    64                
    65                 return( 1 );
    66         }
    67        
     105        g_snprintf( buf, sizeof( buf ), "ADD %d %s %s %s%s\r\n", ++md->trId, list, who, realname, groupid );
    68106        g_free( realname );
    69107       
    70         return( 0 );
     108        return msn_write( ic, buf, strlen( buf ) );
    71109}
    72110
     
    94132        struct msn_buddy_ask_data *bla = data;
    95133       
    96         msn_buddy_list_add( bla->ic, "AL", bla->handle, bla->realname );
    97        
    98         if( imcb_find_buddy( bla->ic, bla->handle ) == NULL )
    99                 imcb_ask_add( bla->ic, bla->handle, NULL );
     134        msn_buddy_list_add( bla->ic, "AL", bla->handle, bla->realname, NULL );
     135       
     136        imcb_ask_add( bla->ic, bla->handle, NULL );
    100137       
    101138        g_free( bla->handle );
     
    108145        struct msn_buddy_ask_data *bla = data;
    109146       
    110         msn_buddy_list_add( bla->ic, "BL", bla->handle, bla->realname );
     147        msn_buddy_list_add( bla->ic, "BL", bla->handle, bla->realname, NULL );
    111148       
    112149        g_free( bla->handle );
  • protocols/msn/ns.c

    r38ff846 r8b8def58  
    7676        if( msn_write( ic, s, strlen( s ) ) )
    7777        {
    78                 ic->inpa = b_input_add( md->fd, GAIM_INPUT_READ, msn_ns_callback, ic );
     78                ic->inpa = b_input_add( md->fd, B_EV_IO_READ, msn_ns_callback, ic );
    7979                imcb_log( ic, "Connected to server, waiting for reply" );
    8080        }
     
    533533                else if( num_parts >= 6 && strcmp( cmd[2], "FL" ) == 0 )
    534534                {
     535                        const char *group = NULL;
     536                        int num;
     537                       
     538                        if( cmd[6] != NULL && sscanf( cmd[6], "%d", &num ) == 1 && num < md->groupcount )
     539                                group = md->grouplist[num];
     540                       
    535541                        http_decode( cmd[5] );
    536                         imcb_add_buddy( ic, cmd[4], NULL );
     542                        imcb_add_buddy( ic, cmd[4], group );
    537543                        imcb_rename_buddy( ic, cmd[4], cmd[5] );
    538544                }
     
    604610                        imc_logout( ic, TRUE );
    605611                        return( 0 );
     612                }
     613        }
     614        else if( strcmp( cmd[0], "ADG" ) == 0 )
     615        {
     616                char *group = g_strdup( cmd[3] );
     617                int groupnum, i;
     618                GSList *l, *next;
     619               
     620                http_decode( group );
     621                if( sscanf( cmd[4], "%d", &groupnum ) == 1 )
     622                {
     623                        if( groupnum >= md->groupcount )
     624                        {
     625                                md->grouplist = g_renew( char *, md->grouplist, groupnum + 1 );
     626                                for( i = md->groupcount; i <= groupnum; i ++ )
     627                                        md->grouplist[i] = NULL;
     628                                md->groupcount = groupnum + 1;
     629                        }
     630                        g_free( md->grouplist[groupnum] );
     631                        md->grouplist[groupnum] = group;
     632                }
     633                else
     634                {
     635                        /* Shouldn't happen, but if it does, give up on the group. */
     636                        g_free( group );
     637                        imcb_error( ic, "Syntax error" );
     638                        imc_logout( ic, TRUE );
     639                        return 0;
     640                }
     641               
     642                for( l = md->grpq; l; l = next )
     643                {
     644                        struct msn_groupadd *ga = l->data;
     645                        next = l->next;
     646                        if( g_strcasecmp( ga->group, group ) == 0 )
     647                        {
     648                                if( !msn_buddy_list_add( ic, "FL", ga->who, ga->who, group ) )
     649                                        return 0;
     650                               
     651                                g_free( ga->group );
     652                                g_free( ga->who );
     653                                g_free( ga );
     654                                md->grpq = g_slist_remove( md->grpq, ga );
     655                        }
    606656                }
    607657        }
  • protocols/msn/sb.c

    r38ff846 r8b8def58  
    2929#include "passport.h"
    3030#include "md5.h"
     31#include "invitation.h"
    3132
    3233static gboolean msn_sb_callback( gpointer data, gint source, b_input_condition cond );
     
    177178                {
    178179                        buf = g_strdup( SB_KEEPALIVE_HEADERS );
     180                        i = strlen( buf );
     181                }
     182                else if( strncmp( text, MSN_INVITE_HEADERS, sizeof( MSN_INVITE_HEADERS ) - 1 ) == 0 )
     183                {
     184                        buf = g_strdup( text );
    179185                        i = strlen( buf );
    180186                }
     
    227233{
    228234        struct im_connection *ic = sb->ic;
     235        struct groupchat *c = NULL;
    229236        char buf[1024];
    230237       
    231238        /* Create the groupchat structure. */
    232239        g_snprintf( buf, sizeof( buf ), "MSN groupchat session %d", sb->session );
    233         sb->chat = imcb_chat_new( ic, buf );
     240        if( sb->who )
     241                c = bee_chat_by_title( ic->bee, ic, sb->who );
     242        if( c && !msn_sb_by_chat( c ) )
     243                sb->chat = c;
     244        else
     245                sb->chat = imcb_chat_new( ic, buf );
    234246       
    235247        /* Populate the channel. */
     
    315327       
    316328        if( msn_sb_write( sb, buf, strlen( buf ) ) )
    317                 sb->inp = b_input_add( sb->fd, GAIM_INPUT_READ, msn_sb_callback, sb );
     329                sb->inp = b_input_add( sb->fd, B_EV_IO_READ, msn_sb_callback, sb );
    318330        else
    319331                debug( "Error %d while connecting to switchboard server", 2 );
     
    692704                        }
    693705                }
     706#if 0
     707                // Disable MSN ft support for now.
    694708                else if( g_strncasecmp( ct, "text/x-msmsgsinvite", 19 ) == 0 )
    695709                {
    696                         char *itype = msn_findheader( body, "Application-GUID:", blen );
    697                         char buf[1024];
     710                        char *command = msn_findheader( body, "Invitation-Command:", blen );
     711                        char *cookie = msn_findheader( body, "Invitation-Cookie:", blen );
     712                        unsigned int icookie;
    698713                       
    699714                        g_free( ct );
    700715                       
    701                         *buf = 0;
    702                        
    703                         if( !itype )
    704                                 return( 1 );
    705                        
    706                         /* File transfer. */
    707                         if( strcmp( itype, "{5D3E02AB-6190-11d3-BBBB-00C04F795683}" ) == 0 )
    708                         {
    709                                 char *name = msn_findheader( body, "Application-File:", blen );
    710                                 char *size = msn_findheader( body, "Application-FileSize:", blen );
    711                                
    712                                 if( name && size )
    713                                 {
    714                                         g_snprintf( buf, sizeof( buf ), "<< \x02""BitlBee\x02"" - Filetransfer: `%s', %s bytes >>\n"
    715                                                     "Filetransfers are not supported by BitlBee for now...", name, size );
    716                                 }
    717                                 else
    718                                 {
    719                                         strcpy( buf, "<< \x02""BitlBee\x02"" - Corrupted MSN filetransfer invitation message >>" );
    720                                 }
    721                                
    722                                 if( name ) g_free( name );
    723                                 if( size ) g_free( size );
    724                         }
    725                         else
    726                         {
    727                                 char *iname = msn_findheader( body, "Application-Name:", blen );
    728                                
    729                                 g_snprintf( buf, sizeof( buf ), "<< \x02""BitlBee\x02"" - Unknown MSN invitation - %s (%s) >>",
    730                                                                 itype, iname ? iname : "no name" );
    731                                
    732                                 if( iname ) g_free( iname );
    733                         }
    734                        
    735                         g_free( itype );
    736                        
    737                         if( !*buf )
    738                                 return( 1 );
    739                        
    740                         if( sb->who )
    741                         {
    742                                 imcb_buddy_msg( ic, cmd[1], buf, 0, 0 );
    743                         }
    744                         else if( sb->chat )
    745                         {
    746                                 imcb_chat_msg( sb->chat, cmd[1], buf, 0, 0 );
    747                         }
    748                         else
    749                         {
    750                                 /* PANIC! */
    751                         }
     716                        /* Every invite should have both a Command and Cookie header */
     717                        if( !command || !cookie ) {
     718                                g_free( command );
     719                                g_free( cookie );
     720                                imcb_log( ic, "Warning: No command or cookie from %s", sb->who );
     721                                return 1;
     722                        }
     723                       
     724                        icookie = strtoul( cookie, NULL, 10 );
     725                        g_free( cookie );
     726                       
     727                        if( g_strncasecmp( command, "INVITE", 6 ) == 0 ) {
     728                                msn_invitation_invite( sb, cmd[1], icookie, body, blen );
     729                        } else if( g_strncasecmp( command, "ACCEPT", 6 ) == 0 ) {
     730                                msn_invitation_accept( sb, cmd[1], icookie, body, blen );
     731                        } else if( g_strncasecmp( command, "CANCEL", 6 ) == 0 ) {
     732                                msn_invitation_cancel( sb, cmd[1], icookie, body, blen );
     733                        } else {
     734                                imcb_log( ic, "Warning: Received invalid invitation with "
     735                                                "command %s from %s", command, sb->who );
     736                        }
     737                       
     738                        g_free( command );
     739                }
     740#endif
     741                else if( g_strncasecmp( ct, "application/x-msnmsgrp2p", 24 ) == 0 )
     742                {
     743                        imcb_error( sb->ic, "Cannot receive file from %s: BitlBee does not "
     744                                        "support msnmsgrp2p yet.", sb->who );
     745                        g_free( ct );
    752746                }
    753747                else if( g_strncasecmp( ct, "text/x-msmsgscontrol", 20 ) == 0 )
     
    780774void msn_sb_start_keepalives( struct msn_switchboard *sb, gboolean initial )
    781775{
    782         struct buddy *b;
     776        bee_user_t *bu;
    783777       
    784778        if( sb && sb->who && sb->keepalive == 0 &&
    785             ( b = imcb_find_buddy( sb->ic, sb->who ) ) && !b->present &&
     779            ( bu = bee_user_by_handle( sb->ic->bee, sb->ic, sb->who ) ) &&
     780            !( bu->flags & BEE_USER_ONLINE ) &&
    786781            set_getbool( &sb->ic->acc->set, "switchboard_keepalives" ) )
    787782        {
  • protocols/nogaim.c

    r38ff846 r8b8def58  
    3838#include "chat.h"
    3939
    40 static int remove_chat_buddy_silent( struct groupchat *b, const char *handle );
    41 static char *format_timestamp( irc_t *irc, time_t msg_ts );
    42 
    4340GSList *connections;
    4441
     
    9289}
    9390#endif
    94 
    95 /* nogaim.c */
    9691
    9792GList *protocols = NULL;
     
    117112{
    118113        GList *gl;
    119         for (gl = protocols; gl; gl = gl->next)
     114       
     115        for( gl = protocols; gl; gl = gl->next )
    120116        {
    121117                struct prpl *proto = gl->data;
    122                 if(!g_strcasecmp(proto->name, name))
     118               
     119                if( g_strcasecmp( proto->name, name ) == 0 )
    123120                        return proto;
    124121        }
     122       
    125123        return NULL;
    126124}
    127125
    128 /* nogaim.c */
    129126void nogaim_init()
    130127{
     
    134131        extern void jabber_initmodule();
    135132        extern void twitter_initmodule();
     133        extern void purple_initmodule();
    136134
    137135#ifdef WITH_MSN
     
    155153#endif
    156154
     155#ifdef WITH_PURPLE
     156        purple_initmodule();
     157#endif
     158
    157159#ifdef WITH_PLUGINS
    158160        load_plugins();
     
    162164GSList *get_connections() { return connections; }
    163165
    164 /* multi.c */
    165 
    166166struct im_connection *imcb_new( account_t *acc )
    167167{
     
    170170        ic = g_new0( struct im_connection, 1 );
    171171       
    172         ic->irc = acc->irc;
     172        ic->bee = acc->bee;
    173173        ic->acc = acc;
    174174        acc->ic = ic;
     
    184184       
    185185        /* Destroy the pointer to this connection from the account list */
    186         for( a = ic->irc->accounts; a; a = a->next )
     186        for( a = ic->bee->accounts; a; a = a->next )
    187187                if( a->ic == ic )
    188188                {
     
    205205        va_end( params );
    206206
    207         if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) ||
    208             ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )
     207        if( ( g_strcasecmp( set_getstr( &ic->bee->set, "strip_html" ), "always" ) == 0 ) ||
     208            ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->bee->set, "strip_html" ) ) )
    209209                strip_html( text );
    210210       
    211211        /* Try to find a different connection on the same protocol. */
    212         for( a = ic->irc->accounts; a; a = a->next )
     212        for( a = ic->bee->accounts; a; a = a->next )
    213213                if( a->prpl == ic->acc->prpl && a->ic != ic )
    214214                        break;
     
    216216        /* If we found one, include the screenname in the message. */
    217217        if( a )
    218                 irc_usermsg( ic->irc, "%s(%s) - %s", ic->acc->prpl->name, ic->acc->user, text );
     218                /* FIXME(wilmer): ui_log callback or so */
     219                irc_usermsg( ic->bee->ui_data, "%s(%s) - %s", ic->acc->prpl->name, ic->acc->user, text );
    219220        else
    220                 irc_usermsg( ic->irc, "%s - %s", ic->acc->prpl->name, text );
     221                irc_usermsg( ic->bee->ui_data, "%s - %s", ic->acc->prpl->name, text );
    221222       
    222223        g_free( text );
     
    269270void imcb_connected( struct im_connection *ic )
    270271{
    271         irc_t *irc = ic->irc;
    272         struct chat *c;
    273         user_t *u;
    274        
    275272        /* MSN servers sometimes redirect you to a different server and do
    276273           the whole login sequence again, so these "late" calls to this
     
    279276                return;
    280277       
    281         u = user_find( ic->irc, ic->irc->nick );
    282        
    283278        imcb_log( ic, "Logged in" );
    284279       
     
    293288        ic->acc->auto_reconnect_delay = 0;
    294289       
     290        /*
    295291        for( c = irc->chatrooms; c; c = c->next )
    296292        {
     
    301297                        chat_join( irc, c, NULL );
    302298        }
     299        */
    303300}
    304301
     
    308305       
    309306        a->reconnect = 0;
    310         account_on( a->irc, a );
     307        account_on( a->bee, a );
    311308       
    312309        return( FALSE );        /* Only have to run the timeout once */
     
    321318void imc_logout( struct im_connection *ic, int allow_reconnect )
    322319{
    323         irc_t *irc = ic->irc;
    324         user_t *t, *u;
     320        bee_t *bee = ic->bee;
    325321        account_t *a;
     322        GSList *l;
    326323        int delay;
    327324       
     
    343340        ic->away = NULL;
    344341       
    345         u = irc->users;
    346         while( u )
    347         {
    348                 if( u->ic == ic )
    349                 {
    350                         t = u->next;
    351                         user_del( irc, u->nick );
    352                         u = t;
    353                 }
    354                 else
    355                         u = u->next;
    356         }
    357        
    358         query_del_by_conn( ic->irc, ic );
    359        
    360         for( a = irc->accounts; a; a = a->next )
     342        for( l = bee->users; l; )
     343        {
     344                bee_user_t *bu = l->data;
     345                GSList *next = l->next;
     346               
     347                if( bu->ic == ic )
     348                        bee_user_free( bee, bu );
     349               
     350                l = next;
     351        }
     352       
     353        query_del_by_conn( (irc_t*) ic->bee->ui_data, ic );
     354       
     355        for( a = bee->accounts; a; a = a->next )
    361356                if( a->ic == ic )
    362357                        break;
     
    366361                /* Uhm... This is very sick. */
    367362        }
    368         else if( allow_reconnect && set_getbool( &irc->set, "auto_reconnect" ) &&
     363        else if( allow_reconnect && set_getbool( &bee->set, "auto_reconnect" ) &&
    369364                 set_getbool( &a->set, "auto_reconnect" ) &&
    370365                 ( delay = account_reconnect_delay( a ) ) > 0 )
     
    377372}
    378373
    379 
    380 /* dialogs.c */
    381 
    382374void imcb_ask( struct im_connection *ic, char *msg, void *data,
    383375               query_callback doit, query_callback dont )
    384376{
    385         query_add( ic->irc, ic, msg, doit, dont, data );
    386 }
    387 
    388 
    389 /* list.c */
     377        query_add( (irc_t *) ic->bee->ui_data, ic, msg, doit, dont, data );
     378}
    390379
    391380void imcb_add_buddy( struct im_connection *ic, const char *handle, const char *group )
    392381{
    393         user_t *u;
    394         char nick[MAX_NICK_LENGTH+1], *s;
    395         irc_t *irc = ic->irc;
    396        
    397         if( user_findhandle( ic, handle ) )
    398         {
    399                 if( set_getbool( &irc->set, "debug" ) )
    400                         imcb_log( ic, "User already exists, ignoring add request: %s", handle );
     382        bee_user_t *bu;
     383        bee_t *bee = ic->bee;
     384       
     385        if( !( bu = bee_user_by_handle( bee, ic, handle ) ) )
     386                bu = bee_user_new( bee, ic, handle, 0 );
     387       
     388        bu->group = bee_group_by_name( bee, group, TRUE );
     389       
     390        if( bee->ui->user_group )
     391                bee->ui->user_group( bee, bu );
     392}
     393
     394void imcb_rename_buddy( struct im_connection *ic, const char *handle, const char *fullname )
     395{
     396        bee_t *bee = ic->bee;
     397        bee_user_t *bu = bee_user_by_handle( bee, ic, handle );
     398       
     399        if( !bu || !fullname ) return;
     400       
     401        if( !bu->fullname || strcmp( bu->fullname, fullname ) != 0 )
     402        {
     403                g_free( bu->fullname );
     404                bu->fullname = g_strdup( fullname );
    401405               
    402                 return;
    403                
    404                 /* Buddy seems to exist already. Let's ignore this request then...
    405                    Eventually subsequent calls to this function *should* be possible
    406                    when a buddy is in multiple groups. But for now BitlBee doesn't
    407                    even support groups so let's silently ignore this for now. */
    408         }
    409        
    410         memset( nick, 0, MAX_NICK_LENGTH + 1 );
    411         strcpy( nick, nick_get( ic->acc, handle ) );
    412        
    413         u = user_add( ic->irc, nick );
    414        
    415 //      if( !realname || !*realname ) realname = nick;
    416 //      u->realname = g_strdup( realname );
    417        
    418         if( ( s = strchr( handle, '@' ) ) )
    419         {
    420                 u->host = g_strdup( s + 1 );
    421                 u->user = g_strndup( handle, s - handle );
    422         }
    423         else if( ic->acc->server )
    424         {
    425                 u->host = g_strdup( ic->acc->server );
    426                 u->user = g_strdup( handle );
    427                
    428                 /* s/ /_/ ... important for AOL screennames */
    429                 for( s = u->user; *s; s ++ )
    430                         if( *s == ' ' )
    431                                 *s = '_';
    432         }
    433         else
    434         {
    435                 u->host = g_strdup( ic->acc->prpl->name );
    436                 u->user = g_strdup( handle );
    437         }
    438        
    439         u->ic = ic;
    440         u->handle = g_strdup( handle );
    441         if( group ) u->group = g_strdup( group );
    442         u->send_handler = buddy_send_handler;
    443         u->last_typing_notice = 0;
    444 }
    445 
    446 struct buddy *imcb_find_buddy( struct im_connection *ic, char *handle )
    447 {
    448         static struct buddy b[1];
    449         user_t *u;
    450        
    451         u = user_findhandle( ic, handle );
    452        
    453         if( !u )
    454                 return( NULL );
    455        
    456         memset( b, 0, sizeof( b ) );
    457         strncpy( b->name, handle, 80 );
    458         strncpy( b->show, u->realname, BUDDY_ALIAS_MAXLEN );
    459         b->present = u->online;
    460         b->ic = u->ic;
    461        
    462         return( b );
    463 }
    464 
    465 void imcb_rename_buddy( struct im_connection *ic, const char *handle, const char *realname )
    466 {
    467         user_t *u = user_findhandle( ic, handle );
    468         char *set;
    469        
    470         if( !u || !realname ) return;
    471        
    472         if( g_strcasecmp( u->realname, realname ) != 0 )
    473         {
    474                 if( u->realname != u->nick ) g_free( u->realname );
    475                
    476                 u->realname = g_strdup( realname );
    477                
    478                 if( ( ic->flags & OPT_LOGGED_IN ) && set_getbool( &ic->irc->set, "display_namechanges" ) )
    479                         imcb_log( ic, "User `%s' changed name to `%s'", u->nick, u->realname );
    480         }
    481        
    482         set = set_getstr( &ic->acc->set, "nick_source" );
    483         if( strcmp( set, "handle" ) != 0 )
    484         {
    485                 char *name = g_strdup( realname );
    486                
    487                 if( strcmp( set, "first_name" ) == 0 )
    488                 {
    489                         int i;
    490                         for( i = 0; name[i] && !isspace( name[i] ); i ++ ) {}
    491                         name[i] = '\0';
    492                 }
    493                
    494                 imcb_buddy_nick_hint( ic, handle, name );
    495                
    496                 g_free( name );
     406                if( bee->ui->user_fullname )
     407                        bee->ui->user_fullname( bee, bu );
    497408        }
    498409}
     
    500411void imcb_remove_buddy( struct im_connection *ic, const char *handle, char *group )
    501412{
    502         user_t *u;
    503        
    504         if( ( u = user_findhandle( ic, handle ) ) )
    505                 user_del( ic->irc, u->nick );
     413        bee_user_free( ic->bee, bee_user_by_handle( ic->bee, ic, handle ) );
    506414}
    507415
     
    510418void imcb_buddy_nick_hint( struct im_connection *ic, const char *handle, const char *nick )
    511419{
    512         user_t *u = user_findhandle( ic, handle );
    513         char newnick[MAX_NICK_LENGTH+1], *orig_nick;
    514        
    515         if( u && !u->online && !nick_saved( ic->acc, handle ) )
    516         {
    517                 /* Only do this if the person isn't online yet (which should
    518                    be the case if we just added it) and if the user hasn't
    519                    assigned a nickname to this buddy already. */
    520                
    521                 strncpy( newnick, nick, MAX_NICK_LENGTH );
    522                 newnick[MAX_NICK_LENGTH] = 0;
    523                
    524                 /* Some processing to make sure this string is a valid IRC nickname. */
    525                 nick_strip( newnick );
    526                 if( set_getbool( &ic->irc->set, "lcnicks" ) )
    527                         nick_lc( newnick );
    528                
    529                 if( strcmp( u->nick, newnick ) != 0 )
    530                 {
    531                         /* Only do this if newnick is different from the current one.
    532                            If rejoining a channel, maybe we got this nick already
    533                            (and dedupe would only add an underscore. */
    534                         nick_dedupe( ic->acc, handle, newnick );
    535                        
    536                         /* u->nick will be freed halfway the process, so it can't be
    537                            passed as an argument. */
    538                         orig_nick = g_strdup( u->nick );
    539                         user_rename( ic->irc, orig_nick, newnick );
    540                         g_free( orig_nick );
    541                 }
    542         }
     420        bee_t *bee = ic->bee;
     421        bee_user_t *bu = bee_user_by_handle( bee, ic, handle );
     422       
     423        if( !bu || !nick ) return;
     424       
     425        if( bee->ui->user_nick_hint )
     426                bee->ui->user_nick_hint( bee, bu, nick );
    543427}
    544428
     
    585469        data->ic = ic;
    586470        data->handle = g_strdup( handle );
    587         query_add( ic->irc, ic, s, imcb_ask_auth_cb_yes, imcb_ask_auth_cb_no, data );
     471        query_add( (irc_t *) ic->bee->ui_data, ic, s,
     472                   imcb_ask_auth_cb_yes, imcb_ask_auth_cb_no, data );
    588473}
    589474
     
    610495       
    611496        /* TODO: Make a setting for this! */
    612         if( user_findhandle( ic, handle ) != NULL )
     497        if( bee_user_by_handle( ic->bee, ic, handle ) != NULL )
    613498                return;
    614499       
     
    617502        data->ic = ic;
    618503        data->handle = g_strdup( handle );
    619         query_add( ic->irc, ic, s, imcb_ask_add_cb_yes, imcb_ask_add_cb_no, data );
    620 }
    621 
    622 
    623 /* server.c */                   
    624 
    625 void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, const char *state, const char *message )
    626 {
    627         user_t *u;
    628         int oa, oo;
    629        
    630         u = user_findhandle( ic, (char*) handle );
    631        
    632         if( !u )
    633         {
    634                 if( g_strcasecmp( set_getstr( &ic->irc->set, "handle_unknown" ), "add" ) == 0 )
    635                 {
    636                         imcb_add_buddy( ic, (char*) handle, NULL );
    637                         u = user_findhandle( ic, (char*) handle );
    638                 }
    639                 else
    640                 {
    641                         if( set_getbool( &ic->irc->set, "debug" ) || g_strcasecmp( set_getstr( &ic->irc->set, "handle_unknown" ), "ignore" ) != 0 )
    642                         {
    643                                 imcb_log( ic, "imcb_buddy_status() for unknown handle %s:", handle );
    644                                 imcb_log( ic, "flags = %d, state = %s, message = %s", flags,
    645                                           state ? state : "NULL", message ? message : "NULL" );
    646                         }
    647                        
    648                         return;
    649                 }
    650         }
    651        
    652         oa = u->away != NULL;
    653         oo = u->online;
    654        
    655         g_free( u->away );
    656         g_free( u->status_msg );
    657         u->away = u->status_msg = NULL;
    658        
    659         if( set_getbool( &ic->irc->set, "show_offline" ) && !u->online )
    660         {
    661                 /* always set users as online */
    662                 irc_spawn( ic->irc, u );
    663                 u->online = 1;
    664                 if( !( flags & OPT_LOGGED_IN ) )
    665                 {
    666                         /* set away message if user isn't really online */
    667                         u->away = g_strdup( "User is offline" );
    668                 }
    669         }
    670         else if( ( flags & OPT_LOGGED_IN ) && !u->online )
    671         {
    672                 irc_spawn( ic->irc, u );
    673                 u->online = 1;
    674         }
    675         else if( !( flags & OPT_LOGGED_IN ) && u->online )
    676         {
    677                 struct groupchat *c;
    678                
    679                 if( set_getbool( &ic->irc->set, "show_offline" ) )
    680                 {
    681                         /* keep offline users in channel and set away message to "offline" */
    682                         u->away = g_strdup( "User is offline" );
    683 
    684                         /* Keep showing him/her in the control channel but not in groupchats. */
    685                         for( c = ic->groupchats; c; c = c->next )
    686                         {
    687                                 if( remove_chat_buddy_silent( c, handle ) && c->joined )
    688                                         irc_part( c->ic->irc, u, c->channel );
    689                         }
    690                 }
    691                 else
    692                 {
    693                         /* kill offline users */
    694                         irc_kill( ic->irc, u );
    695                         u->online = 0;
    696 
    697                         /* Remove him/her from the groupchats to prevent PART messages after he/she QUIT already */
    698                         for( c = ic->groupchats; c; c = c->next )
    699                                 remove_chat_buddy_silent( c, handle );
    700                 }
    701         }
    702 
    703         if( flags & OPT_AWAY )
    704         {
    705                 if( state && message )
    706                 {
    707                         u->away = g_strdup_printf( "%s (%s)", state, message );
    708                 }
    709                 else if( state )
    710                 {
    711                         u->away = g_strdup( state );
    712                 }
    713                 else if( message )
    714                 {
    715                         u->away = g_strdup( message );
    716                 }
    717                 else
    718                 {
    719                         u->away = g_strdup( "Away" );
    720                 }
    721         }
    722         else
    723         {
    724                 u->status_msg = g_strdup( message );
    725         }
    726        
    727         /* early if-clause for show_offline even if there is some redundant code here because this isn't LISP but C ;) */
    728         if( set_getbool( &ic->irc->set, "show_offline" ) && set_getbool( &ic->irc->set, "away_devoice" ) )
    729         {
    730                 char *from;
    731                
    732                 if( set_getbool( &ic->irc->set, "simulate_netsplit" ) )
    733                 {
    734                         from = g_strdup( ic->irc->myhost );
    735                 }
    736                 else
    737                 {
    738                         from = g_strdup_printf( "%s!%s@%s", ic->irc->mynick, ic->irc->mynick,
    739                                                             ic->irc->myhost );
    740                 }
    741 
    742                 /* if we use show_offline, we op online users, voice away users, and devoice/deop offline users */
    743                 if( flags & OPT_LOGGED_IN )
    744                 {
    745                         /* user is "online" (either really online or away) */
    746                         irc_write( ic->irc, ":%s MODE %s %cv%co %s %s", from, ic->irc->channel,
    747                                                                   u->away?'+':'-', u->away?'-':'+', u->nick, u->nick );
    748                 }
    749                 else
    750                 {
    751                         /* user is offline */
    752                         irc_write( ic->irc, ":%s MODE %s -vo %s %s", from, ic->irc->channel, u->nick, u->nick );
    753                 }
    754         }
    755         else
    756         {
    757                 /* LISPy... */
    758                 if( ( set_getbool( &ic->irc->set, "away_devoice" ) ) &&         /* Don't do a thing when user doesn't want it */
    759                     ( u->online ) &&                                            /* Don't touch offline people */
    760                     ( ( ( u->online != oo ) && !u->away ) ||                    /* Voice joining people */
    761                       ( ( u->online == oo ) && ( oa == !u->away ) ) ) )         /* (De)voice people changing state */
    762                 {
    763                         char *from;
    764 
    765                         if( set_getbool( &ic->irc->set, "simulate_netsplit" ) )
    766                         {
    767                                 from = g_strdup( ic->irc->myhost );
    768                         }
    769                         else
    770                         {
    771                                 from = g_strdup_printf( "%s!%s@%s", ic->irc->mynick, ic->irc->mynick,
    772                                                                     ic->irc->myhost );
    773                         }
    774                         irc_write( ic->irc, ":%s MODE %s %cv %s", from, ic->irc->channel,
    775                                                                   u->away?'-':'+', u->nick );
    776                         g_free( from );
    777                 }
    778         }
    779 }
    780 
    781 void imcb_buddy_msg( struct im_connection *ic, const char *handle, char *msg, uint32_t flags, time_t sent_at )
    782 {
    783         irc_t *irc = ic->irc;
    784         char *wrapped, *ts = NULL;
    785         user_t *u;
    786        
    787         u = user_findhandle( ic, handle );
    788        
    789         if( !u )
    790         {
    791                 char *h = set_getstr( &irc->set, "handle_unknown" );
    792                
    793                 if( g_strcasecmp( h, "ignore" ) == 0 )
    794                 {
    795                         if( set_getbool( &irc->set, "debug" ) )
    796                                 imcb_log( ic, "Ignoring message from unknown handle %s", handle );
    797                        
    798                         return;
    799                 }
    800                 else if( g_strncasecmp( h, "add", 3 ) == 0 )
    801                 {
    802                         int private = set_getbool( &irc->set, "private" );
    803                        
    804                         if( h[3] )
    805                         {
    806                                 if( g_strcasecmp( h + 3, "_private" ) == 0 )
    807                                         private = 1;
    808                                 else if( g_strcasecmp( h + 3, "_channel" ) == 0 )
    809                                         private = 0;
    810                         }
    811                        
    812                         imcb_add_buddy( ic, handle, NULL );
    813                         u = user_findhandle( ic, handle );
    814                         u->is_private = private;
    815                 }
    816                 else
    817                 {
    818                         imcb_log( ic, "Message from unknown handle %s:", handle );
    819                         u = user_find( irc, irc->mynick );
    820                 }
    821         }
    822        
    823         if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) ||
    824             ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )
    825                 strip_html( msg );
    826        
    827         if( set_getbool( &ic->irc->set, "display_timestamps" ) &&
    828             ( ts = format_timestamp( irc, sent_at ) ) )
    829         {
    830                 char *new = g_strconcat( ts, msg, NULL );
    831                 g_free( ts );
    832                 ts = msg = new;
    833         }
    834        
    835         wrapped = word_wrap( msg, 425 );
    836         irc_msgfrom( irc, u->nick, wrapped );
    837         g_free( wrapped );
    838         g_free( ts );
    839 }
    840 
    841 void imcb_buddy_typing( struct im_connection *ic, char *handle, uint32_t flags )
    842 {
    843         user_t *u;
    844        
    845         if( !set_getbool( &ic->irc->set, "typing_notice" ) )
    846                 return;
    847        
    848         if( ( u = user_findhandle( ic, handle ) ) )
    849         {
    850                 char buf[256];
    851                
    852                 g_snprintf( buf, 256, "\1TYPING %d\1", ( flags >> 8 ) & 3 );
    853                 irc_privmsg( ic->irc, u, "PRIVMSG", ic->irc->nick, NULL, buf );
    854         }
    855 }
    856 
    857 struct groupchat *imcb_chat_new( struct im_connection *ic, const char *handle )
    858 {
    859         struct groupchat *c;
    860        
    861         /* This one just creates the conversation structure, user won't see anything yet */
    862        
    863         if( ic->groupchats )
    864         {
    865                 for( c = ic->groupchats; c->next; c = c->next );
    866                 c = c->next = g_new0( struct groupchat, 1 );
    867         }
    868         else
    869                 ic->groupchats = c = g_new0( struct groupchat, 1 );
    870        
    871         c->ic = ic;
    872         c->title = g_strdup( handle );
    873         c->channel = g_strdup_printf( "&chat_%03d", ic->irc->c_id++ );
    874         c->topic = g_strdup_printf( "BitlBee groupchat: \"%s\". Please keep in mind that root-commands won't work here. Have fun!", c->title );
    875        
    876         if( set_getbool( &ic->irc->set, "debug" ) )
    877                 imcb_log( ic, "Creating new conversation: (id=%p,handle=%s)", c, handle );
    878        
    879         return c;
    880 }
    881 
    882 void imcb_chat_name_hint( struct groupchat *c, const char *name )
    883 {
    884         if( !c->joined )
    885         {
    886                 struct im_connection *ic = c->ic;
    887                 char stripped[MAX_NICK_LENGTH+1], *full_name;
    888                
    889                 strncpy( stripped, name, MAX_NICK_LENGTH );
    890                 stripped[MAX_NICK_LENGTH] = '\0';
    891                 nick_strip( stripped );
    892                 if( set_getbool( &ic->irc->set, "lcnicks" ) )
    893                         nick_lc( stripped );
    894                
    895                 full_name = g_strdup_printf( "&%s", stripped );
    896                
    897                 if( stripped[0] &&
    898                     nick_cmp( stripped, ic->irc->channel + 1 ) != 0 &&
    899                     irc_chat_by_channel( ic->irc, full_name ) == NULL )
    900                 {
    901                         g_free( c->channel );
    902                         c->channel = full_name;
    903                 }
    904                 else
    905                 {
    906                         g_free( full_name );
    907                 }
    908         }
    909 }
    910 
    911 void imcb_chat_free( struct groupchat *c )
    912 {
    913         struct im_connection *ic = c->ic;
    914         struct groupchat *l;
    915         GList *ir;
    916        
    917         if( set_getbool( &ic->irc->set, "debug" ) )
    918                 imcb_log( ic, "You were removed from conversation %p", c );
    919        
    920         if( c )
    921         {
    922                 if( c->joined )
    923                 {
    924                         user_t *u, *r;
    925                        
    926                         r = user_find( ic->irc, ic->irc->mynick );
    927                         irc_privmsg( ic->irc, r, "PRIVMSG", c->channel, "", "Cleaning up channel, bye!" );
    928                        
    929                         u = user_find( ic->irc, ic->irc->nick );
    930                         irc_kick( ic->irc, u, c->channel, r );
    931                         /* irc_part( ic->irc, u, c->channel ); */
    932                 }
    933                
    934                 /* Find the previous chat in the linked list. */
    935                 for( l = ic->groupchats; l && l->next != c; l = l->next );
    936                
    937                 if( l )
    938                         l->next = c->next;
    939                 else
    940                         ic->groupchats = c->next;
    941                
    942                 for( ir = c->in_room; ir; ir = ir->next )
    943                         g_free( ir->data );
    944                 g_list_free( c->in_room );
    945                 g_free( c->channel );
    946                 g_free( c->title );
    947                 g_free( c->topic );
    948                 g_free( c );
    949         }
    950 }
    951 
    952 void imcb_chat_msg( struct groupchat *c, const char *who, char *msg, uint32_t flags, time_t sent_at )
    953 {
    954         struct im_connection *ic = c->ic;
    955         char *wrapped;
    956         user_t *u;
    957        
    958         /* Gaim sends own messages through this too. IRC doesn't want this, so kill them */
    959         if( g_strcasecmp( who, ic->acc->user ) == 0 )
    960                 return;
    961        
    962         u = user_findhandle( ic, who );
    963        
    964         if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) ||
    965             ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )
    966                 strip_html( msg );
    967        
    968         wrapped = word_wrap( msg, 425 );
    969         if( c && u )
    970         {
    971                 char *ts = NULL;
    972                 if( set_getbool( &ic->irc->set, "display_timestamps" ) )
    973                         ts = format_timestamp( ic->irc, sent_at );
    974                 irc_privmsg( ic->irc, u, "PRIVMSG", c->channel, ts ? : "", wrapped );
    975                 g_free( ts );
    976         }
    977         else
    978         {
    979                 imcb_log( ic, "Message from/to conversation %s@%p (unknown conv/user): %s", who, c, wrapped );
    980         }
    981         g_free( wrapped );
    982 }
    983 
    984 void imcb_chat_log( struct groupchat *c, char *format, ... )
    985 {
    986         irc_t *irc = c->ic->irc;
    987         va_list params;
    988         char *text;
    989         user_t *u;
    990        
    991         va_start( params, format );
    992         text = g_strdup_vprintf( format, params );
    993         va_end( params );
    994        
    995         u = user_find( irc, irc->mynick );
    996        
    997         irc_privmsg( irc, u, "PRIVMSG", c->channel, "System message: ", text );
    998        
    999         g_free( text );
    1000 }
    1001 
    1002 void imcb_chat_topic( struct groupchat *c, char *who, char *topic, time_t set_at )
    1003 {
    1004         struct im_connection *ic = c->ic;
    1005         user_t *u = NULL;
    1006        
    1007         if( who == NULL)
    1008                 u = user_find( ic->irc, ic->irc->mynick );
    1009         else if( g_strcasecmp( who, ic->acc->user ) == 0 )
    1010                 u = user_find( ic->irc, ic->irc->nick );
    1011         else
    1012                 u = user_findhandle( ic, who );
    1013        
    1014         if( ( g_strcasecmp( set_getstr( &ic->irc->set, "strip_html" ), "always" ) == 0 ) ||
    1015             ( ( ic->flags & OPT_DOES_HTML ) && set_getbool( &ic->irc->set, "strip_html" ) ) )
    1016                 strip_html( topic );
    1017        
    1018         g_free( c->topic );
    1019         c->topic = g_strdup( topic );
    1020        
    1021         if( c->joined && u )
    1022                 irc_write( ic->irc, ":%s!%s@%s TOPIC %s :%s", u->nick, u->user, u->host, c->channel, topic );
    1023 }
    1024 
    1025 
    1026 /* buddy_chat.c */
    1027 
    1028 void imcb_chat_add_buddy( struct groupchat *b, const char *handle )
    1029 {
    1030         user_t *u = user_findhandle( b->ic, handle );
    1031         int me = 0;
    1032        
    1033         if( set_getbool( &b->ic->irc->set, "debug" ) )
    1034                 imcb_log( b->ic, "User %s added to conversation %p", handle, b );
    1035        
    1036         /* It might be yourself! */
    1037         if( b->ic->acc->prpl->handle_cmp( handle, b->ic->acc->user ) == 0 )
    1038         {
    1039                 u = user_find( b->ic->irc, b->ic->irc->nick );
    1040                 if( !b->joined )
    1041                         irc_join( b->ic->irc, u, b->channel );
    1042                 b->joined = me = 1;
    1043         }
    1044        
    1045         /* Most protocols allow people to join, even when they're not in
    1046            your contact list. Try to handle that here */
    1047         if( !u )
    1048         {
    1049                 imcb_add_buddy( b->ic, handle, NULL );
    1050                 u = user_findhandle( b->ic, handle );
    1051         }
    1052        
    1053         /* Add the handle to the room userlist, if it's not 'me' */
    1054         if( !me )
    1055         {
    1056                 if( b->joined )
    1057                         irc_join( b->ic->irc, u, b->channel );
    1058                 b->in_room = g_list_append( b->in_room, g_strdup( handle ) );
    1059         }
    1060 }
    1061 
    1062 /* This function is one BIG hack... :-( EREWRITE */
    1063 void imcb_chat_remove_buddy( struct groupchat *b, const char *handle, const char *reason )
    1064 {
    1065         user_t *u;
    1066         int me = 0;
    1067        
    1068         if( set_getbool( &b->ic->irc->set, "debug" ) )
    1069                 imcb_log( b->ic, "User %s removed from conversation %p (%s)", handle, b, reason ? reason : "" );
    1070        
    1071         /* It might be yourself! */
    1072         if( g_strcasecmp( handle, b->ic->acc->user ) == 0 )
    1073         {
    1074                 if( b->joined == 0 )
    1075                         return;
    1076                
    1077                 u = user_find( b->ic->irc, b->ic->irc->nick );
    1078                 b->joined = 0;
    1079                 me = 1;
    1080         }
    1081         else
    1082         {
    1083                 u = user_findhandle( b->ic, handle );
    1084         }
    1085        
    1086         if( me || ( remove_chat_buddy_silent( b, handle ) && b->joined && u ) )
    1087                 irc_part( b->ic->irc, u, b->channel );
    1088 }
    1089 
    1090 static int remove_chat_buddy_silent( struct groupchat *b, const char *handle )
    1091 {
    1092         GList *i;
    1093        
    1094         /* Find the handle in the room userlist and shoot it */
    1095         i = b->in_room;
    1096         while( i )
    1097         {
    1098                 if( g_strcasecmp( handle, i->data ) == 0 )
    1099                 {
    1100                         g_free( i->data );
    1101                         b->in_room = g_list_remove( b->in_room, i->data );
    1102                         return( 1 );
    1103                 }
    1104                
    1105                 i = i->next;
    1106         }
    1107        
    1108         return( 0 );
    1109 }
    1110 
    1111 
    1112 /* Misc. BitlBee stuff which shouldn't really be here */
    1113 
    1114 char *set_eval_away_devoice( set_t *set, char *value )
    1115 {
    1116         irc_t *irc = set->data;
    1117         int st;
    1118        
    1119         if( !is_bool( value ) )
    1120                 return SET_INVALID;
    1121        
    1122         st = bool2int( value );
    1123        
    1124         /* Horror.... */
    1125        
    1126         if( st != set_getbool( &irc->set, "away_devoice" ) )
    1127         {
    1128                 char list[80] = "";
    1129                 user_t *u = irc->users;
    1130                 int i = 0, count = 0;
    1131                 char pm;
    1132                 char v[80];
    1133                
    1134                 if( st )
    1135                         pm = '+';
    1136                 else
    1137                         pm = '-';
    1138                
    1139                 while( u )
    1140                 {
    1141                         if( u->ic && u->online && !u->away )
    1142                         {
    1143                                 if( ( strlen( list ) + strlen( u->nick ) ) >= 79 )
    1144                                 {
    1145                                         for( i = 0; i < count; v[i++] = 'v' ); v[i] = 0;
    1146                                         irc_write( irc, ":%s MODE %s %c%s%s",
    1147                                                    irc->myhost,
    1148                                                    irc->channel, pm, v, list );
    1149                                        
    1150                                         *list = 0;
    1151                                         count = 0;
    1152                                 }
    1153                                
    1154                                 sprintf( list + strlen( list ), " %s", u->nick );
    1155                                 count ++;
    1156                         }
    1157                         u = u->next;
    1158                 }
    1159                
    1160                 /* $v = 'v' x $i */
    1161                 for( i = 0; i < count; v[i++] = 'v' ); v[i] = 0;
    1162                 irc_write( irc, ":%s MODE %s %c%s%s", irc->myhost,
    1163                                                             irc->channel, pm, v, list );
    1164         }
    1165        
    1166         return value;
    1167 }
    1168 
    1169 char *set_eval_timezone( set_t *set, char *value )
    1170 {
    1171         char *s;
    1172        
    1173         if( strcmp( value, "local" ) == 0 ||
    1174             strcmp( value, "gmt" ) == 0 || strcmp( value, "utc" ) == 0 )
    1175                 return value;
    1176        
    1177         /* Otherwise: +/- at the beginning optional, then one or more numbers,
    1178            possibly followed by a colon and more numbers. Don't bother bound-
    1179            checking them since users are free to shoot themselves in the foot. */
    1180         s = value;
    1181         if( *s == '+' || *s == '-' )
    1182                 s ++;
    1183        
    1184         /* \d+ */
    1185         if( !isdigit( *s ) )
    1186                 return SET_INVALID;
    1187         while( *s && isdigit( *s ) ) s ++;
    1188        
    1189         /* EOS? */
    1190         if( *s == '\0' )
    1191                 return value;
    1192        
    1193         /* Otherwise, colon */
    1194         if( *s != ':' )
    1195                 return SET_INVALID;
    1196         s ++;
    1197        
    1198         /* \d+ */
    1199         if( !isdigit( *s ) )
    1200                 return SET_INVALID;
    1201         while( *s && isdigit( *s ) ) s ++;
    1202        
    1203         /* EOS */
    1204         return *s == '\0' ? value : SET_INVALID;
    1205 }
    1206 
    1207 static char *format_timestamp( irc_t *irc, time_t msg_ts )
    1208 {
    1209         time_t now_ts = time( NULL );
    1210         struct tm now, msg;
    1211         char *set;
    1212        
    1213         /* If the timestamp is <= 0 or less than a minute ago, discard it as
    1214            it doesn't seem to add to much useful info and/or might be noise. */
    1215         if( msg_ts <= 0 || msg_ts > now_ts - 60 )
    1216                 return NULL;
    1217        
    1218         set = set_getstr( &irc->set, "timezone" );
    1219         if( strcmp( set, "local" ) == 0 )
    1220         {
    1221                 localtime_r( &now_ts, &now );
    1222                 localtime_r( &msg_ts, &msg );
    1223         }
    1224         else
    1225         {
    1226                 int hr, min = 0, sign = 60;
    1227                
    1228                 if( set[0] == '-' )
    1229                 {
    1230                         sign *= -1;
    1231                         set ++;
    1232                 }
    1233                 else if( set[0] == '+' )
    1234                 {
    1235                         set ++;
    1236                 }
    1237                
    1238                 if( sscanf( set, "%d:%d", &hr, &min ) >= 1 )
    1239                 {
    1240                         msg_ts += sign * ( hr * 60 + min );
    1241                         now_ts += sign * ( hr * 60 + min );
    1242                 }
    1243                
    1244                 gmtime_r( &now_ts, &now );
    1245                 gmtime_r( &msg_ts, &msg );
    1246         }
    1247        
    1248         if( msg.tm_year == now.tm_year && msg.tm_yday == now.tm_yday )
    1249                 return g_strdup_printf( "\x02[\x02\x02\x02%02d:%02d:%02d\x02]\x02 ",
    1250                                         msg.tm_hour, msg.tm_min, msg.tm_sec );
    1251         else
    1252                 return g_strdup_printf( "\x02[\x02\x02\x02%04d-%02d-%02d "
    1253                                         "%02d:%02d:%02d\x02]\x02 ",
    1254                                         msg.tm_year + 1900, msg.tm_mon + 1, msg.tm_mday,
    1255                                         msg.tm_hour, msg.tm_min, msg.tm_sec );
     504        query_add( (irc_t *) ic->bee->ui_data, ic, s,
     505                   imcb_ask_add_cb_yes, imcb_ask_add_cb_no, data );
     506}
     507
     508struct bee_user *imcb_buddy_by_handle( struct im_connection *ic, const char *handle )
     509{
     510        return bee_user_by_handle( ic->bee, ic, handle );
    1256511}
    1257512
    1258513/* The plan is to not allow straight calls to prpl functions anymore, but do
    1259514   them all from some wrappers. We'll start to define some down here: */
    1260 
    1261 int imc_buddy_msg( struct im_connection *ic, char *handle, char *msg, int flags )
    1262 {
    1263         char *buf = NULL;
    1264         int st;
    1265        
    1266         if( ( ic->flags & OPT_DOES_HTML ) && ( g_strncasecmp( msg, "<html>", 6 ) != 0 ) )
    1267         {
    1268                 buf = escape_html( msg );
    1269                 msg = buf;
    1270         }
    1271        
    1272         st = ic->acc->prpl->buddy_msg( ic, handle, msg, flags );
    1273         g_free( buf );
    1274        
    1275         return st;
    1276 }
    1277515
    1278516int imc_chat_msg( struct groupchat *c, char *msg, int flags )
     
    1303541       
    1304542        away = set_getstr( &ic->acc->set, "away" ) ?
    1305              : set_getstr( &ic->irc->set, "away" );
     543             : set_getstr( &ic->bee->set, "away" );
    1306544        if( away && *away )
    1307545        {
     
    1314552                away = NULL;
    1315553                msg = set_getstr( &ic->acc->set, "status" ) ?
    1316                     : set_getstr( &ic->irc->set, "status" );
     554                    : set_getstr( &ic->bee->set, "status" );
    1317555        }
    1318556       
  • protocols/nogaim.h

    r38ff846 r8b8def58  
    22  * BitlBee -- An IRC to other IM-networks gateway                     *
    33  *                                                                    *
    4   * Copyright 2002-2004 Wilmer van der Gaast and others                *
     4  * Copyright 2002-2010 Wilmer van der Gaast and others                *
    55  \********************************************************************/
    66
     
    4545#include "proxy.h"
    4646#include "query.h"
     47#include "md5.h"
     48#include "ft.h"
    4749
    4850#define BUDDY_ALIAS_MAXLEN 388   /* because MSN names can be 387 characters */
     
    8587       
    8688        /* BitlBee */
    87         irc_t *irc;
    88        
    89         struct groupchat *groupchats;
     89        bee_t *bee;
     90       
     91        GSList *groupchats;
    9092};
    9193
     
    98100         * already, for example to avoid adding somebody two times. */
    99101        GList *in_room;
    100         GList *ignored;
    101        
    102         struct groupchat *next;
    103         char *channel;
     102        //GList *ignored;
     103       
     104        //struct groupchat *next;
    104105        /* The title variable contains the ID you gave when you created the
    105106         * chat using imcb_chat_new(). */
     
    112113         * structure for your protocol's needs. */
    113114        void *data;
     115        void *ui_data;
    114116};
    115117
     
    132134         * - The user sees this name ie. when imcb_log() is used. */
    133135        const char *name;
     136        void *data;
    134137
    135138        /* Added this one to be able to add per-account settings, don't think
     
    228231        void (* auth_allow)     (struct im_connection *, const char *who);
    229232        void (* auth_deny)      (struct im_connection *, const char *who);
     233
     234        /* Incoming transfer request */
     235        void (* transfer_request) (struct im_connection *, file_transfer_t *ft, char *handle );
    230236};
    231237
     
    281287G_MODULE_EXPORT void imcb_buddy_nick_hint( struct im_connection *ic, const char *handle, const char *nick );
    282288
    283 /* Buddy activity */
    284 /* To manipulate the status of a handle.
    285  * - flags can be |='d with OPT_* constants. You will need at least:
    286  *   OPT_LOGGED_IN and OPT_AWAY.
    287  * - 'state' and 'message' can be NULL */
    288 G_MODULE_EXPORT void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, const char *state, const char *message );
    289 /* Not implemented yet! */ G_MODULE_EXPORT void imcb_buddy_times( struct im_connection *ic, const char *handle, time_t login, time_t idle );
    290 /* Call when a handle says something. 'flags' and 'sent_at may be just 0. */
    291 G_MODULE_EXPORT void imcb_buddy_msg( struct im_connection *ic, const char *handle, char *msg, uint32_t flags, time_t sent_at );
    292289G_MODULE_EXPORT void imcb_buddy_typing( struct im_connection *ic, char *handle, uint32_t flags );
     290G_MODULE_EXPORT struct bee_user *imcb_buddy_by_handle( struct im_connection *ic, const char *handle );
    293291G_MODULE_EXPORT void imcb_clean_handle( struct im_connection *ic, char *handle );
    294292
     
    316314/* Actions, or whatever. */
    317315int imc_away_send_update( struct im_connection *ic );
    318 int imc_buddy_msg( struct im_connection *ic, char *handle, char *msg, int flags );
    319316int imc_chat_msg( struct groupchat *c, char *msg, int flags );
    320317
  • protocols/oscar/Makefile

    r38ff846 r8b8def58  
    88
    99-include ../../Makefile.settings
     10ifdef SRCDIR
     11SRCDIR := $(SRCDIR)protocols/oscar/
     12CFLAGS += -I$(SRCDIR)
     13endif
    1014
    1115# [SH] Program variables
     
    3337$(objects): ../../Makefile.settings Makefile
    3438
    35 $(objects): %.o: %.c
     39$(objects): %.o: $(SRCDIR)%.c
    3640        @echo '*' Compiling $<
    3741        @$(CC) -c $(CFLAGS) $< -o $@
  • protocols/oscar/oscar.c

    r38ff846 r8b8def58  
    254254
    255255        u = t = g_strdup(s);
    256 
    257         strcpy(t, s);
    258256        g_strdown(t);
    259257
     
    290288        odata = (struct oscar_data *)ic->proto_data;
    291289
    292         if (condition & GAIM_INPUT_READ) {
     290        if (condition & B_EV_IO_READ) {
    293291                if (aim_get_command(odata->sess, conn) >= 0) {
    294292                        aim_rxdispatch(odata->sess);
     
    362360
    363361        aim_conn_completeconnect(sess, conn);
    364         ic->inpa = b_input_add(conn->fd, GAIM_INPUT_READ,
     362        ic->inpa = b_input_add(conn->fd, B_EV_IO_READ,
    365363                        oscar_callback, conn);
    366364       
     
    493491
    494492        aim_conn_completeconnect(sess, bosconn);
    495         ic->inpa = b_input_add(bosconn->fd, GAIM_INPUT_READ,
     493        ic->inpa = b_input_add(bosconn->fd, B_EV_IO_READ,
    496494                        oscar_callback, bosconn);
    497495        imcb_log(ic, _("Connection established, cookie sent"));
     
    652650        struct im_connection *ic = sess->aux_data;
    653651        struct chat_connection *chatcon;
     652        struct groupchat *c = NULL;
    654653        static int id = 1;
    655654
     
    664663        chatcon = find_oscar_chat_by_conn(ic, fr->conn);
    665664        chatcon->id = id;
    666         chatcon->cnv = imcb_chat_new(ic, chatcon->show);
     665       
     666        c = bee_chat_by_title(ic->bee, ic, chatcon->show);
     667        if (c && !c->data)
     668                chatcon->cnv = c;
     669        else
     670                chatcon->cnv = imcb_chat_new(ic, chatcon->show);
    667671        chatcon->cnv->data = chatcon;
    668672
     
    703707
    704708        aim_conn_completeconnect(sess, tstconn);
    705         odata->cnpa = b_input_add(tstconn->fd, GAIM_INPUT_READ,
     709        odata->cnpa = b_input_add(tstconn->fd, B_EV_IO_READ,
    706710                                        oscar_callback, tstconn);
    707711       
     
    731735
    732736        aim_conn_completeconnect(sess, tstconn);
    733         odata->paspa = b_input_add(tstconn->fd, GAIM_INPUT_READ,
     737        odata->paspa = b_input_add(tstconn->fd, B_EV_IO_READ,
    734738                                oscar_callback, tstconn);
    735739       
     
    767771        aim_conn_completeconnect(sess, ccon->conn);
    768772        ccon->inpa = b_input_add(tstconn->fd,
    769                         GAIM_INPUT_READ,
     773                        B_EV_IO_READ,
    770774                        oscar_callback, tstconn);
    771775        odata->oscar_chats = g_slist_append(odata->oscar_chats, ccon);
     
    934938        tmp = normalize(info->sn);
    935939        imcb_buddy_status(ic, tmp, flags, state_string, NULL);
    936         /* imcb_buddy_times(ic, tmp, signon, time_idle); */
     940        imcb_buddy_times(ic, tmp, signon, time_idle);
    937941
    938942
     
    10601064        aim_ssi_auth_reply(od->sess, od->conn, uin, 1, "");
    10611065        // aim_send_im_ch4(od->sess, uin, AIM_ICQMSG_AUTHGRANTED, &message);
    1062         if(imcb_find_buddy(data->ic, uin) == NULL)
    1063                 imcb_ask_add(data->ic, uin, NULL);
     1066        imcb_ask_add(data->ic, uin, NULL);
    10641067       
    10651068        g_free(uin);
     
    18221825        struct oscar_data *odata = (struct oscar_data *)g->proto_data;
    18231826        if (odata->icq) {
     1827                /** FIXME(wilmer): Hmm, lost the ability to get away msgs here, do we care to get that back?
    18241828                struct buddy *budlight = imcb_find_buddy(g, who);
    18251829                if (budlight)
     
    18271831                                if (budlight->caps & AIM_CAPS_ICQSERVERRELAY)
    18281832                                        aim_send_im_ch2_geticqmessage(odata->sess, who, (budlight->uc & 0xff80) >> 7);
     1833                */
    18291834        } else
    18301835                aim_getinfo(odata->sess, odata->conn, who, AIM_GETINFO_AWAYMESSAGE);
     
    19531958static int gaim_ssi_parselist(aim_session_t *sess, aim_frame_t *fr, ...) {
    19541959        struct im_connection *ic = sess->aux_data;
    1955         struct aim_ssi_item *curitem;
     1960        struct aim_ssi_item *curitem, *curgroup;
    19561961        int tmp;
    19571962        char *nrm;
     
    19641969                switch (curitem->type) {
    19651970                        case 0x0000: /* Buddy */
    1966                                 if ((curitem->name) && (!imcb_find_buddy(ic, nrm))) {
     1971                                if ((curitem->name) && (!imcb_buddy_by_handle(ic, nrm))) {
    19671972                                        char *realname = NULL;
    19681973
    19691974                                        if (curitem->data && aim_gettlv(curitem->data, 0x0131, 1))
    19701975                                                    realname = aim_gettlv_str(curitem->data, 0x0131, 1);
    1971                                                
    1972                                         imcb_add_buddy(ic, nrm, NULL);
     1976                                       
     1977                                        imcb_add_buddy(ic, nrm, curgroup->gid == curitem->gid ? curgroup->name : NULL);
    19731978                                       
    19741979                                        if (realname) {
     
    19781983                                        }
    19791984                                }
     1985                                break;
     1986
     1987                        case 0x0001: /* Group */
     1988                                curgroup = curitem;
    19801989                                break;
    19811990
     
    25202529        static int chat_id = 0;
    25212530        char * chatname;
     2531        struct groupchat *c;
    25222532       
    25232533        chatname = g_strdup_printf("%s%s_%d", isdigit(*ic->acc->user) ? "icq_" : "",
    25242534                                   ic->acc->user, chat_id++);
    2525  
     2535       
     2536        c = imcb_chat_new(ic, chatname);
    25262537        ret = oscar_chat_join(ic, chatname, NULL, NULL);
    2527 
    25282538        aim_chat_invite(od->sess, od->conn, who, "", 4, chatname, 0x0);
    25292539
  • protocols/twitter/Makefile

    r38ff846 r8b8def58  
    88
    99-include ../../Makefile.settings
     10ifdef SRCDIR
     11SRCDIR := $(SRCDIR)protocols/twitter/
     12endif
    1013
    1114# [SH] Program variables
     
    3336$(objects): ../../Makefile.settings Makefile
    3437
    35 $(objects): %.o: %.c
     38$(objects): %.o: $(SRCDIR)%.c
    3639        @echo '*' Compiling $<
    3740        @$(CC) -c $(CFLAGS) $< -o $@
  • protocols/twitter/twitter_lib.c

    r38ff846 r8b8def58  
    105105
    106106        // Check if the buddy is allready in the buddy list.
    107         if (!imcb_find_buddy( ic, name ))
     107        if (!bee_user_by_handle( ic->bee, ic, name ))
    108108        {
    109109                char *mode = set_getstr(&ic->acc->set, "mode");
  • protocols/yahoo/Makefile

    r38ff846 r8b8def58  
    88
    99-include ../../Makefile.settings
     10ifdef SRCDIR
     11SRCDIR := $(SRCDIR)protocols/yahoo/
     12endif
    1013
    1114# [SH] Program variables
     
    3336$(objects): ../../Makefile.settings Makefile
    3437
    35 $(objects): %.o: %.c
     38$(objects): %.o: $(SRCDIR)%.c
    3639        @echo '*' Compiling $<
    3740        @$(CC) -c $(CFLAGS) $< -o $@
  • protocols/yahoo/yahoo.c

    r38ff846 r8b8def58  
    158158       
    159159        while( ic->groupchats )
    160                 imcb_chat_free( ic->groupchats );
     160                imcb_chat_free( ic->groupchats->data );
    161161       
    162162        for( l = yd->buddygroups; l; l = l->next )
     
    613613        imcb_buddy_status( ic, who, flags, state_string, msg );
    614614       
    615         /* Not implemented yet...
    616615        if( stat == YAHOO_STATUS_IDLE )
    617                 imcb_buddy_times( ic, who, 0, away );
    618         */
     616                imcb_buddy_times( ic, who, 0, idle );
    619617}
    620618
     
    686684               
    687685                inp->d = d;
    688                 d->tag = inp->h = b_input_add( fd, GAIM_INPUT_READ, (b_event_handler) byahoo_read_ready_callback, (gpointer) d );
     686                d->tag = inp->h = b_input_add( fd, B_EV_IO_READ, (b_event_handler) byahoo_read_ready_callback, (gpointer) d );
    689687        }
    690688        else if( cond == YAHOO_INPUT_WRITE )
     
    697695               
    698696                inp->d = d;
    699                 d->tag = inp->h = b_input_add( fd, GAIM_INPUT_WRITE, (b_event_handler) byahoo_write_ready_callback, (gpointer) d );
     697                d->tag = inp->h = b_input_add( fd, B_EV_IO_WRITE, (b_event_handler) byahoo_write_ready_callback, (gpointer) d );
    700698        }
    701699        else
     
    796794        struct byahoo_conf_invitation *inv = data;
    797795        struct groupchat *b;
    798        
    799         for( b = inv->ic->groupchats; b; b = b->next )
     796        GSList *l;
     797       
     798        for( l = inv->ic->groupchats; l; l = l->next )
     799        {
     800                b = l->data;
    800801                if( b == inv->c )
    801802                        break;
     803        }
    802804       
    803805        if( b != NULL )
     
    865867{
    866868        struct im_connection *ic = byahoo_get_ic_by_id( id );
    867         struct groupchat *c;
    868        
    869         for( c = ic->groupchats; c && strcmp( c->title, room ) != 0; c = c->next );
     869        struct groupchat *c = bee_chat_by_title( ic->bee, ic, room );
    870870       
    871871        if( c )
     
    877877{
    878878        struct im_connection *ic = byahoo_get_ic_by_id( id );
    879         struct groupchat *c;
    880        
    881         for( c = ic->groupchats; c && strcmp( c->title, room ) != 0; c = c->next );
     879        struct groupchat *c = bee_chat_by_title( ic->bee, ic, room );
    882880       
    883881        if( c )
     
    889887        struct im_connection *ic = byahoo_get_ic_by_id( id );
    890888        char *m = byahoo_strip( msg );
    891         struct groupchat *c;
    892        
    893         for( c = ic->groupchats; c && strcmp( c->title, room ) != 0; c = c->next );
     889        struct groupchat *c = bee_chat_by_title( ic->bee, ic, room );
    894890       
    895891        if( c )
  • query.c

    r38ff846 r8b8def58  
    6464        }
    6565       
    66         if( g_strcasecmp( set_getstr( &irc->set, "query_order" ), "lifo" ) == 0 || irc->queries == q )
     66        if( g_strcasecmp( set_getstr( &irc->b->set, "query_order" ), "lifo" ) == 0 || irc->queries == q )
    6767                query_display( irc, q );
    6868       
     
    179179        query_t *q;
    180180       
    181         if( g_strcasecmp( set_getstr( &irc->set, "query_order" ), "fifo" ) == 0 )
     181        if( g_strcasecmp( set_getstr( &irc->b->set, "query_order" ), "fifo" ) == 0 )
    182182                q = irc->queries;
    183183        else
  • root_commands.c

    r38ff846 r8b8def58  
    2626#define BITLBEE_CORE
    2727#include "commands.h"
    28 #include "crypting.h"
    2928#include "bitlbee.h"
    3029#include "help.h"
     
    3332#include <string.h>
    3433
    35 void root_command_string( irc_t *irc, user_t *u, char *command, int flags )
    36 {
    37         char *cmd[IRC_MAX_ARGS];
    38         char *s;
    39         int k;
    40         char q = 0;
    41        
    42         memset( cmd, 0, sizeof( cmd ) );
    43         cmd[0] = command;
    44         k = 1;
    45         for( s = command; *s && k < ( IRC_MAX_ARGS - 1 ); s ++ )
    46                 if( *s == ' ' && !q )
    47                 {
    48                         *s = 0;
    49                         while( *++s == ' ' );
    50                         if( *s == '"' || *s == '\'' )
    51                         {
    52                                 q = *s;
    53                                 s ++;
    54                         }
    55                         if( *s )
    56                         {
    57                                 cmd[k++] = s;
    58                                 s --;
    59                         }
    60                         else
    61                         {
    62                                 break;
    63                         }
    64                 }
    65                 else if( *s == '\\' && ( ( !q && s[1] ) || ( q && q == s[1] ) ) )
    66                 {
    67                         char *cpy;
    68                        
    69                         for( cpy = s; *cpy; cpy ++ )
    70                                 cpy[0] = cpy[1];
    71                 }
    72                 else if( *s == q )
    73                 {
    74                         q = *s = 0;
    75                 }
    76         cmd[k] = NULL;
    77        
    78         root_command( irc, cmd );
     34void root_command_string( irc_t *irc, char *command )
     35{
     36        root_command( irc, split_command_parts( command ) );
    7937}
    8038
     
    9351void root_command( irc_t *irc, char *cmd[] )
    9452{       
    95         int i;
     53        int i, len;
    9654       
    9755        if( !cmd[0] )
    9856                return;
    9957       
     58        len = strlen( cmd[0] );
    10059        for( i = 0; commands[i].command; i++ )
    101                 if( g_strcasecmp( commands[i].command, cmd[0] ) == 0 )
    102                 {
     60                if( g_strncasecmp( commands[i].command, cmd[0], len ) == 0 )
     61                {
     62                        if( commands[i+1].command &&
     63                            g_strncasecmp( commands[i+1].command, cmd[0], len ) == 0 )
     64                                /* Only match on the first letters if the match is unique. */
     65                                break;
     66                       
    10367                        MIN_ARGS( commands[i].required_parameters );
    10468                       
     
    141105static void cmd_identify( irc_t *irc, char **cmd )
    142106{
    143         storage_status_t status = storage_load( irc, cmd[1] );
     107        storage_status_t status;
    144108        char *account_on[] = { "account", "on", NULL };
    145        
    146         if( strchr( irc->umode, 'R' ) != NULL )
     109        gboolean load = TRUE;
     110        char *password = cmd[1];
     111       
     112        if( irc->status & USTATUS_IDENTIFIED )
    147113        {
    148114                irc_usermsg( irc, "You're already logged in." );
    149115                return;
    150116        }
     117       
     118        if( strncmp( cmd[1], "-no", 3 ) == 0 )
     119        {
     120                load = FALSE;
     121                password = cmd[2];
     122        }
     123        else if( strncmp( cmd[1], "-force", 6 ) == 0 )
     124        {
     125                password = cmd[2];
     126        }
     127        else if( irc->b->accounts != NULL )
     128        {
     129                irc_usermsg( irc,
     130                             "You're trying to identify yourself, but already have "
     131                             "at least one IM account set up. "
     132                             "Use \x02identify -noload\x02 or \x02identify -force\x02 "
     133                             "instead (see \x02help identify\x02)." );
     134                return;
     135        }
     136       
     137        if( password == NULL )
     138        {
     139                MIN_ARGS( 2 );
     140        }
     141       
     142        if( load )
     143                status = storage_load( irc, password );
     144        else
     145                status = storage_check_pass( irc->user->nick, password );
    151146       
    152147        switch (status) {
     
    158153                break;
    159154        case STORAGE_OK:
    160                 irc_usermsg( irc, "Password accepted, settings and accounts loaded" );
    161                 irc_setpass( irc, cmd[1] );
     155                irc_usermsg( irc, "Password accepted%s",
     156                             load ? ", settings and accounts loaded" : "" );
     157                irc_setpass( irc, password );
    162158                irc->status |= USTATUS_IDENTIFIED;
    163159                irc_umode_set( irc, "+R", 1 );
    164                 if( set_getbool( &irc->set, "auto_connect" ) )
     160                if( load && set_getbool( &irc->b->set, "auto_connect" ) )
    165161                        cmd_account( irc, account_on );
    166162                break;
     
    202198        storage_status_t status;
    203199       
    204         status = storage_remove (irc->nick, cmd[1]);
     200        status = storage_remove (irc->user->nick, cmd[1]);
    205201        switch (status) {
    206202        case STORAGE_NO_SUCH_USER:
     
    214210                irc->status &= ~USTATUS_IDENTIFIED;
    215211                irc_umode_set( irc, "-R", 1 );
    216                 irc_usermsg( irc, "Account `%s' removed", irc->nick );
     212                irc_usermsg( irc, "Account `%s' removed", irc->user->nick );
    217213                break;
    218214        default:
     
    222218}
    223219
    224 struct cmd_account_del_data
    225 {
    226         account_t *a;
    227         irc_t *irc;
    228 };
    229 
    230 void cmd_account_del_yes( void *data )
    231 {
    232         struct cmd_account_del_data *cad = data;
    233         account_t *a;
    234        
    235         for( a = cad->irc->accounts; a && a != cad->a; a = a->next );
    236        
    237         if( a == NULL )
    238         {
    239                 irc_usermsg( cad->irc, "Account already deleted" );
    240         }
    241         else if( a->ic )
    242         {
    243                 irc_usermsg( cad->irc, "Account is still logged in, can't delete" );
    244         }
    245         else
    246         {
    247                 account_del( cad->irc, a );
    248                 irc_usermsg( cad->irc, "Account deleted" );
    249         }
    250         g_free( data );
    251 }
    252 
    253 void cmd_account_del_no( void *data )
    254 {
    255         g_free( data );
     220static void cmd_save( irc_t *irc, char **cmd )
     221{
     222        if( ( irc->status & USTATUS_IDENTIFIED ) == 0 )
     223                irc_usermsg( irc, "Please create an account first" );
     224        else if( storage_save( irc, NULL, TRUE ) == STORAGE_OK )
     225                irc_usermsg( irc, "Configuration saved" );
     226        else
     227                irc_usermsg( irc, "Configuration could not be saved!" );
    256228}
    257229
     
    286258                set_name = set_full;
    287259               
    288                 head = &irc->set;
     260                head = &irc->b->set;
    289261        }
    290262        else
     
    357329        account_t *a;
    358330       
    359         if( ( a = account_get( irc, id ) ) )
     331        if( ( a = account_get( irc->b, id ) ) )
    360332                return &a->set;
    361333        else
     
    405377                }
    406378
    407                 a = account_add( irc, prpl, cmd[3], cmd[4] );
     379                a = account_add( irc->b, prpl, cmd[3], cmd[4] );
    408380                if( cmd[5] )
    409381                {
     
    419391                MIN_ARGS( 2 );
    420392
    421                 if( !( a = account_get( irc, cmd[2] ) ) )
     393                if( !( a = account_get( irc->b, cmd[2] ) ) )
    422394                {
    423395                        irc_usermsg( irc, "Invalid account" );
     
    429401                else
    430402                {
    431                         struct cmd_account_del_data *cad;
    432                         char *msg;
    433                        
    434                         cad = g_malloc( sizeof( struct cmd_account_del_data ) );
    435                         cad->a = a;
    436                         cad->irc = irc;
    437                        
    438                         msg = g_strdup_printf( "If you remove this account (%s(%s)), BitlBee will "
    439                                                "also forget all your saved nicknames. If you want "
    440                                                "to change your username/password, use the `account "
    441                                                "set' command. Are you sure you want to delete this "
    442                                                "account?", a->prpl->name, a->user );
    443                         query_add( irc, NULL, msg, cmd_account_del_yes, cmd_account_del_no, cad );
    444                         g_free( msg );
     403                        account_del( irc->b, a );
     404                        irc_usermsg( irc, "Account deleted" );
    445405                }
    446406        }
     
    452412                        irc_usermsg( irc, "Account list:" );
    453413               
    454                 for( a = irc->accounts; a; a = a->next )
     414                for( a = irc->b->accounts; a; a = a->next )
    455415                {
    456416                        char *con;
     
    475435                if( cmd[2] )
    476436                {
    477                         if( ( a = account_get( irc, cmd[2] ) ) )
     437                        if( ( a = account_get( irc->b, cmd[2] ) ) )
    478438                        {
    479439                                if( a->ic )
     
    484444                                else
    485445                                {
    486                                         account_on( irc, a );
     446                                        account_on( irc->b, a );
    487447                                }
    488448                        }
     
    495455                else
    496456                {
    497                         if ( irc->accounts ) {
     457                        if ( irc->b->accounts )
     458                        {
    498459                                irc_usermsg( irc, "Trying to get all accounts connected..." );
    499460                       
    500                                 for( a = irc->accounts; a; a = a->next )
     461                                for( a = irc->b->accounts; a; a = a->next )
    501462                                        if( !a->ic && a->auto_connect )
    502                                                 account_on( irc, a );
     463                                                account_on( irc->b, a );
    503464                        }
    504465                        else
     
    514475                        irc_usermsg( irc, "Deactivating all active (re)connections..." );
    515476                       
    516                         for( a = irc->accounts; a; a = a->next )
     477                        for( a = irc->b->accounts; a; a = a->next )
    517478                        {
    518479                                if( a->ic )
    519                                         account_off( irc, a );
     480                                        account_off( irc->b, a );
    520481                                else if( a->reconnect )
    521482                                        cancel_auto_reconnect( a );
    522483                        }
    523484                }
    524                 else if( ( a = account_get( irc, cmd[2] ) ) )
     485                else if( ( a = account_get( irc->b, cmd[2] ) ) )
    525486                {
    526487                        if( a->ic )
    527488                        {
    528                                 account_off( irc, a );
     489                                account_off( irc->b, a );
    529490                        }
    530491                        else if( a->reconnect )
     
    557518}
    558519
     520static set_t **cmd_channel_set_findhead( irc_t *irc, char *id )
     521{
     522        irc_channel_t *ic;
     523       
     524        if( ( ic = irc_channel_get( irc, id ) ) )
     525                return &ic->set;
     526        else
     527                return NULL;
     528}
     529
     530static void cmd_channel( irc_t *irc, char **cmd )
     531{
     532        if( g_strcasecmp( cmd[1], "set" ) == 0 )
     533        {
     534                MIN_ARGS( 2 );
     535               
     536                cmd_set_real( irc, cmd + 1, cmd_channel_set_findhead, NULL );
     537        }
     538        else if( g_strcasecmp( cmd[1], "list" ) == 0 )
     539        {
     540                GSList *l;
     541                int i = 0;
     542               
     543                if( strchr( irc->umode, 'b' ) )
     544                        irc_usermsg( irc, "Channel list:" );
     545               
     546                for( l = irc->channels; l; l = l->next )
     547                {
     548                        irc_channel_t *ic = l->data;
     549                       
     550                        irc_usermsg( irc, "%2d. %s, %s channel%s", i, ic->name,
     551                                     set_getstr( &ic->set, "type" ),
     552                                     ic->flags & IRC_CHANNEL_JOINED ? " (joined)" : "" );
     553                       
     554                        i ++;
     555                }
     556                irc_usermsg( irc, "End of channel list" );
     557        }
     558        else if( g_strcasecmp( cmd[1], "del" ) == 0 )
     559        {
     560                irc_channel_t *ic;
     561               
     562                MIN_ARGS( 2 );
     563               
     564                if( ( ic = irc_channel_get( irc, cmd[2] ) ) &&
     565                   !( ic->flags & IRC_CHANNEL_JOINED ) &&
     566                    ic != ic->irc->default_channel )
     567                {
     568                        irc_usermsg( irc, "Channel %s deleted.", ic->name );
     569                        irc_channel_free( ic );
     570                }
     571                else
     572                        irc_usermsg( irc, "Couldn't remove channel (main channel %s or "
     573                                          "channels you're still in cannot be deleted).",
     574                                          irc->default_channel->name );
     575        }
     576        else
     577        {
     578                irc_usermsg( irc, "Unknown command: %s %s. Please use \x02help commands\x02 to get a list of available commands.", "channel", cmd[1] );
     579        }
     580}
     581
    559582static void cmd_add( irc_t *irc, char **cmd )
    560583{
     
    569592        }
    570593       
    571         if( !( a = account_get( irc, cmd[1] ) ) )
     594        if( !( a = account_get( irc->b, cmd[1] ) ) )
    572595        {
    573596                irc_usermsg( irc, "Invalid account" );
     
    587610                        return;
    588611                }
    589                 else if( user_find( irc, cmd[3] ) )
     612                else if( irc_user_by_name( irc, cmd[3] ) )
    590613                {
    591614                        irc_usermsg( irc, "The requested nick `%s' already exists", cmd[3] );
     
    599622       
    600623        if( add_on_server )
    601                 a->ic->acc->prpl->add_buddy( a->ic, cmd[2], NULL );
    602         else
    603                 /* Yeah, officially this is a call-*back*... So if we just
    604                    called add_buddy, we'll wait for the IM server to respond
    605                    before we do this. */
    606                 imcb_add_buddy( a->ic, cmd[2], NULL );
     624                a->prpl->add_buddy( a->ic, cmd[2], NULL );
     625        else
     626                /* Only for add -tmp. For regular adds, this callback will
     627                   be called once the IM server confirms. */
     628                bee_user_new( irc->b, a->ic, cmd[2], BEE_USER_LOCAL );
    607629       
    608630        irc_usermsg( irc, "Adding `%s' to your contact list", cmd[2]  );
     631}
     632
     633static void cmd_remove( irc_t *irc, char **cmd )
     634{
     635        irc_user_t *iu;
     636        bee_user_t *bu;
     637        char *s;
     638       
     639        if( !( iu = irc_user_by_name( irc, cmd[1] ) ) || !( bu = iu->bu ) )
     640        {
     641                irc_usermsg( irc, "Buddy `%s' not found", cmd[1] );
     642                return;
     643        }
     644        s = g_strdup( bu->handle );
     645       
     646        bu->ic->acc->prpl->remove_buddy( bu->ic, bu->handle, NULL );
     647        nick_del( bu->ic->acc, bu->handle );
     648        //TODO(wilmer): bee_user_free() and/or let the IM mod do it? irc_user_free( irc, cmd[1] );
     649       
     650        irc_usermsg( irc, "Buddy `%s' (nick %s) removed from contact list", s, cmd[1] );
     651        g_free( s );
     652       
     653        return;
    609654}
    610655
     
    616661        if( !cmd[2] )
    617662        {
    618                 user_t *u = user_find( irc, cmd[1] );
    619                 if( !u || !u->ic )
     663                irc_user_t *iu = irc_user_by_name( irc, cmd[1] );
     664                if( !iu || !iu->bu )
    620665                {
    621666                        irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
    622667                        return;
    623668                }
    624                 ic = u->ic;
    625                 cmd[2] = u->handle;
    626         }
    627         else if( !( a = account_get( irc, cmd[1] ) ) )
     669                ic = iu->bu->ic;
     670                cmd[2] = iu->bu->handle;
     671        }
     672        else if( !( a = account_get( irc->b, cmd[1] ) ) )
    628673        {
    629674                irc_usermsg( irc, "Invalid account" );
     
    648693static void cmd_rename( irc_t *irc, char **cmd )
    649694{
    650         user_t *u;
    651        
    652         if( g_strcasecmp( cmd[1], irc->nick ) == 0 )
     695        irc_user_t *iu;
     696       
     697        iu = irc_user_by_name( irc, cmd[1] );
     698       
     699        if( iu == NULL )
     700        {
     701                irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
     702        }
     703        else if( iu == irc->user )
    653704        {
    654705                irc_usermsg( irc, "Nick `%s' can't be changed", cmd[1] );
    655706        }
    656         else if( g_strcasecmp( cmd[1], irc->channel ) == 0 )
    657         {
    658                 if( strchr( CTYPES, cmd[2][0] ) && nick_ok( cmd[2] + 1 ) )
    659                 {
    660                         u = user_find( irc, irc->nick );
    661                        
    662                         irc_part( irc, u, irc->channel );
    663                         g_free( irc->channel );
    664                         irc->channel = g_strdup( cmd[2] );
    665                         irc_join( irc, u, irc->channel );
    666                        
    667                         if( strcmp( cmd[0], "set_rename" ) != 0 )
    668                                 set_setstr( &irc->set, "control_channel", cmd[2] );
    669                 }
    670         }
    671         else if( user_find( irc, cmd[2] ) && ( nick_cmp( cmd[1], cmd[2] ) != 0 ) )
     707        else if( !nick_ok( cmd[2] ) )
     708        {
     709                irc_usermsg( irc, "Nick `%s' is invalid", cmd[2] );
     710        }
     711        else if( irc_user_by_name( irc, cmd[2] ) )
    672712        {
    673713                irc_usermsg( irc, "Nick `%s' already exists", cmd[2] );
    674714        }
    675         else if( !nick_ok( cmd[2] ) )
    676         {
    677                 irc_usermsg( irc, "Nick `%s' is invalid", cmd[2] );
    678         }
    679         else if( !( u = user_find( irc, cmd[1] ) ) )
    680         {
    681                 irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
    682         }
    683         else
    684         {
    685                 user_rename( irc, cmd[1], cmd[2] );
    686                 irc_write( irc, ":%s!%s@%s NICK %s", cmd[1], u->user, u->host, cmd[2] );
    687                 if( g_strcasecmp( cmd[1], irc->mynick ) == 0 )
    688                 {
    689                         g_free( irc->mynick );
    690                         irc->mynick = g_strdup( cmd[2] );
    691                        
     715        else
     716        {
     717                if( !irc_user_set_nick( iu, cmd[2] ) )
     718                {
     719                        irc_usermsg( irc, "Error while changing nick" );
     720                        return;
     721                }
     722               
     723                if( iu == irc->root )
     724                {
    692725                        /* If we're called internally (user did "set root_nick"),
    693726                           let's not go O(INF). :-) */
    694727                        if( strcmp( cmd[0], "set_rename" ) != 0 )
    695                                 set_setstr( &irc->set, "root_nick", cmd[2] );
    696                 }
    697                 else if( u->send_handler == buddy_send_handler )
    698                 {
    699                         nick_set( u->ic->acc, u->handle, cmd[2] );
     728                                set_setstr( &irc->b->set, "root_nick", cmd[2] );
     729                }
     730                else if( iu->bu )
     731                {
     732                        nick_set( iu->bu->ic->acc, iu->bu->handle, cmd[2] );
    700733                }
    701734               
     
    708741        irc_t *irc = set->data;
    709742       
    710         if( strcmp( irc->mynick, new_nick ) != 0 )
    711         {
    712                 char *cmd[] = { "set_rename", irc->mynick, new_nick, NULL };
     743        if( strcmp( irc->root->nick, new_nick ) != 0 )
     744        {
     745                char *cmd[] = { "set_rename", irc->root->nick, new_nick, NULL };
    713746               
    714747                cmd_rename( irc, cmd );
    715748        }
    716749       
    717         return strcmp( irc->mynick, new_nick ) == 0 ? new_nick : SET_INVALID;
    718 }
    719 
    720 char *set_eval_control_channel( set_t *set, char *new_name )
    721 {
    722         irc_t *irc = set->data;
    723        
    724         if( strcmp( irc->channel, new_name ) != 0 )
    725         {
    726                 char *cmd[] = { "set_rename", irc->channel, new_name, NULL };
    727                
    728                 cmd_rename( irc, cmd );
    729         }
    730        
    731         return strcmp( irc->channel, new_name ) == 0 ? new_name : SET_INVALID;
    732 }
    733 
    734 static void cmd_remove( irc_t *irc, char **cmd )
    735 {
    736         user_t *u;
    737         char *s;
    738        
    739         if( !( u = user_find( irc, cmd[1] ) ) || !u->ic )
    740         {
    741                 irc_usermsg( irc, "Buddy `%s' not found", cmd[1] );
    742                 return;
    743         }
    744         s = g_strdup( u->handle );
    745        
    746         u->ic->acc->prpl->remove_buddy( u->ic, u->handle, NULL );
    747         nick_del( u->ic->acc, u->handle );
    748         user_del( irc, cmd[1] );
    749        
    750         irc_usermsg( irc, "Buddy `%s' (nick %s) removed from contact list", s, cmd[1] );
    751         g_free( s );
    752        
    753         return;
     750        return strcmp( irc->root->nick, new_nick ) == 0 ? new_nick : SET_INVALID;
    754751}
    755752
     
    759756        account_t *a;
    760757       
    761         if( !cmd[2] && ( a = account_get( irc, cmd[1] ) ) && a->ic )
     758        if( !cmd[2] && ( a = account_get( irc->b, cmd[1] ) ) && a->ic )
    762759        {
    763760                char *format;
     
    772769                for( l = a->ic->deny; l; l = l->next )
    773770                {
    774                         user_t *u = user_findhandle( a->ic, l->data );
    775                         irc_usermsg( irc, format, l->data, u ? u->nick : "(none)" );
     771                        bee_user_t *bu = bee_user_by_handle( irc->b, a->ic, l->data );
     772                        irc_user_t *iu = bu ? bu->ui_data : NULL;
     773                        irc_usermsg( irc, format, l->data, iu ? iu->nick : "(none)" );
    776774                }
    777775                irc_usermsg( irc, "End of list." );
     
    781779        else if( !cmd[2] )
    782780        {
    783                 user_t *u = user_find( irc, cmd[1] );
    784                 if( !u || !u->ic )
     781                irc_user_t *iu = irc_user_by_name( irc, cmd[1] );
     782                if( !iu || !iu->bu )
    785783                {
    786784                        irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
    787785                        return;
    788786                }
    789                 ic = u->ic;
    790                 cmd[2] = u->handle;
    791         }
    792         else if( !( a = account_get( irc, cmd[1] ) ) )
     787                ic = iu->bu->ic;
     788                cmd[2] = iu->bu->handle;
     789        }
     790        else if( !( a = account_get( irc->b, cmd[1] ) ) )
    793791        {
    794792                irc_usermsg( irc, "Invalid account" );
     
    818816        account_t *a;
    819817       
    820         if( !cmd[2] && ( a = account_get( irc, cmd[1] ) ) && a->ic )
     818        if( !cmd[2] && ( a = account_get( irc->b, cmd[1] ) ) && a->ic )
    821819        {
    822820                char *format;
     
    831829                for( l = a->ic->permit; l; l = l->next )
    832830                {
    833                         user_t *u = user_findhandle( a->ic, l->data );
    834                         irc_usermsg( irc, format, l->data, u ? u->nick : "(none)" );
     831                        bee_user_t *bu = bee_user_by_handle( irc->b, a->ic, l->data );
     832                        irc_user_t *iu = bu ? bu->ui_data : NULL;
     833                        irc_usermsg( irc, format, l->data, iu ? iu->nick : "(none)" );
    835834                }
    836835                irc_usermsg( irc, "End of list." );
     
    840839        else if( !cmd[2] )
    841840        {
    842                 user_t *u = user_find( irc, cmd[1] );
    843                 if( !u || !u->ic )
     841                irc_user_t *iu = irc_user_by_name( irc, cmd[1] );
     842                if( !iu || !iu->bu )
    844843                {
    845844                        irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
    846845                        return;
    847846                }
    848                 ic = u->ic;
    849                 cmd[2] = u->handle;
    850         }
    851         else if( !( a = account_get( irc, cmd[1] ) ) )
     847                ic = iu->bu->ic;
     848                cmd[2] = iu->bu->handle;
     849        }
     850        else if( !( a = account_get( irc->b, cmd[1] ) ) )
    852851        {
    853852                irc_usermsg( irc, "Invalid account" );
     
    916915}
    917916
    918 static void cmd_save( irc_t *irc, char **cmd )
    919 {
    920         if( ( irc->status & USTATUS_IDENTIFIED ) == 0 )
    921                 irc_usermsg( irc, "Please create an account first" );
    922         else if( storage_save( irc, NULL, TRUE ) == STORAGE_OK )
    923                 irc_usermsg( irc, "Configuration saved" );
    924         else
    925                 irc_usermsg( irc, "Configuration could not be saved!" );
    926 }
    927 
    928917static void cmd_blist( irc_t *irc, char **cmd )
    929918{
    930919        int online = 0, away = 0, offline = 0;
    931         user_t *u;
     920        GSList *l;
    932921        char s[256];
    933922        char *format;
     
    950939                format = "%-16.16s  %-40.40s  %s";
    951940       
    952         irc_usermsg( irc, format, "Nick", "User/Host/Network", "Status" );
    953        
    954         for( u = irc->users; u; u = u->next ) if( u->ic && u->online && !u->away )
    955         {
     941        irc_usermsg( irc, format, "Nick", "Handle/Account", "Status" );
     942       
     943        for( l = irc->users; l; l = l->next )
     944        {
     945                irc_user_t *iu = l->data;
     946                bee_user_t *bu = iu->bu;
     947               
     948                if( !bu || ( bu->flags & ( BEE_USER_ONLINE | BEE_USER_AWAY ) ) != BEE_USER_ONLINE )
     949                        continue;
     950               
    956951                if( online == 1 )
    957952                {
    958953                        char st[256] = "Online";
    959954                       
    960                         if( u->status_msg )
    961                                 g_snprintf( st, sizeof( st ) - 1, "Online (%s)", u->status_msg );
     955                        if( bu->status_msg )
     956                                g_snprintf( st, sizeof( st ) - 1, "Online (%s)", bu->status_msg );
    962957                       
    963                         g_snprintf( s, sizeof( s ) - 1, "%s@%s %s(%s)", u->user, u->host, u->ic->acc->prpl->name, u->ic->acc->user );
    964                         irc_usermsg( irc, format, u->nick, s, st );
     958                        g_snprintf( s, sizeof( s ) - 1, "%s %s(%s)", bu->handle, bu->ic->acc->prpl->name, bu->ic->acc->user );
     959                        irc_usermsg( irc, format, iu->nick, s, st );
    965960                }
    966961               
     
    968963        }
    969964
    970         for( u = irc->users; u; u = u->next ) if( u->ic && u->online && u->away )
    971         {
     965        for( l = irc->users; l; l = l->next )
     966        {
     967                irc_user_t *iu = l->data;
     968                bee_user_t *bu = iu->bu;
     969               
     970                if( !bu || !( bu->flags & BEE_USER_ONLINE ) || !( bu->flags & BEE_USER_AWAY ) )
     971                        continue;
     972               
    972973                if( away == 1 )
    973974                {
    974                         g_snprintf( s, sizeof( s ) - 1, "%s@%s %s(%s)", u->user, u->host, u->ic->acc->prpl->name, u->ic->acc->user );
    975                         irc_usermsg( irc, format, u->nick, s, u->away );
     975                        g_snprintf( s, sizeof( s ) - 1, "%s %s(%s)", bu->handle, bu->ic->acc->prpl->name, bu->ic->acc->user );
     976                        irc_usermsg( irc, format, iu->nick, s, irc_user_get_away( iu ) );
    976977                }
    977978                n_away ++;
    978979        }
    979980       
    980         for( u = irc->users; u; u = u->next ) if( u->ic && !u->online )
    981         {
     981        for( l = irc->users; l; l = l->next )
     982        {
     983                irc_user_t *iu = l->data;
     984                bee_user_t *bu = iu->bu;
     985               
     986                if( !bu || bu->flags & BEE_USER_ONLINE )
     987                        continue;
     988               
    982989                if( offline == 1 )
    983990                {
    984                         g_snprintf( s, sizeof( s ) - 1, "%s@%s %s(%s)", u->user, u->host, u->ic->acc->prpl->name, u->ic->acc->user );
    985                         irc_usermsg( irc, format, u->nick, s, "Offline" );
     991                        g_snprintf( s, sizeof( s ) - 1, "%s %s(%s)", bu->handle, bu->ic->acc->prpl->name, bu->ic->acc->user );
     992                        irc_usermsg( irc, format, iu->nick, s, "Offline" );
    986993                }
    987994                n_offline ++;
     
    989996       
    990997        irc_usermsg( irc, "%d buddies (%d available, %d away, %d offline)", n_online + n_away + n_offline, n_online, n_away, n_offline );
    991 }
    992 
    993 static void cmd_nick( irc_t *irc, char **cmd )
    994 {
    995         account_t *a;
    996 
    997         if( !cmd[1] || !( a = account_get( irc, cmd[1] ) ) )
    998         {
    999                 irc_usermsg( irc, "Invalid account");
    1000         }
    1001         else if( !( a->ic && ( a->ic->flags & OPT_LOGGED_IN ) ) )
    1002         {
    1003                 irc_usermsg( irc, "That account is not on-line" );
    1004         }
    1005         else if ( !cmd[2] )
    1006         {
    1007                 irc_usermsg( irc, "Your name is `%s'" , a->ic->displayname ? a->ic->displayname : "NULL" );
    1008         }
    1009         else if ( !a->prpl->set_my_name )
    1010         {
    1011                 irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] );
    1012         }
    1013         else
    1014         {
    1015                 irc_usermsg( irc, "Setting your name to `%s'", cmd[2] );
    1016                
    1017                 a->prpl->set_my_name( a->ic, cmd[2] );
    1018         }
    1019998}
    1020999
     
    10391018}
    10401019
    1041 static void cmd_join_chat( irc_t *irc, char **cmd )
    1042 {
    1043         irc_usermsg( irc, "This command is now obsolete. "
    1044                           "Please try the `chat' command instead." );
    1045 }
    1046 
    1047 static set_t **cmd_chat_set_findhead( irc_t *irc, char *id )
    1048 {
    1049         struct chat *c;
    1050        
    1051         if( ( c = chat_get( irc, id ) ) )
    1052                 return &c->set;
    1053         else
    1054                 return NULL;
    1055 }
    1056 
    10571020static void cmd_chat( irc_t *irc, char **cmd )
    10581021{
    10591022        account_t *acc;
    1060         struct chat *c;
    10611023       
    10621024        if( g_strcasecmp( cmd[1], "add" ) == 0 )
    10631025        {
    10641026                char *channel, *s;
     1027                struct irc_channel *ic;
    10651028               
    10661029                MIN_ARGS( 3 );
    10671030               
    1068                 if( !( acc = account_get( irc, cmd[2] ) ) )
     1031                if( !( acc = account_get( irc->b, cmd[2] ) ) )
    10691032                {
    10701033                        irc_usermsg( irc, "Invalid account" );
     1034                        return;
     1035                }
     1036                else if( !acc->prpl->chat_join )
     1037                {
     1038                        irc_usermsg( irc, "Named chatrooms not supported on that account." );
    10711039                        return;
    10721040                }
     
    10851053                if( strchr( CTYPES, channel[0] ) == NULL )
    10861054                {
    1087                         s = g_strdup_printf( "%c%s", CTYPES[0], channel );
     1055                        s = g_strdup_printf( "#%s", channel );
    10881056                        g_free( channel );
    10891057                        channel = s;
    10901058                }
    10911059               
    1092                 if( ( c = chat_add( irc, acc, cmd[3], channel ) ) )
    1093                         irc_usermsg( irc, "Chatroom added successfully." );
    1094                 else
     1060                if( ( ic = irc_channel_new( irc, channel ) ) &&
     1061                    set_setstr( &ic->set, "chat_type", "room" ) &&
     1062                    set_setstr( &ic->set, "account", cmd[2] ) &&
     1063                    set_setstr( &ic->set, "room", cmd[3] ) )
     1064                {
     1065                        irc_usermsg( irc, "Chatroom successfully added." );
     1066                }
     1067                else
     1068                {
     1069                        if( ic )
     1070                                irc_channel_free( ic );
     1071                       
    10951072                        irc_usermsg( irc, "Could not add chatroom." );
    1096                
     1073                }
    10971074                g_free( channel );
    10981075        }
    1099         else if( g_strcasecmp( cmd[1], "list" ) == 0 )
    1100         {
    1101                 int i = 0;
    1102                
    1103                 if( strchr( irc->umode, 'b' ) )
    1104                         irc_usermsg( irc, "Chatroom list:" );
    1105                
    1106                 for( c = irc->chatrooms; c; c = c->next )
    1107                 {
    1108                         irc_usermsg( irc, "%2d. %s(%s) %s, %s", i, c->acc->prpl->name,
    1109                                           c->acc->user, c->handle, c->channel );
    1110                        
    1111                         i ++;
    1112                 }
    1113                 irc_usermsg( irc, "End of chatroom list" );
    1114         }
    1115         else if( g_strcasecmp( cmd[1], "set" ) == 0 )
    1116         {
     1076        else if( g_strcasecmp( cmd[1], "with" ) == 0 )
     1077        {
     1078                irc_user_t *iu;
     1079               
    11171080                MIN_ARGS( 2 );
    11181081               
    1119                 cmd_set_real( irc, cmd + 1, cmd_chat_set_findhead, NULL );
    1120         }
    1121         else if( g_strcasecmp( cmd[1], "del" ) == 0 )
    1122         {
    1123                 MIN_ARGS( 2 );
    1124                
    1125                 if( ( c = chat_get( irc, cmd[2] ) ) )
    1126                 {
    1127                         chat_del( irc, c );
    1128                 }
    1129                 else
    1130                 {
    1131                         irc_usermsg( irc, "Could not remove chat." );
    1132                 }
    1133         }
    1134         else if( g_strcasecmp( cmd[1], "with" ) == 0 )
    1135         {
    1136                 user_t *u;
    1137                
    1138                 MIN_ARGS( 2 );
    1139                
    1140                 if( ( u = user_find( irc, cmd[2] ) ) && u->ic && u->ic->acc->prpl->chat_with )
    1141                 {
    1142                         if( !u->ic->acc->prpl->chat_with( u->ic, u->handle ) )
     1082                if( ( iu = irc_user_by_name( irc, cmd[2] ) ) &&
     1083                    iu->bu && iu->bu->ic->acc->prpl->chat_with )
     1084                {
     1085                        if( !iu->bu->ic->acc->prpl->chat_with( iu->bu->ic, iu->bu->handle ) )
    11431086                        {
    11441087                                irc_usermsg( irc, "(Possible) failure while trying to open "
    1145                                                   "a groupchat with %s.", u->nick );
     1088                                                  "a groupchat with %s.", iu->nick );
    11461089                        }
    11471090                }
     
    11511094                }
    11521095        }
     1096        else if( g_strcasecmp( cmd[1], "list" ) == 0 ||
     1097                 g_strcasecmp( cmd[1], "set" ) == 0 ||
     1098                 g_strcasecmp( cmd[1], "del" ) == 0 )
     1099        {
     1100                irc_usermsg( irc, "Warning: The \002chat\002 command was mostly replaced with the \002channel\002 command." );
     1101                cmd_channel( irc, cmd );
     1102        }
    11531103        else
    11541104        {
     
    11571107}
    11581108
     1109static void cmd_transfer( irc_t *irc, char **cmd )
     1110{
     1111        GSList *files = irc->file_transfers;
     1112        enum { LIST, REJECT, CANCEL };
     1113        int subcmd = LIST;
     1114        int fid;
     1115
     1116        if( !files )
     1117        {
     1118                irc_usermsg( irc, "No pending transfers" );
     1119                return;
     1120        }
     1121
     1122        if( cmd[1] && ( strcmp( cmd[1], "reject" ) == 0 ) )
     1123        {
     1124                subcmd = REJECT;
     1125        }
     1126        else if( cmd[1] && ( strcmp( cmd[1], "cancel" ) == 0 ) &&
     1127                 cmd[2] && ( sscanf( cmd[2], "%d", &fid ) == 1 ) )
     1128        {
     1129                subcmd = CANCEL;
     1130        }
     1131
     1132        for( ; files; files = g_slist_next( files ) )
     1133        {
     1134                file_transfer_t *file = files->data;
     1135               
     1136                switch( subcmd ) {
     1137                case LIST:
     1138                        if ( file->status == FT_STATUS_LISTENING )
     1139                                irc_usermsg( irc,
     1140                                        "Pending file(id %d): %s (Listening...)", file->local_id, file->file_name);
     1141                        else
     1142                        {
     1143                                int kb_per_s = 0;
     1144                                time_t diff = time( NULL ) - file->started ? : 1;
     1145                                if ( ( file->started > 0 ) && ( file->bytes_transferred > 0 ) )
     1146                                        kb_per_s = file->bytes_transferred / 1024 / diff;
     1147                                       
     1148                                irc_usermsg( irc,
     1149                                        "Pending file(id %d): %s (%10zd/%zd kb, %d kb/s)", file->local_id, file->file_name,
     1150                                        file->bytes_transferred/1024, file->file_size/1024, kb_per_s);
     1151                        }
     1152                        break;
     1153                case REJECT:
     1154                        if( file->status == FT_STATUS_LISTENING )
     1155                        {
     1156                                irc_usermsg( irc, "Rejecting file transfer for %s", file->file_name );
     1157                                imcb_file_canceled( file->ic, file, "Denied by user" );
     1158                        }
     1159                        break;
     1160                case CANCEL:
     1161                        if( file->local_id == fid )
     1162                        {
     1163                                irc_usermsg( irc, "Canceling file transfer for %s", file->file_name );
     1164                                imcb_file_canceled( file->ic, file, "Canceled by user" );
     1165                        }
     1166                        break;
     1167                }
     1168        }
     1169}
     1170
     1171/* IMPORTANT: Keep this list sorted! The short command logic needs that. */
    11591172const command_t commands[] = {
     1173        { "account",        1, cmd_account,        0 },
     1174        { "add",            2, cmd_add,            0 },
     1175        { "allow",          1, cmd_allow,          0 },
     1176        { "blist",          0, cmd_blist,          0 },
     1177        { "block",          1, cmd_block,          0 },
     1178        { "channel",        1, cmd_channel,        0 },
     1179        { "chat",           1, cmd_chat,           0 },
     1180        { "drop",           1, cmd_drop,           0 },
     1181        { "ft",             0, cmd_transfer,       0 },
    11601182        { "help",           0, cmd_help,           0 },
    11611183        { "identify",       1, cmd_identify,       0 },
     1184        { "info",           1, cmd_info,           0 },
     1185        { "no",             0, cmd_yesno,          0 },
     1186        { "qlist",          0, cmd_qlist,          0 },
    11621187        { "register",       1, cmd_register,       0 },
    1163         { "drop",           1, cmd_drop,           0 },
    1164         { "account",        1, cmd_account,        0 },
    1165         { "add",            2, cmd_add,            0 },
    1166         { "info",           1, cmd_info,           0 },
     1188        { "remove",         1, cmd_remove,         0 },
    11671189        { "rename",         2, cmd_rename,         0 },
    1168         { "remove",         1, cmd_remove,         0 },
    1169         { "block",          1, cmd_block,          0 },
    1170         { "allow",          1, cmd_allow,          0 },
    11711190        { "save",           0, cmd_save,           0 },
    11721191        { "set",            0, cmd_set,            0 },
     1192        { "transfer",       0, cmd_transfer,       0 },
    11731193        { "yes",            0, cmd_yesno,          0 },
    1174         { "no",             0, cmd_yesno,          0 },
    1175         { "blist",          0, cmd_blist,          0 },
    1176         { "nick",           1, cmd_nick,           0 },
    1177         { "qlist",          0, cmd_qlist,          0 },
    1178         { "join_chat",      2, cmd_join_chat,      0 },
    1179         { "chat",           1, cmd_chat,           0 },
    11801194        { NULL }
    11811195};
  • set.c

    r38ff846 r8b8def58  
    2929char *SET_INVALID = "nee";
    3030
    31 set_t *set_add( set_t **head, char *key, char *def, set_eval eval, void *data )
     31set_t *set_add( set_t **head, const char *key, const char *def, set_eval eval, void *data )
    3232{
    3333        set_t *s = set_find( head, key );
     
    6363}
    6464
    65 set_t *set_find( set_t **head, char *key )
     65set_t *set_find( set_t **head, const char *key )
    6666{
    6767        set_t *s = *head;
     
    6969        while( s )
    7070        {
    71                 if( g_strcasecmp( s->key, key ) == 0 )
     71                if( g_strcasecmp( s->key, key ) == 0 ||
     72                    ( s->old_key && g_strcasecmp( s->old_key, key ) == 0 ) )
    7273                        break;
    7374                s = s->next;
     
    7778}
    7879
    79 char *set_getstr( set_t **head, char *key )
     80char *set_getstr( set_t **head, const char *key )
    8081{
    8182        set_t *s = set_find( head, key );
     
    8788}
    8889
    89 int set_getint( set_t **head, char *key )
     90int set_getint( set_t **head, const char *key )
    9091{
    9192        char *s = set_getstr( head, key );
     
    101102}
    102103
    103 int set_getbool( set_t **head, char *key )
     104int set_getbool( set_t **head, const char *key )
    104105{
    105106        char *s = set_getstr( head, key );
     
    111112}
    112113
    113 int set_setstr( set_t **head, char *key, char *value )
     114int set_setstr( set_t **head, const char *key, char *value )
    114115{
    115116        set_t *s = set_find( head, key );
     
    150151}
    151152
    152 int set_setint( set_t **head, char *key, int value )
     153int set_setint( set_t **head, const char *key, int value )
    153154{
    154155        char s[24];     /* Not quite 128-bit clean eh? ;-) */
     
    158159}
    159160
    160 void set_del( set_t **head, char *key )
     161void set_del( set_t **head, const char *key )
    161162{
    162163        set_t *s = *head, *t = NULL;
     
    176177               
    177178                g_free( s->key );
    178                 if( s->value ) g_free( s->value );
    179                 if( s->def ) g_free( s->def );
     179                g_free( s->old_key );
     180                g_free( s->value );
     181                g_free( s->def );
    180182                g_free( s );
    181183        }
    182184}
    183185
    184 int set_reset( set_t **head, char *key )
     186int set_reset( set_t **head, const char *key )
    185187{
    186188        set_t *s;
     
    211213{
    212214        return is_bool( value ) ? value : SET_INVALID;
     215}
     216
     217char *set_eval_list( set_t *set, char *value )
     218{
     219        GSList *options = set->eval_data, *opt;
     220       
     221        for( opt = options; opt; opt = opt->next )
     222                if( strcmp( value, opt->data ) == 0 )
     223                        return value;
     224       
     225        /* TODO: It'd be nice to show the user a list of allowed values,
     226                 but we don't have enough context here to do that. May
     227                 want to fix that. */
     228       
     229        return NULL;
    213230}
    214231
     
    225242}
    226243
     244/*
    227245char *set_eval_ops( set_t *set, char *value )
    228246{
     
    246264        return value;
    247265}
     266*/
  • set.h

    r38ff846 r8b8def58  
    5454       
    5555        char *key;
     56        char *old_key;  /* Previously known as; for smooth upgrades. */
    5657        char *value;
    5758        char *def;      /* Default value. If the set_setstr() function
     
    6970           set_setstr() should be able to free() the returned string! */
    7071        set_eval eval;
     72        void *eval_data;
    7173        struct set *next;
    7274} set_t;
    7375
    7476/* Should be pretty clear. */
    75 set_t *set_add( set_t **head, char *key, char *def, set_eval eval, void *data );
     77set_t *set_add( set_t **head, const char *key, const char *def, set_eval eval, void *data );
    7678
    7779/* Returns the raw set_t. Might be useful sometimes. */
    78 set_t *set_find( set_t **head, char *key );
     80set_t *set_find( set_t **head, const char *key );
    7981
    8082/* Returns a pointer to the string value of this setting. Don't modify the
    8183   returned string, and don't free() it! */
    82 G_MODULE_EXPORT char *set_getstr( set_t **head, char *key );
     84G_MODULE_EXPORT char *set_getstr( set_t **head, const char *key );
    8385
    8486/* Get an integer. In previous versions set_getint() was also used to read
    8587   boolean values, but this SHOULD be done with set_getbool() now! */
    86 G_MODULE_EXPORT int set_getint( set_t **head, char *key );
    87 G_MODULE_EXPORT int set_getbool( set_t **head, char *key );
     88G_MODULE_EXPORT int set_getint( set_t **head, const char *key );
     89G_MODULE_EXPORT int set_getbool( set_t **head, const char *key );
    8890
    8991/* set_setstr() strdup()s the given value, so after using this function
    9092   you can free() it, if you want. */
    91 int set_setstr( set_t **head, char *key, char *value );
    92 int set_setint( set_t **head, char *key, int value );
    93 void set_del( set_t **head, char *key );
    94 int set_reset( set_t **head, char *key );
     93int set_setstr( set_t **head, const char *key, char *value );
     94int set_setint( set_t **head, const char *key, int value );
     95void set_del( set_t **head, const char *key );
     96int set_reset( set_t **head, const char *key );
    9597
    9698/* Two very useful generic evaluators. */
    9799char *set_eval_int( set_t *set, char *value );
    98100char *set_eval_bool( set_t *set, char *value );
     101
     102/* Another more complicated one. */
     103char *set_eval_list( set_t *set, char *value );
    99104
    100105/* Some not very generic evaluators that really shouldn't be here... */
  • storage.c

    r38ff846 r8b8def58  
    2828#define BITLBEE_CORE
    2929#include "bitlbee.h"
    30 #include "crypting.h"
    3130
    3231extern storage_t storage_text;
     
    6665        storage_t *storage;
    6766       
    68         register_storage_backend(&storage_text);
    6967        register_storage_backend(&storage_xml);
    7068       
  • storage_xml.c

    r38ff846 r8b8def58  
    147147                                         arc_decode( pass_cr, pass_len, &password, xd->given_pass ) )
    148148                {
    149                         xd->current_account = account_add( irc, prpl, handle, password );
     149                        xd->current_account = account_add( irc->b, prpl, handle, password );
    150150                        if( server )
    151151                                set_setstr( &xd->current_account->set, "server", server );
     
    181181                                xd->current_set_head = &xd->current_account->set;
    182182                        else
    183                                 xd->current_set_head = &xd->irc->set;
     183                                xd->current_set_head = &xd->irc->b->set;
    184184                       
    185185                        xd->current_setting = g_strdup( setting );
     
    215215                if( xd->current_account && handle && channel )
    216216                {
    217                         xd->current_chat = chat_add( xd->irc, xd->current_account, handle, channel );
     217                        //xd->current_chat = chat_add( xd->irc, xd->current_account, handle, channel );
    218218                }
    219219                else
     
    353353static storage_status_t xml_load( irc_t *irc, const char *password )
    354354{
    355         return xml_load_real( irc, irc->nick, password, XML_PASS_UNKNOWN );
     355        return xml_load_real( irc, irc->user->nick, password, XML_PASS_UNKNOWN );
    356356}
    357357
     
    396396        md5_state_t md5_state;
    397397       
    398         path2 = g_strdup( irc->nick );
     398        path2 = g_strdup( irc->user->nick );
    399399        nick_lc( path2 );
    400400        g_snprintf( path, sizeof( path ) - 2, "%s%s%s", global.conf->configdir, path2, ".xml" );
     
    422422        pass_buf = base64_encode( pass_md5, 21 );
    423423       
    424         if( !xml_printf( fd, 0, "<user nick=\"%s\" password=\"%s\" version=\"%d\">\n", irc->nick, pass_buf, XML_FORMAT_VERSION ) )
     424        if( !xml_printf( fd, 0, "<user nick=\"%s\" password=\"%s\" version=\"%d\">\n", irc->user->nick, pass_buf, XML_FORMAT_VERSION ) )
    425425                goto write_error;
    426426       
    427427        g_free( pass_buf );
    428428       
    429         for( set = irc->set; set; set = set->next )
     429        for( set = irc->b->set; set; set = set->next )
    430430                if( set->value )
    431431                        if( !xml_printf( fd, 1, "<setting name=\"%s\">%s</setting>\n", set->key, set->value ) )
    432432                                goto write_error;
    433433       
    434         for( acc = irc->accounts; acc; acc = acc->next )
     434        for( acc = irc->b->accounts; acc; acc = acc->next )
    435435        {
    436436                unsigned char *pass_cr;
     
    470470                        goto write_error;
    471471               
     472#if 0
    472473                for( c = irc->chatrooms; c; c = c->next )
    473474                {
     
    488489                                goto write_error;
    489490                }
     491#endif
    490492               
    491493                if( !xml_printf( fd, 1, "</account>\n" ) )
  • tests/Makefile

    r38ff846 r8b8def58  
    11-include ../Makefile.settings
     2ifdef SRCDIR
     3SRCDIR := $(SRCDIR)tests/
     4endif
    25
    36LFLAGS +=-lcheck
     
    1922        @$(CC) $(CFLAGS) -o $@ $^ $(LFLAGS) $(EFLAGS)
    2023
    21 %.o: %.c
     24%.o: $(SRCDIR)%.c
    2225        @echo '*' Compiling $<
    2326        @$(CC) -c $(CFLAGS) $< -o $@
  • unix.c

    r38ff846 r8b8def58  
    5656       
    5757        log_init();
     58       
    5859        global.conf_file = g_strdup( CONF_FILE_DEF );
    5960        global.conf = conf_load( argc, argv );
     
    6263       
    6364        b_main_init();
    64         nogaim_init();
    6565       
    6666        srand( time( NULL ) ^ getpid() );
     67       
    6768        global.helpfile = g_strdup( HELP_FILE );
     69        if( help_init( &global.help, global.helpfile ) == NULL )
     70                log_message( LOGLVL_WARNING, "Error opening helpfile %s.", HELP_FILE );
     71
     72        global.storage = storage_init( global.conf->primary_storage, global.conf->migrate_storage );
     73        if( global.storage == NULL )
     74        {
     75                log_message( LOGLVL_ERROR, "Unable to load storage backend '%s'", global.conf->primary_storage );
     76                return( 1 );
     77        }
    6878       
    6979        if( global.conf->runmode == RUNMODE_INETD )
     
    116126                        setuid( pw->pw_uid );
    117127                }
    118         }
    119 
    120         global.storage = storage_init( global.conf->primary_storage, global.conf->migrate_storage );
    121         if( global.storage == NULL )
    122         {
    123                 log_message( LOGLVL_ERROR, "Unable to load storage backend '%s'", global.conf->primary_storage );
    124                 return( 1 );
    125128        }
    126129       
     
    142145        if( !getuid() || !geteuid() )
    143146                log_message( LOGLVL_WARNING, "BitlBee is running with root privileges. Why?" );
    144         if( help_init( &global.help, global.helpfile ) == NULL )
    145                 log_message( LOGLVL_WARNING, "Error opening helpfile %s.", HELP_FILE );
    146147       
    147148        b_main_run();
  • win32.c

    r38ff846 r8b8def58  
    2727#include "bitlbee.h"
    2828#include "commands.h"
    29 #include "crypting.h"
    3029#include "protocols/nogaim.h"
    3130#include "help.h"
Note: See TracChangeset for help on using the changeset viewer.