diff options
96 files changed, 256 insertions, 8424 deletions
diff --git a/.travis.yml b/.travis.yml index 67eb4aa1..4127f1a7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ language: c script: - ./configure --pam=1 --ldap=1 - make check - - BITLBEE_SKYPE=plugin dpkg-buildpackage -uc -us -d + - dpkg-buildpackage -uc -us -d # ubuntu precise doesn't have libotr5, so extract a prebuilt version to ~/otr before_install: @@ -18,7 +18,7 @@ OUTFILE = bitlbee # Expansion of variables subdirobjs = $(foreach dir,$(subdirs),$(dir)/$(dir).o) -all: $(OUTFILE) $(OTR_PI) $(SKYPE_PI) doc systemd +all: $(OUTFILE) $(OTR_PI) doc systemd doc: ifdef DOC @@ -58,9 +58,6 @@ Makefile.settings: clean: $(subdirs) rm -f *.o $(OUTFILE) core utils/bitlbeed init/bitlbee*.service $(MAKE) -C tests clean -ifdef SKYPE_PI - $(MAKE) -C protocols/skype clean -endif distclean: clean $(subdirs) rm -rf .depend @@ -84,17 +81,11 @@ install-doc: ifdef DOC $(MAKE) -C doc install endif -ifdef SKYPE_PI - $(MAKE) -C protocols/skype install-doc -endif uninstall-doc: ifdef DOC $(MAKE) -C doc uninstall endif -ifdef SKYPE_PI - $(MAKE) -C protocols/skype uninstall-doc -endif install-bin: mkdir -p $(DESTDIR)$(SBINDIR) @@ -141,7 +132,7 @@ uninstall-etc: rm -f $(DESTDIR)$(ETCDIR)/bitlbee.conf.sample -rmdir $(DESTDIR)$(ETCDIR) -install-plugins: install-plugin-otr install-plugin-skype +install-plugins: install-plugin-otr install-plugin-otr: ifdef OTR_PI @@ -149,17 +140,6 @@ ifdef OTR_PI $(INSTALL) -m 0755 otr.so $(DESTDIR)$(PLUGINDIR) endif -install-plugin-skype: -ifdef SKYPE_PI - mkdir -p $(DESTDIR)$(PLUGINDIR) - $(INSTALL) -m 0755 skype.so $(DESTDIR)$(PLUGINDIR) - mkdir -p $(DESTDIR)$(ETCDIR)/../skyped $(DESTDIR)$(BINDIR) - $(INSTALL) -m 0644 $(_SRCDIR_)protocols/skype/skyped.cnf $(DESTDIR)$(ETCDIR)/../skyped/skyped.cnf - $(INSTALL) -m 0644 $(_SRCDIR_)protocols/skype/skyped.conf.dist $(DESTDIR)$(ETCDIR)/../skyped/skyped.conf - $(INSTALL) -m 0755 $(_SRCDIR_)protocols/skype/skyped.py $(DESTDIR)$(BINDIR)/skyped - $(MAKE) -C protocols/skype install-doc -endif - systemd: ifdef SYSTEMDSYSTEMUNITDIR mkdir -p init @@ -190,10 +170,6 @@ $(OTR_PI): %.so: $(_SRCDIR_)%.c @echo '*' Building plugin $@ $(VERBOSE) $(CC) $(CFLAGS) -fPIC -shared $(LDFLAGS) $< -o $@ $(OTRFLAGS) -$(SKYPE_PI): $(_SRCDIR_)protocols/skype/skype.c - @echo '*' Building plugin skype - $(VERBOSE) $(CC) $(CFLAGS) $(LDFLAGS) $(SKYPEFLAGS) $< -o $@ - $(objects): %.o: $(_SRCDIR_)%.c @echo '*' Compiling $< $(VERBOSE) $(CC) -c $(CFLAGS) $(CFLAGS_BITLBEE) $< -o $@ @@ -119,6 +119,12 @@ int bitlbee_daemon_init() freeaddrinfo(addrinfo_bind); + if (global.listen_socket == -1 && errno == EADDRINUSE) { + log_message(LOGLVL_ERROR, "Can't listen on port %s. Is another bitlbee already running?", + global.conf->port); + return(-1); + } + i = listen(global.listen_socket, 10); if (i == -1) { log_error("listen"); @@ -32,7 +32,6 @@ configure_args="$@" # If the user sets one of these to 1, purple won't disable them. # Otherwise, if it's still default-on, it gets included in normal builds, # but not purple ones. -msn="default-on" jabber="default-on" oscar="default-on" @@ -47,8 +46,6 @@ gcov=0 asan=0 plugins=1 otr=0 -skype=0 -devel=0 events=glib ssl=auto @@ -130,7 +127,6 @@ Option Description Default --verbose=0/1 Disable/enable verbose build $verbose ---msn=0/1 Disable/enable MSN part $msn --jabber=0/1 Disable/enable Jabber part $jabber --oscar=0/1 Disable/enable Oscar part (ICQ, AIM) $oscar --twitter=0/1 Disable/enable Twitter part $twitter @@ -150,9 +146,6 @@ Option Description Default --plugins=0/1 Disable/enable plugins support $plugins --otr=0/1/auto/plugin Disable/enable OTR encryption support $otr ---skype=0/1/plugin - Disable/enable Skype support $skype ---devel=0/1 Disable/enable header install $devel --events=... Event handler (glib, libevent) $events --ssl=... SSL library to use (gnutls, nss, openssl, auto) @@ -345,9 +338,9 @@ else fi echo "CC=$CC" >> Makefile.settings; -if echo $CC | grep -qw gcc; then +if echo $CC | grep -qw 'gcc\|clang'; then # Apparently -Wall is gcc-specific? - echo CFLAGS+=-Wall >> Makefile.settings + echo CFLAGS+=-Wall -Wformat -Werror=format-security >> Makefile.settings fi if [ -z "$LD" ]; then @@ -495,6 +488,16 @@ int main() } ' +BACKTRACE_TESTCODE=' +#include <execinfo.h> + +int main() +{ + void *trace[16]; + return backtrace(trace, 16); +} +' + detect_resolv_dynamic() { case "$arch" in @@ -592,6 +595,19 @@ detect_nameser_has_ns_types() return $ret } +detect_backtrace() +{ + TMPFILE=$(mktemp /tmp/bitlbee-configure.XXXXXX) + ret=1 + echo "$BACKTRACE_TESTCODE" | $CC -o $TMPFILE -x c - >/dev/null 2>/dev/null + if [ "$?" = "0" ]; then + ret=0 + fi + + rm -f $TMPFILE + return $ret +} + if [ "$ssl" = "auto" ]; then detect_gnutls if [ "$ret" = "0" ]; then @@ -661,6 +677,10 @@ else echo 'Insufficient resolv routines. Jabber server must be set explicitly' fi +if detect_backtrace; then + echo '#define HAVE_BACKTRACE' >> config.h + echo '#define CRASHFILE "'$config'crash.log"' >> config.h +fi STORAGES="xml" @@ -764,16 +784,6 @@ elif [ "$otr" = "plugin" ]; then echo 'OTR_PI=otr.so' >> Makefile.settings fi -if [ "$skype" = "1" -o "$skype" = "plugin" ]; then - if [ "$arch" = "Darwin" ]; then - echo "SKYPEFLAGS=-dynamiclib -undefined dynamic_lookup" >> Makefile.settings - else - echo "SKYPEFLAGS=-fPIC -shared" >> Makefile.settings - fi - echo 'SKYPE_PI=skype.so' >> Makefile.settings - protocols_mods="$protocol_mods skype(plugin)" -fi - if [ -z "$PYTHON" ]; then PYTHON=python fi @@ -855,7 +865,6 @@ EOF protoobjs=$protoobjs'purple_mod.o ' # only disable these if the user didn't enable them explicitly - [ "$msn" = "default-on" ] && msn=0 [ "$jabber" = "default-on" ] && jabber=0 [ "$oscar" = "default-on" ] && oscar=0 @@ -878,14 +887,6 @@ case "$CC" in done esac -if [ "$msn" = 0 ]; then - echo '#undef WITH_MSN' >> config.h -else - echo '#define WITH_MSN' >> config.h - protocols=$protocols'msn ' - protoobjs=$protoobjs'msn_mod.o ' -fi - if [ "$jabber" = 0 ]; then echo '#undef WITH_JABBER' >> config.h else diff --git a/debian/bitlbee-plugin-skype.docs b/debian/bitlbee-plugin-skype.docs deleted file mode 100644 index 3f99862a..00000000 --- a/debian/bitlbee-plugin-skype.docs +++ /dev/null @@ -1,2 +0,0 @@ -protocols/skype/NEWS -protocols/skype/README diff --git a/debian/changelog b/debian/changelog index 7c411798..ff6ec7e1 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,16 @@ +bitlbee (3.5.1-1.1) UNRELEASED; urgency=medium + + * Remove bitlbee-plugin-skype and skyped (obsolete) + * Enable only bitlbee.service, not bitlbee.socket too + + -- dequis <dx@dxzone.com.ar> Mon, 19 Mar 2018 22:18:43 -0300 + +bitlbee (3.5.1-1) unstable; urgency=medium + + * Crash bug fix. (Closes: #853282) + + -- Wilmer van der Gaast <wilmer@gaast.net> Thu, 09 Feb 2017 00:46:53 +0000 + bitlbee (3.5-2) unstable; urgency=medium * TFW you find out the corrected fix diff posted on #821967 was still the diff --git a/debian/compat b/debian/compat index 1e8b3149..ec635144 100644 --- a/debian/compat +++ b/debian/compat @@ -1 +1 @@ -6 +9 diff --git a/debian/control b/debian/control index 89a7efb3..9f7db6db 100644 --- a/debian/control +++ b/debian/control @@ -68,26 +68,3 @@ Description: IRC to other chat networks gateway (OTR plugin) . This package contains a plugin that adds support for Off-The-Record encryption of instant messages. - -Package: bitlbee-plugin-skype -Architecture: any -Depends: ${misc:Depends}, ${shlibs:Depends}, bitlbee (= ${binary:Version}) | bitlbee-libpurple (= ${binary:Version}), bitlbee-common (= ${source:Version}) -Recommends: skyped -Description: IRC to other chat networks gateway (Skype plugin) - This program can be used as an IRC server which forwards everything you - say to people on other chat networks: Jabber (which includes Google - Talk), ICQ, AIM, MSN and Twitter. - . - This package contains a plugin that adds support for the Skype IM network. - You need to download and install the Skype client for this to work. - -Package: skyped -Architecture: all -Depends: ${misc:Depends}, ${shlibs:Depends}, python (>= 2.5), python-gnutls, python-skype (>=0.9.28.7) -Recommends: skype -Description: Daemon to control Skype remotely - Daemon to control the GUI Skype client. Currently required to control Skype - from the BitlBee IRC2IM gateway. Skyped and Skype can run on a different - host than the BitlBee server, the communication is encrypted. - . - You need to download and install the Skype client for this to work. diff --git a/debian/rules b/debian/rules index e31e0710..8cdb9628 100755 --- a/debian/rules +++ b/debian/rules @@ -8,11 +8,8 @@ # # Include the bitlbee-libpurple variant and OTR plugin by default. -# Don't build skype by default since it depends on deleted/non-free -# packages. Need to at least get python-skype back into Debian. BITLBEE_LIBPURPLE ?= 1 BITLBEE_OTR ?= plugin -BITLBEE_SKYPE ?= 0 BITLBEE_CONFIGURE_FLAGS ?= DEBUG ?= 0 @@ -29,10 +26,6 @@ ifneq ($(BITLBEE_OTR),plugin) DH_OPTIONS += -Nbitlbee-plugin-otr endif -ifneq ($(BITLBEE_SKYPE),plugin) -DH_OPTIONS += -Nbitlbee-plugin-skype -Nskyped -endif - CPPFLAGS:=$(shell dpkg-buildflags --get CPPFLAGS) CFLAGS:=$(shell dpkg-buildflags --get CFLAGS) LDFLAGS:=$(shell dpkg-buildflags --get LDFLAGS) @@ -51,12 +44,12 @@ build-stamp: dh_testdir mkdir -p debian/build-native - ROOT=$$PWD; cd debian/build-native; $(BITLBEE_CONFIGURE_VERSION) $(CONFIGURE_OVERRIDES) $$ROOT/configure --debug=$(DEBUG) --prefix=/usr --etcdir=/etc/bitlbee --events=libevent --otr=$(BITLBEE_OTR) --skype=$(BITLBEE_SKYPE) $(BITLBEE_CONFIGURE_FLAGS) + ROOT=$$PWD; cd debian/build-native; $(BITLBEE_CONFIGURE_VERSION) $(CONFIGURE_OVERRIDES) $$ROOT/configure --debug=$(DEBUG) --prefix=/usr --etcdir=/etc/bitlbee --events=libevent --otr=$(BITLBEE_OTR) --systemdsystemunitdir=/lib/systemd/system $(BITLBEE_CONFIGURE_FLAGS) $(MAKE) -C debian/build-native ifeq ($(BITLBEE_LIBPURPLE),1) mkdir -p debian/build-libpurple - ROOT=$$PWD; cd debian/build-libpurple; $(BITLBEE_CONFIGURE_VERSION) $(CONFIGURE_OVERRIDES) $$ROOT/configure --debug=$(DEBUG) --prefix=/usr --etcdir=/etc/bitlbee --purple=1 $(BITLBEE_CONFIGURE_FLAGS) + ROOT=$$PWD; cd debian/build-libpurple; $(BITLBEE_CONFIGURE_VERSION) $(CONFIGURE_OVERRIDES) $$ROOT/configure --debug=$(DEBUG) --prefix=/usr --etcdir=/etc/bitlbee --systemdsystemunitdir=/lib/systemd/system --purple=1 $(BITLBEE_CONFIGURE_FLAGS) $(MAKE) -C debian/build-libpurple endif @@ -85,20 +78,11 @@ install: build $(MAKE) -C debian/build-native install-etc install-doc DESTDIR=`pwd`/debian/bitlbee-common $(MAKE) -C debian/build-native install-dev DESTDIR=`pwd`/debian/bitlbee-dev $(MAKE) -C debian/build-native install-plugin-otr DESTDIR=`pwd`/debian/bitlbee-plugin-otr - $(MAKE) -C debian/build-native install-plugin-skype DESTDIR=`pwd`/debian/skyped ifeq ($(HAS_DH_SYSTEMD),1) $(MAKE) -C debian/build-native install-systemd DESTDIR=`pwd`/debian/bitlbee-common endif -ifneq ($(BITLBEE_SKYPE),0) - mkdir -p debian/bitlbee-plugin-skype/usr - mv debian/skyped/usr/lib debian/bitlbee-plugin-skype/usr - - mkdir -p debian/skyped/usr/share/man/man1 - mv debian/bitlbee-common/usr/share/man/man1/skyped* debian/skyped/usr/share/man/man1 -endif - ifeq ($(BITLBEE_LIBPURPLE),1) $(MAKE) -C debian/build-libpurple install-bin DESTDIR=`pwd`/debian/bitlbee-libpurple ln -sf debian/bitlbee.prerm debian/bitlbee-libpurple.prerm @@ -119,12 +103,12 @@ binary-common: for p in bitlbee bitlbee-libpurple bitlbee-dev bitlbee-plugin-otr; do rm -r debian/$$p/usr/share/doc/$$p && ln -s bitlbee-common debian/$$p/usr/share/doc/$$p || true; done dh_installdebconf ifeq ($(HAS_DH_SYSTEMD),1) - dh_systemd_enable --no-enable bitlbee.socket - dh_systemd_enable bitlbee.service - dh_installinit --init-script=bitlbee - dh_systemd_start + dh_systemd_enable -p bitlbee-common --no-enable bitlbee.socket + dh_systemd_enable -p bitlbee-common bitlbee.service + dh_installinit -p bitlbee-common --init-script=bitlbee + dh_systemd_start -p bitlbee-common else - dh_installinit --init-script=bitlbee + dh_installinit -p bitlbee-common --init-script=bitlbee endif dh_installman dh_lintian diff --git a/debian/skyped.README.Debian b/debian/skyped.README.Debian deleted file mode 100644 index 502e6147..00000000 --- a/debian/skyped.README.Debian +++ /dev/null @@ -1,18 +0,0 @@ -bitlbee-skype for Debian ------------------------- - -The upstream package installs global configuration files in /etc. Since -configuration cannot be used by multiple users, however, the default for -Debian packages is in ~/.skyped/. Please copy the configuration files -from ./examples to ~/.skyped/. - -You will also need to change the configuration values in skyped.conf -and skyped.cnf to suit your needs and create the keys. More information -in the respective files as well as the README.gz. - -Without these measures, skyped will NOT work. - -You need to download the official skype client for this to be of any -use. Go to http://www.skype.com/. - - -- David Spreen <netzwurm@debian.org>, Thu, 2 Apr 2009 15:01:25 -0700 diff --git a/debian/skyped.docs b/debian/skyped.docs deleted file mode 100644 index 3f99862a..00000000 --- a/debian/skyped.docs +++ /dev/null @@ -1,2 +0,0 @@ -protocols/skype/NEWS -protocols/skype/README diff --git a/doc/bitlbee.8 b/doc/bitlbee.8 index 2170270d..f3f5159d 100644 --- a/doc/bitlbee.8 +++ b/doc/bitlbee.8 @@ -40,34 +40,48 @@ networks and acts as a gateway. Users can connect to the server with any normal IRC client and see their 'buddy list' in &bitlbee. -\fBbitlbee\fP should be called by -.BR inetd (8), -or you can run it as a stand-alone daemon. +\fBbitlbee\fP is normally started as a system service (with init +scripts, systemd units or equivalent). It can also be run as an +.BR inetd (8) +/ +.BR xinetd (8) +service or a stand-alone daemon with the options below. + +To use it, connect to it with an IRC client with a command such as +"/connect localhost" + .PP -.SH OPTIONS +.SH RUN MODES .PP .IP "-I" Run in .BR inetd (8) -mode. This is the default setting, you usually don't have to specify this -option. +mode. This is the default setting for historical reasons, but not the +recommended one (See ForkDaemon below). .IP "-D" -Run in daemon mode. In this mode, BitlBee forks to the background and +Run in \fBDaemon\fP mode. In this mode, BitlBee forks to the background and waits for new connections. All clients will be served from one process. +This mode is also useful for debugging. .IP "-F" -Run in ForkDaemon mode. This is similar to ordinary daemon mode, but every +Run in \fBForkDaemon\fP mode. This is similar to ordinary daemon mode, but every client gets its own process. Easier to set up than inetd mode, and without -the possible stability issues. +the possible stability issues. This is the recommended runmode for most +use cases. + +.PP +.SH OPTIONS +.PP + .IP "-i \fIaddress\fP" -Only useful when running in daemon mode, to specify the network interface +When running in daemon mode, specifies the network interface (identified by IP address) to which the daemon should attach. Use this if you don't want BitlBee to listen on every interface (which is the default behaviour). .IP "-p \fIport number\fP" -Only useful when running in daemon mode, to specify the port number on +When running in daemon mode, specifies the port number on which BitlBee should listen for connections. 6667 is the default value. .IP "-n" -Only useful when running in daemon mode. This option prevents BitlBee from +Wehn running in daemon mode, this option prevents BitlBee from forking into the background. .IP "-v" Be more verbose. This only works together with the \fB-n\fP flag. @@ -81,17 +95,15 @@ have write permissions in the default location), use this option. Show help information. .SH COMMANDS To get a complete list of commands, please use the \fBhelp commands\fP -command in the &bitlbee channel. +command in the &bitlbee channel after connecting to bitlbee. .SH "SEE ALSO" -.BR ircd (8), .BR inetd (8), -.BR inetd.conf (5), -.BR gaim (1). +.BR inetd.conf (5) .BR http://www.bitlbee.org/ For more information on using BitlBee, once connected, you should use -the on-line help system. +the \fBhelp\fP command in the &bitlbee channel. .SH BUGS Of course there are bugs. If you find some, please report them at \fBhttp://bugs.bitlbee.org/\fP. diff --git a/doc/user-guide/Installation.xml b/doc/user-guide/Installation.xml index 9d555d46..879649f6 100644 --- a/doc/user-guide/Installation.xml +++ b/doc/user-guide/Installation.xml @@ -35,7 +35,7 @@ specify them all separately, just specifying prefix (or keeping the default <listitem><para>config - The place where BitlBee will save all the per-user settings and buddy information. <filename>/var/lib/bitlbee/</filename> is the default value.</para></listitem> -<listitem><para>msn, jabber, oscar, twitter - By default, support for all +<listitem><para>jabber, oscar, twitter - By default, support for all these IM-protocols (OSCAR is the protocol used by both ICQ and AIM) will be compiled in. To make the binary a bit smaller, you can use these options to leave out support for protocols you're not planning to use.</para></listitem> @@ -49,8 +49,7 @@ will be stripped out to make it as small as possible. If you don't want this <listitem><para>flood - To secure your BitlBee server against flooding attacks, you can use this option. It's not compiled in by default because it needs more testing first.</para></listitem> -<listitem><para>ssl - The MSN and Jabber modules require an SSL library for -some of their tasks. BitlBee can use three different SSL libraries: GnuTLS, +<listitem><para>ssl - BitlBee can use three different SSL libraries: GnuTLS, mozilla-nss and OpenSSL. (OpenSSL is, however, a bit troublesome because of licensing issues, so don't forget to read the information configure will give you when you try to use OpenSSL!) By default, configure will try to diff --git a/doc/user-guide/commands.xml b/doc/user-guide/commands.xml index f20e3298..35a1300c 100644 --- a/doc/user-guide/commands.xml +++ b/doc/user-guide/commands.xml @@ -42,16 +42,6 @@ </description> </bitlbee-command> - <bitlbee-command name="msn"> - <syntax>account add msn <handle@server.tld> [<password>]</syntax> - - <description> - <para> - For MSN connections there are no special arguments. - </para> - </description> - </bitlbee-command> - <bitlbee-command name="oscar"> <syntax>account add oscar <handle> [<password>]</syntax> @@ -923,13 +913,10 @@ <bitlbee-setting name="display_name" type="string" scope="account"> <description> <para> - Currently only available for MSN connections, and for jabber groupchats. - </para> - <para> - For MSN: This setting allows you to read and change your "friendly name" for this connection. Since this is a server-side setting, it can't be changed when the account is off-line. + Currently only available for jabber groupchats. </para> <para> - For jabber groupchats: this sets the default value of 'nick' for newly created groupchats. There is no way to set an account-wide nick like MSN. + For jabber groupchats: this sets the default value of 'nick' for newly created groupchats. There is no way to set an account-wide nick. </para> </description> </bitlbee-setting> @@ -1027,17 +1014,6 @@ </bitlbee-setting> - <bitlbee-setting name="local_display_name" type="boolean" scope="account"> - <default>false</default> - - <description> - <para> - Mostly meant to work around a bug in MSN servers (forgetting the display name set by the user), this setting tells BitlBee to store your display name locally and set this name on the MSN servers when connecting. - </para> - </description> - - </bitlbee-setting> - <bitlbee-setting name="mail_notifications" type="boolean" scope="account"> <default>false</default> @@ -1061,11 +1037,11 @@ </bitlbee-setting> <bitlbee-setting name="message_length" type="integer" scope="account"> - <default>140</default> + <default>280</default> <description> <para> - Since Twitter rejects messages longer than 140 characters, BitlBee can count message length and emit a warning instead of waiting for Twitter to reject it. + Since Twitter rejects messages longer than 280 characters, BitlBee can count message length and emit a warning instead of waiting for Twitter to reject it. </para> <para> @@ -1619,24 +1595,6 @@ </description> </bitlbee-setting> - <bitlbee-setting name="switchboard_keepalives" type="boolean" scope="account"> - <default>false</default> - - <description> - <para> - Turn on this flag if you have difficulties talking to offline/invisible contacts. - </para> - - <para> - With this setting enabled, BitlBee will send keepalives to MSN switchboards with offline/invisible contacts every twenty seconds. This should keep the server and client on the other side from shutting it down. - </para> - - <para> - This is useful because BitlBee doesn't support MSN offline messages yet and the MSN servers won't let the user reopen switchboards to offline users. Once offline messaging is supported, this flag might be removed. - </para> - </description> - </bitlbee-setting> - <bitlbee-setting name="tag" type="string" scope="account"> <description> <para> diff --git a/doc/user-guide/misc.xml b/doc/user-guide/misc.xml index 457d5d35..1201467f 100644 --- a/doc/user-guide/misc.xml +++ b/doc/user-guide/misc.xml @@ -1,53 +1,6 @@ <chapter id="misc"> <title>Misc Stuff</title> -<sect1 id="smileys"> -<title>Smileys</title> - -<para> -All MSN smileys (except one) are case insensitive and work without the nose too. -</para> - -<variablelist> - <varlistentry><term>(Y)</term><listitem><para>Thumbs up</para></listitem></varlistentry> - <varlistentry><term>(N)</term><listitem><para>Thumbs down</para></listitem></varlistentry> - <varlistentry><term>(B)</term><listitem><para>Beer mug</para></listitem></varlistentry> - <varlistentry><term>(D)</term><listitem><para>Martini glass</para></listitem></varlistentry> - <varlistentry><term>(X)</term><listitem><para>Girl</para></listitem></varlistentry> - <varlistentry><term>(Z)</term><listitem><para>Boy</para></listitem></varlistentry> - <varlistentry><term>(6)</term><listitem><para>Devil smiley</para></listitem></varlistentry> - <varlistentry><term>:-[</term><listitem><para>Vampire bat</para></listitem></varlistentry> - <varlistentry><term>(})</term><listitem><para>Right hug</para></listitem></varlistentry> - <varlistentry><term>({)</term><listitem><para>Left hug</para></listitem></varlistentry> - <varlistentry><term>(M)</term><listitem><para>MSN Messenger or Windows Messenger icon (think a BitlBee logo here ;)</para></listitem></varlistentry> - <varlistentry><term>:-S</term><listitem><para>Crooked smiley (Confused smiley)</para></listitem></varlistentry> - <varlistentry><term>:-$</term><listitem><para>Embarrassed smiley</para></listitem></varlistentry> - <varlistentry><term>(H)</term><listitem><para>Smiley with sunglasses</para></listitem></varlistentry> - <varlistentry><term>:-@</term><listitem><para>Angry smiley</para></listitem></varlistentry> - <varlistentry><term>(A)</term><listitem><para>Angel smiley</para></listitem></varlistentry> - <varlistentry><term>(L)</term><listitem><para>Red heart (Love)</para></listitem></varlistentry> - <varlistentry><term>(U)</term><listitem><para>Broken heart</para></listitem></varlistentry> - <varlistentry><term>(K)</term><listitem><para>Red lips (Kiss)</para></listitem></varlistentry> - <varlistentry><term>(G)</term><listitem><para>Gift with bow</para></listitem></varlistentry> - <varlistentry><term>(F)</term><listitem><para>Red rose</para></listitem></varlistentry> - <varlistentry><term>(W)</term><listitem><para>Wilted rose</para></listitem></varlistentry> - <varlistentry><term>(P)</term><listitem><para>Camera</para></listitem></varlistentry> - <varlistentry><term>(~)</term><listitem><para>Film strip</para></listitem></varlistentry> - <varlistentry><term>(T)</term><listitem><para>Telephone receiver</para></listitem></varlistentry> - <varlistentry><term>(@)</term><listitem><para>Cat face</para></listitem></varlistentry> - <varlistentry><term>(&)</term><listitem><para>Dog's head</para></listitem></varlistentry> - <varlistentry><term>(C)</term><listitem><para>Coffee cup</para></listitem></varlistentry> - <varlistentry><term>(I)</term><listitem><para>Light bulb</para></listitem></varlistentry> - <varlistentry><term>(S)</term><listitem><para>Half-moon (Case sensitive!)</para></listitem></varlistentry> - <varlistentry><term>(*)</term><listitem><para>Star</para></listitem></varlistentry> - <varlistentry><term>(8)</term><listitem><para>Musical eighth note</para></listitem></varlistentry> - <varlistentry><term>(E)</term><listitem><para>Envelope</para></listitem></varlistentry> - <varlistentry><term>(^)</term><listitem><para>Birthday cake</para></listitem></varlistentry> - <varlistentry><term>(O)</term><listitem><para>Clock</para></listitem></varlistentry> -</variablelist> - -</sect1> - <sect1 id="groupchats"> <title>Groupchats</title> <para> @@ -152,7 +105,7 @@ Control channels are where you see your contacts. By default, you will have one </para> <para> -For example, you can have one channel with all contacts from your MSN Messenger account in it. Or all contacts from the group called "Work". +For example, you can have one channel with all contacts from your jabber account in it. Or all contacts from the group called "Work". </para> <para> @@ -169,7 +122,7 @@ When you create a new channel, BitlBee will try to guess from its name which con </para> <para> -Any valid account ID (so a number, protocol name or part of screenname, as long as it's unique) can also be used as a channel name. So if you just join &msn, it will contain all your MSN contacts. And if you have a Facebook account set up, you can see its contacts by just joining &facebook. +Any valid account ID (so a number, protocol name or part of screenname, as long as it's unique) can also be used as a channel name. So if you just join &jabber, it will contain all your jabber contacts. And if you have a Facebook account set up, you can see its contacts by just joining &facebook. </para> <para> diff --git a/doc/user-guide/quickstart.xml b/doc/user-guide/quickstart.xml index 2eda6be1..6de9b953 100644 --- a/doc/user-guide/quickstart.xml +++ b/doc/user-guide/quickstart.xml @@ -42,7 +42,7 @@ For instance, suppose you have a Jabber account at jabber.org with handle <empha </ircexample> <para> -Other built-in IM protocols include msn, oscar and twitter. OSCAR is the protocol used by ICQ and AOL. Some protocols may be available as plugins that you can install, such as facebook, steam, discord and omegle. And you can get even more protocols by using the libpurple variant of BitlBee. +Other built-in IM protocols include oscar and twitter. OSCAR is the protocol used by ICQ and AOL. Some protocols may be available as plugins that you can install, such as facebook, steam, discord and omegle. And you can get even more protocols by using the libpurple variant of BitlBee. </para> <para> @@ -123,7 +123,7 @@ You know the basics. If you want to know about some of the neat features BitlBee </para> <para> -With multiple channel support you can have contacts for specific protocols in their own channels, for instance, if you <emphasis>/join &msn</emphasis> you will join a channel that only contains your MSN contacts. +With multiple channel support you can have contacts for specific protocols in their own channels, for instance, if you <emphasis>/join &jabber</emphasis> you will join a channel that only contains your jabber contacts. </para> <para> @@ -141,9 +141,11 @@ irc_t *irc_new(int fd) if (isatty(irc->fd)) { irc_write(irc, ":%s NOTICE * :%s", irc->root->host, "If you read this, you most likely accidentally " - "started BitlBee in inetd mode on the command line. " - "You probably want to run it in (Fork)Daemon mode. " - "See doc/README for more information."); + "started BitlBee in inetd mode on the command line."); + irc_write(irc, ":%s NOTICE * :%s", irc->root->host, + "You probably want to run it as a system service, " + "or use (Fork)Daemon mode with the -F or -D switches. " + "See doc/README or 'man bitlbee' for more information."); } /* libpurple doesn't like fork()s after initializing itself, so this @@ -330,7 +330,7 @@ void irc_channel_user_set_mode(irc_channel_t *ic, irc_user_t *iu, irc_channel_us void irc_channel_set_mode(irc_channel_t *ic, const char *s); struct account; void irc_channel_auto_joins(irc_t *irc, struct account *acc); -void irc_channel_printf(irc_channel_t *ic, char *format, ...); +void irc_channel_printf(irc_channel_t *ic, char *format, ...) G_GNUC_PRINTF(2, 3); gboolean irc_channel_name_ok(const char *name); void irc_channel_name_strip(char *name); int irc_channel_name_cmp(const char *a_, const char *b_); @@ -350,9 +350,9 @@ void irc_send_num(irc_t *irc, int code, char *format, ...) G_GNUC_PRINTF(3, 4); void irc_send_login(irc_t *irc); void irc_send_motd(irc_t *irc); const char *irc_user_msgdest(irc_user_t *iu); -void irc_rootmsg(irc_t *irc, char *format, ...); -void irc_usermsg(irc_user_t *iu, char *format, ...); -void irc_usernotice(irc_user_t *iu, char *format, ...); +void irc_rootmsg(irc_t *irc, char *format, ...) G_GNUC_PRINTF(2, 3); +void irc_usermsg(irc_user_t *iu, char *format, ...) G_GNUC_PRINTF(2, 3); +void irc_usernotice(irc_user_t *iu, char *format, ...) G_GNUC_PRINTF(2, 3); void irc_send_join(irc_channel_t *ic, irc_user_t *iu); void irc_send_part(irc_channel_t *ic, irc_user_t *iu, const char *reason); void irc_send_quit(irc_user_t *iu, const char *reason); diff --git a/irc_commands.c b/irc_commands.c index f45f94e2..0bfac9ea 100644 --- a/irc_commands.c +++ b/irc_commands.c @@ -146,6 +146,9 @@ static gboolean irc_sasl_check_pass(irc_t *irc, char *user, char *pass) /* set the nick here so we have it for the following numeric */ irc->user->nick = g_strdup(user); } + irc_send_num(irc, 900, "%s!%s@%s %s :You are now logged in as %s", + irc->user->nick, irc->user->user, irc->user->host, + irc->user->nick, irc->user->nick); irc_send_num(irc, 903, ":Password accepted"); return TRUE; @@ -458,6 +458,35 @@ void bee_irc_user_nick_reset(irc_user_t *iu) } +#define PASTEBUF_LONG_SPACELESS_LINE_LENGTH 350 + +/* Returns FALSE if the last line of the message is near the typical irc length + * limit and the message has no spaces, indicating that it's probably desirable + * to join messages without the newline. + * + * The main use case for this is pasting long URLs and not breaking them */ +static gboolean bee_irc_pastebuf_should_start_with_newline(const char *msg) +{ + int i; + const char *last_line = strrchr(msg, '\n') ? : msg; + + if (*last_line == '\n') { + last_line++; + } + + for (i = 0; last_line[i]; i++) { + if (g_ascii_isspace(last_line[i])) { + return TRUE; + } + } + + if (i < PASTEBUF_LONG_SPACELESS_LINE_LENGTH) { + return TRUE; + } + + return FALSE; +} + /* IRC->IM calls */ static gboolean bee_irc_user_privmsg_cb(gpointer data, gint fd, b_input_condition cond); @@ -482,7 +511,10 @@ static gboolean bee_irc_user_privmsg(irc_user_t *iu, const char *msg) iu->pastebuf = g_string_new(msg); } else { b_event_remove(iu->pastebuf_timer); - g_string_append_printf(iu->pastebuf, "\n%s", msg); + if (bee_irc_pastebuf_should_start_with_newline(iu->pastebuf->str)) { + g_string_append_c(iu->pastebuf, '\n'); + } + g_string_append(iu->pastebuf, msg); } if (set_getbool(&iu->irc->b->set, "paste_buffer")) { diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 73bc77ea..4b24bf60 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -584,9 +584,14 @@ static struct groupchat *jabber_chat_join_(struct im_connection *ic, const char if (strchr(room, '@') == NULL) { imcb_error(ic, "%s is not a valid Jabber room name. Maybe you mean %s@conference.%s?", room, room, jd->server); - } else if (jabber_chat_by_jid(ic, room)) { - imcb_error(ic, "Already present in chat `%s'", room); } else { + struct groupchat *old; + + if ((old = jabber_chat_by_jid(ic, room))) { + imcb_log(ic, "Warning: Already present in chat `%s' - trying to join anyway", room); + jabber_chat_free(old); + } + /* jabber_chat_join without the underscore is the conference.c one */ return jabber_chat_join(ic, room, final_nick, set_getstr(sets, "password"), set_getbool(sets, "always_use_nicks")); diff --git a/protocols/msn/Makefile b/protocols/msn/Makefile deleted file mode 100644 index 089297f6..00000000 --- a/protocols/msn/Makefile +++ /dev/null @@ -1,46 +0,0 @@ -########################### -## Makefile for BitlBee ## -## ## -## Copyright 2002 Lintux ## -########################### - -### DEFINITIONS - --include ../../Makefile.settings -ifdef _SRCDIR_ -_SRCDIR_ := $(_SRCDIR_)protocols/msn/ -endif - -# [SH] Program variables -objects = msn.o msn_util.o ns.o soap.o tables.o gw.o - -LFLAGS += -r - -# [SH] Phony targets -all: msn_mod.o -check: all -lcov: check -gcov: - gcov *.c - -.PHONY: all clean distclean - -clean: - rm -f *.o core - -distclean: clean - rm -rf .depend - -### MAIN PROGRAM - -$(objects): ../../Makefile.settings Makefile - -$(objects): %.o: $(_SRCDIR_)%.c - @echo '*' Compiling $< - $(VERBOSE) $(CC) -c $(CFLAGS) $(CFLAGS_BITLBEE) $< -o $@ - -msn_mod.o: $(objects) - @echo '*' Linking msn_mod.o - $(VERBOSE) $(LD) $(LFLAGS) $(objects) -o msn_mod.o - --include .depend/*.d diff --git a/protocols/msn/gw.c b/protocols/msn/gw.c deleted file mode 100644 index f9cc74fd..00000000 --- a/protocols/msn/gw.c +++ /dev/null @@ -1,223 +0,0 @@ -#include "bitlbee.h" -#include "lib/http_client.h" -#include "msn.h" - -#define GATEWAY_HOST "geo.gateway.messenger.live.com" -#define GATEWAY_PORT 443 - -#define REQUEST_TEMPLATE \ - "POST /gateway/gateway.dll?SessionID=%s&%s HTTP/1.1\r\n" \ - "Host: %s\r\n" \ - "Content-Length: %zd\r\n" \ - "\r\n" \ - "%s" - -static gboolean msn_gw_poll_timeout(gpointer data, gint source, b_input_condition cond); - -struct msn_gw *msn_gw_new(struct im_connection *ic) -{ - struct msn_gw *gw = g_new0(struct msn_gw, 1); - gw->last_host = g_strdup(GATEWAY_HOST); - gw->port = GATEWAY_PORT; - gw->ssl = (GATEWAY_PORT == 443); - gw->poll_timeout = -1; - gw->write_timeout = -1; - gw->ic = ic; - gw->md = ic->proto_data; - gw->in = g_byte_array_new(); - gw->out = g_byte_array_new(); - return gw; -} - -void msn_gw_free(struct msn_gw *gw) -{ - if (gw->poll_timeout != -1) { - b_event_remove(gw->poll_timeout); - } - - if (gw->write_timeout != -1) { - b_event_remove(gw->write_timeout); - } - - g_byte_array_free(gw->in, TRUE); - g_byte_array_free(gw->out, TRUE); - g_free(gw->session_id); - g_free(gw->last_host); - g_free(gw); -} - -static struct msn_gw *msn_gw_from_ic(struct im_connection *ic) -{ - if (g_slist_find(msn_connections, ic) == NULL) { - return NULL; - } else { - struct msn_data *md = ic->proto_data; - return md->gw; - } -} - -static gboolean msn_gw_parse_session_header(struct msn_gw *gw, char *value) -{ - int i; - char **subvalues; - gboolean closed = FALSE; - - subvalues = g_strsplit(value, "; ", 0); - - for (i = 0; subvalues[i]; i++) { - if (strcmp(subvalues[i], "Session=close") == 0) { - /* gateway closed, signal the death of the socket */ - closed = TRUE; - } else if (g_str_has_prefix(subvalues[i], "SessionID=")) { - /* copy the part after the = to session_id*/ - g_free(gw->session_id); - gw->session_id = g_strdup(subvalues[i] + 10); - } - } - - g_strfreev(subvalues); - - return !closed; -} - -void msn_gw_callback(struct http_request *req) -{ - struct msn_gw *gw; - char *value; - - if (!(gw = msn_gw_from_ic(req->data))) { - return; - } - - gw->waiting = FALSE; - gw->polling = FALSE; - - if (req->status_code != 200 || !req->reply_body) { - gw->callback(gw->md, -1, B_EV_IO_READ); - return; - } - - if (getenv("BITLBEE_DEBUG")) { - fprintf(stderr, "\n\x1b[90mHTTP:%s\n", req->reply_body); - fprintf(stderr, "\n\x1b[97m\n"); - } - - if ((value = get_rfc822_header(req->reply_headers, "X-MSN-Messenger", 0))) { - if (!msn_gw_parse_session_header(gw, value)) { - gw->callback(gw->md, -1, B_EV_IO_READ); - g_free(value); - return; - } - g_free(value); - } - - if ((value = get_rfc822_header(req->reply_headers, "X-MSN-Host", 0))) { - g_free(gw->last_host); - gw->last_host = value; /* transfer */ - } - - if (req->body_size) { - g_byte_array_append(gw->in, (const guint8 *) req->reply_body, req->body_size); - - if (!gw->callback(gw->md, -1, B_EV_IO_READ)) { - return; - } - } - - if (gw->poll_timeout != -1) { - b_event_remove(gw->poll_timeout); - } - gw->poll_timeout = b_timeout_add(500, msn_gw_poll_timeout, gw->ic); - -} - -void msn_gw_dorequest(struct msn_gw *gw, char *args) -{ - char *request = NULL; - char *body = NULL; - size_t bodylen = 0; - - if (gw->out) { - bodylen = gw->out->len; - g_byte_array_append(gw->out, (guint8 *) "", 1); /* nullnullnull */ - body = (char *) g_byte_array_free(gw->out, FALSE); - gw->out = g_byte_array_new(); - } - - if (!bodylen && !args) { - args = "Action=poll&Lifespan=60"; - gw->polling = TRUE; - } - - request = g_strdup_printf(REQUEST_TEMPLATE, - gw->session_id ? : "", args ? : "", gw->last_host, bodylen, body ? : ""); - - http_dorequest(gw->last_host, gw->port, gw->ssl, request, msn_gw_callback, gw->ic); - gw->open = TRUE; - gw->waiting = TRUE; - - g_free(body); - g_free(request); -} - -void msn_gw_open(struct msn_gw *gw) -{ - msn_gw_dorequest(gw, "Action=open&Server=NS"); -} - -static gboolean msn_gw_poll_timeout(gpointer data, gint source, b_input_condition cond) -{ - struct msn_gw *gw; - - if (!(gw = msn_gw_from_ic(data))) { - return FALSE; - } - - gw->poll_timeout = -1; - if (!gw->waiting) { - msn_gw_dorequest(gw, NULL); - } - return FALSE; -} - -ssize_t msn_gw_read(struct msn_gw *gw, char **buf) -{ - size_t bodylen; - if (!gw->open) { - return 0; - } - - bodylen = gw->in->len; - g_byte_array_append(gw->in, (guint8 *) "", 1); /* nullnullnull */ - *buf = (char *) g_byte_array_free(gw->in, FALSE); - gw->in = g_byte_array_new(); - return bodylen; -} - -static gboolean msn_gw_write_cb(gpointer data, gint source, b_input_condition cond) -{ - struct msn_gw *gw; - - if (!(gw = msn_gw_from_ic(data))) { - return FALSE; - } - - if (!gw->open) { - msn_gw_open(gw); - } else if (gw->polling || !gw->waiting) { - msn_gw_dorequest(gw, NULL); - } - - gw->write_timeout = -1; - return FALSE; -} - -void msn_gw_write(struct msn_gw *gw, char *buf, size_t len) -{ - g_byte_array_append(gw->out, (const guint8 *) buf, len); - - /* do a bit of buffering here to send several commands with a single request */ - if (gw->write_timeout == -1) { - gw->write_timeout = b_timeout_add(1, msn_gw_write_cb, gw->ic); - } -} diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c deleted file mode 100644 index 8d3e7787..00000000 --- a/protocols/msn/msn.c +++ /dev/null @@ -1,372 +0,0 @@ -/********************************************************************\ - * BitlBee -- An IRC to other IM-networks gateway * - * * - * Copyright 2002-2013 Wilmer van der Gaast and others * - \********************************************************************/ - -/* MSN module - Main file; functions to be called from BitlBee */ - -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License with - the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; - if not, write to the Free Software Foundation, Inc., 51 Franklin St., - Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include "nogaim.h" -#include "soap.h" -#include "msn.h" - -int msn_chat_id; -GSList *msn_connections; - -static char *set_eval_display_name(set_t *set, char *value); - -static void msn_init(account_t *acc) -{ - set_t *s; - - s = set_add(&acc->set, "display_name", NULL, set_eval_display_name, acc); - s->flags |= SET_NOSAVE | ACC_SET_ONLINE_ONLY; - - s = set_add(&acc->set, "server", NULL, set_eval_account, acc); - s->flags |= SET_NOSAVE | ACC_SET_OFFLINE_ONLY; - - s = set_add(&acc->set, "port", MSN_NS_PORT, set_eval_int, acc); - s->flags |= ACC_SET_OFFLINE_ONLY; - - s = set_add(&acc->set, "mail_notifications", "false", set_eval_bool, acc); - s->flags |= ACC_SET_OFFLINE_ONLY; - - s = set_add(&acc->set, "mail_notifications_handle", NULL, NULL, acc); - s->flags |= ACC_SET_OFFLINE_ONLY | SET_NULL_OK; - - acc->flags |= ACC_FLAG_AWAY_MESSAGE | ACC_FLAG_STATUS_MESSAGE | - ACC_FLAG_HANDLE_DOMAINS; -} - -static void msn_login(account_t *acc) -{ - struct im_connection *ic = imcb_new(acc); - struct msn_data *md = g_new0(struct msn_data, 1); - char *server = set_getstr(&ic->acc->set, "server"); - - ic->proto_data = md; - ic->flags |= OPT_PONGS | OPT_PONGED; - - if (!server) { - server = "geo.gateway.messenger.live.com"; - } - - if (strchr(acc->user, '@') == NULL) { - imcb_error(ic, "Invalid account name"); - imc_logout(ic, FALSE); - return; - } - - md->ic = ic; - md->away_state = msn_away_state_list; - md->domaintree = g_tree_new(msn_domaintree_cmp); - md->fd = -1; - md->is_http = TRUE; - - msn_connections = g_slist_prepend(msn_connections, ic); - - imcb_log(ic, "Connecting"); - msn_ns_connect(ic, server, - set_getint(&ic->acc->set, "port")); - - if (set_getbool(&acc->set, "mail_notifications") && set_getstr(&acc->set, "mail_notifications_handle")) { - imcb_add_buddy(ic, set_getstr(&acc->set, "mail_notifications_handle"), NULL); - } -} - -static void msn_logout(struct im_connection *ic) -{ - struct msn_data *md = ic->proto_data; - GSList *l; - int i; - - if (md) { - msn_ns_close(md); - - msn_soapq_flush(ic, FALSE); - - for (i = 0; i < sizeof(md->tokens) / sizeof(md->tokens[0]); i++) { - g_free(md->tokens[i]); - } - g_free(md->lock_key); - g_free(md->pp_policy); - g_free(md->uuid); - - while (md->groups) { - struct msn_group *mg = md->groups->data; - md->groups = g_slist_remove(md->groups, mg); - g_free(mg->id); - g_free(mg->name); - g_free(mg); - } - - g_free(md->profile_rid); - - if (md->domaintree) { - g_tree_destroy(md->domaintree); - } - md->domaintree = NULL; - - while (md->grpq) { - struct msn_groupadd *ga = md->grpq->data; - md->grpq = g_slist_remove(md->grpq, ga); - g_free(ga->group); - g_free(ga->who); - g_free(ga); - } - - g_free(md); - } - - for (l = ic->permit; l; l = l->next) { - g_free(l->data); - } - g_slist_free(ic->permit); - - for (l = ic->deny; l; l = l->next) { - g_free(l->data); - } - g_slist_free(ic->deny); - - msn_connections = g_slist_remove(msn_connections, ic); -} - -static int msn_buddy_msg(struct im_connection *ic, char *who, char *message, int away) -{ - struct bee_user *bu = bee_user_by_handle(ic->bee, ic, who); - msn_ns_send_message(ic, bu, message); - return 0; -} - -static GList *msn_away_states(struct im_connection *ic) -{ - static GList *l = NULL; - int i; - - if (l == NULL) { - for (i = 0; *msn_away_state_list[i].code; i++) { - if (*msn_away_state_list[i].name) { - l = g_list_append(l, (void *) msn_away_state_list[i].name); - } - } - } - - return l; -} - -static void msn_set_away(struct im_connection *ic, char *state, char *message) -{ - struct msn_data *md = ic->proto_data; - char *nick, *psm, *idle, *statecode, *body, *buf; - - if (state == NULL) { - md->away_state = msn_away_state_list; - } else if ((md->away_state = msn_away_state_by_name(state)) == NULL) { - md->away_state = msn_away_state_list + 1; - } - - statecode = (char *) md->away_state->code; - nick = set_getstr(&ic->acc->set, "display_name"); - psm = message ? message : ""; - idle = (strcmp(statecode, "IDL") == 0) ? "false" : "true"; - - body = g_markup_printf_escaped(MSN_PUT_USER_BODY, - nick, psm, psm, md->uuid, statecode, md->uuid, idle, statecode, - MSN_CAP1, MSN_CAP2, MSN_CAP1, MSN_CAP2 - ); - - buf = g_strdup_printf(MSN_PUT_HEADERS, ic->acc->user, ic->acc->user, md->uuid, - "/user", "application/user+xml", - strlen(body), body); - msn_ns_write(ic, -1, "PUT %d %zd\r\n%s", ++md->trId, strlen(buf), buf); - - g_free(buf); - g_free(body); -} - -static void msn_get_info(struct im_connection *ic, char *who) -{ - /* Just make an URL and let the user fetch the info */ - imcb_log(ic, "%s\n%s: %s%s", _("User Info"), _("For now, fetch yourself"), PROFILE_URL, who); -} - -static void msn_add_buddy(struct im_connection *ic, char *who, char *group) -{ - struct bee_user *bu = bee_user_by_handle(ic->bee, ic, who); - - msn_buddy_list_add(ic, MSN_BUDDY_FL, who, who, group); - if (bu && bu->group) { - msn_buddy_list_remove(ic, MSN_BUDDY_FL, who, bu->group->name); - } -} - -static void msn_remove_buddy(struct im_connection *ic, char *who, char *group) -{ - msn_buddy_list_remove(ic, MSN_BUDDY_FL, who, NULL); -} - -static void msn_chat_msg(struct groupchat *c, char *message, int flags) -{ - /* TODO: groupchats*/ -} - -static void msn_chat_invite(struct groupchat *c, char *who, char *message) -{ - /* TODO: groupchats*/ -} - -static void msn_chat_leave(struct groupchat *c) -{ - /* TODO: groupchats*/ -} - -static struct groupchat *msn_chat_with(struct im_connection *ic, char *who) -{ - /* TODO: groupchats*/ - struct groupchat *c = imcb_chat_new(ic, who); - return c; -} - -static void msn_keepalive(struct im_connection *ic) -{ - msn_ns_write(ic, -1, "PNG\r\n"); -} - -static void msn_add_permit(struct im_connection *ic, char *who) -{ - msn_buddy_list_add(ic, MSN_BUDDY_AL, who, who, NULL); -} - -static void msn_rem_permit(struct im_connection *ic, char *who) -{ - msn_buddy_list_remove(ic, MSN_BUDDY_AL, who, NULL); -} - -static void msn_add_deny(struct im_connection *ic, char *who) -{ - msn_buddy_list_add(ic, MSN_BUDDY_BL, who, who, NULL); -} - -static void msn_rem_deny(struct im_connection *ic, char *who) -{ - msn_buddy_list_remove(ic, MSN_BUDDY_BL, who, NULL); -} - -static int msn_send_typing(struct im_connection *ic, char *who, int typing) -{ - struct bee_user *bu = bee_user_by_handle(ic->bee, ic, who); - - if (!(bu->flags & BEE_USER_ONLINE)) { - return 0; - } else if (typing & OPT_TYPING) { - return msn_ns_send_typing(ic, bu); - } else { - return 1; - } -} - -static char *set_eval_display_name(set_t *set, char *value) -{ - account_t *acc = set->data; - struct im_connection *ic = acc->ic; - struct msn_data *md = ic->proto_data; - - if (md->flags & MSN_EMAIL_UNVERIFIED) { - imcb_log(ic, "Warning: Your e-mail address is unverified. MSN doesn't allow " - "changing your display name until your e-mail address is verified."); - } - - if (md->flags & MSN_GOT_PROFILE_DN) { - msn_soap_profile_set_dn(ic, value); - } else { - msn_soap_addressbook_set_display_name(ic, value); - } - - return msn_ns_set_display_name(ic, value) ? value : NULL; -} - -static void msn_buddy_data_add(bee_user_t *bu) -{ - struct msn_data *md = bu->ic->proto_data; - struct msn_buddy_data *bd; - char *handle; - - bd = bu->data = g_new0(struct msn_buddy_data, 1); - g_tree_insert(md->domaintree, bu->handle, bu); - - for (handle = bu->handle; g_ascii_isdigit(*handle); handle++) { - ; - } - if (*handle == ':') { - /* Pass a nick hint so hopefully the stupid numeric prefix - won't show up to the user. */ - char *s = strchr(++handle, '@'); - if (s) { - handle = g_strndup(handle, s - handle); - imcb_buddy_nick_hint(bu->ic, bu->handle, handle); - g_free(handle); - } - - bd->flags |= MSN_BUDDY_FED; - } -} - -static void msn_buddy_data_free(bee_user_t *bu) -{ - struct msn_data *md = bu->ic->proto_data; - struct msn_buddy_data *bd = bu->data; - - g_free(bd->cid); - g_free(bd); - - g_tree_remove(md->domaintree, bu->handle); -} - -void msn_initmodule() -{ - struct prpl *ret = g_new0(struct prpl, 1); - - ret->name = "msn"; - ret->mms = 1409; /* this guess taken from libotr UPGRADING file */ - ret->login = msn_login; - ret->init = msn_init; - ret->logout = msn_logout; - ret->buddy_msg = msn_buddy_msg; - ret->away_states = msn_away_states; - ret->set_away = msn_set_away; - ret->get_info = msn_get_info; - ret->add_buddy = msn_add_buddy; - ret->remove_buddy = msn_remove_buddy; - ret->chat_msg = msn_chat_msg; - ret->chat_invite = msn_chat_invite; - ret->chat_leave = msn_chat_leave; - ret->chat_with = msn_chat_with; - ret->keepalive = msn_keepalive; - ret->add_permit = msn_add_permit; - ret->rem_permit = msn_rem_permit; - ret->add_deny = msn_add_deny; - ret->rem_deny = msn_rem_deny; - ret->send_typing = msn_send_typing; - ret->handle_cmp = g_strcasecmp; - ret->buddy_data_add = msn_buddy_data_add; - ret->buddy_data_free = msn_buddy_data_free; - - register_protocol(ret); -} diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h deleted file mode 100644 index b2e7995d..00000000 --- a/protocols/msn/msn.h +++ /dev/null @@ -1,254 +0,0 @@ -/********************************************************************\ - * BitlBee -- An IRC to other IM-networks gateway * - * * - * Copyright 2002-2012 Wilmer van der Gaast and others * - \********************************************************************/ - -/* MSN module */ - -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License with - the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; - if not, write to the Free Software Foundation, Inc., 51 Franklin St., - Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _MSN_H -#define _MSN_H - -/* This should be MSN Messenger 7.0.0813 -#define MSNP11_PROD_KEY "CFHUR$52U_{VIX5T" -#define MSNP11_PROD_ID "PROD0101{0RM?UBW" -*/ - -#define MSN_NS_HOST "messenger.hotmail.com" -#define MSN_NS_PORT "1863" - -/* Some other version. -#define MSNP11_PROD_KEY "O4BG@C7BWLYQX?5G" -#define MSNP11_PROD_ID "PROD01065C%ZFN6F" -*/ - -/* <= BitlBee 3.0.5 -#define MSNP11_PROD_KEY "ILTXC!4IXB5FB*PX" -#define MSNP11_PROD_ID "PROD0119GSJUC$18" -*/ - -#define MSNP11_PROD_KEY "C1BX{V4W}Q3*10SM" -#define MSNP11_PROD_ID "PROD0120PW!CCV9@" -#define MSNP_VER "MSNP21" -#define MSNP_BUILD "14.0.8117.416" - -#define MSN_SB_NEW -24062002 - -#define MSN_CAP1 0xC000 -#define MSN_CAP2 0x0000 - -#define MSN_BASE_HEADERS \ - "Routing: 1.0\r\n" \ - "To: 1:%s\r\n" \ - "From: 1:%s;epid={%s}\r\n" \ - "\r\n" \ - "Reliability: 1.0\r\n" \ - "\r\n" - -#define MSN_MESSAGE_HEADERS MSN_BASE_HEADERS \ - "Messaging: 2.0\r\n" \ - "Message-Type: %s\r\n" \ - "Content-Length: %zd\r\n" \ - "Content-Type: text/plain; charset=UTF-8\r\n" \ - "X-MMS-IM-Format: FN=Segoe%%20UI; EF=; CO=0; CS=0; PF=0\r\n" \ - "\r\n" \ - "%s" - -#define MSN_PUT_HEADERS MSN_BASE_HEADERS \ - "Publication: 1.0\r\n" \ - "Uri: %s\r\n" \ - "Content-Type: %s\r\n" \ - "Content-Length: %zd\r\n" \ - "\r\n" \ - "%s" - -#define MSN_PUT_USER_BODY \ - "<user>" \ - "<s n=\"PE\"><UserTileLocation></UserTileLocation><FriendlyName>%s</FriendlyName><PSM>%s</PSM><DDP></DDP>" \ - "<Scene></Scene><ASN></ASN><ColorScheme>-3</ColorScheme><BDG></BDG><RUM>%s</RUM><RUL></RUL><RLT>0</RLT>" \ - "<RID></RID><SUL></SUL><MachineGuid>%s</MachineGuid></s>" \ - "<s n=\"IM\"><Status>%s</Status><CurrentMedia></CurrentMedia></s>" \ - "<sep n=\"PD\"><ClientType>1</ClientType><EpName>%s</EpName><Idle>%s</Idle><State>%s</State></sep>" \ - "<sep n=\"PE\"><VER>BitlBee:" BITLBEE_VERSION "</VER><TYP>1</TYP><Capabilities>%d:%d</Capabilities></sep>" \ - "<sep n=\"IM\"><Capabilities>%d:%d</Capabilities></sep>" \ - "</user>" - -#define PROFILE_URL "http://members.msn.com/" - -typedef enum { - MSN_GOT_PROFILE = 1, - MSN_GOT_PROFILE_DN = 2, - MSN_DONE_ADL = 4, - MSN_REAUTHING = 8, - MSN_EMAIL_UNVERIFIED = 16, -} msn_flags_t; - -struct msn_gw { - char *last_host; - int port; - gboolean ssl; - - char *session_id; - - GByteArray *in; - GByteArray *out; - - int poll_timeout; - int write_timeout; - - b_event_handler callback; - - struct im_connection *ic; - struct msn_data *md; - - gboolean open; - gboolean waiting; - gboolean polling; -}; - -struct msn_data { - int fd, inpa; - int rxlen; - char *rxq; - - int msglen; - char *cmd_text; - - struct im_connection *ic; - - msn_flags_t flags; - - int trId; - char *tokens[4]; - char *lock_key, *pp_policy; - char *uuid; - - GSList *msgq, *grpq, *soapq; - - const struct msn_away_state *away_state; - GSList *groups; - char *profile_rid; - - /* Mostly used for sending the ADL command; since MSNP13 the client - is responsible for downloading the contact list and then sending - it to the MSNP server. */ - GTree *domaintree; - int adl_todo; - - gboolean is_http; - struct msn_gw *gw; -}; - -struct msn_away_state { - char code[4]; - char name[16]; -}; - -struct msn_status_code { - int number; - char *text; - int flags; -}; - -struct msn_message { - char *who; - char *text; -}; - -struct msn_groupadd { - char *who; - char *group; -}; - -typedef enum { - MSN_BUDDY_FL = 1, /* Warning: FL,AL,BL *must* be 1,2,4. */ - MSN_BUDDY_AL = 2, - MSN_BUDDY_BL = 4, - MSN_BUDDY_RL = 8, - MSN_BUDDY_PL = 16, - MSN_BUDDY_ADL_SYNCED = 256, - MSN_BUDDY_FED = 512, -} msn_buddy_flags_t; - -struct msn_buddy_data { - char *cid; - msn_buddy_flags_t flags; -}; - -struct msn_group { - char *name; - char *id; -}; - -/* Bitfield values for msn_status_code.flags */ -#define STATUS_FATAL 1 -#define STATUS_SB_FATAL 2 - -extern int msn_chat_id; -extern const struct msn_away_state msn_away_state_list[]; -extern const struct msn_status_code msn_status_code_list[]; - -/* Keep a list of all the active connections. We need these lists because - "connected" callbacks might be called when the connection they belong too - is down already (for example, when an impatient user disabled the - connection), the callback should check whether it's still listed here - before doing *anything* else. */ -extern GSList *msn_connections; - -/* ns.c */ -int msn_ns_write(struct im_connection *ic, int fd, const char *fmt, ...) G_GNUC_PRINTF(3, 4); -gboolean msn_ns_connect(struct im_connection *ic, const char *host, int port); -void msn_ns_close(struct msn_data *handler); -void msn_auth_got_passport_token(struct im_connection *ic, const char *token, const char *error); -void msn_auth_got_contact_list(struct im_connection *ic); -int msn_ns_finish_login(struct im_connection *ic); -int msn_ns_send_typing(struct im_connection *ic, struct bee_user *bu); -int msn_ns_send_message(struct im_connection *ic, struct bee_user *bu, const char *text); -int msn_ns_command(struct msn_data *md, char **cmd, int num_parts); -int msn_ns_message(struct msn_data *md, char *msg, int msglen, char **cmd, int num_parts); - -/* msn_util.c */ -int msn_buddy_list_add(struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *realname_, - const char *group); -int msn_buddy_list_remove(struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *group); -void msn_buddy_ask(bee_user_t *bu); -void msn_queue_feed(struct msn_data *h, char *bytes, int st); -int msn_handler(struct msn_data *h); -char *msn_p11_challenge(char *challenge); -gint msn_domaintree_cmp(gconstpointer a_, gconstpointer b_); -struct msn_group *msn_group_by_name(struct im_connection *ic, const char *name); -struct msn_group *msn_group_by_id(struct im_connection *ic, const char *id); -int msn_ns_set_display_name(struct im_connection *ic, const char *value); -const char *msn_normalize_handle(const char *handle); - -/* tables.c */ -const struct msn_away_state *msn_away_state_by_number(int number); -const struct msn_away_state *msn_away_state_by_code(char *code); -const struct msn_away_state *msn_away_state_by_name(char *name); -const struct msn_status_code *msn_status_by_number(int number); - -/* gw.c */ -struct msn_gw *msn_gw_new(struct im_connection *ic); -void msn_gw_free(struct msn_gw *gw); -void msn_gw_open(struct msn_gw *gw); -ssize_t msn_gw_read(struct msn_gw *gw, char **buf); -void msn_gw_write(struct msn_gw *gw, char *buf, size_t len); - -#endif //_MSN_H diff --git a/protocols/msn/msn_util.c b/protocols/msn/msn_util.c deleted file mode 100644 index af00e461..00000000 --- a/protocols/msn/msn_util.c +++ /dev/null @@ -1,424 +0,0 @@ -/********************************************************************\ - * BitlBee -- An IRC to other IM-networks gateway * - * * - * Copyright 2002-2012 Wilmer van der Gaast and others * - \********************************************************************/ - -/* MSN module - Miscellaneous utilities */ - -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License with - the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; - if not, write to the Free Software Foundation, Inc., 51 Franklin St., - Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include "nogaim.h" -#include "msn.h" -#include "md5.h" -#include "soap.h" -#include <ctype.h> - -static char *adlrml_entry(const char *handle_, msn_buddy_flags_t list) -{ - char *domain, handle[strlen(handle_) + 1]; - - strcpy(handle, handle_); - if ((domain = strchr(handle, '@'))) { - *(domain++) = '\0'; - } else { - return NULL; - } - - return g_markup_printf_escaped("<ml><d n=\"%s\"><c n=\"%s\" t=\"1\"><s n=\"IM\" l=\"%d\" /></c></d></ml>", - domain, handle, list); -} - -int msn_buddy_list_add(struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *realname, - const char *group) -{ - struct msn_data *md = ic->proto_data; - char groupid[8]; - bee_user_t *bu; - struct msn_buddy_data *bd; - char *adl; - - *groupid = '\0'; - - if (!((bu = bee_user_by_handle(ic->bee, ic, who)) || - (bu = bee_user_new(ic->bee, ic, who, 0))) || - !(bd = bu->data) || bd->flags & list) { - return 1; - } - - bd->flags |= list; - - if (list == MSN_BUDDY_FL) { - msn_soap_ab_contact_add(ic, bu); - } else { - msn_soap_memlist_edit(ic, who, TRUE, list); - } - - if ((adl = adlrml_entry(who, list))) { - int st = msn_ns_write(ic, -1, "ADL %d %zd\r\n%s", - ++md->trId, strlen(adl), adl); - g_free(adl); - - return st; - } - - return 1; -} - -int msn_buddy_list_remove(struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *group) -{ - struct msn_data *md = ic->proto_data; - char groupid[8]; - bee_user_t *bu; - struct msn_buddy_data *bd; - char *adl; - - *groupid = '\0'; - - if (!(bu = bee_user_by_handle(ic->bee, ic, who)) || - !(bd = bu->data) || !(bd->flags & list)) { - return 1; - } - - bd->flags &= ~list; - - if (list == MSN_BUDDY_FL) { - msn_soap_ab_contact_del(ic, bu); - } else { - msn_soap_memlist_edit(ic, who, FALSE, list); - } - - if ((adl = adlrml_entry(who, list))) { - int st = msn_ns_write(ic, -1, "RML %d %zd\r\n%s", - ++md->trId, strlen(adl), adl); - g_free(adl); - - return st; - } - - return 1; -} - -struct msn_buddy_ask_data { - struct im_connection *ic; - char *handle; - char *realname; -}; - -static void msn_buddy_ask_free(void *data) -{ - struct msn_buddy_ask_data *bla = data; - - g_free(bla->handle); - g_free(bla->realname); - g_free(bla); -} - -static void msn_buddy_ask_yes(void *data) -{ - struct msn_buddy_ask_data *bla = data; - - msn_buddy_list_add(bla->ic, MSN_BUDDY_AL, bla->handle, bla->realname, NULL); - - imcb_ask_add(bla->ic, bla->handle, NULL); - - msn_buddy_ask_free(bla); -} - -static void msn_buddy_ask_no(void *data) -{ - struct msn_buddy_ask_data *bla = data; - - msn_buddy_list_add(bla->ic, MSN_BUDDY_BL, bla->handle, bla->realname, NULL); - - msn_buddy_ask_free(bla); -} - -void msn_buddy_ask(bee_user_t *bu) -{ - struct msn_buddy_ask_data *bla; - struct msn_buddy_data *bd = bu->data; - char buf[1024]; - - if (!(bd->flags & MSN_BUDDY_PL)) { - return; - } - - bla = g_new0(struct msn_buddy_ask_data, 1); - bla->ic = bu->ic; - bla->handle = g_strdup(bu->handle); - bla->realname = g_strdup(bu->fullname); - - g_snprintf(buf, sizeof(buf), - "The user %s (%s) wants to add you to his/her buddy list.", - bu->handle, bu->fullname); - - imcb_ask_with_free(bu->ic, buf, bla, msn_buddy_ask_yes, msn_buddy_ask_no, msn_buddy_ask_free); -} - -void msn_queue_feed(struct msn_data *h, char *bytes, int st) -{ - h->rxq = g_renew(char, h->rxq, h->rxlen + st); - memcpy(h->rxq + h->rxlen, bytes, st); - h->rxlen += st; - - if (getenv("BITLBEE_DEBUG")) { - fprintf(stderr, "\n\x1b[92m<<< "); - fwrite(bytes, st, 1, stderr); - fprintf(stderr, "\x1b[97m"); - } -} - -/* This one handles input from a MSN Messenger server. Both the NS and SB servers usually give - commands, but sometimes they give additional data (payload). This function tries to handle - this all in a nice way and send all data to the right places. */ - -/* Return values: -1: Read error, abort connection. - 0: Command reported error; Abort *immediately*. (The connection does not exist anymore) - 1: OK */ - -int msn_handler(struct msn_data *h) -{ - int st = 1; - - while (st) { - int i; - - if (h->msglen == 0) { - for (i = 0; i < h->rxlen; i++) { - if (h->rxq[i] == '\r' || h->rxq[i] == '\n') { - char *cmd_text, **cmd; - int count; - - cmd_text = g_strndup(h->rxq, i); - cmd = g_strsplit_set(cmd_text, " ", -1); - count = g_strv_length(cmd); - - st = msn_ns_command(h, cmd, count); - - g_strfreev(cmd); - g_free(cmd_text); - - /* If the connection broke, don't continue. We don't even exist anymore. */ - if (!st) { - return(0); - } - - if (h->msglen) { - h->cmd_text = g_strndup(h->rxq, i); - } - - /* Skip to the next non-emptyline */ - while (i < h->rxlen && (h->rxq[i] == '\r' || h->rxq[i] == '\n')) { - i++; - } - - break; - } - } - - /* If we reached the end of the buffer, there's still an incomplete command there. - Return and wait for more data. */ - if (i && i == h->rxlen && h->rxq[i - 1] != '\r' && h->rxq[i - 1] != '\n') { - break; - } - } else { - char *msg, **cmd; - int count; - - /* Do we have the complete message already? */ - if (h->msglen > h->rxlen) { - break; - } - - msg = g_strndup(h->rxq, h->msglen); - - cmd = g_strsplit_set(h->cmd_text, " ", -1); - count = g_strv_length(cmd); - - st = msn_ns_message(h, msg, h->msglen, cmd, count); - - g_strfreev(cmd); - g_free(msg); - g_free(h->cmd_text); - h->cmd_text = NULL; - - if (!st) { - return(0); - } - - i = h->msglen; - h->msglen = 0; - } - - /* More data after this block? */ - if (i < h->rxlen) { - char *tmp; - - tmp = g_memdup(h->rxq + i, h->rxlen - i); - g_free(h->rxq); - h->rxq = tmp; - h->rxlen -= i; - i = 0; - } else { - /* If not, reset the rx queue and get lost. */ - g_free(h->rxq); - h->rxq = g_new0(char, 1); - h->rxlen = 0; - return(1); - } - } - - return(1); -} - -/* Copied and heavily modified from http://tmsnc.sourceforge.net/chl.c */ -char *msn_p11_challenge(char *challenge) -{ - char *output, buf[256]; - md5_state_t md5c; - unsigned char md5Hash[16], *newHash; - unsigned int *md5Parts, *chlStringParts, newHashParts[5]; - long long nHigh = 0, nLow = 0; - int i, n; - - /* Create the MD5 hash */ - md5_init(&md5c); - md5_append(&md5c, (unsigned char *) challenge, strlen(challenge)); - md5_append(&md5c, (unsigned char *) MSNP11_PROD_KEY, strlen(MSNP11_PROD_KEY)); - md5_finish(&md5c, md5Hash); - - /* Split it into four integers */ - md5Parts = (unsigned int *) md5Hash; - for (i = 0; i < 4; i++) { - md5Parts[i] = GUINT32_TO_LE(md5Parts[i]); - - /* & each integer with 0x7FFFFFFF */ - /* and save one unmodified array for later */ - newHashParts[i] = md5Parts[i]; - md5Parts[i] &= 0x7FFFFFFF; - } - - /* make a new string and pad with '0' */ - n = g_snprintf(buf, sizeof(buf) - 5, "%s%s00000000", challenge, MSNP11_PROD_ID); - /* truncate at an 8-byte boundary */ - buf[n &= ~7] = '\0'; - - /* split into integers */ - chlStringParts = (unsigned int *) buf; - - /* this is magic */ - for (i = 0; i < (n / 4) - 1; i += 2) { - long long temp; - - chlStringParts[i] = GUINT32_TO_LE(chlStringParts[i]); - chlStringParts[i + 1] = GUINT32_TO_LE(chlStringParts[i + 1]); - - temp = - (md5Parts[0] * - (((0x0E79A9C1 * - (long long) chlStringParts[i]) % 0x7FFFFFFF) + nHigh) + md5Parts[1]) % 0x7FFFFFFF; - nHigh = - (md5Parts[2] * - (((long long) chlStringParts[i + 1] + temp) % 0x7FFFFFFF) + md5Parts[3]) % 0x7FFFFFFF; - nLow = nLow + nHigh + temp; - } - nHigh = (nHigh + md5Parts[1]) % 0x7FFFFFFF; - nLow = (nLow + md5Parts[3]) % 0x7FFFFFFF; - - newHashParts[0] ^= nHigh; - newHashParts[1] ^= nLow; - newHashParts[2] ^= nHigh; - newHashParts[3] ^= nLow; - - /* swap more bytes if big endian */ - for (i = 0; i < 4; i++) { - newHashParts[i] = GUINT32_TO_LE(newHashParts[i]); - } - - /* make a string of the parts */ - newHash = (unsigned char *) newHashParts; - - /* convert to hexadecimal */ - output = g_new(char, 33); - for (i = 0; i < 16; i++) { - sprintf(output + i * 2, "%02x", newHash[i]); - } - - return output; -} - -gint msn_domaintree_cmp(gconstpointer a_, gconstpointer b_) -{ - const char *a = a_, *b = b_; - gint ret; - - if (!(a = strchr(a, '@')) || !(b = strchr(b, '@')) || - (ret = strcmp(a, b)) == 0) { - ret = strcmp(a_, b_); - } - - return ret; -} - -struct msn_group *msn_group_by_name(struct im_connection *ic, const char *name) -{ - struct msn_data *md = ic->proto_data; - GSList *l; - - for (l = md->groups; l; l = l->next) { - struct msn_group *mg = l->data; - - if (g_strcasecmp(mg->name, name) == 0) { - return mg; - } - } - - return NULL; -} - -struct msn_group *msn_group_by_id(struct im_connection *ic, const char *id) -{ - struct msn_data *md = ic->proto_data; - GSList *l; - - for (l = md->groups; l; l = l->next) { - struct msn_group *mg = l->data; - - if (g_strcasecmp(mg->id, id) == 0) { - return mg; - } - } - - return NULL; -} - -int msn_ns_set_display_name(struct im_connection *ic, const char *value) -{ - // TODO, implement this through msn_set_away's method - return 1; -} - -const char *msn_normalize_handle(const char *handle) -{ - if (strncmp(handle, "1:", 2) == 0) { - return handle + 2; - } else { - return handle; - } -} diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c deleted file mode 100644 index d577b4b9..00000000 --- a/protocols/msn/ns.c +++ /dev/null @@ -1,779 +0,0 @@ -/********************************************************************\ - * BitlBee -- An IRC to other IM-networks gateway * - * * - * Copyright 2002-2012 Wilmer van der Gaast and others * - \********************************************************************/ - -/* MSN module - Notification server callbacks */ - -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License with - the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; - if not, write to the Free Software Foundation, Inc., 51 Franklin St., - Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include <ctype.h> -#include <sys/utsname.h> -#include "nogaim.h" -#include "msn.h" -#include "md5.h" -#include "sha1.h" -#include "soap.h" -#include "xmltree.h" - -static gboolean msn_ns_connected(gpointer data, gint source, b_input_condition cond); -static gboolean msn_ns_callback(gpointer data, gint source, b_input_condition cond); - -static void msn_ns_send_adl_start(struct im_connection *ic); -static void msn_ns_send_adl(struct im_connection *ic); -static void msn_ns_structured_message(struct msn_data *md, char *msg, int msglen, char **cmd); -static void msn_ns_sdg(struct msn_data *md, char *who, char **parts, char *action, gboolean selfmessage); -static void msn_ns_nfy(struct msn_data *md, char *who, char **parts, char *action, gboolean is_put); - -int msn_ns_write(struct im_connection *ic, int fd, const char *fmt, ...) -{ - struct msn_data *md = ic->proto_data; - va_list params; - char *out; - size_t len; - int st; - - va_start(params, fmt); - out = g_strdup_vprintf(fmt, params); - va_end(params); - - if (fd < 0) { - fd = md->fd; - } - - if (getenv("BITLBEE_DEBUG")) { - fprintf(stderr, "\x1b[91m>>>[NS%d] %s\n\x1b[97m", fd, out); - } - - len = strlen(out); - - if (md->is_http) { - st = len; - msn_gw_write(md->gw, out, len); - } else { - st = write(fd, out, len); - } - - g_free(out); - if (st != len) { - imcb_error(ic, "Short write() to main server"); - imc_logout(ic, TRUE); - return 0; - } - - return 1; -} - -gboolean msn_ns_connect(struct im_connection *ic, const char *host, int port) -{ - struct msn_data *md = ic->proto_data; - - if (md->fd >= 0) { - closesocket(md->fd); - } - - if (md->is_http) { - md->gw = msn_gw_new(ic); - md->gw->callback = msn_ns_callback; - msn_ns_connected(md, -1, B_EV_IO_READ); - } else { - md->fd = proxy_connect(host, port, msn_ns_connected, md); - if (md->fd < 0) { - imcb_error(ic, "Could not connect to server"); - imc_logout(ic, TRUE); - return FALSE; - } - } - - return TRUE; -} - -static gboolean msn_ns_connected(gpointer data, gint source, b_input_condition cond) -{ - struct msn_data *md = data; - struct im_connection *ic = md->ic; - - /* this should be taken from XFR, but hardcoding it for now. it also prevents more redirects. */ - const char *redir_data = "VmVyc2lvbjogMQ0KWGZyQ291bnQ6IDINCklzR2VvWGZyOiB0cnVlDQo="; - - if (source == -1 && !md->is_http) { - imcb_error(ic, "Could not connect to server"); - imc_logout(ic, TRUE); - return FALSE; - } - - g_free(md->rxq); - md->rxlen = 0; - md->rxq = g_new0(char, 1); - - if (md->uuid == NULL) { - struct utsname name; - sha1_state_t sha[1]; - - /* UUID == SHA1("BitlBee" + my hostname + MSN username) */ - sha1_init(sha); - sha1_append(sha, (void *) "BitlBee", 7); - if (uname(&name) == 0) { - sha1_append(sha, (void *) name.nodename, strlen(name.nodename)); - } - sha1_append(sha, (void *) ic->acc->user, strlen(ic->acc->user)); - md->uuid = sha1_random_uuid(sha); - memcpy(md->uuid, "b171be3e", 8); /* :-P */ - } - - /* Having to handle potential errors in each write sure makes these ifs awkward...*/ - - if (msn_ns_write(ic, source, "VER %d %s CVR0\r\n", ++md->trId, MSNP_VER) && - msn_ns_write(ic, source, "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s %s\r\n", - ++md->trId, ic->acc->user, redir_data) && - msn_ns_write(ic, md->fd, "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user)) { - - if (!md->is_http) { - md->inpa = b_input_add(md->fd, B_EV_IO_READ, msn_ns_callback, md); - } - imcb_log(ic, "Connected to server, waiting for reply"); - } - - return FALSE; -} - -void msn_ns_close(struct msn_data *md) -{ - if (md->gw) { - msn_gw_free(md->gw); - } - if (md->fd >= 0) { - closesocket(md->fd); - b_event_remove(md->inpa); - } - - md->fd = md->inpa = -1; - g_free(md->rxq); - g_free(md->cmd_text); - - md->rxlen = 0; - md->rxq = NULL; - md->cmd_text = NULL; -} - -static gboolean msn_ns_callback(gpointer data, gint source, b_input_condition cond) -{ - struct msn_data *md = data; - struct im_connection *ic = md->ic; - char *bytes; - int st; - - if (md->is_http) { - st = msn_gw_read(md->gw, &bytes); - } else { - bytes = g_malloc(1024); - st = read(md->fd, bytes, 1024); - } - - if (st <= 0) { - imcb_error(ic, "Error while reading from server"); - imc_logout(ic, TRUE); - g_free(bytes); - return FALSE; - } - - msn_queue_feed(md, bytes, st); - - g_free(bytes); - - return msn_handler(md); -} - -int msn_ns_command(struct msn_data *md, char **cmd, int num_parts) -{ - struct im_connection *ic = md->ic; - - if (num_parts == 0) { - /* Hrrm... Empty command...? Ignore? */ - return(1); - } - - if (strcmp(cmd[0], "VER") == 0) { - if (cmd[2] && strncmp(cmd[2], MSNP_VER, 5) != 0) { - imcb_error(ic, "Unsupported protocol"); - imc_logout(ic, FALSE); - return(0); - } - - } else if (strcmp(cmd[0], "CVR") == 0) { - /* We don't give a damn about the information we just received */ - } else if (strcmp(cmd[0], "XFR") == 0) { - char *server; - int port; - - if (num_parts >= 6 && strcmp(cmd[2], "NS") == 0) { - b_event_remove(md->inpa); - md->inpa = -1; - - server = strchr(cmd[3], ':'); - if (!server) { - imcb_error(ic, "Syntax error"); - imc_logout(ic, TRUE); - return(0); - } - *server = 0; - port = atoi(server + 1); - server = cmd[3]; - - imcb_log(ic, "Transferring to other server"); - return msn_ns_connect(ic, server, port); - } else { - imcb_error(ic, "Syntax error"); - imc_logout(ic, TRUE); - return(0); - } - } else if (strcmp(cmd[0], "USR") == 0) { - if (num_parts >= 6 && strcmp(cmd[2], "SSO") == 0 && - strcmp(cmd[3], "S") == 0) { - g_free(md->pp_policy); - md->pp_policy = g_strdup(cmd[4]); - msn_soap_passport_sso_request(ic, cmd[5]); - } else if (strcmp(cmd[2], "OK") == 0) { - /* If the number after the handle is 0, the e-mail - address is unverified, which means we can't change - the display name. */ - if (cmd[4][0] == '0') { - md->flags |= MSN_EMAIL_UNVERIFIED; - } - - imcb_log(ic, "Authenticated, getting buddy list"); - msn_soap_memlist_request(ic); - } else { - imcb_error(ic, "Unknown authentication type"); - imc_logout(ic, FALSE); - return(0); - } - } else if (strcmp(cmd[0], "MSG") == 0) { - if (num_parts < 4) { - imcb_error(ic, "Syntax error"); - imc_logout(ic, TRUE); - return(0); - } - - md->msglen = atoi(cmd[3]); - - if (md->msglen <= 0) { - imcb_error(ic, "Syntax error"); - imc_logout(ic, TRUE); - return(0); - } - } else if (strcmp(cmd[0], "ADL") == 0) { - if (num_parts >= 3 && strcmp(cmd[2], "OK") == 0) { - msn_ns_send_adl(ic); - return msn_ns_finish_login(ic); - } else if (num_parts >= 3) { - md->msglen = atoi(cmd[2]); - } - } else if (strcmp(cmd[0], "RML") == 0) { - /* Move along, nothing to see here */ - } else if (strcmp(cmd[0], "CHL") == 0) { - char *resp; - int st; - - if (num_parts < 3) { - imcb_error(ic, "Syntax error"); - imc_logout(ic, TRUE); - return(0); - } - - resp = msn_p11_challenge(cmd[2]); - - st = msn_ns_write(ic, -1, "QRY %d %s %zd\r\n%s", - ++md->trId, MSNP11_PROD_ID, - strlen(resp), resp); - g_free(resp); - return st; - } else if (strcmp(cmd[0], "QRY") == 0) { - /* CONGRATULATIONS */ - } else if (strcmp(cmd[0], "OUT") == 0) { - imcb_error(ic, "Session terminated by remote server (%s)", cmd[1] ? cmd[1] : "reason unknown"); - imc_logout(ic, TRUE); - return(0); - } else if (strcmp(cmd[0], "GCF") == 0) { - /* Coming up is cmd[2] bytes of stuff we're supposed to - censore. Meh. */ - md->msglen = atoi(cmd[2]); - } else if ((strcmp(cmd[0], "NFY") == 0) || (strcmp(cmd[0], "SDG") == 0)) { - if (num_parts >= 3) { - md->msglen = atoi(cmd[2]); - } - } else if (strcmp(cmd[0], "PUT") == 0) { - if (num_parts >= 4) { - md->msglen = atoi(cmd[3]); - } - } else if (strcmp(cmd[0], "NOT") == 0) { - if (num_parts >= 2) { - md->msglen = atoi(cmd[1]); - } - } else if (strcmp(cmd[0], "QNG") == 0) { - ic->flags |= OPT_PONGED; - } else if (g_ascii_isdigit(cmd[0][0])) { - int num = atoi(cmd[0]); - const struct msn_status_code *err = msn_status_by_number(num); - - imcb_error(ic, "Error reported by MSN server: %s", err->text); - - if (err->flags & STATUS_FATAL) { - imc_logout(ic, TRUE); - return(0); - } - - /* Oh yes, errors can have payloads too now. Discard them for now. */ - if (num_parts >= 3) { - md->msglen = atoi(cmd[2]); - } - } else { - imcb_error(ic, "Received unknown command from main server: %s", cmd[0]); - } - - return(1); -} - -int msn_ns_message(struct msn_data *md, char *msg, int msglen, char **cmd, int num_parts) -{ - struct im_connection *ic = md->ic; - char *body; - int blen = 0; - - if (!num_parts) { - return(1); - } - - if ((body = strstr(msg, "\r\n\r\n"))) { - body += 4; - blen = msglen - (body - msg); - } - - if (strcmp(cmd[0], "MSG") == 0) { - if (g_strcasecmp(cmd[1], "Hotmail") == 0) { - char *ct = get_rfc822_header(msg, "Content-Type:", msglen); - - if (!ct) { - return(1); - } - - if (g_strncasecmp(ct, "application/x-msmsgssystemmessage", 33) == 0) { - char *mtype; - char *arg1; - - if (!body) { - return(1); - } - - mtype = get_rfc822_header(body, "Type:", blen); - arg1 = get_rfc822_header(body, "Arg1:", blen); - - if (mtype && strcmp(mtype, "1") == 0) { - if (arg1) { - imcb_log(ic, "The server is going down for maintenance in %s minutes.", - arg1); - } - } - - g_free(arg1); - g_free(mtype); - } else if (g_strncasecmp(ct, "text/x-msmsgsprofile", 20) == 0) { - /* We don't care about this profile for now... */ - } else if (g_strncasecmp(ct, "text/x-msmsgsinitialemailnotification", 37) == 0) { - if (set_getbool(&ic->acc->set, "mail_notifications")) { - char *inbox = get_rfc822_header(body, "Inbox-Unread:", blen); - char *folders = get_rfc822_header(body, "Folders-Unread:", blen); - - if (inbox && folders) { - imcb_notify_email(ic, - "INBOX contains %s new messages, plus %s messages in other folders.", inbox, - folders); - } - - g_free(inbox); - g_free(folders); - } - } else if (g_strncasecmp(ct, "text/x-msmsgsemailnotification", 30) == 0) { - if (set_getbool(&ic->acc->set, "mail_notifications")) { - char *from = get_rfc822_header(body, "From-Addr:", blen); - char *fromname = get_rfc822_header(body, "From:", blen); - - if (from && fromname) { - imcb_notify_email(ic, "Received an e-mail message from %s <%s>.", fromname, from); - } - - g_free(from); - g_free(fromname); - } - } else if (g_strncasecmp(ct, "text/x-msmsgsactivemailnotification", 35) == 0) { - /* Notification that a message has been read... Ignore it */ - } - - g_free(ct); - } - } else if (strcmp(cmd[0], "ADL") == 0) { - struct xt_node *adl, *d, *c; - - if (!(adl = xt_from_string(msg, msglen))) { - return 1; - } - - for (d = adl->children; d; d = d->next) { - char *dn; - if (strcmp(d->name, "d") != 0 || - (dn = xt_find_attr(d, "n")) == NULL) { - continue; - } - for (c = d->children; c; c = c->next) { - bee_user_t *bu; - struct msn_buddy_data *bd; - char *cn, *handle, *f, *l; - int flags; - - if (strcmp(c->name, "c") != 0 || - (l = xt_find_attr(c, "l")) == NULL || - (cn = xt_find_attr(c, "n")) == NULL) { - continue; - } - - /* FIXME: Use "t" here, guess I should just add it - as a prefix like elsewhere in the protocol. */ - handle = g_strdup_printf("%s@%s", cn, dn); - if (!((bu = bee_user_by_handle(ic->bee, ic, handle)) || - (bu = bee_user_new(ic->bee, ic, handle, 0)))) { - g_free(handle); - continue; - } - g_free(handle); - bd = bu->data; - - if ((f = xt_find_attr(c, "f"))) { - http_decode(f); - imcb_rename_buddy(ic, bu->handle, f); - } - - flags = atoi(l) & 15; - if (bd->flags != flags) { - bd->flags = flags; - msn_buddy_ask(bu); - } - } - } - } else if ((strcmp(cmd[0], "SDG") == 0) || (strcmp(cmd[0], "NFY") == 0)) { - msn_ns_structured_message(md, msg, msglen, cmd); - } - - return 1; -} - -/* returns newly allocated string */ -static char *msn_ns_parse_header_address(struct msn_data *md, char *headers, char *header_name) -{ - char *semicolon = NULL; - char *header = NULL; - char *address = NULL; - - if (!(header = get_rfc822_header(headers, header_name, 0))) { - return NULL; - } - - /* either the semicolon or the end of the string */ - semicolon = strchr(header, ';') ? : (header + strlen(header)); - - address = g_strndup(header + 2, semicolon - header - 2); - - g_free(header); - return address; -} - -static void msn_ns_structured_message(struct msn_data *md, char *msg, int msglen, char **cmd) -{ - char **parts = NULL; - char *action = NULL; - char *who = NULL; - gboolean selfmessage = FALSE; - - parts = g_strsplit(msg, "\r\n\r\n", 4); - - if (!(who = msn_ns_parse_header_address(md, parts[0], "From"))) { - goto cleanup; - } - - if (strcmp(who, md->ic->acc->user) == 0) { - selfmessage = TRUE; - g_free(who); - if (!(who = msn_ns_parse_header_address(md, parts[0], "To"))) { - goto cleanup; - } - } - - if ((strcmp(cmd[0], "SDG") == 0) && (action = get_rfc822_header(parts[2], "Message-Type", 0))) { - msn_ns_sdg(md, who, parts, action, selfmessage); - - } else if ((strcmp(cmd[0], "NFY") == 0) && (action = get_rfc822_header(parts[2], "Uri", 0))) { - gboolean is_put = (strcmp(cmd[1], "PUT") == 0); - msn_ns_nfy(md, who, parts, action, is_put); - } - -cleanup: - g_strfreev(parts); - g_free(action); - g_free(who); -} - -static void msn_ns_sdg(struct msn_data *md, char *who, char **parts, char *action, gboolean selfmessage) -{ - struct im_connection *ic = md->ic; - - if (strcmp(action, "Control/Typing") == 0 && !selfmessage) { - imcb_buddy_typing(ic, who, OPT_TYPING); - } else if (strcmp(action, "Text") == 0) { - imcb_buddy_msg(ic, who, parts[3], selfmessage ? OPT_SELFMESSAGE : 0, 0); - } -} - -static void msn_ns_nfy(struct msn_data *md, char *who, char **parts, char *action, gboolean is_put) -{ - struct im_connection *ic = md->ic; - struct xt_node *body = NULL; - struct xt_node *s = NULL; - const char *state = NULL; - char *nick = NULL; - char *psm = NULL; - int flags = OPT_LOGGED_IN; - - if (strcmp(action, "/user") != 0) { - return; - } - - if (!(body = xt_from_string(parts[3], 0))) { - goto cleanup; - } - - s = body->children; - while ((s = xt_find_node(s, "s"))) { - struct xt_node *s2; - char *n = xt_find_attr(s, "n"); /* service name: IM, PE, etc */ - - if (strcmp(n, "IM") == 0) { - /* IM has basic presence information */ - if (!is_put) { - /* NFY DEL with a <s> usually means log out from the last endpoint */ - flags &= ~OPT_LOGGED_IN; - break; - } - - s2 = xt_find_node(s->children, "Status"); - if (s2 && s2->text_len) { - const struct msn_away_state *msn_state = msn_away_state_by_code(s2->text); - state = msn_state->name; - if (msn_state != msn_away_state_list) { - flags |= OPT_AWAY; - } - } - } else if (strcmp(n, "PE") == 0) { - if ((s2 = xt_find_node(s->children, "PSM")) && s2->text_len) { - psm = s2->text; - } - if ((s2 = xt_find_node(s->children, "FriendlyName")) && s2->text_len) { - nick = s2->text; - } - } - s = s->next; - } - - imcb_buddy_status(ic, who, flags, state, psm); - - if (nick) { - imcb_rename_buddy(ic, who, nick); - } - -cleanup: - xt_free_node(body); -} - -void msn_auth_got_passport_token(struct im_connection *ic, const char *token, const char *error) -{ - struct msn_data *md; - - /* Dead connection? */ - if (g_slist_find(msn_connections, ic) == NULL) { - return; - } - - md = ic->proto_data; - - if (token) { - msn_ns_write(ic, -1, "USR %d SSO S %s %s {%s}\r\n", ++md->trId, md->tokens[0], token, md->uuid); - } else { - imcb_error(ic, "Error during Passport authentication: %s", error); - - /* don't reconnect with auth errors */ - if (error && g_str_has_prefix(error, "wsse:FailedAuthentication")) { - imc_logout(ic, FALSE); - } else { - imc_logout(ic, TRUE); - } - } -} - -void msn_auth_got_contact_list(struct im_connection *ic) -{ - /* Dead connection? */ - if (g_slist_find(msn_connections, ic) == NULL) { - return; - } - - msn_ns_send_adl_start(ic); - msn_ns_finish_login(ic); -} - -static gboolean msn_ns_send_adl_1(gpointer key, gpointer value, gpointer data) -{ - struct xt_node *adl = data, *d, *c, *s; - struct bee_user *bu = value; - struct msn_buddy_data *bd = bu->data; - struct msn_data *md = bu->ic->proto_data; - char handle[strlen(bu->handle) + 1]; - char *domain; - char l[4]; - - if ((bd->flags & (MSN_BUDDY_FL | MSN_BUDDY_AL)) == 0 || (bd->flags & MSN_BUDDY_ADL_SYNCED)) { - return FALSE; - } - - strcpy(handle, bu->handle); - if ((domain = strchr(handle, '@')) == NULL) { /* WTF */ - return FALSE; - } - *domain = '\0'; - domain++; - - if ((d = adl->children) == NULL || - g_strcasecmp(xt_find_attr(d, "n"), domain) != 0) { - d = xt_new_node("d", NULL, NULL); - xt_add_attr(d, "n", domain); - xt_insert_child(adl, d); - } - - g_snprintf(l, sizeof(l), "%d", bd->flags & (MSN_BUDDY_FL | MSN_BUDDY_AL)); - c = xt_new_node("c", NULL, NULL); - xt_add_attr(c, "n", handle); - xt_add_attr(c, "t", "1"); /* FIXME: Network type, i.e. 32 for Y!MSG */ - s = xt_new_node("s", NULL, NULL); - xt_add_attr(s, "n", "IM"); - xt_add_attr(s, "l", l); - xt_insert_child(c, s); - xt_insert_child(d, c); - - /* Do this in batches of 100. */ - bd->flags |= MSN_BUDDY_ADL_SYNCED; - return (--md->adl_todo % 140) == 0; -} - -static void msn_ns_send_adl(struct im_connection *ic) -{ - struct xt_node *adl; - struct msn_data *md = ic->proto_data; - char *adls; - - adl = xt_new_node("ml", NULL, NULL); - xt_add_attr(adl, "l", "1"); - g_tree_foreach(md->domaintree, msn_ns_send_adl_1, adl); - if (adl->children == NULL) { - /* This tells the caller that we're done now. */ - md->adl_todo = -1; - xt_free_node(adl); - return; - } - - adls = xt_to_string(adl); - xt_free_node(adl); - msn_ns_write(ic, -1, "ADL %d %zd\r\n%s", ++md->trId, strlen(adls), adls); - g_free(adls); -} - -static void msn_ns_send_adl_start(struct im_connection *ic) -{ - struct msn_data *md; - GSList *l; - - /* Dead connection? */ - if (g_slist_find(msn_connections, ic) == NULL) { - return; - } - - md = ic->proto_data; - md->adl_todo = 0; - for (l = ic->bee->users; l; l = l->next) { - bee_user_t *bu = l->data; - struct msn_buddy_data *bd = bu->data; - - if (bu->ic != ic || (bd->flags & (MSN_BUDDY_FL | MSN_BUDDY_AL)) == 0) { - continue; - } - - bd->flags &= ~MSN_BUDDY_ADL_SYNCED; - md->adl_todo++; - } - - msn_ns_send_adl(ic); -} - -int msn_ns_finish_login(struct im_connection *ic) -{ - struct msn_data *md = ic->proto_data; - - if (ic->flags & OPT_LOGGED_IN) { - return 1; - } - - if (md->adl_todo < 0) { - md->flags |= MSN_DONE_ADL; - } - - if ((md->flags & MSN_DONE_ADL) && (md->flags & MSN_GOT_PROFILE)) { - imcb_connected(ic); - } - - return 1; -} - -static int msn_ns_send_sdg(struct im_connection *ic, bee_user_t *bu, const char *message_type, const char *text) -{ - struct msn_data *md = ic->proto_data; - int retval = 0; - char *buf; - - buf = g_strdup_printf(MSN_MESSAGE_HEADERS, bu->handle, ic->acc->user, md->uuid, message_type, strlen(text), text); - retval = msn_ns_write(ic, -1, "SDG %d %zd\r\n%s", ++md->trId, strlen(buf), buf); - g_free(buf); - return retval; -} - -int msn_ns_send_typing(struct im_connection *ic, bee_user_t *bu) -{ - return msn_ns_send_sdg(ic, bu, "Control/Typing", ""); -} - -int msn_ns_send_message(struct im_connection *ic, bee_user_t *bu, const char *text) -{ - return msn_ns_send_sdg(ic, bu, "Text", text); -} - diff --git a/protocols/msn/soap.c b/protocols/msn/soap.c deleted file mode 100644 index 14aaed11..00000000 --- a/protocols/msn/soap.c +++ /dev/null @@ -1,1032 +0,0 @@ -/********************************************************************\ - * BitlBee -- An IRC to other IM-networks gateway * - * * - * Copyright 2002-2012 Wilmer van der Gaast and others * - \********************************************************************/ - -/* MSN module - All the SOAPy XML stuff. - Some manager at Microsoft apparently thought MSNP wasn't XMLy enough so - someone stepped up and changed that. This is the result. Kilobytes and - more kilobytes of XML vomit to transfer tiny bits of informaiton. */ - -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License with - the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; - if not, write to the Free Software Foundation, Inc., 51 Franklin St., - Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include "http_client.h" -#include "soap.h" -#include "msn.h" -#include "bitlbee.h" -#include "url.h" -#include "misc.h" -#include "sha1.h" -#include "base64.h" -#include "xmltree.h" -#include <ctype.h> -#include <errno.h> - -/* This file tries to make SOAP stuff pretty simple to do by letting you just - provide a function to build a request, a few functions to parse various - parts of the response, and a function to run when the full response was - received and parsed. See the various examples below. */ - -typedef enum { - MSN_SOAP_OK, - MSN_SOAP_RETRY, - MSN_SOAP_REAUTH, - MSN_SOAP_ABORT, -} msn_soap_result_t; - -struct msn_soap_req_data; -typedef int (*msn_soap_func) (struct msn_soap_req_data *); - -struct msn_soap_req_data { - void *data; - struct im_connection *ic; - int ttl; - char *error; - - char *url, *action, *payload; - struct http_request *http_req; - - const struct xt_handler_entry *xml_parser; - msn_soap_func build_request, handle_response, free_data; -}; - -static int msn_soap_send_request(struct msn_soap_req_data *req); -static void msn_soap_free(struct msn_soap_req_data *soap_req); -static void msn_soap_debug_print(const char *headers, const char *payload); - -static int msn_soap_start(struct im_connection *ic, - void *data, - msn_soap_func build_request, - const struct xt_handler_entry *xml_parser, - msn_soap_func handle_response, - msn_soap_func free_data) -{ - struct msn_soap_req_data *req = g_new0(struct msn_soap_req_data, 1); - - req->ic = ic; - req->data = data; - req->xml_parser = xml_parser; - req->build_request = build_request; - req->handle_response = handle_response; - req->free_data = free_data; - req->ttl = 3; - - return msn_soap_send_request(req); -} - -static void msn_soap_handle_response(struct http_request *http_req); - -static int msn_soap_send_request(struct msn_soap_req_data *soap_req) -{ - char *http_req; - char *soap_action = NULL; - url_t url; - - soap_req->build_request(soap_req); - - if (soap_req->action) { - soap_action = g_strdup_printf("SOAPAction: \"%s\"\r\n", soap_req->action); - } - - url_set(&url, soap_req->url); - http_req = g_strdup_printf(SOAP_HTTP_REQUEST, url.file, url.host, - soap_action ? soap_action : "", - strlen(soap_req->payload), soap_req->payload); - - msn_soap_debug_print(http_req, soap_req->payload); - - soap_req->http_req = http_dorequest(url.host, url.port, url.proto == PROTO_HTTPS, - http_req, msn_soap_handle_response, soap_req); - - g_free(http_req); - g_free(soap_action); - - return soap_req->http_req != NULL; -} - -static void msn_soap_handle_response(struct http_request *http_req) -{ - struct msn_soap_req_data *soap_req = http_req->data; - int st; - - if (g_slist_find(msn_connections, soap_req->ic) == NULL) { - msn_soap_free(soap_req); - return; - } - - msn_soap_debug_print(http_req->reply_headers, http_req->reply_body); - - if (http_req->body_size > 0) { - struct xt_parser *parser; - struct xt_node *err; - - parser = xt_new(soap_req->xml_parser, soap_req); - xt_feed(parser, http_req->reply_body, http_req->body_size); - if (http_req->status_code == 500 && - (err = xt_find_path(parser->root, "soap:Body/soap:Fault/detail/errorcode")) && - err->text_len > 0) { - if (strcmp(err->text, "PassportAuthFail") == 0) { - xt_free(parser); - st = MSN_SOAP_REAUTH; - goto fail; - } - /* TODO: Handle/report other errors. */ - } - - xt_handle(parser, NULL, -1); - xt_free(parser); - } - - if (http_req->status_code != 200) { - soap_req->error = g_strdup(http_req->status_string); - } - - st = soap_req->handle_response(soap_req); - -fail: - g_free(soap_req->url); - g_free(soap_req->action); - g_free(soap_req->payload); - g_free(soap_req->error); - soap_req->url = soap_req->action = soap_req->payload = soap_req->error = NULL; - - if (st == MSN_SOAP_RETRY && --soap_req->ttl) { - msn_soap_send_request(soap_req); - } else if (st == MSN_SOAP_REAUTH) { - struct msn_data *md = soap_req->ic->proto_data; - - if (!(md->flags & MSN_REAUTHING)) { - /* Nonce shouldn't actually be touched for re-auths. */ - msn_soap_passport_sso_request(soap_req->ic, "blaataap"); - md->flags |= MSN_REAUTHING; - } - md->soapq = g_slist_append(md->soapq, soap_req); - } else { - soap_req->free_data(soap_req); - g_free(soap_req); - } -} - -static char *msn_soap_abservice_build(const char *body_fmt, const char *scenario, const char *ticket, ...) -{ - va_list params; - char *ret, *format, *body; - - format = g_markup_printf_escaped(SOAP_ABSERVICE_PAYLOAD, scenario, ticket); - - va_start(params, ticket); - body = g_strdup_vprintf(body_fmt, params); - va_end(params); - - ret = g_strdup_printf(format, body); - g_free(body); - g_free(format); - - return ret; -} - -static void msn_soap_debug_print(const char *headers, const char *payload) -{ - char *s; - - if (!getenv("BITLBEE_DEBUG")) { - return; - } - fprintf(stderr, "\n\x1b[90mSOAP:\n"); - - if (headers) { - if ((s = strstr(headers, "\r\n\r\n"))) { - fwrite(headers, s - headers + 4, 1, stderr); - } else { - fwrite(headers, strlen(headers), 1, stderr); - } - } - - if (payload) { - struct xt_node *xt = xt_from_string(payload, 0); - if (xt) { - xt_print(xt); - } - xt_free_node(xt); - } - fprintf(stderr, "\n\x1b[97m\n"); -} - -int msn_soapq_flush(struct im_connection *ic, gboolean resend) -{ - struct msn_data *md = ic->proto_data; - - while (md->soapq) { - if (resend) { - msn_soap_send_request((struct msn_soap_req_data*) md->soapq->data); - } else { - msn_soap_free((struct msn_soap_req_data*) md->soapq->data); - } - md->soapq = g_slist_remove(md->soapq, md->soapq->data); - } - - return MSN_SOAP_OK; -} - -static void msn_soap_free(struct msn_soap_req_data *soap_req) -{ - soap_req->free_data(soap_req); - g_free(soap_req->url); - g_free(soap_req->action); - g_free(soap_req->payload); - g_free(soap_req->error); - g_free(soap_req); -} - - -/* passport_sso: Authentication MSNP15+ */ - -struct msn_soap_passport_sso_data { - char *nonce; - char *secret; - char *error; - char *redirect; -}; - -static int msn_soap_passport_sso_build_request(struct msn_soap_req_data *soap_req) -{ - struct msn_soap_passport_sso_data *sd = soap_req->data; - struct im_connection *ic = soap_req->ic; - struct msn_data *md = ic->proto_data; - - if (sd->redirect) { - soap_req->url = sd->redirect; - sd->redirect = NULL; - } - /* MS changed this URL and broke the old MSN-specific one. The generic - one works, forwarding us to a msn.com URL that works. Takes an extra - second, but that's better than not being able to log in at all. :-/ - else if( g_str_has_suffix( ic->acc->user, "@msn.com" ) ) - soap_req->url = g_strdup( SOAP_PASSPORT_SSO_URL_MSN ); - */ - else { - soap_req->url = g_strdup(SOAP_PASSPORT_SSO_URL); - } - - soap_req->payload = g_markup_printf_escaped(SOAP_PASSPORT_SSO_PAYLOAD, - ic->acc->user, ic->acc->pass, md->pp_policy); - - return MSN_SOAP_OK; -} - -static xt_status msn_soap_passport_sso_token(struct xt_node *node, gpointer data) -{ - struct msn_soap_req_data *soap_req = data; - struct msn_soap_passport_sso_data *sd = soap_req->data; - struct msn_data *md = soap_req->ic->proto_data; - struct xt_node *p; - char *id; - - if ((id = xt_find_attr(node, "Id")) == NULL) { - return XT_HANDLED; - } - id += strlen(id) - 1; - if (*id == '1' && - (p = xt_find_path(node, "../../wst:RequestedProofToken/wst:BinarySecret")) && - p->text) { - sd->secret = g_strdup(p->text); - } - - *id -= '1'; - if (*id >= 0 && *id < sizeof(md->tokens) / sizeof(md->tokens[0])) { - g_free(md->tokens[(int) *id]); - md->tokens[(int) *id] = g_strdup(node->text); - } - - return XT_HANDLED; -} - -static xt_status msn_soap_passport_failure(struct xt_node *node, gpointer data) -{ - struct msn_soap_req_data *soap_req = data; - struct msn_soap_passport_sso_data *sd = soap_req->data; - struct xt_node *code = xt_find_node(node->children, "faultcode"); - struct xt_node *string = xt_find_node(node->children, "faultstring"); - struct xt_node *reqstatus = xt_find_path(node, "psf:pp/psf:reqstatus"); - struct xt_node *url; - - if (code == NULL || code->text_len == 0) { - sd->error = g_strdup("Unknown error"); - } else if (strcmp(code->text, "psf:Redirect") == 0 && - (url = xt_find_node(node->children, "psf:redirectUrl")) && - url->text_len > 0) { - sd->redirect = g_strdup(url->text); - } else if (reqstatus && strcmp(reqstatus->text, "0x800488fe") == 0) { - char *msg = "Location blocked. Log in to live.com, go to recent activity and click 'this was me'"; - sd->error = g_strdup_printf("%s (%s)", code->text, msg); - } else { - sd->error = g_strdup_printf("%s (%s)", code->text, string && string->text_len ? - string->text : "no description available"); - } - - return XT_HANDLED; -} - -static const struct xt_handler_entry msn_soap_passport_sso_parser[] = { - { "wsse:BinarySecurityToken", "wst:RequestedSecurityToken", msn_soap_passport_sso_token }, - { "S:Fault", "S:Envelope", msn_soap_passport_failure }, - { "S:Fault", "wst:RequestSecurityTokenResponse", msn_soap_passport_failure }, - { NULL, NULL, NULL } -}; - -static char *msn_key_fuckery(char *key, int key_len, char *type) -{ - unsigned char hash1[20 + strlen(type) + 1]; - unsigned char hash2[20]; - char *ret; - - sha1_hmac(key, key_len, type, 0, hash1); - strcpy((char *) hash1 + 20, type); - sha1_hmac(key, key_len, (char *) hash1, sizeof(hash1) - 1, hash2); - - /* This is okay as hash1 is read completely before it's overwritten. */ - sha1_hmac(key, key_len, (char *) hash1, 20, hash1); - sha1_hmac(key, key_len, (char *) hash1, sizeof(hash1) - 1, hash1); - - ret = g_malloc(24); - memcpy(ret, hash2, 20); - memcpy(ret + 20, hash1, 4); - return ret; -} - -static int msn_soap_passport_sso_handle_response(struct msn_soap_req_data *soap_req) -{ - struct msn_soap_passport_sso_data *sd = soap_req->data; - struct im_connection *ic = soap_req->ic; - struct msn_data *md = ic->proto_data; - char *key1, *key2, *key3, *blurb64; - int key1_len; - unsigned char *padnonce, *des3res; - - struct { - unsigned int uStructHeaderSize; // 28. Does not count data - unsigned int uCryptMode; // CRYPT_MODE_CBC (1) - unsigned int uCipherType; // TripleDES (0x6603) - unsigned int uHashType; // SHA1 (0x8004) - unsigned int uIVLen; // 8 - unsigned int uHashLen; // 20 - unsigned int uCipherLen; // 72 - unsigned char iv[8]; - unsigned char hash[20]; - unsigned char cipherbytes[72]; - } blurb = { - GUINT32_TO_LE(28), - GUINT32_TO_LE(1), - GUINT32_TO_LE(0x6603), - GUINT32_TO_LE(0x8004), - GUINT32_TO_LE(8), - GUINT32_TO_LE(20), - GUINT32_TO_LE(72), - }; - - if (sd->redirect) { - return MSN_SOAP_RETRY; - } - - if (md->soapq) { - md->flags &= ~MSN_REAUTHING; - return msn_soapq_flush(ic, TRUE); - } - - if (sd->secret == NULL) { - msn_auth_got_passport_token(ic, NULL, sd->error ? sd->error : soap_req->error); - return MSN_SOAP_OK; - } - - key1_len = base64_decode(sd->secret, (unsigned char **) &key1); - - key2 = msn_key_fuckery(key1, key1_len, "WS-SecureConversationSESSION KEY HASH"); - key3 = msn_key_fuckery(key1, key1_len, "WS-SecureConversationSESSION KEY ENCRYPTION"); - - sha1_hmac(key2, 24, sd->nonce, 0, blurb.hash); - padnonce = g_malloc(strlen(sd->nonce) + 8); - strcpy((char *) padnonce, sd->nonce); - memset(padnonce + strlen(sd->nonce), 8, 8); - - random_bytes(blurb.iv, 8); - - ssl_des3_encrypt((unsigned char *) key3, 24, padnonce, strlen(sd->nonce) + 8, blurb.iv, &des3res); - memcpy(blurb.cipherbytes, des3res, 72); - - blurb64 = base64_encode((unsigned char *) &blurb, sizeof(blurb)); - msn_auth_got_passport_token(ic, blurb64, NULL); - - g_free(padnonce); - g_free(blurb64); - g_free(des3res); - g_free(key1); - g_free(key2); - g_free(key3); - - return MSN_SOAP_OK; -} - -static int msn_soap_passport_sso_free_data(struct msn_soap_req_data *soap_req) -{ - struct msn_soap_passport_sso_data *sd = soap_req->data; - - g_free(sd->nonce); - g_free(sd->secret); - g_free(sd->error); - g_free(sd->redirect); - g_free(sd); - - return MSN_SOAP_OK; -} - -int msn_soap_passport_sso_request(struct im_connection *ic, const char *nonce) -{ - struct msn_soap_passport_sso_data *sd = g_new0(struct msn_soap_passport_sso_data, 1); - - sd->nonce = g_strdup(nonce); - - return msn_soap_start(ic, sd, msn_soap_passport_sso_build_request, - msn_soap_passport_sso_parser, - msn_soap_passport_sso_handle_response, - msn_soap_passport_sso_free_data); -} - - -/* memlist: Fetching the membership list (NOT address book) */ - -static int msn_soap_memlist_build_request(struct msn_soap_req_data *soap_req) -{ - struct msn_data *md = soap_req->ic->proto_data; - - soap_req->url = g_strdup(SOAP_MEMLIST_URL); - soap_req->action = g_strdup(SOAP_MEMLIST_ACTION); - soap_req->payload = msn_soap_abservice_build(SOAP_MEMLIST_PAYLOAD, "Initial", md->tokens[1]); - - return 1; -} - -static xt_status msn_soap_memlist_member(struct xt_node *node, gpointer data) -{ - bee_user_t *bu; - struct msn_buddy_data *bd; - struct xt_node *p; - char *role = NULL, *handle = NULL; - struct msn_soap_req_data *soap_req = data; - struct im_connection *ic = soap_req->ic; - - if ((p = xt_find_path(node, "../../MemberRole"))) { - role = p->text; - } - - if ((p = xt_find_node(node->children, "PassportName"))) { - handle = p->text; - } - - if (!role || !handle || - !((bu = bee_user_by_handle(ic->bee, ic, handle)) || - (bu = bee_user_new(ic->bee, ic, handle, 0)))) { - return XT_HANDLED; - } - - bd = bu->data; - if (strcmp(role, "Allow") == 0) { - bd->flags |= MSN_BUDDY_AL; - ic->permit = g_slist_prepend(ic->permit, g_strdup(handle)); - } else if (strcmp(role, "Block") == 0) { - bd->flags |= MSN_BUDDY_BL; - ic->deny = g_slist_prepend(ic->deny, g_strdup(handle)); - } else if (strcmp(role, "Reverse") == 0) { - bd->flags |= MSN_BUDDY_RL; - } else if (strcmp(role, "Pending") == 0) { - bd->flags |= MSN_BUDDY_PL; - } - - if (getenv("BITLBEE_DEBUG")) { - fprintf(stderr, "%p %s %d\n", bu, handle, bd->flags); - } - - return XT_HANDLED; -} - -static const struct xt_handler_entry msn_soap_memlist_parser[] = { - { "Member", "Members", msn_soap_memlist_member }, - { NULL, NULL, NULL } -}; - -static int msn_soap_memlist_handle_response(struct msn_soap_req_data *soap_req) -{ - msn_soap_addressbook_request(soap_req->ic); - - return MSN_SOAP_OK; -} - -static int msn_soap_memlist_free_data(struct msn_soap_req_data *soap_req) -{ - return 0; -} - -int msn_soap_memlist_request(struct im_connection *ic) -{ - return msn_soap_start(ic, NULL, msn_soap_memlist_build_request, - msn_soap_memlist_parser, - msn_soap_memlist_handle_response, - msn_soap_memlist_free_data); -} - -/* Variant: Adding/Removing people */ -struct msn_soap_memlist_edit_data { - char *handle; - gboolean add; - msn_buddy_flags_t list; -}; - -static int msn_soap_memlist_edit_build_request(struct msn_soap_req_data *soap_req) -{ - struct msn_data *md = soap_req->ic->proto_data; - struct msn_soap_memlist_edit_data *med = soap_req->data; - char *add, *scenario, *list; - - soap_req->url = g_strdup(SOAP_MEMLIST_URL); - if (med->add) { - soap_req->action = g_strdup(SOAP_MEMLIST_ADD_ACTION); - add = "Add"; - } else { - soap_req->action = g_strdup(SOAP_MEMLIST_DEL_ACTION); - add = "Delete"; - } - switch (med->list) { - case MSN_BUDDY_AL: - scenario = "BlockUnblock"; - list = "Allow"; - break; - case MSN_BUDDY_BL: - scenario = "BlockUnblock"; - list = "Block"; - break; - case MSN_BUDDY_RL: - scenario = "Timer"; - list = "Reverse"; - break; - case MSN_BUDDY_PL: - default: - scenario = "Timer"; - list = "Pending"; - break; - } - soap_req->payload = msn_soap_abservice_build(SOAP_MEMLIST_EDIT_PAYLOAD, - scenario, md->tokens[1], add, list, med->handle, add); - - return 1; -} - -static int msn_soap_memlist_edit_handle_response(struct msn_soap_req_data *soap_req) -{ - return MSN_SOAP_OK; -} - -static int msn_soap_memlist_edit_free_data(struct msn_soap_req_data *soap_req) -{ - struct msn_soap_memlist_edit_data *med = soap_req->data; - - g_free(med->handle); - g_free(med); - - return 0; -} - -int msn_soap_memlist_edit(struct im_connection *ic, const char *handle, gboolean add, int list) -{ - struct msn_soap_memlist_edit_data *med; - - med = g_new0(struct msn_soap_memlist_edit_data, 1); - med->handle = g_strdup(handle); - med->add = add; - med->list = list; - - return msn_soap_start(ic, med, msn_soap_memlist_edit_build_request, - NULL, - msn_soap_memlist_edit_handle_response, - msn_soap_memlist_edit_free_data); -} - - -/* addressbook: Fetching the membership list (NOT address book) */ - -static int msn_soap_addressbook_build_request(struct msn_soap_req_data *soap_req) -{ - struct msn_data *md = soap_req->ic->proto_data; - - soap_req->url = g_strdup(SOAP_ADDRESSBOOK_URL); - soap_req->action = g_strdup(SOAP_ADDRESSBOOK_ACTION); - soap_req->payload = msn_soap_abservice_build(SOAP_ADDRESSBOOK_PAYLOAD, "Initial", md->tokens[1]); - - return 1; -} - -static xt_status msn_soap_addressbook_group(struct xt_node *node, gpointer data) -{ - struct xt_node *p; - char *id = NULL, *name = NULL; - struct msn_soap_req_data *soap_req = data; - struct msn_data *md = soap_req->ic->proto_data; - - if ((p = xt_find_path(node, "../groupId"))) { - id = p->text; - } - - if ((p = xt_find_node(node->children, "name"))) { - name = p->text; - } - - if (id && name) { - struct msn_group *mg = g_new0(struct msn_group, 1); - mg->id = g_strdup(id); - mg->name = g_strdup(name); - md->groups = g_slist_prepend(md->groups, mg); - } - - if (getenv("BITLBEE_DEBUG")) { - fprintf(stderr, "%s %s\n", id, name); - } - - return XT_HANDLED; -} - -static xt_status msn_soap_addressbook_contact(struct xt_node *node, gpointer data) -{ - bee_user_t *bu; - struct msn_buddy_data *bd; - struct xt_node *p; - char *id = NULL, *type = NULL, *handle = NULL, *is_msgr = "false", - *display_name = NULL, *group_id = NULL; - struct msn_soap_req_data *soap_req = data; - struct im_connection *ic = soap_req->ic; - struct msn_group *group; - - if ((p = xt_find_path(node, "../contactId"))) { - id = p->text; - } - if ((p = xt_find_node(node->children, "contactType"))) { - type = p->text; - } - if ((p = xt_find_node(node->children, "passportName"))) { - handle = p->text; - } - if ((p = xt_find_node(node->children, "displayName"))) { - display_name = p->text; - } - if ((p = xt_find_node(node->children, "isMessengerUser"))) { - is_msgr = p->text; - } - if ((p = xt_find_path(node, "groupIds/guid"))) { - group_id = p->text; - } - - if (type && g_strcasecmp(type, "me") == 0) { - set_t *set = set_find(&ic->acc->set, "display_name"); - g_free(set->value); - set->value = g_strdup(display_name); - - /* Try to fetch the profile; if the user has one, that's where - we can find the persistent display_name. */ - if ((p = xt_find_node(node->children, "CID")) && p->text) { - msn_soap_profile_get(ic, p->text); - } - - return XT_HANDLED; - } - - if (!bool2int(is_msgr) || handle == NULL) { - return XT_HANDLED; - } - - if (!(bu = bee_user_by_handle(ic->bee, ic, handle)) && - !(bu = bee_user_new(ic->bee, ic, handle, 0))) { - return XT_HANDLED; - } - - bd = bu->data; - bd->flags |= MSN_BUDDY_FL; - g_free(bd->cid); - bd->cid = g_strdup(id); - - imcb_rename_buddy(ic, handle, display_name); - - if (group_id && (group = msn_group_by_id(ic, group_id))) { - imcb_add_buddy(ic, handle, group->name); - } - - if (getenv("BITLBEE_DEBUG")) { - fprintf(stderr, "%s %s %s %s\n", id, type, handle, display_name); - } - - return XT_HANDLED; -} - -static const struct xt_handler_entry msn_soap_addressbook_parser[] = { - { "contactInfo", "Contact", msn_soap_addressbook_contact }, - { "groupInfo", "Group", msn_soap_addressbook_group }, - { NULL, NULL, NULL } -}; - -static int msn_soap_addressbook_handle_response(struct msn_soap_req_data *soap_req) -{ - GSList *l; - int wtf = 0; - - for (l = soap_req->ic->bee->users; l; l = l->next) { - struct bee_user *bu = l->data; - struct msn_buddy_data *bd = bu->data; - - if (bu->ic == soap_req->ic && bd) { - msn_buddy_ask(bu); - - if ((bd->flags & (MSN_BUDDY_AL | MSN_BUDDY_BL)) == - (MSN_BUDDY_AL | MSN_BUDDY_BL)) { - /* both allow and block, delete block, add wtf */ - bd->flags &= ~MSN_BUDDY_BL; - wtf++; - } - - - if ((bd->flags & (MSN_BUDDY_AL | MSN_BUDDY_BL)) == 0) { - /* neither allow or block, add allow */ - bd->flags |= MSN_BUDDY_AL; - } - } - } - - if (wtf) { - imcb_log(soap_req->ic, "Warning: %d contacts were in both your " - "block and your allow list. Assuming they're all " - "allowed.", wtf); - } - - msn_auth_got_contact_list(soap_req->ic); - - return MSN_SOAP_OK; -} - -static int msn_soap_addressbook_free_data(struct msn_soap_req_data *soap_req) -{ - return 0; -} - -int msn_soap_addressbook_request(struct im_connection *ic) -{ - return msn_soap_start(ic, NULL, msn_soap_addressbook_build_request, - msn_soap_addressbook_parser, - msn_soap_addressbook_handle_response, - msn_soap_addressbook_free_data); -} - -/* Variant: Change our display name. */ -static int msn_soap_ab_namechange_build_request(struct msn_soap_req_data *soap_req) -{ - struct msn_data *md = soap_req->ic->proto_data; - - soap_req->url = g_strdup(SOAP_ADDRESSBOOK_URL); - soap_req->action = g_strdup(SOAP_AB_NAMECHANGE_ACTION); - soap_req->payload = msn_soap_abservice_build(SOAP_AB_NAMECHANGE_PAYLOAD, - "Timer", md->tokens[1], (char *) soap_req->data); - - return 1; -} - -static int msn_soap_ab_namechange_handle_response(struct msn_soap_req_data *soap_req) -{ - /* TODO: Ack the change? Not sure what the NAKs look like.. */ - return MSN_SOAP_OK; -} - -static int msn_soap_ab_namechange_free_data(struct msn_soap_req_data *soap_req) -{ - g_free(soap_req->data); - return 0; -} - -int msn_soap_addressbook_set_display_name(struct im_connection *ic, const char *new) -{ - return msn_soap_start(ic, g_strdup(new), - msn_soap_ab_namechange_build_request, - NULL, - msn_soap_ab_namechange_handle_response, - msn_soap_ab_namechange_free_data); -} - -/* Add a contact. */ -static int msn_soap_ab_contact_add_build_request(struct msn_soap_req_data *soap_req) -{ - struct msn_data *md = soap_req->ic->proto_data; - bee_user_t *bu = soap_req->data; - - soap_req->url = g_strdup(SOAP_ADDRESSBOOK_URL); - soap_req->action = g_strdup(SOAP_AB_CONTACT_ADD_ACTION); - soap_req->payload = msn_soap_abservice_build(SOAP_AB_CONTACT_ADD_PAYLOAD, - "ContactSave", md->tokens[1], bu->handle, - bu->fullname ? bu->fullname : bu->handle); - - return 1; -} - -static xt_status msn_soap_ab_contact_add_cid(struct xt_node *node, gpointer data) -{ - struct msn_soap_req_data *soap_req = data; - bee_user_t *bu = soap_req->data; - struct msn_buddy_data *bd = bu->data; - - g_free(bd->cid); - bd->cid = g_strdup(node->text); - - return XT_HANDLED; -} - -static const struct xt_handler_entry msn_soap_ab_contact_add_parser[] = { - { "guid", "ABContactAddResult", msn_soap_ab_contact_add_cid }, - { NULL, NULL, NULL } -}; - -static int msn_soap_ab_contact_add_handle_response(struct msn_soap_req_data *soap_req) -{ - /* TODO: Ack the change? Not sure what the NAKs look like.. */ - return MSN_SOAP_OK; -} - -static int msn_soap_ab_contact_add_free_data(struct msn_soap_req_data *soap_req) -{ - return 0; -} - -int msn_soap_ab_contact_add(struct im_connection *ic, bee_user_t *bu) -{ - return msn_soap_start(ic, bu, - msn_soap_ab_contact_add_build_request, - msn_soap_ab_contact_add_parser, - msn_soap_ab_contact_add_handle_response, - msn_soap_ab_contact_add_free_data); -} - -/* Remove a contact. */ -static int msn_soap_ab_contact_del_build_request(struct msn_soap_req_data *soap_req) -{ - struct msn_data *md = soap_req->ic->proto_data; - const char *cid = soap_req->data; - - soap_req->url = g_strdup(SOAP_ADDRESSBOOK_URL); - soap_req->action = g_strdup(SOAP_AB_CONTACT_DEL_ACTION); - soap_req->payload = msn_soap_abservice_build(SOAP_AB_CONTACT_DEL_PAYLOAD, - "Timer", md->tokens[1], cid); - - return 1; -} - -static int msn_soap_ab_contact_del_handle_response(struct msn_soap_req_data *soap_req) -{ - /* TODO: Ack the change? Not sure what the NAKs look like.. */ - return MSN_SOAP_OK; -} - -static int msn_soap_ab_contact_del_free_data(struct msn_soap_req_data *soap_req) -{ - g_free(soap_req->data); - return 0; -} - -int msn_soap_ab_contact_del(struct im_connection *ic, bee_user_t *bu) -{ - struct msn_buddy_data *bd = bu->data; - - return msn_soap_start(ic, g_strdup(bd->cid), - msn_soap_ab_contact_del_build_request, - NULL, - msn_soap_ab_contact_del_handle_response, - msn_soap_ab_contact_del_free_data); -} - - - -/* Storage stuff: Fetch profile. */ -static int msn_soap_profile_get_build_request(struct msn_soap_req_data *soap_req) -{ - struct msn_data *md = soap_req->ic->proto_data; - - soap_req->url = g_strdup(SOAP_STORAGE_URL); - soap_req->action = g_strdup(SOAP_PROFILE_GET_ACTION); - soap_req->payload = g_markup_printf_escaped(SOAP_PROFILE_GET_PAYLOAD, - md->tokens[3], (char *) soap_req->data); - - return 1; -} - -static xt_status msn_soap_profile_get_result(struct xt_node *node, gpointer data) -{ - struct msn_soap_req_data *soap_req = data; - struct im_connection *ic = soap_req->ic; - struct msn_data *md = soap_req->ic->proto_data; - struct xt_node *dn; - - if ((dn = xt_find_node(node->children, "DisplayName")) && dn->text) { - set_t *set = set_find(&ic->acc->set, "display_name"); - g_free(set->value); - set->value = g_strdup(dn->text); - - md->flags |= MSN_GOT_PROFILE_DN; - } - - return XT_HANDLED; -} - -static xt_status msn_soap_profile_get_rid(struct xt_node *node, gpointer data) -{ - struct msn_soap_req_data *soap_req = data; - struct msn_data *md = soap_req->ic->proto_data; - - g_free(md->profile_rid); - md->profile_rid = g_strdup(node->text); - - return XT_HANDLED; -} - -static const struct xt_handler_entry msn_soap_profile_get_parser[] = { - { "ExpressionProfile", "GetProfileResult", msn_soap_profile_get_result }, - { "ResourceID", "GetProfileResult", msn_soap_profile_get_rid }, - { NULL, NULL, NULL } -}; - -static int msn_soap_profile_get_handle_response(struct msn_soap_req_data *soap_req) -{ - struct msn_data *md = soap_req->ic->proto_data; - - md->flags |= MSN_GOT_PROFILE; - msn_ns_finish_login(soap_req->ic); - - return MSN_SOAP_OK; -} - -static int msn_soap_profile_get_free_data(struct msn_soap_req_data *soap_req) -{ - g_free(soap_req->data); - return 0; -} - -int msn_soap_profile_get(struct im_connection *ic, const char *cid) -{ - return msn_soap_start(ic, g_strdup(cid), - msn_soap_profile_get_build_request, - msn_soap_profile_get_parser, - msn_soap_profile_get_handle_response, - msn_soap_profile_get_free_data); -} - -/* Update profile (display name). */ -static int msn_soap_profile_set_dn_build_request(struct msn_soap_req_data *soap_req) -{ - struct msn_data *md = soap_req->ic->proto_data; - - soap_req->url = g_strdup(SOAP_STORAGE_URL); - soap_req->action = g_strdup(SOAP_PROFILE_SET_DN_ACTION); - soap_req->payload = g_markup_printf_escaped(SOAP_PROFILE_SET_DN_PAYLOAD, - md->tokens[3], md->profile_rid, (char *) soap_req->data); - - return 1; -} - -static const struct xt_handler_entry msn_soap_profile_set_dn_parser[] = { - { NULL, NULL, NULL } -}; - -static int msn_soap_profile_set_dn_handle_response(struct msn_soap_req_data *soap_req) -{ - return MSN_SOAP_OK; -} - -static int msn_soap_profile_set_dn_free_data(struct msn_soap_req_data *soap_req) -{ - g_free(soap_req->data); - return 0; -} - -int msn_soap_profile_set_dn(struct im_connection *ic, const char *dn) -{ - return msn_soap_start(ic, g_strdup(dn), - msn_soap_profile_set_dn_build_request, - msn_soap_profile_set_dn_parser, - msn_soap_profile_set_dn_handle_response, - msn_soap_profile_set_dn_free_data); -} diff --git a/protocols/msn/soap.h b/protocols/msn/soap.h deleted file mode 100644 index 27cfa0cb..00000000 --- a/protocols/msn/soap.h +++ /dev/null @@ -1,341 +0,0 @@ -/********************************************************************\ - * BitlBee -- An IRC to other IM-networks gateway * - * * - * Copyright 2002-2012 Wilmer van der Gaast and others * - \********************************************************************/ - -/* MSN module - All the SOAPy XML stuff. - Some manager at Microsoft apparently thought MSNP wasn't XMLy enough so - someone stepped up and changed that. This is the result. Kilobytes and - more kilobytes of XML vomit to transfer tiny bits of informaiton. */ - -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License with - the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; - if not, write to the Free Software Foundation, Inc., 51 Franklin St., - Fifth Floor, Boston, MA 02110-1301 USA -*/ - -/* Thanks to http://msnpiki.msnfanatic.com/ for lots of info on this! */ - -#ifndef __SOAP_H__ -#define __SOAP_H__ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <unistd.h> -#include "nogaim.h" - - -int msn_soapq_flush(struct im_connection *ic, gboolean resend); - - -#define SOAP_HTTP_REQUEST \ - "POST %s HTTP/1.0\r\n" \ - "Host: %s\r\n" \ - "Accept: */*\r\n" \ - "User-Agent: BitlBee " BITLBEE_VERSION "\r\n" \ - "Content-Type: text/xml; charset=utf-8\r\n" \ - "%s" \ - "Content-Length: %zd\r\n" \ - "Cache-Control: no-cache\r\n" \ - "\r\n" \ - "%s" - - -#define SOAP_PASSPORT_SSO_URL "https://login.live.com/RST.srf" -#define SOAP_PASSPORT_SSO_URL_MSN "https://msnia.login.live.com/pp900/RST.srf" - -#define SOAP_PASSPORT_SSO_PAYLOAD \ - "<Envelope xmlns=\"http://schemas.xmlsoap.org/soap/envelope/\" " \ - "xmlns:wsse=\"http://schemas.xmlsoap.org/ws/2003/06/secext\" " \ - "xmlns:saml=\"urn:oasis:names:tc:SAML:1.0:assertion\" " \ - "xmlns:wsp=\"http://schemas.xmlsoap.org/ws/2002/12/policy\" " \ - "xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\" " \ - "xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/03/addressing\" " \ - "xmlns:wssc=\"http://schemas.xmlsoap.org/ws/2004/04/sc\" " \ - "xmlns:wst=\"http://schemas.xmlsoap.org/ws/2004/04/trust\">" \ - "<Header>" \ - "<ps:AuthInfo " \ - "xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\" " \ - "Id=\"PPAuthInfo\">" \ - "<ps:HostingApp>{7108E71A-9926-4FCB-BCC9-9A9D3F32E423}</ps:HostingApp>" \ - "<ps:BinaryVersion>4</ps:BinaryVersion>" \ - "<ps:UIVersion>1</ps:UIVersion>" \ - "<ps:Cookies></ps:Cookies>" \ - "<ps:RequestParams>AQAAAAIAAABsYwQAAAAxMDMz</ps:RequestParams>" \ - "</ps:AuthInfo>" \ - "<wsse:Security>" \ - "<wsse:UsernameToken Id=\"user\">" \ - "<wsse:Username>%s</wsse:Username>" \ - "<wsse:Password>%s</wsse:Password>" \ - "</wsse:UsernameToken>" \ - "</wsse:Security>" \ - "</Header>" \ - "<Body>" \ - "<ps:RequestMultipleSecurityTokens " \ - "xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\" " \ - "Id=\"RSTS\">" \ - "<wst:RequestSecurityToken Id=\"RST0\">" \ - "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>" \ - "<wsp:AppliesTo>" \ - "<wsa:EndpointReference>" \ - "<wsa:Address>http://Passport.NET/tb</wsa:Address>" \ - "</wsa:EndpointReference>" \ - "</wsp:AppliesTo>" \ - "</wst:RequestSecurityToken>" \ - "<wst:RequestSecurityToken Id=\"RST1\">" \ - "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>" \ - "<wsp:AppliesTo>" \ - "<wsa:EndpointReference>" \ - "<wsa:Address>messengerclear.live.com</wsa:Address>" \ - "</wsa:EndpointReference>" \ - "</wsp:AppliesTo>" \ - "<wsse:PolicyReference URI=\"%s\"></wsse:PolicyReference>" \ - "</wst:RequestSecurityToken>" \ - "<wst:RequestSecurityToken Id=\"RST2\">" \ - "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>" \ - "<wsp:AppliesTo>" \ - "<wsa:EndpointReference>" \ - "<wsa:Address>contacts.msn.com</wsa:Address>" \ - "</wsa:EndpointReference>" \ - "</wsp:AppliesTo>" \ - "<wsse:PolicyReference xmlns=\"http://schemas.xmlsoap.org/ws/2003/06/secext\" URI=\"MBI\"></wsse:PolicyReference>" \ - "</wst:RequestSecurityToken>" \ - "<wst:RequestSecurityToken Id=\"RST3\">" \ - "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>" \ - "<wsp:AppliesTo>" \ - "<wsa:EndpointReference>" \ - "<wsa:Address>messengersecure.live.com</wsa:Address>" \ - "</wsa:EndpointReference>" \ - "</wsp:AppliesTo>" \ - "<wsse:PolicyReference xmlns=\"http://schemas.xmlsoap.org/ws/2003/06/secext\" URI=\"MBI_SSL\"></wsse:PolicyReference>" \ - "</wst:RequestSecurityToken>" \ - "<wst:RequestSecurityToken Id=\"RST4\">" \ - "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>" \ - "<wsp:AppliesTo>" \ - "<wsa:EndpointReference>" \ - "<wsa:Address>storage.msn.com</wsa:Address>" \ - "</wsa:EndpointReference>" \ - "</wsp:AppliesTo>" \ - "<wsse:PolicyReference xmlns=\"http://schemas.xmlsoap.org/ws/2003/06/secext\" URI=\"MBI_SSL\"></wsse:PolicyReference>" \ - "</wst:RequestSecurityToken>" \ - "</ps:RequestMultipleSecurityTokens>" \ - "</Body>" \ - "</Envelope>" - -int msn_soap_passport_sso_request(struct im_connection *ic, const char *nonce); - - -#define SOAP_ABSERVICE_PAYLOAD \ - "<?xml version=\"1.0\" encoding=\"utf-8\"?>" \ - "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" \ - "<soap:Header xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" \ - "<ABApplicationHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">" \ - "<ApplicationId xmlns=\"http://www.msn.com/webservices/AddressBook\">F6D2794D-501F-443A-ADBE-8F1490FF30FD</ApplicationId>" \ - "<IsMigration xmlns=\"http://www.msn.com/webservices/AddressBook\">false</IsMigration>" \ - "<PartnerScenario xmlns=\"http://www.msn.com/webservices/AddressBook\">%s</PartnerScenario>" \ - "</ABApplicationHeader>" \ - "<ABAuthHeader xmlns=\"http://www.msn.com/webservices/AddressBook\">" \ - "<ManagedGroupRequest xmlns=\"http://www.msn.com/webservices/AddressBook\">false</ManagedGroupRequest>" \ - "<TicketToken>%s</TicketToken>" \ - "</ABAuthHeader>" \ - "</soap:Header>" \ - "<soap:Body xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" \ - "%%s" \ - "</soap:Body>" \ - "</soap:Envelope>" - -#define SOAP_MEMLIST_URL "http://contacts.msn.com/abservice/SharingService.asmx" -#define SOAP_MEMLIST_ACTION "http://www.msn.com/webservices/AddressBook/FindMembership" - -#define SOAP_MEMLIST_PAYLOAD \ - "<FindMembership xmlns=\"http://www.msn.com/webservices/AddressBook\"><serviceFilter><Types><ServiceType>Messenger</ServiceType><ServiceType>IMAvailability</ServiceType></Types></serviceFilter><expandMembership>true</expandMembership>" \ - "</FindMembership>" - -#define SOAP_MEMLIST_ADD_ACTION "http://www.msn.com/webservices/AddressBook/AddMember" -#define SOAP_MEMLIST_DEL_ACTION "http://www.msn.com/webservices/AddressBook/DeleteMember" - -#define SOAP_MEMLIST_EDIT_PAYLOAD \ - "<%sMember xmlns=\"http://www.msn.com/webservices/AddressBook\">" \ - "<serviceHandle>" \ - "<Id>0</Id>" \ - "<Type>Messenger</Type>" \ - "<ForeignId></ForeignId>" \ - "</serviceHandle>" \ - "<memberships>" \ - "<Membership>" \ - "<MemberRole>%s</MemberRole>" \ - "<Members>" \ - "<Member xsi:type=\"PassportMember\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">" \ - "<Type>Passport</Type>" \ - "<State>Accepted</State>" \ - "<PassportName>%s</PassportName>" \ - "</Member>" \ - "</Members>" \ - "</Membership>" \ - "</memberships>" \ - "</%sMember>" - -int msn_soap_memlist_request(struct im_connection *ic); -int msn_soap_memlist_edit(struct im_connection *ic, const char *handle, gboolean add, int list); - - -#define SOAP_ADDRESSBOOK_URL "http://contacts.msn.com/abservice/abservice.asmx" -#define SOAP_ADDRESSBOOK_ACTION "http://www.msn.com/webservices/AddressBook/ABFindAll" - -#define SOAP_ADDRESSBOOK_PAYLOAD \ - "<ABFindAll xmlns=\"http://www.msn.com/webservices/AddressBook\">" \ - "<abId>00000000-0000-0000-0000-000000000000</abId>" \ - "<abView>Full</abView>" \ - "<deltasOnly>false</deltasOnly>" \ - "<lastChange>0001-01-01T00:00:00.0000000-08:00</lastChange>" \ - "</ABFindAll>" - -#define SOAP_AB_NAMECHANGE_ACTION "http://www.msn.com/webservices/AddressBook/ABContactUpdate" - -#define SOAP_AB_NAMECHANGE_PAYLOAD \ - "<ABContactUpdate xmlns=\"http://www.msn.com/webservices/AddressBook\">" \ - "<abId>00000000-0000-0000-0000-000000000000</abId>" \ - "<contacts>" \ - "<Contact xmlns=\"http://www.msn.com/webservices/AddressBook\">" \ - "<contactInfo>" \ - "<contactType>Me</contactType>" \ - "<displayName>%s</displayName>" \ - "</contactInfo>" \ - "<propertiesChanged>DisplayName</propertiesChanged>" \ - "</Contact>" \ - "</contacts>" \ - "</ABContactUpdate>" - -#define SOAP_AB_CONTACT_ADD_ACTION "http://www.msn.com/webservices/AddressBook/ABContactAdd" - -#define SOAP_AB_CONTACT_ADD_PAYLOAD \ - "<ABContactAdd xmlns=\"http://www.msn.com/webservices/AddressBook\">" \ - "<abId>00000000-0000-0000-0000-000000000000</abId>" \ - "<contacts>" \ - "<Contact xmlns=\"http://www.msn.com/webservices/AddressBook\">" \ - "<contactInfo>" \ - "<contactType>LivePending</contactType>" \ - "<passportName>%s</passportName>" \ - "<isMessengerUser>true</isMessengerUser>" \ - "<MessengerMemberInfo>" \ - "<DisplayName>%s</DisplayName>" \ - "</MessengerMemberInfo>" \ - "</contactInfo>" \ - "</Contact>" \ - "</contacts>" \ - "<options>" \ - "<EnableAllowListManagement>true</EnableAllowListManagement>" \ - "</options>" \ - "</ABContactAdd>" - -#define SOAP_AB_CONTACT_DEL_ACTION "http://www.msn.com/webservices/AddressBook/ABContactDelete" - -#define SOAP_AB_CONTACT_DEL_PAYLOAD \ - "<ABContactDelete xmlns=\"http://www.msn.com/webservices/AddressBook\">" \ - "<abId>00000000-0000-0000-0000-000000000000</abId>" \ - "<contacts>" \ - "<Contact xmlns=\"http://www.msn.com/webservices/AddressBook\">" \ - "<contactId>%s</contactId>" \ - "</Contact>" \ - "</contacts>" \ - "</ABContactDelete>" - -int msn_soap_addressbook_request(struct im_connection *ic); -int msn_soap_addressbook_set_display_name(struct im_connection *ic, const char *new); -int msn_soap_ab_contact_add(struct im_connection *ic, bee_user_t *bu); -int msn_soap_ab_contact_del(struct im_connection *ic, bee_user_t *bu); - - -#define SOAP_STORAGE_URL "https://storage.msn.com/storageservice/SchematizedStore.asmx" -#define SOAP_PROFILE_GET_ACTION "http://www.msn.com/webservices/storage/w10/GetProfile" -#define SOAP_PROFILE_SET_DN_ACTION "http://www.msn.com/webservices/storage/w10/UpdateProfile" - -#define SOAP_PROFILE_GET_PAYLOAD \ - "<?xml version=\"1.0\" encoding=\"utf-8\"?>" \ - "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" \ - "<soap:Header xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" \ - "<StorageApplicationHeader xmlns=\"http://www.msn.com/webservices/storage/w10\">" \ - "<ApplicationID>Messenger Client 9.0</ApplicationID>" \ - "<Scenario>Initial</Scenario>" \ - "</StorageApplicationHeader>" \ - "<StorageUserHeader xmlns=\"http://www.msn.com/webservices/storage/w10\">" \ - "<Puid>0</Puid>" \ - "<TicketToken>%s</TicketToken>" \ - "</StorageUserHeader>" \ - "</soap:Header>" \ - "<soap:Body xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" \ - "<GetProfile xmlns=\"http://www.msn.com/webservices/storage/w10\">" \ - "<profileHandle>" \ - "<Alias>" \ - "<Name>%s</Name>" \ - "<NameSpace>MyCidStuff</NameSpace>" \ - "</Alias>" \ - "<RelationshipName>MyProfile</RelationshipName>" \ - "</profileHandle>" \ - "<profileAttributes>" \ - "<ResourceID>true</ResourceID>" \ - "<DateModified>true</DateModified>" \ - "<ExpressionProfileAttributes>" \ - "<ResourceID>true</ResourceID>" \ - "<DateModified>true</DateModified>" \ - "<DisplayName>true</DisplayName>" \ - "<DisplayNameLastModified>true</DisplayNameLastModified>" \ - "<PersonalStatus>true</PersonalStatus>" \ - "<PersonalStatusLastModified>true</PersonalStatusLastModified>" \ - "<StaticUserTilePublicURL>true</StaticUserTilePublicURL>" \ - "<Photo>true</Photo>" \ - "<Flags>true</Flags>" \ - "</ExpressionProfileAttributes>" \ - "</profileAttributes>" \ - "</GetProfile>" \ - "</soap:Body>" \ - "</soap:Envelope>" - -#define SOAP_PROFILE_SET_DN_PAYLOAD \ - "<?xml version=\"1.0\" encoding=\"utf-8\"?>" \ - "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" \ - "<soap:Header xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" \ - "<StorageApplicationHeader xmlns=\"http://www.msn.com/webservices/storage/w10\">" \ - "<ApplicationID>Messenger Client 9.0</ApplicationID>" \ - "<Scenario>Initial</Scenario>" \ - "</StorageApplicationHeader>" \ - "<StorageUserHeader xmlns=\"http://www.msn.com/webservices/storage/w10\">" \ - "<Puid>0</Puid>" \ - "<TicketToken>%s</TicketToken>" \ - "</StorageUserHeader>" \ - "</soap:Header>" \ - "<soap:Body xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" \ - "<UpdateProfile xmlns=\"http://www.msn.com/webservices/storage/w10\">" \ - "<profile>" \ - "<ResourceID>%s</ResourceID>" \ - "<ExpressionProfile>" \ - "<FreeText>Update</FreeText>" \ - "<DisplayName>%s</DisplayName>" \ - "<Flags>0</Flags>" \ - "</ExpressionProfile>" \ - "</profile>" \ - "</UpdateProfile>" \ - "</soap:Body>" \ - "</soap:Envelope>" - -int msn_soap_profile_get(struct im_connection *ic, const char *cid); -int msn_soap_profile_set_dn(struct im_connection *ic, const char *dn); - -#endif /* __SOAP_H__ */ diff --git a/protocols/msn/tables.c b/protocols/msn/tables.c deleted file mode 100644 index 712116e5..00000000 --- a/protocols/msn/tables.c +++ /dev/null @@ -1,162 +0,0 @@ -/********************************************************************\ - * BitlBee -- An IRC to other IM-networks gateway * - * * - * Copyright 2002-2010 Wilmer van der Gaast and others * - \********************************************************************/ - -/* MSN module - Some tables with useful data */ - -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License with - the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; - if not, write to the Free Software Foundation, Inc., 51 Franklin St., - Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include "nogaim.h" -#include "msn.h" - -const struct msn_away_state msn_away_state_list[] = -{ - { "NLN", "" }, - { "AWY", "Away" }, - { "BSY", "Busy" }, - { "IDL", "Idle" }, - { "BRB", "Be Right Back" }, - { "PHN", "On the Phone" }, - { "LUN", "Out to Lunch" }, - { "HDN", "Hidden" }, - { "", "" } -}; - -const struct msn_away_state *msn_away_state_by_code(char *code) -{ - int i; - - for (i = 0; *msn_away_state_list[i].code; i++) { - if (g_strcasecmp(msn_away_state_list[i].code, code) == 0) { - return(msn_away_state_list + i); - } - } - - return NULL; -} - -const struct msn_away_state *msn_away_state_by_name(char *name) -{ - int i; - - for (i = 0; *msn_away_state_list[i].code; i++) { - if (g_strcasecmp(msn_away_state_list[i].name, name) == 0) { - return(msn_away_state_list + i); - } - } - - return NULL; -} - -const struct msn_status_code msn_status_code_list[] = -{ - { 200, "Invalid syntax", 0 }, - { 201, "Invalid parameter", 0 }, - { 205, "Invalid (non-existent) handle", 0 }, - { 206, "Domain name missing", 0 }, - { 207, "Already logged in", 0 }, - { 208, "Invalid handle", 0 }, - { 209, "Forbidden nickname", 0 }, - { 210, "Buddy list too long", 0 }, - { 215, "Handle is already in list", 0 }, - { 216, "Handle is not in list", 0 }, - { 217, "Person is off-line or non-existent", 0 }, - { 218, "Already in that mode", 0 }, - { 219, "Handle is already in opposite list", 0 }, - { 223, "Too many groups", 0 }, - { 224, "Invalid group or already in list", 0 }, - { 225, "Handle is not in that group", 0 }, - { 229, "Group name too long", 0 }, - { 230, "Cannot remove that group", 0 }, - { 231, "Invalid group", 0 }, - { 240, "ADL/RML command with corrupted payload", STATUS_FATAL }, - { 241, "ADL/RML command with invalid modification", 0 }, - { 280, "Switchboard failed", STATUS_SB_FATAL }, - { 281, "Transfer to switchboard failed", 0 }, - - { 300, "Required field missing", 0 }, - { 302, "Not logged in", 0 }, - - { 500, "Internal server error/Account banned", STATUS_FATAL }, - { 501, "Database server error", STATUS_FATAL }, - { 502, "Command disabled", 0 }, - { 510, "File operation failed", STATUS_FATAL }, - { 520, "Memory allocation failed", STATUS_FATAL }, - { 540, "Challenge response invalid", STATUS_FATAL }, - - { 600, "Server is busy", STATUS_FATAL }, - { 601, "Server is unavailable", STATUS_FATAL }, - { 602, "Peer nameserver is down", STATUS_FATAL }, - { 603, "Database connection failed", STATUS_FATAL }, - { 604, "Server is going down", STATUS_FATAL }, - { 605, "Server is unavailable", STATUS_FATAL }, - - { 700, "Could not create connection", STATUS_FATAL }, - { 710, "Invalid CVR parameters", STATUS_FATAL }, - { 711, "Write is blocking", STATUS_FATAL }, - { 712, "Session is overloaded", STATUS_FATAL }, - { 713, "Calling too rapidly", 0 }, - { 714, "Too many sessions", STATUS_FATAL }, - { 715, "Not expected/Invalid argument/action", 0 }, - { 717, "Bad friend file", STATUS_FATAL }, - { 731, "Not expected/Invalid argument", 0 }, - - { 800, "Changing too rapidly", 0 }, - - { 910, "Server is busy", STATUS_FATAL }, - { 911, "Authentication failed", STATUS_SB_FATAL | STATUS_FATAL }, - { 912, "Server is busy", STATUS_FATAL }, - { 913, "Not allowed when hiding", 0 }, - { 914, "Server is unavailable", STATUS_FATAL }, - { 915, "Server is unavailable", STATUS_FATAL }, - { 916, "Server is unavailable", STATUS_FATAL }, - { 917, "Authentication failed", STATUS_FATAL }, - { 918, "Server is busy", STATUS_FATAL }, - { 919, "Server is busy", STATUS_FATAL }, - { 920, "Not accepting new principals", 0 }, /* When a sb is full? */ - { 922, "Server is busy", STATUS_FATAL }, - { 923, "Kids Passport without parental consent", STATUS_FATAL }, - { 924, "Passport account not yet verified", STATUS_FATAL }, - { 928, "Bad ticket", STATUS_FATAL }, - { -1, NULL, 0 } -}; - -const struct msn_status_code *msn_status_by_number(int number) -{ - static struct msn_status_code *unknown = NULL; - int i; - - for (i = 0; msn_status_code_list[i].number >= 0; i++) { - if (msn_status_code_list[i].number == number) { - return(msn_status_code_list + i); - } - } - - if (unknown == NULL) { - unknown = g_new0(struct msn_status_code, 1); - unknown->text = g_new0(char, 128); - } - - unknown->number = number; - unknown->flags = 0; - g_snprintf(unknown->text, 128, "Unknown error (%d)", number); - - return(unknown); -} diff --git a/protocols/nogaim.c b/protocols/nogaim.c index 2937bdcc..716dae9b 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -253,16 +253,11 @@ char *explain_unknown_protocol(const char *name) void nogaim_init() { - extern void msn_initmodule(); extern void oscar_initmodule(); extern void jabber_initmodule(); extern void twitter_initmodule(); extern void purple_initmodule(); -#ifdef WITH_MSN - msn_initmodule(); -#endif - #ifdef WITH_OSCAR oscar_initmodule(); #endif diff --git a/protocols/oscar/aim.h b/protocols/oscar/aim.h index fa1f884e..d8221b51 100644 --- a/protocols/oscar/aim.h +++ b/protocols/oscar/aim.h @@ -364,7 +364,6 @@ typedef struct aim_session_s { /* Values for sess->flags */ #define AIM_SESS_FLAGS_SNACLOGIN 0x00000001 -#define AIM_SESS_FLAGS_XORLOGIN 0x00000002 #define AIM_SESS_FLAGS_NONBLOCKCONNECT 0x00000004 #define AIM_SESS_FLAGS_DONTTIMEOUTONICBM 0x00000008 diff --git a/protocols/oscar/auth.c b/protocols/oscar/auth.c index e4f624c0..d54d483b 100644 --- a/protocols/oscar/auth.c +++ b/protocols/oscar/auth.c @@ -7,8 +7,6 @@ #include "md5.h" -static int aim_encode_password(const char *password, unsigned char *encoded); - /* * This just pushes the passed cookie onto the passed connection, without * the SNAC header or any of that. @@ -60,56 +58,6 @@ int aim_sendflapver(aim_session_t *sess, aim_conn_t *conn) } /* - * This is a bit confusing. - * - * Normal SNAC login goes like this: - * - connect - * - server sends flap version - * - client sends flap version - * - client sends screen name (17/6) - * - server sends hash key (17/7) - * - client sends auth request (17/2 -- aim_send_login) - * - server yells - * - * XOR login (for ICQ) goes like this: - * - connect - * - server sends flap version - * - client sends auth request which contains flap version (aim_send_login) - * - server yells - * - * For the client API, we make them implement the most complicated version, - * and for the simpler version, we fake it and make it look like the more - * complicated process. - * - * This is done by giving the client a faked key, just so we can convince - * them to call aim_send_login right away, which will detect the session - * flag that says this is XOR login and ignore the key, sending an ICQ - * login request instead of the normal SNAC one. - * - * As soon as AOL makes ICQ log in the same way as AIM, this is /gone/. - * - * XXX This may cause problems if the client relies on callbacks only - * being called from the context of aim_rxdispatch()... - * - */ -static int goddamnicq(aim_session_t *sess, aim_conn_t *conn, const char *sn) -{ - aim_frame_t fr; - aim_rxcallback_t userfunc; - - sess->flags &= ~AIM_SESS_FLAGS_SNACLOGIN; - sess->flags |= AIM_SESS_FLAGS_XORLOGIN; - - fr.conn = conn; - - if ((userfunc = aim_callhandler(sess, conn, 0x0017, 0x0007))) { - userfunc(sess, &fr, ""); - } - - return 0; -} - -/* * In AIM 3.5 protocol, the first stage of login is to request login from the * Authorizer, passing it the screen name for verification. If the name is * invalid, a 0017/0003 is spit back, with the standard error contents. If @@ -122,16 +70,11 @@ int aim_request_login(aim_session_t *sess, aim_conn_t *conn, const char *sn) aim_frame_t *fr; aim_snacid_t snacid; aim_tlvlist_t *tl = NULL; - struct im_connection *ic = sess->aux_data; if (!sess || !conn || !sn) { return -EINVAL; } - if (g_ascii_isdigit(sn[0]) && set_getbool(&ic->acc->set, "old_icq_auth")) { - return goddamnicq(sess, conn, sn); - } - sess->flags |= AIM_SESS_FLAGS_SNACLOGIN; aim_sendflapver(sess, conn); @@ -153,52 +96,6 @@ int aim_request_login(aim_session_t *sess, aim_conn_t *conn, const char *sn) } /* - * Part two of the ICQ hack. Note the ignoring of the key and clientinfo. - */ -static int goddamnicq2(aim_session_t *sess, aim_conn_t *conn, const char *sn, const char *password) -{ - static const char clientstr[] = { "ICQ Inc. - Product of ICQ (TM) 2001b.5.17.1.3642.85" }; - static const char lang[] = { "en" }; - static const char country[] = { "us" }; - aim_frame_t *fr; - aim_tlvlist_t *tl = NULL; - guint8 *password_encoded; - - if (!(password_encoded = (guint8 *) g_malloc(strlen(password)))) { - return -ENOMEM; - } - - if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x01, 1152))) { - g_free(password_encoded); - return -ENOMEM; - } - - aim_encode_password(password, password_encoded); - - aimbs_put32(&fr->data, 0x00000001); - aim_addtlvtochain_raw(&tl, 0x0001, strlen(sn), (guint8 *) sn); - aim_addtlvtochain_raw(&tl, 0x0002, strlen(password), password_encoded); - aim_addtlvtochain_raw(&tl, 0x0003, strlen(clientstr), (guint8 *) clientstr); - aim_addtlvtochain16(&tl, 0x0016, 0x010a); /* cliend ID */ - aim_addtlvtochain16(&tl, 0x0017, 0x0005); /* major version */ - aim_addtlvtochain16(&tl, 0x0018, 0x0011); /* minor version */ - aim_addtlvtochain16(&tl, 0x0019, 0x0001); /* point version */ - aim_addtlvtochain16(&tl, 0x001a, 0x0e3a); /* build */ - aim_addtlvtochain32(&tl, 0x0014, 0x00000055); /* distribution chan */ - aim_addtlvtochain_raw(&tl, 0x000f, strlen(lang), (guint8 *) lang); - aim_addtlvtochain_raw(&tl, 0x000e, strlen(country), (guint8 *) country); - - aim_writetlvchain(&fr->data, &tl); - - g_free(password_encoded); - aim_freetlvchain(&tl); - - aim_tx_enqueue(sess, fr); - - return 0; -} - -/* * send_login(int socket, char *sn, char *password) * * This is the initial login request packet. @@ -279,16 +176,6 @@ int aim_send_login(aim_session_t *sess, aim_conn_t *conn, const char *sn, const return -EINVAL; } - /* - * What the XORLOGIN flag _really_ means is that its an ICQ login, - * which is really stupid and painful, so its not done here. - * - */ - if (sess->flags & AIM_SESS_FLAGS_XORLOGIN) { - return goddamnicq2(sess, conn, sn, password); - } - - if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 1152))) { return -ENOMEM; } @@ -344,41 +231,6 @@ int aim_encode_password_md5(const char *password, const char *key, guint8 *diges return 0; } -/** - * aim_encode_password - Encode a password using old XOR method - * @password: incoming password - * @encoded: buffer to put encoded password - * - * This takes a const pointer to a (null terminated) string - * containing the unencoded password. It also gets passed - * an already allocated buffer to store the encoded password. - * This buffer should be the exact length of the password without - * the null. The encoded password buffer /is not %NULL terminated/. - * - * The encoding_table seems to be a fixed set of values. We'll - * hope it doesn't change over time! - * - * This is only used for the XOR method, not the better MD5 method. - * - */ -static int aim_encode_password(const char *password, guint8 *encoded) -{ - guint8 encoding_table[] = { - /* v2.1 table, also works for ICQ */ - 0xf3, 0x26, 0x81, 0xc4, - 0x39, 0x86, 0xdb, 0x92, - 0x71, 0xa3, 0xb9, 0xe6, - 0x53, 0x7a, 0x95, 0x7c - }; - int i; - - for (i = 0; i < strlen(password); i++) { - encoded[i] = (password[i] ^ encoding_table[i]); - } - - return 0; -} - /* * This is sent back as a general response to the login command. * It can be either an error or a success, depending on the diff --git a/protocols/oscar/conn.c b/protocols/oscar/conn.c index 3e84f1a4..aaee71de 100644 --- a/protocols/oscar/conn.c +++ b/protocols/oscar/conn.c @@ -474,13 +474,7 @@ void aim_session_init(aim_session_t *sess, guint32 flags, int debuglevel) sess->emailinfo = NULL; sess->oft_info = NULL; - - /* - * Default to SNAC login unless XORLOGIN is explicitly set. - */ - if (!(flags & AIM_SESS_FLAGS_XORLOGIN)) { - sess->flags |= AIM_SESS_FLAGS_SNACLOGIN; - } + sess->flags |= AIM_SESS_FLAGS_SNACLOGIN; sess->flags |= flags; /* diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c index f86f8bcb..55cdd2e9 100644 --- a/protocols/oscar/oscar.c +++ b/protocols/oscar/oscar.c @@ -384,7 +384,6 @@ static void oscar_init(account_t *acc) if (icq) { set_add(&acc->set, "ignore_auth_requests", "false", set_eval_bool, acc); - set_add(&acc->set, "old_icq_auth", "false", set_eval_bool, acc); } s = set_add(&acc->set, "server", diff --git a/protocols/purple/purple.c b/protocols/purple/purple.c index 25cd00cf..6204614d 100644 --- a/protocols/purple/purple.c +++ b/protocols/purple/purple.c @@ -30,6 +30,10 @@ #include <glib.h> #include <purple.h> +#if !PURPLE_VERSION_CHECK(2, 12, 0) +#define PURPLE_MESSAGE_REMOTE_SEND 0x10000 +#endif + GSList *purple_connections; /* This makes me VERY sad... :-( But some libpurple callbacks come in without @@ -1217,7 +1221,10 @@ static void handle_conv_msg(PurpleConversation *conv, const char *who, const cha * Those are safe to display. The rest (with just _SEND) may be echoes. */ static void prplcb_conv_msg(PurpleConversation *conv, const char *who, const char *message, PurpleMessageFlags flags, time_t mtime) { - if ((!(flags & PURPLE_MESSAGE_SEND)) || (flags & PURPLE_MESSAGE_DELAYED)) { + if ((!(flags & PURPLE_MESSAGE_SEND)) || + (flags & PURPLE_MESSAGE_DELAYED) || + (flags & PURPLE_MESSAGE_REMOTE_SEND) + ) { handle_conv_msg(conv, who, message, (flags & PURPLE_MESSAGE_SEND) ? OPT_SELFMESSAGE : 0, mtime); } } diff --git a/protocols/skype/.bzrignore b/protocols/skype/.bzrignore deleted file mode 100644 index e90a033b..00000000 --- a/protocols/skype/.bzrignore +++ /dev/null @@ -1,19 +0,0 @@ -Changelog -HEADER.html -*.gz -*.asc -.htaccess -shot -*.swp -aclocal.m4 -autom4te.cache -config.log -config.mak -config.status -configure -etc -install-sh -skype.so -skyped.conf -skyped.conf.dist -skype.dylib* diff --git a/protocols/skype/HACKING b/protocols/skype/HACKING deleted file mode 100644 index 935856a7..00000000 --- a/protocols/skype/HACKING +++ /dev/null @@ -1,80 +0,0 @@ -== Tabs - -I use the following tabs during the development: - -1) bitlbee-skype: - -vim, make, etc. - -2) bitlbee: - -gdb --args ./bitlbee -v -n -D -run - -3) skyped: - -python skyped.py -n -d - -4) irssi - - -== Tests - -The plugin is tested with a mocked IRC client and a mocked skyped. - -=== Requirements - -Python pexpect module is required to run the tests. - -To run tests with bitlbee built in a development tree and not (the one) -installed in the system (e.g. /usr), make sure to specify --plugindir= option to -./configure script during the build process: - -bitlbee% ./configure --skype=1 --plugindir="$(realpath .)" - -Otherwise bitlbee will try to load skype.so (among other things) from /usr/lib, -which is probably not what you want to test, or produce "Unknown protocol" -error. - -=== Running - -Tests can be run by running test.py script in this ("protocols/skype") -directory. - -For more control over how/which tests are being run from there, use "python -m -unittest" command: - -bitlbee/protocols/skype% python -m unittest test -bitlbee/protocols/skype% python -m unittest -f test -bitlbee/protocols/skype% python -m unittest test.Test.testMsg - -If bitlbee crashes during tests with SIGSEGV (segmentation fault), it's likely -that there is some problem with skype.c plugin. -To get a backtrace of such crash, use: - -bitlbee/protocols/skype% ATTACH_GDB=true python -m unittest test.Test.testMsg - -Example shows running "testMsg" test with gdb attached to bitlbee, which will -produce full backtrace in "t/gdb-<pid>.log" files (see pid in pexpect error -output of the test). - -=== Adding new tests - -To add a new test, the following steps are necessary: - -1) Add a new -skyped.mock file: just do the test manually, copy&paste the -skyped output and clean it up, so Alice talks to Bob. You can test the created -mock file by starting skyped with the -m option, and testing it from an IRC -client manually. - -2) Add a new -bitlbee.mock file: do the test manually from irssi, and use: - -/connect -rawlog rawlog localhost - -Then clean up the rawlog: the input lines are parsed as matching patterns, so -boring prefix/suffix text can be left out, non-interesting lines can be -deleted. The output lines still have to be strict IRC commands, as usual. - -3) Add the new test to test.py and run it! - -// vim: ft=asciidoc diff --git a/protocols/skype/Makefile b/protocols/skype/Makefile deleted file mode 100644 index 95a134c6..00000000 --- a/protocols/skype/Makefile +++ /dev/null @@ -1,27 +0,0 @@ --include ../../Makefile.settings -ifdef _SRCDIR_ -_SRCDIR_ := $(_SRCDIR_)protocols/skype/ -endif - -DATE := $(shell date +%Y-%m-%d) -INSTALL = install - -all: -clean: - -# take this from the kernel -check: - perl checkpatch.pl --show-types --ignore LONG_LINE,CAMELCASE --no-tree --file skype.c - -test: all - ./test.py - -install-doc: - $(INSTALL) -d $(DESTDIR)$(MANDIR)/man1 - $(INSTALL) -m644 $(_SRCDIR_)skyped.1 $(DESTDIR)$(MANDIR)/man1 - -uninstall-doc: - rm -f $(DESTDIR)$(MANDIR)/man1/skyped.1* - -%.1: $(_SRCDIR_)%.txt $(_SRCDIR_)asciidoc.conf - a2x --asciidoc-opts="-f $(_SRCDIR_)asciidoc.conf" -a bee_date=$(DATE) -f manpage $< diff --git a/protocols/skype/NEWS b/protocols/skype/NEWS deleted file mode 100644 index b55b34c6..00000000 --- a/protocols/skype/NEWS +++ /dev/null @@ -1,131 +0,0 @@ -VERSION DESCRIPTION ------------------------------------------------------------------------------ -0.9.0 - merge support for building the plugin on OpenBSD - - merge support for running skyped without gobject and - pygnutls/pyopenssl - as a side effect this adds Windows support - - add /ctcp call|hangup support (you need BitlBee from bzr to use - this) - - add group support (see http://wiki.bitlbee.org/UiFix) -0.8.4 - now using python2.7 directly in case python would point to python3k - - merge patch to avoid a crash when failing to connect to skyped - - merge support for building the plugin on NetBSD - - merge Debian patches -0.8.3 - support for BitlBee 1.3dev - - fixed --debug switch (-d was fine) - - documentation fixes -0.8.2 - building documentation is now optional - - new settings: test_join and show_moods - - '~' in skyped.conf is now expanded to the user's home directory - - groupchat channel names are now persistent (requires - BitlBee-1.2.6) -0.8.1 - support for BitlBee 1.2.5 - - support for Skype 2.1.0.81 and Skype4Py 1.0.32.0 - - the plugin part now supports FreeBSD - - fix for edited messages, the prefix can now be configured -0.8.0 - fix build on x86_64 (-fPIC usage) - - debug messages now have a timestamp - - more work on having the default config under ~/.skyped - - added a manual page for skyped -0.7.2 - add --log option to skyped to allow logging while it the - daemon is in the background. - - prefer config files from ~/.skyped over /etc/skyped - - handle the case when LANG and LC_ALL env vars are empty -0.7.1 - mostly internal changes, the monster read callback is - now replaced by tiny parser functions -0.7.0 - made 'make config' more portable - - add 'skypeconsole' buddy for debugging purposes - - support autojoin for bookmarked groupchats - - skyped: make hardwired '/dev/null' portable and fix - Python-2.6 warnings -0.6.3 - various osx-specific improvements (see the new screenshot!) - - added python-gnutls install instructions - - bitlbee.pc is now searched under - /usr/local/lib/pkgconfig by default to help LFS monkeys ;) -0.6.2 - bugfix: make install required the plugin even in case - its build was disabled -0.6.1 - added keepalive traffic to avoid disconnects in bitlbee - when there is no traffic for a long time - - now the plugin or skyped is automatically disabled if - the dependencies are not available; useful in case the - plugin is to be installed on a public server, or the - skyped is to be used with a public server only -0.6.0 - works with BitlBee 1.2.1 -0.5.1 - configure now automatically detects the right prefix to - match witl BitlBee's one - - minor documentation improvements (public chats, bug - reporting address) -0.5.0 - skyped now uses gnutls if possible, which seem to be - more stable, compared to openssl. - - skyped now tries to handle all read/write errors from/to - clients, and always just warn about failures, never exit. - - installation for Debian users should be more simple - - improved documentation - - this .0 release should be quite stable, only about 100 - lines of new code -0.4.2 - skyped should be now more responsive - - new skypeout_offline setting for hiding/showing SkypeOut - contacts - - support for SkypeOut calls - - support for querying the balance from Skype - - all setting should be documented now -0.4.1 - support for building the plugin on Mac OSX - - tested with BitlBee 1.2 and Skype 2.0.0.63 - - avoid ${prefix} (by autoconf) in the config file as we - don't handle such a variable - - now you can call echo123 (patch by Riskó Gergely) -0.4.0 - support for starting, accepting and rejecting calls - - also updated documentation (the key is the account set - skype/call command) - - as usual with the .0 releases, be careful, ~200 lines of - new code -0.3.2 - support for Skype 2.0.0.43 - - skyped now automatically starts/shuts down skype - - improved 'make prepare' to handle more automake versions - - documentation improvements -0.3.1 - beautify output when skyped is interrupted using ^C - - 'nick skype foo' now really sets display name, not the mood - text - - documentation fixups - - this version should be again as stable as 0.2.6 was -0.3.0 - authentication support in skyped via ssl - - ~200 lines of new code, so be careful :) - - upgraders: please read the documentation about how to set up - your config the ssl certificate, this was no necessary till now -0.2.6 - the server setting has a default value, 'localhost' so in most - cases you no longer have to set it explicitly - - support for receiving emoted messages, ie. when the user types - '/me foo' - - support for setting the display name (nick 0 "foo bar") - it - sets the mood text -0.2.5 - now bitlbee's info command is supported (it displays full name, - birthday, homepage, age, etc.) -0.2.4 - improve documentation based on feedback from people on #bitlbee - - fixed for Skype4Py >= 0.9.28.4 - - tested with latest Skype beta, too (the one which supports - video) -0.2.3 - fixed that annoying "creating groupchat failed" warning -0.2.2 - don't change the topic if skype does not report a successful - topic change - - fixed for the recent bitlbee API changes -0.2.1 - topic support in group chats - - bugfixes for multiline messages - - this version should be again as stable as 0.1.4 was -0.2.0 - group chat support - - ~300 lines of new code, so be careful :) - - the version number mentions that this is not a minor change -0.1.4 - documentation: mention the version of all deps (requirements - section) - - fix sending / sending accents - - don't use internal functions of skype4py - - skyped no longer dies when skype is killed -0.1.3 - support for edited messages - - ignore empty messages (skype does the same) - - support for multiline messages - - switch to the x11 api instead of dbus (it's much more stable) -0.1.2 - notification when a new call arrives in - - more documentation (vnc) - - first release which works with unpatched bitlbee -0.1.1 - skyped now runs as daemon in the background by default - - skyped now automatically reconnects on Skype restarts -0.1.0 - initial release - - see README for major features diff --git a/protocols/skype/README b/protocols/skype/README deleted file mode 100644 index 021f6d20..00000000 --- a/protocols/skype/README +++ /dev/null @@ -1,359 +0,0 @@ -= Skype plugin for BitlBee -Miklos Vajna <vmiklos-at-vmiklos-dot-hu> - -== Status - -[quote, Wilmer van der Gaast (author of BitlBee)] -____ -Okay, this exists now, with lots of thanks to vmiklos for his *excellent* -work!! - -It's not in the main BitlBee and it'll never be for various reasons, but -because it's a plugin that shouldn't be a problem. -____ - -One day I browsed the BitlBee bugtracker and found -http://bugs.bitlbee.org/bitlbee/ticket/82[this] ticket. Then after a while I -returned and saw that it was still open. So I wrote it. - -It's pretty stable (one day I wanted to restart it because of an upgrade -and just noticed it was running for 2+ months without crashing), I use -it for my daily work. Being a plug-in, no patching is required, you can -just install it after installing BitlBee itself. - -NOTE: You will see that this implementation of the Skype plug-in still requires -a Skype instance to be running. This is because I'm not motivated to reverse -engineer Skype's -http://en.wikipedia.org/wiki/Skype_Protocol#Obfuscation_Layer[obfuscation -layer]. (Not mentioning that you should ask your lawyer about if it is legal or -not..) - -== Requirements - -* Skype >= 1.4.0.99. The latest version I've tested is 4.1.0.20. -* BitlBee >= 3.0. The latest version I've tested is @BITLBEE_VERSION@. Use - old versions (see the NEWS file about which one) if you have older BitlBee - installed. -* Skype4Py >= 0.9.28.7. Previous versions won't work due to API changes. - The latest version I've tested is 1.0.32.0. - -* Python >= 2.5. Skype4Py does not work with 2.4. - -* OS: `bitlbee-skype` has been tested under Linux and Mac OS X. The plugin part - has been tested under Free/Open/NetBSD as well. The daemon part has been - tested on Windows, too. - -== How to set it up - -Before you start. The setup is the following: BitlBee can't connect directly to -Skype servers (the company's ones). It needs a running Skype client to do so. -In fact BitlBee will connect to `skyped` (a tcp server, provided in this -package) and `skyped` will connect to to your Skype client. - -The benefit of this architecture is that you can run Skype and `skyped` -on a machine different to the one where you run BitlBee (it can be even -a public server) and/or your IRC client. - -NOTE: The order is important. First `skyped` starts Skype. Then `skyped` -connects to Skype, finally BitlBee can connect to `skyped`. - -=== Installing - -Either use your package manager to install the Skype plugin, using something -like: - ----- -# apt-get install skyped bitlbee-plugin-skype ----- - -Or install http://sourceforge.net/projects/skype4py/[Skype4Py], and build -BitlBee with `--skype=1`. - -=== Configuring - -See the manpage of `skyped`. - -== Setting up Skype in a VNC server (optional) - -Optionally, if you want to run Skype on a server, you might want to setup up -a `VNC` server as well. I used `tightvnc` but probably other `VNC` servers will -work, too. - -First run - ----- -$ vncpasswd ~/.vnc/passwd ----- - -and create a password. You will need it at least once. - -Now create `~/.vnc/xstartup` with the following contents: - ----- -#!/bin/sh - -blackbox ----- - -Adjust the permissions: - ----- -$ chmod +x ~/.vnc/xstartup ----- - -Then start the server: - ----- -$ vncserver ----- - -Then connect to it, start an `xterm`, set up Skype (username, password, -enable X11 API and allow the `Skype4Py` client), quit from Skype, and -start `skyped`. If you want to watch its traffic, enable debug messages -and foreground mode: - ----- -$ skyped -n -d ----- - -== Features - -- Download nicks and away statuses from Skype - -- Noticing joins / parts while we're connected - -- Sending messages - -- Receiving messages - -- Receiving away status changes - -- `skyped` (the tcp daemon that is a gateway between Skype and tcp) - -- Error handling when `skyped` is not running and when it exits - -- Marking received messages as seen so that Skype won't say there are unread messages - -- Adding / removing contacts - -- Set away state when you do a `/away`. - -- When you `account off`, Skype will set status to `Offline` - -- When you `account on`, Skype will set status to `Online` - -- Detect when somebody wants to add you and ask for confirmation - -- Detect when somebody wants to transfer a file - -- Group chat support: - - * Detect if we're invited - - * Send / receive group chat messages - - * Invite others (using `/invite <nick>`) - - * Part from group chats - - * Starting a group chat (using `/j #nick`) - -- Topic changes in group chats: - - * Show the current topic (if any) on join - - * Notice when someone changes the topic - - * Support changing the topic using `/topic` - -- Viewing the profile using the `info` command. - -- Handling skype actions (when the `CHATMESSAGE` has `EMOTED` type) - -- Setting your display name using the `nick` command. - -- Running Skype on a machine different to BitlBee is possible, the - communication is encrypted. - -- Managing outgoing calls (with call duration at the end): - - * `/ctcp nick call` - * `/ctcp nick hangup` - -- Managing outgoing SkypeOut or conference calls: - - * `account skype set call +18005551234` - * `account skype set call nick1 nick2` - * `account skype set -del call` - -- Managing incoming calls via questions, just like when you add / remove - contacts. - -- Querying the current SkypeOut balance: - - * `account skype set balance query` - -- For debug purposes, it's possible to send any command to `skyped`. To - achieve this, you need to: - - * `account skype set skypeconsole true` - - * then writing `skypeconsole: <command>` will work in the control - channel. - - * `account skype set skypeconsole_receive true` will make the - `skypeconsole` account dump all the received raw traffic for you - -- If you want to automatically join bookmarked groupchats right after - you logged in, do: - - * `account skype set auto_join true` - -- Edited messages are shown with the `EDIT:` prefix. If you don't like - this, you can set your own prefix using: - - * `account skype set edit_prefix "updated message:"` - -- The `echo123` test account is hidden by default. If you want to see it: - - * `account skype set test_join true` - -- Mood texts are not shown by default. - - * If you want to see them: `account skype set show_moods true` - * If you want to change your mood text: `account skype set mood_text 'foo bar'` - -- Group support: - - * To enable: `account skype set read_groups true` - * Skype groups are told to BitlBee - * The usual `/invite` in a group channel adds the buddy to the group in skype - as well (and if necessary, it creates a new group in Skype) - -== What needs to be done (aka. TODO) - -- Notice if foo invites bar. Currently you can see only that bar joined. - -- Public chats. See - link:https://developer.skype.com/jira/browse/SCL-381[this feature - request], this is because it is still not possible (under Linux) to - `join_chat` to a public chat.. - -- Add yasrd (Yet Another Skype-Related Daemon) to allow using a public - server for users who are behind NAT. - -== I would like to have support for ... - -If something does not work and it's not in the TODO section, then please -contact me! Please also try the bzr version before reporting a bug, your -problem may be already fixed there. - -In fact, of course, I wrote this documentation after figured out how to do this -setup, so maybe I left out some steps. If you needed 'any' additional tricks, -then it would be nice to include them here. - -== Known bugs - -- File transfers are view-only from BitlBee. Quoting the - https://developer.skype.com/Docs/ApiDoc/FILETRANSFER_object[relevant - documentation]: 'File transfers cannot be initiated nor accepted via - API commands.' So it's not something I can add support for, sadly. - -== Screenshots - -You can reach some screenshots link:shot[here]. - -== Additional resources - -The Skype API documentation is -http://developer.skype.com/resources/public_api_ref.zip[here] if you're -interested. - -== Testimonials - ----- -00:56 < scathe> I like your skype plugin :) ----- - ----- -It's really working great so far. - -Good Job and thank you! -Sebastian ----- - ----- -Big respect for your work, i really appreciate it. - -Martin ----- - ----- -Thanks for bitlbee-skype. As a blind Linux user, I cannot use the -skype GUI client because qt apps ar not accessible yet with the -available screen readers. bitlbee-skype allows me to make use of skype -without having to interact much with the GUI client, which helps me a -lot. - -Lukas ----- - ----- -02:12 < newton> i must say, i love this little bee ;) -02:15 < newton> tried it out today with the skype plugin, good work! ----- - ----- -18:10 < miCSu> it works fine ----- - ----- -13:56 < seo> i just want to thank you :) -13:56 < seo> for bitlbee-skype -13:57 < seo> it's working very well, so, again, thank you for your work, and for sharing it ----- - ----- -22:16 < ecraven> vmiklos: thanks a lot for the skype plugin for bitlbee! ----- - ----- -I'm blind and so I have to use a screen reader, in my case Gnome-Orca. -But since Skype is written in QT, while Orca uses gtk+, I have no direct -access to the Skype interface. That's why I desided to use Skyped and -Erc. -The text console is fully accessible. -Thank you very much. - -Hermann ----- - ----- -i love that bitlbeeplugin. big thx for that. - -michael ----- - ----- -23:47 < krisfremen> thanks for creating this fabulous piece of software vmiklos :) ----- - -== Thanks - -to the following people: - -* people in link:AUTHORS[AUTHORS] for their contributions - -* Arkadiusz Wahlig, author of skype4py, for making suggestions to skyped - -* Gabor Adam Toth (tg), for noticing extra code is needed to handle multiline - messages - -* Cristobal Palmer (tarheelcoxn), for helping to testing the plugin in a - timezone different to mine - -* people on `#bitlbee` for feedback - -Back to my link:/projects[projects page]. - -// vim: ft=asciidoc diff --git a/protocols/skype/asciidoc.conf b/protocols/skype/asciidoc.conf deleted file mode 100644 index f52b3ad6..00000000 --- a/protocols/skype/asciidoc.conf +++ /dev/null @@ -1,20 +0,0 @@ -ifdef::doctype-manpage[] -ifdef::backend-docbook[] -[header] -template::[header-declarations] -<refentry> - <refentryinfo> - <date>{bee_date}</date> - </refentryinfo> - <refmeta> - <refentrytitle>{mantitle}</refentrytitle> - <manvolnum>{manvolnum}</manvolnum> - <refmiscinfo class="source">BitlBee</refmiscinfo> - <refmiscinfo class="manual">BitlBee manual</refmiscinfo> - </refmeta> - <refnamediv> - <refname>{manname}</refname> - <refpurpose>{manpurpose}</refpurpose> - </refnamediv> -endif::backend-docbook[] -endif::doctype-manpage[] diff --git a/protocols/skype/client.sh b/protocols/skype/client.sh deleted file mode 100644 index 7d7689a8..00000000 --- a/protocols/skype/client.sh +++ /dev/null @@ -1 +0,0 @@ -openssl s_client -host localhost -port 2727 -verify 0 diff --git a/protocols/skype/skype.c b/protocols/skype/skype.c deleted file mode 100644 index bd8a1850..00000000 --- a/protocols/skype/skype.c +++ /dev/null @@ -1,1778 +0,0 @@ -/* - * skype.c - Skype plugin for BitlBee - * - * Copyright (c) 2007-2013 by Miklos Vajna <vmiklos@vmiklos.hu> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#define _XOPEN_SOURCE -#include <poll.h> -#include <stdio.h> -#include <bitlbee.h> -#include <ssl_client.h> - -#define SKYPE_DEFAULT_SERVER "localhost" -#define SKYPE_DEFAULT_PORT "2727" -#define IRC_LINE_SIZE 16384 -#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) - -/* - * Enumerations - */ - -enum { - SKYPE_CALL_RINGING = 1, - SKYPE_CALL_MISSED, - SKYPE_CALL_CANCELLED, - SKYPE_CALL_FINISHED, - SKYPE_CALL_REFUSED -}; - -enum { - SKYPE_FILETRANSFER_NEW = 1, - SKYPE_FILETRANSFER_TRANSFERRING, - SKYPE_FILETRANSFER_COMPLETED, - SKYPE_FILETRANSFER_FAILED -}; - -/* - * Structures - */ - -struct skype_data { - struct im_connection *ic; - char *username; - /* The effective file descriptor. We store it here so any function can - * write() to it. */ - int fd; - /* File descriptor returned by bitlbee. we store it so we know when - * we're connected and when we aren't. */ - int bfd; - /* ssl_getfd() uses this to get the file desciptor. */ - void *ssl; - /* When we receive a new message id, we query the properties, finally - * the chatname. Store the properties here so that we can use - * imcb_buddy_msg() when we got the chatname. */ - char *handle; - /* List, because of multiline messages. */ - GList *body; - char *type; - /* This is necessary because we send a notification when we get the - * handle. So we store the state here and then we can send a - * notification about the handle is in a given status. */ - int call_status; - char *call_id; - char *call_duration; - /* If the call is outgoing or not */ - int call_out; - /* Same for file transfers. */ - int filetransfer_status; - /* Path of the file being transferred. */ - char *filetransfer_path; - /* Using /j #nick we want to have a groupchat with two people. Usually - * not (default). */ - char *groupchat_with; - /* The user who invited us to the chat. */ - char *adder; - /* If we are waiting for a confirmation about we changed the topic. */ - int topic_wait; - /* These are used by the info command. */ - char *info_fullname; - char *info_phonehome; - char *info_phoneoffice; - char *info_phonemobile; - char *info_nrbuddies; - char *info_tz; - char *info_seen; - char *info_birthday; - char *info_sex; - char *info_language; - char *info_country; - char *info_province; - char *info_city; - char *info_homepage; - char *info_about; - /* When a call fails, we get the reason and later we get the failure - * event, so store the failure code here till then */ - int failurereason; - /* If this is just an update of an already received message. */ - int is_edit; - /* List of struct skype_group* */ - GList *groups; - /* Pending user which has to be added to the next group which is - * created. */ - char *pending_user; - /* If the info command was used, to determine what to do with FULLNAME result. */ - int is_info; -}; - -struct skype_away_state { - char *code; - char *full_name; -}; - -struct skype_buddy_ask_data { - struct im_connection *ic; - /* This is also used for call IDs for simplicity */ - char *handle; -}; - -struct skype_group { - int id; - char *name; - GList *users; -}; - -/* - * Tables - */ - -const struct skype_away_state skype_away_state_list[] = { - { "AWAY", "Away" }, - { "NA", "Not available" }, - { "DND", "Do Not Disturb" }, - { "INVISIBLE", "Invisible" }, - { "OFFLINE", "Offline" }, - { "SKYPEME", "Skype Me" }, - { "ONLINE", "Online" }, - { NULL, NULL } -}; - -/* - * Functions - */ - -int skype_write(struct im_connection *ic, char *buf, int len) -{ - struct skype_data *sd = ic->proto_data; - struct pollfd pfd[1]; - - if (!sd->ssl) { - return FALSE; - } - - pfd[0].fd = sd->fd; - pfd[0].events = POLLOUT; - - /* This poll is necessary or we'll get a SIGPIPE when we write() to - * sd->fd. */ - poll(pfd, 1, 1000); - if (pfd[0].revents & POLLHUP) { - imc_logout(ic, TRUE); - return FALSE; - } - ssl_write(sd->ssl, buf, len); - - return TRUE; -} - -int skype_printf(struct im_connection *ic, char *fmt, ...) -{ - va_list args; - char str[IRC_LINE_SIZE]; - - va_start(args, fmt); - g_vsnprintf(str, IRC_LINE_SIZE, fmt, args); - va_end(args); - - return skype_write(ic, str, strlen(str)); -} - -static void skype_buddy_ask_yes(void *data) -{ - struct skype_buddy_ask_data *bla = data; - - skype_printf(bla->ic, "SET USER %s ISAUTHORIZED TRUE\n", - bla->handle); - g_free(bla->handle); - g_free(bla); -} - -static void skype_buddy_ask_no(void *data) -{ - struct skype_buddy_ask_data *bla = data; - - skype_printf(bla->ic, "SET USER %s ISAUTHORIZED FALSE\n", - bla->handle); - g_free(bla->handle); - g_free(bla); -} - -void skype_buddy_ask(struct im_connection *ic, char *handle, char *message) -{ - struct skype_buddy_ask_data *bla = g_new0(struct skype_buddy_ask_data, - 1); - char *buf; - - bla->ic = ic; - bla->handle = g_strdup(handle); - - buf = g_strdup_printf("The user %s wants to add you to his/her buddy list, saying: '%s'.", handle, message); - imcb_ask(ic, buf, bla, skype_buddy_ask_yes, skype_buddy_ask_no); - g_free(buf); -} - -static void skype_call_ask_yes(void *data) -{ - struct skype_buddy_ask_data *bla = data; - - skype_printf(bla->ic, "SET CALL %s STATUS INPROGRESS\n", - bla->handle); - g_free(bla->handle); - g_free(bla); -} - -static void skype_call_ask_no(void *data) -{ - struct skype_buddy_ask_data *bla = data; - - skype_printf(bla->ic, "SET CALL %s STATUS FINISHED\n", - bla->handle); - g_free(bla->handle); - g_free(bla); -} - -void skype_call_ask(struct im_connection *ic, char *call_id, char *message) -{ - struct skype_buddy_ask_data *bla = g_new0(struct skype_buddy_ask_data, - 1); - - bla->ic = ic; - bla->handle = g_strdup(call_id); - - imcb_ask(ic, message, bla, skype_call_ask_yes, skype_call_ask_no); -} - -static char *skype_call_strerror(int err) -{ - switch (err) { - case 1: - return "Miscellaneous error"; - case 2: - return "User or phone number does not exist."; - case 3: - return "User is offline"; - case 4: - return "No proxy found"; - case 5: - return "Session terminated."; - case 6: - return "No common codec found."; - case 7: - return "Sound I/O error."; - case 8: - return "Problem with remote sound device."; - case 9: - return "Call blocked by recipient."; - case 10: - return "Recipient not a friend."; - case 11: - return "Current user not authorized by recipient."; - case 12: - return "Sound recording error."; - default: - return "Unknown error"; - } -} - -static char *skype_group_by_username(struct im_connection *ic, char *username) -{ - struct skype_data *sd = ic->proto_data; - int i, j; - - /* NEEDSWORK: we just search for the first group of the user, multiple - * groups / user is not yet supported by BitlBee. */ - - for (i = 0; i < g_list_length(sd->groups); i++) { - struct skype_group *sg = g_list_nth_data(sd->groups, i); - for (j = 0; j < g_list_length(sg->users); j++) { - if (!strcmp(g_list_nth_data(sg->users, j), username)) { - return sg->name; - } - } - } - return NULL; -} - -static struct skype_group *skype_group_by_name(struct im_connection *ic, char *name) -{ - struct skype_data *sd = ic->proto_data; - int i; - - for (i = 0; i < g_list_length(sd->groups); i++) { - struct skype_group *sg = g_list_nth_data(sd->groups, i); - if (!strcmp(sg->name, name)) { - return sg; - } - } - return NULL; -} - -static struct groupchat *skype_chat_get_or_create(struct im_connection *ic, char *id) -{ - struct skype_data *sd = ic->proto_data; - struct groupchat *gc = bee_chat_by_title(ic->bee, ic, id); - - if (!gc) { - gc = imcb_chat_new(ic, id); - imcb_chat_name_hint(gc, id); - imcb_chat_add_buddy(gc, sd->username); - - skype_printf(ic, "GET CHAT %s ADDER\n", id); - skype_printf(ic, "GET CHAT %s TOPIC\n", id); - skype_printf(ic, "GET CHAT %s ACTIVEMEMBERS\n", id); - } - - return gc; -} - -static void skype_parse_users(struct im_connection *ic, char *line) -{ - char **i, **nicks; - - nicks = g_strsplit(line + 6, ", ", 0); - for (i = nicks; *i; i++) { - skype_printf(ic, "GET USER %s ONLINESTATUS\n", *i); - skype_printf(ic, "GET USER %s FULLNAME\n", *i); - } - g_strfreev(nicks); -} - -static void skype_parse_user(struct im_connection *ic, char *line) -{ - int flags = 0; - char *ptr; - struct skype_data *sd = ic->proto_data; - char *user = strchr(line, ' '); - char *status = strrchr(line, ' '); - - status++; - ptr = strchr(++user, ' '); - if (!ptr) { - return; - } - *ptr = '\0'; - ptr++; - if (!strncmp(ptr, "ONLINESTATUS ", 13)) { - if (!strlen(user) || !strcmp(user, sd->username)) { - return; - } - if (!set_getbool(&ic->acc->set, "test_join") - && !strcmp(user, "echo123")) { - return; - } - ptr = g_strdup_printf("%s@skype.com", user); - imcb_add_buddy(ic, ptr, skype_group_by_username(ic, user)); - if (strcmp(status, "OFFLINE") && (strcmp(status, "SKYPEOUT") || - !set_getbool(&ic->acc->set, "skypeout_offline"))) { - flags |= OPT_LOGGED_IN; - } - if (strcmp(status, "ONLINE") && strcmp(status, "SKYPEME")) { - flags |= OPT_AWAY; - } - imcb_buddy_status(ic, ptr, flags, NULL, NULL); - g_free(ptr); - } else if (!strncmp(ptr, "RECEIVEDAUTHREQUEST ", 20)) { - char *message = ptr + 20; - if (strlen(message)) { - skype_buddy_ask(ic, user, message); - } - } else if (!strncmp(ptr, "BUDDYSTATUS ", 12)) { - char *st = ptr + 12; - if (!strcmp(st, "3")) { - char *buf = g_strdup_printf("%s@skype.com", user); - imcb_add_buddy(ic, buf, skype_group_by_username(ic, user)); - g_free(buf); - } - } else if (!strncmp(ptr, "MOOD_TEXT ", 10)) { - char *buf = g_strdup_printf("%s@skype.com", user); - bee_user_t *bu = bee_user_by_handle(ic->bee, ic, buf); - g_free(buf); - buf = ptr + 10; - if (bu) { - imcb_buddy_status(ic, bu->handle, bu->flags, NULL, - *buf ? buf : NULL); - } - if (set_getbool(&ic->acc->set, "show_moods")) { - imcb_log(ic, "User `%s' changed mood text to `%s'", user, buf); - } - } else if (!strncmp(ptr, "FULLNAME ", 9)) { - char *name = ptr + 9; - if (sd->is_info) { - sd->is_info = FALSE; - sd->info_fullname = g_strdup(name); - } else { - char *buf = g_strdup_printf("%s@skype.com", user); - imcb_rename_buddy(ic, buf, name); - g_free(buf); - } - } else if (!strncmp(ptr, "PHONE_HOME ", 11)) { - sd->info_phonehome = g_strdup(ptr + 11); - } else if (!strncmp(ptr, "PHONE_OFFICE ", 13)) { - sd->info_phoneoffice = g_strdup(ptr + 13); - } else if (!strncmp(ptr, "PHONE_MOBILE ", 13)) { - sd->info_phonemobile = g_strdup(ptr + 13); - } else if (!strncmp(ptr, "NROF_AUTHED_BUDDIES ", 20)) { - sd->info_nrbuddies = g_strdup(ptr + 20); - } else if (!strncmp(ptr, "TIMEZONE ", 9)) { - sd->info_tz = g_strdup(ptr + 9); - } else if (!strncmp(ptr, "LASTONLINETIMESTAMP ", 20)) { - sd->info_seen = g_strdup(ptr + 20); - } else if (!strncmp(ptr, "SEX ", 4)) { - sd->info_sex = g_strdup(ptr + 4); - } else if (!strncmp(ptr, "LANGUAGE ", 9)) { - sd->info_language = g_strdup(ptr + 9); - } else if (!strncmp(ptr, "COUNTRY ", 8)) { - sd->info_country = g_strdup(ptr + 8); - } else if (!strncmp(ptr, "PROVINCE ", 9)) { - sd->info_province = g_strdup(ptr + 9); - } else if (!strncmp(ptr, "CITY ", 5)) { - sd->info_city = g_strdup(ptr + 5); - } else if (!strncmp(ptr, "HOMEPAGE ", 9)) { - sd->info_homepage = g_strdup(ptr + 9); - } else if (!strncmp(ptr, "ABOUT ", 6)) { - /* Support multiple about lines. */ - if (!sd->info_about) { - sd->info_about = g_strdup(ptr + 6); - } else { - GString *st = g_string_new(sd->info_about); - g_string_append_printf(st, "\n%s", ptr + 6); - g_free(sd->info_about); - sd->info_about = g_strdup(st->str); - g_string_free(st, TRUE); - } - } else if (!strncmp(ptr, "BIRTHDAY ", 9)) { - sd->info_birthday = g_strdup(ptr + 9); - - GString *st = g_string_new("Contact Information\n"); - g_string_append_printf(st, "Skype Name: %s\n", user); - if (sd->info_fullname) { - if (strlen(sd->info_fullname)) { - g_string_append_printf(st, "Full Name: %s\n", - sd->info_fullname); - } - g_free(sd->info_fullname); - sd->info_fullname = NULL; - } - if (sd->info_phonehome) { - if (strlen(sd->info_phonehome)) { - g_string_append_printf(st, "Home Phone: %s\n", - sd->info_phonehome); - } - g_free(sd->info_phonehome); - sd->info_phonehome = NULL; - } - if (sd->info_phoneoffice) { - if (strlen(sd->info_phoneoffice)) { - g_string_append_printf(st, "Office Phone: %s\n", - sd->info_phoneoffice); - } - g_free(sd->info_phoneoffice); - sd->info_phoneoffice = NULL; - } - if (sd->info_phonemobile) { - if (strlen(sd->info_phonemobile)) { - g_string_append_printf(st, "Mobile Phone: %s\n", - sd->info_phonemobile); - } - g_free(sd->info_phonemobile); - sd->info_phonemobile = NULL; - } - g_string_append_printf(st, "Personal Information\n"); - if (sd->info_nrbuddies) { - if (strlen(sd->info_nrbuddies)) { - g_string_append_printf(st, - "Contacts: %s\n", sd->info_nrbuddies); - } - g_free(sd->info_nrbuddies); - sd->info_nrbuddies = NULL; - } - if (sd->info_tz) { - if (strlen(sd->info_tz)) { - char ib[256]; - time_t t = time(NULL); - t += atoi(sd->info_tz) - (60 * 60 * 24); - struct tm *gt = gmtime(&t); - strftime(ib, 256, "%H:%M:%S", gt); - g_string_append_printf(st, - "Local Time: %s\n", ib); - } - g_free(sd->info_tz); - sd->info_tz = NULL; - } - if (sd->info_seen) { - if (strlen(sd->info_seen)) { - char ib[256]; - time_t it = atoi(sd->info_seen); - struct tm *tm = localtime(&it); - strftime(ib, 256, ("%Y. %m. %d. %H:%M"), tm); - g_string_append_printf(st, - "Last Seen: %s\n", ib); - } - g_free(sd->info_seen); - sd->info_seen = NULL; - } - if (sd->info_birthday) { - if (strlen(sd->info_birthday) && - strcmp(sd->info_birthday, "0")) { - char ib[256]; - struct tm tm; - strptime(sd->info_birthday, "%Y%m%d", &tm); - strftime(ib, 256, "%B %d, %Y", &tm); - g_string_append_printf(st, - "Birthday: %s\n", ib); - - strftime(ib, 256, "%Y", &tm); - int year = atoi(ib); - time_t t = time(NULL); - struct tm *lt = localtime(&t); - g_string_append_printf(st, - "Age: %d\n", lt->tm_year + 1900 - year); - } - g_free(sd->info_birthday); - sd->info_birthday = NULL; - } - if (sd->info_sex) { - if (strlen(sd->info_sex)) { - char *iptr = sd->info_sex; - while (*iptr++) { - *iptr = g_ascii_tolower(*iptr); - } - g_string_append_printf(st, - "Gender: %s\n", sd->info_sex); - } - g_free(sd->info_sex); - sd->info_sex = NULL; - } - if (sd->info_language) { - if (strlen(sd->info_language)) { - char *iptr = strchr(sd->info_language, ' '); - if (iptr) { - iptr++; - } else { - iptr = sd->info_language; - } - g_string_append_printf(st, - "Language: %s\n", iptr); - } - g_free(sd->info_language); - sd->info_language = NULL; - } - if (sd->info_country) { - if (strlen(sd->info_country)) { - char *iptr = strchr(sd->info_country, ' '); - if (iptr) { - iptr++; - } else { - iptr = sd->info_country; - } - g_string_append_printf(st, - "Country: %s\n", iptr); - } - g_free(sd->info_country); - sd->info_country = NULL; - } - if (sd->info_province) { - if (strlen(sd->info_province)) { - g_string_append_printf(st, - "Region: %s\n", sd->info_province); - } - g_free(sd->info_province); - sd->info_province = NULL; - } - if (sd->info_city) { - if (strlen(sd->info_city)) { - g_string_append_printf(st, - "City: %s\n", sd->info_city); - } - g_free(sd->info_city); - sd->info_city = NULL; - } - if (sd->info_homepage) { - if (strlen(sd->info_homepage)) { - g_string_append_printf(st, - "Homepage: %s\n", sd->info_homepage); - } - g_free(sd->info_homepage); - sd->info_homepage = NULL; - } - if (sd->info_about) { - if (strlen(sd->info_about)) { - g_string_append_printf(st, "%s\n", - sd->info_about); - } - g_free(sd->info_about); - sd->info_about = NULL; - } - imcb_log(ic, "%s", st->str); - g_string_free(st, TRUE); - } -} - -static void skype_parse_chatmessage_said_emoted(struct im_connection *ic, struct groupchat *gc, char *body) -{ - struct skype_data *sd = ic->proto_data; - char buf[IRC_LINE_SIZE]; - - if (!strcmp(sd->type, "SAID")) { - if (!sd->is_edit) { - g_snprintf(buf, IRC_LINE_SIZE, "%s", body); - } else { - g_snprintf(buf, IRC_LINE_SIZE, "%s %s", set_getstr(&ic->acc->set, "edit_prefix"), body); - sd->is_edit = 0; - } - } else { - g_snprintf(buf, IRC_LINE_SIZE, "/me %s", body); - } - if (!gc) { - /* Private message */ - imcb_buddy_msg(ic, sd->handle, buf, 0, 0); - } else { - /* Groupchat message */ - imcb_chat_msg(gc, sd->handle, buf, 0, 0); - } -} - -static void skype_parse_chatmessage(struct im_connection *ic, char *line) -{ - struct skype_data *sd = ic->proto_data; - char *id = strchr(line, ' '); - - if (!++id) { - return; - } - char *info = strchr(id, ' '); - - if (!info) { - return; - } - *info = '\0'; - info++; - if (!strcmp(info, "STATUS RECEIVED") || !strncmp(info, "EDITED_TIMESTAMP", 16)) { - /* New message ID: - * (1) Request its from field - * (2) Request its body - * (3) Request its type - * (4) Query chatname - */ - skype_printf(ic, "GET CHATMESSAGE %s FROM_HANDLE\n", id); - if (!strcmp(info, "STATUS RECEIVED")) { - skype_printf(ic, "GET CHATMESSAGE %s BODY\n", id); - } else { - sd->is_edit = 1; - } - skype_printf(ic, "GET CHATMESSAGE %s TYPE\n", id); - skype_printf(ic, "GET CHATMESSAGE %s CHATNAME\n", id); - } else if (!strncmp(info, "FROM_HANDLE ", 12)) { - info += 12; - /* New from field value. Store - * it, then we can later use it - * when we got the message's - * body. */ - g_free(sd->handle); - sd->handle = g_strdup_printf("%s@skype.com", info); - } else if (!strncmp(info, "EDITED_BY ", 10)) { - info += 10; - /* This is the same as - * FROM_HANDLE, except that we - * never request these lines - * from Skype, we just get - * them. */ - g_free(sd->handle); - sd->handle = g_strdup_printf("%s@skype.com", info); - } else if (!strncmp(info, "BODY ", 5)) { - info += 5; - sd->body = g_list_append(sd->body, g_strdup(info)); - } else if (!strncmp(info, "TYPE ", 5)) { - info += 5; - g_free(sd->type); - sd->type = g_strdup(info); - } else if (!strncmp(info, "CHATNAME ", 9)) { - info += 9; - if (sd->handle && sd->body && sd->type) { - struct groupchat *gc = skype_chat_get_or_create(ic, info); - int i; - for (i = 0; i < g_list_length(sd->body); i++) { - char *body = g_list_nth_data(sd->body, i); - if (!strcmp(sd->type, "SAID") || - !strcmp(sd->type, "EMOTED")) { - skype_parse_chatmessage_said_emoted(ic, gc, body); - } else if (!strcmp(sd->type, "SETTOPIC") && gc) { - imcb_chat_topic(gc, - sd->handle, body, 0); - } else if (!strcmp(sd->type, "LEFT") && gc) { - imcb_chat_remove_buddy(gc, - sd->handle, NULL); - } - } - g_list_free(sd->body); - sd->body = NULL; - } - } -} - -static void skype_parse_call(struct im_connection *ic, char *line) -{ - struct skype_data *sd = ic->proto_data; - char *id = strchr(line, ' '); - char buf[IRC_LINE_SIZE]; - - if (!++id) { - return; - } - char *info = strchr(id, ' '); - - if (!info) { - return; - } - *info = '\0'; - info++; - if (!strncmp(info, "FAILUREREASON ", 14)) { - sd->failurereason = atoi(strchr(info, ' ')); - } else if (!strcmp(info, "STATUS RINGING")) { - if (sd->call_id) { - g_free(sd->call_id); - } - sd->call_id = g_strdup(id); - skype_printf(ic, "GET CALL %s PARTNER_HANDLE\n", id); - sd->call_status = SKYPE_CALL_RINGING; - } else if (!strcmp(info, "STATUS MISSED")) { - skype_printf(ic, "GET CALL %s PARTNER_HANDLE\n", id); - sd->call_status = SKYPE_CALL_MISSED; - } else if (!strcmp(info, "STATUS CANCELLED")) { - skype_printf(ic, "GET CALL %s PARTNER_HANDLE\n", id); - sd->call_status = SKYPE_CALL_CANCELLED; - } else if (!strcmp(info, "STATUS FINISHED")) { - skype_printf(ic, "GET CALL %s PARTNER_HANDLE\n", id); - sd->call_status = SKYPE_CALL_FINISHED; - } else if (!strcmp(info, "STATUS REFUSED")) { - skype_printf(ic, "GET CALL %s PARTNER_HANDLE\n", id); - sd->call_status = SKYPE_CALL_REFUSED; - } else if (!strcmp(info, "STATUS UNPLACED")) { - if (sd->call_id) { - g_free(sd->call_id); - } - /* Save the ID for later usage (Cancel/Finish). */ - sd->call_id = g_strdup(id); - sd->call_out = TRUE; - } else if (!strcmp(info, "STATUS FAILED")) { - imcb_error(ic, "Call failed: %s", - skype_call_strerror(sd->failurereason)); - sd->call_id = NULL; - } else if (!strncmp(info, "DURATION ", 9)) { - if (sd->call_duration) { - g_free(sd->call_duration); - } - sd->call_duration = g_strdup(info + 9); - } else if (!strncmp(info, "PARTNER_HANDLE ", 15)) { - info += 15; - if (!sd->call_status) { - return; - } - switch (sd->call_status) { - case SKYPE_CALL_RINGING: - if (sd->call_out) { - imcb_log(ic, "You are currently ringing the user %s.", info); - } else { - g_snprintf(buf, IRC_LINE_SIZE, - "The user %s is currently ringing you.", - info); - skype_call_ask(ic, sd->call_id, buf); - } - break; - case SKYPE_CALL_MISSED: - imcb_log(ic, "You have missed a call from user %s.", - info); - break; - case SKYPE_CALL_CANCELLED: - imcb_log(ic, "You cancelled the call to the user %s.", - info); - sd->call_status = 0; - sd->call_out = FALSE; - break; - case SKYPE_CALL_REFUSED: - if (sd->call_out) { - imcb_log(ic, "The user %s refused the call.", - info); - } else { - imcb_log(ic, - "You refused the call from user %s.", - info); - } - sd->call_out = FALSE; - break; - case SKYPE_CALL_FINISHED: - if (sd->call_duration) { - imcb_log(ic, - "You finished the call to the user %s " - "(duration: %s seconds).", - info, sd->call_duration); - } else { - imcb_log(ic, - "You finished the call to the user %s.", - info); - } - sd->call_out = FALSE; - break; - default: - /* Don't be noisy, ignore other statuses for now. */ - break; - } - sd->call_status = 0; - } -} - -static void skype_parse_filetransfer(struct im_connection *ic, char *line) -{ - struct skype_data *sd = ic->proto_data; - char *id = strchr(line, ' '); - - if (!++id) { - return; - } - char *info = strchr(id, ' '); - - if (!info) { - return; - } - *info = '\0'; - info++; - if (!strcmp(info, "STATUS NEW")) { - skype_printf(ic, "GET FILETRANSFER %s PARTNER_HANDLE\n", - id); - sd->filetransfer_status = SKYPE_FILETRANSFER_NEW; - } else if (!strcmp(info, "STATUS FAILED")) { - skype_printf(ic, "GET FILETRANSFER %s PARTNER_HANDLE\n", - id); - sd->filetransfer_status = SKYPE_FILETRANSFER_FAILED; - } else if (!strcmp(info, "STATUS COMPLETED")) { - skype_printf(ic, "GET FILETRANSFER %s PARTNER_HANDLE\n", id); - sd->filetransfer_status = SKYPE_FILETRANSFER_COMPLETED; - } else if (!strcmp(info, "STATUS TRANSFERRING")) { - skype_printf(ic, "GET FILETRANSFER %s PARTNER_HANDLE\n", id); - sd->filetransfer_status = SKYPE_FILETRANSFER_TRANSFERRING; - } else if (!strncmp(info, "FILEPATH ", 9)) { - info += 9; - sd->filetransfer_path = g_strdup(info); - } else if (!strncmp(info, "PARTNER_HANDLE ", 15)) { - info += 15; - if (!sd->filetransfer_status) { - return; - } - switch (sd->filetransfer_status) { - case SKYPE_FILETRANSFER_NEW: - imcb_log(ic, "The user %s offered a new file for you.", - info); - break; - case SKYPE_FILETRANSFER_FAILED: - imcb_log(ic, "Failed to transfer file from user %s.", - info); - break; - case SKYPE_FILETRANSFER_COMPLETED: - imcb_log(ic, "File transfer from user %s completed.", info); - break; - case SKYPE_FILETRANSFER_TRANSFERRING: - if (sd->filetransfer_path) { - imcb_log(ic, "File transfer from user %s started, saving to %s.", info, - sd->filetransfer_path); - g_free(sd->filetransfer_path); - sd->filetransfer_path = NULL; - } - break; - } - sd->filetransfer_status = 0; - } -} - -static struct skype_group *skype_group_by_id(struct im_connection *ic, int id) -{ - struct skype_data *sd = ic->proto_data; - int i; - - for (i = 0; i < g_list_length(sd->groups); i++) { - struct skype_group *sg = (struct skype_group *) g_list_nth_data(sd->groups, i); - - if (sg->id == id) { - return sg; - } - } - return NULL; -} - -static void skype_group_free(struct skype_group *sg, gboolean usersonly) -{ - int i; - - for (i = 0; i < g_list_length(sg->users); i++) { - char *user = g_list_nth_data(sg->users, i); - g_free(user); - } - sg->users = NULL; - if (usersonly) { - return; - } - g_free(sg->name); - g_free(sg); -} - -/* Update the group of each user in this group */ -static void skype_group_users(struct im_connection *ic, struct skype_group *sg) -{ - int i; - - for (i = 0; i < g_list_length(sg->users); i++) { - char *user = g_list_nth_data(sg->users, i); - char *buf = g_strdup_printf("%s@skype.com", user); - imcb_add_buddy(ic, buf, sg->name); - g_free(buf); - } -} - -static void skype_parse_group(struct im_connection *ic, char *line) -{ - struct skype_data *sd = ic->proto_data; - char *id = strchr(line, ' '); - - if (!++id) { - return; - } - - char *info = strchr(id, ' '); - - if (!info) { - return; - } - *info = '\0'; - info++; - - if (!strncmp(info, "DISPLAYNAME ", 12)) { - info += 12; - - /* Name given for a group ID: try to update it or insert a new - * one if not found */ - struct skype_group *sg = skype_group_by_id(ic, atoi(id)); - if (sg) { - g_free(sg->name); - sg->name = g_strdup(info); - } else { - sg = g_new0(struct skype_group, 1); - sg->id = atoi(id); - sg->name = g_strdup(info); - sd->groups = g_list_append(sd->groups, sg); - } - } else if (!strncmp(info, "USERS ", 6)) { - struct skype_group *sg = skype_group_by_id(ic, atoi(id)); - - if (sg) { - char **i; - char **users = g_strsplit(info + 6, ", ", 0); - - skype_group_free(sg, TRUE); - i = users; - while (*i) { - sg->users = g_list_append(sg->users, g_strdup(*i)); - i++; - } - g_strfreev(users); - skype_group_users(ic, sg); - } else { - log_message(LOGLVL_ERROR, - "No skype group with id %s. That's probably a bug.", id); - } - } else if (!strncmp(info, "NROFUSERS ", 10)) { - if (!sd->pending_user) { - /* Number of users changed in this group, query its type to see - * if it's a custom one we should care about. */ - skype_printf(ic, "GET GROUP %s TYPE\n", id); - return; - } - - /* This is a newly created group, we have a single user - * to add. */ - struct skype_group *sg = skype_group_by_id(ic, atoi(id)); - - if (sg) { - skype_printf(ic, "ALTER GROUP %d ADDUSER %s\n", sg->id, sd->pending_user); - g_free(sd->pending_user); - sd->pending_user = NULL; - } else { - log_message(LOGLVL_ERROR, - "No skype group with id %s. That's probably a bug.", id); - } - } else if (!strcmp(info, "TYPE CUSTOM_GROUP")) { - /* This one is interesting, query its users. */ - skype_printf(ic, "GET GROUP %s USERS\n", id); - } -} - -static void skype_parse_chat(struct im_connection *ic, char *line) -{ - struct skype_data *sd = ic->proto_data; - char buf[IRC_LINE_SIZE]; - char *id = strchr(line, ' '); - - if (!++id) { - return; - } - struct groupchat *gc; - char *info = strchr(id, ' '); - - if (!info) { - return; - } - *info = '\0'; - info++; - /* Remove fake chat if we created one in skype_chat_with() */ - gc = bee_chat_by_title(ic->bee, ic, ""); - if (gc) { - imcb_chat_free(gc); - } - if (!strcmp(info, "STATUS MULTI_SUBSCRIBED")) { - skype_chat_get_or_create(ic, id); - } else if (!strcmp(info, "STATUS DIALOG") && sd->groupchat_with) { - gc = skype_chat_get_or_create(ic, id); - /* According to the docs this - * is necessary. However it - * does not seem the situation - * and it would open an extra - * window on our client, so - * just leave it out. */ - /*skype_printf(ic, "OPEN CHAT %s\n", id);*/ - g_snprintf(buf, IRC_LINE_SIZE, "%s@skype.com", - sd->groupchat_with); - imcb_chat_add_buddy(gc, buf); - g_free(sd->groupchat_with); - sd->groupchat_with = NULL; - } else if (!strcmp(info, "STATUS UNSUBSCRIBED")) { - gc = bee_chat_by_title(ic->bee, ic, id); - if (gc) { - gc->data = (void *) FALSE; - } - } else if (!strncmp(info, "ADDER ", 6)) { - info += 6; - g_free(sd->adder); - sd->adder = g_strdup_printf("%s@skype.com", info); - } else if (!strncmp(info, "TOPIC ", 6)) { - info += 6; - gc = bee_chat_by_title(ic->bee, ic, id); - if (gc && (sd->adder || sd->topic_wait)) { - if (sd->topic_wait) { - sd->adder = g_strdup(sd->username); - sd->topic_wait = 0; - } - imcb_chat_topic(gc, sd->adder, info, 0); - g_free(sd->adder); - sd->adder = NULL; - } - } else if (!strncmp(info, "MEMBERS ", 8) || !strncmp(info, "ACTIVEMEMBERS ", 14)) { - if (!strncmp(info, "MEMBERS ", 8)) { - info += 8; - } else { - info += 14; - } - gc = bee_chat_by_title(ic->bee, ic, id); - /* Hack! We set ->data to TRUE - * while we're on the channel - * so that we won't rejoin - * after a /part. */ - if (!gc || gc->data) { - return; - } - char **members = g_strsplit(info, " ", 0); - int i; - for (i = 0; members[i]; i++) { - if (!strcmp(members[i], sd->username)) { - continue; - } - g_snprintf(buf, IRC_LINE_SIZE, "%s@skype.com", - members[i]); - if (!g_list_find_custom(gc->in_room, buf, - (GCompareFunc) strcmp)) { - imcb_chat_add_buddy(gc, buf); - } - } - imcb_chat_add_buddy(gc, sd->username); - g_strfreev(members); - } -} - -static void skype_parse_password(struct im_connection *ic, char *line) -{ - if (!strncmp(line + 9, "OK", 2)) { - imcb_connected(ic); - } else { - imcb_error(ic, "Authentication Failed"); - imc_logout(ic, TRUE); - } -} - -static void skype_parse_profile(struct im_connection *ic, char *line) -{ - imcb_log(ic, "SkypeOut balance value is '%s'.", line + 21); -} - -static void skype_parse_ping(struct im_connection *ic, char *line) -{ - /* Unused parameter */ - line = line; - skype_printf(ic, "PONG\n"); -} - -static void skype_parse_chats(struct im_connection *ic, char *line) -{ - char **i; - char **chats = g_strsplit(line + 6, ", ", 0); - - i = chats; - while (*i) { - skype_printf(ic, "GET CHAT %s STATUS\n", *i); - skype_printf(ic, "GET CHAT %s ACTIVEMEMBERS\n", *i); - i++; - } - g_strfreev(chats); -} - -static void skype_parse_groups(struct im_connection *ic, char *line) -{ - if (!set_getbool(&ic->acc->set, "read_groups")) { - return; - } - - char **i; - char **groups = g_strsplit(line + 7, ", ", 0); - - i = groups; - while (*i) { - skype_printf(ic, "GET GROUP %s DISPLAYNAME\n", *i); - skype_printf(ic, "GET GROUP %s USERS\n", *i); - i++; - } - g_strfreev(groups); -} - -static void skype_parse_alter_group(struct im_connection *ic, char *line) -{ - char *id = line + strlen("ALTER GROUP"); - - if (!++id) { - return; - } - - char *info = strchr(id, ' '); - - if (!info) { - return; - } - *info = '\0'; - info++; - - if (!strncmp(info, "ADDUSER ", 8)) { - struct skype_group *sg = skype_group_by_id(ic, atoi(id)); - - info += 8; - if (sg) { - char *buf = g_strdup_printf("%s@skype.com", info); - sg->users = g_list_append(sg->users, g_strdup(info)); - imcb_add_buddy(ic, buf, sg->name); - g_free(buf); - } else { - log_message(LOGLVL_ERROR, - "No skype group with id %s. That's probably a bug.", id); - } - } -} - -typedef void (*skype_parser)(struct im_connection *ic, char *line); - -static gboolean skype_read_callback(gpointer data, gint fd, - b_input_condition cond) -{ - struct im_connection *ic = data; - struct skype_data *sd = ic->proto_data; - char buf[IRC_LINE_SIZE]; - int st, i; - char **lines, **lineptr, *line; - static struct parse_map { - char *k; - skype_parser v; - } parsers[] = { - { "USERS ", skype_parse_users }, - { "USER ", skype_parse_user }, - { "CHATMESSAGE ", skype_parse_chatmessage }, - { "CALL ", skype_parse_call }, - { "FILETRANSFER ", skype_parse_filetransfer }, - { "CHAT ", skype_parse_chat }, - { "GROUP ", skype_parse_group }, - { "PASSWORD ", skype_parse_password }, - { "PROFILE PSTN_BALANCE ", skype_parse_profile }, - { "PING", skype_parse_ping }, - { "CHATS ", skype_parse_chats }, - { "GROUPS ", skype_parse_groups }, - { "ALTER GROUP ", skype_parse_alter_group }, - }; - - /* Unused parameters */ - fd = fd; - cond = cond; - - if (!sd || sd->fd == -1) { - return FALSE; - } - /* Read the whole data. */ - st = ssl_read(sd->ssl, buf, sizeof(buf)); - if (st >= IRC_LINE_SIZE - 1) { - /* As we don't buffer incoming data, if IRC_LINE_SIZE amount of bytes - * were received, there's a good chance last message was truncated - * and the next recv() will yield garbage. */ - imcb_error(ic, "Unable to handle incoming data from skyped"); - st = 0; - } - if (st > 0) { - buf[st] = '\0'; - /* Then split it up to lines. */ - lines = g_strsplit(buf, "\n", 0); - lineptr = lines; - while ((line = *lineptr)) { - if (!strlen(line)) { - break; - } - if (set_getbool(&ic->acc->set, "skypeconsole_receive")) { - imcb_buddy_msg(ic, "skypeconsole", line, 0, 0); - } - for (i = 0; i < ARRAY_SIZE(parsers); i++) { - if (!strncmp(line, parsers[i].k, - strlen(parsers[i].k))) { - parsers[i].v(ic, line); - break; - } - } - lineptr++; - } - g_strfreev(lines); - } else if (st == 0 || (st < 0 && !ssl_sockerr_again(sd->ssl))) { - ssl_disconnect(sd->ssl); - sd->fd = -1; - sd->ssl = NULL; - - imcb_error(ic, "Error while reading from server"); - imc_logout(ic, TRUE); - return FALSE; - } - return TRUE; -} - -gboolean skype_start_stream(struct im_connection *ic) -{ - struct skype_data *sd = ic->proto_data; - int st; - - if (!sd) { - return FALSE; - } - - if (sd->bfd <= 0) { - sd->bfd = b_input_add(sd->fd, B_EV_IO_READ, - skype_read_callback, ic); - } - - /* Log in */ - skype_printf(ic, "USERNAME %s\n", ic->acc->user); - skype_printf(ic, "PASSWORD %s\n", ic->acc->pass); - - /* This will download all buddies and groups. */ - st = skype_printf(ic, "SEARCH GROUPS CUSTOM\n"); - skype_printf(ic, "SEARCH FRIENDS\n"); - - skype_printf(ic, "SET USERSTATUS ONLINE\n"); - - /* Auto join to bookmarked chats if requested.*/ - if (set_getbool(&ic->acc->set, "auto_join")) { - skype_printf(ic, "SEARCH BOOKMARKEDCHATS\n"); - skype_printf(ic, "SEARCH ACTIVECHATS\n"); - skype_printf(ic, "SEARCH MISSEDCHATS\n"); - skype_printf(ic, "SEARCH RECENTCHATS\n"); - } - return st; -} - -gboolean skype_connected(gpointer data, int returncode, void *source, b_input_condition cond) -{ - struct im_connection *ic = data; - struct skype_data *sd = ic->proto_data; - - /* Unused parameter */ - cond = cond; - - if (!source) { - sd->ssl = NULL; - imcb_error(ic, "Could not connect to server"); - imc_logout(ic, TRUE); - return FALSE; - } - imcb_log(ic, "Connected to server, logging in"); - - return skype_start_stream(ic); -} - -static void skype_login(account_t *acc) -{ - struct im_connection *ic = imcb_new(acc); - struct skype_data *sd = g_new0(struct skype_data, 1); - - ic->proto_data = sd; - - imcb_log(ic, "Connecting"); - sd->ssl = ssl_connect(set_getstr(&acc->set, "server"), - set_getint(&acc->set, "port"), FALSE, skype_connected, ic); - sd->fd = sd->ssl ? ssl_getfd(sd->ssl) : -1; - sd->username = g_strdup(acc->user); - - sd->ic = ic; - - if (set_getbool(&acc->set, "skypeconsole")) { - imcb_add_buddy(ic, "skypeconsole", NULL); - } -} - -static void skype_logout(struct im_connection *ic) -{ - struct skype_data *sd = ic->proto_data; - int i; - - skype_printf(ic, "SET USERSTATUS OFFLINE\n"); - - while (ic->groupchats) { - imcb_chat_free(ic->groupchats->data); - } - - for (i = 0; i < g_list_length(sd->groups); i++) { - struct skype_group *sg = (struct skype_group *) g_list_nth_data(sd->groups, i); - skype_group_free(sg, FALSE); - } - - if (sd->ssl) { - ssl_disconnect(sd->ssl); - } - - g_free(sd->username); - g_free(sd->handle); - g_free(sd); - ic->proto_data = NULL; -} - -static int skype_buddy_msg(struct im_connection *ic, char *who, char *message, - int flags) -{ - char *ptr, *nick; - int st; - - /* Unused parameter */ - flags = flags; - - nick = g_strdup(who); - ptr = strchr(nick, '@'); - if (ptr) { - *ptr = '\0'; - } - - if (!strncmp(who, "skypeconsole", 12)) { - st = skype_printf(ic, "%s\n", message); - } else { - st = skype_printf(ic, "MESSAGE %s %s\n", nick, message); - } - g_free(nick); - - return st; -} - -const struct skype_away_state *skype_away_state_by_name(char *name) -{ - int i; - - for (i = 0; skype_away_state_list[i].full_name; i++) { - if (g_strcasecmp(skype_away_state_list[i].full_name, name) == 0) { - return skype_away_state_list + i; - } - } - - return NULL; -} - -static void skype_set_away(struct im_connection *ic, char *state_txt, - char *message) -{ - const struct skype_away_state *state; - - /* Unused parameter */ - message = message; - - if (state_txt == NULL) { - state = skype_away_state_by_name("Online"); - } else { - state = skype_away_state_by_name(state_txt); - } - skype_printf(ic, "SET USERSTATUS %s\n", state->code); -} - -static GList *skype_away_states(struct im_connection *ic) -{ - static GList *l; - int i; - - /* Unused parameter */ - ic = ic; - - if (l == NULL) { - for (i = 0; skype_away_state_list[i].full_name; i++) { - l = g_list_append(l, - (void *) skype_away_state_list[i].full_name); - } - } - - return l; -} - -static char *skype_set_display_name(set_t *set, char *value) -{ - account_t *acc = set->data; - struct im_connection *ic = acc->ic; - - skype_printf(ic, "SET PROFILE FULLNAME %s\n", value); - return value; -} - -static char *skype_set_mood_text(set_t *set, char *value) -{ - account_t *acc = set->data; - struct im_connection *ic = acc->ic; - - skype_printf(ic, "SET PROFILE MOOD_TEXT %s\n", value); - return value; -} - -static char *skype_set_balance(set_t *set, char *value) -{ - account_t *acc = set->data; - struct im_connection *ic = acc->ic; - - skype_printf(ic, "GET PROFILE PSTN_BALANCE\n"); - return value; -} - -static void skype_call(struct im_connection *ic, char *value) -{ - char *nick = g_strdup(value); - char *ptr = strchr(nick, '@'); - - if (ptr) { - *ptr = '\0'; - } - skype_printf(ic, "CALL %s\n", nick); - g_free(nick); -} - -static void skype_hangup(struct im_connection *ic) -{ - struct skype_data *sd = ic->proto_data; - - if (sd->call_id) { - skype_printf(ic, "SET CALL %s STATUS FINISHED\n", - sd->call_id); - g_free(sd->call_id); - sd->call_id = 0; - } else { - imcb_error(ic, "There are no active calls currently."); - } -} - -static char *skype_set_call(set_t *set, char *value) -{ - account_t *acc = set->data; - struct im_connection *ic = acc->ic; - - if (value) { - skype_call(ic, value); - } else { - skype_hangup(ic); - } - return value; -} - -static void skype_add_buddy(struct im_connection *ic, char *who, char *group) -{ - struct skype_data *sd = ic->proto_data; - char *nick, *ptr; - - nick = g_strdup(who); - ptr = strchr(nick, '@'); - if (ptr) { - *ptr = '\0'; - } - - if (!group) { - skype_printf(ic, "SET USER %s BUDDYSTATUS 2 Please authorize me\n", - nick); - g_free(nick); - } else { - struct skype_group *sg = skype_group_by_name(ic, group); - - if (!sg) { - /* No such group, we need to create it, then have to - * add the user once it's created. */ - skype_printf(ic, "CREATE GROUP %s\n", group); - sd->pending_user = g_strdup(nick); - } else { - skype_printf(ic, "ALTER GROUP %d ADDUSER %s\n", sg->id, nick); - } - } -} - -static void skype_remove_buddy(struct im_connection *ic, char *who, char *group) -{ - char *nick, *ptr; - - /* Unused parameter */ - group = group; - - nick = g_strdup(who); - ptr = strchr(nick, '@'); - if (ptr) { - *ptr = '\0'; - } - skype_printf(ic, "SET USER %s BUDDYSTATUS 1\n", nick); - g_free(nick); -} - -void skype_chat_msg(struct groupchat *gc, char *message, int flags) -{ - struct im_connection *ic = gc->ic; - - /* Unused parameter */ - flags = flags; - - skype_printf(ic, "CHATMESSAGE %s %s\n", gc->title, message); -} - -void skype_chat_leave(struct groupchat *gc) -{ - struct im_connection *ic = gc->ic; - - skype_printf(ic, "ALTER CHAT %s LEAVE\n", gc->title); - gc->data = (void *) TRUE; -} - -void skype_chat_invite(struct groupchat *gc, char *who, char *message) -{ - struct im_connection *ic = gc->ic; - char *ptr, *nick; - - nick = g_strdup(who); - ptr = strchr(nick, '@'); - if (ptr) { - *ptr = '\0'; - } - skype_printf(ic, "ALTER CHAT %s ADDMEMBERS %s\n", gc->title, nick); - g_free(nick); -} - -void skype_chat_topic(struct groupchat *gc, char *message) -{ - struct im_connection *ic = gc->ic; - struct skype_data *sd = ic->proto_data; - - skype_printf(ic, "ALTER CHAT %s SETTOPIC %s\n", - gc->title, message); - sd->topic_wait = 1; -} - -struct groupchat *skype_chat_with(struct im_connection *ic, char *who) -{ - struct skype_data *sd = ic->proto_data; - char *ptr, *nick; - - nick = g_strdup(who); - ptr = strchr(nick, '@'); - if (ptr) { - *ptr = '\0'; - } - skype_printf(ic, "CHAT CREATE %s\n", nick); - sd->groupchat_with = g_strdup(nick); - g_free(nick); - /* We create a fake chat for now. We will replace it with a real one in - * the real callback. */ - return imcb_chat_new(ic, ""); -} - -static void skype_get_info(struct im_connection *ic, char *who) -{ - struct skype_data *sd = ic->proto_data; - char *ptr, *nick; - - nick = g_strdup(who); - ptr = strchr(nick, '@'); - if (ptr) { - *ptr = '\0'; - } - sd->is_info = TRUE; - skype_printf(ic, "GET USER %s FULLNAME\n", nick); - skype_printf(ic, "GET USER %s PHONE_HOME\n", nick); - skype_printf(ic, "GET USER %s PHONE_OFFICE\n", nick); - skype_printf(ic, "GET USER %s PHONE_MOBILE\n", nick); - skype_printf(ic, "GET USER %s NROF_AUTHED_BUDDIES\n", nick); - skype_printf(ic, "GET USER %s TIMEZONE\n", nick); - skype_printf(ic, "GET USER %s LASTONLINETIMESTAMP\n", nick); - skype_printf(ic, "GET USER %s SEX\n", nick); - skype_printf(ic, "GET USER %s LANGUAGE\n", nick); - skype_printf(ic, "GET USER %s COUNTRY\n", nick); - skype_printf(ic, "GET USER %s PROVINCE\n", nick); - skype_printf(ic, "GET USER %s CITY\n", nick); - skype_printf(ic, "GET USER %s HOMEPAGE\n", nick); - skype_printf(ic, "GET USER %s ABOUT\n", nick); - /* - * Hack: we query the bithday property which is always a single line, - * so we can send the collected properties to the user when we have - * this one. - */ - skype_printf(ic, "GET USER %s BIRTHDAY\n", nick); -} - -static void skype_init(account_t *acc) -{ - set_t *s; - - s = set_add(&acc->set, "server", SKYPE_DEFAULT_SERVER, set_eval_account, - acc); - s->flags |= ACC_SET_OFFLINE_ONLY; - - s = set_add(&acc->set, "port", SKYPE_DEFAULT_PORT, set_eval_int, acc); - s->flags |= ACC_SET_OFFLINE_ONLY; - - s = set_add(&acc->set, "display_name", NULL, skype_set_display_name, - acc); - s->flags |= SET_NOSAVE | ACC_SET_ONLINE_ONLY; - - s = set_add(&acc->set, "mood_text", NULL, skype_set_mood_text, acc); - s->flags |= SET_NOSAVE | ACC_SET_ONLINE_ONLY; - - s = set_add(&acc->set, "call", NULL, skype_set_call, acc); - s->flags |= SET_NOSAVE | ACC_SET_ONLINE_ONLY; - - s = set_add(&acc->set, "balance", NULL, skype_set_balance, acc); - s->flags |= SET_NOSAVE | ACC_SET_ONLINE_ONLY; - - s = set_add(&acc->set, "skypeout_offline", "true", set_eval_bool, acc); - - s = set_add(&acc->set, "skypeconsole", "false", set_eval_bool, acc); - s->flags |= ACC_SET_OFFLINE_ONLY; - - s = set_add(&acc->set, "skypeconsole_receive", "false", set_eval_bool, - acc); - s->flags |= ACC_SET_OFFLINE_ONLY; - - s = set_add(&acc->set, "auto_join", "false", set_eval_bool, acc); - s->flags |= ACC_SET_OFFLINE_ONLY; - - s = set_add(&acc->set, "test_join", "false", set_eval_bool, acc); - s->flags |= ACC_SET_OFFLINE_ONLY; - - s = set_add(&acc->set, "show_moods", "false", set_eval_bool, acc); - - s = set_add(&acc->set, "edit_prefix", "EDIT:", - NULL, acc); - - s = set_add(&acc->set, "read_groups", "false", set_eval_bool, acc); -} - -#if BITLBEE_VERSION_CODE > BITLBEE_VER(3, 0, 1) -GList *skype_buddy_action_list(bee_user_t *bu) -{ - static GList *ret; - - /* Unused parameter */ - bu = bu; - - if (ret == NULL) { - static const struct buddy_action ba[2] = { - { "CALL", "Initiate a call" }, - { "HANGUP", "Hang up a call" }, - }; - int i; - - for (i = 0; i < ARRAY_SIZE(ba); i++) { - ret = g_list_prepend(ret, (void *) (ba + i)); - } - } - - return ret; -} - -void *skype_buddy_action(struct bee_user *bu, const char *action, char * const args[], void *data) -{ - /* Unused parameters */ - args = args; - data = data; - - if (!g_strcasecmp(action, "CALL")) { - skype_call(bu->ic, bu->handle); - } else if (!g_strcasecmp(action, "HANGUP")) { - skype_hangup(bu->ic); - } - - return NULL; -} -#endif - -void init_plugin(void) -{ - struct prpl *ret = g_new0(struct prpl, 1); - - ret->name = "skype"; - ret->login = skype_login; - ret->init = skype_init; - ret->logout = skype_logout; - ret->buddy_msg = skype_buddy_msg; - ret->get_info = skype_get_info; - ret->away_states = skype_away_states; - ret->set_away = skype_set_away; - ret->add_buddy = skype_add_buddy; - ret->remove_buddy = skype_remove_buddy; - ret->chat_msg = skype_chat_msg; - ret->chat_leave = skype_chat_leave; - ret->chat_invite = skype_chat_invite; - ret->chat_with = skype_chat_with; - ret->handle_cmp = g_strcasecmp; - ret->chat_topic = skype_chat_topic; -#if BITLBEE_VERSION_CODE > BITLBEE_VER(3, 0, 1) - ret->buddy_action_list = skype_buddy_action_list; - ret->buddy_action = skype_buddy_action; -#endif - register_protocol(ret); -} - -struct plugin_info *init_plugin_info(void) -{ - static struct plugin_info info = { - BITLBEE_ABI_VERSION_CODE, - "skype", - BITLBEE_VERSION, - "Skype protocol plugin", - NULL, - NULL - }; - - return &info; -} diff --git a/protocols/skype/skyped.1 b/protocols/skype/skyped.1 deleted file mode 100644 index d7542184..00000000 --- a/protocols/skype/skyped.1 +++ /dev/null @@ -1,207 +0,0 @@ -'\" t -.\" Title: skyped -.\" Author: [see the "AUTHOR" section] -.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/> -.\" Date: 123 -.\" Manual: BitlBee manual -.\" Source: BitlBee -.\" Language: English -.\" -.TH "SKYPED" "1" "123" "BitlBee" "BitlBee manual" -.\" ----------------------------------------------------------------- -.\" * Define some portability stuff -.\" ----------------------------------------------------------------- -.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.\" http://bugs.debian.org/507673 -.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html -.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.ie \n(.g .ds Aq \(aq -.el .ds Aq ' -.\" ----------------------------------------------------------------- -.\" * set default formatting -.\" ----------------------------------------------------------------- -.\" disable hyphenation -.nh -.\" disable justification (adjust text to left margin only) -.ad l -.\" ----------------------------------------------------------------- -.\" * MAIN CONTENT STARTS HERE * -.\" ----------------------------------------------------------------- -.SH "NAME" -skyped \- allows remote control of the Skype GUI client -.SH "SYNOPSIS" -.sp -skyped [<options>] -.SH "DESCRIPTION" -.sp -Skype supports remote control of the GUI client only via X11 or DBus messages\&. This is hard in case you want remote control\&. This daemon listens on a TCP port and runs on the same machine where the GUI client runs\&. It passes all the input it gets to Skype directly, except for a few commands which is related to authentication\&. The whole communication is done via SSL\&. -.SH "CONFIGURATION" -.sp -.RS 4 -.ie n \{\ -\h'-04'\(bu\h'+03'\c -.\} -.el \{\ -.sp -1 -.IP \(bu 2.3 -.\} -Set up -~/\&.skyped/skyped\&.conf: Create the -~/\&.skyped -directory, copy -skyped\&.conf -and -skyped\&.cnf -from -/usr/local/etc/skyped/ -to -~/\&.skyped, adjust -username -and -password\&. The -username -should be your Skype login and the -password -can be whatever you want, but you will have to specify that one when adding the Skype account to BitlBee (see later)\&. -.RE -.if n \{\ -.sp -.\} -.RS 4 -.it 1 an-trap -.nr an-no-space-flag 1 -.nr an-break-flag 1 -.br -.ps +1 -\fBNote\fR -.ps -1 -.br -.sp -Here, and later \- /usr/local/etc can be different on your installation if you used the \-\-sysconfdir switch when running the configure of BitlBee\&. -.sp .5v -.RE -.sp -.RS 4 -.ie n \{\ -\h'-04'\(bu\h'+03'\c -.\} -.el \{\ -.sp -1 -.IP \(bu 2.3 -.\} -Generate the SSL pem files: -.RE -.sp -.if n \{\ -.RS 4 -.\} -.nf -$ cd ~/\&.skyped -$ openssl req \-new \-x509 \-days 365 \-nodes \-config skyped\&.cnf \-out skyped\&.cert\&.pem \e - \-keyout skyped\&.key\&.pem -.fi -.if n \{\ -.RE -.\} -.sp -.RS 4 -.ie n \{\ -\h'-04'\(bu\h'+03'\c -.\} -.el \{\ -.sp -1 -.IP \(bu 2.3 -.\} -Start -skyped -(the TCP server), initially without detaching and enabling debug messages: -.RE -.sp -.if n \{\ -.RS 4 -.\} -.nf -$ skyped \-d \-n -.fi -.if n \{\ -.RE -.\} -.sp -.RS 4 -.ie n \{\ -\h'-04'\(bu\h'+03'\c -.\} -.el \{\ -.sp -1 -.IP \(bu 2.3 -.\} -Start your -IRC -client, connect to BitlBee and add your account: -.RE -.sp -.if n \{\ -.RS 4 -.\} -.nf -account add skype <user> <pass> -.fi -.if n \{\ -.RE -.\} -.sp -<user> should be your Skype account name, <pass> should be the one you declared in skyped\&.conf\&. -.SH "OPTIONS" -.PP -\-c, \-\-config -.RS 4 -Path to configuration file (default: $HOME/\&.skyped/skyped\&.conf) -.RE -.PP -\-d, \-\-debug -.RS 4 -Enable debug messages -.RE -.PP -\-h, \-\-help -.RS 4 -Show short summary of options -.RE -.PP -\-H, \-\-host -.RS 4 -Set the tcp host (default: 0\&.0\&.0\&.0) -.RE -.PP -\-l, \-\-log -.RS 4 -Set the log file in background mode (default: none) -.RE -.PP -\-m, \-\-mock=<file> -.RS 4 -Mock mode: replay session from file, instead of connecting to Skype\&. -.RE -.PP -\-n, \-\-nofork -.RS 4 -Don\(cqt run as daemon in the background -.RE -.PP -\-s, \-\-dont\-start\-skype -.RS 4 -Assume that skype is running independently, don\(cqt try to start/stop it\&. -.RE -.PP -\-p, \-\-port -.RS 4 -Set the tcp port (default: 2727) -.RE -.PP -\-v, \-\-version -.RS 4 -Display version information -.RE -.SH "AUTHOR" -.sp -Written by Miklos Vajna <vmiklos@vmiklos\&.hu> diff --git a/protocols/skype/skyped.cnf b/protocols/skype/skyped.cnf deleted file mode 100644 index c7dc9098..00000000 --- a/protocols/skype/skyped.cnf +++ /dev/null @@ -1,40 +0,0 @@ -# create RSA certs - Server - -RANDFILE = skyped.rnd - -[ req ] -default_bits = 1024 -encrypt_key = yes -distinguished_name = req_dn -x509_extensions = cert_type - -[ req_dn ] -countryName = Country Name (2 letter code) -countryName_default = HU -countryName_min = 2 -countryName_max = 2 - -stateOrProvinceName = State or Province Name (full name) -stateOrProvinceName_default = Some-State - -localityName = Locality Name (eg, city) - -0.organizationName = Organization Name (eg, company) -0.organizationName_default = Stunnel Developers Ltd - -organizationalUnitName = Organizational Unit Name (eg, section) -#organizationalUnitName_default = - -0.commonName = Common Name (FQDN of your server) -0.commonName_default = localhost - -# To create a certificate for more than one name uncomment: -# 1.commonName = DNS alias of your server -# 2.commonName = DNS alias of your server -# ... -# See http://home.netscape.com/eng/security/ssl_2.0_certificate.html -# to see how Netscape understands commonName. - -[ cert_type ] -nsCertType = server - diff --git a/protocols/skype/skyped.conf.dist b/protocols/skype/skyped.conf.dist deleted file mode 100644 index 21e07796..00000000 --- a/protocols/skype/skyped.conf.dist +++ /dev/null @@ -1,10 +0,0 @@ -[skyped] -# change to your skype username -username = john -# use `echo -n foo|sha1sum` to generate this hash for your password -password = 0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33 - -# you have to change the following paths to your home directory: -cert = /home/YOUR_USER/.skyped/skyped.cert.pem -key = /home/YOUR_USER/.skyped/skyped.key.pem -port = 2727 diff --git a/protocols/skype/skyped.py b/protocols/skype/skyped.py deleted file mode 100644 index c9bb103b..00000000 --- a/protocols/skype/skyped.py +++ /dev/null @@ -1,523 +0,0 @@ -#!/usr/bin/env python2.7 -# -# skyped.py -# -# Copyright (c) 2007-2013 by Miklos Vajna <vmiklos@vmiklos.hu> -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, -# USA. -# - -import sys -import os -import signal -import time -import socket -import Skype4Py -import hashlib -from ConfigParser import ConfigParser, NoOptionError -from traceback import print_exception -from fcntl import fcntl, F_SETFD, FD_CLOEXEC -import ssl - -__version__ = "0.1.1" - -try: - import gobject - hasgobject = True -except ImportError: - import select - import threading - hasgobject = False - -def eh(type, value, tb): - global options - - if type != KeyboardInterrupt: - print_exception(type, value, tb) - if hasgobject: - gobject.MainLoop().quit() - if options.conn: - options.conn.close() - if not options.dont_start_skype: - # shut down client if it's running - try: - skype.skype.Client.Shutdown() - except NameError: - pass - sys.exit("Exiting.") - -sys.excepthook = eh - -def wait_for_lock(lock, timeout_to_print, timeout, msg): - start = time.time() - locked = lock.acquire(0) - while not(locked): - time.sleep(0.5) - if timeout_to_print and (time.time() - timeout_to_print > start): - dprint("%s: Waited %f seconds" % \ - (msg, time.time() - start)) - timeout_to_print = False - if timeout and (time.time() - timeout > start): - dprint("%s: Waited %f seconds, giving up" % \ - (msg, time.time() - start)) - return False - locked = lock.acquire(0) - return True - -def input_handler(fd, io_condition = None): - global options - global skype - if options.buf: - for i in options.buf: - skype.send(i.strip()) - options.buf = None - if not hasgobject: - return True - else: - if not hasgobject: - close_socket = False - if wait_for_lock(options.lock, 3, 10, "input_handler"): - try: - input = fd.recv(1024) - options.lock.release() - except Exception, s: - dprint("Warning, receiving 1024 bytes failed (%s)." % s) - fd.close() - options.conn = False - options.lock.release() - return False - for i in input.split("\n"): - if i.strip() == "SET USERSTATUS OFFLINE": - close_socket = True - skype.send(i.strip()) - return not(close_socket) - try: - input = fd.recv(1024) - except Exception, s: - dprint("Warning, receiving 1024 bytes failed (%s)." % s) - fd.close() - return False - for i in input.split("\n"): - skype.send(i.strip()) - return True - -def skype_idle_handler(skype): - try: - c = skype.skype.Command("PING", Block=True) - skype.skype.SendCommand(c) - except (Skype4Py.SkypeAPIError, AttributeError), s: - dprint("Warning, pinging Skype failed (%s)." % (s)) - time.sleep(1) - return True - -def send(sock, txt, tries=10): - global options - if hasgobject: - if not options.conn: return - try: - done = sock.sendall(txt) - except socket.error as s: - dprint("Warning, sending '%s' failed (%s)." % (txt, s)) - options.conn.close() - options.conn = False - else: - for attempt in xrange(1, tries+1): - if not options.conn: break - if wait_for_lock(options.lock, 3, 10, "socket send"): - try: - if options.conn: done = sock.sendall(txt) - options.lock.release() - except socket.error as s: - options.lock.release() - dprint("Warning, sending '%s' failed (%s). count=%d" % (txt, s, count)) - time.sleep(1) - else: - break - else: - if options.conn: - options.conn.close() - options.conn = False - return done - -def bitlbee_idle_handler(skype): - global options - done = False - if options.conn: - try: - e = "PING" - done = send(options.conn, "%s\n" % e) - except Exception, s: - dprint("Warning, sending '%s' failed (%s)." % (e, s)) - if hasgobject: - options.conn.close() - else: - if options.conn: options.conn.close() - options.conn = False - done = False - if hasgobject: - return True - else: - return done - return True - -def server(host, port, skype = None): - global options - if ":" in host: - sock = socket.socket(socket.AF_INET6) - else: - sock = socket.socket() - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - fcntl(sock, F_SETFD, FD_CLOEXEC); - sock.bind((host, port)) - sock.listen(1) - - if hasgobject: - gobject.io_add_watch(sock, gobject.IO_IN, listener) - else: - dprint("Waiting for connection...") - listener(sock, skype) - -def listener(sock, skype): - global options - if not hasgobject: - if not(wait_for_lock(options.lock, 3, 10, "listener")): return False - rawsock, addr = sock.accept() - try: - options.conn = ssl.wrap_socket(rawsock, - server_side=True, - certfile=options.config.sslcert, - keyfile=options.config.sslkey, - ssl_version=ssl.PROTOCOL_TLSv1) - except (ssl.SSLError, socket.error) as err: - if isinstance(err, ssl.SSLError): - dprint("Warning, SSL init failed, did you create your certificate?") - return False - else: - dprint('Warning, SSL init failed') - return True - if hasattr(options.conn, 'handshake'): - try: - options.conn.handshake() - except Exception: - if not hasgobject: - options.lock.release() - dprint("Warning, handshake failed, closing connection.") - return False - ret = 0 - try: - line = options.conn.recv(1024) - if line.startswith("USERNAME") and line.split(' ')[1].strip() == options.config.username: - ret += 1 - line = options.conn.recv(1024) - if line.startswith("PASSWORD") and hashlib.sha1(line.split(' ')[1].strip()).hexdigest() == options.config.password: - ret += 1 - except Exception, s: - dprint("Warning, receiving 1024 bytes failed (%s)." % s) - options.conn.close() - if not hasgobject: - options.conn = False - options.lock.release() - return False - if ret == 2: - dprint("Username and password OK.") - options.conn.send("PASSWORD OK\n") - if hasgobject: - gobject.io_add_watch(options.conn, gobject.IO_IN, input_handler) - else: - options.lock.release() - serverloop(options, skype) - return True - else: - dprint("Username and/or password WRONG.") - options.conn.send("PASSWORD KO\n") - if not hasgobject: - options.conn.close() - options.conn = False - options.lock.release() - return False - -def dprint(msg): - from time import strftime - global options - - if options.debug: - import inspect - prefix = strftime("[%Y-%m-%d %H:%M:%S]") + " %s:%d" % inspect.stack()[1][1:3] - sanitized = msg - - try: - print prefix + ": " + msg - except Exception, s: - try: - sanitized = msg.encode("ascii", "backslashreplace") - except Error, s: - try: - sanitized = "hex [" + msg.encode("hex") + "]" - except Error, s: - sanitized = "[unable to print debug message]" - print prefix + "~=" + sanitized - - if options.log: - sock = open(options.log, "a") - sock.write("%s: %s\n" % (prefix, sanitized)) - sock.close() - - sys.stdout.flush() - -class MockedSkype: - """Mock class for Skype4Py.Skype(), in case the -m option is used.""" - def __init__(self, mock): - sock = open(mock) - self.lines = sock.readlines() - - def SendCommand(self, c): - pass - - def Command(self, msg, Block): - if msg == "PING": - return ["PONG"] - line = self.lines[0].strip() - if not line.startswith(">> "): - raise Exception("Corrupted mock input") - line = line[3:] - if line != msg: - raise Exception("'%s' != '%s'" % (line, msg)) - self.lines = self.lines[1:] # drop the expected incoming line - ret = [] - while True: - # and now send back all the following lines, up to the next expected incoming line - if len(self.lines) == 0: - break - if self.lines[0].startswith(">> "): - break - if not self.lines[0].startswith("<< "): - raise Exception("Corrupted mock input") - ret.append(self.lines[0][3:].strip()) - self.lines = self.lines[1:] - return ret - -class SkypeApi: - def __init__(self, mock): - global options - if not mock: - self.skype = Skype4Py.Skype() - self.skype.OnNotify = self.recv - if not options.dont_start_skype: - self.skype.Client.Start() - else: - self.skype = MockedSkype(mock) - - def recv(self, msg_text): - global options - if msg_text == "PONG": - return - if "\n" in msg_text: - # crappy skype prefixes only the first line for - # multiline messages so we need to do so for the other - # lines, too. this is something like: - # 'CHATMESSAGE id BODY first line\nsecond line' -> - # 'CHATMESSAGE id BODY first line\nCHATMESSAGE id BODY second line' - prefix = " ".join(msg_text.split(" ")[:3]) - msg_text = ["%s %s" % (prefix, i) for i in " ".join(msg_text.split(" ")[3:]).split("\n")] - else: - msg_text = [msg_text] - for i in msg_text: - try: - # Internally, BitlBee always uses UTF-8 and encodes/decodes as - # necessary to communicate with the IRC client; thus send the - # UTF-8 it expects - e = i.encode('UTF-8') - except: - # Should never happen, but it's better to send difficult to - # read data than crash because some message couldn't be encoded - e = i.encode('ascii', 'backslashreplace') - if options.conn: - dprint('<< ' + e) - try: - send(options.conn, e + "\n") - except Exception, s: - dprint("Warning, sending '%s' failed (%s)." % (e, s)) - if options.conn: options.conn.close() - options.conn = False - else: - dprint('-- ' + e) - - def send(self, msg_text): - if not len(msg_text) or msg_text == "PONG": - if msg_text == "PONG": - options.last_bitlbee_pong = time.time() - return - try: - # Internally, BitlBee always uses UTF-8 and encodes/decodes as - # necessary to communicate with the IRC client; thus decode the - # UTF-8 it sent us - e = msg_text.decode('UTF-8') - except: - # Should never happen, but it's better to send difficult to read - # data to Skype than to crash - e = msg_text.decode('ascii', 'backslashreplace') - dprint('>> ' + e) - try: - c = self.skype.Command(e, Block=True) - self.skype.SendCommand(c) - if hasattr(c, "Reply"): - self.recv(c.Reply) # Skype4Py answer - else: - for i in c: # mock may return multiple iterable answers - self.recv(i) - except Skype4Py.SkypeError: - pass - except Skype4Py.SkypeAPIError, s: - dprint("Warning, sending '%s' failed (%s)." % (e, s)) - - -def serverloop(options, skype): - timeout = 1; # in seconds - skype_ping_period = 5 - bitlbee_ping_period = 10 - bitlbee_pong_timeout = 30 - now = time.time() - skype_ping_start_time = now - bitlbee_ping_start_time = now - options.last_bitlbee_pong = now - in_error = [] - handler_ok = True - while (len(in_error) == 0) and handler_ok and options.conn: - ready_to_read, ready_to_write, in_error = \ - select.select([options.conn], [], [options.conn], \ - timeout) - now = time.time() - handler_ok = len(in_error) == 0 - if (len(ready_to_read) == 1) and handler_ok: - handler_ok = input_handler(ready_to_read.pop()) - # don't ping bitlbee/skype if they already received data - now = time.time() # allow for the input_handler to take some time - bitlbee_ping_start_time = now - skype_ping_start_time = now - options.last_bitlbee_pong = now - if (now - skype_ping_period > skype_ping_start_time) and handler_ok: - handler_ok = skype_idle_handler(skype) - skype_ping_start_time = now - if now - bitlbee_ping_period > bitlbee_ping_start_time: - handler_ok = bitlbee_idle_handler(skype) - bitlbee_ping_start_time = now - if options.last_bitlbee_pong: - if (now - options.last_bitlbee_pong) > bitlbee_pong_timeout: - dprint("Bitlbee pong timeout") - # TODO is following line necessary? Should there be a options.conn.unwrap() somewhere? - # options.conn.shutdown() - if options.conn: - options.conn.close() - options.conn = False - else: - options.last_bitlbee_pong = now - - -def main(args=None): - global options - global skype - - cfgpath = os.path.join(os.environ['HOME'], ".skyped", "skyped.conf") - syscfgpath = "/usr/local/etc/skyped/skyped.conf" - if not os.path.exists(cfgpath) and os.path.exists(syscfgpath): - cfgpath = syscfgpath # fall back to system-wide settings - port = 2727 - - import argparse - parser = argparse.ArgumentParser() - parser.add_argument('-c', '--config', - metavar='path', default=cfgpath, - help='path to configuration file (default: %(default)s)') - parser.add_argument('-H', '--host', default='0.0.0.0', - help='set the tcp host, supports IPv4 and IPv6 (default: %(default)s)') - parser.add_argument('-p', '--port', type=int, - help='set the tcp port (default: %(default)s)') - parser.add_argument('-l', '--log', metavar='path', - help='set the log file in background mode (default: none)') - parser.add_argument('-v', '--version', action='store_true', help='display version information') - parser.add_argument('-n', '--nofork', - action='store_true', help="don't run as daemon in the background") - parser.add_argument('-s', '--dont-start-skype', action='store_true', - help="assume that skype is running independently, don't try to start/stop it") - parser.add_argument('-m', '--mock', help='fake interactions with skype (only useful for tests)') - parser.add_argument('-d', '--debug', action='store_true', help='enable debug messages') - options = parser.parse_args(sys.argv[1:] if args is None else args) - - if options.version: - print "skyped %s" % __version__ - sys.exit(0) - - # well, this is a bit hackish. we store the socket of the last connected client - # here and notify it. maybe later notify all connected clients? - options.conn = None - # this will be read first by the input handler - options.buf = None - - if not os.path.exists(options.config): - parser.error(( "Can't find configuration file at '%s'. " - "Use the -c option to specify an alternate one." )% options.config) - - cfgpath = options.config - options.config = ConfigParser() - options.config.read(cfgpath) - options.config.username = options.config.get('skyped', 'username').split('#', 1)[0] - options.config.password = options.config.get('skyped', 'password').split('#', 1)[0] - options.config.sslkey = os.path.expanduser(options.config.get('skyped', 'key').split('#', 1)[0]) - options.config.sslcert = os.path.expanduser(options.config.get('skyped', 'cert').split('#', 1)[0]) - - # hack: we have to parse the parameters first to locate the - # config file but the -p option should overwrite the value from - # the config file - try: - options.config.port = int(options.config.get('skyped', 'port').split('#', 1)[0]) - if not options.port: - options.port = options.config.port - except NoOptionError: - pass - if not options.port: - options.port = port - dprint("Parsing config file '%s' done, username is '%s'." % (cfgpath, options.config.username)) - if not options.nofork: - pid = os.fork() - if pid == 0: - nullin = file(os.devnull, 'r') - nullout = file(os.devnull, 'w') - os.dup2(nullin.fileno(), sys.stdin.fileno()) - os.dup2(nullout.fileno(), sys.stdout.fileno()) - os.dup2(nullout.fileno(), sys.stderr.fileno()) - else: - print 'skyped is started on port %s, pid: %d' % (options.port, pid) - sys.exit(0) - else: - dprint('skyped is started on port %s' % options.port) - if hasgobject: - server(options.host, options.port) - try: - skype = SkypeApi(options.mock) - except Skype4Py.SkypeAPIError, s: - sys.exit("%s. Are you sure you have started Skype?" % s) - if hasgobject: - gobject.timeout_add(2000, skype_idle_handler, skype) - gobject.timeout_add(60000, bitlbee_idle_handler, skype) - gobject.MainLoop().run() - else: - while 1: - options.conn = False - options.lock = threading.Lock() - server(options.host, options.port, skype) - - -if __name__ == '__main__': main() diff --git a/protocols/skype/skyped.txt b/protocols/skype/skyped.txt deleted file mode 100644 index c5f9abb9..00000000 --- a/protocols/skype/skyped.txt +++ /dev/null @@ -1,88 +0,0 @@ -= skyped(1) - -== NAME - -skyped - allows remote control of the Skype GUI client - -== SYNOPSIS - -skyped [<options>] - -== DESCRIPTION - -Skype supports remote control of the GUI client only via X11 or DBus -messages. This is hard in case you want remote control. This daemon -listens on a TCP port and runs on the same machine where the GUI client -runs. It passes all the input it gets to Skype directly, except for a -few commands which is related to authentication. The whole communication -is done via SSL. - -== CONFIGURATION - -- Set up `~/.skyped/skyped.conf`: Create the `~/.skyped` directory, copy - `skyped.conf` and `skyped.cnf` from `/usr/local/etc/skyped/` to `~/.skyped`, - adjust `username` and `password`. The `username` should be your Skype login and - the `password` can be whatever you want, but you will have to specify that one - when adding the Skype account to BitlBee (see later). - -NOTE: Here, and later - `/usr/local/etc` can be different on your installation -if you used the `--sysconfdir` switch when running the `configure` of BitlBee. - -- Generate the SSL pem files: - ----- -$ cd ~/.skyped -$ openssl req -new -x509 -days 365 -nodes -config skyped.cnf -out skyped.cert.pem \ - -keyout skyped.key.pem ----- - -- Start `skyped` (the TCP server), initially without detaching and enabling debug messages: - ----- -$ skyped -d -n ----- - -- Start your `IRC` client, connect to BitlBee and add your account: - ----- -account add skype <user> <pass> ----- - -`<user>` should be your Skype account name, `<pass>` should be the one you declared -in `skyped.conf`. - -== OPTIONS - --c, --config:: - Path to configuration file (default: $HOME/.skyped/skyped.conf) - --d, --debug:: - Enable debug messages - --h, --help:: - Show short summary of options - --H, --host:: - Set the tcp host (default: 0.0.0.0) - --l, --log:: - Set the log file in background mode (default: none) - --m, --mock=<file>:: - Mock mode: replay session from file, instead of connecting to Skype. - --n, --nofork:: - Don't run as daemon in the background - --s, --dont-start-skype:: - Assume that skype is running independently, don't try to start/stop it. - --p, --port:: - Set the tcp port (default: 2727) - --v, --version:: - Display version information - -== AUTHOR - -Written by Miklos Vajna <vmiklos@vmiklos.hu> diff --git a/protocols/skype/t/add-yes-bitlbee.mock b/protocols/skype/t/add-yes-bitlbee.mock deleted file mode 100644 index 60eccfc2..00000000 --- a/protocols/skype/t/add-yes-bitlbee.mock +++ /dev/null @@ -1,8 +0,0 @@ ->> NOTICE * -<< NICK alice -<< USER alice alice localhost :Alice ->> PRIVMSG &bitlbee -<< PRIVMSG &bitlbee :account add skype alice foo -<< PRIVMSG &bitlbee :account skype on -<< PRIVMSG &bitlbee :add skype bob ->> :bob!bob@skype.com JOIN :&bitlbee diff --git a/protocols/skype/t/add-yes-skyped.mock b/protocols/skype/t/add-yes-skyped.mock deleted file mode 100644 index dea175a3..00000000 --- a/protocols/skype/t/add-yes-skyped.mock +++ /dev/null @@ -1,23 +0,0 @@ ->> SEARCH GROUPS CUSTOM -<< GROUPS 48, 49 ->> SEARCH FRIENDS -<< USERS echo123 ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> GET USER echo123 ONLINESTATUS -<< USER echo123 ONLINESTATUS ONLINE ->> GET USER echo123 FULLNAME -<< USER echo123 FULLNAME Echo / Sound Test Service ->> SET USER bob BUDDYSTATUS 2 Please authorize me -<< USER bob BUDDYSTATUS 2 -<< USER bob ISAUTHORIZED TRUE -<< USER bob ISBLOCKED FALSE -<< USER bob BUDDYSTATUS 2 -<< USER bob ONLINESTATUS OFFLINE -<< USER bob FULLNAME skype test203 -<< USER bob BUDDYSTATUS 3 -<< USER bob ONLINESTATUS OFFLINE -<< USER bob ONLINESTATUS ONLINE -<< USER bob TIMEZONE 90000 diff --git a/protocols/skype/t/added-no-bitlbee.mock b/protocols/skype/t/added-no-bitlbee.mock deleted file mode 100644 index f96c7ec7..00000000 --- a/protocols/skype/t/added-no-bitlbee.mock +++ /dev/null @@ -1,9 +0,0 @@ ->> NOTICE * -<< NICK alice -<< USER alice alice localhost :Alice ->> PRIVMSG &bitlbee -<< PRIVMSG &bitlbee :account add skype alice foo -<< PRIVMSG &bitlbee :account skype on ->> PRIVMSG &bitlbee :skype - New request: The user bob wants to add you -<< PRIVMSG &bitlbee :no ->> PRIVMSG &bitlbee :skype - Rejected diff --git a/protocols/skype/t/added-no-skyped.mock b/protocols/skype/t/added-no-skyped.mock deleted file mode 100644 index 0e4bfc8a..00000000 --- a/protocols/skype/t/added-no-skyped.mock +++ /dev/null @@ -1,15 +0,0 @@ ->> SEARCH GROUPS CUSTOM -<< GROUPS 48, 49 ->> SEARCH FRIENDS -<< USERS echo123 ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> GET USER echo123 ONLINESTATUS -<< USER echo123 ONLINESTATUS ONLINE ->> GET USER echo123 FULLNAME -<< USER echo123 FULLNAME Echo / Sound Test Service -<< USER bob RECEIVEDAUTHREQUEST Please allow me to see when you are online ->> SET USER bob ISAUTHORIZED FALSE -<< USER bob ISAUTHORIZED FALSE diff --git a/protocols/skype/t/added-yes-bitlbee.mock b/protocols/skype/t/added-yes-bitlbee.mock deleted file mode 100644 index 690dd77b..00000000 --- a/protocols/skype/t/added-yes-bitlbee.mock +++ /dev/null @@ -1,9 +0,0 @@ ->> NOTICE * -<< NICK alice -<< USER alice alice localhost :Alice ->> PRIVMSG &bitlbee -<< PRIVMSG &bitlbee :account add skype alice foo -<< PRIVMSG &bitlbee :account skype on ->> PRIVMSG &bitlbee :skype - New request: The user bob wants to add you -<< PRIVMSG &bitlbee :yes ->> :bob!bob@skype.com JOIN :&bitlbee diff --git a/protocols/skype/t/added-yes-skyped.mock b/protocols/skype/t/added-yes-skyped.mock deleted file mode 100644 index fc3d756f..00000000 --- a/protocols/skype/t/added-yes-skyped.mock +++ /dev/null @@ -1,25 +0,0 @@ ->> SEARCH GROUPS CUSTOM -<< GROUPS 48, 49 ->> SEARCH FRIENDS -<< USERS echo123 ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> GET USER echo123 ONLINESTATUS -<< USER echo123 ONLINESTATUS ONLINE ->> GET USER echo123 FULLNAME -<< USER echo123 FULLNAME Echo / Sound Test Service -<< USER bob RECEIVEDAUTHREQUEST Please allow me to see when you are online ->> SET USER bob ISAUTHORIZED TRUE -<< USER bob ISAUTHORIZED TRUE -<< USER bob RECEIVEDAUTHREQUEST -<< USER bob ISAUTHORIZED TRUE -<< USER bob ISBLOCKED FALSE -<< USER bob BUDDYSTATUS 3 -<< USER bob ONLINESTATUS OFFLINE -<< USER bob ONLINESTATUS ONLINE -<< USER bob TIMEZONE 90000 -<< USER bob FULLNAME Miklos V -<< USER bob LANGUAGE hu Hungarian -<< USER bob COUNTRY hu Hungary diff --git a/protocols/skype/t/away-set-bitlbee.mock b/protocols/skype/t/away-set-bitlbee.mock deleted file mode 100644 index 9212fcd3..00000000 --- a/protocols/skype/t/away-set-bitlbee.mock +++ /dev/null @@ -1,10 +0,0 @@ ->> NOTICE * -<< NICK alice -<< USER alice alice localhost :Alice ->> PRIVMSG &bitlbee -<< PRIVMSG &bitlbee :account add skype alice foo -<< PRIVMSG &bitlbee :account skype set skypeconsole_receive true -<< PRIVMSG &bitlbee :account skype on ->> PRIVMSG &bitlbee :skype - Logging in: Logged in -<< AWAY :work ->> PRIVMSG &bitlbee :alice: USERSTATUS AWAY diff --git a/protocols/skype/t/away-set-skyped.mock b/protocols/skype/t/away-set-skyped.mock deleted file mode 100644 index 0c2cc494..00000000 --- a/protocols/skype/t/away-set-skyped.mock +++ /dev/null @@ -1,20 +0,0 @@ ->> SEARCH GROUPS CUSTOM -<< GROUPS 48, 49 ->> SEARCH FRIENDS -<< USERS echo123, bob ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> GET USER echo123 ONLINESTATUS -<< USER echo123 ONLINESTATUS ONLINE ->> GET USER echo123 FULLNAME -<< USER echo123 FULLNAME Echo / Sound Test Service ->> GET USER bob ONLINESTATUS -<< USER bob ONLINESTATUS ONLINE ->> GET USER bob FULLNAME -<< USER bob FULLNAME Bob ->> SET USERSTATUS AWAY -<< USERSTATUS AWAY -<< USER alice ONLINESTATUS AWAY -<< USERSTATUS AWAY diff --git a/protocols/skype/t/call-bitlbee.mock b/protocols/skype/t/call-bitlbee.mock deleted file mode 100644 index 5171dd65..00000000 --- a/protocols/skype/t/call-bitlbee.mock +++ /dev/null @@ -1,11 +0,0 @@ ->> NOTICE * -<< NICK alice -<< USER alice alice localhost :alice ->> PRIVMSG &bitlbee -<< PRIVMSG &bitlbee :account add skype alice foo -<< PRIVMSG &bitlbee :account skype on ->> :bob!bob@skype.com JOIN :&bitlbee -<< PRIVMSG bob :CALL ->> PRIVMSG &bitlbee :skype - You are currently ringing the user bob. -<< PRIVMSG bob :HANGUP ->> PRIVMSG &bitlbee :skype - You cancelled the call to the user bob. diff --git a/protocols/skype/t/call-failed-bitlbee.mock b/protocols/skype/t/call-failed-bitlbee.mock deleted file mode 100644 index 5ba71117..00000000 --- a/protocols/skype/t/call-failed-bitlbee.mock +++ /dev/null @@ -1,9 +0,0 @@ ->> NOTICE * -<< NICK alice -<< USER alice alice localhost :alice ->> PRIVMSG &bitlbee -<< PRIVMSG &bitlbee :account add skype alice foo -<< PRIVMSG &bitlbee :account skype on ->> PRIVMSG &bitlbee :skype - Logging in: Logged in -<< PRIVMSG bob :CALL ->> PRIVMSG &bitlbee :skype - Error: Call failed: User is offline diff --git a/protocols/skype/t/call-failed-skyped.mock b/protocols/skype/t/call-failed-skyped.mock deleted file mode 100644 index 30699f91..00000000 --- a/protocols/skype/t/call-failed-skyped.mock +++ /dev/null @@ -1,21 +0,0 @@ ->> SEARCH GROUPS CUSTOM -<< GROUPS 48, 49 ->> SEARCH FRIENDS -<< USERS echo123, bob ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> GET USER echo123 ONLINESTATUS -<< USER echo123 ONLINESTATUS ONLINE ->> GET USER echo123 FULLNAME -<< USER echo123 FULLNAME Echo / Sound Test Service ->> GET USER bob ONLINESTATUS -<< USER bob ONLINESTATUS OFFLINE ->> GET USER bob FULLNAME -<< USER bob FULLNAME Bob ->> CALL bob -<< CALL 216 STATUS UNPLACED -<< CALL 216 STATUS ROUTING -<< CALL 216 FAILUREREASON 3 -<< CALL 216 STATUS FAILED diff --git a/protocols/skype/t/call-skyped.mock b/protocols/skype/t/call-skyped.mock deleted file mode 100644 index 92947ba9..00000000 --- a/protocols/skype/t/call-skyped.mock +++ /dev/null @@ -1,26 +0,0 @@ ->> SEARCH GROUPS CUSTOM -<< GROUPS 48, 49 ->> SEARCH FRIENDS -<< USERS echo123, bob ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> GET USER echo123 ONLINESTATUS -<< USER echo123 ONLINESTATUS OFFLINE ->> GET USER echo123 FULLNAME -<< USER echo123 FULLNAME Echo / Sound Test Service ->> GET USER bob ONLINESTATUS -<< USER bob ONLINESTATUS ONLINE ->> GET USER bob FULLNAME -<< USER bob FULLNAME Bob ->> CALL bob -<< CALL 178 STATUS UNPLACED -<< CALL 178 STATUS ROUTING -<< CALL 178 STATUS RINGING ->> GET CALL 178 PARTNER_HANDLE -<< CALL 178 PARTNER_HANDLE bob ->> SET CALL 178 STATUS FINISHED -<< CALL 178 STATUS CANCELLED ->> GET CALL 178 PARTNER_HANDLE -<< CALL 178 PARTNER_HANDLE bob diff --git a/protocols/skype/t/called-no-bitlbee.mock b/protocols/skype/t/called-no-bitlbee.mock deleted file mode 100644 index 00f7a8f8..00000000 --- a/protocols/skype/t/called-no-bitlbee.mock +++ /dev/null @@ -1,10 +0,0 @@ ->> NOTICE * -<< NICK alice -<< USER alice alice localhost :Alice ->> PRIVMSG &bitlbee -<< PRIVMSG &bitlbee :account add skype alice foo -<< PRIVMSG &bitlbee :account skype on ->> PRIVMSG &bitlbee :skype - New request: The user bob is currently ringing you. -<< PRIVMSG &bitlbee :no ->> PRIVMSG &bitlbee :skype - Rejected: The user bob is currently ringing you. ->> PRIVMSG &bitlbee :skype - You refused the call from user bob. diff --git a/protocols/skype/t/called-no-skyped.mock b/protocols/skype/t/called-no-skyped.mock deleted file mode 100644 index 5152fe9e..00000000 --- a/protocols/skype/t/called-no-skyped.mock +++ /dev/null @@ -1,24 +0,0 @@ ->> SEARCH GROUPS CUSTOM -<< GROUPS 48, 49 ->> SEARCH FRIENDS -<< USERS echo123, bob ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> GET USER echo123 ONLINESTATUS -<< USER echo123 ONLINESTATUS ONLINE ->> GET USER echo123 FULLNAME -<< USER echo123 FULLNAME Echo / Sound Test Service ->> GET USER bob ONLINESTATUS -<< USER bob ONLINESTATUS ONLINE ->> GET USER bob FULLNAME -<< USER bob FULLNAME Bob -<< CALL 212 CONF_ID 0 -<< CALL 212 STATUS RINGING ->> GET CALL 212 PARTNER_HANDLE -<< CALL 212 PARTNER_HANDLE bob ->> SET CALL 212 STATUS FINISHED -<< CALL 212 STATUS REFUSED ->> GET CALL 212 PARTNER_HANDLE -<< CALL 212 PARTNER_HANDLE bob diff --git a/protocols/skype/t/called-yes-bitlbee.mock b/protocols/skype/t/called-yes-bitlbee.mock deleted file mode 100644 index 288547dd..00000000 --- a/protocols/skype/t/called-yes-bitlbee.mock +++ /dev/null @@ -1,9 +0,0 @@ ->> NOTICE * -<< NICK alice -<< USER alice alice localhost :Alice ->> PRIVMSG &bitlbee -<< PRIVMSG &bitlbee :account add skype alice foo -<< PRIVMSG &bitlbee :account skype on ->> PRIVMSG &bitlbee :skype - New request: The user bob is currently ringing you. -<< PRIVMSG &bitlbee :yes ->> PRIVMSG &bitlbee :skype - Accepted: The user bob is currently ringing you. diff --git a/protocols/skype/t/called-yes-skyped.mock b/protocols/skype/t/called-yes-skyped.mock deleted file mode 100644 index 67cdffe3..00000000 --- a/protocols/skype/t/called-yes-skyped.mock +++ /dev/null @@ -1,22 +0,0 @@ ->> SEARCH GROUPS CUSTOM -<< GROUPS 48, 49 ->> SEARCH FRIENDS -<< USERS echo123, bob ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> GET USER echo123 ONLINESTATUS -<< USER echo123 ONLINESTATUS ONLINE ->> GET USER echo123 FULLNAME -<< USER echo123 FULLNAME Echo / Sound Test Service ->> GET USER bob ONLINESTATUS -<< USER bob ONLINESTATUS ONLINE ->> GET USER bob FULLNAME -<< USER bob FULLNAME Bob -<< CALL 208 CONF_ID 0 -<< CALL 208 STATUS RINGING ->> GET CALL 208 PARTNER_HANDLE -<< CALL 208 PARTNER_HANDLE bob ->> SET CALL 208 STATUS INPROGRESS -<< CALL 208 STATUS INPROGRESS diff --git a/protocols/skype/t/ctcp-help-bitlbee.mock b/protocols/skype/t/ctcp-help-bitlbee.mock deleted file mode 100644 index fa471bd3..00000000 --- a/protocols/skype/t/ctcp-help-bitlbee.mock +++ /dev/null @@ -1,9 +0,0 @@ ->> NOTICE * -<< NICK alice -<< USER alice alice localhost :Alice ->> PRIVMSG &bitlbee -<< PRIVMSG &bitlbee :account add skype alice foo -<< PRIVMSG &bitlbee :account skype on ->> :bob!bob@skype.com JOIN :&bitlbee -<< PRIVMSG bob :HELP ->> :bob!bob@skype.com NOTICE alice :HELP Supported CTCPs: HANGUP (Hang up a call), CALL (Initiate a call) diff --git a/protocols/skype/t/ctcp-help-skyped.mock b/protocols/skype/t/ctcp-help-skyped.mock deleted file mode 100644 index eacff2e6..00000000 --- a/protocols/skype/t/ctcp-help-skyped.mock +++ /dev/null @@ -1,16 +0,0 @@ ->> SEARCH GROUPS CUSTOM -<< GROUPS 48, 49 ->> SEARCH FRIENDS -<< USERS echo123, bob ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> GET USER echo123 ONLINESTATUS -<< USER echo123 ONLINESTATUS ONLINE ->> GET USER echo123 FULLNAME -<< USER echo123 FULLNAME Echo / Sound Test Service ->> GET USER bob ONLINESTATUS -<< USER bob ONLINESTATUS ONLINE ->> GET USER bob FULLNAME -<< USER bob FULLNAME Bob diff --git a/protocols/skype/t/filetransfer-bitlbee.mock b/protocols/skype/t/filetransfer-bitlbee.mock deleted file mode 100644 index 0c7f5e15..00000000 --- a/protocols/skype/t/filetransfer-bitlbee.mock +++ /dev/null @@ -1,10 +0,0 @@ ->> NOTICE * -<< NICK alice -<< USER alice alice localhost :Alice ->> PRIVMSG &bitlbee -<< PRIVMSG &bitlbee :account add skype alice foo -<< PRIVMSG &bitlbee :account skype on ->> :bob!bob@skype.com JOIN :&bitlbee ->> PRIVMSG &bitlbee :skype - The user bob offered a new file for you. ->> PRIVMSG &bitlbee :skype - File transfer from user bob started, saving to /home/alice/text.odt. ->> PRIVMSG &bitlbee :skype - File transfer from user bob completed. diff --git a/protocols/skype/t/filetransfer-skyped.mock b/protocols/skype/t/filetransfer-skyped.mock deleted file mode 100644 index b24fcc94..00000000 --- a/protocols/skype/t/filetransfer-skyped.mock +++ /dev/null @@ -1,37 +0,0 @@ ->> SEARCH GROUPS CUSTOM -<< GROUPS 48, 49 ->> SEARCH FRIENDS -<< USERS echo123, bob ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> GET USER echo123 ONLINESTATUS -<< USER echo123 ONLINESTATUS ONLINE ->> GET USER echo123 FULLNAME -<< USER echo123 FULLNAME Echo / Sound Test Service ->> GET USER bob ONLINESTATUS -<< USER bob ONLINESTATUS ONLINE ->> GET USER bob FULLNAME -<< USER bob FULLNAME Bob -<< FILETRANSFER 208 TYPE INCOMING -<< FILETRANSFER 208 PARTNER_HANDLE bob -<< FILETRANSFER 208 PARTNER_DISPNAME bob -<< FILETRANSFER 208 FILENAME text.odt -<< FILETRANSFER 208 STATUS NEW -<< FILETRANSFER 208 FILESIZE 83534193 -<< FILETRANSFER 208 STARTTIME 1358458276 -<< FILETRANSFER 208 FINISHTIME 0 -<< FILETRANSFER 208 BYTESPERSECOND 0 -<< FILETRANSFER 208 BYTESTRANSFERRED 0 -<< FILETRANSFER 208 FILESIZE 83534193 ->> GET FILETRANSFER 208 PARTNER_HANDLE -<< FILETRANSFER 208 PARTNER_HANDLE bob -<< FILETRANSFER 208 FILEPATH /home/alice/text.odt -<< FILETRANSFER 208 STATUS CONNECTING -<< FILETRANSFER 208 STATUS TRANSFERRING ->> GET FILETRANSFER 208 PARTNER_HANDLE -<< FILETRANSFER 208 PARTNER_HANDLE bob -<< FILETRANSFER 208 STATUS COMPLETED ->> GET FILETRANSFER 208 PARTNER_HANDLE -<< FILETRANSFER 208 PARTNER_HANDLE bob diff --git a/protocols/skype/t/group-add-bitlbee.mock b/protocols/skype/t/group-add-bitlbee.mock deleted file mode 100644 index 0de88f09..00000000 --- a/protocols/skype/t/group-add-bitlbee.mock +++ /dev/null @@ -1,14 +0,0 @@ ->> NOTICE * -<< NICK alice -<< USER alice alice localhost :Alice ->> PRIVMSG &bitlbee -<< PRIVMSG &bitlbee :account add skype alice foo -<< PRIVMSG &bitlbee :account skype set read_groups true -<< PRIVMSG &bitlbee :account skype on ->> :bob!bob@skype.com JOIN :&bitlbee ->> :cecil!cecil@skype.com JOIN :&bitlbee ->> :daniel!daniel@skype.com JOIN :&bitlbee -<< JOIN &family ->> 353 alice = &family :@alice +bob +cecil @root -<< INVITE daniel &family ->> :daniel!daniel@skype.com JOIN :&family diff --git a/protocols/skype/t/group-add-skyped.mock b/protocols/skype/t/group-add-skyped.mock deleted file mode 100644 index c47f6629..00000000 --- a/protocols/skype/t/group-add-skyped.mock +++ /dev/null @@ -1,38 +0,0 @@ ->> SEARCH GROUPS CUSTOM -<< GROUPS 70, 71 ->> SEARCH FRIENDS -<< USERS echo123, bob, cecil, daniel, emily ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> GET GROUP 70 DISPLAYNAME -<< GROUP 70 DISPLAYNAME Family ->> GET GROUP 70 USERS -<< GROUP 70 USERS bob, cecil ->> GET GROUP 71 DISPLAYNAME -<< GROUP 71 DISPLAYNAME Work ->> GET GROUP 71 USERS -<< GROUP 71 USERS daniel, emily ->> GET USER echo123 ONLINESTATUS -<< USER echo123 ONLINESTATUS ONLINE ->> GET USER echo123 FULLNAME -<< USER echo123 FULLNAME Echo / Sound Test Service ->> GET USER bob ONLINESTATUS -<< USER bob ONLINESTATUS ONLINE ->> GET USER bob FULLNAME -<< USER bob FULLNAME Bob ->> GET USER cecil ONLINESTATUS -<< USER cecil ONLINESTATUS ONLINE ->> GET USER cecil FULLNAME -<< USER cecil FULLNAME Cecil ->> GET USER daniel ONLINESTATUS -<< USER daniel ONLINESTATUS ONLINE ->> GET USER daniel FULLNAME -<< USER daniel FULLNAME Daniel ->> GET USER emily ONLINESTATUS -<< USER emily ONLINESTATUS OFFLINE ->> GET USER emily FULLNAME -<< USER emily FULLNAME Emily ->> ALTER GROUP 70 ADDUSER daniel -<< ALTER GROUP 70 ADDUSER daniel diff --git a/protocols/skype/t/group-read-bitlbee.mock b/protocols/skype/t/group-read-bitlbee.mock deleted file mode 100644 index 7ca8bbc0..00000000 --- a/protocols/skype/t/group-read-bitlbee.mock +++ /dev/null @@ -1,14 +0,0 @@ ->> NOTICE * -<< NICK alice -<< USER alice alice localhost :Alice ->> PRIVMSG &bitlbee -<< PRIVMSG &bitlbee :account add skype alice foo -<< PRIVMSG &bitlbee :account skype set read_groups true -<< PRIVMSG &bitlbee :account skype on ->> :bob!bob@skype.com JOIN :&bitlbee ->> :cecil!cecil@skype.com JOIN :&bitlbee ->> :daniel!daniel@skype.com JOIN :&bitlbee -<< JOIN &family ->> 353 alice = &family :@alice +bob +cecil @root -<< JOIN &work ->> 353 alice = &work :@alice +daniel @root diff --git a/protocols/skype/t/group-read-skyped.mock b/protocols/skype/t/group-read-skyped.mock deleted file mode 100644 index 148661a1..00000000 --- a/protocols/skype/t/group-read-skyped.mock +++ /dev/null @@ -1,36 +0,0 @@ ->> SEARCH GROUPS CUSTOM -<< GROUPS 70, 71 ->> SEARCH FRIENDS -<< USERS echo123, bob, cecil, daniel, emily ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> GET GROUP 70 DISPLAYNAME -<< GROUP 70 DISPLAYNAME Family ->> GET GROUP 70 USERS -<< GROUP 70 USERS bob, cecil ->> GET GROUP 71 DISPLAYNAME -<< GROUP 71 DISPLAYNAME Work ->> GET GROUP 71 USERS -<< GROUP 71 USERS daniel, emily ->> GET USER echo123 ONLINESTATUS -<< USER echo123 ONLINESTATUS ONLINE ->> GET USER echo123 FULLNAME -<< USER echo123 FULLNAME Echo / Sound Test Service ->> GET USER bob ONLINESTATUS -<< USER bob ONLINESTATUS ONLINE ->> GET USER bob FULLNAME -<< USER bob FULLNAME Bob ->> GET USER cecil ONLINESTATUS -<< USER cecil ONLINESTATUS ONLINE ->> GET USER cecil FULLNAME -<< USER cecil FULLNAME Cecil ->> GET USER daniel ONLINESTATUS -<< USER daniel ONLINESTATUS ONLINE ->> GET USER daniel FULLNAME -<< USER daniel FULLNAME Daniel ->> GET USER emily ONLINESTATUS -<< USER emily ONLINESTATUS OFFLINE ->> GET USER emily FULLNAME -<< USER emily FULLNAME Emily diff --git a/protocols/skype/t/groupchat-invite-bitlbee.mock b/protocols/skype/t/groupchat-invite-bitlbee.mock deleted file mode 100644 index b79a8faa..00000000 --- a/protocols/skype/t/groupchat-invite-bitlbee.mock +++ /dev/null @@ -1,11 +0,0 @@ ->> NOTICE * -<< NICK alice -<< USER alice alice localhost :Alice ->> PRIVMSG &bitlbee -<< PRIVMSG &bitlbee :account add skype alice foo -<< PRIVMSG &bitlbee :account skype on ->> :bob!bob@skype.com JOIN :&bitlbee -<< PRIVMSG &bitlbee :chat with bob ->> 353 alice = ##alice/$bob;a7ab206ec78 :@alice @root -<< INVITE cecil ##alice/$bob;a7ab206ec78 ->> cecil@skype.com JOIN :##alice/$bob;a7ab206ec78 diff --git a/protocols/skype/t/groupchat-invite-skyped.mock b/protocols/skype/t/groupchat-invite-skyped.mock deleted file mode 100644 index 472c6801..00000000 --- a/protocols/skype/t/groupchat-invite-skyped.mock +++ /dev/null @@ -1,50 +0,0 @@ ->> SEARCH GROUPS CUSTOM -<< GROUPS 48, 49 ->> SEARCH FRIENDS -<< USERS echo123, bob, cecil ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> GET USER echo123 ONLINESTATUS -<< USER echo123 ONLINESTATUS ONLINE ->> GET USER echo123 FULLNAME -<< USER echo123 FULLNAME Echo / Sound Test Service ->> GET USER bob ONLINESTATUS -<< USER bob ONLINESTATUS ONLINE ->> GET USER bob FULLNAME -<< USER bob FULLNAME Bob ->> GET USER cecil ONLINESTATUS -<< USER cecil ONLINESTATUS ONLINE ->> GET USER cecil FULLNAME -<< USER cecil FULLNAME Cecil ->> CHAT CREATE bob -<< CHAT #alice/$bob;a7ab206ec78060f1 STATUS DIALOG ->> GET CHAT #alice/$bob;a7ab206ec78060f1 ADDER -<< CHAT #alice/$bob;a7ab206ec78060f1 ADDER -<< CHAT #alice/$bob;a7ab206ec78060f1 NAME #alice/$bob;a7ab206ec78060f1 ->> GET CHAT #alice/$bob;a7ab206ec78060f1 TOPIC -<< CHAT #alice/$bob;a7ab206ec78060f1 TOPIC ->> GET CHAT #alice/$bob;a7ab206ec78060f1 ACTIVEMEMBERS -<< CHAT #alice/$bob;a7ab206ec78060f1 ACTIVEMEMBERS -<< CHATMESSAGE 206 STATUS SENDING -<< CHAT #alice/$bob;a7ab206ec78060f1 STATUS DIALOG -<< CHATMEMBER 204 ROLE USER -<< CHAT #alice/$bob;a7ab206ec78060f1 MYROLE USER -<< CHAT #alice/$bob;a7ab206ec78060f1 MEMBERS bob alice -<< CHAT #alice/$bob;a7ab206ec78060f1 ACTIVEMEMBERS alice -<< CHAT #alice/$bob;a7ab206ec78060f1 STATUS DIALOG -<< CHAT #alice/$bob;a7ab206ec78060f1 TIMESTAMP 1358344213 -<< CHAT #alice/$bob;a7ab206ec78060f1 DIALOG_PARTNER bob -<< CHAT #alice/$bob;a7ab206ec78060f1 MEMBERS bob alice -<< CHAT #alice/$bob;a7ab206ec78060f1 FRIENDLYNAME bob ->> ALTER CHAT #alice/$bob;a7ab206ec78060f1 ADDMEMBERS cecil -<< ALTER CHAT ADDMEMBERS -<< CHAT #alice/$bob;a7ab206ec78060f1 STATUS MULTI_SUBSCRIBED -<< CHAT #alice/$bob;a7ab206ec78060f1 MEMBERS bob cecil alice ->> GET CHAT #alice/$bob;a7ab206ec78060f1 ADDER -<< CHAT #alice/$bob;a7ab206ec78060f1 ADDER -<< CHAT #alice/$bob;a7ab206ec78060f1 FRIENDLYNAME bob, cecil ->> GET CHAT #alice/$bob;a7ab206ec78060f1 TOPIC -<< CHAT #alice/$bob;a7ab206ec78060f1 TOPIC -<< CHATMESSAGE 210 STATUS SENDING diff --git a/protocols/skype/t/groupchat-invited-bitlbee.mock b/protocols/skype/t/groupchat-invited-bitlbee.mock deleted file mode 100644 index 344d5f71..00000000 --- a/protocols/skype/t/groupchat-invited-bitlbee.mock +++ /dev/null @@ -1,8 +0,0 @@ ->> NOTICE * -<< NICK alice -<< USER alice alice localhost :Alice ->> PRIVMSG &bitlbee -<< PRIVMSG &bitlbee :account add skype alice foo -<< PRIVMSG &bitlbee :account skype on ->> JOIN :##cecil/$bob;4d8cc996579 ->> 353 alice = ##cecil/$bob;4d8cc996579 :@alice @root diff --git a/protocols/skype/t/groupchat-invited-skyped.mock b/protocols/skype/t/groupchat-invited-skyped.mock deleted file mode 100644 index a5c754ce..00000000 --- a/protocols/skype/t/groupchat-invited-skyped.mock +++ /dev/null @@ -1,58 +0,0 @@ ->> SEARCH GROUPS CUSTOM -<< GROUPS 48, 49 ->> SEARCH FRIENDS -<< USERS echo123, bob, cecil ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> GET USER echo123 ONLINESTATUS -<< USER echo123 ONLINESTATUS ONLINE ->> GET USER echo123 FULLNAME -<< USER echo123 FULLNAME Echo / Sound Test Service ->> GET USER bob ONLINESTATUS -<< USER bob ONLINESTATUS OFFLINE ->> GET USER bob FULLNAME -<< USER bob FULLNAME Bob ->> GET USER cecil ONLINESTATUS -<< USER cecil ONLINESTATUS OFFLINE ->> GET USER cecil FULLNAME -<< USER cecil FULLNAME Cecil -<< CHAT #cecil/$bob;4d8cc9965791c6b9 NAME #cecil/$bob;4d8cc9965791c6b9 -<< CHAT #cecil/$bob;4d8cc9965791c6b9 STATUS MULTI_SUBSCRIBED -<< CHAT #cecil/$bob;4d8cc9965791c6b9 STATUS MULTI_SUBSCRIBED -<< CHATMEMBER 186 ROLE USER -<< CHAT #cecil/$bob;4d8cc9965791c6b9 MYROLE USER -<< CHAT #cecil/$bob;4d8cc9965791c6b9 MEMBERS bob cecil alice -<< CHAT #cecil/$bob;4d8cc9965791c6b9 FRIENDLYNAME bob, cecil -<< CHAT #cecil/$bob;4d8cc9965791c6b9 ACTIVEMEMBERS bob alice -<< CHAT #cecil/$bob;4d8cc9965791c6b9 TIMESTAMP 1358276196 -<< CHAT #cecil/$bob;4d8cc9965791c6b9 ADDER bob -<< CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC -<< CHAT #cecil/$bob;4d8cc9965791c6b9 STATUS MULTI_SUBSCRIBED -<< CHATMESSAGE 188 STATUS RECEIVED ->> GET CHAT #cecil/$bob;4d8cc9965791c6b9 ADDER -<< CHAT #cecil/$bob;4d8cc9965791c6b9 ADDER bob ->> GET CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC -<< CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC ->> GET CHAT #cecil/$bob;4d8cc9965791c6b9 ADDER -<< CHAT #cecil/$bob;4d8cc9965791c6b9 ADDER bob ->> GET CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC -<< CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC ->> GET CHAT #cecil/$bob;4d8cc9965791c6b9 ADDER -<< CHAT #cecil/$bob;4d8cc9965791c6b9 ADDER bob ->> GET CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC -<< CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC ->> GET CHATMESSAGE 188 FROM_HANDLE -<< CHATMESSAGE 188 FROM_HANDLE bob ->> GET CHATMESSAGE 188 BODY -<< CHATMESSAGE 188 BODY ->> GET CHATMESSAGE 188 TYPE -<< CHATMESSAGE 188 TYPE ADDEDMEMBERS ->> GET CHATMESSAGE 188 CHATNAME -<< CHATMESSAGE 188 CHATNAME #cecil/$bob;4d8cc9965791c6b9 -<< CHATMESSAGE 189 STATUS READ -<< CHATMESSAGE 189 STATUS READ -<< CHATMEMBER 186 IS_ACTIVE TRUE -<< CHAT #cecil/$bob;4d8cc9965791c6b9 ACTIVEMEMBERS bob cecil alice -<< CHATMESSAGE 190 STATUS SENT diff --git a/protocols/skype/t/groupchat-leave-bitlbee.mock b/protocols/skype/t/groupchat-leave-bitlbee.mock deleted file mode 100644 index 0a1c02df..00000000 --- a/protocols/skype/t/groupchat-leave-bitlbee.mock +++ /dev/null @@ -1,11 +0,0 @@ ->> NOTICE * -<< NICK alice -<< USER alice alice localhost :Alice ->> PRIVMSG &bitlbee -<< PRIVMSG &bitlbee :account add skype alice foo -<< PRIVMSG &bitlbee :account skype set skypeconsole_receive true -<< PRIVMSG &bitlbee :account skype on ->> JOIN :##cecil/$bob;4d8cc996579 ->> 353 alice = ##cecil/$bob;4d8cc996579 :@alice @root -<< PART ##cecil/$bob;4d8cc996579 ->> PRIVMSG &bitlbee :alice: CHAT #cecil/$bob;4d8cc9965791c6b9 STATUS UNSUBSCRIBED diff --git a/protocols/skype/t/groupchat-leave-skyped.mock b/protocols/skype/t/groupchat-leave-skyped.mock deleted file mode 100644 index 49601c28..00000000 --- a/protocols/skype/t/groupchat-leave-skyped.mock +++ /dev/null @@ -1,57 +0,0 @@ ->> SEARCH GROUPS CUSTOM -<< GROUPS 48, 49 ->> SEARCH FRIENDS -<< USERS echo123, bob, cecil ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> GET USER echo123 ONLINESTATUS -<< USER echo123 ONLINESTATUS ONLINE ->> GET USER echo123 FULLNAME -<< USER echo123 FULLNAME Echo / Sound Test Service ->> GET USER bob ONLINESTATUS -<< USER bob ONLINESTATUS OFFLINE ->> GET USER bob FULLNAME -<< USER bob FULLNAME Bob ->> GET USER cecil ONLINESTATUS -<< USER cecil ONLINESTATUS OFFLINE ->> GET USER cecil FULLNAME -<< USER cecil FULLNAME Cecil -<< CHAT #cecil/$bob;4d8cc9965791c6b9 NAME #cecil/$bob;4d8cc9965791c6b9 -<< CHAT #cecil/$bob;4d8cc9965791c6b9 STATUS MULTI_SUBSCRIBED -<< CHAT #cecil/$bob;4d8cc9965791c6b9 STATUS MULTI_SUBSCRIBED -<< CHATMEMBER 186 ROLE USER -<< CHAT #cecil/$bob;4d8cc9965791c6b9 MYROLE USER -<< CHAT #cecil/$bob;4d8cc9965791c6b9 MEMBERS bob cecil alice -<< CHAT #cecil/$bob;4d8cc9965791c6b9 FRIENDLYNAME bob, cecil -<< CHAT #cecil/$bob;4d8cc9965791c6b9 ACTIVEMEMBERS bob alice -<< CHAT #cecil/$bob;4d8cc9965791c6b9 TIMESTAMP 1358276196 -<< CHAT #cecil/$bob;4d8cc9965791c6b9 ADDER bob -<< CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC -<< CHAT #cecil/$bob;4d8cc9965791c6b9 STATUS MULTI_SUBSCRIBED -<< CHATMESSAGE 188 STATUS RECEIVED ->> GET CHAT #cecil/$bob;4d8cc9965791c6b9 ADDER -<< CHAT #cecil/$bob;4d8cc9965791c6b9 ADDER bob ->> GET CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC -<< CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC ->> GET CHAT #cecil/$bob;4d8cc9965791c6b9 ACTIVEMEMBERS -<< CHAT #cecil/$bob;4d8cc9965791c6b9 ACTIVEMEMBERS ->> GET CHATMESSAGE 188 FROM_HANDLE -<< CHATMESSAGE 188 FROM_HANDLE bob ->> GET CHATMESSAGE 188 BODY -<< CHATMESSAGE 188 BODY ->> GET CHATMESSAGE 188 TYPE -<< CHATMESSAGE 188 TYPE ADDEDMEMBERS ->> GET CHATMESSAGE 188 CHATNAME -<< CHATMESSAGE 188 CHATNAME #cecil/$bob;4d8cc9965791c6b9 -<< CHATMESSAGE 189 STATUS READ -<< CHATMESSAGE 189 STATUS READ -<< CHATMEMBER 186 IS_ACTIVE TRUE -<< CHAT #cecil/$bob;4d8cc9965791c6b9 ACTIVEMEMBERS bob cecil alice -<< CHATMESSAGE 190 STATUS SENT ->> ALTER CHAT #cecil/$bob;4d8cc9965791c6b9 LEAVE -<< ALTER CHAT LEAVE -<< CHAT #cecil/$bob;4d8cc9965791c6b9 MEMBERS bob cecil -<< CHAT #cecil/$bob;4d8cc9965791c6b9 ACTIVEMEMBERS bob cecil -<< CHAT #cecil/$bob;4d8cc9965791c6b9 STATUS UNSUBSCRIBED diff --git a/protocols/skype/t/groupchat-msg-bitlbee.mock b/protocols/skype/t/groupchat-msg-bitlbee.mock deleted file mode 100644 index 114084ba..00000000 --- a/protocols/skype/t/groupchat-msg-bitlbee.mock +++ /dev/null @@ -1,11 +0,0 @@ ->> NOTICE * -<< NICK alice -<< USER alice alice localhost :Alice ->> PRIVMSG &bitlbee -<< PRIVMSG &bitlbee :account add skype alice foo -<< PRIVMSG &bitlbee :account skype set skypeconsole_receive true -<< PRIVMSG &bitlbee :account skype on ->> JOIN :##cecil/$bob;4d8cc996579 ->> 353 alice = ##cecil/$bob;4d8cc996579 :@alice @root -<< PRIVMSG ##cecil/$bob;4d8cc996579 :hello ->> PRIVMSG &bitlbee :alice: CHAT #cecil/$bob;4d8cc9965791c6b9 ACTIVITY_TIMESTAMP diff --git a/protocols/skype/t/groupchat-msg-skyped.mock b/protocols/skype/t/groupchat-msg-skyped.mock deleted file mode 100644 index c49604a2..00000000 --- a/protocols/skype/t/groupchat-msg-skyped.mock +++ /dev/null @@ -1,54 +0,0 @@ ->> SEARCH GROUPS CUSTOM -<< GROUPS 48, 49 ->> SEARCH FRIENDS -<< USERS echo123, bob, cecil ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> GET USER echo123 ONLINESTATUS -<< USER echo123 ONLINESTATUS ONLINE ->> GET USER echo123 FULLNAME -<< USER echo123 FULLNAME Echo / Sound Test Service ->> GET USER bob ONLINESTATUS -<< USER bob ONLINESTATUS OFFLINE ->> GET USER bob FULLNAME -<< USER bob FULLNAME Bob ->> GET USER cecil ONLINESTATUS -<< USER cecil ONLINESTATUS OFFLINE ->> GET USER cecil FULLNAME -<< USER cecil FULLNAME Cecil -<< CHAT #cecil/$bob;4d8cc9965791c6b9 NAME #cecil/$bob;4d8cc9965791c6b9 -<< CHAT #cecil/$bob;4d8cc9965791c6b9 STATUS MULTI_SUBSCRIBED -<< CHAT #cecil/$bob;4d8cc9965791c6b9 STATUS MULTI_SUBSCRIBED -<< CHATMEMBER 186 ROLE USER -<< CHAT #cecil/$bob;4d8cc9965791c6b9 MYROLE USER -<< CHAT #cecil/$bob;4d8cc9965791c6b9 MEMBERS bob cecil alice -<< CHAT #cecil/$bob;4d8cc9965791c6b9 FRIENDLYNAME bob, cecil -<< CHAT #cecil/$bob;4d8cc9965791c6b9 ACTIVEMEMBERS bob alice -<< CHAT #cecil/$bob;4d8cc9965791c6b9 TIMESTAMP 1358276196 -<< CHAT #cecil/$bob;4d8cc9965791c6b9 ADDER bob -<< CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC -<< CHAT #cecil/$bob;4d8cc9965791c6b9 STATUS MULTI_SUBSCRIBED -<< CHATMESSAGE 188 STATUS RECEIVED ->> GET CHAT #cecil/$bob;4d8cc9965791c6b9 ADDER -<< CHAT #cecil/$bob;4d8cc9965791c6b9 ADDER bob ->> GET CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC -<< CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC ->> GET CHAT #cecil/$bob;4d8cc9965791c6b9 ACTIVEMEMBERS -<< CHAT #cecil/$bob;4d8cc9965791c6b9 ACTIVEMEMBERS bob cecil alice ->> GET CHATMESSAGE 188 FROM_HANDLE -<< CHATMESSAGE 188 FROM_HANDLE bob ->> GET CHATMESSAGE 188 BODY -<< CHATMESSAGE 188 BODY ->> GET CHATMESSAGE 188 TYPE -<< CHATMESSAGE 188 TYPE ADDEDMEMBERS ->> GET CHATMESSAGE 188 CHATNAME -<< CHATMESSAGE 188 CHATNAME #cecil/$bob;4d8cc9965791c6b9 -<< CHATMESSAGE 189 STATUS READ -<< CHATMESSAGE 189 STATUS READ -<< CHATMEMBER 186 IS_ACTIVE TRUE -<< CHAT #cecil/$bob;4d8cc9965791c6b9 ACTIVEMEMBERS bob cecil alice -<< CHATMESSAGE 190 STATUS SENT ->> CHATMESSAGE #cecil/$bob;4d8cc9965791c6b9 hello -<< CHAT #cecil/$bob;4d8cc9965791c6b9 ACTIVITY_TIMESTAMP 1364652882 diff --git a/protocols/skype/t/groupchat-topic-bitlbee.mock b/protocols/skype/t/groupchat-topic-bitlbee.mock deleted file mode 100644 index fe995448..00000000 --- a/protocols/skype/t/groupchat-topic-bitlbee.mock +++ /dev/null @@ -1,10 +0,0 @@ ->> NOTICE * -<< NICK alice -<< USER alice alice localhost :Alice ->> PRIVMSG &bitlbee -<< PRIVMSG &bitlbee :account add skype alice foo -<< PRIVMSG &bitlbee :account skype on ->> JOIN :##cecil/$bob;4d8cc996579 ->> 353 alice = ##cecil/$bob;4d8cc996579 :@alice @root -<< TOPIC ##cecil/$bob;4d8cc996579 :topic ->> TOPIC ##cecil/$bob;4d8cc996579 :topic diff --git a/protocols/skype/t/groupchat-topic-skyped.mock b/protocols/skype/t/groupchat-topic-skyped.mock deleted file mode 100644 index 26c4b53b..00000000 --- a/protocols/skype/t/groupchat-topic-skyped.mock +++ /dev/null @@ -1,60 +0,0 @@ ->> SEARCH GROUPS CUSTOM -<< GROUPS 48, 49 ->> SEARCH FRIENDS -<< USERS echo123, bob, cecil ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> GET USER echo123 ONLINESTATUS -<< USER echo123 ONLINESTATUS ONLINE ->> GET USER echo123 FULLNAME -<< USER echo123 FULLNAME Echo / Sound Test Service ->> GET USER bob ONLINESTATUS -<< USER bob ONLINESTATUS OFFLINE ->> GET USER bob FULLNAME -<< USER bob FULLNAME Bob ->> GET USER cecil ONLINESTATUS -<< USER cecil ONLINESTATUS OFFLINE ->> GET USER cecil FULLNAME -<< USER cecil FULLNAME Cecil -<< CHAT #cecil/$bob;4d8cc9965791c6b9 NAME #cecil/$bob;4d8cc9965791c6b9 -<< CHAT #cecil/$bob;4d8cc9965791c6b9 STATUS MULTI_SUBSCRIBED -<< CHAT #cecil/$bob;4d8cc9965791c6b9 STATUS MULTI_SUBSCRIBED -<< CHATMEMBER 186 ROLE USER -<< CHAT #cecil/$bob;4d8cc9965791c6b9 MYROLE USER -<< CHAT #cecil/$bob;4d8cc9965791c6b9 MEMBERS bob cecil alice -<< CHAT #cecil/$bob;4d8cc9965791c6b9 FRIENDLYNAME bob, cecil -<< CHAT #cecil/$bob;4d8cc9965791c6b9 ACTIVEMEMBERS bob alice -<< CHAT #cecil/$bob;4d8cc9965791c6b9 TIMESTAMP 1358276196 -<< CHAT #cecil/$bob;4d8cc9965791c6b9 ADDER bob -<< CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC -<< CHAT #cecil/$bob;4d8cc9965791c6b9 STATUS MULTI_SUBSCRIBED -<< CHATMESSAGE 188 STATUS RECEIVED ->> GET CHAT #cecil/$bob;4d8cc9965791c6b9 ADDER -<< CHAT #cecil/$bob;4d8cc9965791c6b9 ADDER bob ->> GET CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC -<< CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC ->> GET CHAT #cecil/$bob;4d8cc9965791c6b9 ADDER -<< CHAT #cecil/$bob;4d8cc9965791c6b9 ADDER bob ->> GET CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC -<< CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC ->> GET CHAT #cecil/$bob;4d8cc9965791c6b9 ADDER -<< CHAT #cecil/$bob;4d8cc9965791c6b9 ADDER bob ->> GET CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC -<< CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC ->> GET CHATMESSAGE 188 FROM_HANDLE -<< CHATMESSAGE 188 FROM_HANDLE bob ->> GET CHATMESSAGE 188 BODY -<< CHATMESSAGE 188 BODY ->> GET CHATMESSAGE 188 TYPE -<< CHATMESSAGE 188 TYPE ADDEDMEMBERS ->> GET CHATMESSAGE 188 CHATNAME -<< CHATMESSAGE 188 CHATNAME #cecil/$bob;4d8cc9965791c6b9 -<< CHATMESSAGE 189 STATUS READ -<< CHATMESSAGE 189 STATUS READ -<< CHATMEMBER 186 IS_ACTIVE TRUE -<< CHAT #cecil/$bob;4d8cc9965791c6b9 ACTIVEMEMBERS bob cecil alice -<< CHATMESSAGE 190 STATUS SENT ->> ALTER CHAT #cecil/$bob;4d8cc9965791c6b9 SETTOPIC topic -<< CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC topic diff --git a/protocols/skype/t/info-bitlbee.mock b/protocols/skype/t/info-bitlbee.mock deleted file mode 100644 index ae52fbad..00000000 --- a/protocols/skype/t/info-bitlbee.mock +++ /dev/null @@ -1,9 +0,0 @@ ->> NOTICE * -<< NICK alice -<< USER alice alice localhost :Alice ->> PRIVMSG &bitlbee -<< PRIVMSG &bitlbee :account add skype alice foo -<< PRIVMSG &bitlbee :account skype on ->> :bob!bob@skype.com JOIN :&bitlbee -<< PRIVMSG &bitlbee :info bob ->> PRIVMSG &bitlbee :Full Name: Bob diff --git a/protocols/skype/t/info-skyped.mock b/protocols/skype/t/info-skyped.mock deleted file mode 100644 index 63076b09..00000000 --- a/protocols/skype/t/info-skyped.mock +++ /dev/null @@ -1,46 +0,0 @@ ->> SEARCH GROUPS CUSTOM -<< GROUPS 48, 49 ->> SEARCH FRIENDS -<< USERS echo123, bob ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> GET USER echo123 ONLINESTATUS -<< USER echo123 ONLINESTATUS ONLINE ->> GET USER echo123 FULLNAME -<< USER echo123 FULLNAME Echo / Sound Test Service ->> GET USER bob ONLINESTATUS -<< USER bob ONLINESTATUS ONLINE ->> GET USER bob FULLNAME -<< USER bob FULLNAME Bob ->> GET USER bob FULLNAME -<< USER bob FULLNAME Bob ->> GET USER bob PHONE_HOME -<< USER bob PHONE_HOME ->> GET USER bob PHONE_OFFICE -<< USER bob PHONE_OFFICE ->> GET USER bob PHONE_MOBILE -<< USER bob PHONE_MOBILE ->> GET USER bob NROF_AUTHED_BUDDIES -<< USER bob NROF_AUTHED_BUDDIES 145 ->> GET USER bob TIMEZONE -<< USER bob TIMEZONE 90000 ->> GET USER bob LASTONLINETIMESTAMP -<< USER bob LASTONLINETIMESTAMP 1358023469 ->> GET USER bob SEX -<< USER bob SEX MALE ->> GET USER bob LANGUAGE -<< USER bob LANGUAGE hu Hungarian ->> GET USER bob COUNTRY -<< USER bob COUNTRY hu Hungary ->> GET USER bob PROVINCE -<< USER bob PROVINCE ->> GET USER bob CITY -<< USER bob CITY Budapest ->> GET USER bob HOMEPAGE -<< USER bob HOMEPAGE ->> GET USER bob ABOUT -<< USER bob ABOUT ->> GET USER bob BIRTHDAY -<< USER bob BIRTHDAY 19781108 diff --git a/protocols/skype/t/login-bitlbee.mock b/protocols/skype/t/login-bitlbee.mock deleted file mode 100644 index 6952cefe..00000000 --- a/protocols/skype/t/login-bitlbee.mock +++ /dev/null @@ -1,7 +0,0 @@ ->> NOTICE * -<< NICK alice -<< USER alice alice localhost :Alice ->> PRIVMSG &bitlbee -<< PRIVMSG &bitlbee :account add skype alice foo -<< PRIVMSG &bitlbee :account skype on ->> PRIVMSG &bitlbee :skype - Logging in: Logged in diff --git a/protocols/skype/t/login-skyped.mock b/protocols/skype/t/login-skyped.mock deleted file mode 100644 index eacff2e6..00000000 --- a/protocols/skype/t/login-skyped.mock +++ /dev/null @@ -1,16 +0,0 @@ ->> SEARCH GROUPS CUSTOM -<< GROUPS 48, 49 ->> SEARCH FRIENDS -<< USERS echo123, bob ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> GET USER echo123 ONLINESTATUS -<< USER echo123 ONLINESTATUS ONLINE ->> GET USER echo123 FULLNAME -<< USER echo123 FULLNAME Echo / Sound Test Service ->> GET USER bob ONLINESTATUS -<< USER bob ONLINESTATUS ONLINE ->> GET USER bob FULLNAME -<< USER bob FULLNAME Bob diff --git a/protocols/skype/t/msg-bitlbee.mock b/protocols/skype/t/msg-bitlbee.mock deleted file mode 100644 index 712a9816..00000000 --- a/protocols/skype/t/msg-bitlbee.mock +++ /dev/null @@ -1,9 +0,0 @@ ->> NOTICE * -<< NICK alice -<< USER alice alice localhost :Alice ->> PRIVMSG &bitlbee -<< PRIVMSG &bitlbee :account add skype alice foo -<< PRIVMSG &bitlbee :account skype on ->> :bob!bob@skype.com JOIN :&bitlbee -<< PRIVMSG &bitlbee :bob: foo ->> :bob!bob@skype.com PRIVMSG &bitlbee :alice: bar diff --git a/protocols/skype/t/msg-skyped.mock b/protocols/skype/t/msg-skyped.mock deleted file mode 100644 index 03efb6bc..00000000 --- a/protocols/skype/t/msg-skyped.mock +++ /dev/null @@ -1,49 +0,0 @@ ->> SEARCH GROUPS CUSTOM -<< GROUPS 48, 49 ->> SEARCH FRIENDS -<< USERS echo123, bob ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> GET USER echo123 ONLINESTATUS -<< USER echo123 ONLINESTATUS ONLINE ->> GET USER echo123 FULLNAME -<< USER echo123 FULLNAME Echo / Sound Test Service ->> GET USER bob ONLINESTATUS -<< USER bob ONLINESTATUS ONLINE ->> GET USER bob FULLNAME -<< USER bob FULLNAME Bob ->> MESSAGE bob foo -<< CHATMESSAGE 290 STATUS SENDING -<< CHAT #alice/$bob;ea753190f0a3e49b NAME #alice/$bob;ea753190f0a3e49b -<< CHAT #alice/$bob;ea753190f0a3e49b STATUS DIALOG -<< CHATMEMBER 287 ROLE USER -<< CHAT #alice/$bob;ea753190f0a3e49b MYROLE USER -<< CHAT #alice/$bob;ea753190f0a3e49b MEMBERS alice bob -<< CHAT #alice/$bob;ea753190f0a3e49b ACTIVEMEMBERS alice -<< CHAT #alice/$bob;ea753190f0a3e49b STATUS DIALOG -<< CHAT #alice/$bob;ea753190f0a3e49b TIMESTAMP 1357987847 -<< CHAT #alice/$bob;ea753190f0a3e49b DIALOG_PARTNER bob -<< CHAT #alice/$bob;ea753190f0a3e49b MEMBERS alice bob -<< CHAT #alice/$bob;ea753190f0a3e49b FRIENDLYNAME bob | foo -<< CHAT #alice/$bob;ea753190f0a3e49b POSTERS alice -<< CHAT #alice/$bob;ea753190f0a3e49b ACTIVITY_TIMESTAMP 1357987847 -<< CHAT #alice/$bob;ea753190f0a3e49b FRIENDLYNAME bob | foo -<< CHATMESSAGE 289 STATUS SENDING -<< CHATMESSAGE 290 STATUS SENDING -<< CHATMESSAGE 289 STATUS SENT -<< CHATMESSAGE 290 STATUS SENT -<< CHATMEMBER 288 IS_ACTIVE TRUE -<< CHAT #alice/$bob;ea753190f0a3e49b ACTIVEMEMBERS alice bob -<< CHAT #alice/$bob;ea753190f0a3e49b POSTERS alice bob -<< CHAT #alice/$bob;ea753190f0a3e49b ACTIVITY_TIMESTAMP 1357987875 -<< CHATMESSAGE 293 STATUS RECEIVED ->> GET CHATMESSAGE 293 FROM_HANDLE -<< CHATMESSAGE 293 FROM_HANDLE bob ->> GET CHATMESSAGE 293 BODY -<< CHATMESSAGE 293 BODY bar ->> GET CHATMESSAGE 293 TYPE -<< CHATMESSAGE 293 TYPE SAID ->> GET CHATMESSAGE 293 CHATNAME -<< CHATMESSAGE 293 CHATNAME #alice/$bob;ea753190f0a3e49b diff --git a/protocols/skype/t/set-mood-text-bitlbee.mock b/protocols/skype/t/set-mood-text-bitlbee.mock deleted file mode 100644 index bd78f74b..00000000 --- a/protocols/skype/t/set-mood-text-bitlbee.mock +++ /dev/null @@ -1,9 +0,0 @@ ->> NOTICE * -<< NICK alice -<< USER alice alice localhost :Alice ->> PRIVMSG &bitlbee -<< PRIVMSG &bitlbee :account add skype alice foo -<< PRIVMSG &bitlbee :account skype set skypeconsole_receive true -<< PRIVMSG &bitlbee :account skype on -<< PRIVMSG &bitlbee :account skype set mood_text "foo bar" ->> PRIVMSG &bitlbee :alice: PROFILE MOOD_TEXT foo bar diff --git a/protocols/skype/t/set-mood-text-skyped.mock b/protocols/skype/t/set-mood-text-skyped.mock deleted file mode 100644 index 566f4234..00000000 --- a/protocols/skype/t/set-mood-text-skyped.mock +++ /dev/null @@ -1,14 +0,0 @@ ->> SEARCH GROUPS CUSTOM -<< GROUPS 48, 49 ->> SEARCH FRIENDS -<< USERS echo123 ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> SET USERSTATUS ONLINE -<< USERSTATUS ONLINE ->> GET USER echo123 ONLINESTATUS -<< USER echo123 ONLINESTATUS ONLINE ->> GET USER echo123 FULLNAME -<< USER echo123 FULLNAME Echo / Sound Test Service ->> SET PROFILE MOOD_TEXT foo bar -<< PROFILE MOOD_TEXT foo bar diff --git a/protocols/skype/test.py b/protocols/skype/test.py deleted file mode 100755 index 233c41c8..00000000 --- a/protocols/skype/test.py +++ /dev/null @@ -1,147 +0,0 @@ -#!/usr/bin/env python2.7 - -import subprocess -import sys -import pexpect -import unittest -import shutil -import os -import hashlib - -def openssl(args): - with open(os.devnull, "w") as devnull: - proc = subprocess.Popen(['openssl'] + args, stdin=subprocess.PIPE, stderr=devnull) - for i in range(6): - proc.stdin.write("\n") - proc.stdin.close() - proc.communicate() -def setupSkyped(): - try: - shutil.rmtree("t/skyped") - except OSError: - pass - os.makedirs("t/skyped") - cwd = os.getcwd() - os.chdir("t/skyped") - try: - shutil.copyfile("../../skyped.cnf", "skyped.cnf") - openssl(['req', '-new', '-x509', '-days', '365', '-nodes', '-config', 'skyped.cnf', '-out', 'skyped.cert.pem', '-keyout', 'skyped.key.pem']) - with open("skyped.conf", "w") as sock: - sock.write("[skyped]\n") - sock.write("username = alice\n") - sock.write("password = %s\n" % hashlib.sha1("foo").hexdigest()) - sock.write("cert = %s/skyped.cert.pem\n" % os.getcwd()) - sock.write("key = %s/skyped.key.pem\n" % os.getcwd()) - sock.write("port = 2727\n") - finally: - os.chdir(cwd) - -class Test(unittest.TestCase): - def mock(self, name): - with open("t/skyped.log", "w") as skyped_log,\ - open("t/pexpect.log", "w") as pexpect_log: - skyped = subprocess.Popen([sys.executable, "skyped.py", - "-c", "t/skyped/skyped.conf", "-n", "-d", "-m", "t/%s-skyped.mock" % name], - stdout=skyped_log, stderr=subprocess.STDOUT) - try: - bitlbee = pexpect.spawn('../../bitlbee', ['-d', 't/bitlbee'], logfile=pexpect_log) - if os.environ.get('ATTACH_GDB'): - subprocess.Popen(['gdb', '-batch-silent', - '-ex', 'set logging overwrite on', - '-ex', 'set logging file t/gdb-%s.log' % bitlbee.pid, - '-ex', 'set logging on', - '-ex', 'handle all pass nostop noprint', - '-ex', 'handle SIGSEGV pass stop print', - '-ex', 'set pagination 0', - '-ex', 'continue', - '-ex', 'backtrace full', - '-ex', 'info registers', - '-ex', 'thread apply all backtrace', - '-ex', 'quit', - '../../bitlbee', str(bitlbee.pid) ]) - bitlbee_mock = open("t/%s-bitlbee.mock" % name) - for i in bitlbee_mock.readlines(): - line = i.strip() - if line.startswith(">> "): - bitlbee.expect_exact(line[3:], timeout=10) - elif line.startswith("<< "): - bitlbee.sendline(line[3:]) - bitlbee_mock.close() - bitlbee.close() - finally: - skyped.terminate() - skyped.communicate() - - def setUp(self): - try: - shutil.rmtree("t/bitlbee") - except OSError: - pass - os.makedirs("t/bitlbee") - - def testMsg(self): - self.mock("msg") - - def testLogin(self): - self.mock("login") - - def testInfo(self): - self.mock("info") - - def testCall(self): - self.mock("call") - - def testCallFailed(self): - self.mock("call-failed") - - def testAddYes(self): - self.mock("add-yes") - - def testAddedYes(self): - self.mock("added-yes") - - def testAddedNo(self): - self.mock("added-no") - - def testGroupchatInvited(self): - self.mock("groupchat-invited") - - def testGroupchatInvite(self): - self.mock("groupchat-invite") - - def testGroupchatLeave(self): - self.mock("groupchat-leave") - - def testGroupchatMsg(self): - self.mock("groupchat-msg") - - def testGroupchatTopic(self): - self.mock("groupchat-topic") - - def testCalledYes(self): - self.mock("called-yes") - - def testCalledNo(self): - self.mock("called-no") - - def testFiletransfer(self): - self.mock("filetransfer") - - def testGroupRead(self): - self.mock("group-read") - - def testGroupAdd(self): - self.mock("group-add") - - def testCtcpHelp(self): - self.mock("ctcp-help") - - def testSetMoodText(self): - self.mock("set-mood-text") - - def testAwaySet(self): - self.mock("away-set") - -if __name__ == '__main__': - setupSkyped() - unittest.main() diff --git a/protocols/twitter/twitter.c b/protocols/twitter/twitter.c index b0ab98c4..d43d2909 100644 --- a/protocols/twitter/twitter.c +++ b/protocols/twitter/twitter.c @@ -368,25 +368,11 @@ static const struct oauth_service twitter_oauth = { .consumer_secret = "FCxqcr0pXKzsF9ajmP57S3VQ8V6Drk4o2QYtqMcOszo", }; -static const struct oauth_service identica_oauth = { - "https://identi.ca/api/oauth/request_token", - "https://identi.ca/api/oauth/access_token", - "https://identi.ca/api/oauth/authorize", - .consumer_key = "e147ff789fcbd8a5a07963afbb43f9da", - .consumer_secret = "c596267f277457ec0ce1ab7bb788d828", -}; - static gboolean twitter_oauth_callback(struct oauth_info *info); static const struct oauth_service *get_oauth_service(struct im_connection *ic) { - struct twitter_data *td = ic->proto_data; - - if (strstr(td->url_host, "identi.ca")) { - return &identica_oauth; - } else { - return &twitter_oauth; - } + return &twitter_oauth; /* Could add more services, or allow configuring your own base URL + API keys. */ @@ -399,9 +385,8 @@ static void twitter_oauth_start(struct im_connection *ic) imcb_log(ic, "Requesting OAuth request token"); - if (!strstr(url, "twitter.com") && !strstr(url, "identi.ca")) { - imcb_log(ic, "Warning: OAuth only works with identi.ca and " - "Twitter."); + if (!strstr(url, "twitter.com")) { + imcb_log(ic, "Warning: OAuth only works with Twitter."); } td->oauth_info = oauth_request_token(get_oauth_service(ic), twitter_oauth_callback, ic); @@ -574,8 +559,8 @@ static void twitter_init(account_t * acc) def_url = TWITTER_API_URL; def_tul = "23"; def_mentions = "true"; - } else { /* if( strcmp( acc->prpl->name, "identica" ) == 0 ) */ - def_url = IDENTICA_API_URL; + } else { + def_url = ""; def_tul = "0"; def_mentions = "false"; } @@ -592,7 +577,7 @@ static void twitter_init(account_t * acc) s = set_add(&acc->set, "fetch_mentions", def_mentions, set_eval_bool, acc); - s = set_add(&acc->set, "message_length", "140", set_eval_int, acc); + s = set_add(&acc->set, "message_length", "280", set_eval_int, acc); s = set_add(&acc->set, "target_url_length", def_tul, set_eval_int, acc); diff --git a/protocols/twitter/twitter_lib.h b/protocols/twitter/twitter_lib.h index 88396a1e..03da6421 100644 --- a/protocols/twitter/twitter_lib.h +++ b/protocols/twitter/twitter_lib.h @@ -29,7 +29,6 @@ #include "twitter_http.h" #define TWITTER_API_URL "https://api.twitter.com/1.1" -#define IDENTICA_API_URL "https://identi.ca/api" /* Status URLs */ #define TWITTER_STATUS_UPDATE_URL "/statuses/update.json" diff --git a/root_commands.c b/root_commands.c index 48400cdd..8e410340 100644 --- a/root_commands.c +++ b/root_commands.c @@ -449,7 +449,7 @@ static void cmd_account(irc_t *irc, char **cmd) if (prpl == NULL) { char *msg = explain_unknown_protocol(cmd[2]); irc_rootmsg(irc, "Unknown protocol"); - irc_rootmsg(irc, msg); + irc_rootmsg(irc, "%s", msg); g_free(msg); return; } @@ -603,7 +603,7 @@ static void cmd_account(irc_t *irc, char **cmd) char *proto = set_getstr(&a->set, "_protocol_name"); char *msg = explain_unknown_protocol(proto); irc_rootmsg(irc, "Unknown protocol `%s'", proto); - irc_rootmsg(irc, msg); + irc_rootmsg(irc, "%s", msg); g_free(msg); } else { account_on(irc->b, a); @@ -1085,7 +1085,7 @@ static void cmd_blist(irc_t *irc, char **cmd) } if (error) { - irc_rootmsg(irc, error->message); + irc_rootmsg(irc, "%s", error->message); g_error_free(error); } @@ -1279,7 +1279,7 @@ static void cmd_plugins(irc_t *irc, char **cmd) } #endif - irc_rootmsg(irc, ""); + irc_rootmsg(irc, " "); gstr = g_string_new(NULL); prpls = get_protocols(); @@ -1385,13 +1385,19 @@ static void cmd_chat(irc_t *irc, char **cmd) set_setstr(&ic->set, "chat_type", "room") && set_setstr(&ic->set, "account", cmd[2]) && set_setstr(&ic->set, "room", room)) { - irc_rootmsg(irc, "Chatroom successfully added."); + irc_rootmsg(irc, "Chatroom successfully added, join with \002/join %s\002", channel); } else { if (ic) { irc_channel_free(ic); - } - irc_rootmsg(irc, "Could not add chatroom."); + irc_rootmsg(irc, "Error adding chatroom."); + } else if (irc_channel_by_name(irc, channel)) { + irc_rootmsg(irc, "A channel named `%s' already exists. " + "Join with \002/join %s\002 or see \002help channel\002 to modify it", + channel, channel); + } else { + irc_rootmsg(irc, "Error creating channel for chatroom."); + } } g_free(channel); } else if (g_strcasecmp(cmd[1], "list") == 0) { @@ -45,6 +45,10 @@ #include "otr.h" #endif +#ifdef HAVE_BACKTRACE +#include <execinfo.h> +#endif + global_t global; /* Against global namespace pollution */ static struct { @@ -62,6 +66,9 @@ int main(int argc, char *argv[]) int i = 0; char *old_cwd = NULL; struct sigaction sig, old; +#ifdef HAVE_BACKTRACE + void *unused[1]; +#endif /* Required to make iconv to ASCII//TRANSLIT work. This makes BitlBee system-locale-sensitive. :-( */ @@ -175,6 +182,13 @@ int main(int argc, char *argv[]) sigaction(SIGINT, &sig, &old); sigaction(SIGTERM, &sig, &old); +#ifdef HAVE_BACKTRACE + /* As per the backtrace(3) man page, call this outside of the signal + * handler once to ensure any dynamic libraries are loaded in an + * async-signal-safe environment to prevent deadlocks */ + backtrace(unused, 1); +#endif + if (!getuid() || !geteuid()) { log_message(LOGLVL_WARNING, "BitlBee is running with root privileges. Why?"); } @@ -291,22 +305,82 @@ static void sighandler_shutdown(int signal) unused = write(shutdown_pipe.fd[1], "", 1); } +#ifdef HAVE_BACKTRACE +/* Writes a backtrace to (usually) /var/lib/bitlbee/crash.log + * No malloc allowed means not a lot can be written to that file */ +static void sighandler_crash_backtrace() +{ + int fd, mapsfd; + int size; + void *trace[128]; + const char message[] = "## " PACKAGE " crashed\n" + "## Version: " BITLBEE_VERSION "\n" + "## Configure args: " BITLBEE_CONFIGURE_ARGS "\n" + "##\n" + "## Backtrace:\n\n"; + const char message2[] = "\n" + "## Hint: To get details on addresses use\n" + "## addr2line -e <binary> <address>\n" + "## or\n" + "## gdb <binary> -ex 'l *<address>' -ex q\n" + "## where <binary> is a filename from above and <address> is the part between (...)\n" + "##\n\n"; + const char message3[] = "\n## End of memory maps. See above for the backtrace\n\n"; + + fd = open(CRASHFILE, O_WRONLY | O_APPEND | O_CREAT, 0600); + + if (fd == -1 || write(fd, message, sizeof(message) - 1) == -1) { + return; + } + + size = backtrace(trace, 128); + backtrace_symbols_fd(trace, size, fd); + + (void) write(fd, message2, sizeof(message2) - 1); + + /* a bit too linux-specific, so fail gracefully */ + mapsfd = open("/proc/self/maps", O_RDONLY, 0); + + if (mapsfd != -1) { + char buf[4096] = {0}; + ssize_t bytes; + + while ((bytes = read(mapsfd, buf, sizeof(buf))) > 0) { + (void) write(fd, buf, bytes); + } + (void) close(mapsfd); + (void) write(fd, message3, sizeof(message3) - 1); + } + + (void) close(fd); +} +#endif + /* Signal handler for SIGSEGV * A desperate attempt to tell the user that everything is wrong in the world. * Avoids using irc_abort() because it has several unsafe calls to malloc */ static void sighandler_crash(int signal) { GSList *l; - int unused G_GNUC_UNUSED; - const char *message = "ERROR :BitlBee crashed! (SIGSEGV received)\r\n"; - int len = strlen(message); + const char message[] = "ERROR :BitlBee crashed! (SIGSEGV received)\r\n" +#ifdef HAVE_BACKTRACE + "ERROR :Writing backtrace to " CRASHFILE "\r\n" +#endif + "ERROR :This is a bug either in BitlBee or a plugin, ask us on IRC if unsure\r\n"; for (l = irc_connection_list; l; l = l->next) { irc_t *irc = l->data; sock_make_blocking(irc->fd); - unused = write(irc->fd, message, len); + if (irc->sendbuffer) { + (void) write(irc->fd, irc->sendbuffer, strlen(irc->sendbuffer)); + } + (void) write(irc->fd, message, sizeof(message) - 1); } +#ifdef HAVE_BACKTRACE + sighandler_crash_backtrace(); +#endif + raise(signal); } |