Changeset 3fbce97
- Timestamp:
- 2016-09-24T20:14:34Z (8 years ago)
- Children:
- ba52ac5
- Parents:
- 63cad66 (diff), 82cb190 (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:
-
- 2 added
- 117 edited
Legend:
- Unmodified
- Added
- Removed
-
.travis.yml
r63cad66 r3fbce97 1 sudo: false 1 2 language: c 2 3 … … 4 5 - ./configure 5 6 - make check 6 - BITLBEE_SKYPE=plugin dpkg-buildpackage -uc -us 7 - BITLBEE_SKYPE=plugin dpkg-buildpackage -uc -us -d 7 8 9 # ubuntu precise doesn't have libotr5, so extract a prebuilt version to ~/otr 8 10 before_install: 9 - sudo apt-get update -qq 10 - sudo apt-get install --no-install-recommends -qq libevent-dev libpurple-dev check 11 - wget http://dump.dequis.org/indexed/bitlbee-travis-libs/libotr5{,-dev}_4.1.0-2~bpo70+1_amd64.deb 12 - sudo dpkg -i *.deb 11 - wget http://dump.dequis.org/indexed/bitlbee-travis-libs/libotr5_4.1.0_amd64_with_dev_for_travis.tar.gz -O /tmp/otr.tar.gz 12 - echo "8424feb28a2cff3ce603ddcdff9be788701ff7e4 /tmp/otr.tar.gz" | sha1sum -c - 13 - tar -C "$HOME" -xf /tmp/otr.tar.gz 14 - sed -i "s#/usr#$HOME/otr/usr/#" "$HOME/otr/usr/lib/pkgconfig/libotr.pc" 15 - echo "libotr 5 libotr" > debian/shlibs.local 13 16 14 17 env: 15 18 global: 19 - PKG_CONFIG_PATH=$HOME/otr/usr/lib/pkgconfig/ 20 - LD_LIBRARY_PATH=$HOME/otr/usr/lib/ 16 21 # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created 17 22 # via the "travis encrypt" command using the project repo's public key … … 19 24 20 25 addons: 26 apt: 27 packages: 28 - libevent-dev 29 - libpurple-dev 30 - check 21 31 coverity_scan: 22 32 project: -
Makefile
r63cad66 r3fbce97 10 10 11 11 # Program variables 12 objects = bitlbee.o dcc.o help.o ipc.o irc.o irc_im.o irc_c hannel.o irc_commands.o irc_send.o irc_user.o irc_util.o nick.o $(OTR_BI) query.o root_commands.o set.o storage.o $(STORAGE_OBJS) unix.o conf.o log.o12 objects = bitlbee.o dcc.o help.o ipc.o irc.o irc_im.o irc_cap.o irc_channel.o irc_commands.o irc_send.o irc_user.o irc_util.o nick.o $(OTR_BI) query.o root_commands.o set.o storage.o $(STORAGE_OBJS) unix.o conf.o log.o 13 13 headers = $(wildcard $(_SRCDIR_)*.h $(_SRCDIR_)lib/*.h $(_SRCDIR_)protocols/*.h) 14 14 subdirs = lib protocols … … 30 30 31 31 install: install-bin install-doc install-plugins 32 @echo 33 @echo Installed successfully 34 @echo 32 35 @if ! [ -d $(DESTDIR)$(CONFIG) ]; then echo -e '\nThe configuration directory $(DESTDIR)$(CONFIG) does not exist yet, don'\''t forget to create it!'; fi 33 36 @if ! [ -e $(DESTDIR)$(ETCDIR)/bitlbee.conf ]; then echo -e '\nNo files are installed in '$(DESTDIR)$(ETCDIR)' by make install. Run make install-etc to do that.'; fi … … 35 38 @echo If you want to start BitlBee using systemd, try \"make install-systemd\". 36 39 endif 37 @echo 38 39 .PHONY: install install-bin install-etc install-doc install-plugins install-systemd \ 40 uninstall uninstall-bin uninstall-etc uninstall-doc \ 40 @echo To be able to compile third party plugins, run \"make install-dev\" 41 @echo 42 43 .PHONY: install install-bin install-etc install-doc install-plugins install-systemd install-dev \ 44 uninstall uninstall-bin uninstall-etc uninstall-doc uninstall-etc \ 41 45 all clean distclean tar $(subdirs) doc 42 46 -
README.md
r63cad66 r3fbce97 16 16 License: GPLv2 17 17 18 ## Development18 ## Installation 19 19 20 Use github pull requests against the 'develop' branch to submit patches.20 BitlBee is available in the package managers of most distros. 21 21 22 The 'master' branch should be stable enough to be usable by users of the APT repo, but only requires a few days of testing in the 'develop' branch. 22 For debian/ubuntu/etc you may use the nightly APT repository: http://code.bitlbee.org/debian/ 23 23 24 Building: 24 You can also use a public server (such as `im.bitlbee.org`) instead of installing it: http://bitlbee.org/main.php/servers.html 25 25 26 ``` 27 ./configure --debug=1 28 # or, for a local install: 29 # ./configure --debug=1 --prefix=$HOME/bitlbee --config=$HOME/bitlbee --pidfile=$HOME/bitlbee/bitlbee.pid 26 ## Compiling 30 27 31 # Also try --asan=1 for AddressSanitizer 28 If you wish to compile it yourself, ensure you have the following packages and their headers: 32 29 33 make 30 * glib 2.16 or newer (not to be confused with glibc) 31 * gnutls 32 * python 2 or 3 (for the user guide) 34 33 35 BITLBEE_DEBUG=1 ./bitlbee -Dnv 36 ``` 34 Some optional features have additional dependencies, such as libpurple, libotr, libevent, etc. 35 NSS and OpenSSL are also available but not as well supported as GnuTLS. 37 36 38 See ./doc/README and ./doc/HACKING for more details. 37 Once you have the dependencies, building should be a matter of: 39 38 40 Mappings of bzr revisions to git commits (for historical purposes) are available in ./doc/git-bzr-rev-map 39 ./configure 40 make 41 sudo make install 42 43 ## Development tips 44 45 * To enable debug symbols: `./configure --debug=1` 46 * To get some additional debug output for some protocols: `BITLBEE_DEBUG=1 ./bitlbee -Dnv` 47 * Use github pull requests against the 'develop' branch to submit patches. 48 * The coding style based on K&R with tabs and 120 columns. See `./doc/uncrustify.cfg` for the parameters used to reformat the code. 49 * Mappings of bzr revisions to git commits (for historical purposes) are available in `./doc/git-bzr-rev-map` 50 * See also `./doc/README` and `./doc/HACKING` 41 51 42 52 ## Help? 43 53 44 Join **#BitlBee** on OFTC (**irc.oftc.net**) (OFTC, *not* FreeNode!) and flame us right in the face. :-)54 Join **#BitlBee** on OFTC (**irc.oftc.net**) (OFTC, *not* FreeNode!) -
bitlbee.c
r63cad66 r3fbce97 311 311 b_event_remove(global.listen_watch_source_id); 312 312 313 /* Make a new pipe for the shutdown signal handler */ 314 sighandler_shutdown_setup(); 315 313 316 /* Make the connection. */ 314 317 irc = irc_new(new_socket); -
bitlbee.h
r63cad66 r3fbce97 158 158 } global_t; 159 159 160 void sighandler_shutdown_setup(void); 161 160 162 int bitlbee_daemon_init(void); 161 163 int bitlbee_inetd_init(void); -
conf.c
r63cad66 r3fbce97 37 37 38 38 static int conf_loadini(conf_t *conf, char *file); 39 static void conf_free(conf_t *conf); 39 40 40 41 conf_t *conf_load(int argc, char *argv[]) … … 73 74 if (i == 0) { 74 75 fprintf(stderr, "Error: Syntax error in configuration file `%s'.\n", global.conf_file); 76 conf_free(conf); 75 77 return NULL; 76 78 } else if (i == -1) { … … 104 106 g_free(global.conf_file); 105 107 global.conf_file = g_strdup(optarg); 106 g_free(conf);108 conf_free(conf); 107 109 /* Re-evaluate arguments. Don't use this option twice, 108 110 you'll end up in an infinite loop! Hope this trick … … 135 137 " -h Show this help page.\n" 136 138 " -V Show version info.\n"); 139 conf_free(conf); 137 140 return NULL; 138 141 } else if (opt == 'V') { 139 printf("BitlBee %s\nAPI version %06x\n", 140 BITLBEE_VERSION, BITLBEE_VERSION_CODE); 142 printf("BitlBee %s\nAPI version %06x\nConfigure args: %s\n", 143 BITLBEE_VERSION, BITLBEE_VERSION_CODE, BITLBEE_CONFIGURE_ARGS); 144 conf_free(conf); 141 145 return NULL; 142 146 } else if (opt == 'u') { … … 162 166 they're secure when in fact they're not. */ 163 167 fprintf(stderr, "Error: Could not read CA file %s: %s\n", conf->cafile, strerror(errno)); 168 conf_free(conf); 164 169 return NULL; 165 170 } 166 171 167 172 return conf; 173 } 174 175 static void conf_free(conf_t *conf) 176 { 177 /* Free software means users have the four essential freedoms: 178 0. to run the program, 179 2. to study and change the program in source code form, 180 2. to redistribute exact copies, and 181 3. to distribute modified versions 182 */ 183 g_free(conf->auth_pass); 184 g_free(conf->cafile); 185 g_free(conf->configdir); 186 g_free(conf->ft_listen); 187 g_free(conf->hostname); 188 g_free(conf->iface_in); 189 g_free(conf->iface_out); 190 g_free(conf->motdfile); 191 g_free(conf->oper_pass); 192 g_free(conf->pidfile); 193 g_free(conf->plugindir); 194 g_free(conf->port); 195 g_free(conf->primary_storage); 196 g_free(conf->user); 197 g_strfreev(conf->migrate_storage); 198 g_strfreev(conf->protocols); 199 g_free(conf); 200 168 201 } 169 202 … … 219 252 g_free(conf->configdir); 220 253 conf->configdir = g_strdup(ini->value); 254 } else if (g_strcasecmp(ini->key, "plugindir") == 0) { 255 g_free(conf->plugindir); 256 conf->plugindir = g_strdup(ini->value); 221 257 } else if (g_strcasecmp(ini->key, "motdfile") == 0) { 222 258 g_free(conf->motdfile); … … 259 295 } else if (url->proto == PROTO_SOCKS5) { 260 296 proxytype = PROXY_SOCKS5; 297 } else if (url->proto == PROTO_SOCKS4A) { 298 proxytype = PROXY_SOCKS4A; 261 299 } 262 300 -
configure
r63cad66 r3fbce97 24 24 pcdir='$prefix/lib/pkgconfig' 25 25 systemlibdirs="/lib64 /usr/lib64 /usr/local/lib64 /lib /usr/lib /usr/local/lib" 26 sysroot='' 27 28 configure_args="$@" 26 29 27 30 # Set these to default-on to let it be overriden by either the user or purple … … 53 56 pie=1 54 57 55 arch= `uname -s`56 cpu= `uname -m`58 arch=$(uname -s) 59 cpu=$(uname -m) 57 60 58 61 GLIB_MIN_VERSION=2.16 … … 105 108 106 109 while [ -n "$1" ]; do 107 e=" `expr "X$1" : 'X--\(.*=.*\)'`"110 e="$(expr "X$1" : 'X--\(.*=.*\)')" 108 111 if [ -z "$e" ]; then 109 112 cat<<EOF … … 153 156 154 157 --target=... Cross compilation target same as host 158 --sysroot=... Cross compilation sysroot $sysroot 155 159 EOF 156 160 exit; … … 161 165 162 166 # Expand $prefix and get rid of double slashes 163 bindir= `eval echo "$bindir/" | sed 's/\/\{1,\}/\//g'`164 sbindir= `eval echo "$sbindir/" | sed 's/\/\{1,\}/\//g'`165 etcdir= `eval echo "$etcdir/" | sed 's/\/\{1,\}/\//g'`166 mandir= `eval echo "$mandir/" | sed 's/\/\{1,\}/\//g'`167 datadir= `eval echo "$datadir/" | sed 's/\/\{1,\}/\//g'`168 config= `eval echo "$config/" | sed 's/\/\{1,\}/\//g'`169 plugindir= `eval echo "$plugindir/" | sed 's/\/\{1,\}/\//g'`167 bindir=$(eval echo "$bindir/" | sed 's/\/\{1,\}/\//g') 168 sbindir=$(eval echo "$sbindir/" | sed 's/\/\{1,\}/\//g') 169 etcdir=$(eval echo "$etcdir/" | sed 's/\/\{1,\}/\//g') 170 mandir=$(eval echo "$mandir/" | sed 's/\/\{1,\}/\//g') 171 datadir=$(eval echo "$datadir/" | sed 's/\/\{1,\}/\//g') 172 config=$(eval echo "$config/" | sed 's/\/\{1,\}/\//g') 173 plugindir=$(eval echo "$plugindir/" | sed 's/\/\{1,\}/\//g') 170 174 rpcplugindir=$(eval echo "$rpcplugindir/" | sed 's/\/\{1,\}/\//g') 171 includedir= `eval echo "$includedir"/ | sed 's/\/\{1,\}/\//g'`172 libevent= `eval echo "$libevent"/ | sed 's/\/\{1,\}/\//g'`173 174 pidfile= `eval echo "$pidfile" | sed 's/\/\{1,\}/\//g'`175 ipcsocket= `eval echo "$ipcsocket" | sed 's/\/\{1,\}/\//g'`176 pcdir= `eval echo "$pcdir" | sed 's/\/\{1,\}/\//g'`175 includedir=$(eval echo "$includedir"/ | sed 's/\/\{1,\}/\//g') 176 libevent=$(eval echo "$libevent"/ | sed 's/\/\{1,\}/\//g') 177 178 pidfile=$(eval echo "$pidfile" | sed 's/\/\{1,\}/\//g') 179 ipcsocket=$(eval echo "$ipcsocket" | sed 's/\/\{1,\}/\//g') 180 pcdir=$(eval echo "$pcdir" | sed 's/\/\{1,\}/\//g') 177 181 178 182 protocols_mods="" … … 180 184 cat <<EOF >Makefile.settings 181 185 ## BitlBee settings, generated by configure 186 187 # ./configure $configure_args 188 182 189 PREFIX=$prefix 183 190 BINDIR=$bindir … … 233 240 of them can/will be overridden at run-time */ 234 241 242 #define BITLBEE_CONFIGURE_ARGS "$configure_args" 243 235 244 #define CONFIG "$config" 236 245 #define ETCDIR "$etcdir" … … 247 256 248 257 if [ -n "$target" ]; then 249 PKG_CONFIG_LIBDIR=/usr/$target/lib/pkgconfig 250 export PKG_CONFIG_LIBDIR 251 PATH=/usr/$target/bin:$PATH 258 # prepend sysroot to system lib dirs 259 260 systemlibdirs_cross='' 261 for i in $systemlibdirs; do 262 systemlibdirs_cross="$systemlibdirs_cross $sysroot$i" 263 done 264 systemlibdirs=$systemlibdirs_cross 265 unset systemlibdirs_cross 266 267 # backward compatibility 268 269 if [ -z "$PKG_CONFIG_LIBDIR" ]; then 270 PKG_CONFIG_LIBDIR=/usr/$target/lib/pkgconfig 271 export PKG_CONFIG_LIBDIR 272 fi 273 274 if [ -d /usr/$target/bin ]; then 275 PATH=/usr/$target/bin:$PATH 276 fi 277 278 if [ -d /usr/$target/lib ]; then 279 systemlibdirs="$systemlibdirs /usr/$target/lib" 280 fi 281 252 282 CC=$target-cc 253 283 LD=$target-ld 254 systemlibdirs="/usr/$target/lib"284 STRIP=$target-strip 255 285 fi 256 286 … … 321 351 if $PKG_CONFIG glib-2.0 --atleast-version=$GLIB_MIN_VERSION; then 322 352 cat<<EOF >>Makefile.settings 323 EFLAGS+= `$PKG_CONFIG --libs glib-2.0 gmodule-2.0`324 CFLAGS+= `$PKG_CONFIG --cflags glib-2.0 gmodule-2.0`353 EFLAGS+=$($PKG_CONFIG --libs glib-2.0 gmodule-2.0) 354 CFLAGS+=$($PKG_CONFIG --cflags glib-2.0 gmodule-2.0) 325 355 EOF 326 356 else 327 357 echo 328 echo 'Found glib2 ' `$PKG_CONFIG glib-2.0 --modversion`', but version '$GLIB_MIN_VERSION' or newer is required.'358 echo 'Found glib2 '$($PKG_CONFIG glib-2.0 --modversion)', but version '$GLIB_MIN_VERSION' or newer is required.' 329 359 exit 1 330 360 fi … … 362 392 if $PKG_CONFIG --exists gnutls; then 363 393 cat <<EOF >>Makefile.settings 364 EFLAGS+= `$PKG_CONFIG --libs gnutls` `libgcrypt-config --libs`365 CFLAGS+= `$PKG_CONFIG --cflags gnutls` `libgcrypt-config --cflags`394 EFLAGS+=$($PKG_CONFIG --libs gnutls) $(libgcrypt-config --libs) 395 CFLAGS+=$($PKG_CONFIG --cflags gnutls) $(libgcrypt-config --cflags) 366 396 EOF 367 397 ssl=gnutls 368 if ! pkg-configgnutls --atleast-version=2.8; then398 if ! $PKG_CONFIG gnutls --atleast-version=2.8; then 369 399 echo 370 400 echo 'Warning: With GnuTLS versions <2.8, certificate expire dates are not verified.' … … 373 403 elif libgnutls-config --version > /dev/null 2> /dev/null; then 374 404 cat <<EOF >>Makefile.settings 375 EFLAGS+= `libgnutls-config --libs` `libgcrypt-config --libs`376 CFLAGS+= `libgnutls-config --cflags` `libgcrypt-config --cflags`405 EFLAGS+=$(libgnutls-config --libs) $(libgcrypt-config --libs) 406 CFLAGS+=$(libgnutls-config --cflags) $(libgcrypt-config --cflags) 377 407 EOF 378 408 … … 388 418 if $PKG_CONFIG --version > /dev/null 2>/dev/null && $PKG_CONFIG nss; then 389 419 cat<<EOF >>Makefile.settings 390 EFLAGS+= `$PKG_CONFIG --libs nss`391 CFLAGS+= `$PKG_CONFIG --cflags nss`420 EFLAGS+=$($PKG_CONFIG --libs nss) 421 CFLAGS+=$($PKG_CONFIG --cflags nss) 392 422 EOF 393 423 … … 634 664 if [ -z "$systemdsystemunitdir" ]; then 635 665 if $PKG_CONFIG --exists systemd; then 636 systemdsystemunitdir= `$PKG_CONFIG --variable=systemdsystemunitdir systemd`666 systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd) 637 667 fi 638 668 fi … … 662 692 663 693 otrprefix="" 664 for i in / /usr /usr/local; do665 if [ -f ${i}/lib/libotr.a ]; then666 otrprefix=${i}667 break668 fi669 done670 694 if [ "$otr" = "auto" ]; then 671 if [ -n "$otrprefix" ]; then 672 otr=1 673 else 674 otr=0 675 fi 676 fi 695 ! $PKG_CONFIG --exists libotr 696 otr=$? 697 fi 698 699 if [ "$otr" != 0 ] && ! $PKG_CONFIG --atleast-version=4.0 --print-errors libotr; then 700 exit 1 701 fi 702 677 703 if [ "$otr" = 1 ]; then 678 704 # BI == built-in 679 705 echo '#define OTR_BI' >> config.h 680 echo "EFLAGS+= -L${otrprefix}/lib -lotr -lgcrypt" >> Makefile.settings681 echo "CFLAGS+= -I${otrprefix}/include" >> Makefile.settings706 echo "EFLAGS+=$($PKG_CONFIG --libs libotr) $(libgcrypt-config --libs)" >> Makefile.settings 707 echo "CFLAGS+=$($PKG_CONFIG --cflags libotr) $(libgcrypt-config --cflags)" >> Makefile.settings 682 708 echo 'OTR_BI=otr.o' >> Makefile.settings 683 709 elif [ "$otr" = "plugin" ]; then 710 # for some mysterious reason beyond the comprehension of my mortal mind, 711 # the libgcrypt flags aren't needed when building as plugin. add them anyway. 684 712 echo '#define OTR_PI' >> config.h 685 echo "OTRFLAGS= -L${otrprefix}/lib -lotr" >> Makefile.settings686 echo "CFLAGS+= -I${otrprefix}/include" >> Makefile.settings713 echo "OTRFLAGS=$($PKG_CONFIG --libs libotr) $(libgcrypt-config --libs)" >> Makefile.settings 714 echo "CFLAGS+=$($PKG_CONFIG --cflags libotr) $(libgcrypt-config --cflags)" >> Makefile.settings 687 715 echo 'OTR_PI=otr.so' >> Makefile.settings 688 fi689 if [ "$otr" != 0 ] && ! pkg-config libotr --atleast-version=4.0; then690 echo691 echo 'WARNING: Your libotr seems to be old. BitlBee now needs at least libotr 4.0.'692 # Not hard-failing because the code above doesn't use pkg-config, so who knows693 # what's true at this point...694 716 fi 695 717 -
dcc.c
r63cad66 r3fbce97 265 265 } 266 266 267 /* How likely is it that a 32-bit integer gets split ac cross267 /* How likely is it that a 32-bit integer gets split across 268 268 packet boundaries? Chances are rarely 0 so let's be sure. */ 269 269 if ((df->acked_len = (df->acked_len + ret) % 4) > 0) { -
debian/changelog
r63cad66 r3fbce97 1 bitlbee (3. 2.2-2) UNRELEASED; urgency=medium1 bitlbee (3.4.1-1) unstable; urgency=medium 2 2 3 3 * Fix copyright info (Closes: #764181) 4 5 -- Wilmer van der Gaast <wilmer@gaast.net> Fri, 17 Oct 2014 23:25:33 +0100 4 * "New" upstream release. Apologies for the delay. 5 * Exclude .git not .bzr when building the source package. 6 7 -- Wilmer van der Gaast <wilmer@gaast.net> Mon, 03 Aug 2015 22:33:25 +0100 6 8 7 9 bitlbee (3.2.2-1) unstable; urgency=medium -
debian/source/options
r63cad66 r3fbce97 1 --diff-ignore='(^|/)\. bzr'1 --diff-ignore='(^|/)\.git' -
doc/CHANGES
r63cad66 r3fbce97 429 429 officially be treated as case sensitive. 430 430 - Fully stripping spaces from AIM screennames, this didn't happen completely 431 which sever ly breaks the IRC protocol.431 which severely breaks the IRC protocol. 432 432 - Removed all the yellow tape around daemon mode, it's pretty mature by now: 433 433 testing.bitlbee.org serves all (~30) SSL users from one daemon mode … … 629 629 some situations. 630 630 - Outgoing MSN typing notifications are now understood correctly by the 631 orig nal MS Mac/Windows clients (again).631 original MS Mac/Windows clients (again). 632 632 - Added "account add $protocol" to the documentation, got rid of a lot 633 633 of over-markup (i.e. overuse of bold-tags), reviewed some other parts. -
doc/HACKING
r63cad66 r3fbce97 14 14 calls and arguments where that seemed useful, etc. 15 15 16 However, up to late in the 1.2 series, the IRC core was still spread ac cross16 However, up to late in the 1.2 series, the IRC core was still spread across 17 17 several files, mostly irc.c + irc_commands.c and pieces and bits in 18 18 nogaim.c. If you're looking for a textbook example of layer violation, start -
doc/README
r63cad66 r3fbce97 8 8 to set up the build system. If configure succeeds, run make to build BitlBee. 9 9 make install will move all the files to the right places. 10 11 RUN MODES 12 ========= 10 13 11 14 --- (Fork)Daemon mode … … 89 92 ================== 90 93 91 Cygwin NOTE: You'll need a glib installation to run BitlBee. However, Cygwin 92 doesn't provide a glib package. You can download a binary tar.gz from: 93 <http://my.dreamwiz.com/jbdoll/>. When you installed it, BitlBee should work 94 fine. You'll probably like bitlbeed or xinetd to get it running on the 95 network. 96 97 On some non-Linux systems the program still suffers from some random bugs. 98 Please do report them, we might be able to fix them if they're not too 99 mysterious. 100 101 Also, the configure script is known to not work very well with non-Bash 102 shells, so if you experience problems, make sure you use bash to run the 103 script. Same for the Makefile, it only works well with GNU make. (gmake on 104 most BSD systems) 94 The configure script is may not work very well with some non-bash shells (but 95 dash is supported), so if you experience problems, make sure you use bash to 96 run the script. Same for the Makefile, it only works well with GNU make. (gmake 97 on most BSD systems) 105 98 106 99 If someone can tell us how to write Makefiles that work with both/all … … 153 146 ============================= 154 147 155 There used to be a note here about the simple obfuscation method used to 156 make the passwords in the configuration files unreadable. However, BitlBee 157 now uses a better format (and real encryption (salted MD5 and RC4)) to store 158 the passwords. This means that people who somehow get their hands on your 159 configuration files can't easily extract your passwords from them anymore. 148 BitlBee currently uses salted MD5 and RC4 to store the passwords. This means 149 that people who somehow get their hands on your configuration files can't 150 easily extract your passwords from them anymore. 160 151 161 152 However, once you log into the BitlBee server and send your password, an 162 153 intruder with tcpdump can still read your passwords. This can't really be 163 avoided, of course. The new format is a lot more reliable (because it can't 164 be cracked with just very basic crypto analysis anymore), but you still have 165 to be careful. The main extra protection offered by the new format is that 166 the files can only be cracked with some help from the user (by sending the 167 password at login time). 168 169 So if you run a public server, it's most important that you don't give root 170 access to people who like to play with tcpdump. Also, it's a good idea to 171 delete all *.nicks/*.accounts files as soon as BitlBee converted them to the 172 new format (which happens as soon as the user logs in, it can't be done 173 automatically because it needs the password for that account). You won't 174 need them anymore (unless you want to switch back to an older BitlBee 175 version) and they only make it easier for others to crack your passwords. 176 154 avoided, of course. So if you run a public server, it's most important that you 155 don't give root access to people who like to play with tcpdump. 177 156 178 157 LEGAL … … 181 160 BitlBee is distributed under the GPL (GNU General Public License). See the 182 161 file COPYING for this license. 183 184 The MD5 algorithm code is licensed under the Aladdin license. This license185 can be found in the files, to which this applies. The SHA1 algorithm code186 is licensed under the Mozilla Public License, see http://www.mozilla.org/MPL/187 for details.188 162 189 163 The Yahoo! library used by BitlBee is libyahoo2 <http://libyahoo2.sf.net/>, -
doc/user-guide/Installation.xml
r63cad66 r3fbce97 73 73 <para> 74 74 By default, BitlBee runs as the user nobody. You might want 75 to run it as a sep erate user (some computers run named or apache as nobody).75 to run it as a separate user (some computers run named or apache as nobody). 76 76 </para> 77 77 -
doc/user-guide/commands.xml
r63cad66 r3fbce97 182 182 183 183 <para> 184 For more info mation about a setting, see <emphasis>help set <setting></emphasis>.184 For more information about a setting, see <emphasis>help set <setting></emphasis>. 185 185 </para> 186 186 … … 240 240 241 241 <para> 242 For more info mation about a setting, see <emphasis>help set <setting></emphasis>.242 For more information about a setting, see <emphasis>help set <setting></emphasis>. 243 243 </para> 244 244 … … 785 785 <para> 786 786 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. 787 </para> 788 </description> 789 </bitlbee-setting> 790 791 <bitlbee-setting name="carbons" type="boolean" scope="account"> 792 <default>true</default> 793 794 <description> 795 <para> 796 Jabber specific. "Message carbons" (XEP-0280) is a server feature to get copies of outgoing messages sent from other clients connected to the same account. It's not widely supported by most public XMPP servers (easier if you host your own), but this will probably change in the next few years. 797 </para> 798 <para> 799 This defaults to true, which will enable it if the server supports it, or fail silently if it's not. This setting only exists to allow disabling the feature if anyone considers it undesirable. 800 </para> 801 <para> 802 See also the <emphasis>self_messages</emphasis> setting. 787 803 </para> 788 804 </description> … … 1093 1109 1094 1110 <para> 1095 With modes "chat" and "many", you can send direct messages by /msg'ing your contacts directly. Note, however, that incoming DMs are not fetched yet.1111 With modes "chat" and "many", you can send direct messages by /msg'ing your contacts directly. Incoming DMs are only fetched if the "stream" setting is on (default). 1096 1112 </para> 1097 1113 … … 1158 1174 <description> 1159 1175 <para> 1160 By default, BitlBee generates a nickname for every contact by taking its handle and chopping off everything after the @. In some cases, this gives very inconvenient nicknames. The Facebook XMPP server is a good example, as all Facebook XMPP handles are numeric.1176 By default, BitlBee generates a nickname for every contact by taking its handle and chopping off everything after the @. In some cases, this gives very inconvenient nicknames. Some servers use internal identifiers, which are often just numbers. 1161 1177 </para> 1162 1178 … … 1172 1188 <description> 1173 1189 <para> 1174 This enables OAuth authentication for an IM account; right now the Twitter (working for Twitter only) and Jabber (for Google Talk , Facebook and MSN Messenger) module support it.1190 This enables OAuth authentication for an IM account; right now the Twitter (working for Twitter only) and Jabber (for Google Talk only) module support it. 1175 1191 </para> 1176 1192 … … 1324 1340 </bitlbee-setting> 1325 1341 1342 <bitlbee-setting name="proxy" type="string" scope="account"> 1343 <default><local><auto></default> 1344 1345 <description> 1346 <para> 1347 A list of <emphasis>file transfer proxies</emphasis> for jabber. This isn't the connection proxy. Sorry, look in bitlbee.conf for those. 1348 </para> 1349 1350 <para> 1351 It's a semicolon-separated list of items that can be either <emphasis>JID,HOST,PORT</emphasis> or two special values, <emphasis><local></emphasis> (to try a direct connection first) and <emphasis><auto></emphasis> (to try to discover a proxy). For example, "<local>;proxy.somewhere.org,123.123.123.123,7777". 1352 </para> 1353 <para> 1354 The address should point to a SOCKS5 bytestreams server, usually provided by jabber servers. This is only used for sending files. Note that the host address might not match what DNS tells you, and the port isn't always the same. 1355 </para> 1356 <para> 1357 The correct way to get a socks proxy host/port is a mystery, and the file transfer might fail anyway. Maybe just try using dropbox instead. 1358 </para> 1359 </description> 1360 </bitlbee-setting> 1361 1326 1362 <bitlbee-setting name="query_order" type="string" scope="global"> 1327 1363 <default>lifo</default> … … 1384 1420 </bitlbee-setting> 1385 1421 1422 <bitlbee-setting name="self_messages" type="string" scope="global"> 1423 <default>true</default> 1424 <possible-values>true, false, prefix, prefix_notice</possible-values> 1425 1426 <description> 1427 <para> 1428 Change this setting to customize how (or whether) to show self-messages, which are messages sent by yourself from other locations (for example, mobile clients), for IM protocols that support it. 1429 </para> 1430 1431 <para> 1432 When this is set to "true", it will send those messages in the "standard" way, which is a PRIVMSG with source and target fields swapped. 1433 </para> 1434 1435 <para> 1436 Since this isn't very well supported by some clients (the messages might appear in the wrong window), you can set it to "prefix" to show them as a normal message prefixed with "-> ", or use "prefix_notice" which is the same thing but with a NOTICE instead. 1437 </para> 1438 1439 <para> 1440 You can also set it to "false" to disable these messages completely. 1441 </para> 1442 1443 <para> 1444 This setting only applies to private messages. Self messages in groupchats are always shown, since they haven't caused issues in any clients so far. 1445 </para> 1446 1447 <para> 1448 More information: <emphasis>https://wiki.bitlbee.org/SelfMessages</emphasis> 1449 </para> 1450 </description> 1451 </bitlbee-setting> 1452 1386 1453 <bitlbee-setting name="server" type="string" scope="account"> 1387 1454 <description> … … 1417 1484 1418 1485 <bitlbee-setting name="show_users" type="string" scope="channel"> 1419 <default>online+, away</default>1486 <default>online+,special%,away</default> 1420 1487 1421 1488 <description> … … 1424 1491 and any modes they should have. The following statuses are currently 1425 1492 recognised: <emphasis>online</emphasis> (i.e. available, not 1426 away), <emphasis>away</emphasis>, and <emphasis>offline</emphasis>. 1493 away), <emphasis>special</emphasis>, <emphasis>away</emphasis>, 1494 and <emphasis>offline</emphasis>. 1427 1495 </para> 1428 1496 … … 1430 1498 If a status is followed by a valid channel mode character 1431 1499 (@, % or +), it will be given to users with that status. 1432 For example, <emphasis>online@, away+,offline</emphasis> will1433 show all users in the channel. Online people will1500 For example, <emphasis>online@,special%,away+,offline</emphasis> 1501 will show all users in the channel. Online people will 1434 1502 have +o, people who are online but away will have +v, 1435 1503 and others will have no special modes. … … 1891 1959 1892 1960 <description> 1893 <para>Rejects all incoming (not already transferring) file transfers. Since you probably have only one incoming transfer at a time, no id is nec cessary. Or is it?</para>1961 <para>Rejects all incoming (not already transferring) file transfers. Since you probably have only one incoming transfer at a time, no id is necessary. Or is it?</para> 1894 1962 </description> 1895 1963 -
doc/user-guide/misc.xml
r63cad66 r3fbce97 90 90 91 91 <para> 92 Away states have different names ac cross different protocols. BitlBee will try to pick the best available option for every connection:92 Away states have different names across different protocols. BitlBee will try to pick the best available option for every connection: 93 93 </para> 94 94 … … 146 146 147 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 ac cross several channels.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 across several channels. 149 149 </para> 150 150 -
doc/user-guide/quickstart.xml
r63cad66 r3fbce97 11 11 12 12 <para> 13 You need register so that all your IM settings (passwords, contacts, etc) can be saved on the BitlBee server. It's important that you pick a good password so no one else can access your account. Register with this password using the <emphasis>register</emphasis> command: <emphasis>register <password></emphasis> (without the brackets!).13 You need to register so that all your IM settings (passwords, contacts, etc) can be saved on the BitlBee server. It's important that you pick a good password so no one else can access your account. Register with this password using the <emphasis>register</emphasis> command: <emphasis>register <password></emphasis> (without the brackets!). 14 14 </para> 15 15 -
help.c
r63cad66 r3fbce97 105 105 h = *help; 106 106 while (h) { 107 if (h->fd != last_fd) { 107 if (h->fd == -1) { 108 g_free(h->offset.mem_offset); 109 } else if (h->fd != last_fd) { 108 110 close(h->fd); 109 111 last_fd = h->fd; … … 146 148 if (lseek(h->fd, h->offset.file_offset, SEEK_SET) == -1 || 147 149 read(h->fd, s, h->length) != h->length) { 150 g_free(s); 148 151 return NULL; 149 152 } -
ipc.c
r63cad66 r3fbce97 590 590 } 591 591 592 *recv_fd = *(int *) CMSG_DATA(cmsg);592 memcpy(recv_fd, CMSG_DATA(cmsg), sizeof(int)); 593 593 /* 594 594 fprintf( stderr, "pid %d received fd %d\n", (int) getpid(), *recv_fd ); … … 758 758 cmsg->cmsg_type = SCM_RIGHTS; 759 759 cmsg->cmsg_len = CMSG_LEN(sizeof(send_fd)); 760 *(int *) CMSG_DATA(cmsg) = send_fd;760 memcpy(CMSG_DATA(cmsg), &send_fd, sizeof(int)); 761 761 msg.msg_controllen = cmsg->cmsg_len; 762 762 #endif -
irc.c
r63cad66 r3fbce97 129 129 s = set_add(&b->set, "show_offline", "false", set_eval_bw_compat, irc); 130 130 s->flags |= SET_HIDDEN; 131 s = set_add(&b->set, "self_messages", "true", set_eval_self_messages, irc); 131 132 s = set_add(&b->set, "simulate_netsplit", "true", set_eval_bool, irc); 132 133 s = set_add(&b->set, "timezone", "local", set_eval_timezone, irc); … … 153 154 set_eval_charset(set_find(&b->set, "charset"), set_getstr(&b->set, "charset")); 154 155 155 irc_write(irc, ":%s NOTICE AUTH:%s", irc->root->host, "BitlBee-IRCd initialized, please go on");156 irc_write(irc, ":%s NOTICE * :%s", irc->root->host, "BitlBee-IRCd initialized, please go on"); 156 157 if (isatty(irc->fd)) { 157 irc_write(irc, ":%s NOTICE AUTH:%s", irc->root->host,158 irc_write(irc, ":%s NOTICE * :%s", irc->root->host, 158 159 "If you read this, you most likely accidentally " 159 160 "started BitlBee in inetd mode on the command line. " … … 380 381 conv = NULL; 381 382 } else { 382 irc_write(irc, ":%s NOTICE AUTH:%s", irc->root->host,383 irc_write(irc, ":%s NOTICE * :%s", irc->root->host, 383 384 "Warning: invalid characters received at login time."); 384 385 … … 727 728 int irc_check_login(irc_t *irc) 728 729 { 729 if (irc->user->user && irc->user->nick ) {730 if (irc->user->user && irc->user->nick && !(irc->status & USTATUS_CAP_PENDING)) { 730 731 if (global.conf->authmode == AUTHMODE_CLOSED && !(irc->status & USTATUS_AUTHORIZED)) { 731 732 irc_send_num(irc, 464, ":This server is password-protected."); -
irc.h
r63cad66 r3fbce97 49 49 USTATUS_SHUTDOWN = 8, /* Now used to indicate we're shutting down. 50 50 Currently just blocks irc_vawrite(). */ 51 USTATUS_CAP_PENDING = 16, 52 USTATUS_SASL_PLAIN_PENDING = 32, 51 53 52 54 /* Not really status stuff, but other kinds of flags: For slightly … … 65 67 } irc_status_t; 66 68 69 typedef enum { 70 CAP_SASL = (1 << 0), 71 CAP_MULTI_PREFIX = (1 << 1), 72 CAP_EXTENDED_JOIN = (1 << 2), 73 CAP_AWAY_NOTIFY = (1 << 3), 74 CAP_USERHOST_IN_NAMES = (1 << 4), 75 } irc_cap_flag_t; 76 67 77 struct irc_user; 68 78 … … 102 112 103 113 struct bee *b; 114 guint32 caps; 104 115 } irc_t; 105 116 … … 302 313 gboolean irc_channel_name_hint(irc_channel_t *ic, const char *name); 303 314 void irc_channel_update_ops(irc_channel_t *ic, char *value); 315 char irc_channel_user_get_prefix(irc_channel_user_t *icu); 304 316 char *set_eval_irc_channel_ops(struct set *set, char *value); 305 317 gboolean irc_channel_wants_user(irc_channel_t *ic, irc_user_t *iu); … … 331 343 irc_channel_user_flags_t old_flags, irc_channel_user_flags_t new_flags); 332 344 void irc_send_invite(irc_user_t *iu, irc_channel_t *ic); 345 void irc_send_cap(irc_t *irc, char *subcommand, char *body); 346 void irc_send_away_notify(irc_user_t *iu); 333 347 334 348 /* irc_user.c */ … … 344 358 char *set_eval_timezone(struct set *set, char *value); 345 359 char *irc_format_timestamp(irc_t *irc, time_t msg_ts); 360 char *set_eval_self_messages(struct set *set, char *value); 346 361 347 362 /* irc_im.c */ … … 349 364 void bee_irc_user_nick_reset(irc_user_t *iu); 350 365 366 /* irc_cap.c */ 367 void irc_cmd_cap(irc_t *irc, char **cmd); 368 351 369 #endif -
irc_channel.c
r63cad66 r3fbce97 213 213 } 214 214 215 /* Skip the free/init if nothing is being changed */ 216 if (ic->f == new) { 217 return value; 218 } 219 215 220 /* TODO: Return values. */ 216 221 if (ic->f && ic->f->_free) { … … 255 260 256 261 if (!(icu = irc_channel_has_user(ic, iu))) { 262 if (iu == ic->irc->user && type == IRC_CDU_KICK) { 263 /* an error happened before joining, inform the client with a numeric */ 264 irc_send_num(ic->irc, 403, "%s :Error joining channel (check control channel?)", ic->name); 265 } 257 266 return 0; 258 267 } … … 427 436 changes); 428 437 } 438 } 439 440 char irc_channel_user_get_prefix(irc_channel_user_t *icu) 441 { 442 if (icu->flags & IRC_CHANNEL_USER_OP) { 443 return '@'; 444 } else if (icu->flags & IRC_CHANNEL_USER_HALFOP) { 445 return '%'; 446 } else if (icu->flags & IRC_CHANNEL_USER_VOICE) { 447 return '+'; 448 } 449 return 0; 429 450 } 430 451 … … 593 614 594 615 translit_name = g_convert_with_fallback(hint, -1, "ASCII//TRANSLIT", "UTF-8", "", NULL, &bytes_written, NULL); 616 617 if (!translit_name) { 618 /* Same thing as in nick_gen() in nick.c, try again without //TRANSLIT */ 619 translit_name = g_convert_with_fallback(hint, -1, "ASCII", "UTF-8", "", NULL, &bytes_written, NULL); 620 } 621 622 if (!translit_name) { 623 return NULL; 624 } 625 595 626 if (bytes_written > MAX_NICK_LENGTH) { 596 627 translit_name[MAX_NICK_LENGTH] = '\0'; -
irc_commands.c
r63cad66 r3fbce97 28 28 #include "help.h" 29 29 #include "ipc.h" 30 #include "base64.h" 30 31 31 32 static void irc_cmd_pass(irc_t *irc, char **cmd) … … 55 56 irc_setpass(irc, cmd[1]); 56 57 irc_check_login(irc); 58 } 59 } 60 61 static gboolean irc_sasl_plain_parse(char *input, char **user, char **pass) 62 { 63 int i, part, len; 64 guint8 *decoded; 65 char *parts[3]; 66 67 /* bitlbee's base64_decode wrapper adds an extra null terminator at the end */ 68 len = base64_decode(input, &decoded); 69 70 /* this loop splits the decoded string into the parts array, like this: 71 "username\0username\0password" -> {"username", "username", "password"} */ 72 73 for (i = 0, part = 0; i < len && part < 3; part++) { 74 /* set each of parts[] to point to the beginning of a string */ 75 parts[part] = (char *) decoded + i; 76 77 /* move the cursor forward to the next null terminator*/ 78 i += strlen(parts[part]) + 1; 79 } 80 81 /* sanity checks */ 82 if (part != 3 || i != (len + 1) || (parts[0][0] && strcmp(parts[0], parts[1]) != 0)) { 83 g_free(decoded); 84 return FALSE; 85 } else { 86 *user = g_strdup(parts[1]); 87 *pass = g_strdup(parts[2]); 88 g_free(decoded); 89 return TRUE; 90 } 91 } 92 93 static gboolean irc_sasl_check_pass(irc_t *irc, char *user, char *pass) 94 { 95 storage_status_t status; 96 97 /* just check the password here to be able to reply with useful numerics 98 * the actual identification will be handled later */ 99 status = storage_check_pass(user, pass); 100 101 if (status == STORAGE_OK) { 102 if (!irc->user->nick) { 103 /* set the nick here so we have it for the following numeric */ 104 irc->user->nick = g_strdup(user); 105 } 106 irc_send_num(irc, 903, ":Password accepted"); 107 return TRUE; 108 109 } else if (status == STORAGE_INVALID_PASSWORD) { 110 irc_send_num(irc, 904, ":Incorrect password"); 111 } else if (status == STORAGE_NO_SUCH_USER) { 112 irc_send_num(irc, 904, ":The nick is (probably) not registered"); 113 } else { 114 irc_send_num(irc, 904, ":Unknown SASL authentication error"); 115 } 116 117 return FALSE; 118 } 119 120 static void irc_cmd_authenticate(irc_t *irc, char **cmd) 121 { 122 /* require the CAP to be enabled, and don't allow authentication before server password */ 123 if (!(irc->caps & CAP_SASL) || 124 (global.conf->authmode == AUTHMODE_CLOSED && !(irc->status & USTATUS_AUTHORIZED))) { 125 return; 126 } 127 128 if (irc->status & USTATUS_SASL_PLAIN_PENDING) { 129 char *user, *pass; 130 131 irc->status &= ~USTATUS_SASL_PLAIN_PENDING; 132 133 if (!irc_sasl_plain_parse(cmd[1], &user, &pass)) { 134 irc_send_num(irc, 904, ":SASL authentication failed"); 135 return; 136 } 137 138 /* let's not support the nick != user case 139 * if NICK is received after SASL, it will just fail after registration */ 140 if (user && irc->user->nick && strcmp(user, irc->user->nick) != 0) { 141 irc_send_num(irc, 902, ":Your SASL username does not match your nickname"); 142 143 } else if (irc_sasl_check_pass(irc, user, pass)) { 144 /* and here we do the same thing as the PASS command*/ 145 if (irc->status & USTATUS_LOGGED_IN) { 146 char *send_cmd[] = { "identify", pass, NULL }; 147 root_command(irc, send_cmd); 148 } else { 149 /* no check_login here - wait for CAP END */ 150 irc_setpass(irc, pass); 151 } 152 } 153 154 g_free(user); 155 g_free(pass); 156 157 } else if (irc->status & USTATUS_IDENTIFIED) { 158 irc_send_num(irc, 907, ":You have already authenticated"); 159 160 } else if (strcmp(cmd[1], "*") == 0) { 161 irc_send_num(irc, 906, ":SASL authentication aborted"); 162 irc->status &= ~USTATUS_SASL_PLAIN_PENDING; 163 164 } else if (g_strcasecmp(cmd[1], "PLAIN") == 0) { 165 irc_write(irc, "AUTHENTICATE +"); 166 irc->status |= USTATUS_SASL_PLAIN_PENDING; 167 168 } else { 169 irc_send_num(irc, 908, "PLAIN :is the available SASL mechanism"); 170 irc_send_num(irc, 904, ":SASL authentication failed"); 171 irc->status &= ~USTATUS_SASL_PLAIN_PENDING; 57 172 } 58 173 } … … 83 198 irc->status &= ~USTATUS_IDENTIFIED; 84 199 irc_umode_set(irc, "-R", 1); 200 201 if (irc->caps & CAP_SASL) { 202 irc_send_num(irc, 901, "%s!%s@%s :You are now logged out", 203 irc->user->nick, irc->user->user, irc->user->host); 204 } 205 85 206 irc_rootmsg(irc, "Changing nicks resets your identify status. " 86 207 "Re-identify or register a new account if you want " … … 685 806 686 807 static const command_t irc_commands[] = { 808 { "cap", 1, irc_cmd_cap, 0 }, 687 809 { "pass", 1, irc_cmd_pass, 0 }, 688 810 { "user", 4, irc_cmd_user, IRC_CMD_PRE_LOGIN }, … … 721 843 { "restart", 0, NULL, IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER }, 722 844 { "kill", 2, NULL, IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER }, 845 { "authenticate", 1, irc_cmd_authenticate, 0 }, 723 846 { NULL } 724 847 }; -
irc_im.c
r63cad66 r3fbce97 84 84 } 85 85 86 while ((s = strchr(iu->user, ' '))) {87 *s = '_';88 }86 /* Sanitize */ 87 str_reject_chars(iu->user, " ", '_'); 88 str_reject_chars(iu->host, " ", '_'); 89 89 90 90 if (bu->flags & BEE_USER_LOCAL) { … … 118 118 if (bu->flags & BEE_USER_AWAY || !(bu->flags & BEE_USER_ONLINE)) { 119 119 iu->flags |= IRC_USER_AWAY; 120 } 121 122 if ((irc->caps & CAP_AWAY_NOTIFY) && 123 ((bu->flags & BEE_USER_AWAY) != (old->flags & BEE_USER_AWAY) || 124 (bu->flags & BEE_USER_ONLINE) != (old->flags & BEE_USER_ONLINE))) { 125 irc_send_away_notify(iu); 120 126 } 121 127 … … 201 207 } 202 208 203 static gboolean bee_irc_user_msg(bee_t *bee, bee_user_t *bu, const char *msg_, time_t sent_at)209 static gboolean bee_irc_user_msg(bee_t *bee, bee_user_t *bu, const char *msg_, guint32 flags, time_t sent_at) 204 210 { 205 211 irc_t *irc = bee->ui_data; 206 212 irc_user_t *iu = (irc_user_t *) bu->ui_data; 213 irc_user_t *src_iu = iu; 214 irc_user_t *dst_iu = irc->user; 207 215 const char *dst; 208 216 char *prefix = NULL; 209 217 char *wrapped, *ts = NULL; 210 218 char *msg = g_strdup(msg_); 219 char *message_type = "PRIVMSG"; 211 220 GSList *l; 212 221 … … 216 225 217 226 dst = irc_user_msgdest(iu); 218 if (dst != irc->user->nick) { 219 /* if not messaging directly, call user by name */ 220 prefix = g_strdup_printf("%s%s%s", irc->user->nick, set_getstr(&bee->set, "to_char"), ts ? : ""); 227 228 if (flags & OPT_SELFMESSAGE) { 229 char *setting = set_getstr(&irc->b->set, "self_messages"); 230 231 if (is_bool(setting)) { 232 if (bool2int(setting)) { 233 /* set to true, send it with src/dst flipped */ 234 235 dst_iu = iu; 236 src_iu = irc->user; 237 238 if (dst == irc->user->nick) { 239 dst = dst_iu->nick; 240 } 241 } else { 242 /* set to false, skip the message completely */ 243 goto cleanup; 244 } 245 } else if (g_strncasecmp(setting, "prefix", 6) == 0) { 246 /* third state, prefix, loosely imitates the znc privmsg_prefix module */ 247 248 g_free(msg); 249 if (g_strncasecmp(msg_, "/me ", 4) == 0) { 250 msg = g_strdup_printf("/me -> %s", msg_ + 4); 251 } else { 252 msg = g_strdup_printf("-> %s", msg_); 253 } 254 255 if (g_strcasecmp(setting, "prefix_notice") == 0) { 256 message_type = "NOTICE"; 257 } 258 } 259 260 } 261 262 if (dst != dst_iu->nick) { 263 /* if not messaging directly (control channel), call user by name */ 264 prefix = g_strdup_printf("%s%s%s", dst_iu->nick, set_getstr(&bee->set, "to_char"), ts ? : ""); 221 265 } else { 222 266 prefix = ts; … … 249 293 250 294 wrapped = word_wrap(msg, 425); 251 irc_send_msg( iu, "PRIVMSG", dst, wrapped, prefix);295 irc_send_msg(src_iu, message_type, dst, wrapped, prefix); 252 296 g_free(wrapped); 253 297 … … 260 304 } 261 305 262 static gboolean bee_irc_user_typing(bee_t *bee, bee_user_t *bu, uint32_tflags)306 static gboolean bee_irc_user_typing(bee_t *bee, bee_user_t *bu, guint32 flags) 263 307 { 264 308 irc_t *irc = (irc_t *) bee->ui_data; … … 617 661 } 618 662 619 static gboolean bee_irc_chat_msg(bee_t *bee, struct groupchat *c, bee_user_t *bu, const char *msg, time_t sent_at)663 static gboolean bee_irc_chat_msg(bee_t *bee, struct groupchat *c, bee_user_t *bu, const char *msg, guint32 flags, time_t sent_at) 620 664 { 621 665 irc_t *irc = bee->ui_data; 622 irc_user_t *iu = bu->ui_data;666 irc_user_t *iu = flags & OPT_SELFMESSAGE ? irc->user : bu->ui_data; 623 667 irc_channel_t *ic = c->ui_data; 624 668 char *wrapped, *ts = NULL; … … 654 698 } 655 699 656 static gboolean bee_irc_chat_remove_user(bee_t *bee, struct groupchat *c, bee_user_t *bu )700 static gboolean bee_irc_chat_remove_user(bee_t *bee, struct groupchat *c, bee_user_t *bu, const char *reason) 657 701 { 658 702 irc_t *irc = bee->ui_data; … … 666 710 using imcb_chat_free() and the channel was IRC_CHANNEL_TEMP, we get into 667 711 a broken state around here. */ 668 irc_channel_del_user(ic, bu == bee->user ? irc->user : bu->ui_data, IRC_CDU_PART, NULL);712 irc_channel_del_user(ic, bu == bee->user ? irc->user : bu->ui_data, IRC_CDU_PART, reason); 669 713 670 714 return TRUE; … … 839 883 acc->prpl->chat_join) { 840 884 char *nick; 885 struct groupchat *gc; 841 886 842 887 if (!(nick = set_getstr(&ic->set, "nick"))) { … … 845 890 846 891 ic->flags |= IRC_CHANNEL_CHAT_PICKME; 847 acc->prpl->chat_join(acc->ic, room, nick, NULL, &ic->set);892 gc = acc->prpl->chat_join(acc->ic, room, nick, NULL, &ic->set); 848 893 ic->flags &= ~IRC_CHANNEL_CHAT_PICKME; 894 895 if (!gc) { 896 irc_send_num(ic->irc, 403, "%s :Error joining channel (check control channel?)", ic->name); 897 } 849 898 850 899 return FALSE; … … 863 912 } 864 913 865 /* Remove the reference. We don't need it anymore. */ 866 ic->data = NULL; 914 if (!(ic->flags & IRC_CHANNEL_TEMP)) { 915 /* Remove the reference. 916 * We only need it for temp channels that are being freed */ 917 ic->data = NULL; 918 } 867 919 868 920 return TRUE; … … 1055 1107 df->proto_finished = TRUE; 1056 1108 } 1109 } 1110 1111 static void bee_irc_log(bee_t *bee, const char *tag, const char *msg) 1112 { 1113 irc_t *irc = (irc_t *) bee->ui_data; 1114 1115 irc_rootmsg(irc, "%s - %s", tag, msg); 1057 1116 } 1058 1117 … … 1085 1144 bee_irc_ft_close, 1086 1145 bee_irc_ft_finished, 1146 1147 bee_irc_log, 1087 1148 }; -
irc_send.c
r63cad66 r3fbce97 172 172 irc_t *irc = ic->irc; 173 173 174 irc_write(irc, ":%s!%s@%s JOIN :%s", iu->nick, iu->user, iu->host, ic->name); 174 if (irc->caps & CAP_EXTENDED_JOIN) { 175 irc_write(irc, ":%s!%s@%s JOIN %s * :%s", iu->nick, iu->user, iu->host, ic->name, iu->fullname); 176 } else { 177 irc_write(irc, ":%s!%s@%s JOIN :%s", iu->nick, iu->user, iu->host, ic->name); 178 } 175 179 176 180 if (iu == irc->user) { … … 198 202 } 199 203 204 #define IRC_NAMES_LEN 385 205 200 206 void irc_send_names(irc_channel_t *ic) 201 207 { 202 208 GSList *l; 203 char namelist[385] = ""; 209 GString *namelist = g_string_sized_new(IRC_NAMES_LEN); 210 gboolean uhnames = (ic->irc->caps & CAP_USERHOST_IN_NAMES); 204 211 205 212 /* RFCs say there is no error reply allowed on NAMES, so when the … … 208 215 irc_channel_user_t *icu = l->data; 209 216 irc_user_t *iu = icu->iu; 210 211 if (strlen(namelist) + strlen(iu->nick) > sizeof(namelist) - 4) { 212 irc_send_num(ic->irc, 353, "= %s :%s", ic->name, namelist); 213 *namelist = 0; 214 } 215 216 if (icu->flags & IRC_CHANNEL_USER_OP) { 217 strcat(namelist, "@"); 218 } else if (icu->flags & IRC_CHANNEL_USER_HALFOP) { 219 strcat(namelist, "%"); 220 } else if (icu->flags & IRC_CHANNEL_USER_VOICE) { 221 strcat(namelist, "+"); 222 } 223 224 strcat(namelist, iu->nick); 225 strcat(namelist, " "); 226 } 227 228 if (*namelist) { 229 irc_send_num(ic->irc, 353, "= %s :%s", ic->name, namelist); 217 size_t extra_len = strlen(iu->nick); 218 char prefix; 219 220 if (uhnames) { 221 extra_len += strlen(iu->user) + strlen(iu->host) + 2; 222 } 223 224 if (namelist->len + extra_len > IRC_NAMES_LEN - 4) { 225 irc_send_num(ic->irc, 353, "= %s :%s", ic->name, namelist->str); 226 g_string_truncate(namelist, 0); 227 } 228 229 if ((prefix = irc_channel_user_get_prefix(icu))) { 230 g_string_append_c(namelist, prefix); 231 } 232 233 if (uhnames) { 234 g_string_append_printf(namelist, "%s!%s@%s ", iu->nick, iu->user, iu->host); 235 } else { 236 g_string_append(namelist, iu->nick); 237 g_string_append_c(namelist, ' '); 238 } 239 } 240 241 if (namelist->len) { 242 irc_send_num(ic->irc, 353, "= %s :%s", ic->name, namelist->str); 230 243 } 231 244 232 245 irc_send_num(ic->irc, 366, "%s :End of /NAMES list", ic->name); 246 247 g_string_free(namelist, TRUE); 233 248 } 234 249 … … 249 264 } 250 265 266 /* msg1 and msg2 are output parameters. If msg2 is non-null, msg1 is guaranteed to be non-null too. 267 The idea is to defer the formatting of "$msg1 ($msg2)" to later calls to avoid a g_strdup_printf() here. */ 268 static void get_status_message(bee_user_t *bu, char **msg1, char **msg2) 269 { 270 *msg1 = NULL; 271 *msg2 = NULL; 272 273 if (!(bu->flags & BEE_USER_ONLINE)) { 274 *msg1 = "User is offline"; 275 276 } else if ((bu->status && *bu->status) || 277 (bu->status_msg && *bu->status_msg)) { 278 279 if (bu->status && bu->status_msg) { 280 *msg1 = bu->status; 281 *msg2 = bu->status_msg; 282 } else { 283 *msg1 = bu->status ? : bu->status_msg; 284 } 285 } 286 287 if (*msg1 && !**msg1) { 288 *msg1 = (bu->flags & BEE_USER_AWAY) ? "Away" : NULL; 289 } 290 } 291 251 292 void irc_send_whois(irc_user_t *iu) 252 293 { … … 258 299 if (iu->bu) { 259 300 bee_user_t *bu = iu->bu; 301 char *msg1, *msg2; 302 int num; 260 303 261 304 irc_send_num(irc, 312, "%s %s.%s :%s network", iu->nick, bu->ic->acc->user, … … 263 306 bu->ic->acc->prpl->name); 264 307 265 if ((bu->status && *bu->status) || 266 (bu->status_msg && *bu->status_msg)) { 267 int num = bu->flags & BEE_USER_AWAY ? 301 : 320; 268 269 if (bu->status && bu->status_msg) { 270 irc_send_num(irc, num, "%s :%s (%s)", iu->nick, bu->status, bu->status_msg); 271 } else { 272 irc_send_num(irc, num, "%s :%s", iu->nick, bu->status ? : bu->status_msg); 273 } 274 } else if (!(bu->flags & BEE_USER_ONLINE)) { 275 irc_send_num(irc, 301, "%s :%s", iu->nick, "User is offline"); 308 num = (bu->flags & BEE_USER_AWAY || !(bu->flags & BEE_USER_ONLINE)) ? 301 : 320; 309 310 get_status_message(bu, &msg1, &msg2); 311 312 if (msg1 && msg2) { 313 irc_send_num(irc, num, "%s :%s (%s)", iu->nick, msg1, msg2); 314 } else if (msg1) { 315 irc_send_num(irc, num, "%s :%s", iu->nick, msg1); 276 316 } 277 317 … … 294 334 295 335 while (l) { 296 irc_user_t *iu = l->data; 336 irc_user_t *iu; 337 338 /* Null terminated string with three chars, respectively: 339 * { <H|G>, <@|%|+|\0>, \0 } */ 340 char status_prefix[3] = {0}; 341 297 342 if (is_channel) { 298 iu = ((irc_channel_user_t *) iu)->iu; 299 } 300 /* TODO(wilmer): Restore away/channel information here */ 301 irc_send_num(irc, 352, "%s %s %s %s %s %c :0 %s", 343 irc_channel_user_t *icu = l->data; 344 status_prefix[1] = irc_channel_user_get_prefix(icu); 345 iu = icu->iu; 346 } else { 347 iu = l->data; 348 } 349 350 /* rfc1459 doesn't mention this: G means gone, H means here */ 351 status_prefix[0] = iu->flags & IRC_USER_AWAY ? 'G' : 'H'; 352 353 irc_send_num(irc, 352, "%s %s %s %s %s %s :0 %s", 302 354 is_channel ? channel : "*", iu->user, iu->host, irc->root->host, 303 iu->nick, iu->flags & IRC_USER_AWAY ? 'G' : 'H', 304 iu->fullname); 355 iu->nick, status_prefix, iu->fullname); 305 356 l = l->next; 306 357 } … … 428 479 iu->nick, iu->user, iu->host, irc->user->nick, ic->name); 429 480 } 481 482 void irc_send_cap(irc_t *irc, char *subcommand, char *body) 483 { 484 char *nick = irc->user->nick ? : "*"; 485 486 irc_write(irc, ":%s CAP %s %s :%s", irc->root->host, nick, subcommand, body); 487 } 488 489 void irc_send_away_notify(irc_user_t *iu) 490 { 491 bee_user_t *bu = iu->bu; 492 493 if (!bu) { 494 return; 495 } 496 497 if (bu->flags & BEE_USER_AWAY || !(bu->flags & BEE_USER_ONLINE)) { 498 char *msg1, *msg2; 499 500 get_status_message(bu, &msg1, &msg2); 501 502 if (msg2) { 503 irc_write(iu->irc, ":%s!%s@%s AWAY :%s (%s)", iu->nick, iu->user, iu->host, msg1, msg2); 504 } else { 505 irc_write(iu->irc, ":%s!%s@%s AWAY :%s", iu->nick, iu->user, iu->host, msg1); 506 } 507 } else { 508 irc_write(iu->irc, ":%s!%s@%s AWAY", iu->nick, iu->user, iu->host); 509 } 510 } 511 -
irc_util.c
r63cad66 r3fbce97 119 119 } 120 120 } 121 122 123 char *set_eval_self_messages(set_t *set, char *value) 124 { 125 if (is_bool(value) || 126 g_strcasecmp(value, "prefix") == 0 || 127 g_strcasecmp(value, "prefix_notice") == 0) { 128 return value; 129 } else { 130 return SET_INVALID; 131 } 132 } -
lib/http_client.c
r63cad66 r3fbce97 162 162 } 163 163 164 req->func(req); 164 if (req->func != NULL) { 165 req->func(req); 166 } 165 167 http_free(req); 166 168 return FALSE; … … 299 301 } 300 302 301 req->func(req); 303 if (req->func != NULL) { 304 req->func(req); 305 } 302 306 http_free(req); 303 307 return FALSE; … … 412 416 } 413 417 414 if ((req->flags & HTTPC_STREAMING) && req->reply_body ) {418 if ((req->flags & HTTPC_STREAMING) && req->reply_body && req->func != NULL) { 415 419 req->func(req); 416 420 } … … 696 700 ssl_disconnect(req->ssl); 697 701 } else { 698 closesocket(req->fd);702 proxy_disconnect(req->fd); 699 703 } 700 704 -
lib/ini.c
r63cad66 r3fbce97 28 28 ini_t *ini_open(char *file) 29 29 { 30 int fd ;30 int fd = -1; 31 31 ini_t *ini = NULL; 32 32 struct stat fi; 33 33 34 if ( (fd = open(file, O_RDONLY)) != -1 &&34 if (file && (fd = open(file, O_RDONLY)) != -1 && 35 35 fstat(fd, &fi) == 0 && 36 36 fi.st_size <= 16384 && -
lib/misc.c
r63cad66 r3fbce97 187 187 } else if (g_strncasecmp(cs + 1, "br", taglen) == 0) { 188 188 *(s++) = '\n'; 189 } else if (g_strncasecmp(cs + 1, "br/", taglen) == 0) { 190 *(s++) = '\n'; 191 } else if (g_strncasecmp(cs + 1, "br /", taglen) == 0) { 192 *(s++) = '\n'; 189 193 } 190 194 in++; … … 295 299 296 300 /* Warning: This one explodes the string. Worst-cases can make the string 3x its original size! */ 297 /* This fu ction is safe, but make sure you call it safely as well! */301 /* This function is safe, but make sure you call it safely as well! */ 298 302 void http_encode(char *s) 299 303 { … … 767 771 } 768 772 773 /* Filters all the characters in 'blacklist' replacing them with 'replacement'. 774 * Modifies the string in-place and returns the string itself. 775 * For the opposite, use g_strcanon() */ 776 char *str_reject_chars(char *string, const char *reject, char replacement) 777 { 778 char *c = string; 779 780 while (*c) { 781 c += strcspn(c, reject); 782 if (*c) { 783 *c = replacement; 784 } 785 } 786 787 return string; 788 } -
lib/misc.h
r63cad66 r3fbce97 150 150 G_MODULE_EXPORT int truncate_utf8(char *string, int maxlen); 151 151 G_MODULE_EXPORT gboolean parse_int64(char *string, int base, guint64 *number); 152 G_MODULE_EXPORT char *str_reject_chars(char *string, const char *reject, char replacement); 152 153 153 154 #endif -
lib/proxy.c
r63cad66 r3fbce97 51 51 #endif 52 52 53 static GHashTable *phb_hash = NULL; 54 53 55 struct PHB { 54 56 b_event_handler func, proxy_func; … … 61 63 }; 62 64 65 typedef int (*proxy_connect_func)(const char *host, unsigned short port_, struct PHB *phb); 66 63 67 static int proxy_connect_none(const char *host, unsigned short port_, struct PHB *phb); 64 68 65 static gboolean phb_close(struct PHB *phb) 66 { 67 close(phb->fd); 68 phb->func(phb->data, -1, B_EV_IO_READ); 69 static gboolean phb_free(struct PHB *phb, gboolean success) 70 { 71 g_hash_table_remove(phb_hash, &phb->fd); 72 73 if (!success) { 74 if (phb->fd > 0) { 75 closesocket(phb->fd); 76 } 77 if (phb->func) { 78 phb->func(phb->data, -1, B_EV_IO_READ); 79 } 80 } 81 if (phb->gai) { 82 freeaddrinfo(phb->gai); 83 } 69 84 g_free(phb->host); 70 85 g_free(phb); … … 89 104 dup2(new_fd, source); 90 105 closesocket(new_fd); 106 phb->fd = source; 91 107 phb->inpa = b_input_add(source, B_EV_IO_WRITE, proxy_connected, phb); 92 108 return FALSE; … … 101 117 102 118 freeaddrinfo(phb->gai); 119 phb->gai = NULL; 120 103 121 b_event_remove(phb->inpa); 104 122 phb->inpa = 0; 123 105 124 if (phb->proxy_func) { 106 125 phb->proxy_func(phb->proxy_data, source, B_EV_IO_READ); 107 126 } else { 108 127 phb->func(phb->data, source, B_EV_IO_READ); 109 g_free(phb);128 phb_free(phb, TRUE); 110 129 } 111 130 … … 171 190 172 191 if (fd < 0 && host) { 173 g_free(phb);192 phb_free(phb, TRUE); 174 193 } 175 194 … … 204 223 (memcmp(HTTP_GOODSTRING2, inputline, strlen(HTTP_GOODSTRING2)) == 0)) { 205 224 phb->func(phb->data, source, B_EV_IO_READ); 206 g_free(phb->host); 207 g_free(phb); 208 return FALSE; 209 } 210 211 return phb_close(phb); 225 return phb_free(phb, TRUE); 226 } 227 228 return phb_free(phb, FALSE); 212 229 } 213 230 … … 224 241 len = sizeof(error); 225 242 if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { 226 return phb_ close(phb);243 return phb_free(phb, FALSE); 227 244 } 228 245 sock_make_blocking(source); … … 231 248 phb->host, phb->port); 232 249 if (send(source, cmd, strlen(cmd), 0) < 0) { 233 return phb_ close(phb);250 return phb_free(phb, FALSE); 234 251 } 235 252 … … 242 259 g_free(t2); 243 260 if (send(source, cmd, strlen(cmd), 0) < 0) { 244 return phb_ close(phb);261 return phb_free(phb, FALSE); 245 262 } 246 263 } … … 248 265 g_snprintf(cmd, sizeof(cmd), "\r\n"); 249 266 if (send(source, cmd, strlen(cmd), 0) < 0) { 250 return phb_ close(phb);267 return phb_free(phb, FALSE); 251 268 } 252 269 … … 279 296 if (read(source, packet, 9) >= 4 && packet[1] == 90) { 280 297 phb->func(phb->data, source, B_EV_IO_READ); 281 g_free(phb->host); 282 g_free(phb); 283 return FALSE; 284 } 285 286 return phb_close(phb); 298 return phb_free(phb, TRUE); 299 } 300 301 return phb_free(phb, FALSE); 287 302 } 288 303 … … 294 309 socklen_t len; 295 310 int error = ETIMEDOUT; 311 gboolean is_socks4a = (proxytype == PROXY_SOCKS4A); 296 312 297 313 if (phb->inpa > 0) { … … 300 316 len = sizeof(error); 301 317 if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { 302 return phb_ close(phb);318 return phb_free(phb, FALSE); 303 319 } 304 320 sock_make_blocking(source); 305 321 306 /* XXX does socks4 not support host name lookups by the proxy? */ 307 if (!(hp = gethostbyname(phb->host))) { 308 return phb_close(phb); 322 if (!is_socks4a && !(hp = gethostbyname(phb->host))) { 323 return phb_free(phb, FALSE); 309 324 } 310 325 … … 313 328 packet[2] = phb->port >> 8; 314 329 packet[3] = phb->port & 0xff; 315 packet[4] = (unsigned char) (hp->h_addr_list[0])[0]; 316 packet[5] = (unsigned char) (hp->h_addr_list[0])[1]; 317 packet[6] = (unsigned char) (hp->h_addr_list[0])[2]; 318 packet[7] = (unsigned char) (hp->h_addr_list[0])[3]; 330 if (is_socks4a) { 331 packet[4] = 0; 332 packet[5] = 0; 333 packet[6] = 0; 334 packet[7] = 1; 335 } else { 336 packet[4] = (unsigned char) (hp->h_addr_list[0])[0]; 337 packet[5] = (unsigned char) (hp->h_addr_list[0])[1]; 338 packet[6] = (unsigned char) (hp->h_addr_list[0])[2]; 339 packet[7] = (unsigned char) (hp->h_addr_list[0])[3]; 340 } 319 341 packet[8] = 0; 320 342 if (write(source, packet, 9) != 9) { 321 return phb_close(phb); 343 return phb_free(phb, FALSE); 344 } 345 346 if (is_socks4a) { 347 size_t host_len = strlen(phb->host) + 1; /* include the \0 */ 348 349 if (write(source, phb->host, host_len) != host_len) { 350 return phb_free(phb, FALSE); 351 } 322 352 } 323 353 … … 348 378 349 379 if (read(source, buf, 10) < 10) { 350 return phb_ close(phb);380 return phb_free(phb, FALSE); 351 381 } 352 382 if ((buf[0] != 0x05) || (buf[1] != 0x00)) { 353 return phb_ close(phb);383 return phb_free(phb, FALSE); 354 384 } 355 385 356 386 phb->func(phb->data, source, B_EV_IO_READ); 357 g_free(phb->host); 358 g_free(phb); 359 360 return FALSE; 387 return phb_free(phb, TRUE); 361 388 } 362 389 … … 377 404 378 405 if (write(source, buf, (5 + strlen(phb->host) + 2)) < (5 + strlen(phb->host) + 2)) { 379 phb_ close(phb);406 phb_free(phb, FALSE); 380 407 return; 381 408 } … … 392 419 393 420 if (read(source, buf, 2) < 2) { 394 return phb_ close(phb);421 return phb_free(phb, FALSE); 395 422 } 396 423 397 424 if ((buf[0] != 0x01) || (buf[1] != 0x00)) { 398 return phb_ close(phb);425 return phb_free(phb, FALSE); 399 426 } 400 427 … … 412 439 413 440 if (read(source, buf, 2) < 2) { 414 return phb_ close(phb);441 return phb_free(phb, FALSE); 415 442 } 416 443 417 444 if ((buf[0] != 0x05) || (buf[1] == 0xff)) { 418 return phb_ close(phb);445 return phb_free(phb, FALSE); 419 446 } 420 447 … … 427 454 memcpy(buf + 2 + i + 1, proxypass, j); 428 455 if (write(source, buf, 3 + i + j) < 3 + i + j) { 429 return phb_ close(phb);456 return phb_free(phb, FALSE); 430 457 } 431 458 … … 451 478 len = sizeof(error); 452 479 if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { 453 return phb_ close(phb);480 return phb_free(phb, FALSE); 454 481 } 455 482 sock_make_blocking(source); … … 469 496 470 497 if (write(source, buf, i) < i) { 471 return phb_ close(phb);498 return phb_free(phb, FALSE); 472 499 } 473 500 … … 487 514 } 488 515 516 static const proxy_connect_func proxy_connect_funcs_array[] = { 517 proxy_connect_none, /* PROXY_NONE */ 518 proxy_connect_http, /* PROXY_HTTP */ 519 proxy_connect_socks4, /* PROXY_SOCKS4 */ 520 proxy_connect_socks5, /* PROXY_SOCKS5 */ 521 proxy_connect_socks4, /* PROXY_SOCKS4A */ 522 }; 489 523 490 524 /* Export functions */ … … 493 527 { 494 528 struct PHB *phb; 529 proxy_connect_func fun; 530 int fd; 531 532 if (!phb_hash) { 533 phb_hash = g_hash_table_new(g_int_hash, g_int_equal); 534 } 495 535 496 536 if (!host || port <= 0 || !func || strlen(host) > 128) { … … 502 542 phb->data = data; 503 543 504 if (proxytype == PROXY_NONE || !proxyhost[0] || proxyport <= 0) { 505 return proxy_connect_none(host, port, phb); 506 } else if (proxytype == PROXY_HTTP) { 507 return proxy_connect_http(host, port, phb); 508 } else if (proxytype == PROXY_SOCKS4) { 509 return proxy_connect_socks4(host, port, phb); 510 } else if (proxytype == PROXY_SOCKS5) { 511 return proxy_connect_socks5(host, port, phb); 512 } 513 514 g_free(phb); 515 return -1; 516 } 544 if (proxyhost[0] && proxyport > 0 && proxytype >= 0 && proxytype < G_N_ELEMENTS(proxy_connect_funcs_array)) { 545 fun = proxy_connect_funcs_array[proxytype]; 546 } else { 547 fun = proxy_connect_none; 548 } 549 550 fd = fun(host, port, phb); 551 552 if (fd != -1) { 553 g_hash_table_insert(phb_hash, &phb->fd, phb); 554 } 555 556 return fd; 557 } 558 559 void proxy_disconnect(int fd) 560 { 561 struct PHB *phb = g_hash_table_lookup(phb_hash, &fd); 562 563 if (!phb) { 564 /* not in the early part of the connection - just close the fd */ 565 closesocket(fd); 566 return; 567 } 568 569 if (phb->inpa) { 570 b_event_remove(phb->inpa); 571 phb->inpa = 0; 572 } 573 574 /* avoid calling the callback, which might result in double-free */ 575 phb->func = NULL; 576 577 /* close and free */ 578 phb_free(phb, FALSE); 579 } -
lib/proxy.h
r63cad66 r3fbce97 40 40 #define PROXY_SOCKS4 2 41 41 #define PROXY_SOCKS5 3 42 #define PROXY_SOCKS4A 4 42 43 43 44 extern char proxyhost[128]; … … 48 49 49 50 G_MODULE_EXPORT int proxy_connect(const char *host, int port, b_event_handler func, gpointer data); 51 G_MODULE_EXPORT void proxy_disconnect(int fd); 50 52 51 53 #endif /* _PROXY_H_ */ -
lib/ssl_gnutls.c
r63cad66 r3fbce97 455 455 } 456 456 457 closesocket(conn->fd);457 proxy_disconnect(conn->fd); 458 458 459 459 if (conn->session) { -
lib/ssl_nss.c
r63cad66 r3fbce97 226 226 if (conn->prfd) { 227 227 PR_Close(conn->prfd); 228 } 229 if (source >= 0) {228 } else if (source >= 0) { 229 /* proxy_disconnect() would be redundant here */ 230 230 closesocket(source); 231 231 } … … 305 305 if (conn->prfd) { 306 306 PR_Close(conn->prfd); 307 } else if (conn->fd) { 308 proxy_disconnect(conn->fd); 307 309 } 308 310 -
lib/ssl_openssl.c
r63cad66 r3fbce97 131 131 conn->func(conn->data, 1, NULL, cond); 132 132 if (source >= 0) { 133 closesocket(source);133 proxy_disconnect(source); 134 134 } 135 135 ssl_conn_free(conn); … … 276 276 } 277 277 278 closesocket(conn->fd);278 proxy_disconnect(conn->fd); 279 279 280 280 ssl_conn_free(conn); -
lib/url.c
r63cad66 r3fbce97 48 48 } else if (g_strncasecmp(set_url, "socks5", i - set_url) == 0) { 49 49 url->proto = PROTO_SOCKS5; 50 } else if (g_strncasecmp(set_url, "socks4a", i - set_url) == 0) { 51 url->proto = PROTO_SOCKS4A; 50 52 } else { 51 53 return 0; -
lib/url.h
r63cad66 r3fbce97 30 30 #define PROTO_SOCKS4 3 31 31 #define PROTO_SOCKS5 4 32 #define PROTO_SOCKS4A 5 32 33 #define PROTO_DEFAULT PROTO_HTTP 33 34 -
log.c
r63cad66 r3fbce97 51 51 void log_link(int level, int output) 52 52 { 53 /* I know it's ugly, but it works and I didn't feel like messing with pointer to function pointers */ 53 void (*output_function)(int level, const char *logmessage) = &log_null; 54 55 if (output == LOGOUTPUT_NULL) { 56 output_function = &log_null; 57 } else if (output == LOGOUTPUT_IRC) { 58 output_function = &log_irc; 59 } else if (output == LOGOUTPUT_SYSLOG) { 60 output_function = &log_syslog; 61 } else if (output == LOGOUTPUT_CONSOLE) { 62 output_function = &log_console; 63 } 54 64 55 65 if (level == LOGLVL_INFO) { 56 if (output == LOGOUTPUT_NULL) { 57 logoutput.informational = &log_null; 58 } else if (output == LOGOUTPUT_IRC) { 59 logoutput.informational = &log_irc; 60 } else if (output == LOGOUTPUT_SYSLOG) { 61 logoutput.informational = &log_syslog; 62 } else if (output == LOGOUTPUT_CONSOLE) { 63 logoutput.informational = &log_console; 64 } 66 logoutput.informational = output_function; 65 67 } else if (level == LOGLVL_WARNING) { 66 if (output == LOGOUTPUT_NULL) { 67 logoutput.warning = &log_null; 68 } else if (output == LOGOUTPUT_IRC) { 69 logoutput.warning = &log_irc; 70 } else if (output == LOGOUTPUT_SYSLOG) { 71 logoutput.warning = &log_syslog; 72 } else if (output == LOGOUTPUT_CONSOLE) { 73 logoutput.warning = &log_console; 74 } 68 logoutput.warning = output_function; 75 69 } else if (level == LOGLVL_ERROR) { 76 if (output == LOGOUTPUT_NULL) { 77 logoutput.error = &log_null; 78 } else if (output == LOGOUTPUT_IRC) { 79 logoutput.error = &log_irc; 80 } else if (output == LOGOUTPUT_SYSLOG) { 81 logoutput.error = &log_syslog; 82 } else if (output == LOGOUTPUT_CONSOLE) { 83 logoutput.error = &log_console; 84 } 70 logoutput.error = output_function; 85 71 } 86 72 #ifdef DEBUG 87 73 else if (level == LOGLVL_DEBUG) { 88 if (output == LOGOUTPUT_NULL) { 89 logoutput.debug = &log_null; 90 } else if (output == LOGOUTPUT_IRC) { 91 logoutput.debug = &log_irc; 92 } else if (output == LOGOUTPUT_SYSLOG) { 93 logoutput.debug = &log_syslog; 94 } else if (output == LOGOUTPUT_CONSOLE) { 95 logoutput.debug = &log_console; 96 } 74 logoutput.debug = output_function; 97 75 } 98 76 #endif -
otr.c
r63cad66 r3fbce97 187 187 /* update op/voice flag of given user according to encryption state and settings 188 188 returns 0 if neither op_buddies nor voice_buddies is set to "encrypted", 189 i.e. msgstate should be announced sep erately */189 i.e. msgstate should be announced separately */ 190 190 int otr_update_modeflags(irc_t *irc, irc_user_t *u); 191 191 … … 216 216 void otr_disconnect_all(irc_t *irc); 217 217 218 /* modifies string in-place, replacing \x03 with '?', 219 as a quick way to prevent remote users from messing with irc colors */ 220 static char *otr_filter_colors(char *msg); 221 218 222 /* functions to be called for certain events */ 219 223 static const struct irc_plugin otr_plugin; 224 225 #define OTR_COLOR_TRUSTED "03" /* green */ 226 #define OTR_COLOR_UNTRUSTED "05" /* red */ 220 227 221 228 /*** routines declared in otr.h: ***/ … … 434 441 435 442 /* don't do OTR on certain (not classic IM) protocols, e.g. twitter */ 436 if (ic->acc->prpl->options & OPT_NOOTR) { 443 if (ic->acc->prpl->options & OPT_NOOTR || 444 iu->bu->flags & BEE_USER_NOOTR) { 437 445 return msg; 438 446 } … … 451 459 } else if (!newmsg) { 452 460 /* this was a non-OTR message */ 453 return msg;461 return otr_filter_colors(msg); 454 462 } else { 455 463 /* we're done with the original msg, which will be caller-freed. */ … … 472 480 473 481 /* don't do OTR on certain (not classic IM) protocols, e.g. twitter */ 474 if (ic->acc->prpl->options & OPT_NOOTR) { 482 if (ic->acc->prpl->options & OPT_NOOTR || 483 iu->bu->flags & BEE_USER_NOOTR) { 475 484 return msg; 476 485 } … … 742 751 } 743 752 753 static char *otr_filter_colors(char *msg) 754 { 755 return str_reject_chars(msg, "\x02\x03", '?'); 756 } 757 758 /* returns newly allocated string */ 759 static char *otr_color_encrypted(char *msg, char *color, gboolean is_query) { 760 char **lines; 761 GString *out; 762 int i; 763 764 lines = g_strsplit(msg, "\n", -1); 765 766 /* up to 4 extra chars per line (e.g., '\x03' + ("03"|"05") + ' ') */ 767 out = g_string_sized_new(strlen(msg) + g_strv_length(lines) * 4); 768 769 for (i = 0; lines[i]; i++) { 770 char *line = lines[i]; 771 772 if (i != 0) { 773 g_string_append_c(out, '\n'); 774 775 } else if (is_query && g_strncasecmp(line, "/me ", 4) == 0) { 776 /* in a query window, keep "/me " uncolored at the beginning */ 777 line += 4; 778 g_string_append(out, "/me "); 779 } 780 781 g_string_append_c(out, '\x03'); 782 g_string_append(out, color); 783 784 /* comma in first place could mess with the color code */ 785 if (line[0] == ',') { 786 /* insert a space between color spec and message */ 787 g_string_append_c(out, ' '); 788 } 789 790 g_string_append(out, otr_filter_colors(line)); 791 } 792 793 g_strfreev(lines); 794 795 return g_string_free(out, FALSE); 796 } 797 744 798 void op_convert_msg(void *opdata, ConnContext *ctx, OtrlConvertType typ, 745 799 char **dst, const char *src) … … 752 806 if (typ == OTRL_CONVERT_RECEIVING) { 753 807 char *msg = g_strdup(src); 754 char *buf = msg;755 808 756 809 /* HTML decoding */ … … 759 812 set_getbool(&ic->bee->set, "strip_html")) { 760 813 strip_html(msg); 814 815 /* msg is borrowed by *dst (unless the next if decides to color it) */ 761 816 *dst = msg; 762 817 } … … 764 819 /* coloring */ 765 820 if (set_getbool(&ic->bee->set, "otr_color_encrypted")) { 766 int color; /* color according to f'print trust */767 char *pre = "", *sep = ""; /* optional parts */768 821 const char *trust = ctx->active_fingerprint->trust; 769 770 if (trust && trust[0] != '\0') { 771 color = 3; /* green */ 772 } else { 773 color = 5; /* red */ 774 775 } 776 /* in a query window, keep "/me " uncolored at the beginning */ 777 if (g_strncasecmp(msg, "/me ", 4) == 0 778 && irc_user_msgdest(iu) == irc->user->nick) { 779 msg += 4; /* skip */ 780 pre = "/me "; 781 } 782 783 /* comma in first place could mess with the color code */ 784 if (msg[0] == ',') { 785 /* insert a space between color spec and message */ 786 sep = " "; 787 } 788 789 *dst = g_strdup_printf("%s\x03%.2d%s%s\x0F", pre, 790 color, sep, msg); 791 g_free(buf); 822 char *color = (trust && *trust) ? OTR_COLOR_TRUSTED : OTR_COLOR_UNTRUSTED; 823 gboolean is_query = (irc_user_msgdest(iu) == irc->user->nick); 824 825 /* the return value of otr_color_encrypted() is borrowed by *dst */ 826 *dst = otr_color_encrypted(msg, color, is_query); 827 828 /* this branch doesn't need msg */ 829 g_free(msg); 792 830 } 793 831 } else { … … 1357 1395 1358 1396 if (u) { 1359 /* display as a notice from this particular user*/1360 irc_user notice(u, "%s", msg);1397 /* just show this as a regular message */ 1398 irc_usermsg(u, "<<\002OTR\002>> %s", msg); 1361 1399 } else { 1362 1400 irc_rootmsg(irc, "[otr] %s", msg); … … 1695 1733 *p = '\0'; 1696 1734 1735 /* remove trailing whitespace */ 1736 g_strchomp(prefix); 1737 1697 1738 /* find first key which matches the given prefix */ 1698 1739 n = strlen(prefix); -
protocols/account.c
r63cad66 r3fbce97 84 84 strstr(a->user, "@googlemail.com")) { 85 85 strcpy(tag, "gtalk"); 86 } else if (strstr(a->user, "@chat.facebook.com")) {87 strcpy(tag, "fb");88 86 } 89 87 } -
protocols/bee.h
r63cad66 r3fbce97 62 62 BEE_USER_LOCAL = 256, /* Locally-added contacts (not in real contact list) */ 63 63 BEE_USER_SPECIAL = 512, /* Denotes a user as being special */ 64 BEE_USER_NOOTR = 4096, /* Per-user version of OPT_NOOTR */ 64 65 } bee_user_flags_t; 65 66 … … 104 105 gboolean (*user_status)(bee_t *bee, struct bee_user *bu, struct bee_user *old); 105 106 /* On every incoming message. sent_at = 0 means unknown. */ 106 gboolean (*user_msg)(bee_t *bee, bee_user_t *bu, const char *msg, time_t sent_at);107 gboolean (*user_msg)(bee_t *bee, bee_user_t *bu, const char *msg, guint32 flags, time_t sent_at); 107 108 /* Flags currently defined (OPT_TYPING/THINKING) in nogaim.h. */ 108 109 gboolean (*user_typing)(bee_t *bee, bee_user_t *bu, guint32 flags); … … 117 118 /* System messages of any kind. */ 118 119 gboolean (*chat_log)(bee_t *bee, struct groupchat *c, const char *text); 119 gboolean (*chat_msg)(bee_t *bee, struct groupchat *c, bee_user_t *bu, const char *msg, time_t sent_at);120 gboolean (*chat_msg)(bee_t *bee, struct groupchat *c, bee_user_t *bu, const char *msg, guint32 flags, time_t sent_at); 120 121 gboolean (*chat_add_user)(bee_t *bee, struct groupchat *c, bee_user_t *bu); 121 gboolean (*chat_remove_user)(bee_t *bee, struct groupchat *c, bee_user_t *bu );122 gboolean (*chat_remove_user)(bee_t *bee, struct groupchat *c, bee_user_t *bu, const char *reason); 122 123 gboolean (*chat_topic)(bee_t *bee, struct groupchat *c, const char *new_topic, bee_user_t *bu); 123 124 gboolean (*chat_name_hint)(bee_t *bee, struct groupchat *c, const char *name); … … 128 129 void (*ft_close)(struct im_connection *ic, struct file_transfer *ft); 129 130 void (*ft_finished)(struct im_connection *ic, struct file_transfer *ft); 131 132 void (*log)(bee_t *bee, const char *tag, const char *msg); 130 133 } bee_ui_funcs_t; 131 134 -
protocols/bee_chat.c
r63cad66 r3fbce97 95 95 } 96 96 97 void imcb_chat_msg(struct groupchat *c, const char *who, char *msg, uint32_tflags, time_t sent_at)97 void imcb_chat_msg(struct groupchat *c, const char *who, char *msg, guint32 flags, time_t sent_at) 98 98 { 99 99 struct im_connection *ic = c->ic; 100 100 bee_t *bee = ic->bee; 101 101 bee_user_t *bu; 102 gboolean temp ;102 gboolean temp = FALSE; 103 103 char *s; 104 104 105 /* Gaim sends own messages through this too. IRC doesn't want this, so kill them */ 106 if (handle_is_self(ic, who)) { 105 if (handle_is_self(ic, who) && !(flags & OPT_SELFMESSAGE)) { 107 106 return; 108 107 } … … 122 121 123 122 if (bee->ui->chat_msg) { 124 bee->ui->chat_msg(bee, c, bu, msg, sent_at);123 bee->ui->chat_msg(bee, c, bu, msg, flags, sent_at); 125 124 } 126 125 … … 230 229 231 230 if (bee->ui->chat_remove_user && bu) { 232 bee->ui->chat_remove_user(bee, c, bu );231 bee->ui->chat_remove_user(bee, c, bu, reason); 233 232 } 234 233 } -
protocols/bee_user.c
r63cad66 r3fbce97 247 247 } 248 248 249 void imcb_buddy_msg(struct im_connection *ic, const char *handle, const char *msg, uint32_tflags, time_t sent_at)249 void imcb_buddy_msg(struct im_connection *ic, const char *handle, const char *msg, guint32 flags, time_t sent_at) 250 250 { 251 251 bee_t *bee = ic->bee; … … 265 265 266 266 if (bee->ui->user_msg && bu) { 267 bee->ui->user_msg(bee, bu, msg, sent_at);267 bee->ui->user_msg(bee, bu, msg, flags, sent_at); 268 268 } else { 269 269 imcb_log(ic, "Message from unknown handle %s:\n%s", handle, msg); … … 297 297 } 298 298 299 void imcb_buddy_typing(struct im_connection *ic, const char *handle, uint32_tflags)299 void imcb_buddy_typing(struct im_connection *ic, const char *handle, guint32 flags) 300 300 { 301 301 bee_user_t *bu; -
protocols/ft.h
r63cad66 r3fbce97 58 58 * | accept 59 59 * V 60 * /------ /-------------\ /------------------------ \61 * out_of_data | | TRANSFER ING | -----------------> | TRANSFERING | CANCELED |62 * \-----> \-------------/ [canceled,]free \------------------------ /60 * /------ /-------------\ /--------------------------\ 61 * out_of_data | | TRANSFERRING | -----------------> | TRANSFERRING | CANCELED | 62 * \-----> \-------------/ [canceled,]free \--------------------------/ 63 63 * | 64 64 * | finished,free 65 65 * V 66 * /------------------------ \67 * | TRANSFER ING | FINISHED |68 * \------------------------ /66 * /-------------------------\ 67 * | TRANSFERRING | FINISHED | 68 * \-------------------------/ 69 69 */ 70 70 typedef struct file_transfer { … … 115 115 116 116 /* 117 * If set, called after succes ful connection setup.117 * If set, called after successful connection setup. 118 118 */ 119 119 void (*accept)(struct file_transfer *file); -
protocols/jabber/conference.c
r63cad66 r3fbce97 26 26 27 27 static xt_status jabber_chat_join_failed(struct im_connection *ic, struct xt_node *node, struct xt_node *orig); 28 static xt_status jabber_chat_self_message(struct im_connection *ic, struct xt_node *node, struct xt_node *orig); 28 29 29 30 struct groupchat *jabber_chat_join(struct im_connection *ic, const char *room, const char *nick, const char *password) … … 121 122 } 122 123 if (bud) { 123 jabber_chat_free(jabber_chat_by_jid(ic, bud->bare_jid)); 124 struct groupchat *c = jabber_chat_by_jid(ic, bud->bare_jid); 125 if (c) { 126 jabber_chat_free(c); 127 } 124 128 } 125 129 126 130 return XT_HANDLED; 131 } 132 133 static xt_status jabber_chat_self_message(struct im_connection *ic, struct xt_node *node, struct xt_node *orig) 134 { 135 /* This is a self message sent by this bitlbee - just drop it */ 136 return XT_ABORT; 127 137 } 128 138 … … 171 181 node = jabber_make_packet("message", "groupchat", jc->name, node); 172 182 173 if (!jabber_write_packet(ic, node)) { 174 xt_free_node(node); 175 return 0; 176 } 177 xt_free_node(node); 178 179 return 1; 183 jabber_cache_add(ic, node, jabber_chat_self_message); 184 185 return !jabber_write_packet(ic, node); 180 186 } 181 187 … … 299 305 } 300 306 } 301 302 /* Some program-specific restrictions. */303 imcb_clean_handle(ic, bud->ext_jid);304 307 } 305 308 bud->flags |= JBFLAG_IS_ANONYMOUS; … … 331 334 } else if (type) { /* type can only be NULL or "unavailable" in this function */ 332 335 if ((bud->flags & JBFLAG_IS_CHATROOM) && bud->ext_jid) { 336 char *reason = NULL; 337 char *status = NULL; 338 char *status_text = NULL; 339 340 if ((c = xt_find_node_by_attr(node->children, "x", "xmlns", XMLNS_MUC_USER))) { 341 struct xt_node *c2 = c->children; 342 343 while ((c2 = xt_find_node(c2, "status"))) { 344 char *code = xt_find_attr(c2, "code"); 345 if (g_strcmp0(code, "301") == 0) { 346 status = "Banned"; 347 break; 348 } else if (g_strcmp0(code, "303") == 0) { 349 /* This could be handled in a cleverer way, 350 * but let's just show a literal part/join for now */ 351 status = "Changing nicks"; 352 break; 353 } else if (g_strcmp0(code, "307") == 0) { 354 status = "Kicked"; 355 break; 356 } 357 c2 = c2->next; 358 } 359 360 /* Sometimes the status message is in presence/x/item/reason */ 361 if ((c2 = xt_find_path(c, "item/reason")) && c2->text && c2->text_len) { 362 status_text = c2->text; 363 } 364 } 365 366 /* Sometimes the status message is right inside <presence> */ 367 if ((c = xt_find_node(node->children, "status")) && c->text && c->text_len) { 368 status_text = c->text; 369 } 370 371 if (status_text && status) { 372 reason = g_strdup_printf("%s: %s", status, status_text); 373 } else { 374 reason = g_strdup(status_text ? : status); 375 } 376 333 377 s = strchr(bud->ext_jid, '/'); 334 378 if (s) { 335 379 *s = 0; 336 380 } 337 imcb_chat_remove_buddy(chat, bud->ext_jid, NULL);381 imcb_chat_remove_buddy(chat, bud->ext_jid, reason); 338 382 if (bud != jc->me && bud->flags & JBFLAG_IS_ANONYMOUS) { 339 imcb_remove_buddy(ic, bud->ext_jid, NULL);383 imcb_remove_buddy(ic, bud->ext_jid, reason); 340 384 } 341 385 if (s) { 342 386 *s = '/'; 343 387 } 388 389 g_free(reason); 344 390 } 345 391 … … 360 406 char *final_from = NULL; 361 407 char *bare_jid = NULL; 408 guint32 flags = 0; 362 409 363 410 from = (bud) ? bud->full_jid : xt_find_attr(node, "from"); … … 396 443 397 444 if (subject && chat) { 398 char *subject_text = subject->text_len > 0 ? subject->text : NULL;445 char *subject_text = subject->text_len > 0 ? subject->text : ""; 399 446 if (g_strcmp0(chat->topic, subject_text) != 0) { 400 447 bare_jid = (bud) ? jabber_get_bare_jid(bud->ext_jid) : NULL; … … 402 449 jabber_get_timestamp(node)); 403 450 g_free(bare_jid); 451 bare_jid = NULL; 404 452 } 405 453 } … … 422 470 imcb_chat_log(chat, "From conference server: %s", body->text); 423 471 return; 424 } else if (jc && jc->flags & JCFLAG_MESSAGE_SENT && bud == jc->me ) {425 /* exclude self-messages since they would get filtered out426 * but not the ones in the backlog*/472 } else if (jc && jc->flags & JCFLAG_MESSAGE_SENT && bud == jc->me && 473 (jabber_cache_handle_packet(ic, node) == XT_ABORT)) { 474 /* Self message marked by this bitlbee, don't show it */ 427 475 return; 428 476 } 429 477 430 if (bud && jc && bud != jc->me) {478 if (bud) { 431 479 bare_jid = jabber_get_bare_jid(bud->ext_jid ? bud->ext_jid : bud->full_jid); 432 480 final_from = bare_jid; 481 flags = (bud == jc->me) ? OPT_SELFMESSAGE : 0; 433 482 } else { 434 483 final_from = nick; 435 484 } 436 485 437 imcb_chat_msg(chat, final_from, body->text, 0, jabber_get_timestamp(node));486 imcb_chat_msg(chat, final_from, body->text, flags, jabber_get_timestamp(node)); 438 487 439 488 g_free(bare_jid); -
protocols/jabber/hipchat.c
r63cad66 r3fbce97 42 42 *sep = '/'; 43 43 } 44 45 jd->muc_host = g_strdup(xt_find_attr(node, "muc_host")); 44 46 45 47 /* Hipchat's auth doesn't expect a restart here */ … … 92 94 93 95 } 96 97 /* Returns a newly allocated string that tries to match the "slug" part of the JID using an 98 * approximation of the method used by the server. This might fail in some rare conditions 99 * (old JIDs generated a different way, locale settings unicode, etc) */ 100 char *hipchat_make_channel_slug(const char *name) 101 { 102 char *lower; 103 char *new = g_malloc(strlen(name) + 1); 104 int i = 0; 105 106 do { 107 if (*name == ' ') { 108 new[i++] = '_'; 109 } else if (*name && !strchr("\"&'/:<>@", *name)) { 110 new[i++] = *name; 111 } 112 } while (*(name++)); 113 114 new[i] = '\0'; 115 116 lower = g_utf8_strdown(new, -1); 117 g_free(new); 118 119 return lower; 120 } 121 122 char *hipchat_guess_channel_name(struct im_connection *ic, const char *name) 123 { 124 struct jabber_data *jd = ic->proto_data; 125 char *slug, *retval, *underscore; 126 127 if (!(underscore = strchr(jd->username, '_')) || !jd->muc_host) { 128 return NULL; 129 } 130 131 slug = hipchat_make_channel_slug(name); 132 133 /* Get the organization ID from the username, before the underscore */ 134 *underscore = '\0'; 135 136 retval = g_strdup_printf("%s_%s@%s", jd->username, slug, jd->muc_host); 137 138 *underscore = '_'; 139 140 g_free(slug); 141 142 return retval; 143 } -
protocols/jabber/io.c
r63cad66 r3fbce97 147 147 } 148 148 149 static gboolean jabber_read_callback(gpointer data, gint fd, b_input_condition cond) 150 { 151 struct im_connection *ic = data; 152 struct jabber_data *jd = ic->proto_data; 153 char buf[512]; 154 int st; 155 156 if (jd->fd == -1) { 157 return FALSE; 158 } 159 160 if (jd->ssl) { 161 st = ssl_read(jd->ssl, buf, sizeof(buf)); 162 } else { 163 st = read(jd->fd, buf, sizeof(buf)); 164 } 165 166 if (st > 0) { 167 /* Parse. */ 168 if (xt_feed(jd->xt, buf, st) < 0) { 149 static gboolean jabber_feed_input(struct im_connection *ic, char *buf, int size) 150 { 151 struct jabber_data *jd = ic->proto_data; 152 153 /* Allow not passing a size for debugging purposes. 154 * This never happens when reading from the socket */ 155 if (size == -1) { 156 size = strlen(buf); 157 } 158 159 /* Parse. */ 160 if (xt_feed(jd->xt, buf, size) < 0) { 161 imcb_error(ic, "XML stream error"); 162 imc_logout(ic, TRUE); 163 return FALSE; 164 } 165 166 /* Execute all handlers. */ 167 if (!xt_handle(jd->xt, NULL, 1)) { 168 /* Don't do anything, the handlers should have 169 aborted the connection already. */ 170 return FALSE; 171 } 172 173 if (jd->flags & JFLAG_STREAM_RESTART) { 174 jd->flags &= ~JFLAG_STREAM_RESTART; 175 jabber_start_stream(ic); 176 } 177 178 /* Garbage collection. */ 179 xt_cleanup(jd->xt, NULL, 1); 180 181 /* This is a bit hackish, unfortunately. Although xmltree 182 has nifty event handler stuff, it only calls handlers 183 when nodes are complete. Since the server should only 184 send an opening <stream:stream> tag, we have to check 185 this by hand. :-( */ 186 if (!(jd->flags & JFLAG_STREAM_STARTED) && jd->xt && jd->xt->root) { 187 if (g_strcasecmp(jd->xt->root->name, "stream:stream") == 0) { 188 jd->flags |= JFLAG_STREAM_STARTED; 189 190 /* If there's no version attribute, assume 191 this is an old server that can't do SASL 192 authentication. */ 193 if (!set_getbool(&ic->acc->set, "sasl") || !sasl_supported(ic)) { 194 /* If there's no version= tag, we suppose 195 this server does NOT implement: XMPP 1.0, 196 SASL and TLS. */ 197 if (set_getbool(&ic->acc->set, "tls")) { 198 imcb_error(ic, "TLS is turned on for this " 199 "account, but is not supported by this server"); 200 imc_logout(ic, FALSE); 201 return FALSE; 202 } else { 203 if (!jabber_init_iq_auth(ic)) { 204 return FALSE; 205 } 206 } 207 } 208 } else { 169 209 imcb_error(ic, "XML stream error"); 170 210 imc_logout(ic, TRUE); 171 211 return FALSE; 172 212 } 173 174 /* Execute all handlers. */ 175 if (!xt_handle(jd->xt, NULL, 1)) { 176 /* Don't do anything, the handlers should have 177 aborted the connection already. */ 213 } 214 215 return TRUE; 216 } 217 218 219 static gboolean jabber_read_callback(gpointer data, gint fd, b_input_condition cond) 220 { 221 struct im_connection *ic = data; 222 struct jabber_data *jd = ic->proto_data; 223 char buf[512]; 224 int st; 225 226 if (jd->fd == -1) { 227 return FALSE; 228 } 229 230 if (jd->ssl) { 231 st = ssl_read(jd->ssl, buf, sizeof(buf)); 232 } else { 233 st = read(jd->fd, buf, sizeof(buf)); 234 } 235 236 if (st > 0) { 237 if (!jabber_feed_input(ic, buf, st)) { 178 238 return FALSE; 179 }180 181 if (jd->flags & JFLAG_STREAM_RESTART) {182 jd->flags &= ~JFLAG_STREAM_RESTART;183 jabber_start_stream(ic);184 }185 186 /* Garbage collection. */187 xt_cleanup(jd->xt, NULL, 1);188 189 /* This is a bit hackish, unfortunately. Although xmltree190 has nifty event handler stuff, it only calls handlers191 when nodes are complete. Since the server should only192 send an opening <stream:stream> tag, we have to check193 this by hand. :-( */194 if (!(jd->flags & JFLAG_STREAM_STARTED) && jd->xt && jd->xt->root) {195 if (g_strcasecmp(jd->xt->root->name, "stream:stream") == 0) {196 jd->flags |= JFLAG_STREAM_STARTED;197 198 /* If there's no version attribute, assume199 this is an old server that can't do SASL200 authentication. */201 if (!set_getbool(&ic->acc->set, "sasl") || !sasl_supported(ic)) {202 /* If there's no version= tag, we suppose203 this server does NOT implement: XMPP 1.0,204 SASL and TLS. */205 if (set_getbool(&ic->acc->set, "tls")) {206 imcb_error(ic, "TLS is turned on for this "207 "account, but is not supported by this server");208 imc_logout(ic, FALSE);209 return FALSE;210 } else {211 return jabber_init_iq_auth(ic);212 }213 }214 } else {215 imcb_error(ic, "XML stream error");216 imc_logout(ic, TRUE);217 return FALSE;218 }219 239 } 220 240 } else if (st == 0 || (st < 0 && !ssl_sockerr_again(jd->ssl))) { -
protocols/jabber/iq.c
r63cad66 r3fbce97 28 28 static xt_status jabber_iq_display_vcard(struct im_connection *ic, struct xt_node *node, struct xt_node *orig); 29 29 static xt_status jabber_gmail_handle_new(struct im_connection *ic, struct xt_node *node); 30 static xt_status jabber_iq_carbons_response(struct im_connection *ic, struct xt_node *node, struct xt_node *orig); 30 31 31 32 xt_status jabber_pkt_iq(struct xt_node *node, gpointer data) … … 52 53 (c = xt_find_node(node->children, "time"))) || 53 54 !(s = xt_find_attr(c, "xmlns"))) { 54 /* Sigh. Who decided to suddenly invent new elements 55 instead of just sticking with <query/>? */ 56 return XT_HANDLED; 55 56 reply = jabber_make_error_packet(node, "service-unavailable", "cancel", NULL); 57 st = jabber_write_packet(ic, reply); 58 xt_free_node(reply); 59 return st; 57 60 } 58 61 … … 118 121 XMLNS_BYTESTREAMS, 119 122 XMLNS_FILETRANSFER, 123 XMLNS_CARBONS, 120 124 NULL }; 121 125 const char **f; … … 134 138 } else { 135 139 xt_free_node(reply); 136 reply = jabber_make_error_packet(node, " feature-not-implemented", "cancel", NULL);140 reply = jabber_make_error_packet(node, "service-unavailable", "cancel", NULL); 137 141 pack = 0; 138 142 } … … 385 389 struct xt_node *response; 386 390 struct jabber_data *jd = ic->proto_data; 387 388 response = jabber_make_packet("iq", "result", g_strdup_printf("%s@%s", jd->username, jd->server), NULL);391 392 response = jabber_make_packet("iq", "result", jd->me, NULL); 389 393 390 394 jabber_cache_add(ic, response, NULL); … … 1004 1008 { 1005 1009 struct jabber_data *jd = ic->proto_data; 1006 struct xt_node *id; 1007 1008 if ((id = xt_find_path(node, "query/identity"))) { 1010 struct xt_node *query, *id; 1011 1012 if (!(query = xt_find_node(node->children, "query"))) { 1013 return XT_HANDLED; 1014 } 1015 1016 if (xt_find_node_by_attr(query->children, "feature", "var", XMLNS_CARBONS) && 1017 set_getbool(&ic->acc->set, "carbons")) { 1018 1019 struct xt_node *enable, *iq; 1020 1021 enable = xt_new_node("enable", NULL, NULL); 1022 xt_add_attr(enable, "xmlns", XMLNS_CARBONS); 1023 iq = jabber_make_packet("iq", "set", NULL, enable); 1024 1025 jabber_cache_add(ic, iq, jabber_iq_carbons_response); 1026 jabber_write_packet(ic, iq); 1027 } 1028 1029 if ((id = xt_find_node(query->children, "identity"))) { 1009 1030 char *cat, *type, *name; 1010 1031 … … 1023 1044 return XT_HANDLED; 1024 1045 } 1046 1047 static xt_status jabber_iq_carbons_response(struct im_connection *ic, 1048 struct xt_node *node, struct xt_node *orig) 1049 { 1050 struct jabber_error *err; 1051 1052 if ((err = jabber_error_parse(xt_find_node(node->children, "error"), XMLNS_STANZA_ERROR))) { 1053 imcb_error(ic, "Error enabling carbons: %s%s%s", 1054 err->code, err->text ? ": " : "", err->text ? err->text : ""); 1055 jabber_error_free(err); 1056 } else { 1057 imcb_log(ic, "Carbons enabled"); 1058 } 1059 1060 return XT_HANDLED; 1061 } -
protocols/jabber/jabber.c
r63cad66 r3fbce97 114 114 s->flags |= ACC_SET_OFFLINE_ONLY | SET_NULL_OK; 115 115 116 s = set_add(&acc->set, "carbons", "true", set_eval_bool, acc); 117 s->flags |= ACC_SET_OFFLINE_ONLY; 118 116 119 acc->flags |= ACC_FLAG_AWAY_MESSAGE | ACC_FLAG_STATUS_MESSAGE | 117 120 ACC_FLAG_HANDLE_DOMAINS; … … 148 151 } 149 152 153 if (strstr(jd->server, ".facebook.com")) { 154 imcb_error(ic, "Facebook's XMPP service is gone. Try this instead: https://wiki.bitlbee.org/HowtoFacebookMQTT"); 155 imc_logout(ic, FALSE); 156 return; 157 } 158 150 159 if ((s = strchr(jd->server, '/'))) { 151 160 *s = 0; … … 167 176 jd->fd = jd->r_inpa = jd->w_inpa = -1; 168 177 169 if (strstr(jd->server, ".facebook.com")) { 170 jd->oauth2_service = &oauth2_service_facebook; 171 } else { 172 jd->oauth2_service = &oauth2_service_google; 173 } 178 /* There are no other options atm, so assume google for everything 179 Facebook and MSN XMPP used to be here. RIP. */ 180 jd->oauth2_service = &oauth2_service_google; 174 181 175 182 oauth_params_parse(&p_in, ic->acc->pass); … … 197 204 } else { 198 205 jabber_connect(ic); 206 } 207 } 208 209 static void jabber_xmlconsole_enable(struct im_connection *ic) 210 { 211 struct jabber_data *jd = ic->proto_data; 212 const char *handle = JABBER_XMLCONSOLE_HANDLE; 213 bee_user_t *bu; 214 215 jd->flags |= JFLAG_XMLCONSOLE; 216 217 if (!(bu = bee_user_by_handle(ic->bee, ic, handle))) { 218 bu = bee_user_new(ic->bee, ic, handle, 0); 219 bu->flags |= BEE_USER_NOOTR; 199 220 } 200 221 } … … 266 287 267 288 if (set_getbool(&acc->set, "xmlconsole")) { 268 jd->flags |= JFLAG_XMLCONSOLE; 269 /* Shouldn't really do this at this stage already, maybe. But 270 I think this shouldn't break anything. */ 271 imcb_add_buddy(ic, JABBER_XMLCONSOLE_HANDLE, NULL); 289 jabber_xmlconsole_enable(ic); 272 290 } 273 291 … … 334 352 } 335 353 if (jd->fd >= 0) { 336 closesocket(jd->fd);354 proxy_disconnect(jd->fd); 337 355 } 338 356 … … 345 363 } 346 364 347 jabber_buddy_remove_all(ic); 365 if (jd->buddies) { 366 jabber_buddy_remove_all(ic); 367 } 348 368 349 369 xt_free(jd->xt); … … 355 375 g_free(jd->internal_jid); 356 376 g_free(jd->gmail_tid); 377 g_free(jd->muc_host); 357 378 g_free(jd->username); 358 379 g_free(jd->me); … … 413 434 } 414 435 436 /* XEP-0364 suggests we add message processing hints (XEP-0334) to OTR messages, 437 mostly to avoid carbons (XEP-0280) and server-side message archiving. 438 OTR messages are roughly like this: /^\?OTR(.*\?| Error:|:)/ 439 But I'm going to simplify it to messages starting with "?OTR". */ 440 if (g_str_has_prefix(message, "?OTR")) { 441 int i; 442 char *hints[] = { 443 "no-copy", XMLNS_HINTS, 444 "no-permanent-store", XMLNS_HINTS, 445 "private", XMLNS_CARBONS, 446 NULL 447 }; 448 449 for (i = 0; hints[i]; i += 2) { 450 struct xt_node *hint; 451 hint = xt_new_node(hints[i], NULL, NULL); 452 xt_add_attr(hint, "xmlns", hints[i + 1]); 453 xt_add_child(node, hint); 454 } 455 } 456 415 457 st = jabber_write_packet(ic, node); 416 458 xt_free_node(node); … … 472 514 static void jabber_add_buddy(struct im_connection *ic, char *who, char *group) 473 515 { 474 struct jabber_data *jd = ic->proto_data;475 476 516 if (g_strcasecmp(who, JABBER_XMLCONSOLE_HANDLE) == 0) { 477 jd->flags |= JFLAG_XMLCONSOLE; 478 imcb_add_buddy(ic, JABBER_XMLCONSOLE_HANDLE, NULL); 517 jabber_xmlconsole_enable(ic); 479 518 return; 480 519 } … … 520 559 } 521 560 561 if (jd->flags & JFLAG_HIPCHAT && jd->muc_host && !g_str_has_suffix(room, jd->muc_host)) { 562 char *guessed_name = hipchat_guess_channel_name(ic, room); 563 if (guessed_name) { 564 set_setstr(sets, "room", guessed_name); 565 g_free(guessed_name); 566 567 /* call this same function again with the fixed name */ 568 return jabber_chat_join_(ic, set_getstr(sets, "room"), nick, password, sets); 569 } 570 } 571 522 572 if (strchr(room, '@') == NULL) { 523 573 imcb_error(ic, "%s is not a valid Jabber room name. Maybe you mean %s@conference.%s?", … … 526 576 imcb_error(ic, "Already present in chat `%s'", room); 527 577 } else { 578 /* jabber_chat_join without the underscore is the conference.c one */ 528 579 return jabber_chat_join(ic, room, final_nick, set_getstr(sets, "password")); 529 580 } … … 590 641 { 591 642 struct jabber_data *jd = ic->proto_data; 592 struct jabber_buddy *bud ;643 struct jabber_buddy *bud, *bare; 593 644 594 645 /* Enable typing notification related code from now. */ 595 646 jd->flags |= JFLAG_WANT_TYPING; 596 647 597 if ((bud = jabber_buddy_by_jid(ic, who, 0)) == NULL) { 648 if ((bud = jabber_buddy_by_jid(ic, who, 0)) == NULL || 649 (bare = jabber_buddy_by_jid(ic, who, GET_BUDDY_BARE)) == NULL) { 598 650 /* Sending typing notifications to unknown buddies is 599 651 unsupported for now. Shouldn't be a problem, I think. */ … … 601 653 } 602 654 603 if (bud->flags & JBFLAG_DOES_XEP85) { 655 656 if (bud->flags & JBFLAG_DOES_XEP85 || bare->flags & JBFLAG_DOES_XEP85) { 604 657 /* We're only allowed to send this stuff if we know the other 605 side supports it. */ 658 side supports it. If the bare JID has the flag, all other 659 resources get it, too (That is the case in gtalk) */ 606 660 607 661 struct xt_node *node; -
protocols/jabber/jabber.h
r63cad66 r3fbce97 50 50 JFLAG_GTALK = 0x100000, /* Is Google Talk, as confirmed by iq discovery */ 51 51 JFLAG_HIPCHAT = 0x200000, /* Is hipchat, because prpl->name says so */ 52 53 JFLAG_SASL_FB = 0x10000, /* Trying Facebook authentication. */54 52 } jabber_flags_t; 55 53 … … 113 111 GSList *streamhosts; 114 112 int have_streamhosts; 113 114 char *muc_host; 115 115 }; 116 116 … … 228 228 #define XMLNS_XDATA "jabber:x:data" /* XEP-0004 */ 229 229 #define XMLNS_GMAILNOTIFY "google:mail:notify" /* Not a XEP */ 230 #define XMLNS_CARBONS "urn:xmpp:carbons:2" /* XEP-0280 */ 231 #define XMLNS_FORWARDING "urn:xmpp:forward:0" /* XEP-0297 */ 232 #define XMLNS_HINTS "urn:xmpp:hints" /* XEP-0334 */ 230 233 #define XMLNS_CHATSTATES "http://jabber.org/protocol/chatstates" /* XEP-0085 */ 231 234 #define XMLNS_DISCO_INFO "http://jabber.org/protocol/disco#info" /* XEP-0030 */ … … 338 341 339 342 extern const struct oauth2_service oauth2_service_google; 340 extern const struct oauth2_service oauth2_service_facebook;341 343 342 344 /* conference.c */ … … 356 358 xt_status jabber_parse_hipchat_profile(struct im_connection *ic, struct xt_node *node, struct xt_node *orig); 357 359 xt_status hipchat_handle_success(struct im_connection *ic, struct xt_node *node); 360 char *hipchat_make_channel_slug(const char *name); 361 char *hipchat_guess_channel_name(struct im_connection *ic, const char *name); 358 362 359 363 #endif -
protocols/jabber/jabber_util.c
r63cad66 r3fbce97 514 514 } else if (bud->resource && (flags & GET_BUDDY_EXACT)) { 515 515 /* We want an exact match, so in thise case there shouldn't be a /resource. */ 516 return NULL; 516 if (head != bud && head->resource == NULL) { 517 return head; 518 } else { 519 return NULL; 520 } 517 521 } else if (bud->resource == NULL || bud->next == NULL) { 518 522 /* No need for selection if there's only one option. */ -
protocols/jabber/message.c
r63cad66 r3fbce97 24 24 #include "jabber.h" 25 25 26 xt_status jabber_pkt_message(struct xt_node *node, gpointer data)26 static xt_status jabber_pkt_message_normal(struct xt_node *node, gpointer data, gboolean carbons_sent) 27 27 { 28 28 struct im_connection *ic = data; 29 char *from = xt_find_attr(node, "from"); 29 struct jabber_data *jd = ic->proto_data; 30 char *from = xt_find_attr(node, carbons_sent ? "to" : "from"); 30 31 char *type = xt_find_attr(node, "type"); 31 32 char *id = xt_find_attr(node, "id"); … … 37 38 if (!from) { 38 39 return XT_HANDLED; /* Consider this packet corrupted. */ 39 40 } 41 if (request && id) { 40 } 41 42 /* try to detect hipchat's own version of self-messages */ 43 if (jd->flags & JFLAG_HIPCHAT) { 44 struct xt_node *c; 45 46 if ((c = xt_find_node_by_attr(node->children, "delay", "xmlns", XMLNS_DELAY)) && 47 (s = xt_find_attr(c, "from_jid")) && 48 jabber_compare_jid(s, jd->me)) { 49 carbons_sent = TRUE; 50 } 51 } 52 53 if (request && id && g_strcmp0(type, "groupchat") != 0 && !carbons_sent) { 42 54 /* Send a message receipt (XEP-0184), looking like this: 43 * <message 44 * from='kingrichard@royalty.england.lit/throne' 45 * id='bi29sg183b4v' 46 * to='northumberland@shakespeare.lit/westminster'> 55 * <message from='...' id='...' to='...'> 47 56 * <received xmlns='urn:xmpp:receipts' id='richard2-4.1.247'/> 48 * </message> */ 57 * </message> 58 * 59 * MUC messages are excluded, since receipts aren't supposed to be sent over MUCs 60 * (XEP-0184 section 5.3) and replying to those may result in 'forbidden' errors. 61 */ 49 62 struct xt_node *received, *receipt; 50 63 … … 127 140 if (fullmsg->len > 0) { 128 141 imcb_buddy_msg(ic, from, fullmsg->str, 129 0, jabber_get_timestamp(node));142 carbons_sent ? OPT_SELFMESSAGE : 0, jabber_get_timestamp(node)); 130 143 } 131 144 if (room) { … … 136 149 137 150 /* Handling of incoming typing notifications. */ 138 if (bud == NULL) { 139 /* Can't handle these for unknown buddies. */ 151 if (bud == NULL || carbons_sent) { 152 /* Can't handle these for unknown buddies. 153 And ignore them if it's just carbons */ 140 154 } else if (xt_find_node(node->children, "composing")) { 141 155 bud->flags |= JBFLAG_DOES_XEP85; 142 156 imcb_buddy_typing(ic, from, OPT_TYPING); 143 157 } 144 /* No need to send a "stopped typing" signal when there's a message. */ 145 else if (xt_find_node(node->children, "active") && (body == NULL)) { 158 else if (xt_find_node(node->children, "active")) { 146 159 bud->flags |= JBFLAG_DOES_XEP85; 147 imcb_buddy_typing(ic, from, 0); 160 161 /* No need to send a "stopped typing" signal when there's a message. */ 162 if (body == NULL) { 163 imcb_buddy_typing(ic, from, 0); 164 } 148 165 } else if (xt_find_node(node->children, "paused")) { 149 166 bud->flags |= JBFLAG_DOES_XEP85; … … 158 175 return XT_HANDLED; 159 176 } 177 178 static xt_status jabber_carbons_message(struct xt_node *node, gpointer data) 179 { 180 struct im_connection *ic = data; 181 struct xt_node *wrap, *fwd, *msg; 182 gboolean carbons_sent; 183 184 if ((wrap = xt_find_node(node->children, "received"))) { 185 carbons_sent = FALSE; 186 } else if ((wrap = xt_find_node(node->children, "sent"))) { 187 carbons_sent = TRUE; 188 } 189 190 if (wrap == NULL || g_strcmp0(xt_find_attr(wrap, "xmlns"), XMLNS_CARBONS) != 0) { 191 return XT_NEXT; 192 } 193 194 if (!(fwd = xt_find_node(wrap->children, "forwarded")) || 195 (g_strcmp0(xt_find_attr(fwd, "xmlns"), XMLNS_FORWARDING) != 0) || 196 !(msg = xt_find_node(fwd->children, "message"))) { 197 imcb_log(ic, "Error: Invalid carbons message received"); 198 return XT_ABORT; 199 } 200 201 return jabber_pkt_message_normal(msg, data, carbons_sent); 202 } 203 204 xt_status jabber_pkt_message(struct xt_node *node, gpointer data) 205 { 206 struct im_connection *ic = data; 207 struct jabber_data *jd = ic->proto_data; 208 char *from = xt_find_attr(node, "from"); 209 210 if (jabber_compare_jid(jd->me, from)) { /* Probably a Carbons message */ 211 xt_status st = jabber_carbons_message(node, data); 212 if (st == XT_HANDLED || st == XT_ABORT) { 213 return st; 214 } 215 } 216 return jabber_pkt_message_normal(node, data, FALSE); 217 } -
protocols/jabber/presence.c
r63cad66 r3fbce97 186 186 char *prio = set_getstr(&ic->acc->set, "priority"); 187 187 188 if (jd->away_state ->code != NULL) {188 if (jd->away_state && jd->away_state->full_name != NULL) { 189 189 int new_prio = (atoi(prio) - 5); 190 190 if (new_prio < 0) { … … 222 222 cap = xt_new_node("c", NULL, NULL); 223 223 xt_add_attr(cap, "xmlns", XMLNS_CAPS); 224 xt_add_attr(cap, "node", "http://bitlbee.org/xmpp/caps"); 224 225 if (jd->flags & JFLAG_HIPCHAT) { 226 /* hipchat specific node, whitelisted by request to receive self-messages */ 227 xt_add_attr(cap, "node", "http://bitlbee.org/xmpp/caps/hipchat"); 228 } else { 229 xt_add_attr(cap, "node", "http://bitlbee.org/xmpp/caps"); 230 } 225 231 xt_add_attr(cap, "ver", BITLBEE_VERSION); /* The XEP wants this hashed, but nobody's doing that. */ 226 232 xt_add_child(node, cap); -
protocols/jabber/s5bytestream.c
r63cad66 r3fbce97 536 536 * that sends atyp=0 addrlen=0 and only 6 bytes (one less than one would expect). 537 537 * Therefore I removed the wait for more bytes. Since we don't care about what else the proxy 538 * is sending, it should nt matter */538 * is sending, it should not matter */ 539 539 540 540 if (bt->tf->ft->sending) { … … 559 559 * An intelligent sender would probably specify himself as the first streamhost and 560 560 * a proxy as the second (Kopete and PSI are examples here). That way, a (potentially) 561 * slow proxy is only used if nec cessary. This of course also means, that the timeout561 * slow proxy is only used if necessary. This of course also means, that the timeout 562 562 * per streamhost should be kept short. If one or two firewalled adresses are specified, 563 563 * they have to timeout first before a proxy is tried. -
protocols/jabber/sasl.c
r63cad66 r3fbce97 38 38 "6C-Zgf7Tr7gEQTPlBhMUgo7R", 39 39 }; 40 const struct oauth2_service oauth2_service_facebook =41 {42 "https://www.facebook.com/dialog/oauth",43 "https://graph.facebook.com/oauth/access_token",44 "https://www.bitlbee.org/main.php/Facebook/oauth2.html",45 "offline_access,xmpp_login",46 "126828914005625",47 "4b100f0f244d620bf3f15f8b217d4c32",48 };49 40 50 41 xt_status sasl_pkt_mechanisms(struct xt_node *node, gpointer data) … … 54 45 struct xt_node *c, *reply; 55 46 char *s; 56 int sup_plain = 0, sup_digest = 0, sup_gtalk = 0, sup_ fb = 0, sup_anonymous = 0;47 int sup_plain = 0, sup_digest = 0, sup_gtalk = 0, sup_anonymous = 0; 57 48 int want_oauth = FALSE, want_hipchat = FALSE, want_anonymous = FALSE; 58 49 GString *mechs; … … 89 80 } else if (c->text && g_strcasecmp(c->text, "X-OAUTH2") == 0) { 90 81 sup_gtalk = 1; 91 } else if (c->text && g_strcasecmp(c->text, "X-FACEBOOK-PLATFORM") == 0) {92 sup_fb = 1;93 82 } 94 83 … … 101 90 102 91 if (!want_oauth && !sup_plain && !sup_digest) { 103 if (!sup_gtalk && !sup_fb) {92 if (!sup_gtalk) { 104 93 imcb_error(ic, "This server requires OAuth " 105 94 "(supported schemes:%s)", mechs->str); … … 137 126 reply->text_len = strlen(reply->text); 138 127 g_free(s); 139 } else if (sup_fb && want_oauth) {140 xt_add_attr(reply, "mechanism", "X-FACEBOOK-PLATFORM");141 jd->flags |= JFLAG_SASL_FB;142 128 } else if (want_oauth) { 143 129 imcb_error(ic, "OAuth requested, but not supported by server"); … … 154 140 xt_free_node(reply); 155 141 return XT_ABORT; 156 } else if (sup_digest) { 142 } else if (sup_digest && !(jd->ssl && sup_plain)) { 143 /* Only try DIGEST-MD5 if there's no SSL/TLS or if PLAIN isn't supported. 144 * Which in practice means "don't bother with DIGEST-MD5 most of the time". 145 * It's weak, pointless over TLS, and often breaks with some servers (hi openfire) */ 146 157 147 xt_add_attr(reply, "mechanism", "DIGEST-MD5"); 158 148 … … 295 285 dec = frombase64(node->text); 296 286 297 if (jd->flags & JFLAG_SASL_FB) { 298 /* New-style Facebook OAauth2 support. Instead of sending a refresh 299 token, they just send an access token that should never expire. */ 300 GSList *p_in = NULL, *p_out = NULL; 301 char time[33]; 302 303 oauth_params_parse(&p_in, dec); 304 oauth_params_add(&p_out, "nonce", oauth_params_get(&p_in, "nonce")); 305 oauth_params_add(&p_out, "method", oauth_params_get(&p_in, "method")); 306 oauth_params_free(&p_in); 307 308 g_snprintf(time, sizeof(time), "%lld", (long long) (gettime() * 1000)); 309 oauth_params_add(&p_out, "call_id", time); 310 oauth_params_add(&p_out, "api_key", oauth2_service_facebook.consumer_key); 311 oauth_params_add(&p_out, "v", "1.0"); 312 oauth_params_add(&p_out, "format", "XML"); 313 oauth_params_add(&p_out, "access_token", jd->oauth2_access_token); 314 315 reply = oauth_params_string(p_out); 316 oauth_params_free(&p_out); 317 } else if (!(s = sasl_get_part(dec, "rspauth"))) { 287 if (!(s = sasl_get_part(dec, "rspauth"))) { 318 288 /* See RFC 2831 for for information. */ 319 289 md5_state_t A1, A2, H; -
protocols/jabber/si.c
r63cad66 r3fbce97 186 186 jd->filetransfers = g_slist_prepend(jd->filetransfers, tf); 187 187 188 /* query buddy's features and server's streaming proxies if nec cessary */188 /* query buddy's features and server's streaming proxies if necessary */ 189 189 190 190 if (!tf->bud->features) { … … 283 283 284 284 if (requestok) { 285 /* Figure out who the transfer should come from e... */285 /* Figure out who the transfer should come from... */ 286 286 287 287 ext_jid = ini_jid; … … 403 403 * <iq from=... to=... id=...> 404 404 * <si xmlns=si> 405 * [ <file xmlns=ft/> ] <-- not nec cessary405 * [ <file xmlns=ft/> ] <-- not necessary 406 406 * <feature xmlns=feature> 407 407 * <x xmlns=xdata type=submit> -
protocols/msn/gw.c
r63cad66 r3fbce97 22 22 gw->ssl = (GATEWAY_PORT == 443); 23 23 gw->poll_timeout = -1; 24 gw->write_timeout = -1; 24 25 gw->ic = ic; 25 26 gw->md = ic->proto_data; … … 34 35 b_event_remove(gw->poll_timeout); 35 36 } 37 38 if (gw->write_timeout != -1) { 39 b_event_remove(gw->write_timeout); 40 } 41 36 42 g_byte_array_free(gw->in, TRUE); 37 43 g_byte_array_free(gw->out, TRUE); … … 189 195 } 190 196 191 void msn_gw_write(struct msn_gw *gw, char *buf, size_t len) 192 { 193 g_byte_array_append(gw->out, (const guint8 *) buf, len); 197 static gboolean msn_gw_write_cb(gpointer data, gint source, b_input_condition cond) 198 { 199 struct msn_gw *gw; 200 201 if (!(gw = msn_gw_from_ic(data))) { 202 return FALSE; 203 } 204 194 205 if (!gw->open) { 195 206 msn_gw_open(gw); … … 197 208 msn_gw_dorequest(gw, NULL); 198 209 } 199 } 210 211 gw->write_timeout = -1; 212 return FALSE; 213 } 214 215 void msn_gw_write(struct msn_gw *gw, char *buf, size_t len) 216 { 217 g_byte_array_append(gw->out, (const guint8 *) buf, len); 218 219 /* do a bit of buffering here to send several commands with a single request */ 220 if (gw->write_timeout == -1) { 221 gw->write_timeout = b_timeout_add(1, msn_gw_write_cb, gw->ic); 222 } 223 } -
protocols/msn/msn.h
r63cad66 r3fbce97 112 112 113 113 int poll_timeout; 114 int write_timeout; 114 115 115 116 b_event_handler callback; -
protocols/msn/msn_util.c
r63cad66 r3fbce97 41 41 } 42 42 43 return g_markup_printf_escaped("<ml><d n=\"%s\"><c n=\"%s\" l=\"%d\" t=\"1\"/></d></ml>",43 return g_markup_printf_escaped("<ml><d n=\"%s\"><c n=\"%s\" t=\"1\"><s n=\"IM\" l=\"%d\" /></c></d></ml>", 44 44 domain, handle, list); 45 45 } -
protocols/msn/ns.c
r63cad66 r3fbce97 39 39 static void msn_ns_send_adl(struct im_connection *ic); 40 40 static void msn_ns_structured_message(struct msn_data *md, char *msg, int msglen, char **cmd); 41 static void msn_ns_sdg(struct msn_data *md, char *who, char **parts, char *action );41 static void msn_ns_sdg(struct msn_data *md, char *who, char **parts, char *action, gboolean selfmessage); 42 42 static void msn_ns_nfy(struct msn_data *md, char *who, char **parts, char *action, gboolean is_put); 43 43 … … 110 110 struct im_connection *ic = md->ic; 111 111 112 /* this should be taken from XFR, but hardcoding it for now. it also prevents more redirects. */ 113 const char *redir_data = "VmVyc2lvbjogMQ0KWGZyQ291bnQ6IDINCklzR2VvWGZyOiB0cnVlDQo="; 114 112 115 if (source == -1 && !md->is_http) { 113 116 imcb_error(ic, "Could not connect to server"); … … 135 138 } 136 139 137 if (msn_ns_write(ic, source, "VER %d %s CVR0\r\n", ++md->trId, MSNP_VER)) { 140 /* Having to handle potential errors in each write sure makes these ifs awkward...*/ 141 142 if (msn_ns_write(ic, source, "VER %d %s CVR0\r\n", ++md->trId, MSNP_VER) && 143 msn_ns_write(ic, source, "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s %s\r\n", 144 ++md->trId, ic->acc->user, redir_data) && 145 msn_ns_write(ic, md->fd, "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user)) { 146 138 147 if (!md->is_http) { 139 148 md->inpa = b_input_add(md->fd, B_EV_IO_READ, msn_ns_callback, md); … … 208 217 } 209 218 210 return(msn_ns_write(ic, md->fd, "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s VmVyc2lvbjogMQ0KWGZyQ291bnQ6IDINClhmclNlbnRVVENUaW1lOiA2MzU2MTQ3OTU5NzgzOTAwMDANCklzR2VvWGZyOiB0cnVlDQo=\r\n",211 ++md->trId, ic->acc->user));212 219 } else if (strcmp(cmd[0], "CVR") == 0) { 213 220 /* We don't give a damn about the information we just received */ 214 return msn_ns_write(ic, md->fd, "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user);215 221 } else if (strcmp(cmd[0], "XFR") == 0) { 216 222 char *server; … … 280 286 md->msglen = atoi(cmd[2]); 281 287 } 288 } else if (strcmp(cmd[0], "RML") == 0) { 289 /* Move along, nothing to see here */ 282 290 } else if (strcmp(cmd[0], "CHL") == 0) { 283 291 char *resp; … … 475 483 } 476 484 485 /* returns newly allocated string */ 486 static char *msn_ns_parse_header_address(struct msn_data *md, char *headers, char *header_name) 487 { 488 char *semicolon = NULL; 489 char *header = NULL; 490 char *address = NULL; 491 492 if (!(header = get_rfc822_header(headers, header_name, 0))) { 493 return NULL; 494 } 495 496 /* either the semicolon or the end of the string */ 497 semicolon = strchr(header, ';') ? : (header + strlen(header)); 498 499 address = g_strndup(header + 2, semicolon - header - 2); 500 501 g_free(header); 502 return address; 503 } 504 477 505 static void msn_ns_structured_message(struct msn_data *md, char *msg, int msglen, char **cmd) 478 506 { 479 507 char **parts = NULL; 480 char *semicolon = NULL;481 508 char *action = NULL; 482 char *from = NULL;483 509 char *who = NULL; 510 gboolean selfmessage = FALSE; 484 511 485 512 parts = g_strsplit(msg, "\r\n\r\n", 4); 486 513 487 if (!( from = get_rfc822_header(parts[0], "From", 0))) {514 if (!(who = msn_ns_parse_header_address(md, parts[0], "From"))) { 488 515 goto cleanup; 489 516 } 490 517 491 /* either the semicolon or the end of the string */ 492 semicolon = strchr(from, ';') ? : (from + strlen(from)); 493 494 who = g_strndup(from + 2, semicolon - from - 2); 518 if (strcmp(who, md->ic->acc->user) == 0) { 519 selfmessage = TRUE; 520 g_free(who); 521 if (!(who = msn_ns_parse_header_address(md, parts[0], "To"))) { 522 goto cleanup; 523 } 524 } 495 525 496 526 if ((strcmp(cmd[0], "SDG") == 0) && (action = get_rfc822_header(parts[2], "Message-Type", 0))) { 497 msn_ns_sdg(md, who, parts, action );527 msn_ns_sdg(md, who, parts, action, selfmessage); 498 528 499 529 } else if ((strcmp(cmd[0], "NFY") == 0) && (action = get_rfc822_header(parts[2], "Uri", 0))) { … … 505 535 g_strfreev(parts); 506 536 g_free(action); 507 g_free(from);508 537 g_free(who); 509 538 } 510 539 511 static void msn_ns_sdg(struct msn_data *md, char *who, char **parts, char *action )540 static void msn_ns_sdg(struct msn_data *md, char *who, char **parts, char *action, gboolean selfmessage) 512 541 { 513 542 struct im_connection *ic = md->ic; 514 543 515 if (strcmp(action, "Control/Typing") == 0 ) {544 if (strcmp(action, "Control/Typing") == 0 && !selfmessage) { 516 545 imcb_buddy_typing(ic, who, OPT_TYPING); 517 546 } else if (strcmp(action, "Text") == 0) { 518 imcb_buddy_msg(ic, who, parts[3], 0, 0);547 imcb_buddy_msg(ic, who, parts[3], selfmessage ? OPT_SELFMESSAGE : 0, 0); 519 548 } 520 549 } … … 595 624 } else { 596 625 imcb_error(ic, "Error during Passport authentication: %s", error); 597 imc_logout(ic, TRUE); 626 627 /* don't reconnect with auth errors */ 628 if (error && g_str_has_prefix(error, "wsse:FailedAuthentication")) { 629 imc_logout(ic, FALSE); 630 } else { 631 imc_logout(ic, TRUE); 632 } 598 633 } 599 634 } -
protocols/msn/soap.c
r63cad66 r3fbce97 270 270 struct im_connection *ic = soap_req->ic; 271 271 struct msn_data *md = ic->proto_data; 272 char pass[MAX_PASSPORT_PWLEN + 1];273 272 274 273 if (sd->redirect) { … … 286 285 } 287 286 288 strncpy(pass, ic->acc->pass, MAX_PASSPORT_PWLEN);289 pass[MAX_PASSPORT_PWLEN] = '\0';290 287 soap_req->payload = g_markup_printf_escaped(SOAP_PASSPORT_SSO_PAYLOAD, 291 ic->acc->user, pass, md->pp_policy);288 ic->acc->user, ic->acc->pass, md->pp_policy); 292 289 293 290 return MSN_SOAP_OK; … … 327 324 struct xt_node *code = xt_find_node(node->children, "faultcode"); 328 325 struct xt_node *string = xt_find_node(node->children, "faultstring"); 326 struct xt_node *reqstatus = xt_find_path(node, "psf:pp/psf:reqstatus"); 329 327 struct xt_node *url; 330 328 … … 335 333 url->text_len > 0) { 336 334 sd->redirect = g_strdup(url->text); 335 } else if (reqstatus && strcmp(reqstatus->text, "0x800488fe") == 0) { 336 char *msg = "Location blocked. Log in to live.com, go to recent activity and click 'this was me'"; 337 sd->error = g_strdup_printf("%s (%s)", code->text, msg); 337 338 } else { 338 339 sd->error = g_strdup_printf("%s (%s)", code->text, string && string->text_len ? … … 346 347 { "wsse:BinarySecurityToken", "wst:RequestedSecurityToken", msn_soap_passport_sso_token }, 347 348 { "S:Fault", "S:Envelope", msn_soap_passport_failure }, 349 { "S:Fault", "wst:RequestSecurityTokenResponse", msn_soap_passport_failure }, 348 350 { NULL, NULL, NULL } 349 351 }; … … 774 776 imcb_log(soap_req->ic, "Warning: %d contacts were in both your " 775 777 "block and your allow list. Assuming they're all " 776 "allowed. Use the official WLM client once to fix " 777 "this.", wtf); 778 "allowed.", wtf); 778 779 } 779 780 -
protocols/msn/soap.h
r63cad66 r3fbce97 61 61 #define SOAP_PASSPORT_SSO_URL "https://login.live.com/RST.srf" 62 62 #define SOAP_PASSPORT_SSO_URL_MSN "https://msnia.login.live.com/pp900/RST.srf" 63 #define MAX_PASSPORT_PWLEN 1664 63 65 64 #define SOAP_PASSPORT_SSO_PAYLOAD \ -
protocols/nogaim.c
r63cad66 r3fbce97 90 90 91 91 GList *protocols = NULL; 92 GList *disabled_protocols = NULL; 92 93 93 94 void register_protocol(struct prpl *p) … … 103 104 104 105 if (refused) { 105 log_message(LOGLVL_WARNING, "Protocol %s disabled\n", p->name);106 disabled_protocols = g_list_append(disabled_protocols, p); 106 107 } else { 107 108 protocols = g_list_append(protocols, p); … … 109 110 } 110 111 112 static int proto_name_cmp(const void *proto_, const void *name) 113 { 114 const struct prpl *proto = proto_; 115 return g_strcasecmp(proto->name, name); 116 } 117 111 118 struct prpl *find_protocol(const char *name) 112 119 { 113 GList *gl; 114 115 for (gl = protocols; gl; gl = gl->next) { 116 struct prpl *proto = gl->data; 117 118 if (g_strcasecmp(proto->name, name) == 0) { 119 return proto; 120 } 121 } 122 123 return NULL; 120 GList *gl = g_list_find_custom(protocols, name, proto_name_cmp); 121 return gl ? gl->data: NULL; 122 } 123 124 gboolean is_protocol_disabled(const char *name) 125 { 126 return g_list_find_custom(disabled_protocols, name, proto_name_cmp) != NULL; 124 127 } 125 128 … … 209 212 account_t *a; 210 213 214 if (!ic->bee->ui->log) { 215 return; 216 } 217 211 218 va_start(params, format); 212 219 text = g_strdup_vprintf(format, params); … … 227 234 /* If we found one, include the screenname in the message. */ 228 235 if (a) { 229 /* FIXME(wilmer): ui_log callback or so */ 230 irc_rootmsg(ic->bee->ui_data, "%s - %s", ic->acc->tag, text); 236 ic->bee->ui->log(ic->bee, ic->acc->tag, text); 231 237 } else { 232 i rc_rootmsg(ic->bee->ui_data, "%s - %s", ic->acc->prpl->name, text);238 ic->bee->ui->log(ic->bee, ic->acc->prpl->name, text); 233 239 } 234 240 … … 662 668 GList *m = ic->acc->prpl->away_states(ic); 663 669 msg = ic->acc->flags & ACC_FLAG_AWAY_MESSAGE ? away : NULL; 664 away = imc_away_state_find(m, away, &msg) ? : m->data; 670 away = imc_away_state_find(m, away, &msg) ? : 671 (imc_away_state_find(m, "away", &msg) ? : m->data); 665 672 } else if (ic->acc->flags & ACC_FLAG_STATUS_MESSAGE) { 666 673 away = NULL; … … 781 788 } 782 789 790 /* Deprecated: using this function resulted in merging several handles accidentally 791 * Also the irc layer handles this decently nowadays */ 783 792 void imcb_clean_handle(struct im_connection *ic, char *handle) 784 793 { 785 /* Accepts a handle and does whatever is necessary to make it 786 BitlBee-friendly. Currently this means removing everything 787 outside 33-127 (ASCII printable excl spaces), @ (only one 788 is allowed) and ! and : */ 789 char out[strlen(handle) + 1]; 790 int s, d; 791 792 s = d = 0; 793 while (handle[s]) { 794 if (handle[s] > ' ' && handle[s] != '!' && handle[s] != ':' && 795 (handle[s] & 0x80) == 0) { 796 if (handle[s] == '@') { 797 /* See if we got an @ already? */ 798 out[d] = 0; 799 if (strchr(out, '@')) { 800 continue; 801 } 802 } 803 804 out[d++] = handle[s]; 805 } 806 s++; 807 } 808 out[d] = handle[s]; 809 810 strcpy(handle, out); 811 } 794 } -
protocols/nogaim.h
r63cad66 r3fbce97 76 76 #define OPT_PONGED 0x00020000 /* Received a keep-alive during last interval */ 77 77 #define OPT_LOCAL_CONTACTS_SENT 0x00040000 /* Protocol already requested local contact list, so don't send it after finishing login. */ 78 #define OPT_SELFMESSAGE 0x00080000 /* A message sent by self from another location */ 78 79 79 80 /* ok. now the fun begins. first we create a connection structure */ … … 280 281 G_MODULE_EXPORT GSList *get_connections(); 281 282 G_MODULE_EXPORT struct prpl *find_protocol(const char *name); 283 G_MODULE_EXPORT gboolean is_protocol_disabled(const char *name); 282 284 /* When registering a new protocol, you should allocate space for a new prpl 283 285 * struct, initialize it (set the function pointers to point to your … … 326 328 G_MODULE_EXPORT void imcb_add_buddy(struct im_connection *ic, const char *handle, const char *group); 327 329 G_MODULE_EXPORT void imcb_remove_buddy(struct im_connection *ic, const char *handle, char *group); 328 G_MODULE_EXPORT struct buddy *imcb_find_buddy(struct im_connection *ic, char *handle);329 330 G_MODULE_EXPORT void imcb_rename_buddy(struct im_connection *ic, const char *handle, const char *realname); 330 331 G_MODULE_EXPORT void imcb_buddy_nick_hint(struct im_connection *ic, const char *handle, const char *nick); … … 332 333 G_MODULE_EXPORT GSList *imcb_get_local_contacts(struct im_connection *ic); 333 334 334 G_MODULE_EXPORT void imcb_buddy_typing(struct im_connection *ic, const char *handle, uint32_tflags);335 G_MODULE_EXPORT void imcb_buddy_typing(struct im_connection *ic, const char *handle, guint32 flags); 335 336 G_MODULE_EXPORT struct bee_user *imcb_buddy_by_handle(struct im_connection *ic, const char *handle); 336 G_MODULE_EXPORT void imcb_clean_handle(struct im_connection *ic, char *handle); 337 338 G_GNUC_DEPRECATED G_MODULE_EXPORT void imcb_clean_handle(struct im_connection *ic, char *handle); 337 339 338 340 /* Actions, or whatever. */ -
protocols/oscar/aim.h
r63cad66 r3fbce97 21 21 22 22 #include "bitlbee.h" 23 24 #ifdef WITH_PURPLE 25 /* For compatibility with builds that include both purple and this oscar module */ 26 #include "aim_prefixes.h" 27 #endif 23 28 24 29 /* XXX adjust these based on autoconf-detected platform */ … … 871 876 * SNAC Family: Internal Messages 872 877 * 873 * This isn't tru ely a SNAC family either, but using878 * This isn't truly a SNAC family either, but using 874 879 * these, we can integrated non-SNAC services into 875 880 * the SNAC-centered libfaim callback structure. -
protocols/oscar/auth.c
r63cad66 r3fbce97 41 41 * meaning you generally never call this. 42 42 * 43 * But there are times when something might want it sep erate. Specifically,43 * But there are times when something might want it separate. Specifically, 44 44 * libfaim sends this internally when doing SNAC login. 45 45 * -
protocols/oscar/conn.c
r63cad66 r3fbce97 15 15 * In OSCAR, every connection has a set of SNAC groups associated 16 16 * with it. These are the groups that you can send over this connection 17 * without being guar enteed a "Not supported" SNAC error.17 * without being guaranteed a "Not supported" SNAC error. 18 18 * 19 19 * The grand theory of things says that these associations transcend … … 36 36 * 37 37 * Here comes the good bit. Without even letting anyone know, particularly 38 * the module that decided to send this SNAC, and definit ly not that twit38 * the module that decided to send this SNAC, and definitely not that twit 39 39 * in Greenland, you send out a service request. In this request, you have 40 40 * marked the need for a connection supporting group 0x000e. A few seconds … … 317 317 318 318 if (deadconn->fd >= 3) { 319 closesocket(deadconn->fd);319 proxy_disconnect(deadconn->fd); 320 320 } 321 321 deadconn->fd = -1; -
protocols/oscar/im.c
r63cad66 r3fbce97 50 50 * encoding for your message. In UNICODE mode, _all_ characters must 51 51 * occupy 16bits, including ones that are not special. (Remember that 52 * the first 128 UNICODE symbols are equiv elent to ASCII7, however they52 * the first 128 UNICODE symbols are equivalent to ASCII7, however they 53 53 * must be prefixed with a zero high order byte.) 54 54 * … … 64 64 * in all of libfaim, it is written with performance in mind. As such, 65 65 * it is not as clear as it could be in respect to how this message is 66 * supposed to be la yed out. Most obviously, tlvlists should be used66 * supposed to be laid out. Most obviously, tlvlists should be used 67 67 * instead of writing out the bytes manually. 68 68 * … … 476 476 * examples of how to do this. 477 477 * 478 * I would definit ly recommend avoiding this feature unless you really478 * I would definitely recommend avoiding this feature unless you really 479 479 * know what you are doing, and/or you have something neat to do with it. 480 480 * … … 638 638 } 639 639 #if 0 640 /* XXX this isn't really neces ary... */640 /* XXX this isn't really necessary... */ 641 641 if (((args.flag1 != 0x0000) && 642 642 (args.flag1 != 0x0002) && … … 1161 1161 * 1162 1162 * Channel 0x0001 is the message channel. There are 1163 * other channels for things called "rende vous"1163 * other channels for things called "rendezvous" 1164 1164 * which represent chat and some of the other new 1165 1165 * features of AIM2/3/3.5. 1166 1166 * 1167 * Channel 0x0002 is the Rende vous channel, which1167 * Channel 0x0002 is the Rendezvous channel, which 1168 1168 * is where Chat Invitiations and various client-client 1169 1169 * connection negotiations come from. … … 1181 1181 * with the TLVs read below, they are two different pieces. The 1182 1182 * userinfo block contains the number of TLVs that contain user 1183 * information, the rest are not even though there is no sep eration.1183 * information, the rest are not even though there is no separation. 1184 1184 * aim_extractuserinfo() returns the number of bytes used by the 1185 1185 * userinfo tlvs, so you can start reading the rest of them right … … 1253 1253 /* 1254 1254 * 1255 * I definit ly recommend sending this. If you don't, you'll be stuck1255 * I definitely recommend sending this. If you don't, you'll be stuck 1256 1256 * with the rather unreasonable defaults. You don't want those. Send this. 1257 1257 * -
protocols/oscar/misc.c
r63cad66 r3fbce97 3 3 * aim_misc.c 4 4 * 5 * TODO: Sep erate a lot of this into an aim_bos.c.5 * TODO: Separate a lot of this into an aim_bos.c. 6 6 * 7 7 * Other things... -
protocols/oscar/msgcookie.c
r63cad66 r3fbce97 142 142 * @cookiep: the address of a pointer to the cookie struct to remove 143 143 * 144 * this function removes the cookie *cookie from t ehlist of cookies144 * this function removes the cookie *cookie from the list of cookies 145 145 * in sess, and then frees all memory associated with it. including 146 146 * its data! if you want to use the private data after calling this, -
protocols/oscar/oscar.c
r63cad66 r3fbce97 1266 1266 } break; 1267 1267 1268 case 2: { /* rende vous */1268 case 2: { /* rendezvous */ 1269 1269 struct aim_incomingim_ch2_args *args; 1270 1270 args = va_arg(ap, struct aim_incomingim_ch2_args *); -
protocols/oscar/rxhandlers.c
r63cad66 r3fbce97 381 381 /* 382 382 * This doesn't have to be called here. It could easily be done 383 * by a sep erate thread or something. It's an administrative operation,383 * by a separate thread or something. It's an administrative operation, 384 384 * and can take a while. Though the less you call it the less memory 385 385 * you'll have :) -
protocols/oscar/rxqueue.c
r63cad66 r3fbce97 361 361 /* 362 362 * Grab a single command sequence off the socket, and enqueue 363 * it in the incoming event queue in a sep erate struct.363 * it in the incoming event queue in a separate struct. 364 364 */ 365 365 int aim_get_command(aim_session_t *sess, aim_conn_t *conn) … … 479 479 480 480 /* 481 * Purge rec ieve queue of all handled commands (->handled==1). Also481 * Purge receive queue of all handled commands (->handled==1). Also 482 482 * allows for selective freeing using ->nofree so that the client can 483 483 * keep the data for various purposes. -
protocols/oscar/service.c
r63cad66 r3fbce97 157 157 158 158 /* 159 * OSCAR defines several 'rate classes'. Each class has sep erate159 * OSCAR defines several 'rate classes'. Each class has separate 160 160 * rate limiting properties (limit level, alert level, disconnect 161 161 * level, etc), and a set of SNAC family/type pairs associated with … … 709 709 * of memory. (I won't put it past them to start requesting data in 710 710 * less static regions -- regions that are initialized at run time, but still 711 * before the client rec ieves this request.)712 * 713 * When the client rec ieves the request, it adds it to the current ds711 * before the client receives this request.) 712 * 713 * When the client receives the request, it adds it to the current ds 714 714 * (0x00400000) and dereferences it, copying the data into a buffer which 715 715 * it then runs directly through the MD5 hasher. The 16 byte output of … … 723 723 * download a FREE, fully featured, and authorized client, here 724 724 * http://www.aol.com/aim/download2.html" 725 * The connection is then closed, rec ieving disconnect code 1, URL725 * The connection is then closed, receiving disconnect code 1, URL 726 726 * http://www.aim.aol.com/errors/USER_LOGGED_OFF_NEW_LOGIN.html. 727 727 * 728 728 * Note, however, that numerous inconsistencies can cause the above error, 729 * not just sending back a bad hash. Do not immediat ly suspect this code729 * not just sending back a bad hash. Do not immediately suspect this code 730 730 * if you get disconnected. AOL and the open/free software community have 731 731 * played this game for a couple years now, generating the above message 732 * on numerous oc assions.732 * on numerous occasions. 733 733 * 734 734 * Anyway, neener. We win again. -
protocols/oscar/tlv.c
r63cad66 r3fbce97 25 25 * bstream references, so that at least the ->value portion of each 26 26 * element doesn't need to be malloc/memcpy'd. This could prove to be 27 * just as eff ecient as the in-place TLV parsing used in a couple places27 * just as efficient as the in-place TLV parsing used in a couple places 28 28 * in libfaim. 29 29 * … … 135 135 /** 136 136 * aim_addtlvtochain_str - Add a string to a TLV chain 137 * @list: Desi nation chain (%NULL pointer if empty)137 * @list: Designation chain (%NULL pointer if empty) 138 138 * @type: TLV type 139 139 * @str: String to add -
protocols/oscar/txqueue.c
r63cad66 r3fbce97 67 67 * The overall purpose here is to enqueue the passed in command struct 68 68 * into the outgoing (tx) queue. Basically... 69 * 1) Make a scope-irrelev ent copy of the struct69 * 1) Make a scope-irrelevant copy of the struct 70 70 * 3) Mark as not-sent-yet 71 71 * 4) Enqueue the struct into the list -
protocols/purple/ft-direct.c
r63cad66 r3fbce97 193 193 PurpleXferUiOps bee_xfer_uiops = 194 194 { 195 prplcb_xfer_new, 196 prplcb_xfer_dbg, 197 prplcb_xfer_dbg, 198 prplcb_xfer_progress, 199 prplcb_xfer_dbg, 200 prplcb_xfer_dbg, 201 prplcb_xfer_write, 202 prplcb_xfer_read, 203 prplcb_xfer_dbg, 195 prplcb_xfer_new, /* new_xfer */ 196 prplcb_xfer_dbg, /* destroy */ 197 prplcb_xfer_dbg, /* add_xfer */ 198 prplcb_xfer_progress, /* update_progress */ 199 prplcb_xfer_dbg, /* cancel_local */ 200 prplcb_xfer_dbg, /* cancel_remote */ 201 prplcb_xfer_write, /* ui_write */ 202 prplcb_xfer_read, /* ui_read */ 203 prplcb_xfer_dbg, /* data_not_sent */ 204 204 }; 205 205 -
protocols/purple/ft.c
r63cad66 r3fbce97 232 232 } 233 233 234 static void prplcb_xfer_dbg(PurpleXfer *xfer)235 {236 fprintf(stderr, "prplcb_xfer_dbg 0x%p\n", xfer);237 }238 239 234 240 235 /* Sending files (UI->IM): */ … … 337 332 PurpleXferUiOps bee_xfer_uiops = 338 333 { 339 prplcb_xfer_new, 340 prplcb_xfer_destroy, 341 NULL, /* prplcb_xfer_add,*/342 prplcb_xfer_progress, 343 prplcb_xfer_dbg,344 prplcb_xfer_cancel_remote, 345 NULL, 346 NULL, 347 prplcb_xfer_dbg,334 prplcb_xfer_new, /* new_xfer */ 335 prplcb_xfer_destroy, /* destroy */ 336 NULL, /* add_xfer */ 337 prplcb_xfer_progress, /* update_progress */ 338 NULL, /* cancel_local */ 339 prplcb_xfer_cancel_remote, /* cancel_remote */ 340 NULL, /* ui_write */ 341 NULL, /* ui_read */ 342 NULL, /* data_not_sent */ 348 343 }; -
protocols/purple/purple.c
r63cad66 r3fbce97 113 113 servers anyway! */ 114 114 if (!dir_fixed) { 115 PurpleCertificatePool *pool; 115 116 irc_t *irc = acc->bee->ui_data; 116 117 char *dir; … … 122 123 purple_blist_load(); 123 124 purple_prefs_load(); 125 126 if (proxytype == PROXY_SOCKS4A) { 127 /* do this here after loading prefs. yes, i know, it sucks */ 128 purple_prefs_set_bool("/purple/proxy/socks4_remotedns", TRUE); 129 } 130 131 /* re-create the certificate cache directory */ 132 pool = purple_certificate_find_pool("x509", "tls_peers"); 133 dir = purple_certificate_pool_mkpath(pool, NULL); 134 purple_build_dir(dir, 0700); 135 g_free(dir); 136 124 137 dir_fixed = TRUE; 125 138 } … … 352 365 if (!pd) { 353 366 return; 367 } 368 369 while (ic->groupchats) { 370 imcb_chat_free(ic->groupchats->data); 354 371 } 355 372 … … 639 656 /* Call the fucker. */ 640 657 callback = (void *) mi->callback; 641 callback(&pb->node, m enu->data);658 callback(&pb->node, mi->data); 642 659 643 660 return NULL; … … 707 724 g_hash_table_replace(chat_hash, "passwd", g_strdup(password)); 708 725 } 709 } 726 727 g_free(pce); 728 } 729 730 g_list_free(info); 710 731 711 732 serv_join_chat(purple_account_get_connection(pd->account), chat_hash); 712 733 713 return NULL; 734 g_hash_table_destroy(chat_hash); 735 736 return imcb_chat_new(ic, room); 714 737 } 715 738 … … 733 756 static PurpleCoreUiOps bee_core_uiops = 734 757 { 735 NULL, 736 NULL, 737 purple_ui_init, 738 NULL, 739 prplcb_ui_info, 758 NULL, /* ui_prefs_init */ 759 NULL, /* debug_ui_init */ 760 purple_ui_init, /* ui_init */ 761 NULL, /* quit */ 762 prplcb_ui_info, /* get_ui_info */ 740 763 }; 741 764 … … 764 787 purple_gg_buddylist_import(gc); 765 788 766 if (gc->flags & PURPLE_CONNECTION_HTML) { 767 ic->flags |= OPT_DOES_HTML; 768 } 789 ic->flags |= OPT_DOES_HTML; 769 790 } 770 791 … … 800 821 static PurpleConnectionUiOps bee_conn_uiops = 801 822 { 802 prplcb_conn_progress, 803 prplcb_conn_connected, 804 prplcb_conn_disconnected, 805 prplcb_conn_notice, 806 NULL, 807 NULL, 808 NULL, 809 prplcb_conn_report_disconnect_reason, 823 prplcb_conn_progress, /* connect_progress */ 824 prplcb_conn_connected, /* connected */ 825 prplcb_conn_disconnected, /* disconnected */ 826 prplcb_conn_notice, /* notice */ 827 NULL, /* report_disconnect */ 828 NULL, /* network_connected */ 829 NULL, /* network_disconnected */ 830 prplcb_conn_report_disconnect_reason, /* report_disconnect_reason */ 810 831 }; 811 832 … … 882 903 static PurpleBlistUiOps bee_blist_uiops = 883 904 { 884 NULL, 885 prplcb_blist_new, 886 NULL, 887 prplcb_blist_update, 888 prplcb_blist_remove, 905 NULL, /* new_list */ 906 prplcb_blist_new, /* new_node */ 907 NULL, /* show */ 908 prplcb_blist_update, /* update */ 909 prplcb_blist_remove, /* remove */ 889 910 }; 890 911 … … 895 916 struct groupchat *gc; 896 917 897 gc = imcb_chat_new(ic, conv->name); 898 if (conv->title != NULL) { 899 imcb_chat_name_hint(gc, conv->title); 918 gc = bee_chat_by_title(ic->bee, ic, conv->name); 919 920 if (!gc) { 921 gc = imcb_chat_new(ic, conv->name); 922 if (conv->title != NULL) { 923 imcb_chat_name_hint(gc, conv->title); 924 } 925 } 926 927 /* don't set the topic if it's just the name */ 928 if (conv->title != NULL && strcmp(conv->name, conv->title) != 0) { 900 929 imcb_chat_topic(gc, NULL, conv->title, 0); 901 930 } … … 940 969 } 941 970 942 void prplcb_conv_chat_msg(PurpleConversation *conv, const char *who, const char *message, PurpleMessageFlags flags, 943 time_t mtime) 944 { 971 /* Generic handler for IM or chat messages, covers write_chat, write_im and write_conv */ 972 static void handle_conv_msg(PurpleConversation *conv, const char *who, const char *message, guint32 bee_flags, time_t mtime) 973 { 974 struct im_connection *ic = purple_ic_by_pa(conv->account); 945 975 struct groupchat *gc = conv->ui_data; 946 976 PurpleBuddy *buddy; 947 948 /* ..._SEND means it's an outgoing message, no need to echo those. */949 if (flags & PURPLE_MESSAGE_SEND) {950 return;951 }952 977 953 978 buddy = purple_find_buddy(conv->account, who); … … 956 981 } 957 982 958 imcb_chat_msg(gc, who, (char *) message, 0, mtime); 959 } 960 961 static void prplcb_conv_im(PurpleConversation *conv, const char *who, const char *message, PurpleMessageFlags flags, 962 time_t mtime) 963 { 964 struct im_connection *ic = purple_ic_by_pa(conv->account); 965 PurpleBuddy *buddy; 966 967 /* ..._SEND means it's an outgoing message, no need to echo those. */ 983 if (conv->type == PURPLE_CONV_TYPE_IM) { 984 imcb_buddy_msg(ic, (char *) who, (char *) message, bee_flags, mtime); 985 } else if (gc) { 986 imcb_chat_msg(gc, who, (char *) message, bee_flags, mtime); 987 } 988 } 989 990 /* Handles write_im and write_chat. Removes echoes of locally sent messages */ 991 static void prplcb_conv_msg(PurpleConversation *conv, const char *who, const char *message, PurpleMessageFlags flags, time_t mtime) 992 { 993 if (!(flags & PURPLE_MESSAGE_SEND)) { 994 handle_conv_msg(conv, who, message, 0, mtime); 995 } 996 } 997 998 /* Handles write_conv. Only passes self messages from other locations through. 999 * That is, only writes of PURPLE_MESSAGE_SEND. 1000 * There are more events which might be handled in the future, but some are tricky. 1001 * (images look like <img id="123">, what do i do with that?) */ 1002 static void prplcb_conv_write(PurpleConversation *conv, const char *who, const char *alias, const char *message, 1003 PurpleMessageFlags flags, time_t mtime) 1004 { 968 1005 if (flags & PURPLE_MESSAGE_SEND) { 969 return; 970 } 971 972 buddy = purple_find_buddy(conv->account, who); 973 if (buddy != NULL) { 974 who = purple_buddy_get_name(buddy); 975 } 976 977 imcb_buddy_msg(ic, (char *) who, (char *) message, 0, mtime); 1006 handle_conv_msg(conv, who, message, OPT_SELFMESSAGE, mtime); 1007 } 978 1008 } 979 1009 … … 1008 1038 prplcb_conv_new, /* create_conversation */ 1009 1039 prplcb_conv_free, /* destroy_conversation */ 1010 prplcb_conv_ chat_msg,/* write_chat */1011 prplcb_conv_ im,/* write_im */1012 NULL,/* write_conv */1040 prplcb_conv_msg, /* write_chat */ 1041 prplcb_conv_msg, /* write_im */ 1042 prplcb_conv_write, /* write_conv */ 1013 1043 prplcb_conv_add_users, /* chat_add_users */ 1014 1044 NULL, /* chat_rename_user */ … … 1175 1205 static PurpleRequestUiOps bee_request_uiops = 1176 1206 { 1177 prplcb_request_input, 1178 NULL, 1179 prplcb_request_action, 1180 NULL, 1181 NULL, 1182 prplcb_close_request, 1183 NULL, 1207 prplcb_request_input, /* request_input */ 1208 NULL, /* request_choice */ 1209 prplcb_request_action, /* request_action */ 1210 NULL, /* request_fields */ 1211 NULL, /* request_file */ 1212 prplcb_close_request, /* close_request */ 1213 NULL, /* request_folder */ 1184 1214 }; 1185 1215 … … 1222 1252 static PurplePrivacyUiOps bee_privacy_uiops = 1223 1253 { 1224 prplcb_privacy_permit_added, 1225 prplcb_privacy_permit_removed, 1226 prplcb_privacy_deny_added, 1227 prplcb_privacy_deny_removed, 1254 prplcb_privacy_permit_added, /* permit_added */ 1255 prplcb_privacy_permit_removed, /* permit_removed */ 1256 prplcb_privacy_deny_added, /* deny_added */ 1257 prplcb_privacy_deny_removed, /* deny_removed */ 1228 1258 }; 1229 1259 … … 1235 1265 static PurpleDebugUiOps bee_debug_uiops = 1236 1266 { 1237 prplcb_debug_print, 1267 prplcb_debug_print, /* print */ 1238 1268 }; 1239 1269 … … 1256 1286 static PurpleEventLoopUiOps glib_eventloops = 1257 1287 { 1258 prplcb_ev_timeout_add, 1259 prplcb_ev_remove, 1260 prplcb_ev_input_add, 1261 prplcb_ev_remove, 1288 prplcb_ev_timeout_add, /* timeout_add */ 1289 prplcb_ev_remove, /* timeout_remove */ 1290 prplcb_ev_input_add, /* input_add */ 1291 prplcb_ev_remove, /* input_remove */ 1262 1292 }; 1293 1294 /* Absolutely no connection context at all. Thanks purple! brb crying */ 1295 static void *prplcb_notify_message(PurpleNotifyMsgType type, const char *title, 1296 const char *primary, const char *secondary) 1297 { 1298 char *text = g_strdup_printf("%s%s - %s%s%s", 1299 (type == PURPLE_NOTIFY_MSG_ERROR) ? "Error: " : "", 1300 title, 1301 primary ?: "", 1302 (primary && secondary) ? " - " : "", 1303 secondary ?: "" 1304 ); 1305 1306 if (local_bee->ui->log) { 1307 local_bee->ui->log(local_bee, "purple", text); 1308 } 1309 1310 g_free(text); 1311 1312 return NULL; 1313 } 1263 1314 1264 1315 static void *prplcb_notify_email(PurpleConnection *gc, const char *subject, const char *from, … … 1322 1373 static PurpleNotifyUiOps bee_notify_uiops = 1323 1374 { 1324 NULL,1325 prplcb_notify_email, 1326 NULL, 1327 NULL, 1328 NULL, 1329 NULL, 1330 prplcb_notify_userinfo, 1375 prplcb_notify_message, /* notify_message */ 1376 prplcb_notify_email, /* notify_email */ 1377 NULL, /* notify_emails */ 1378 NULL, /* notify_formatted */ 1379 NULL, /* notify_searchresults */ 1380 NULL, /* notify_searchresults_new_rows */ 1381 prplcb_notify_userinfo, /* notify_userinfo */ 1331 1382 }; 1332 1383 … … 1355 1406 static PurpleAccountUiOps bee_account_uiops = 1356 1407 { 1357 NULL, 1358 NULL, 1359 NULL, 1360 prplcb_account_request_authorize, 1361 NULL, 1408 NULL, /* notify_added */ 1409 NULL, /* status_changed */ 1410 NULL, /* request_add */ 1411 prplcb_account_request_authorize, /* request_authorize */ 1412 NULL, /* close_account_request */ 1362 1413 }; 1363 1414 … … 1387 1438 char *dir; 1388 1439 1389 if (B_EV_IO_READ != PURPLE_INPUT_READ || 1390 B_EV_IO_WRITE != PURPLE_INPUT_WRITE) { 1391 /* FIXME FIXME FIXME FIXME FIXME :-) */ 1392 exit(1); 1393 } 1440 g_assert((int) B_EV_IO_READ == (int) PURPLE_INPUT_READ); 1441 g_assert((int) B_EV_IO_WRITE == (int) PURPLE_INPUT_WRITE); 1394 1442 1395 1443 dir = g_strdup_printf("%s/purple", global.conf->configdir); … … 1409 1457 PurpleProxyInfo *pi = purple_global_proxy_get_info(); 1410 1458 switch (proxytype) { 1459 case PROXY_SOCKS4A: 1411 1460 case PROXY_SOCKS4: 1412 1461 purple_proxy_info_set_type(pi, PURPLE_PROXY_SOCKS4); -
protocols/skype/README
r63cad66 r3fbce97 203 203 204 204 * `account skype set skypeconsole_receive true` will make the 205 `skypeconsole` account dump all the rec ieved raw traffic for you205 `skypeconsole` account dump all the received raw traffic for you 206 206 207 207 - If you want to automatically join bookmarked groupchats right after -
protocols/skype/skype.c
r63cad66 r3fbce97 21 21 22 22 #define _XOPEN_SOURCE 23 #define _BSD_SOURCE24 23 #include <poll.h> 25 24 #include <stdio.h> … … 188 187 189 188 va_start(args, fmt); 190 vsnprintf(str, IRC_LINE_SIZE, fmt, args);189 g_vsnprintf(str, IRC_LINE_SIZE, fmt, args); 191 190 va_end(args); 192 191 … … 322 321 } 323 322 return NULL; 323 } 324 325 static struct groupchat *skype_chat_get_or_create(struct im_connection *ic, char *id) 326 { 327 struct skype_data *sd = ic->proto_data; 328 struct groupchat *gc = bee_chat_by_title(ic->bee, ic, id); 329 330 if (!gc) { 331 gc = imcb_chat_new(ic, id); 332 imcb_chat_name_hint(gc, id); 333 imcb_chat_add_buddy(gc, sd->username); 334 335 skype_printf(ic, "GET CHAT %s ADDER\n", id); 336 skype_printf(ic, "GET CHAT %s TOPIC\n", id); 337 skype_printf(ic, "GET CHAT %s ACTIVEMEMBERS\n", id); 338 } 339 340 return gc; 324 341 } 325 342 … … 688 705 info += 9; 689 706 if (sd->handle && sd->body && sd->type) { 690 struct groupchat *gc = bee_chat_by_title(ic->bee,ic, info);707 struct groupchat *gc = skype_chat_get_or_create(ic, info); 691 708 int i; 692 709 for (i = 0; i < g_list_length(sd->body); i++) { … … 1026 1043 } 1027 1044 if (!strcmp(info, "STATUS MULTI_SUBSCRIBED")) { 1028 gc = bee_chat_by_title(ic->bee, ic, id); 1029 if (!gc) { 1030 gc = imcb_chat_new(ic, id); 1031 imcb_chat_name_hint(gc, id); 1032 } 1033 skype_printf(ic, "GET CHAT %s ADDER\n", id); 1034 skype_printf(ic, "GET CHAT %s TOPIC\n", id); 1045 skype_chat_get_or_create(ic, id); 1035 1046 } else if (!strcmp(info, "STATUS DIALOG") && sd->groupchat_with) { 1036 gc = imcb_chat_new(ic, id); 1037 imcb_chat_name_hint(gc, id); 1047 gc = skype_chat_get_or_create(ic, id); 1038 1048 /* According to the docs this 1039 1049 * is necessary. However it … … 1046 1056 sd->groupchat_with); 1047 1057 imcb_chat_add_buddy(gc, buf); 1048 imcb_chat_add_buddy(gc, sd->username);1049 1058 g_free(sd->groupchat_with); 1050 1059 sd->groupchat_with = NULL; 1051 skype_printf(ic, "GET CHAT %s ADDER\n", id);1052 skype_printf(ic, "GET CHAT %s TOPIC\n", id);1053 1060 } else if (!strcmp(info, "STATUS UNSUBSCRIBED")) { 1054 1061 gc = bee_chat_by_title(ic->bee, ic, id); … … 1257 1264 } 1258 1265 g_strfreev(lines); 1259 } else if (st == 0 || (st < 0 && !s ockerr_again())) {1266 } else if (st == 0 || (st < 0 && !ssl_sockerr_again(sd->ssl))) { 1260 1267 ssl_disconnect(sd->ssl); 1261 1268 sd->fd = -1; -
protocols/skype/t/add-yes-bitlbee.mock
r63cad66 r3fbce97 1 >> NOTICE AUTH1 >> NOTICE * 2 2 << NICK alice 3 3 << USER alice alice localhost :Alice -
protocols/skype/t/added-no-bitlbee.mock
r63cad66 r3fbce97 1 >> NOTICE AUTH1 >> NOTICE * 2 2 << NICK alice 3 3 << USER alice alice localhost :Alice -
protocols/skype/t/added-yes-bitlbee.mock
r63cad66 r3fbce97 1 >> NOTICE AUTH1 >> NOTICE * 2 2 << NICK alice 3 3 << USER alice alice localhost :Alice -
protocols/skype/t/away-set-bitlbee.mock
r63cad66 r3fbce97 1 >> NOTICE AUTH1 >> NOTICE * 2 2 << NICK alice 3 3 << USER alice alice localhost :Alice -
protocols/skype/t/call-bitlbee.mock
r63cad66 r3fbce97 1 >> NOTICE AUTH1 >> NOTICE * 2 2 << NICK alice 3 3 << USER alice alice localhost :alice -
protocols/skype/t/call-failed-bitlbee.mock
r63cad66 r3fbce97 1 >> NOTICE AUTH1 >> NOTICE * 2 2 << NICK alice 3 3 << USER alice alice localhost :alice -
protocols/skype/t/called-no-bitlbee.mock
r63cad66 r3fbce97 1 >> NOTICE AUTH1 >> NOTICE * 2 2 << NICK alice 3 3 << USER alice alice localhost :Alice -
protocols/skype/t/called-yes-bitlbee.mock
r63cad66 r3fbce97 1 >> NOTICE AUTH1 >> NOTICE * 2 2 << NICK alice 3 3 << USER alice alice localhost :Alice -
protocols/skype/t/ctcp-help-bitlbee.mock
r63cad66 r3fbce97 1 >> NOTICE AUTH1 >> NOTICE * 2 2 << NICK alice 3 3 << USER alice alice localhost :Alice -
protocols/skype/t/filetransfer-bitlbee.mock
r63cad66 r3fbce97 1 >> NOTICE AUTH1 >> NOTICE * 2 2 << NICK alice 3 3 << USER alice alice localhost :Alice -
protocols/skype/t/group-add-bitlbee.mock
r63cad66