Changeset 2945c6f
- Timestamp:
- 2010-07-24T21:16:18Z (14 years ago)
- Branches:
- master
- Children:
- f1f7b5e
- Parents:
- ef14a83 (diff), 593971d (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - Files:
-
- 26 added
- 8 deleted
- 87 edited
- 7 moved
Legend:
- Unmodified
- Added
- Removed
-
Makefile
ref14a83 r2945c6f 10 10 11 11 # 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.o13 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.h12 objects = 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) 13 headers = 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 14 14 subdirs = lib protocols 15 15 … … 82 82 install-dev: 83 83 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 85 86 mkdir -p $(DESTDIR)$(PCDIR) 86 87 install -m 0644 bitlbee.pc $(DESTDIR)$(PCDIR) … … 93 94 install-etc: 94 95 mkdir -p $(DESTDIR)$(ETCDIR) 95 install -m 0644 motd.txt $(DESTDIR)$(ETCDIR)/motd.txt96 install -m 0644 bitlbee.conf $(DESTDIR)$(ETCDIR)/bitlbee.conf96 install -m 0644 $(SRCDIR)motd.txt $(DESTDIR)$(ETCDIR)/motd.txt 97 install -m 0644 $(SRCDIR)bitlbee.conf $(DESTDIR)$(ETCDIR)/bitlbee.conf 97 98 98 99 uninstall-etc: … … 110 111 @$(MAKE) -C $@ $(MAKECMDGOALS) 111 112 112 $(objects): %.o: %.c113 $(objects): %.o: $(SRCDIR)%.c 113 114 @echo '*' Compiling $< 114 115 @$(CC) -c $(CFLAGS) $< -o $@ -
bitlbee.c
ref14a83 r2945c6f 121 121 } 122 122 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 ); 124 124 125 125 #ifndef _WIN32 … … 318 318 struct bitlbee_child *child; 319 319 320 /* TODO: Stuff like this belongs in ipc.c. */ 320 321 child = g_new0( struct bitlbee_child, 1 ); 321 322 child->pid = client_pid; 322 323 child->ipc_fd = fds[0]; 323 child->ipc_inpa = b_input_add( child->ipc_fd, GAIM_INPUT_READ, ipc_master_read, child ); 324 child->ipc_inpa = b_input_add( child->ipc_fd, B_EV_IO_READ, ipc_master_read, child ); 325 child->to_fd = -1; 324 326 child_list = g_slist_append( child_list, child ); 325 327 … … 349 351 /* We can store the IPC fd there now. */ 350 352 global.listen_socket = fds[1]; 351 global.listen_watch_source_id = b_input_add( fds[1], GAIM_INPUT_READ, ipc_child_read, irc );353 global.listen_watch_source_id = b_input_add( fds[1], B_EV_IO_READ, ipc_child_read, irc ); 352 354 353 355 close( fds[0] ); … … 370 372 /* Try to save data for all active connections (if desired). */ 371 373 while( irc_connection_list != NULL ) 372 irc_free( irc_connection_list->data ); 374 irc_abort( irc_connection_list->data, FALSE, 375 "BitlBee server shutting down" ); 373 376 374 377 /* We'll only reach this point when not running in inetd mode: */ -
bitlbee.h
ref14a83 r2945c6f 43 43 44 44 #if HAVE_CONFIG_H 45 #include "config.h"45 #include <config.h> 46 46 #endif 47 47 … … 126 126 #define CONF_FILE_DEF ETCDIR "bitlbee.conf" 127 127 128 #include "bee.h" 128 129 #include "irc.h" 129 130 #include "storage.h" … … 160 161 gboolean bitlbee_io_current_client_write( gpointer data, gint source, b_input_condition cond ); 161 162 162 void root_command_string( irc_t *irc, user_t *u, char *command, int flags);163 void root_command_string( irc_t *irc, char *command ); 163 164 void root_command( irc_t *irc, char *command[] ); 165 gboolean cmd_identify_finish( gpointer data, gint fd, b_input_condition cond ); 164 166 gboolean bitlbee_shutdown( gpointer data, gint fd, b_input_condition cond ); 165 167 -
conf.c
ref14a83 r2945c6f 63 63 conf->ping_timeout = 300; 64 64 conf->user = NULL; 65 conf->ft_max_size = SIZE_MAX; 66 conf->ft_max_kbps = G_MAXUINT; 67 conf->ft_listen = NULL; 65 68 conf->protocols = NULL; 66 69 proxytype = 0; … … 315 318 conf->user = g_strdup( ini->value ); 316 319 } 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 } 317 344 else if( g_strcasecmp( ini->key, "protocols" ) == 0 ) 318 345 { … … 349 376 if( g_strcasecmp( ini->section, "defaults" ) == 0 ) 350 377 { 351 set_t *s = set_find( &irc-> set, ini->key );378 set_t *s = set_find( &irc->b->set, ini->key ); 352 379 353 380 if( s ) -
conf.h
ref14a83 r2945c6f 50 50 int ping_timeout; 51 51 char *user; 52 size_t ft_max_size; 53 int ft_max_kbps; 54 char *ft_listen; 52 55 char **protocols; 53 56 } conf_t; -
configure
ref14a83 r2945c6f 27 27 yahoo=1 28 28 twitter=1 29 twitter=1 30 purple=0 29 31 30 32 debug=0 … … 67 69 --oscar=0/1 Disable/enable Oscar part (ICQ, AIM) $oscar 68 70 --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 70 74 71 75 --debug=0/1 Disable/enable debugging $debug … … 121 125 EOF 122 126 127 srcdir="$(dirname $0)" 128 if [ "$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}" 146 else 147 srcdir=$PWD 148 fi 149 123 150 cat<<EOF>config.h 124 151 /* BitlBee settings, generated by configure … … 158 185 159 186 echo CFLAGS=$CFLAGS >> Makefile.settings 160 echo CFLAGS+=-I `pwd` -I`pwd`/lib -I`pwd`/protocols -I. >> Makefile.settings187 echo CFLAGS+=-I${srcdir} -I${srcdir}/lib -I${srcdir}/protocols -I. >> Makefile.settings 161 188 162 189 echo CFLAGS+=-DHAVE_CONFIG_H >> Makefile.settings … … 398 425 fi 399 426 400 STORAGES=" textxml"427 STORAGES="xml" 401 428 402 429 if [ "$ldap" = "auto" ]; then … … 508 535 protoobjs='' 509 536 537 if [ "$purple" = 0 ]; then 538 echo '#undef WITH_PURPLE' >> config.h 539 else 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 547 EFLAGS += $($PKG_CONFIG purple --libs) 548 PURPLE_CFLAGS += $($PKG_CONFIG purple --cflags) 549 EOF 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 567 fi 568 510 569 if [ "$msn" = 0 ]; then 511 570 echo '#undef WITH_MSN' >> config.h -
debian/bitlbee-common.config
-
Property
mode
changed from
100755
to100644
-
Property
mode
changed from
-
debian/bitlbee.init
-
Property
mode
changed from
100755
to100644
-
Property
mode
changed from
-
debian/bitlbee.postinst
-
Property
mode
changed from
100755
to100644
-
Property
mode
changed from
-
debian/bitlbee.postrm
-
Property
mode
changed from
100755
to100644
-
Property
mode
changed from
-
debian/bitlbee.prerm
-
Property
mode
changed from
100755
to100644
-
Property
mode
changed from
-
debian/changelog
ref14a83 r2945c6f 1 bitlbee (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 1 10 bitlbee (1.2.8-1) unstable; urgency=low 2 11 -
debian/control
ref14a83 r2945c6f 4 4 Maintainer: Wilmer van der Gaast <wilmer@gaast.net> 5 5 Uploaders: Jelmer Vernooij <jelmer@samba.org> 6 Standards-Version: 3.8. 07 Build-Depends: libglib2.0-dev (>= 2.4), libevent-dev, libgnutls-dev | libnss-dev (>= 1.6), debconf-2.0, po-debconf6 Standards-Version: 3.8.4 7 Build-Depends: libglib2.0-dev (>= 2.4), libevent-dev, libgnutls-dev | libnss-dev (>= 1.6), po-debconf, libpurple-dev, debhelper (>= 6) 8 8 Homepage: http://www.bitlbee.org/ 9 9 Vcs-Bzr: http://code.bitlbee.org/bitlbee/ … … 12 12 Package: bitlbee 13 13 Architecture: any 14 Depends: ${shlibs:Depends}, adduser, net-tools, ${debconf-depends}, debianutils (>= 1.16) 15 Description: An IRC to other chat networks gateway 14 Depends: ${shlibs:Depends}, adduser, debianutils (>= 1.16), bitlbee-common (= ${bee:Version}) 15 Conflicts: bitlbee-libpurple 16 Replaces: bitlbee-libpurple 17 Description: An IRC to other chat networks gateway (default version) 16 18 This program can be used as an IRC server which forwards everything you 17 19 say to people on other chat networks: Jabber, ICQ, AIM, MSN, Yahoo! and 18 20 Twitter. 19 21 22 Package: bitlbee-libpurple 23 Architecture: any 24 Depends: ${shlibs:Depends}, adduser, debianutils (>= 1.16), bitlbee-common (= ${bee:Version}) 25 Conflicts: bitlbee 26 Replaces: bitlbee 27 Description: 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 40 Package: bitlbee-common 41 Architecture: all 42 Depends: ${misc:Depends}, net-tools 43 Replaces: bitlbee 44 Description: 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 20 52 Package: bitlbee-dev 21 53 Architecture: all 22 Depends: bitlbee (>= ${source:Version}), bitlbee (<< ${source:Version}.1~)23 Description: An IRC to other chat networks gateway 54 Depends: ${misc:Depends}, bitlbee (>= ${bee:Version}), bitlbee (<< ${bee:Version}.1~) 55 Description: An IRC to other chat networks gateway (dev files) 24 56 This program can be used as an IRC server which forwards everything you 25 57 say to people on other chat networks: Jabber, ICQ, AIM, MSN, Yahoo! and -
debian/patches/bitlbee.conf.diff
ref14a83 r2945c6f 1 --- debian/bitlbee/etc/bitlbee/bitlbee.conf 2009-06-01 00:20:24.000000000 +01002 +++ debian/bitlbee/etc/bitlbee/bitlbee.conf 2009-06-07 21:16:19.000000000 +01001 --- bitlbee.conf 2009-06-01 00:20:24.000000000 +0100 2 +++ bitlbee.conf 2009-06-07 21:16:19.000000000 +0100 3 3 @@ -23,13 +23,18 @@ 4 4 ## If BitlBee is started by root as a daemon, it can drop root privileges, -
debian/po/POTFILES.in
ref14a83 r2945c6f 1 [type: gettext/rfc822deb] templates1 [type: gettext/rfc822deb] bitlbee-common.templates -
debian/rules
ref14a83 r2945c6f 1 1 #!/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 # 2 9 10 BITLBEE_CONFIGURE_FLAGS ?= 3 11 DEBUG ?= 0 4 12 5 ifdef BITLBEE_VERSION 6 BITLBEE_FORCE_VERSION=1 7 else 13 ifndef BITLBEE_VERSION 8 14 # 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 15 BITLBEE_CONFIGURE_VERSION ?= BITLBEE_VERSION=\"$(shell dpkg-parsechangelog | grep ^Version: | awk '{print $$2}')\" 11 16 endif 12 17 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 18 build: build-stamp 19 build-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 20 33 21 34 clean: 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-* 24 40 $(MAKE) distclean 25 # -$(MAKE) -C doc/ clean26 27 41 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 32 43 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/ 44 install: build 45 dh_testdir 46 dh_testroot 47 dh_clean -k 48 dh_installdirs 36 49 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 41 53 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 43 56 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 46 60 47 chmod 755 debian/post* debian/pre* debian/config debian/bitlbee.init 61 binary-common: 62 dh_testdir 63 dh_testroot 48 64 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 73 ifeq ($(DH_OPTIONS),-a) 74 cp -a debian/bitlbee/etc debian/bitlbee-libpurple 75 endif 76 dh_installman 77 dh_strip 78 dh_link 79 dh_compress 80 dh_fixperms 81 dh_installdeb 82 ifeq ($(DH_OPTIONS),-a) 83 cp -a debian/bitlbee/DEBIAN/post* debian/bitlbee/DEBIAN/pre* debian/bitlbee-libpurple/DEBIAN 84 endif 85 dh_shlibdeps 86 ifdef BITLBEE_VERSION 87 dh_gencontrol -- -v1:$(BITLBEE_VERSION)-0 -Vbee:Version=1:$(BITLBEE_VERSION)-0 88 else 89 dh_gencontrol -- -Vbee:Version=$(shell dpkg-parsechangelog | grep ^Version: | awk '{print $$2}' | sed -e 's/+[^+]*$$//') 90 endif 91 dh_md5sums 92 dh_builddeb 70 93 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 94 binary-indep: build install 95 $(MAKE) -f debian/rules DH_OPTIONS=-i binary-common 75 96 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 97 binary-arch: build install 98 $(MAKE) -f debian/rules DH_OPTIONS=-a binary-common 84 99 85 dpkg --build debian/bitlbee .. 100 binary-%: build install 101 make -f debian/rules binary-common DH_OPTIONS=-p$* 86 102 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 103 binary: binary-indep binary-arch 104 .PHONY: build clean binary-indep binary-arch binary-common binary install -
doc/CHANGES
ref14a83 r2945c6f 3 3 4 4 http://bugs.bitlbee.org/bitlbee/timeline?daysback=90&changeset=on 5 6 Version 1.3dev: 7 - Loads of new stuff, mostly ready for a new major release, but starting with 8 a dev snapshot. A few changes that were planned for a long time already: 9 - Rewrote the IRC core, which brings: 10 * Support for multiple (control) channels, so you can have one channel per 11 buddy group, per IM account/protocol, or for example a &offline with all 12 offline contacts. See "help channels" for information on how to use this. 13 * You can also leave and rejoin all channels. Being in &bitlbee is no 14 longer required. 15 * Now you can start groupchats by just joining a new channel and inviting 16 contacts. (The "chat with" command still works as well.) 17 * You can change your nickname, whenever you want. 18 * Root commands: 19 + To hopefully resolve confusion about the "account set" syntax, the 20 ordering was changed slightly: "account set acc/setting value" 21 becomes "account acc set setting value". Obviously the same order 22 should now be used for other account subcommands. 23 + Shortcuts: Instead of "account list" you can say "acc li". 24 * /whois shows idle/login times of your contacts when available. 25 * paste_buffer (previously known as buddy_sendbuffer) now works for chats 26 as well. 27 * The nick_source setting was replaced with a nick_format setting, which 28 looks more or less like a format string, and lets you tweak how nicknames 29 for contacts are generated in more detail. 30 * A per-channel show_users setting lets you configure exactly which kinds 31 of contacts (online/away/offline) should show up in a channel and what 32 modes (none/voice/etc) they should have. 33 * If you connect (and identify) to a BitlBee server you're already 34 connected to, you can take over the existing session instead of starting 35 a new one. 36 * More correct validation of channel names: They can contain pretty much 37 any character, unlike nicknames. 38 - Support for using libpurple instead of BitlBee's built-in IM protocol 39 modules. This can be enabled by passing --purple=1 to the configure script. 40 * This adds support for many more IM protocols to BitlBee. 41 * And new functionality to existing protocols. 42 * This is and will always be optional and using it on public servers is 43 *not* recommended. It should be pretty stable, but costs more RAM/etc. 44 * When using this variant, type "help purple" to get a list of supported 45 protocols. 46 - Support for file transfers, in and out. /DCC SEND a file to a contact and 47 it becomes a file transfer, and incoming file transfers become /DCC SENDs 48 to you. Note that this is mostly useful when combined with libpurple, as 49 only the Jabber native protocol module currently supports file transfers. 50 51 Finished ... 2010 5 52 6 53 Version 1.2.8: -
doc/Makefile
ref14a83 r2945c6f 1 1 -include ../Makefile.settings 2 ifdef SRCDIR 3 SRCDIR := $(SRCDIR)doc/ 4 endif 2 5 3 6 all: … … 7 10 install: 8 11 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/ 11 14 $(MAKE) -C user-guide $@ 12 15 -
doc/user-guide/Makefile
ref14a83 r2945c6f 1 1 -include ../../Makefile.settings 2 ifdef SRCDIR 3 SRCDIR := $(SRCDIR)doc/user-guide/ 4 endif 5 2 6 EXTRAPARANEWLINE = 1 3 7 # EXTRAPARANEWLINE = 0 … … 38 42 chmod 0755 $(DESTDIR)$(DATADIR) 39 43 rm -f $(DESTDIR)$(DATADIR)/help.txt # Prevent help function from breaking in running sessions 40 install -m 0644 help.txt $(DESTDIR)$(DATADIR)/help.txt44 install -m 0644 $(SRCDIR)help.txt $(DESTDIR)$(DATADIR)/help.txt 41 45 42 46 uninstall: -
doc/user-guide/commands.xml
ref14a83 r2945c6f 6 6 <bitlbee-command name="account"> 7 7 <short-description>IM-account list maintenance</short-description> 8 <syntax>account <action> [<arguments>]</syntax>8 <syntax>account [<account id>] <action> [<arguments>]</syntax> 9 9 10 10 <description> … … 99 99 100 100 <bitlbee-command name="del"> 101 <syntax>account del <account id></syntax>101 <syntax>account <account id> del</syntax> 102 102 103 103 <description> … … 108 108 109 109 <para> 110 The account ID can be a number (see <emphasis>account list</emphasis>), the protocol name or (part of) the screenname, as long as it matches only one connection.110 The account ID can be a number/tag (see <emphasis>account list</emphasis>), the protocol name or (part of) the screenname, as long as it matches only one connection. 111 111 </para> 112 112 </description> … … 114 114 115 115 <bitlbee-command name="on"> 116 <syntax>account on [<account id>]</syntax>116 <syntax>account [<account id>] on</syntax> 117 117 118 118 <description> … … 122 122 123 123 <para> 124 The account ID can be a number (see <emphasis>account list</emphasis>), the protocol name or (part of) the screenname, as long as it matches only one connection.124 The account ID can be a number/tag (see <emphasis>account list</emphasis>), the protocol name or (part of) the screenname, as long as it matches only one connection. 125 125 </para> 126 126 </description> … … 129 129 130 130 <bitlbee-command name="off"> 131 <syntax>account off [<account id>]</syntax>131 <syntax>account [<account id>] off</syntax> 132 132 133 133 <description> … … 137 137 138 138 <para> 139 The account ID can be a number (see <emphasis>account list</emphasis>), the protocol name or (part of) the screenname, as long as it matches only one connection.139 The account ID can be a number/tag (see <emphasis>account list</emphasis>), the protocol name or (part of) the screenname, as long as it matches only one connection. 140 140 </para> 141 141 </description> … … 153 153 154 154 <bitlbee-command name="set"> 155 <syntax>account set <account id></syntax>156 <syntax>account set <account id>/<setting></syntax>157 <syntax>account set <account id>/<setting> <value></syntax>158 <syntax>account set -del <account id>/<setting></syntax>155 <syntax>account <account id> set</syntax> 156 <syntax>account <account id> set <setting></syntax> 157 <syntax>account <account id> set <setting> <value></syntax> 158 <syntax>account <account id> set -del <setting></syntax> 159 159 160 160 <description> 161 161 <para> 162 This command can be used to change various settings for IM accounts. For all protocols, this command can be used to change the handle or the password BitlBee uses to log in and if it should be logged in automatically. Some protocols have additional settings. You can see the settings available for a connection by typing <emphasis>account set <account id></emphasis>.162 This command can be used to change various settings for IM accounts. For all protocols, this command can be used to change the handle or the password BitlBee uses to log in and if it should be logged in automatically. Some protocols have additional settings. You can see the settings available for a connection by typing <emphasis>account <account id> set</emphasis>. 163 163 </para> 164 164 … … 168 168 169 169 <para> 170 The account ID can be a number (see <emphasis>account list</emphasis>), the protocol name or (part of) the screenname, as long as it matches only one connection.170 The account ID can be a number/tag (see <emphasis>account list</emphasis>), the protocol name or (part of) the screenname, as long as it matches only one connection. 171 171 </para> 172 172 </description> 173 173 </bitlbee-command> 174 </bitlbee-command> 175 176 <bitlbee-command name="channel"> 177 <short-description>Channel list maintenance</short-description> 178 <syntax>channel [<account id>] <action> [<arguments>]</syntax> 179 180 <description> 181 <para> 182 Available actions: del, list, set. See <emphasis>help chat <action></emphasis> for more information. 183 </para> 184 185 <para> 186 There is no <emphasis>channel add</emphasis> command. To create a new channel, just use the IRC <emphasis>/join</emphasis> command. See also <emphasis>help channels</emphasis> and <emphasis>help groupchats</emphasis>. 187 </para> 188 </description> 189 190 <bitlbee-command name="del"> 191 <syntax>channel <channel id> del</syntax> 192 193 <description> 194 <para> 195 Remove a channel and forget all its settings. You can only remove channels you're not currently in, and can't remove the main control channel. (You can, however, leave it.) 196 </para> 197 </description> 198 199 </bitlbee-command> 200 201 <bitlbee-command name="list"> 202 <syntax>channel list</syntax> 203 204 <description> 205 <para> 206 This command gives you a list of all the channels you configured. 207 </para> 208 </description> 209 210 </bitlbee-command> 211 212 <bitlbee-command name="set"> 213 <syntax>channel [<channel id>] set</syntax> 214 <syntax>channel [<channel id>] set <setting></syntax> 215 <syntax>channel [<channel id>] set <setting> <value></syntax> 216 <syntax>channel [<channel id>] set -del <setting></syntax> 217 218 <description> 219 <para> 220 This command can be used to change various settings for channels. Different channel types support different settings. You can see the settings available for a channel by typing <emphasis>channel <channel id> set</emphasis>. 221 </para> 222 223 <para> 224 For more infomation about a setting, see <emphasis>help set <setting></emphasis>. 225 </para> 226 227 <para> 228 The channel ID can be a number (see <emphasis>channel list</emphasis>), or (part of) its name, as long as it matches only one channel. If you want to change settings of the current channel, you can omit the channel ID. 229 </para> 230 </description> 231 </bitlbee-command> 232 174 233 </bitlbee-command> 175 234 … … 181 240 182 241 <para> 183 Available actions: add, del, list, with and set. See <emphasis>help chat <action></emphasis> for more information.242 Available actions: add, with. See <emphasis>help chat <action></emphasis> for more information. 184 243 </para> 185 244 … … 187 246 188 247 <bitlbee-command name="add"> 189 <syntax>chat add <account > <room> [<channel>]</syntax>248 <syntax>chat add <account id> <room> [<channel>]</syntax> 190 249 191 250 <description> … … 205 264 </bitlbee-command> 206 265 207 <bitlbee-command name=" del">208 <syntax>chat del <chat id></syntax>266 <bitlbee-command name="with"> 267 <syntax>chat with <nickname></syntax> 209 268 210 269 <description> 211 270 <para> 212 This commands deletes an chatroom from your list. 213 </para> 214 215 <para> 216 The room ID can be a number (see <emphasis>chat list</emphasis>), or (part of) the name of the room/channel. 271 While most <emphasis>chat</emphasis> subcommands are about named chatrooms, this command can be used to open an unnamed groupchat with one or more persons. This command is what <emphasis>/join #nickname</emphasis> used to do in older BitlBee versions. 217 272 </para> 218 273 </description> 219 274 </bitlbee-command> 220 221 <bitlbee-command name="list">222 <syntax>chat list</syntax>223 224 <description>225 <para>226 This command gives you a list of all the chatrooms known by BitlBee.227 </para>228 </description>229 </bitlbee-command>230 231 <bitlbee-command name="with">232 <syntax>chat with <nickname></syntax>233 234 <description>235 <para>236 While most <emphasis>chat</emphasis> subcommands are about named chatrooms, this command can be used to open an unnamed groupchat with one or more persons. This command is what <emphasis>/join #nickname</emphasis> used to do in older BitlBee versions.237 </para>238 </description>239 </bitlbee-command>240 241 <bitlbee-command name="set">242 <syntax>chat set <chat id></syntax>243 <syntax>chat set <chat id>/<setting></syntax>244 <syntax>chat set <chat id>/<setting> <value></syntax>245 <syntax>chat set -del <chat id>/<setting></syntax>246 247 <description>248 <para>249 This command can be used to change various settings for chatrooms.250 </para>251 252 <para>253 For more infomation about a setting, see <emphasis>help set <setting></emphasis>.254 </para>255 256 <para>257 The room ID can be a number (see <emphasis>chat list</emphasis>), or (part of) the name of the room/channel.258 </para>259 </description>260 </bitlbee-command>261 275 </bitlbee-command> 262 276 263 277 <bitlbee-command name="add"> 264 278 <short-description>Add a buddy to your contact list</short-description> 265 <syntax>add < connection> <handle> [<nick>]</syntax>266 <syntax>add -tmp < connection> <handle> [<nick>]</syntax>279 <syntax>add <account id> <handle> [<nick>]</syntax> 280 <syntax>add -tmp <account id> <handle> [<nick>]</syntax> 267 281 268 282 <description> … … 273 287 <para> 274 288 If you want, you can also tell BitlBee what nick to give the new contact. The -tmp option adds the buddy to the internal BitlBee structures only, not to the real contact list (like done by <emphasis>set handle_unknown add</emphasis>). This allows you to talk to people who are not in your contact list. This normally won't show you any presence notifications. 289 </para> 290 291 <para> 292 If you use this command in a control channel containing people from only one group, the new contact will be added to that group automatically. 275 293 </para> 276 294 </description> … … 398 416 </bitlbee-command> 399 417 418 <bitlbee-setting name="account" type="string" scope="channel"> 419 420 <description> 421 <para> 422 For control channels with <emphasis>fill_by</emphasis> set to <emphasis>account</emphasis>: Set this setting to the account id (numeric, or part of the username) of the account containing the contacts you want to see in this channel. 423 </para> 424 </description> 425 </bitlbee-setting> 426 427 <bitlbee-setting name="allow_takeover" type="boolean" scope="global"> 428 <default>true</default> 429 430 <description> 431 <para> 432 When you're already connected to a BitlBee server and you connect (and identify) again, BitlBee will offer to migrate your existing session to the new connection. If for whatever reason you don't want this, you can disable this setting. 433 </para> 434 </description> 435 </bitlbee-setting> 436 400 437 <bitlbee-setting name="auto_connect" type="boolean" scope="both"> 401 438 <default>true</default> … … 412 449 </bitlbee-setting> 413 450 414 <bitlbee-setting name="auto_join" type="boolean" scope="cha t">451 <bitlbee-setting name="auto_join" type="boolean" scope="channel"> 415 452 <default>false</default> 416 453 417 454 <description> 418 455 <para> 419 With this option enabled, BitlBee will automatically join this cha troomwhen you log in.456 With this option enabled, BitlBee will automatically join this channel when you log in. 420 457 </para> 421 458 </description> … … 481 518 With this option enabled, the root user devoices people when they go away (just away, not offline) and gives the voice back when they come back. You might dislike the voice-floods you'll get if your contact list is huge, so this option can be disabled. 482 519 </para> 520 521 <para> 522 Replaced with the <emphasis>show_users</emphasis> setting. See <emphasis>help show_users</emphasis>. 523 </para> 524 </description> 525 </bitlbee-setting> 526 527 <bitlbee-setting name="away_reply_timeout" type="integer" scope="global"> 528 <default>3600</default> 529 530 <description> 531 <para> 532 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. 533 </para> 534 535 <para> 536 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. 537 </para> 483 538 </description> 484 539 </bitlbee-setting> … … 498 553 <para> 499 554 Keep two things in mind: When not using Twitter, you <emphasis>must</emphasis> also disable the <emphasis>oauth</emphasis> setting as it currently only works with Twitter. If you're still having issues, make sure there is <emphasis>no</emphasis> slash at the end of the URL you enter here. 500 </para>501 </description>502 </bitlbee-setting>503 504 <bitlbee-setting name="buddy_sendbuffer" type="boolean" scope="global">505 <default>false</default>506 507 <description>508 <para>509 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.510 </para>511 512 <para>513 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.514 </para>515 516 <para>517 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.518 </para>519 </description>520 </bitlbee-setting>521 522 <bitlbee-setting name="buddy_sendbuffer_delay" type="integer" scope="global">523 <default>200</default>524 525 <description>526 527 <para>528 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.529 </para>530 531 <para>532 See also the <emphasis>buddy_sendbuffer</emphasis> setting.533 555 </para> 534 556 </description> … … 561 583 </bitlbee-setting> 562 584 585 <bitlbee-setting name="chat_type" type="string" scope="channel"> 586 <default>groupchat</default> 587 <possible-values>groupchat, room</possible-values> 588 589 <description> 590 <para> 591 There are two kinds of chat channels: simple groupchats (basically normal IM chats with more than two participants) and names chatrooms, more similar to IRC channels. 592 </para> 593 594 <para> 595 BitlBee supports both types. With this setting set to <emphasis>groupchat</emphasis> (the default), you can just invite people into the room and start talking. 596 </para> 597 598 <para> 599 For setting up named chatrooms, it's currently easier to just use the <emphasis>chat add</emphasis> command. 600 </para> 601 </description> 602 </bitlbee-setting> 603 563 604 <bitlbee-setting name="debug" type="boolean" scope="global"> 564 605 <default>false</default> … … 610 651 </bitlbee-setting> 611 652 653 <bitlbee-setting name="fill_by" type="string" scope="channel"> 654 <default>all</default> 655 <possible-values>all, group, account, protocol</possible-values> 656 657 <description> 658 <para> 659 For control channels only: This setting determines which contacts the channel gets populated with. 660 </para> 661 662 <para> 663 By default, control channels will contain all your contacts. You instead select contacts by buddy group, IM account or IM protocol. 664 </para> 665 666 <para> 667 Change this setting and the corresponding <emphasis>account</emphasis>/<emphasis>group</emphasis>/<emphasis>protocol</emphasis> setting to set up this selection. 668 </para> 669 670 <para> 671 Note that, when creating a new channel, BitlBee will try to preconfigure the channel for you, based on the channel name. See <emphasis>help channels</emphasis>. 672 </para> 673 </description> 674 </bitlbee-setting> 675 676 <bitlbee-setting name="group" type="string" scope="channel"> 677 678 <description> 679 <para> 680 For control channels with <emphasis>fill_by</emphasis> set to <emphasis>group</emphasis>: Set this setting to the name of the group containing the contacts you want to see in this channel. 681 </para> 682 </description> 683 </bitlbee-setting> 684 612 685 <bitlbee-setting name="handle_unknown" type="string" scope="global"> 613 <default> root</default>686 <default>add_channel</default> 614 687 <possible-values>root, add, add_private, add_channel, ignore</possible-values> 615 688 … … 717 790 718 791 <bitlbee-setting name="nick" type="string" scope="chat"> 719 720 792 <description> 721 793 <para> 722 794 You can use this option to set your nickname in a chatroom. You won't see this nickname yourself, but other people in the room will. By default, BitlBee will use your username as the chatroom nickname. 795 </para> 796 </description> 797 </bitlbee-setting> 798 799 <bitlbee-setting name="nick_format" type="string" scope="both"> 800 <default>%-@nick</default> 801 802 <description> 803 <para> 804 By default, BitlBee tries to derive sensible nicknames for all your contacts from their IM handles. In some cases, IM modules (ICQ for example) will provide a nickname suggestion, which will then be used instead. This setting lets you change this behaviour. 805 </para> 806 807 <para> 808 Whenever this setting is set for an account, it will be used for all its contacts. If it's not set, the global value will be used. 809 </para> 810 811 <para> 812 It's easier to describe this setting using a few examples: 813 </para> 814 815 <para> 816 FB-%full_name will make all nicknames start with "FB-", followed by the person's full name. For example you can set this format for your Facebook account so all Facebook contacts are clearly marked. 817 </para> 818 819 <para> 820 [%group]%-@nick will make all nicknames start with the group the contact is in between square brackets, followed by the nickname suggestions from the IM module if available, or otherwise the handle. Because of the "-@" part, everything from the first @ will be stripped. 821 </para> 822 823 <para> 824 See <emphasis>help nick_format</emphasis> for more information. 723 825 </para> 724 826 </description> … … 789 891 </description> 790 892 </bitlbee-setting> 893 894 <bitlbee-setting name="paste_buffer" type="boolean" scope="global"> 895 <default>false</default> 896 897 <description> 898 <para> 899 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. 900 </para> 901 902 <para> 903 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. 904 </para> 905 906 <para> 907 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. 908 </para> 909 </description> 910 </bitlbee-setting> 911 912 <bitlbee-setting name="paste_buffer_delay" type="integer" scope="global"> 913 <default>200</default> 914 915 <description> 916 917 <para> 918 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. 919 </para> 920 921 <para> 922 See also the <emphasis>paste_buffer</emphasis> setting. 923 </para> 924 </description> 925 </bitlbee-setting> 791 926 792 927 <bitlbee-setting name="port" type="integer" scope="account"> … … 822 957 <para> 823 958 This setting is remembered (during one session) per-user, this setting only changes the default state. This option takes effect as soon as you reconnect. 959 </para> 960 </description> 961 </bitlbee-setting> 962 963 <bitlbee-setting name="protocol" type="string" scope="channel"> 964 965 <description> 966 <para> 967 For control channels with <emphasis>fill_by</emphasis> set to <emphasis>protocol</emphasis>: Set this setting to the name of the IM protocol of all contacts you want to see in this channel. 824 968 </para> 825 969 </description> … … 901 1045 If enabled causes BitlBee to also show offline users in Channel. Online-users will get op, away-users voice and offline users none of both. This option takes effect as soon as you reconnect. 902 1046 </para> 1047 1048 <para> 1049 Replaced with the <emphasis>show_users</emphasis> setting. See <emphasis>help show_users</emphasis>. 1050 </para> 1051 </description> 1052 </bitlbee-setting> 1053 1054 <bitlbee-setting name="show_users" type="string" scope="channel"> 1055 <default>online+,away</default> 1056 1057 <description> 1058 <para> 1059 Comma-separated list of statuses of users you want in the channel, 1060 and any modes they should have. The following statuses are currently 1061 recognised: <emphasis>online</emphasis> (i.e. available, not 1062 away), <emphasis>away</emphasis>, and <emphasis>offline</emphasis>. 1063 </para> 1064 1065 <para> 1066 If a status is followed by a valid channel mode character 1067 (@, % or +), it will be given to users with that status. 1068 For example, <emphasis>online@,away+,offline</emphasis> will 1069 show all users in the channel. Online people will 1070 have +o, people who are online but away will have +v, 1071 and others will have no special modes. 1072 </para> 903 1073 </description> 904 1074 </bitlbee-setting> … … 967 1137 <para> 968 1138 This is useful because BitlBee doesn't support MSN offline messages yet and the MSN servers won't let the user reopen switchboards to offline users. Once offline messaging is supported, this flag might be removed. 1139 </para> 1140 </description> 1141 </bitlbee-setting> 1142 1143 <bitlbee-setting name="tag" type="string" scope="account"> 1144 <description> 1145 <para> 1146 For every account you have, you can set a tag you can use to uniquely identify that account. This tag can be used instead of the account number (or protocol name, or part of the screenname) when using commands like <emphasis>account</emphasis>, <emphasis>add</emphasis>, etc. You can't have two accounts with one and the same account tag. 1147 </para> 1148 1149 <para> 1150 By default, it will be set to the name of the IM protocol. Once you add a second account on an IM network, a numeric suffix will be added, starting with 2. 969 1151 </para> 970 1152 </description> … … 1010 1192 <para> 1011 1193 Please note that this setting is only used for incoming messages. For outgoing messages you can use ':' (colon) or ',' to separate the destination nick from the message, and this is not configurable. 1194 </para> 1195 </description> 1196 </bitlbee-setting> 1197 1198 <bitlbee-setting name="translate_to_nicks" type="boolean" scope="channel"> 1199 <default>true</default> 1200 1201 <description> 1202 <para> 1203 IRC's nickname namespace is quite limited compared to most IM protocols. Not any non-ASCII characters are allowed, in fact nicknames have to be mostly alpha-numeric. Also, BitlBee has to add underscores sometimes to avoid nickname collisions. 1204 </para> 1205 1206 <para> 1207 While normally the BitlBee user is the only one seeing these names, they may be exposed to other chatroom participants for example when addressing someone in the channel (with or without tab completion). By default BitlBee will translate these stripped nicknames back to the original nick. If you don't want this, disable this setting. 1208 </para> 1209 </description> 1210 </bitlbee-setting> 1211 1212 <bitlbee-setting name="type" type="string" scope="channel"> 1213 <default>control</default> 1214 <possible-values>control, chat</possible-values> 1215 1216 <description> 1217 <para> 1218 BitlBee supports two kinds of channels: control channels (usually with a name starting with a &) and chatroom channels (name usually starts with a #). 1219 </para> 1220 1221 <para> 1222 See <emphasis>help channels</emphasis> for a full description of channel types in BitlBee. 1012 1223 </para> 1013 1224 </description> … … 1146 1357 1147 1358 <bitlbee-command name="identify"> 1148 <syntax>identify <password></syntax>1359 <syntax>identify [-noload|-force] <password></syntax> 1149 1360 <short-description>Identify yourself with your password</short-description> 1150 1361 … … 1156 1367 <para> 1157 1368 Once you're registered, you can change your password using <emphasis>set password <password></emphasis>. 1369 </para> 1370 1371 <para> 1372 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). 1373 </para> 1374 1375 <para> 1376 <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). 1158 1377 </para> 1159 1378 </description> … … 1183 1402 </bitlbee-command> 1184 1403 1185 <bitlbee-command name="nick"> 1186 <short-description>Change friendly name, nick</short-description> 1187 <syntax>nick <connection> [<new nick>]</syntax> 1188 <syntax>nick <connection></syntax> 1189 1190 <description> 1191 <para> 1192 Deprecated: Use the per-account <emphasis>display_name</emphasis> setting to read and change this information. 1193 </para> 1194 </description> 1195 1196 <ircexample> 1197 <ircline nick="wouter">account set 1/display_name "The majestik møøse"</ircline> 1198 <ircline nick="root">display_name = `The majestik møøse'</ircline> 1199 </ircexample> 1200 1201 </bitlbee-command> 1404 <bitlbee-command name="group"> 1405 <short-description>Contact group management</short-description> 1406 <syntax>group list</syntax> 1407 1408 <description> 1409 <para> 1410 Only the <emphasis>group list</emphasis> command is supported at the moment, which shows a list of all groups defined so far. 1411 </para> 1412 </description> 1413 </bitlbee-command> 1414 1415 <bitlbee-command name="transfers"> 1416 <short-description>Monitor, cancel, or reject file transfers</short-description> 1417 <syntax>transfers [<cancel> id | <reject>]</syntax> 1418 1419 <description> 1420 <para> 1421 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 <action></emphasis> for more information. 1422 </para> 1423 1424 <ircexample> 1425 <ircline nick="ulim">transfers</ircline> 1426 </ircexample> 1427 </description> 1428 1429 <bitlbee-command name="cancel"> 1430 <short-description>Cancels the file transfer with the given id</short-description> 1431 <syntax>transfers <cancel> id</syntax> 1432 1433 <description> 1434 <para>Cancels the file transfer with the given id</para> 1435 </description> 1436 1437 <ircexample> 1438 <ircline nick="ulim">transfers cancel 1</ircline> 1439 <ircline nick="root">Canceling file transfer for test</ircline> 1440 </ircexample> 1441 </bitlbee-command> 1442 1443 <bitlbee-command name="reject"> 1444 <short-description>Rejects all incoming transfers</short-description> 1445 <syntax>transfers <reject></syntax> 1446 1447 <description> 1448 <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> 1449 </description> 1450 1451 <ircexample> 1452 <ircline nick="ulim">transfers reject</ircline> 1453 </ircexample> 1454 </bitlbee-command> 1455 </bitlbee-command> 1456 1202 1457 </chapter> -
doc/user-guide/help.xml
ref14a83 r2945c6f 14 14 <varlistentry><term>quickstart</term><listitem><para>A short introduction into BitlBee</para></listitem></varlistentry> 15 15 <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> 16 17 <varlistentry><term>away</term><listitem><para>About setting away states</para></listitem></varlistentry> 18 <varlistentry><term>groupchats</term><listitem><para>How to work with groupchats on BitlBee</para></listitem></varlistentry> 19 <varlistentry><term>nick_changes</term><listitem><para>Changing your nickname without losing any settings</para></listitem></varlistentry> 17 20 <varlistentry><term>smileys</term><listitem><para>A summary of some non-standard smileys you might find and fail to understand</para></listitem></varlistentry> 18 <varlistentry><term>groupchats</term><listitem><para>How to work with groupchats on BitlBee</para></listitem></varlistentry>19 21 </variablelist> 20 22 … … 43 45 <varlistentry><term>quickstart</term><listitem><para>A short introduction into BitlBee</para></listitem></varlistentry> 44 46 <varlistentry><term>commands</term><listitem><para>All available commands and settings</para></listitem></varlistentry> 47 <varlistentry><term>channels</term><listitem><para>About creating and customizing channels</para></listitem></varlistentry> 45 48 <varlistentry><term>away</term><listitem><para>About setting away states</para></listitem></varlistentry> 49 <varlistentry><term>groupchats</term><listitem><para>How to work with groupchats on BitlBee</para></listitem></varlistentry> 50 <varlistentry><term>nick_changes</term><listitem><para>Changing your nickname without losing any settings</para></listitem></varlistentry> 46 51 <varlistentry><term>smileys</term><listitem><para>A summary of some non-standard smileys you might find and fail to understand</para></listitem></varlistentry> 47 <varlistentry><term>groupchats</term><listitem><para>How to work with groupchats on BitlBee</para></listitem></varlistentry>48 52 </variablelist> 49 53 -
doc/user-guide/misc.xml
ref14a83 r2945c6f 117 117 </sect1> 118 118 119 <sect1 id="nick_changes"> 120 <title>Changing your nickname</title> 121 122 <para> 123 BitlBee 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> 127 The 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> 131 To 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> 140 You 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> 144 You 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 &, and as chat channels if it starts with a #. 145 </para> 146 147 <para> 148 Control channels are where you see your contacts. By default, you will have one control channel called &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> 152 For 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> 156 Type <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> 165 When 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 &) 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> 169 Any 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 &msn, it will contain all your MSN contacts. And if you have a Facebook account set up, you can see its contacts by just joining &facebook. 170 </para> 171 172 <para> 173 To 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> 177 If you want to configure your own channels, you can use the <emphasis>channel set</emphasis>. 178 </para> 179 180 </sect1> 181 182 <sect1 id="nick_format"> 183 <title>Nickname formatting</title> 184 185 <para> 186 The <emphasis>nick_format</emphasis> setting can be set globally using 187 the <emphasis>set</emphasis> command, or per account using <emphasis>account 188 set</emphasis> (so that you can set a per-account suffix/prefix or have 189 nicknames generated from full names for certain accounts). 190 </para> 191 192 <para> 193 The setting is basically some kind of format string. It can contain normal 194 text that will be copied to the nick, combined with several variables: 195 </para> 196 197 <variablelist> 198 <varlistentry><term>%nick</term><listitem><para>Nickname suggested for this contact by the IM protocol, or just the handle if no nickname was suggested.</para></listitem></varlistentry> 199 <varlistentry><term>%handle</term><listitem><para>The handle/screenname of the contact.</para></listitem></varlistentry> 200 <varlistentry><term>%full_name</term><listitem><para>The full name of the contact.</para></listitem></varlistentry> 201 <varlistentry><term>%first_name</term><listitem><para>The first name of the contact (the full name up to the first space).</para></listitem></varlistentry> 202 <varlistentry><term>%group</term><listitem><para>The name of the group this contact is a member of</para></listitem></varlistentry> 203 </variablelist> 204 205 <para> 206 Invalid characters (like spaces) will always be stripped. Depending on your 207 locale settings, characters with accents will be converted to ASCII. 208 </para> 209 210 <para> 211 See <emphasis>set nick_format2</emphasis> for some more information. 212 </para> 213 214 </sect1> 215 216 <sect1 id="nick_format2"> 217 <title>Nickname formatting - modifiers</title> 218 219 <para> 220 Two modifiers ares currently available: You can include only the first few 221 characters of a variable by putting a number right after the %. For 222 example, <emphasis>[%3group]%-@nick</emphasis> will include only the first 223 three characters of the group name in the nick. 224 </para> 225 226 <para> 227 Also, you can truncate variables from a certain character using 228 the <emphasis>-</emphasis> modifier. For example, you may want to leave out 229 everything after the @. <emphasis>%-@handle</emphasis> will expand to 230 everything in the handle up to the first @. 231 </para> 232 233 </sect1> 234 119 235 </chapter> -
help.c
ref14a83 r2945c6f 2 2 * BitlBee -- An IRC to other IM-networks gateway * 3 3 * * 4 * Copyright 2002-200 5Wilmer van der Gaast and others *4 * Copyright 2002-2009 Wilmer van der Gaast and others * 5 5 \********************************************************************/ 6 6 … … 169 169 return NULL; 170 170 } 171 172 int 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
ref14a83 r2945c6f 46 46 void help_free( help_t **help ); 47 47 char *help_get( help_t **help, char *title ); 48 int help_add_mem( help_t **help, const char *title, const char *content_ ); 48 49 49 50 #endif -
ipc.c
ref14a83 r2945c6f 2 2 * BitlBee -- An IRC to other IM-networks gateway * 3 3 * * 4 * Copyright 2002-20 06Wilmer van der Gaast and others *4 * Copyright 2002-2010 Wilmer van der Gaast and others * 5 5 \********************************************************************/ 6 6 … … 29 29 #include "commands.h" 30 30 #ifndef _WIN32 31 #include <sys/uio.h> 31 32 #include <sys/un.h> 32 33 #endif 33 34 34 35 GSList *child_list = NULL; 36 static int ipc_child_recv_fd = -1; 37 38 static void ipc_master_takeover_fail( struct bitlbee_child *child, gboolean both ); 39 static gboolean ipc_send_fd( int fd, int send_fd ); 35 40 36 41 static void ipc_master_cmd_client( irc_t *data, char **cmd ) … … 49 54 } 50 55 56 /* CLIENT == On initial connects, HELLO is after /RESTARTs. */ 51 57 if( g_strcasecmp( cmd[0], "CLIENT" ) == 0 ) 52 58 ipc_to_children_str( "OPERMSG :Client connecting (PID=%d): %s@%s (%s)\r\n", … … 54 60 } 55 61 62 static void ipc_master_cmd_nick( irc_t *data, char **cmd ) 63 { 64 struct bitlbee_child *child = (void*) data; 65 66 if( child && cmd[1] ) 67 { 68 g_free( child->nick ); 69 child->nick = g_strdup( cmd[1] ); 70 } 71 } 72 56 73 static void ipc_master_cmd_die( irc_t *data, char **cmd ) 57 74 { … … 110 127 global.restart = -1; 111 128 bitlbee_shutdown( NULL, -1, 0 ); 129 } 130 131 void ipc_master_cmd_identify( irc_t *data, char **cmd ) 132 { 133 struct bitlbee_child *child = (void*) data, *old = NULL; 134 char *resp; 135 GSList *l; 136 137 if( !child || !child->nick || strcmp( child->nick, cmd[1] ) != 0 ) 138 return; 139 140 g_free( child->password ); 141 child->password = g_strdup( cmd[2] ); 142 143 for( l = child_list; l; l = l->next ) 144 { 145 old = l->data; 146 if( child != old && 147 old->nick && nick_cmp( old->nick, child->nick ) == 0 && 148 old->password && strcmp( old->password, child->password ) == 0 ) 149 break; 150 } 151 152 if( l && !child->to_child && !old->to_child ) 153 { 154 resp = "TAKEOVER INIT\r\n"; 155 child->to_child = old; 156 old->to_child = child; 157 } 158 else 159 { 160 /* Won't need the fd since we can't send it anywhere. */ 161 closesocket( child->to_fd ); 162 child->to_fd = -1; 163 resp = "TAKEOVER NO\r\n"; 164 } 165 166 if( write( child->ipc_fd, resp, strlen( resp ) ) != strlen( resp ) ) 167 ipc_master_free_one( child ); 168 } 169 170 171 void ipc_master_cmd_takeover( irc_t *data, char **cmd ) 172 { 173 struct bitlbee_child *child = (void*) data; 174 char *fwd = NULL; 175 176 /* Normal daemon mode doesn't keep these and has simplified code for 177 takeovers. */ 178 if( child == NULL ) 179 return; 180 181 if( child->to_child == NULL || 182 g_slist_find( child_list, child->to_child ) == NULL ) 183 return ipc_master_takeover_fail( child, FALSE ); 184 185 if( strcmp( cmd[1], "AUTH" ) == 0 ) 186 { 187 /* New connection -> Master */ 188 if( child->to_child && 189 child->nick && child->to_child->nick && cmd[2] && 190 child->password && child->to_child->password && cmd[3] && 191 strcmp( child->nick, child->to_child->nick ) == 0 && 192 strcmp( child->nick, cmd[2] ) == 0 && 193 strcmp( child->password, child->to_child->password ) == 0 && 194 strcmp( child->password, cmd[3] ) == 0 ) 195 { 196 ipc_send_fd( child->to_child->ipc_fd, child->to_fd ); 197 198 fwd = irc_build_line( cmd ); 199 if( write( child->to_child->ipc_fd, fwd, strlen( fwd ) ) != strlen( fwd ) ) 200 ipc_master_free_one( child ); 201 g_free( fwd ); 202 } 203 else 204 return ipc_master_takeover_fail( child, TRUE ); 205 } 206 else if( strcmp( cmd[1], "DONE" ) == 0 || strcmp( cmd[1], "FAIL" ) == 0 ) 207 { 208 /* Old connection -> Master */ 209 int fd; 210 211 /* The copy was successful (or not), we don't need it anymore. */ 212 closesocket( child->to_fd ); 213 child->to_fd = -1; 214 215 /* Pass it through to the other party, and flush all state. */ 216 fwd = irc_build_line( cmd ); 217 fd = child->to_child->ipc_fd; 218 child->to_child->to_child = NULL; 219 child->to_child = NULL; 220 if( write( fd, fwd, strlen( fwd ) ) != strlen( fwd ) ) 221 ipc_master_free_one( child ); 222 g_free( fwd ); 223 } 112 224 } 113 225 … … 115 227 { "client", 3, ipc_master_cmd_client, 0 }, 116 228 { "hello", 0, ipc_master_cmd_client, 0 }, 229 { "nick", 1, ipc_master_cmd_nick, 0 }, 117 230 { "die", 0, ipc_master_cmd_die, 0 }, 118 231 { "deaf", 0, ipc_master_cmd_deaf, 0 }, … … 123 236 { "kill", 2, NULL, IPC_CMD_TO_CHILDREN }, 124 237 { "restart", 0, ipc_master_cmd_restart, 0 }, 238 { "identify", 2, ipc_master_cmd_identify, 0 }, 239 { "takeover", 1, ipc_master_cmd_takeover, 0 }, 125 240 { NULL } 126 241 }; … … 138 253 139 254 if( strchr( irc->umode, 'w' ) ) 140 irc_write( irc, ":%s WALLOPS :%s", irc-> myhost, cmd[1] );255 irc_write( irc, ":%s WALLOPS :%s", irc->root->host, cmd[1] ); 141 256 } 142 257 … … 147 262 148 263 if( strchr( irc->umode, 's' ) ) 149 irc_write( irc, ":%s NOTICE %s :%s", irc-> myhost, irc->nick, cmd[1] );264 irc_write( irc, ":%s NOTICE %s :%s", irc->root->host, irc->user->nick, cmd[1] ); 150 265 } 151 266 … … 156 271 157 272 if( strchr( irc->umode, 'o' ) ) 158 irc_write( irc, ":%s NOTICE %s :*** OperMsg *** %s", irc-> myhost, irc->nick, cmd[1] );273 irc_write( irc, ":%s NOTICE %s :*** OperMsg *** %s", irc->root->host, irc->user->nick, cmd[1] ); 159 274 } 160 275 … … 176 291 return; 177 292 178 if( nick_cmp( cmd[1], irc-> nick ) != 0 )293 if( nick_cmp( cmd[1], irc->user->nick ) != 0 ) 179 294 return; /* It's not for us. */ 180 295 181 irc_write( irc, ":%s!%s@%s KILL %s :%s", irc-> mynick, irc->mynick, irc->myhost, irc->nick, cmd[2] );296 irc_write( irc, ":%s!%s@%s KILL %s :%s", irc->root->nick, irc->root->nick, irc->root->host, irc->user->nick, cmd[2] ); 182 297 irc_abort( irc, 0, "Killed by operator: %s", cmd[2] ); 183 298 } … … 188 303 ipc_to_master_str( "HELLO\r\n" ); 189 304 else 190 ipc_to_master_str( "HELLO %s %s :%s\r\n", irc->host, irc->nick, irc->realname ); 305 ipc_to_master_str( "HELLO %s %s :%s\r\n", irc->user->host, irc->user->nick, irc->user->fullname ); 306 } 307 308 static void ipc_child_cmd_takeover_yes( void *data ); 309 static void ipc_child_cmd_takeover_no( void *data ); 310 311 static void ipc_child_cmd_takeover( irc_t *irc, char **cmd ) 312 { 313 if( strcmp( cmd[1], "NO" ) == 0 ) 314 { 315 /* Master->New connection */ 316 /* No takeover, finish the login. */ 317 } 318 else if( strcmp( cmd[1], "INIT" ) == 0 ) 319 { 320 /* Master->New connection */ 321 if( !set_getbool( &irc->b->set, "allow_takeover" ) ) 322 { 323 ipc_child_cmd_takeover_no( irc ); 324 return; 325 } 326 327 /* Offer to take over the old session, unless for some reason 328 we're already logging into IM connections. */ 329 if( irc->login_source_id != -1 ) 330 query_add( irc, NULL, 331 "You're already connected to this server. " 332 "Would you like to take over this session?", 333 ipc_child_cmd_takeover_yes, 334 ipc_child_cmd_takeover_no, NULL, irc ); 335 336 /* This one's going to connect to accounts, avoid that. */ 337 b_event_remove( irc->login_source_id ); 338 irc->login_source_id = -1; 339 } 340 else if( strcmp( cmd[1], "AUTH" ) == 0 ) 341 { 342 /* Master->Old connection */ 343 if( irc->password && cmd[2] && cmd[3] && 344 ipc_child_recv_fd != -1 && 345 strcmp( irc->user->nick, cmd[2] ) == 0 && 346 strcmp( irc->password, cmd[3] ) == 0 && 347 set_getbool( &irc->b->set, "allow_takeover" ) ) 348 { 349 irc_switch_fd( irc, ipc_child_recv_fd ); 350 irc_sync( irc ); 351 irc_usermsg( irc, "You've successfully taken over your old session" ); 352 ipc_child_recv_fd = -1; 353 354 ipc_to_master_str( "TAKEOVER DONE\r\n" ); 355 } 356 else 357 { 358 ipc_to_master_str( "TAKEOVER FAIL\r\n" ); 359 } 360 } 361 else if( strcmp( cmd[1], "DONE" ) == 0 ) 362 { 363 /* Master->New connection (now taken over by old process) */ 364 irc_free( irc ); 365 } 366 else if( strcmp( cmd[1], "FAIL" ) == 0 ) 367 { 368 /* Master->New connection */ 369 irc_usermsg( irc, "Could not take over old session" ); 370 } 371 } 372 373 static void ipc_child_cmd_takeover_yes( void *data ) 374 { 375 irc_t *irc = data, *old = NULL; 376 char *to_auth[] = { "TAKEOVER", "AUTH", irc->user->nick, irc->password, NULL }; 377 378 /* Master->New connection */ 379 ipc_to_master_str( "TAKEOVER AUTH %s :%s\r\n", 380 irc->user->nick, irc->password ); 381 382 if( global.conf->runmode == RUNMODE_DAEMON ) 383 { 384 GSList *l; 385 386 for( l = irc_connection_list; l; l = l->next ) 387 { 388 old = l->data; 389 390 if( irc != old && 391 irc->user->nick && old->user->nick && 392 irc->password && old->password && 393 strcmp( irc->user->nick, old->user->nick ) == 0 && 394 strcmp( irc->password, old->password ) == 0 ) 395 break; 396 } 397 if( l == NULL ) 398 { 399 to_auth[1] = "FAIL"; 400 ipc_child_cmd_takeover( irc, to_auth ); 401 return; 402 } 403 } 404 405 /* Drop credentials, we'll shut down soon and shouldn't overwrite 406 any settings. */ 407 irc_usermsg( irc, "Trying to take over existing session" ); 408 409 irc_desync( irc ); 410 411 if( old ) 412 { 413 ipc_child_recv_fd = dup( irc->fd ); 414 ipc_child_cmd_takeover( old, to_auth ); 415 } 416 417 /* TODO: irc_setpass() should do all of this. */ 418 irc_setpass( irc, NULL ); 419 irc->status &= ~USTATUS_IDENTIFIED; 420 irc_umode_set( irc, "-R", 1 ); 421 422 if( old ) 423 { 424 irc->status |= USTATUS_SHUTDOWN; 425 irc_abort( irc, FALSE, NULL ); 426 } 427 } 428 429 static void ipc_child_cmd_takeover_no( void *data ) 430 { 431 ipc_to_master_str( "TAKEOVER NO\r\n" ); 432 cmd_identify_finish( data, 0, 0 ); 191 433 } 192 434 … … 199 441 { "kill", 2, ipc_child_cmd_kill, 0 }, 200 442 { "hello", 0, ipc_child_cmd_hello, 0 }, 443 { "takeover", 1, ipc_child_cmd_takeover, 0 }, 201 444 { NULL } 202 445 }; 203 446 447 gboolean ipc_child_identify( irc_t *irc ) 448 { 449 if( global.conf->runmode == RUNMODE_FORKDAEMON ) 450 { 451 if( !ipc_send_fd( global.listen_socket, irc->fd ) ) 452 ipc_child_disable(); 453 454 ipc_to_master_str( "IDENTIFY %s :%s\r\n", irc->user->nick, irc->password ); 455 456 return TRUE; 457 } 458 else if( global.conf->runmode == RUNMODE_DAEMON ) 459 { 460 GSList *l; 461 irc_t *old; 462 char *to_init[] = { "TAKEOVER", "INIT", NULL }; 463 464 for( l = irc_connection_list; l; l = l->next ) 465 { 466 old = l->data; 467 468 if( irc != old && 469 irc->user->nick && old->user->nick && 470 irc->password && old->password && 471 strcmp( irc->user->nick, old->user->nick ) == 0 && 472 strcmp( irc->password, old->password ) == 0 ) 473 break; 474 } 475 if( l == NULL || 476 !set_getbool( &irc->b->set, "allow_takeover" ) || 477 !set_getbool( &old->b->set, "allow_takeover" ) ) 478 return FALSE; 479 480 ipc_child_cmd_takeover( irc, to_init ); 481 482 return TRUE; 483 } 484 else 485 return FALSE; 486 } 487 488 static void ipc_master_takeover_fail( struct bitlbee_child *child, gboolean both ) 489 { 490 if( child == NULL || g_slist_find( child_list, child ) == NULL ) 491 return; 492 493 if( both && child->to_child != NULL ) 494 ipc_master_takeover_fail( child->to_child, FALSE ); 495 496 if( child->to_fd > -1 ) 497 { 498 /* Send this error only to the new connection, which can be 499 recognised by to_fd being set. */ 500 if( write( child->ipc_fd, "TAKEOVER FAIL\r\n", 15 ) != 15 ) 501 { 502 ipc_master_free_one( child ); 503 return; 504 } 505 close( child->to_fd ); 506 child->to_fd = -1; 507 } 508 child->to_child = NULL; 509 } 204 510 205 511 static void ipc_command_exec( void *data, char **cmd, const command_t *commands ) … … 230 536 /* Return just one line. Returns NULL if something broke, an empty string 231 537 on temporary "errors" (EAGAIN and friends). */ 232 static char *ipc_readline( int fd ) 233 { 538 static char *ipc_readline( int fd, int *recv_fd ) 539 { 540 struct msghdr msg; 541 struct iovec iov; 542 char ccmsg[CMSG_SPACE(sizeof(recv_fd))]; 543 struct cmsghdr *cmsg; 234 544 char buf[513], *eol; 235 545 int size; … … 253 563 size = eol - buf + 2; 254 564 255 if( recv( fd, buf, size, 0 ) != size ) 565 iov.iov_base = buf; 566 iov.iov_len = size; 567 568 memset( &msg, 0, sizeof( msg ) ); 569 msg.msg_iov = &iov; 570 msg.msg_iovlen = 1; 571 msg.msg_control = ccmsg; 572 msg.msg_controllen = sizeof( ccmsg ); 573 574 if( recvmsg( fd, &msg, 0 ) != size ) 256 575 return NULL; 257 else 258 return g_strndup( buf, size - 2 ); 576 577 if( recv_fd ) 578 for( cmsg = CMSG_FIRSTHDR( &msg ); cmsg; cmsg = CMSG_NXTHDR( &msg, cmsg ) ) 579 if( cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS ) 580 { 581 /* Getting more than one shouldn't happen but if it does, 582 make sure we don't leave them around. */ 583 if( *recv_fd != -1 ) 584 close( *recv_fd ); 585 586 *recv_fd = *(int*) CMSG_DATA( cmsg ); 587 /* 588 fprintf( stderr, "pid %d received fd %d\n", (int) getpid(), *recv_fd ); 589 */ 590 } 591 592 /* 593 fprintf( stderr, "pid %d received: %s", (int) getpid(), buf ); 594 */ 595 return g_strndup( buf, size - 2 ); 259 596 } 260 597 261 598 gboolean ipc_master_read( gpointer data, gint source, b_input_condition cond ) 262 599 { 600 struct bitlbee_child *child = data; 263 601 char *buf, **cmd; 264 602 265 if( ( buf = ipc_readline( source ) ) )603 if( ( buf = ipc_readline( source, &child->to_fd ) ) ) 266 604 { 267 605 cmd = irc_parse_line( buf ); 268 606 if( cmd ) 269 607 { 270 ipc_command_exec( data, cmd, ipc_master_commands );608 ipc_command_exec( child, cmd, ipc_master_commands ); 271 609 g_free( cmd ); 272 610 } … … 285 623 char *buf, **cmd; 286 624 287 if( ( buf = ipc_readline( source ) ) )625 if( ( buf = ipc_readline( source, &ipc_child_recv_fd ) ) ) 288 626 { 289 627 cmd = irc_parse_line( buf ); … … 392 730 next = l->next; 393 731 if( write( c->ipc_fd, msg_buf, msg_len ) <= 0 ) 394 {395 732 ipc_master_free_one( c ); 396 child_list = g_slist_remove( child_list, c );397 }398 733 } 399 734 } … … 413 748 } 414 749 750 static gboolean ipc_send_fd( int fd, int send_fd ) 751 { 752 struct msghdr msg; 753 struct iovec iov; 754 char ccmsg[CMSG_SPACE(sizeof(fd))]; 755 struct cmsghdr *cmsg; 756 757 memset( &msg, 0, sizeof( msg ) ); 758 iov.iov_base = "0x90\r\n"; /* Ja, noppes */ 759 iov.iov_len = 6; 760 msg.msg_iov = &iov; 761 msg.msg_iovlen = 1; 762 763 msg.msg_control = ccmsg; 764 msg.msg_controllen = sizeof( ccmsg ); 765 cmsg = CMSG_FIRSTHDR( &msg ); 766 cmsg->cmsg_level = SOL_SOCKET; 767 cmsg->cmsg_type = SCM_RIGHTS; 768 cmsg->cmsg_len = CMSG_LEN( sizeof( send_fd ) ); 769 *(int*)CMSG_DATA( cmsg ) = send_fd; 770 msg.msg_controllen = cmsg->cmsg_len; 771 772 return sendmsg( fd, &msg, 0 ) == 6; 773 } 774 415 775 void ipc_master_free_one( struct bitlbee_child *c ) 416 776 { 777 GSList *l; 778 417 779 b_event_remove( c->ipc_inpa ); 418 780 closesocket( c->ipc_fd ); 781 782 if( c->to_fd != -1 ) 783 close( c->to_fd ); 419 784 420 785 g_free( c->host ); 421 786 g_free( c->nick ); 422 787 g_free( c->realname ); 788 g_free( c->password ); 423 789 g_free( c ); 790 791 child_list = g_slist_remove( child_list, c ); 792 793 /* Also, if any child has a reference to this one, remove it. */ 794 for( l = child_list; l; l = l->next ) 795 { 796 struct bitlbee_child *oc = l->data; 797 798 if( oc->to_child == c ) 799 ipc_master_takeover_fail( oc, FALSE ); 800 } 424 801 } 425 802 … … 435 812 { 436 813 ipc_master_free_one( c ); 437 child_list = g_slist_remove( child_list, c );438 814 break; 439 815 } … … 443 819 void ipc_master_free_all() 444 820 { 445 GSList *l; 446 447 for( l = child_list; l; l = l->next ) 448 ipc_master_free_one( l->data ); 449 450 g_slist_free( child_list ); 451 child_list = NULL; 821 while( child_list ) 822 ipc_master_free_one( child_list->data ); 452 823 } 453 824 … … 506 877 struct bitlbee_child *child = g_new0( struct bitlbee_child, 1 ); 507 878 879 child->to_fd = -1; 508 880 child->ipc_fd = accept( serversock, NULL, 0 ); 509 510 881 if( child->ipc_fd == -1 ) 511 882 { … … 514 885 } 515 886 516 child->ipc_inpa = b_input_add( child->ipc_fd, GAIM_INPUT_READ, ipc_master_read, child );517 518 child_list = g_slist_ append( child_list, child );887 child->ipc_inpa = b_input_add( child->ipc_fd, B_EV_IO_READ, ipc_master_read, child ); 888 889 child_list = g_slist_prepend( child_list, child ); 519 890 520 891 return TRUE; … … 552 923 } 553 924 554 b_input_add( serversock, GAIM_INPUT_READ, new_ipc_client, NULL );925 b_input_add( serversock, B_EV_IO_READ, new_ipc_client, NULL ); 555 926 556 927 return 1; … … 597 968 return 0; 598 969 } 599 child->ipc_inpa = b_input_add( child->ipc_fd, GAIM_INPUT_READ, ipc_master_read, child ); 600 601 child_list = g_slist_append( child_list, child ); 970 child->ipc_inpa = b_input_add( child->ipc_fd, B_EV_IO_READ, ipc_master_read, child ); 971 child->to_fd = -1; 972 973 child_list = g_slist_prepend( child_list, child ); 602 974 } 603 975 -
ipc.h
ref14a83 r2945c6f 2 2 * BitlBee -- An IRC to other IM-networks gateway * 3 3 * * 4 * Copyright 2002-20 04Wilmer van der Gaast and others *4 * Copyright 2002-2010 Wilmer van der Gaast and others * 5 5 \********************************************************************/ 6 6 … … 37 37 char *nick; 38 38 char *realname; 39 40 char *password; 41 42 /* For takeovers: */ 43 struct bitlbee_child *to_child; 44 int to_fd; 39 45 }; 40 46 … … 48 54 49 55 void ipc_child_disable(); 56 57 gboolean ipc_child_identify( irc_t *irc ); 50 58 51 59 void ipc_to_master( char **cmd ); -
irc.c
ref14a83 r2945c6f 5 5 \********************************************************************/ 6 6 7 /* The big hairy IRCd part of the project*/7 /* The IRC-based UI (for now the only one) */ 8 8 9 9 /* … … 24 24 */ 25 25 26 #define BITLBEE_CORE27 26 #include "bitlbee.h" 28 #include "sock.h"29 #include "crypting.h"30 27 #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 30 GSList *irc_connection_list; 31 32 static gboolean irc_userping( gpointer _irc, gint fd, b_input_condition cond ); 33 static char *set_eval_charset( set_t *set, char *value ); 34 static char *set_eval_password( set_t *set, char *value ); 35 static char *set_eval_bw_compat( set_t *set, char *value ); 114 36 115 37 irc_t *irc_new( int fd ) … … 118 40 struct sockaddr_storage sock; 119 41 socklen_t socklen = sizeof( sock ); 42 char *host = NULL, *myhost = NULL; 43 irc_user_t *iu; 120 44 set_t *s; 45 bee_t *b; 121 46 122 47 irc = g_new0( irc_t, 1 ); … … 125 50 sock_make_nonblocking( irc->fd ); 126 51 127 irc->r_watch_source_id = b_input_add( irc->fd, GAIM_INPUT_READ, bitlbee_io_current_client_read, irc );52 irc->r_watch_source_id = b_input_add( irc->fd, B_EV_IO_READ, bitlbee_io_current_client_read, irc ); 128 53 129 54 irc->status = USTATUS_OFFLINE; 130 55 irc->last_pong = gettime(); 131 56 132 irc-> userhash = g_hash_table_new( g_str_hash, g_str_equal );57 irc->nick_user_hash = g_hash_table_new( g_str_hash, g_str_equal ); 133 58 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 );138 59 139 60 irc->iconv = (GIConv) -1; … … 142 63 if( global.conf->hostname ) 143 64 { 144 irc->myhost = g_strdup( global.conf->hostname );65 myhost = g_strdup( global.conf->hostname ); 145 66 } 146 67 else if( getsockname( irc->fd, (struct sockaddr*) &sock, &socklen ) == 0 ) … … 151 72 NI_MAXHOST, NULL, 0, 0 ) == 0 ) 152 73 { 153 irc->myhost = g_strdup( ipv6_unwrap( buf ) );74 myhost = g_strdup( ipv6_unwrap( buf ) ); 154 75 } 155 76 } … … 162 83 NI_MAXHOST, NULL, 0, 0 ) == 0 ) 163 84 { 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" );85 host = g_strdup( ipv6_unwrap( buf ) ); 86 } 87 } 88 89 if( host == NULL ) 90 host = g_strdup( "localhost.localdomain" ); 91 if( myhost == NULL ) 92 myhost = g_strdup( "localhost.localdomain" ); 172 93 173 94 if( global.conf->ping_interval > 0 && global.conf->ping_timeout > 0 ) 174 95 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" );177 96 178 97 irc_connection_list = g_slist_append( irc_connection_list, irc ); 179 98 180 s = set_add( &irc->set, "away", NULL, set_eval_away_status, irc ); 99 b = irc->b = bee_new(); 100 b->ui_data = irc; 101 b->ui = &irc_ui_funcs; 102 103 s = set_add( &b->set, "allow_takeover", "true", set_eval_bool, irc ); 104 s = set_add( &b->set, "away_devoice", "true", set_eval_bw_compat, irc ); 105 s = set_add( &b->set, "away_reply_timeout", "3600", set_eval_int, irc ); 106 s = set_add( &b->set, "charset", "utf-8", set_eval_charset, irc ); 107 s = set_add( &b->set, "default_target", "root", NULL, irc ); 108 s = set_add( &b->set, "display_namechanges", "false", set_eval_bool, irc ); 109 s = set_add( &b->set, "display_timestamps", "true", set_eval_bool, irc ); 110 s = set_add( &b->set, "handle_unknown", "add_channel", NULL, irc ); 111 s = set_add( &b->set, "lcnicks", "true", set_eval_bool, irc ); 112 s = set_add( &b->set, "nick_format", "%-@nick", NULL, irc ); 113 s = set_add( &b->set, "offline_user_quits", "true", set_eval_bool, irc ); 114 s = set_add( &b->set, "ops", "both", set_eval_irc_channel_ops, irc ); 115 s = set_add( &b->set, "paste_buffer", "false", set_eval_bool, irc ); 116 s->old_key = g_strdup( "buddy_sendbuffer" ); 117 s = set_add( &b->set, "paste_buffer_delay", "200", set_eval_int, irc ); 118 s->old_key = g_strdup( "buddy_sendbuffer_delay" ); 119 s = set_add( &b->set, "password", NULL, set_eval_password, irc ); 181 120 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 ); 121 s = set_add( &b->set, "private", "true", set_eval_bool, irc ); 122 s = set_add( &b->set, "query_order", "lifo", NULL, irc ); 123 s = set_add( &b->set, "root_nick", ROOT_NICK, set_eval_root_nick, irc ); 124 s = set_add( &b->set, "show_offline", "false", set_eval_bw_compat, irc ); 125 s = set_add( &b->set, "simulate_netsplit", "true", set_eval_bool, irc ); 126 s = set_add( &b->set, "timezone", "local", set_eval_timezone, irc ); 127 s = set_add( &b->set, "to_char", ": ", set_eval_to_char, irc ); 128 s = set_add( &b->set, "typing_notice", "false", set_eval_bool, irc ); 129 130 irc->root = iu = irc_user_new( irc, ROOT_NICK ); 131 iu->host = g_strdup( myhost ); 132 iu->fullname = g_strdup( ROOT_FN ); 133 iu->f = &irc_user_root_funcs; 134 135 iu = irc_user_new( irc, NS_NICK ); 136 iu->host = g_strdup( myhost ); 137 iu->fullname = g_strdup( ROOT_FN ); 138 iu->f = &irc_user_root_funcs; 139 140 irc->user = g_new0( irc_user_t, 1 ); 141 irc->user->host = g_strdup( host ); 211 142 212 143 conf_loaddefaults( irc ); 213 144 214 145 /* Evaluator sets the iconv/oconv structures. */ 215 set_eval_charset( set_find( &irc->set, "charset" ), set_getstr( &irc->set, "charset" ) ); 216 217 return( irc ); 146 set_eval_charset( set_find( &b->set, "charset" ), set_getstr( &b->set, "charset" ) ); 147 148 irc_write( irc, ":%s NOTICE AUTH :%s", irc->root->host, "BitlBee-IRCd initialized, please go on" ); 149 150 g_free( myhost ); 151 g_free( host ); 152 153 nogaim_init(); 154 155 return irc; 218 156 } 219 157 … … 236 174 237 175 ipc_to_master_str( "OPERMSG :Client exiting: %s@%s [%s]\r\n", 238 irc-> nick ? irc->nick : "(NONE)", irc->host, reason );176 irc->user->nick ? irc->user->nick : "(NONE)", irc->user->host, reason ); 239 177 240 178 g_free( reason ); … … 246 184 247 185 ipc_to_master_str( "OPERMSG :Client exiting: %s@%s [%s]\r\n", 248 irc-> nick ? irc->nick : "(NONE)", irc->host, "No reason given" );186 irc->user->nick ? irc->user->nick : "(NONE)", irc->user->host, "No reason given" ); 249 187 } 250 188 … … 267 205 } 268 206 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 */ 207 static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data ); 208 277 209 void irc_free( irc_t * irc ) 278 210 { 279 user_t *user, *usertmp;280 281 211 log_message( LOGLVL_INFO, "Destroying connection with fd %d", irc->fd ); 282 212 283 if( irc->status & USTATUS_IDENTIFIED && set_getbool( &irc-> set, "save_on_quit" ) )213 if( irc->status & USTATUS_IDENTIFIED && set_getbool( &irc->b->set, "save_on_quit" ) ) 284 214 if( storage_save( irc, NULL, TRUE ) != STORAGE_OK ) 285 irc_usermsg( irc, "Error while saving settings!");215 log_message( LOGLVL_WARNING, "Error while saving settings for user %s", irc->user->nick ); 286 216 287 217 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 else299 /* Nasty hack, but account_del() doesn't work in this300 case and we don't want infinite loops, do we? ;-) */301 irc->accounts = irc->accounts->next;302 }303 218 304 219 while( irc->queries != NULL ) 305 220 query_del( irc, irc->queries ); 306 221 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 } 222 /* This is a little bit messy: bee_free() frees all b->users which 223 calls us back to free the corresponding irc->users. So do this 224 before we clear the remaining ones ourselves. */ 225 bee_free( irc->b ); 226 227 while( irc->users ) 228 irc_user_free( irc, (irc_user_t *) irc->users->data ); 229 230 while( irc->channels ) 231 irc_channel_free( irc->channels->data ); 328 232 329 233 if( irc->ping_source_id > 0 ) … … 337 241 irc->fd = -1; 338 242 339 g_hash_table_foreach_remove( irc-> userhash, irc_free_hashkey, NULL );340 g_hash_table_destroy( irc-> userhash );243 g_hash_table_foreach_remove( irc->nick_user_hash, irc_free_hashkey, NULL ); 244 g_hash_table_destroy( irc->nick_user_hash ); 341 245 342 246 g_hash_table_foreach_remove( irc->watches, irc_free_hashkey, NULL ); … … 350 254 g_free( irc->sendbuffer ); 351 255 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 );357 256 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 ); 257 g_free( irc->last_root_cmd ); 365 258 366 259 g_free( irc ); … … 374 267 } 375 268 269 static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data ) 270 { 271 g_free( key ); 272 273 return( TRUE ); 274 } 275 376 276 /* USE WITH CAUTION! 377 277 Sets pass without checking */ 378 void irc_setpass (irc_t *irc, const char *pass) 278 void irc_setpass (irc_t *irc, const char *pass) 379 279 { 380 280 g_free (irc->password); … … 387 287 } 388 288 289 static char *set_eval_password( set_t *set, char *value ) 290 { 291 irc_t *irc = set->data; 292 293 if( irc->status & USTATUS_IDENTIFIED && value ) 294 { 295 irc_setpass( irc, value ); 296 return NULL; 297 } 298 else 299 { 300 return SET_INVALID; 301 } 302 } 303 304 static char **irc_splitlines( char *buffer ); 305 389 306 void irc_process( irc_t *irc ) 390 307 { … … 394 311 if( irc->readbuffer != NULL ) 395 312 { 396 lines = irc_ tokenize( irc->readbuffer );313 lines = irc_splitlines( irc->readbuffer ); 397 314 398 315 for( i = 0; *lines[i] != '\0'; i ++ ) … … 431 348 "`help set charset' for more information. Your " 432 349 "message was ignored.", 433 set_getstr( &irc-> set, "charset" ) );350 set_getstr( &irc->b->set, "charset" ) ); 434 351 435 352 g_free( conv ); … … 438 355 else 439 356 { 440 irc_write( irc, ":%s NOTICE AUTH :%s", irc-> myhost,357 irc_write( irc, ":%s NOTICE AUTH :%s", irc->root->host, 441 358 "Warning: invalid characters received at login time." ); 442 359 … … 476 393 } 477 394 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 ) 395 /* Splits a long string into separate lines. The array is NULL-terminated 396 and, unless the string contains an incomplete line at the end, ends with 397 an empty string. Could use g_strsplit() but this one does it in-place. 398 (So yes, it's destructive.) */ 399 static char **irc_splitlines( char *buffer ) 481 400 { 482 401 int i, j, n = 3; … … 609 528 } 610 529 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 641 530 void irc_write( irc_t *irc, char *format, ... ) 642 531 { … … 649 538 return; 650 539 } 540 541 void irc_write_all( int now, char *format, ... ) 542 { 543 va_list params; 544 GSList *temp; 545 546 va_start( params, format ); 547 548 temp = irc_connection_list; 549 while( temp != NULL ) 550 { 551 irc_t *irc = temp->data; 552 553 if( now ) 554 { 555 g_free( irc->sendbuffer ); 556 irc->sendbuffer = g_strdup( "\r\n" ); 557 } 558 irc_vawrite( temp->data, format, params ); 559 if( now ) 560 { 561 bitlbee_io_current_client_write( irc, irc->fd, B_EV_IO_WRITE ); 562 } 563 temp = temp->next; 564 } 565 566 va_end( params ); 567 return; 568 } 651 569 652 570 void irc_vawrite( irc_t *irc, char *format, va_list params ) … … 696 614 in the event queue. */ 697 615 /* 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 ) ) */616 if( bitlbee_io_current_client_write( irc, irc->fd, B_EV_IO_WRITE ) ) */ 699 617 700 618 /* 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 );619 irc->w_watch_source_id = b_input_add( irc->fd, B_EV_IO_WRITE, bitlbee_io_current_client_write, irc ); 702 620 } 703 621 … … 705 623 } 706 624 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 ) 625 /* Flush sendbuffer if you can. If it fails, fail silently and let some 626 I/O event handler clean up. */ 627 void irc_flush( irc_t *irc ) 628 { 629 ssize_t n; 630 size_t len; 631 632 if( irc->sendbuffer == NULL ) 633 return; 634 635 len = strlen( irc->sendbuffer ); 636 if( ( n = send( irc->fd, irc->sendbuffer, len, 0 ) ) == len ) 637 { 638 g_free( irc->sendbuffer ); 639 irc->sendbuffer = NULL; 640 641 b_event_remove( irc->w_watch_source_id ); 642 irc->w_watch_source_id = 0; 643 } 644 else if( n > 0 ) 645 { 646 char *s = g_strdup( irc->sendbuffer + n ); 647 g_free( irc->sendbuffer ); 648 irc->sendbuffer = s; 649 } 650 /* Otherwise something went wrong and we don't currently care 651 what the error was. We may or may not succeed later, we 652 were just trying to flush the buffer immediately. */ 653 } 654 655 /* Meant for takeover functionality. Transfer an IRC connection to a different 656 socket. */ 657 void irc_switch_fd( irc_t *irc, int fd ) 658 { 659 irc_write( irc, "ERROR :Transferring session to a new connection" ); 660 irc_flush( irc ); /* Write it now or forget about it forever. */ 661 662 if( irc->sendbuffer ) 663 { 664 b_event_remove( irc->w_watch_source_id ); 665 irc->w_watch_source_id = 0; 666 g_free( irc->sendbuffer ); 667 irc->sendbuffer = NULL; 668 } 669 670 b_event_remove( irc->r_watch_source_id ); 671 closesocket( irc->fd ); 672 irc->fd = fd; 673 irc->r_watch_source_id = b_input_add( irc->fd, B_EV_IO_READ, bitlbee_io_current_client_read, irc ); 674 } 675 676 void irc_sync( irc_t *irc ) 677 { 678 GSList *l; 679 680 irc_write( irc, ":%s!%s@%s MODE %s :+%s", irc->user->nick, 681 irc->user->user, irc->user->host, irc->user->nick, 682 irc->umode ); 683 684 for( l = irc->channels; l; l = l->next ) 685 { 686 irc_channel_t *ic = l->data; 687 if( ic->flags & IRC_CHANNEL_JOINED ) 688 irc_send_join( ic, irc->user ); 689 } 690 } 691 692 void irc_desync( irc_t *irc ) 693 { 694 GSList *l; 695 696 for( l = irc->channels; l; l = l->next ) 697 irc_channel_del_user( l->data, irc->user, IRC_CDU_KICK, 698 "Switching to old session" ); 699 700 irc_write( irc, ":%s!%s@%s MODE %s :-%s", irc->user->nick, 701 irc->user->user, irc->user->host, irc->user->nick, 702 irc->umode ); 703 } 704 705 int irc_check_login( irc_t *irc ) 706 { 707 if( irc->user->user && irc->user->nick ) 708 { 709 if( global.conf->authmode == AUTHMODE_CLOSED && !( irc->status & USTATUS_AUTHORIZED ) ) 710 { 711 irc_send_num( irc, 464, ":This server is password-protected." ); 712 return 0; 713 } 714 else 715 { 716 irc_channel_t *ic; 717 irc_user_t *iu = irc->user; 718 719 irc->user = irc_user_new( irc, iu->nick ); 720 irc->user->user = iu->user; 721 irc->user->host = iu->host; 722 irc->user->fullname = iu->fullname; 723 irc->user->f = &irc_user_self_funcs; 724 g_free( iu->nick ); 725 g_free( iu ); 726 727 if( global.conf->runmode == RUNMODE_FORKDAEMON || global.conf->runmode == RUNMODE_DAEMON ) 728 ipc_to_master_str( "CLIENT %s %s :%s\r\n", irc->user->host, irc->user->nick, irc->user->fullname ); 729 730 irc->status |= USTATUS_LOGGED_IN; 731 732 irc_send_login( irc ); 733 734 irc->umode[0] = '\0'; 735 irc_umode_set( irc, "+" UMODE, TRUE ); 736 737 ic = irc->default_channel = irc_channel_new( irc, ROOT_CHAN ); 738 irc_channel_set_topic( ic, CONTROL_TOPIC, irc->root ); 739 set_setstr( &ic->set, "auto_join", "true" ); 740 irc_channel_auto_joins( irc, NULL ); 741 742 irc->last_root_cmd = g_strdup( ROOT_CHAN ); 743 744 irc_send_msg( irc->root, "PRIVMSG", ROOT_CHAN, 745 "Welcome to the BitlBee gateway!\n\n" 746 "If you've never used BitlBee before, please do read the help " 747 "information using the \x02help\x02 command. Lots of FAQs are " 748 "answered there.\n" 749 "If you already have an account on this server, just use the " 750 "\x02identify\x02 command to identify yourself.", NULL ); 751 752 /* This is for bug #209 (use PASS to identify to NickServ). */ 753 if( irc->password != NULL ) 751 754 { 752 irc_reply( irc, 353, "= %s :%s", channel, namelist ); 753 *namelist = 0; 755 char *send_cmd[] = { "identify", g_strdup( irc->password ), NULL }; 756 757 irc_setpass( irc, NULL ); 758 root_command( irc, send_cmd ); 759 g_free( send_cmd[1] ); 754 760 } 755 761 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 should771 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 else804 {805 irc_login( irc );806 762 return 1; 807 763 } … … 814 770 } 815 771 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 ) 772 void irc_umode_set( irc_t *irc, const char *s, gboolean allow_priv ) 941 773 { 942 774 /* allow_priv: Set to 0 if s contains user input, 1 if you want 943 775 to set a "privileged" mode (+o, +R, etc). */ 944 char m[256], st = 1, *t; 776 char m[128], st = 1; 777 const char *t; 945 778 int i; 946 779 char changes[512], *p, st2 = 2; … … 950 783 951 784 for( t = irc->umode; *t; t ++ ) 952 m[(int)*t] = 1; 953 785 if( *t < sizeof( m ) ) 786 m[(int)*t] = 1; 787 954 788 p = changes; 955 789 for( t = s; *t; t ++ ) … … 957 791 if( *t == '+' || *t == '-' ) 958 792 st = *t == '+'; 959 else if( st == 0 || ( strchr( UMODES, *t ) || ( allow_priv && strchr( UMODES_PRIV, *t ) ) ) ) 793 else if( ( st == 0 && ( !strchr( UMODES_KEEP, *t ) || allow_priv ) ) || 794 ( st == 1 && strchr( UMODES, *t ) ) || 795 ( st == 1 && allow_priv && strchr( UMODES_PRIV, *t ) ) ) 960 796 { 961 797 if( m[(int)*t] != st) … … 974 810 memset( irc->umode, 0, sizeof( irc->umode ) ); 975 811 976 for( i = 0; i < 256&& strlen( irc->umode ) < ( sizeof( irc->umode ) - 1 ); i ++ )812 for( i = 'A'; i <= 'z' && strlen( irc->umode ) < ( sizeof( irc->umode ) - 1 ); i ++ ) 977 813 if( m[i] ) 978 814 irc->umode[strlen(irc->umode)] = i; 979 815 980 816 if( badflag ) 981 irc_reply( irc, 501, ":Unknown MODE flag" ); 982 /* Deliberately no !user@host on the prefix here */ 817 irc_send_num( irc, 501, ":Unknown MODE flag" ); 983 818 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 ); 819 irc_write( irc, ":%s!%s@%s MODE %s :%s", irc->user->nick, 820 irc->user->user, irc->user->host, irc->user->nick, 821 changes ); 1298 822 } 1299 823 … … 1334 858 } 1335 859 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 } 860 static char *set_eval_charset( set_t *set, char *value ) 861 { 862 irc_t *irc = (irc_t*) set->data; 863 char *test; 864 gsize test_bytes = 0; 865 GIConv ic, oc; 866 867 if( g_strcasecmp( value, "none" ) == 0 ) 868 value = g_strdup( "utf-8" ); 869 870 if( ( oc = g_iconv_open( value, "utf-8" ) ) == (GIConv) -1 ) 871 { 872 return NULL; 873 } 874 875 /* Do a test iconv to see if the user picked an IRC-compatible 876 charset (for example utf-16 goes *horribly* wrong). */ 877 if( ( test = g_convert_with_iconv( " ", 1, oc, NULL, &test_bytes, NULL ) ) == NULL || 878 test_bytes > 1 ) 879 { 880 g_free( test ); 881 g_iconv_close( oc ); 882 irc_usermsg( irc, "Unsupported character set: The IRC protocol " 883 "only supports 8-bit character sets." ); 884 return NULL; 885 } 886 g_free( test ); 887 888 if( ( ic = g_iconv_open( "utf-8", value ) ) == (GIConv) -1 ) 889 { 890 g_iconv_close( oc ); 891 return NULL; 892 } 893 894 if( irc->iconv != (GIConv) -1 ) 895 g_iconv_close( irc->iconv ); 896 if( irc->oconv != (GIConv) -1 ) 897 g_iconv_close( irc->oconv ); 898 899 irc->iconv = ic; 900 irc->oconv = oc; 901 902 return value; 903 } 904 905 /* Mostly meant for upgrades. If one of these is set to the non-default, 906 set show_users of all channels to something with the same effect. */ 907 static char *set_eval_bw_compat( set_t *set, char *value ) 908 { 909 irc_t *irc = set->data; 910 char *val; 911 GSList *l; 912 913 irc_usermsg( irc, "Setting `%s' is obsolete, use the `show_users' " 914 "channel setting instead.", set->key ); 915 916 if( strcmp( set->key, "away_devoice" ) == 0 && !bool2int( value ) ) 917 val = "online,away"; 918 else if( strcmp( set->key, "show_offline" ) == 0 && bool2int( value ) ) 919 val = "online@,away+,offline"; 920 else 921 return SET_INVALID; 922 923 for( l = irc->channels; l; l = l->next ) 924 { 925 irc_channel_t *ic = l->data; 926 /* No need to check channel type, if the setting doesn't exist it 927 will just be ignored. */ 928 set_setstr( &ic->set, "show_users", val ); 929 } 930 931 return SET_INVALID; 932 } -
irc.h
ref14a83 r2945c6f 5 5 \********************************************************************/ 6 6 7 /* The big hairy IRCd part of the project*/7 /* The IRC-based UI (for now the only one) */ 8 8 9 9 /* … … 33 33 #define IRC_PING_STRING "PinglBee" 34 34 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 */ 41 43 42 44 typedef enum … … 48 50 USTATUS_SHUTDOWN = 8 49 51 } irc_status_t; 52 53 struct irc_user; 50 54 51 55 typedef struct irc … … 59 63 GIConv iconv, oconv; 60 64 61 int sentbytes; 62 time_t oldtime; 63 65 struct irc_user *root; 66 struct irc_user *user; 67 68 char *last_root_cmd; /* Either the nickname from which the last root 69 msg came, or the last channel root was talked 70 to. */ 71 72 char *password; /* HACK: Used to save the user's password, but before 73 logging in, this may contain a password we should 74 send to identify after USER/NICK are received. */ 75 76 char umode[8]; 77 78 struct query *queries; 79 GSList *file_transfers; 80 81 GSList *users, *channels; 82 struct irc_channel *default_channel; 83 GHashTable *nick_user_hash; 84 GHashTable *watches; /* See irc_cmd_watch() */ 85 86 gint r_watch_source_id; 87 gint w_watch_source_id; 88 gint ping_source_id; 89 gint login_source_id; /* To slightly delay some events at login time. */ 90 91 struct bee *b; 92 } irc_t; 93 94 typedef enum 95 { 96 /* Replaced with iu->last_channel IRC_USER_PRIVATE = 1, */ 97 IRC_USER_AWAY = 2, 98 } irc_user_flags_t; 99 100 typedef struct irc_user 101 { 102 irc_t *irc; 103 64 104 char *nick; 65 105 char *user; 66 106 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; 107 char *fullname; 108 109 /* Nickname in lowercase for case sensitive searches */ 110 char *key; 111 112 irc_user_flags_t flags; 113 struct irc_channel *last_channel; 114 115 GString *pastebuf; /* Paste buffer (combine lines into a multiline msg). */ 116 guint pastebuf_timer; 117 time_t away_reply_timeout; /* Only send a 301 if this time passed. */ 118 119 struct bee_user *bu; 120 121 const struct irc_user_funcs *f; 122 } irc_user_t; 123 124 struct irc_user_funcs 125 { 126 gboolean (*privmsg)( irc_user_t *iu, const char *msg ); 127 gboolean (*ctcp)( irc_user_t *iu, char * const* ctcp ); 128 }; 129 130 extern const struct irc_user_funcs irc_user_root_funcs; 131 extern const struct irc_user_funcs irc_user_self_funcs; 132 133 typedef enum 134 { 135 IRC_CHANNEL_JOINED = 1, /* The user is currently in the channel. */ 136 IRC_CHANNEL_TEMP = 2, /* Erase the channel when the user leaves, 137 and don't save it. */ 138 139 /* Hack: Set this flag right before jumping into IM when we expect 140 a call to imcb_chat_new(). */ 141 IRC_CHANNEL_CHAT_PICKME = 0x10000, 142 } irc_channel_flags_t; 143 144 typedef struct irc_channel 145 { 146 irc_t *irc; 147 char *name; 148 char mode[8]; 149 int flags; 150 151 char *topic; 152 char *topic_who; 153 time_t topic_time; 154 155 GSList *users; /* struct irc_channel_user */ 91 156 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 157 158 GString *pastebuf; /* Paste buffer (combine lines into a multiline msg). */ 159 guint pastebuf_timer; 160 161 const struct irc_channel_funcs *f; 162 void *data; 163 } irc_channel_t; 164 165 struct irc_channel_funcs 166 { 167 gboolean (*privmsg)( irc_channel_t *ic, const char *msg ); 168 gboolean (*join)( irc_channel_t *ic ); 169 gboolean (*part)( irc_channel_t *ic, const char *msg ); 170 gboolean (*topic)( irc_channel_t *ic, const char *new ); 171 gboolean (*invite)( irc_channel_t *ic, irc_user_t *iu ); 172 173 gboolean (*_init)( irc_channel_t *ic ); 174 gboolean (*_free)( irc_channel_t *ic ); 175 }; 176 177 typedef enum 178 { 179 IRC_CHANNEL_USER_OP = 1, 180 IRC_CHANNEL_USER_HALFOP = 2, 181 IRC_CHANNEL_USER_VOICE = 4, 182 IRC_CHANNEL_USER_NONE = 8, 183 } irc_channel_user_flags_t; 184 185 typedef struct irc_channel_user 186 { 187 irc_user_t *iu; 188 int flags; 189 } irc_channel_user_t; 190 191 typedef enum 192 { 193 IRC_CC_TYPE_DEFAULT, 194 IRC_CC_TYPE_REST, 195 IRC_CC_TYPE_GROUP, 196 IRC_CC_TYPE_ACCOUNT, 197 IRC_CC_TYPE_PROTOCOL, 198 } irc_control_channel_type_t; 199 200 struct irc_control_channel 201 { 202 irc_control_channel_type_t type; 203 struct bee_group *group; 204 struct account *account; 205 struct prpl *protocol; 206 char modes[4]; 207 }; 208 209 extern const struct bee_ui_funcs irc_ui_funcs; 210 211 typedef enum 212 { 213 IRC_CDU_SILENT, 214 IRC_CDU_PART, 215 IRC_CDU_KICK, 216 } irc_channel_del_user_type_t; 217 218 /* irc.c */ 100 219 extern GSList *irc_connection_list; 101 220 … … 103 222 void irc_abort( irc_t *irc, int immed, char *format, ... ) G_GNUC_PRINTF( 3, 4 ); 104 223 void irc_free( irc_t *irc ); 105 106 void irc_exec( irc_t *irc, char **cmd ); 224 void irc_setpass (irc_t *irc, const char *pass); 225 107 226 void irc_process( irc_t *irc ); 108 227 char **irc_parse_line( char *line ); 109 228 char *irc_build_line( char **cmd ); 110 229 111 void irc_vawrite( irc_t *irc, char *format, va_list params );112 230 void irc_write( irc_t *irc, char *format, ... ) G_GNUC_PRINTF( 2, 3 ); 113 231 void 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 ); 232 void irc_vawrite( irc_t *irc, char *format, va_list params ); 233 234 void irc_flush( irc_t *irc ); 235 void irc_switch_fd( irc_t *irc, int fd ); 236 void irc_sync( irc_t *irc ); 237 void irc_desync( irc_t *irc ); 238 119 239 int 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 ); 240 241 void irc_umode_set( irc_t *irc, const char *s, gboolean allow_priv ); 242 243 /* irc_channel.c */ 244 irc_channel_t *irc_channel_new( irc_t *irc, const char *name ); 245 irc_channel_t *irc_channel_by_name( irc_t *irc, const char *name ); 246 irc_channel_t *irc_channel_get( irc_t *irc, char *id ); 247 int irc_channel_free( irc_channel_t *ic ); 248 void irc_channel_free_soon( irc_channel_t *ic ); 249 int irc_channel_add_user( irc_channel_t *ic, irc_user_t *iu ); 250 int irc_channel_del_user( irc_channel_t *ic, irc_user_t *iu, irc_channel_del_user_type_t type, const char *msg ); 251 irc_channel_user_t *irc_channel_has_user( irc_channel_t *ic, irc_user_t *iu ); 252 int irc_channel_set_topic( irc_channel_t *ic, const char *topic, const irc_user_t *who ); 253 void irc_channel_user_set_mode( irc_channel_t *ic, irc_user_t *iu, irc_channel_user_flags_t flags ); 254 void irc_channel_auto_joins( irc_t *irc, struct account *acc ); 255 void irc_channel_printf( irc_channel_t *ic, char *format, ... ); 256 gboolean irc_channel_name_ok( const char *name ); 257 void irc_channel_name_strip( char *name ); 258 int irc_channel_name_cmp( const char *a_, const char *b_ ); 259 void irc_channel_update_ops( irc_channel_t *ic, char *value ); 260 char *set_eval_irc_channel_ops( struct set *set, char *value ); 261 262 /* irc_commands.c */ 263 void irc_exec( irc_t *irc, char **cmd ); 264 265 /* irc_send.c */ 266 void irc_send_num( irc_t *irc, int code, char *format, ... ) G_GNUC_PRINTF( 3, 4 ); 267 void irc_send_login( irc_t *irc ); 268 void irc_send_motd( irc_t *irc ); 269 void irc_usermsg( irc_t *irc, char *format, ... ); 270 void irc_send_join( irc_channel_t *ic, irc_user_t *iu ); 271 void irc_send_part( irc_channel_t *ic, irc_user_t *iu, const char *reason ); 272 void irc_send_quit( irc_user_t *iu, const char *reason ); 273 void irc_send_kick( irc_channel_t *ic, irc_user_t *iu, irc_user_t *kicker, const char *reason ); 274 void irc_send_names( irc_channel_t *ic ); 275 void irc_send_topic( irc_channel_t *ic, gboolean topic_change ); 276 void irc_send_whois( irc_user_t *iu ); 277 void irc_send_who( irc_t *irc, GSList *l, const char *channel ); 278 void irc_send_msg( irc_user_t *iu, const char *type, const char *dst, const char *msg, const char *prefix ); 279 void irc_send_msg_raw( irc_user_t *iu, const char *type, const char *dst, const char *msg ); 280 void irc_send_msg_f( irc_user_t *iu, const char *type, const char *dst, const char *format, ... ) G_GNUC_PRINTF( 4, 5 ); 281 void irc_send_nick( irc_user_t *iu, const char *new ); 282 void irc_send_channel_user_mode_diff( irc_channel_t *ic, irc_user_t *iu, 283 irc_channel_user_flags_t old, irc_channel_user_flags_t new ); 284 285 /* irc_user.c */ 286 irc_user_t *irc_user_new( irc_t *irc, const char *nick ); 287 int irc_user_free( irc_t *irc, irc_user_t *iu ); 288 irc_user_t *irc_user_by_name( irc_t *irc, const char *nick ); 289 int irc_user_set_nick( irc_user_t *iu, const char *new ); 290 gint irc_user_cmp( gconstpointer a_, gconstpointer b_ ); 291 const char *irc_user_get_away( irc_user_t *iu ); 292 void irc_user_quit( irc_user_t *iu, const char *msg ); 293 294 /* irc_util.c */ 295 char *set_eval_timezone( struct set *set, char *value ); 296 char *irc_format_timestamp( irc_t *irc, time_t msg_ts ); 297 298 /* irc_im.c */ 299 void bee_irc_channel_update( irc_t *irc, irc_channel_t *ic, irc_user_t *iu ); 141 300 142 301 #endif -
irc_commands.c
ref14a83 r2945c6f 2 2 * BitlBee -- An IRC to other IM-networks gateway * 3 3 * * 4 * Copyright 2002-20 06Wilmer van der Gaast and others *4 * Copyright 2002-2010 Wilmer van der Gaast and others * 5 5 \********************************************************************/ 6 6 … … 27 27 #include "bitlbee.h" 28 28 #include "ipc.h" 29 #include "chat.h"30 29 31 30 static void irc_cmd_pass( irc_t *irc, char **cmd ) … … 53 52 else if( global.conf->auth_pass ) 54 53 { 55 irc_ reply( irc, 464, ":Incorrect password" );54 irc_send_num( irc, 464, ":Incorrect password" ); 56 55 } 57 56 else … … 65 64 static void irc_cmd_user( irc_t *irc, char **cmd ) 66 65 { 67 irc->user = g_strdup( cmd[1] );68 irc-> realname = g_strdup( cmd[4] );66 irc->user->user = g_strdup( cmd[1] ); 67 irc->user->fullname = g_strdup( cmd[4] ); 69 68 70 69 irc_check_login( irc ); … … 73 72 static void irc_cmd_nick( irc_t *irc, char **cmd ) 74 73 { 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] ); 74 irc_user_t *iu; 75 76 if( ( iu = irc_user_by_name( irc, cmd[1] ) ) && iu != irc->user ) 77 { 78 irc_send_num( irc, 433, "%s :This nick is already in use", cmd[1] ); 84 79 } 85 80 else if( !nick_ok( cmd[1] ) ) 86 81 { 87 82 /* [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] ); 83 irc_send_num( irc, 432, "%s :This nick contains invalid characters", cmd[1] ); 84 } 85 else if( irc->status & USTATUS_LOGGED_IN ) 86 { 87 if( irc->status & USTATUS_IDENTIFIED ) 88 { 89 irc_setpass( irc, NULL ); 90 irc->status &= ~USTATUS_IDENTIFIED; 91 irc_umode_set( irc, "-R", 1 ); 92 irc_usermsg( irc, "Changing nicks resets your identify status. " 93 "Re-identify or register a new account if you want " 94 "your configuration to be saved. See \x02help " 95 "nick_changes\x02." ); 96 } 97 98 irc_user_set_nick( irc->user, cmd[1] ); 99 } 100 else 101 { 102 g_free( irc->user->nick ); 103 irc->user->nick = g_strdup( cmd[1] ); 102 104 103 105 irc_check_login( irc ); … … 115 117 static void irc_cmd_ping( irc_t *irc, char **cmd ) 116 118 { 117 irc_write( irc, ":%s PONG %s :%s", irc->myhost, irc->myhost, cmd[1]?cmd[1]:irc->myhost ); 118 } 119 irc_write( irc, ":%s PONG %s :%s", irc->root->host, 120 irc->root->host, cmd[1]?cmd[1]:irc->root->host ); 121 } 122 123 static void irc_cmd_pong( irc_t *irc, char **cmd ) 124 { 125 /* We could check the value we get back from the user, but in 126 fact we don't care, we're just happy s/he's still alive. */ 127 irc->last_pong = gettime(); 128 irc->pinging = 0; 129 } 130 131 static void irc_cmd_join( irc_t *irc, char **cmd ) 132 { 133 char *comma, *s = cmd[1]; 134 135 while( s ) 136 { 137 irc_channel_t *ic; 138 139 if( ( comma = strchr( s, ',' ) ) ) 140 *comma = '\0'; 141 142 if( ( ic = irc_channel_by_name( irc, s ) ) == NULL ) 143 { 144 ic = irc_channel_new( irc, s ); 145 146 if( strcmp( set_getstr( &ic->set, "type" ), "control" ) != 0 ) 147 { 148 /* Autoconfiguration is for control channels only ATM. */ 149 } 150 else if( bee_group_by_name( ic->irc->b, ic->name + 1, FALSE ) ) 151 { 152 set_setstr( &ic->set, "group", ic->name + 1 ); 153 set_setstr( &ic->set, "fill_by", "group" ); 154 } 155 else if( set_setstr( &ic->set, "protocol", ic->name + 1 ) ) 156 { 157 set_setstr( &ic->set, "fill_by", "protocol" ); 158 } 159 else if( set_setstr( &ic->set, "account", ic->name + 1 ) ) 160 { 161 set_setstr( &ic->set, "fill_by", "account" ); 162 } 163 else 164 { 165 bee_irc_channel_update( ic->irc, ic, NULL ); 166 } 167 } 168 169 if( ic == NULL ) 170 { 171 irc_send_num( irc, 479, "%s :Invalid channel name", s ); 172 goto next; 173 } 174 175 if( ic->flags & IRC_CHANNEL_JOINED ) 176 /* Dude, you're already there... 177 RFC doesn't have any reply for that though? */ 178 goto next; 179 180 if( ic->f->join && !ic->f->join( ic ) ) 181 /* The story is: FALSE either means the handler 182 showed an error message, or is doing some work 183 before the join should be confirmed. (In the 184 latter case, the caller should take care of that 185 confirmation.) TRUE means all's good, let the 186 user join the channel right away. */ 187 goto next; 188 189 irc_channel_add_user( ic, irc->user ); 190 191 next: 192 if( comma ) 193 { 194 s = comma + 1; 195 *comma = ','; 196 } 197 else 198 break; 199 } 200 } 201 202 static void irc_cmd_names( irc_t *irc, char **cmd ) 203 { 204 irc_channel_t *ic; 205 206 if( cmd[1] && ( ic = irc_channel_by_name( irc, cmd[1] ) ) ) 207 irc_send_names( ic ); 208 /* With no args, we should show /names of all chans. Make the code 209 below work well if necessary. 210 else 211 { 212 GSList *l; 213 214 for( l = irc->channels; l; l = l->next ) 215 irc_send_names( l->data ); 216 } 217 */ 218 } 219 220 static void irc_cmd_part( irc_t *irc, char **cmd ) 221 { 222 irc_channel_t *ic; 223 224 if( ( ic = irc_channel_by_name( irc, cmd[1] ) ) == NULL ) 225 { 226 irc_send_num( irc, 403, "%s :No such channel", cmd[1] ); 227 } 228 else if( irc_channel_del_user( ic, irc->user, IRC_CDU_PART, cmd[2] ) ) 229 { 230 if( ic->f->part ) 231 ic->f->part( ic, NULL ); 232 } 233 else 234 { 235 irc_send_num( irc, 442, "%s :You're not on that channel", cmd[1] ); 236 } 237 } 238 239 static void irc_cmd_whois( irc_t *irc, char **cmd ) 240 { 241 char *nick = cmd[1]; 242 irc_user_t *iu = irc_user_by_name( irc, nick ); 243 244 if( iu ) 245 irc_send_whois( iu ); 246 else 247 irc_send_num( irc, 401, "%s :Nick does not exist", nick ); 248 } 249 250 static void irc_cmd_whowas( irc_t *irc, char **cmd ) 251 { 252 /* For some reason irssi tries a whowas when whois fails. We can 253 ignore this, but then the user never gets a "user not found" 254 message from irssi which is a bit annoying. So just respond 255 with not-found and irssi users will get better error messages */ 256 257 irc_send_num( irc, 406, "%s :Nick does not exist", cmd[1] ); 258 irc_send_num( irc, 369, "%s :End of WHOWAS", cmd[1] ); 259 } 260 261 static void irc_cmd_motd( irc_t *irc, char **cmd ) 262 { 263 irc_send_motd( irc ); 264 } 265 266 static void irc_cmd_mode( irc_t *irc, char **cmd ) 267 { 268 if( irc_channel_name_ok( cmd[1] ) ) 269 { 270 irc_channel_t *ic; 271 272 if( ( ic = irc_channel_by_name( irc, cmd[1] ) ) == NULL ) 273 irc_send_num( irc, 403, "%s :No such channel", cmd[1] ); 274 else if( cmd[2] ) 275 { 276 if( *cmd[2] == '+' || *cmd[2] == '-' ) 277 irc_send_num( irc, 477, "%s :Can't change channel modes", cmd[1] ); 278 else if( *cmd[2] == 'b' ) 279 irc_send_num( irc, 368, "%s :No bans possible", cmd[1] ); 280 } 281 else 282 irc_send_num( irc, 324, "%s +%s", cmd[1], ic->mode ); 283 } 284 else 285 { 286 if( nick_cmp( cmd[1], irc->user->nick ) == 0 ) 287 { 288 if( cmd[2] ) 289 irc_umode_set( irc, cmd[2], 0 ); 290 else 291 irc_send_num( irc, 221, "+%s", irc->umode ); 292 } 293 else 294 irc_send_num( irc, 502, ":Don't touch their modes" ); 295 } 296 } 297 298 static void irc_cmd_who( irc_t *irc, char **cmd ) 299 { 300 char *channel = cmd[1]; 301 irc_channel_t *ic; 302 303 if( !channel || *channel == '0' || *channel == '*' || !*channel ) 304 irc_send_who( irc, irc->users, "**" ); 305 else if( ( ic = irc_channel_by_name( irc, channel ) ) ) 306 irc_send_who( irc, ic->users, channel ); 307 else 308 irc_send_num( irc, 403, "%s :No such channel", channel ); 309 } 310 311 static void irc_cmd_privmsg( irc_t *irc, char **cmd ) 312 { 313 irc_channel_t *ic; 314 irc_user_t *iu; 315 316 if( !cmd[2] ) 317 { 318 irc_send_num( irc, 412, ":No text to send" ); 319 return; 320 } 321 322 /* Don't treat CTCP actions as real CTCPs, just convert them right now. */ 323 if( g_strncasecmp( cmd[2], "\001ACTION", 7 ) == 0 ) 324 { 325 cmd[2] += 4; 326 memcpy( cmd[2], "/me", 3 ); 327 if( cmd[2][strlen(cmd[2])-1] == '\001' ) 328 cmd[2][strlen(cmd[2])-1] = '\0'; 329 } 330 331 if( irc_channel_name_ok( cmd[1] ) && 332 ( ic = irc_channel_by_name( irc, cmd[1] ) ) ) 333 { 334 if( ic->f->privmsg ) 335 ic->f->privmsg( ic, cmd[2] ); 336 } 337 else if( ( iu = irc_user_by_name( irc, cmd[1] ) ) ) 338 { 339 if( cmd[2][0] == '\001' ) 340 { 341 char **ctcp; 342 343 if( iu->f->ctcp == NULL ) 344 return; 345 if( cmd[2][strlen(cmd[2])-1] == '\001' ) 346 cmd[2][strlen(cmd[2])-1] = '\0'; 347 348 ctcp = split_command_parts( cmd[2] + 1 ); 349 iu->f->ctcp( iu, ctcp ); 350 } 351 else if( iu->f->privmsg ) 352 { 353 iu->last_channel = NULL; 354 iu->f->privmsg( iu, cmd[2] ); 355 } 356 } 357 else 358 { 359 irc_send_num( irc, 401, "%s :No such nick/channel", cmd[1] ); 360 } 361 } 362 363 static void irc_cmd_notice( irc_t *irc, char **cmd ) 364 { 365 if( !cmd[2] ) 366 { 367 irc_send_num( irc, 412, ":No text to send" ); 368 return; 369 } 370 371 /* At least for now just echo. IIRC some IRC clients use self-notices 372 for lag checks, so try to support that. */ 373 if( nick_cmp( cmd[1], irc->user->nick ) == 0 ) 374 irc_send_msg( irc->user, "NOTICE", irc->user->nick, cmd[2], NULL ); 375 } 376 377 static void irc_cmd_nickserv( irc_t *irc, char **cmd ) 378 { 379 /* [SH] This aliases the NickServ command to PRIVMSG root */ 380 /* [TV] This aliases the NS command to PRIVMSG root as well */ 381 root_command( irc, cmd + 1 ); 382 } 383 384 119 385 120 386 static void irc_cmd_oper( irc_t *irc, char **cmd ) … … 126 392 { 127 393 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] ); 394 irc_send_num( irc, 381, ":Password accepted" ); 395 } 396 else 397 { 398 irc_send_num( irc, 432, ":Incorrect password" ); 214 399 } 215 400 } … … 217 402 static void irc_cmd_invite( irc_t *irc, char **cmd ) 218 403 { 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:"**" ); 404 irc_channel_t *ic; 405 irc_user_t *iu; 406 407 if( ( iu = irc_user_by_name( irc, cmd[1] ) ) == NULL ) 408 { 409 irc_send_num( irc, 401, "%s :No such nick", cmd[1] ); 410 return; 411 } 412 else if( ( ic = irc_channel_by_name( irc, cmd[2] ) ) == NULL ) 413 { 414 irc_send_num( irc, 403, "%s :No such channel", cmd[2] ); 415 return; 416 } 417 418 if( !ic->f->invite ) 419 irc_send_num( irc, 482, "%s :Can't invite people here", cmd[2] ); 420 else if( ic->f->invite( ic, iu ) ) 421 irc_send_num( irc, 341, "%s %s", iu->nick, ic->name ); 315 422 } 316 423 317 424 static void irc_cmd_userhost( irc_t *irc, char **cmd ) 318 425 { 319 user_t *u;320 426 int i; 321 427 … … 327 433 328 434 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 } 435 { 436 irc_user_t *iu = irc_user_by_name( irc, cmd[i] ); 437 438 if( iu ) 439 irc_send_num( irc, 302, ":%s=%c%s@%s", iu->nick, 440 irc_user_get_away( iu ) ? '-' : '+', 441 iu->user, iu->host ); 442 } 336 443 } 337 444 338 445 static void irc_cmd_ison( irc_t *irc, char **cmd ) 339 446 { 340 user_t *u;341 447 char buff[IRC_MAX_LINE]; 342 448 int lenleft, i; … … 354 460 while( *this ) 355 461 { 462 irc_user_t *iu; 463 356 464 if( ( next = strchr( this, ' ' ) ) ) 357 465 *next = 0; 358 466 359 if( ( u = user_find( irc, this ) ) && u->online ) 360 { 361 lenleft -= strlen( u->nick ) + 1; 467 if( ( iu = irc_user_by_name( irc, this ) ) && 468 iu->bu && iu->bu->flags & BEE_USER_ONLINE ) 469 { 470 lenleft -= strlen( iu->nick ) + 1; 362 471 363 472 if( lenleft < 0 ) 364 473 break; 365 474 366 strcat( buff, u->nick );475 strcat( buff, iu->nick ); 367 476 strcat( buff, " " ); 368 477 } … … 387 496 buff[strlen(buff)-1] = '\0'; 388 497 389 irc_ reply( irc, 303, ":%s", buff );498 irc_send_num( irc, 303, ":%s", buff ); 390 499 } 391 500 … … 400 509 { 401 510 char *nick; 402 user_t *u;511 irc_user_t *iu; 403 512 404 513 if( !cmd[i][0] || !cmd[i][1] ) … … 408 517 nick_lc( nick ); 409 518 410 u = user_find( irc, nick );519 iu = irc_user_by_name( irc, nick ); 411 520 412 521 if( cmd[i][0] == '+' ) … … 415 524 g_hash_table_insert( irc->watches, nick, nick ); 416 525 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" ); 526 if( iu && iu->bu && iu->bu->flags & BEE_USER_ONLINE ) 527 irc_send_num( irc, 604, "%s %s %s %d :%s", iu->nick, iu->user, 528 iu->host, (int) time( NULL ), "is online" ); 419 529 else 420 irc_reply( irc, 605, "%s %s %s %d :%s", nick, "*", "*", (int) time( NULL ), "is offline" ); 530 irc_send_num( irc, 605, "%s %s %s %d :%s", nick, "*", "*", 531 (int) time( NULL ), "is offline" ); 421 532 } 422 533 else if( cmd[i][0] == '-' ) … … 429 540 g_free( okey ); 430 541 431 irc_ reply( irc, 602, "%s %s %s %d :%s", nick, "*", "*", 0, "Stopped watching" );542 irc_send_num( irc, 602, "%s %s %s %d :%s", nick, "*", "*", 0, "Stopped watching" ); 432 543 } 433 544 } … … 437 548 static void irc_cmd_topic( irc_t *irc, char **cmd ) 438 549 { 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 ); 550 irc_channel_t *ic = irc_channel_by_name( irc, cmd[1] ); 551 const char *new = cmd[2]; 552 553 if( ic == NULL ) 554 { 555 irc_send_num( irc, 403, "%s :No such channel", cmd[1] ); 556 } 557 else if( new ) 558 { 559 if( ic->f->topic == NULL ) 560 irc_send_num( irc, 482, "%s :Can't change this channel's topic", ic->name ); 561 else if( ic->f->topic( ic, new ) ) 562 irc_send_topic( ic, TRUE ); 563 } 564 else 565 { 566 irc_send_topic( ic, FALSE ); 453 567 } 454 568 } … … 456 570 static void irc_cmd_away( irc_t *irc, char **cmd ) 457 571 { 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 { 572 if( cmd[1] && *cmd[1] ) 573 { 574 char away[strlen(cmd[1])+1]; 465 575 int i, j; 466 576 467 577 /* Copy away string, but skip control chars. Mainly because 468 578 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] ) >= ' ' ) 579 for( i = j = 0; cmd[1][i]; i ++ ) 580 if( ( away[j] = cmd[1][i] ) >= ' ' ) 472 581 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; 582 away[j] = '\0'; 583 584 irc_send_num( irc, 306, ":You're now away: %s", away ); 585 set_setstr( &irc->b->set, "away", away ); 586 } 587 else 588 { 589 irc_send_num( irc, 305, ":Welcome back" ); 590 set_setstr( &irc->b->set, "away", NULL ); 591 } 549 592 } 550 593 551 594 static void irc_cmd_version( irc_t *irc, char **cmd ) 552 595 { 553 irc_reply( irc, 351, "bitlbee-%s. %s :%s/%s ", BITLBEE_VERSION, irc->myhost, ARCH, CPU ); 596 irc_send_num( irc, 351, "bitlbee-%s. %s :%s/%s ", 597 BITLBEE_VERSION, irc->root->host, ARCH, CPU ); 554 598 } 555 599 556 600 static void irc_cmd_completions( irc_t *irc, char **cmd ) 557 601 { 558 user_t *u = user_find( irc, irc->mynick );559 602 help_t *h; 560 603 set_t *s; 561 604 int i; 562 605 563 irc_ privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", "OK" );606 irc_send_msg_raw( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS OK" ); 564 607 565 608 for( i = 0; commands[i].command; i ++ ) 566 irc_ privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS", commands[i].command );609 irc_send_msg_f( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS %s", commands[i].command ); 567 610 568 611 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" );612 irc_send_msg_f( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS help %s", h->title ); 613 614 for( s = irc->b->set; s; s = s->next ) 615 irc_send_msg_f( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS set %s", s->key ); 616 617 irc_send_msg_raw( irc->root, "NOTICE", irc->user->nick, "COMPLETIONS END" ); 575 618 } 576 619 … … 582 625 ipc_to_master( cmd ); 583 626 584 irc_ reply( irc, 382, "%s :Rehashing", global.conf_file );627 irc_send_num( irc, 382, "%s :Rehashing", global.conf_file ); 585 628 } 586 629 … … 591 634 { "quit", 0, irc_cmd_quit, 0 }, 592 635 { "ping", 0, irc_cmd_ping, 0 }, 593 { "oper", 2, irc_cmd_oper, IRC_CMD_LOGGED_IN }, 636 { "pong", 0, irc_cmd_pong, IRC_CMD_LOGGED_IN }, 637 { "join", 1, irc_cmd_join, IRC_CMD_LOGGED_IN }, 638 { "names", 1, irc_cmd_names, IRC_CMD_LOGGED_IN }, 639 { "part", 1, irc_cmd_part, IRC_CMD_LOGGED_IN }, 640 { "whois", 1, irc_cmd_whois, IRC_CMD_LOGGED_IN }, 641 { "whowas", 1, irc_cmd_whowas, IRC_CMD_LOGGED_IN }, 642 { "motd", 0, irc_cmd_motd, IRC_CMD_LOGGED_IN }, 594 643 { "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 }, 644 { "who", 0, irc_cmd_who, IRC_CMD_LOGGED_IN }, 599 645 { "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 }, 646 { "notice", 1, irc_cmd_notice, IRC_CMD_LOGGED_IN }, 647 { "nickserv", 1, irc_cmd_nickserv, IRC_CMD_LOGGED_IN }, 648 { "ns", 1, irc_cmd_nickserv, IRC_CMD_LOGGED_IN }, 649 { "away", 0, irc_cmd_away, IRC_CMD_LOGGED_IN }, 650 { "version", 0, irc_cmd_version, IRC_CMD_LOGGED_IN }, 651 { "completions", 0, irc_cmd_completions, IRC_CMD_LOGGED_IN }, 602 652 { "userhost", 1, irc_cmd_userhost, IRC_CMD_LOGGED_IN }, 603 653 { "ison", 1, irc_cmd_ison, IRC_CMD_LOGGED_IN }, 604 654 { "watch", 1, irc_cmd_watch, IRC_CMD_LOGGED_IN }, 655 { "invite", 2, irc_cmd_invite, IRC_CMD_LOGGED_IN }, 605 656 { "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 }, 657 { "oper", 2, irc_cmd_oper, IRC_CMD_LOGGED_IN }, 615 658 { "die", 0, NULL, IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER }, 616 659 { "deaf", 0, NULL, IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER }, … … 638 681 if( irc_commands[i].flags & IRC_CMD_PRE_LOGIN && irc->status & USTATUS_LOGGED_IN ) 639 682 { 640 irc_ reply( irc, 462, ":Only allowed before logging in" );683 irc_send_num( irc, 462, ":Only allowed before logging in" ); 641 684 } 642 685 else if( irc_commands[i].flags & IRC_CMD_LOGGED_IN && !( irc->status & USTATUS_LOGGED_IN ) ) 643 686 { 644 irc_ reply( irc, 451, ":Register first" );687 irc_send_num( irc, 451, ":Register first" ); 645 688 } 646 689 else if( irc_commands[i].flags & IRC_CMD_OPER_ONLY && !strchr( irc->umode, 'o' ) ) 647 690 { 648 irc_ reply( irc, 481, ":Permission denied - You're not an IRC operator" );691 irc_send_num( irc, 481, ":Permission denied - You're not an IRC operator" ); 649 692 } 650 693 else if( n_arg < irc_commands[i].required_parameters ) 651 694 { 652 irc_ reply( irc, 461, "%s :Need more parameters", cmd[0] );695 irc_send_num( irc, 461, "%s :Need more parameters", cmd[0] ); 653 696 } 654 697 else if( irc_commands[i].flags & IRC_CMD_TO_MASTER ) … … 667 710 668 711 if( irc->status >= USTATUS_LOGGED_IN ) 669 irc_ reply( irc, 421, "%s :Unknown command", cmd[0] );670 } 712 irc_send_num( irc, 421, "%s :Unknown command", cmd[0] ); 713 } -
lib/Makefile
ref14a83 r2945c6f 8 8 9 9 -include ../Makefile.settings 10 ifdef SRCDIR 11 SRCDIR := $(SRCDIR)lib/ 12 endif 10 13 11 14 # [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.o15 objects = 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 13 16 14 17 CFLAGS += -Wall … … 37 40 $(objects): ../Makefile.settings Makefile 38 41 39 $(objects): %.o: %.c42 $(objects): %.o: $(SRCDIR)%.c 40 43 @echo '*' Compiling $< 41 44 @$(CC) -c $(CFLAGS) $< -o $@ -
lib/events.h
ref14a83 r2945c6f 48 48 the given callback function. */ 49 49 typedef 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, 52 54 } b_input_condition; 53 55 typedef gboolean (*b_event_handler)(gpointer data, gint fd, b_input_condition cond); -
lib/events_glib.c
ref14a83 r2945c6f 49 49 b_event_handler function; 50 50 gpointer data; 51 guint flags; 51 52 } GaimIOClosure; 52 53 … … 76 77 77 78 if (condition & GAIM_READ_COND) 78 gaim_cond |= GAIM_INPUT_READ;79 gaim_cond |= B_EV_IO_READ; 79 80 if (condition & GAIM_WRITE_COND) 80 gaim_cond |= GAIM_INPUT_WRITE;81 gaim_cond |= B_EV_IO_WRITE; 81 82 82 83 event_debug( "gaim_io_invoke( %d, %d, 0x%x )\n", g_io_channel_unix_get_fd(source), condition, data ); … … 87 88 event_debug( "Returned FALSE, cancelling.\n" ); 88 89 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; 90 96 } 91 97 … … 105 111 closure->function = function; 106 112 closure->data = data; 113 closure->flags = condition; 107 114 108 if (condition & GAIM_INPUT_READ)115 if (condition & B_EV_IO_READ) 109 116 cond |= GAIM_READ_COND; 110 if (condition & GAIM_INPUT_WRITE)117 if (condition & B_EV_IO_WRITE) 111 118 cond |= GAIM_WRITE_COND; 112 119 -
lib/events_libevent.c
ref14a83 r2945c6f 60 60 b_event_handler function; 61 61 void *data; 62 guint flags; 62 63 }; 63 64 … … 126 127 { 127 128 if( event & EV_READ ) 128 cond |= GAIM_INPUT_READ;129 cond |= B_EV_IO_READ; 129 130 if( event & EV_WRITE ) 130 cond |= GAIM_INPUT_WRITE;131 cond |= B_EV_IO_WRITE; 131 132 } 132 133 … … 150 151 return; 151 152 } 152 else if( !st )153 else if( !st && !( b_ev->flags & B_EV_FLAG_FORCE_REPEAT ) ) 153 154 { 154 155 event_debug( "Handler returned FALSE: " ); … … 174 175 event_debug( "b_input_add( %d, %d, 0x%x, 0x%x ) ", fd, condition, function, data ); 175 176 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 ) ) ) ) 178 179 { 179 180 /* We'll stick with this libevent entry, but give it a new BitlBee id. */ … … 198 199 199 200 out_cond = EV_PERSIST; 200 if( condition & GAIM_INPUT_READ )201 if( condition & B_EV_IO_READ ) 201 202 out_cond |= EV_READ; 202 if( condition & GAIM_INPUT_WRITE )203 if( condition & B_EV_IO_WRITE ) 203 204 out_cond |= EV_WRITE; 204 205 … … 212 213 } 213 214 215 b_ev->flags = condition; 214 216 g_hash_table_insert( id_hash, &b_ev->id, b_ev ); 215 217 return b_ev->id; -
lib/http_client.c
ref14a83 r2945c6f 151 151 if( req->bytes_written < req->request_length ) 152 152 req->inpa = b_input_add( source, 153 req->ssl ? ssl_getdirection( req->ssl ) : GAIM_INPUT_WRITE,153 req->ssl ? ssl_getdirection( req->ssl ) : B_EV_IO_WRITE, 154 154 http_connected, req ); 155 155 else 156 req->inpa = b_input_add( source, GAIM_INPUT_READ, http_incoming_data, req );156 req->inpa = b_input_add( source, B_EV_IO_READ, http_incoming_data, req ); 157 157 158 158 return FALSE; … … 236 236 /* There will be more! */ 237 237 req->inpa = b_input_add( req->fd, 238 req->ssl ? ssl_getdirection( req->ssl ) : GAIM_INPUT_READ,238 req->ssl ? ssl_getdirection( req->ssl ) : B_EV_IO_READ, 239 239