Index: .travis.yml
===================================================================
--- .travis.yml	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ .travis.yml	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -4,9 +4,9 @@
  - ./configure
  - make check
- - BITLBEE_SKYPE=plugin dpkg-buildpackage -uc -us
+ - dpkg-buildpackage -uc -us
 
 before_install:
  - sudo apt-get update -qq
- - sudo apt-get install --no-install-recommends -qq libevent-dev libpurple-dev check
+ - sudo apt-get install --no-install-recommends -qq asciidoc xsltproc xmlto lynx check libevent-dev libpurple-dev check
  - wget http://dump.dequis.org/indexed/bitlbee-travis-libs/libotr5{,-dev}_4.1.0-2~bpo70+1_amd64.deb
  - sudo dpkg -i *.deb
Index: Makefile
===================================================================
--- Makefile	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ Makefile	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -20,4 +20,7 @@
 
 all: $(OUTFILE) $(OTR_PI) $(SKYPE_PI) doc systemd
+ifdef SKYPE_PI
+	$(MAKE) -C protocols/skype doc
+endif
 
 doc:
Index: bitlbee.h
===================================================================
--- bitlbee.h	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ bitlbee.h	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -36,8 +36,8 @@
 
 #define PACKAGE "BitlBee"
-#define BITLBEE_VERSION "3.4.1"
+#define BITLBEE_VERSION "3.4"
 #define VERSION BITLBEE_VERSION
 #define BITLBEE_VER(a, b, c) (((a) << 16) + ((b) << 8) + (c))
-#define BITLBEE_VERSION_CODE BITLBEE_VER(3, 4, 1)
+#define BITLBEE_VERSION_CODE BITLBEE_VER(3, 4, 0)
 
 #define MAX_STRING 511
@@ -93,4 +93,6 @@
 #undef g_source_remove
 #define g_source_remove         __PLEASE_USE_B_EVENT_REMOVE__
+#undef g_source_remove_by_user_data
+#define g_source_remove_by_user_data    __PLEASE_USE_B_SOURCE_REMOVE_BY_USER_DATA__
 #undef g_main_run
 #define g_main_run              __PLEASE_USE_B_MAIN_RUN__
Index: configure
===================================================================
--- configure	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ configure	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -67,11 +67,4 @@
 get_version() {
 	REAL_BITLBEE_VERSION=$(grep '^#define BITLBEE_VERSION ' $srcdir/bitlbee.h | sed 's/.*\"\(.*\)\".*/\1/')
-
-	if [ -n "$BITLBEE_VERSION" ]; then
-		# environment variable already set to something to spoof it
-		# don't replace it with the git stuff
-		return
-	fi
-
 	BITLBEE_VERSION=$REAL_BITLBEE_VERSION
 
@@ -80,15 +73,10 @@
 		branch=$(cd $srcdir; git rev-parse --abbrev-ref HEAD)
 
-		search='\(.*\)-\([0-9]*\)-\(g[0-9a-f]*\)'
+		search="(.+)-([0-9]+)-(g[0-9a-f]+)"
 		replace="\1+$timestamp+$branch+\2-\3-git"
 
-		describe=$(cd $srcdir; git describe --long --tags 2>/dev/null)
-		if [ $? -ne 0 ]; then
-			describe=${REAL_BITLBEE_VERSION}-0-g$(cd $srcdir; git rev-parse --short HEAD)
-		fi
-
-		BITLBEE_VERSION=$(echo $describe | sed "s#$search#$replace#")
-
-		unset timestamp branch search replace describe
+		BITLBEE_VERSION=$(cd $srcdir; git describe --long --tags | sed -r "s/$search/$replace/")
+
+		unset timestamp branch search replace
 	fi
 }
@@ -687,18 +675,25 @@
 fi
 
-if [ -z "$PYTHON" ]; then
-	PYTHON=python
-fi
-
 if [ "$doc" = "1" ]; then
-	# check this here just in case someone tries to install it in python2.4...
-	if ! $PYTHON -m xml.etree.ElementTree > /dev/null 2>&1; then
+	if [ ! -e doc/user-guide/help.txt ] && \
+	     ! type xmlto > /dev/null 2> /dev/null || \
+	     ! type xsltproc > /dev/null 2> /dev/null
+	then
 		echo
-		echo 'ERROR: Python (>=2.5 or 3.x) is required to generate docs'
-		echo "(Use the PYTHON environment variable if it's in a weird location)"
-		exit 1
-	fi
-	echo "DOC=1" >> Makefile.settings
-	echo "PYTHON=$PYTHON" >> Makefile.settings
+		echo 'WARNING: Building from an unreleased source tree without prebuilt helpfile.'
+		echo 'Install xmlto and xsltproc if you want online help to work.'
+	else
+		echo "DOC=1" >> Makefile.settings
+	fi
+
+	if [ "$skype" = "1" -o "$skype" = "plugin" ]; then
+		# skype also needs asciidoc
+		if ! type a2x > /dev/null 2> /dev/null; then
+			echo
+			echo 'WARNING: The skyped man page requires asciidoc. It will not be generated.'
+		else
+			echo "ASCIIDOC=1" >> Makefile.settings
+		fi
+	fi
 fi
 
Index: debian/bitlbee-common.docs
===================================================================
--- debian/bitlbee-common.docs	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ debian/bitlbee-common.docs	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -1,2 +1,4 @@
+doc/user-guide/user-guide.txt
+doc/user-guide/user-guide.html
 doc/AUTHORS
 doc/CREDITS
Index: debian/control
===================================================================
--- debian/control	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ debian/control	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -5,5 +5,5 @@
 Uploaders: Jelmer Vernooij <jelmer@debian.org>
 Standards-Version: 3.9.5
-Build-Depends: libglib2.0-dev (>= 2.4), libevent-dev, libgnutls28-dev | libgnutls-dev | gnutls-dev, po-debconf, libpurple-dev, libotr5-dev, debhelper (>= 6.0.7~)
+Build-Depends: libglib2.0-dev (>= 2.4), libevent-dev, libgnutls28-dev | libgnutls-dev | gnutls-dev, po-debconf, libpurple-dev, libotr5-dev, debhelper (>= 6.0.7~), asciidoc
 Homepage: http://www.bitlbee.org/
 Vcs-Bzr: http://code.bitlbee.org/bitlbee/
Index: doc/CHANGES
===================================================================
--- doc/CHANGES	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ doc/CHANGES	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -3,26 +3,4 @@
 
 https://github.com/bitlbee/bitlbee/commits/master
-
-Version 3.4.1:
-- msn:
-  * Upgraded protocol to MSNP21, works again (dx)
-  * Contact list management, groupchats and skype username logins won't work.
-    Next release!
-- jabber:
-  * Add "hipchat" protocol, for smoother login. Takes the same username as
-    the official client. Note that unlike the 'hip-cat' branch, this doesn't
-    preload channels. https://wiki.bitlbee.org/HowtoHipchat for details (dx)
-  * Fixed a bug when receiving topics set by people who left the channel (dx)
-  * Create fake users instead of showing "unknown participant" errors (dx)
-  * Gmail mail notifications support (Artem Savkov)
-  * Lowering xmpp presence priority on away (Artem Savkov)
-- twitter:
-  * Show quoted tweets/RTs with comment inline (wilmer)
-  * Added "url" command, can be used to quote tweets (wilmer)
-  * Make replies to self work (wilmer)
-- Building documentation is now done with a python script (both 2.x/3.x work)
-  Asciidoc/xsltproc/xmlto are no longer build dependencies (dx)
-
-Finished 16 Jun 2015
 
 Version 3.4:
Index: doc/Makefile
===================================================================
--- doc/Makefile	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ doc/Makefile	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -5,5 +5,6 @@
 
 all:
-	$(MAKE) -C user-guide
+	# Only build the docs if this is a git tree
+	test ! '(' -d ../.git -o -d ../.bzr ')' || $(MAKE) -C user-guide
 
 install:
Index: doc/user-guide/Makefile
===================================================================
--- doc/user-guide/Makefile	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ doc/user-guide/Makefile	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -4,11 +4,8 @@
 endif
 
-ifndef PYTHON
-PYTHON = python
-endif 
+EXTRAPARANEWLINE = 1
+# EXTRAPARANEWLINE = 0
 
-all: help.txt
-
-user-guide: user-guide.txt user-guide.html # user-guide.pdf user-guide.ps user-guide.rtf
+all: user-guide.txt user-guide.html help.txt # user-guide.pdf user-guide.ps user-guide.rtf
 
 %.tex: %.db.xml
@@ -35,6 +32,6 @@
 	xsltproc --xinclude --output $@ docbook.xsl $< 
 
-help.txt: $(_SRCDIR_)help.xml $(_SRCDIR_)commands.xml $(_SRCDIR_)misc.xml $(_SRCDIR_)quickstart.xml
-	$(PYTHON) $(_SRCDIR_)genhelp.py $< $@
+help.txt: help.xml help.xsl commands.xml misc.xml quickstart.xml
+	xsltproc --stringparam extraparanewline "$(EXTRAPARANEWLINE)" --xinclude help.xsl $< | perl -0077 -pe 's/\n\n%/\n%/s; s/_b_/\002/g;' > $@
 
 clean: 
@@ -51,3 +48,3 @@
 	-rmdir $(DESTDIR)$(DATADIR)
 
-.PHONY: clean install uninstall user-guide
+.PHONY: clean install uninstall
Index: doc/user-guide/commands.xml
===================================================================
--- doc/user-guide/commands.xml	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ doc/user-guide/commands.xml	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -1017,16 +1017,5 @@
 		<description>
 			<para>
-				Some protocols (MSN, Yahoo!, GTalk) can notify via IM about new e-mail. Since most people use their Hotmail/Yahoo! addresses as a spam-box, this is disabled default. If you want these notifications, you can enable this setting.
-			</para>
-		</description>
-
-	</bitlbee-setting>
-
-	<bitlbee-setting name="mail_notifications_handle" type="string" scope="account">
-		<default>empty</default>
-
-		<description>
-			<para>
-				This setting is available for protocols with e-mail notification functionality. If set to empty all e-mail notifications will go to control channel, if set to some string - this will be the name of a contact who will PRIVMSG you on every new notification.
+				Some protocols (MSN, Yahoo!) can notify via IM about new e-mail. Since most people use their Hotmail/Yahoo! addresses as a spam-box, this is disabled default. If you want these notifications, you can enable this setting.
 			</para>
 		</description>
Index: c/user-guide/genhelp.py
===================================================================
--- doc/user-guide/genhelp.py	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ 	(revision )
@@ -1,235 +1,0 @@
-#!/usr/bin/env python
-
-# Usage: python genhelp.py input.xml output.txt
-# (Both python2 (>=2.5) or python3 work)
-#
-# The shebang above isn't used, set the PYTHON environment variable
-# before running ./configure instead
-
-# 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.
-
-
-import os
-import re
-import sys
-import xml.etree.ElementTree as ET
-
-NORMALIZE_RE = re.compile(r"([^<>\s\t])[\s\t]+([^<>\s\t])")
-
-# Helpers
-
-def normalize(x):
-    """Normalize whitespace of a string.
-
-    The regexp turns any sequence of whitespace into a single space if it's in
-    the middle of the tag text, and then all newlines and tabs are removed,
-    keeping spaces.
-    """
-
-    x = NORMALIZE_RE.sub(r"\1 \2", x or '')
-    return x.replace("\n", "").replace("\t", "")
-
-def join(list):
-    """Turns any iterator into a string"""
-    return ''.join([str(x) for x in list])
-
-def fix_tree(tag, debug=False, lvl=''):
-    """Walks the XML tree and modifies it in-place fixing various details"""
-
-    # The include tags have an ugly namespace in the tag name. Simplify that.
-    if tag.tag.count("XInclude"):
-        tag.tag = 'include'
-
-    # Print a pretty tree-like representation of the processed tags
-    if debug:
-        print("%s<%s>%r" % (lvl, tag.tag, [tag.text, normalize(tag.text)]))
-
-    for subtag in tag:
-        fix_tree(subtag, debug, lvl + "  ")
-
-    if debug:
-        print("%s</%s>%r" % (lvl, tag.tag, [tag.tail, normalize(tag.tail)]))
-
-    # Actually normalize whitespace
-    tag.text = normalize(tag.text)
-    tag.tail = normalize(tag.tail)
-
-
-# Main logic
-
-def process_file(filename, parent=None):
-    tree = ET.parse(open(filename)).getroot()
-    fix_tree(tree)
-    return parse_tag(tree, parent)
-
-def parse_tag(tag, parent):
-    """Calls a tag_... function based on the tag name"""
-
-    fun = globals()["tag_%s" % tag.tag.replace("-", "_")]
-    return join(fun(tag, parent))
-
-def parse_subtags(tag, parent=None):
-    yield tag.text
-
-    for subtag in tag:
-        yield parse_tag(subtag, tag)
-
-    yield tag.tail
-
-
-# Main tag handlers
-
-def handle_subject(tag, parent):
-    """Tag handler for preface, chapter, sect1 and sect2 (aliased below)"""
-
-    yield '?%s\n' % tag.attrib['id']
-
-    first = True
-    for element in tag:
-        if element.tag in ["para", "variablelist", "simplelist",
-                           "command-list", "ircexample"]:
-            if not first:
-                # Spaces between paragraphs
-                yield "\n"
-            first = False
-
-            if element.attrib.get('title', ''):
-                yield element.attrib['title']
-                yield "\n"
-            yield join(parse_tag(element, tag)).rstrip("\n")
-            yield "\n"
-
-    yield "%\n"
-
-    for element in tag:
-        if element.tag in ["sect1", "sect2"]:
-            yield join(handle_subject(element, tag))
-
-    for element in tag.findall("bitlbee-command"):
-        yield join(handle_command(element))
-
-    for element in tag.findall("bitlbee-setting"):
-        yield join(handle_setting(element))
-
-def handle_command(tag, prefix=''):
-    """Tag handler for <bitlbee-command> (called from handle_subject)"""
-
-    this_cmd = prefix + tag.attrib['name']
-
-    yield "?%s\n" % this_cmd
-    for syntax in tag.findall("syntax"):
-        yield '\x02Syntax:\x02 %s\n' % syntax.text
-
-    yield "\n"
-    yield join(parse_subtags(tag.find("description"))).rstrip()
-    yield "\n"
-
-    for example in tag.findall("ircexample"):
-        yield "\n\x02Example:\x02\n"
-        yield join(parse_subtags(example)).rstrip()
-        yield "\n"
-
-    yield "%\n"
-
-    for element in tag.findall("bitlbee-command"):
-        yield join(handle_command(element, this_cmd + " "))
-
-def handle_setting(tag):
-    """Tag handler for <bitlbee-setting> (called from handle_subject)"""
-
-    yield "?set %s\n" % tag.attrib['name']
-    yield "\x02Type:\x02 %s\n" % tag.attrib["type"]
-    yield "\x02Scope:\x02 %s\n" % tag.attrib["scope"]
-
-    if tag.find("default") is not None:
-        yield "\x02Default:\x02 %s\n" % tag.findtext("default")
-
-    if tag.find("possible-values") is not None:
-        yield "\x02Possible Values:\x02 %s\n" % tag.findtext("possible-values")
-
-    yield "\n"
-    yield join(parse_subtags(tag.find("description"))).rstrip()
-    yield "\n%\n"
-
-
-# Aliases for tags that behave like subjects
-tag_preface = handle_subject
-tag_chapter = handle_subject
-tag_sect1 = handle_subject
-tag_sect2 = handle_subject
-
-# Aliases for tags that don't have any special behavior
-tag_ulink = parse_subtags
-tag_note = parse_subtags
-tag_book = parse_subtags
-tag_ircexample = parse_subtags
-
-
-# Handlers for specific tags
-
-def tag_include(tag, parent):
-    return process_file(tag.attrib['href'], tag)
-
-def tag_para(tag, parent):
-    return join(parse_subtags(tag)) + "\n\n"
-
-def tag_emphasis(tag, parent):
-    return "\x02%s\x02%s" % (tag.text, tag.tail)
-
-def tag_ircline(tag, parent):
-    return "\x02<%s>\x02 %s\n" % (tag.attrib['nick'], join(parse_subtags(tag)))
-
-def tag_ircaction(tag, parent):
-    return "\x02* %s\x02 %s\n" % (tag.attrib['nick'], join(parse_subtags(tag)))
-
-def tag_command_list(tag, parent):
-    yield "These are all root commands. See \x02help <command name>\x02 " \
-          "for more details on each command.\n\n"
-
-    for subtag in parent.findall("bitlbee-command"):
-        yield " * \x02%s\x02 - %s\n" % \
-            (subtag.attrib['name'],
-             subtag.findtext("short-description"))
-
-    yield "\nMost commands can be shortened. For example instead of " \
-          "\x02account list\x02, try \x02ac l\x02.\n\n"
-
-def tag_variablelist(tag, parent):
-    for subtag in tag:
-        yield " \x02%s\x02 - %s\n" % \
-            (subtag.findtext("term"),
-             join(parse_subtags(subtag.find("listitem/para"))))
-    yield '\n'
-
-def tag_simplelist(tag, parent):
-    for subtag in tag:
-        yield " - %s\n" % join(parse_subtags(subtag))
-    yield '\n'
-
-
-def main():
-    if len(sys.argv) != 3:
-        print("Usage: python genhelp.py input.xml output.txt")
-        return
-
-    # ensure that we really are in the same directory as the input file
-    os.chdir(os.path.dirname(os.path.abspath(sys.argv[1])))
-
-    txt = process_file(sys.argv[1])
-    open(sys.argv[2], "w").write(txt)
-
-if __name__ == '__main__':
-    main()
Index: doc/user-guide/misc.xml
===================================================================
--- doc/user-guide/misc.xml	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ doc/user-guide/misc.xml	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -433,15 +433,3 @@
 </sect1>
 
-<sect1 id="whatsnew030401">
-<title>New stuff in BitlBee 3.4.1</title>
-
-<simplelist>
-	<member><emphasis>msn:</emphasis> Upgraded protocol version to MSNP21, works again</member>
-	<member><emphasis>jabber:</emphasis> Add "hipchat" protocol, for smoother login. Takes the same username as the official client. Note that unlike the 'hip-cat' branch, this doesn't preload channels. See the <emphasis>HowtoHipchat</emphasis> wiki page for details</member>
-	<member><emphasis>jabber:</emphasis> Gmail notifications support</member>
-	<member><emphasis>twitter:</emphasis> Show quoted tweets inline. Added "url" command, can be used to quote tweets.</member>
-</simplelist>
-
-</sect1>
-
 </chapter>
Index: irc_im.c
===================================================================
--- irc_im.c	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ irc_im.c	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -50,5 +50,5 @@
 
 	memset(nick, 0, MAX_NICK_LENGTH + 1);
-	strncpy(nick, nick_get(bu), MAX_NICK_LENGTH);
+	strcpy(nick, nick_get(bu));
 
 	bu->ui_data = iu = irc_user_new(irc, nick);
@@ -723,6 +723,4 @@
 			g_free(channel);
 			channel = s;
-		} else {
-			g_free(s);
 		}
 	}
Index: irc_send.c
===================================================================
--- irc_send.c	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ irc_send.c	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -175,8 +175,9 @@
 
 	if (iu == irc->user) {
+		irc_write(irc, ":%s MODE %s +%s", irc->root->host, ic->name, ic->mode);
+		irc_send_names(ic);
 		if (ic->topic && *ic->topic) {
 			irc_send_topic(ic, FALSE);
 		}
-		irc_send_names(ic);
 	}
 }
Index: lib/events_glib.c
===================================================================
--- lib/events_glib.c	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ lib/events_glib.c	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -82,5 +82,5 @@
 	}
 
-	event_debug("gaim_io_invoke( %d, %d, %p )\n", g_io_channel_unix_get_fd(source), condition, data);
+	event_debug("gaim_io_invoke( %d, %d, 0x%x )\n", g_io_channel_unix_get_fd(source), condition, data);
 
 	st = closure->function(closure->data, g_io_channel_unix_get_fd(source), gaim_cond);
@@ -101,5 +101,5 @@
 static void gaim_io_destroy(gpointer data)
 {
-	event_debug("gaim_io_destroy( 0%p )\n", data);
+	event_debug("gaim_io_destroy( 0x%x )\n", data);
 	g_free(data);
 }
@@ -127,5 +127,5 @@
 	                         gaim_io_invoke, closure, gaim_io_destroy);
 
-	event_debug("b_input_add( %d, %d, %p, %p ) = %d (%p)\n", source, condition, function, data, st, closure);
+	event_debug("b_input_add( %d, %d, 0x%x, 0x%x ) = %d (%p)\n", source, condition, function, data, st, closure);
 
 	g_io_channel_unref(channel);
@@ -140,5 +140,5 @@
 	gint st = g_timeout_add(timeout, (GSourceFunc) func, data);
 
-	event_debug("b_timeout_add( %d, %p, %p ) = %d\n", timeout, func, data, st);
+	event_debug("b_timeout_add( %d, %d, %d ) = %d\n", timeout, func, data, st);
 
 	return st;
Index: lib/misc.c
===================================================================
--- lib/misc.c	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ lib/misc.c	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -751,18 +751,2 @@
 	return end - string;
 }
-
-/* Parses a guint64 from string, returns TRUE on success */
-gboolean parse_int64(char *string, int base, guint64 *number)
-{
-	guint64 parsed;
-	char *endptr;
-
-	errno = 0;
-	parsed = g_ascii_strtoull(string, &endptr, base);
-	if (errno || endptr == string || *endptr != '\0') {
-		return FALSE;
-	}
-	*number = parsed;
-	return TRUE;
-}
-
Index: lib/misc.h
===================================================================
--- lib/misc.h	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ lib/misc.h	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -149,5 +149,4 @@
 G_MODULE_EXPORT char *get_rfc822_header(const char *text, const char *header, int len);
 G_MODULE_EXPORT int truncate_utf8(char *string, int maxlen);
-G_MODULE_EXPORT gboolean parse_int64(char *string, int base, guint64 *number);
 
 #endif
Index: lib/oauth2.c
===================================================================
--- lib/oauth2.c	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ lib/oauth2.c	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -138,13 +138,7 @@
 	struct oauth2_access_token_data *cb_data = req->data;
 	char *atoken = NULL, *rtoken = NULL, *error = NULL;
-	char *content_type = NULL;
+	char *content_type;
 
-	if (req->status_code <= 0 && !req->reply_body) {
-		cb_data->func(cb_data->data, NULL, NULL, req->status_string);
-		g_free(cb_data);
-		return;
-	}
-
-	if (getenv("BITLBEE_DEBUG")) {
+	if (getenv("BITLBEE_DEBUG") && req->reply_body) {
 		printf("%s\n", req->reply_body);
 	}
Index: nick.c
===================================================================
--- nick.c	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ nick.c	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -186,14 +186,6 @@
 		   LC_CTYPE being set to something other than C/POSIX. */
 		if (!(irc && irc->status & IRC_UTF8_NICKS)) {
-			asc = g_convert_with_fallback(part, -1, "ASCII//TRANSLIT", "UTF-8", "", NULL, NULL, NULL);
-
-			if (!asc) {
-				/* If above failed, try again without //TRANSLIT.
-				   //TRANSLIT is a GNU iconv special and is not POSIX.
-				   Other platforms may not support it. */
-				asc = g_convert_with_fallback(part, -1, "ASCII", "UTF-8", "", NULL, NULL, NULL);
-			}
-
-			part = asc;
+			part = asc = g_convert_with_fallback(part, -1, "ASCII//TRANSLIT",
+			                                     "UTF-8", "", NULL, NULL, NULL);
 		}
 
@@ -376,11 +368,7 @@
 
 	if (tab['A'] == 0) {
-		/* initialize table so nonchars are mapped to themselves */
-		for (i = 0; i < sizeof(tab); i++) {
-			tab[i] = i;
-		}
-		/* replace uppercase chars with lowercase chars */
 		for (i = 0; nick_lc_chars[i]; i++) {
 			tab[(int) nick_uc_chars[i]] = nick_lc_chars[i];
+			tab[(int) nick_lc_chars[i]] = nick_lc_chars[i];
 		}
 	}
Index: otr.c
===================================================================
--- otr.c	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ otr.c	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -193,8 +193,6 @@
 void show_general_otr_info(irc_t *irc);
 
-/* show info about a given OTR context and subcontexts/instances. bestctx
-   may be either NULL or preferred destination context (this is hilighted
-   in the output as being the target for a message) */
-void show_otr_context_info(irc_t *irc, ConnContext *ctx, ConnContext *bestctx);
+/* show info about a given OTR context */
+void show_otr_context_info(irc_t *irc, ConnContext *ctx);
 
 /* show the list of fingerprints associated with a given context */
@@ -1104,5 +1102,5 @@
 		char *arg = g_strdup(args[1]);
 		char *myhandle, *handle = NULL, *protocol;
-		ConnContext *bestctx = NULL, *ctx;
+		ConnContext *ctx;
 
 		/* interpret arg as 'user/protocol/account' if possible */
@@ -1137,16 +1135,12 @@
 				return;
 			}
-			/* This does no harm if it returns NULL */
-			bestctx = otrl_context_find(irc->otr->us, u->bu->handle, u->bu->ic->acc->user,
-			                            u->bu->ic->acc->prpl->name, OTRL_INSTAG_BEST, 0, NULL, NULL, NULL);
 		}
 
 		/* show how we resolved the (nick) argument, if we did */
 		if (handle != arg) {
-			irc_rootmsg(irc, "%s:", args[1]);
-			irc_rootmsg(irc, "  they are: %s/%s", ctx->username, ctx->protocol);
-			irc_rootmsg(irc, "  we are: %s/%s", ctx->accountname, ctx->protocol);
-		}
-		show_otr_context_info(irc, ctx, bestctx);
+			irc_rootmsg(irc, "%s is %s/%s; we are %s/%s to them", args[1],
+			            ctx->username, ctx->protocol, ctx->accountname, ctx->protocol);
+		}
+		show_otr_context_info(irc, ctx);
 		g_free(arg);
 	}
@@ -1555,14 +1549,6 @@
 	int count = 0;
 
-	/* Is this a subcontext? If so, only list the active fingerprint */
-	if (ctx->m_context != ctx) {
-		fp = ctx->active_fingerprint;
-	} else {
-		fp = &ctx->fingerprint_root;
-	}
-
-	while (fp) {
+	for (fp = &ctx->fingerprint_root; fp; fp = fp->next) {
 		if (!fp->fingerprint) {
-			fp = fp->next;
 			continue;
 		}
@@ -1575,17 +1561,11 @@
 		}
 		if (fp == ctx->active_fingerprint) {
-			irc_rootmsg(irc, "      \x02%s (%s)\x02", human, trust);
+			irc_rootmsg(irc, "    \x02%s (%s)\x02", human, trust);
 		} else {
-			irc_rootmsg(irc, "      %s (%s)", human, trust);
-		}
-
-		/* Break if this is a subcontext - we only print active fp */
-		if (ctx->m_context != ctx) {
-			break;
-		}
-		fp = fp->next;
+			irc_rootmsg(irc, "    %s (%s)", human, trust);
+		}
 	}
 	if (count == 0) {
-		irc_rootmsg(irc, "      (none)");
+		irc_rootmsg(irc, "    (none)");
 	}
 }
@@ -1775,13 +1755,10 @@
 	/* list all contexts */
 	/* XXX remove this, or split off as its own command */
+	/* XXX show instags? */
 	irc_rootmsg(irc, "%s", "");
 	irc_rootmsg(irc, "\x1f" "connection contexts:\x1f (bold=currently encrypted)");
-
-	ctx = irc->otr->us->context_root;
-	while (ctx) {
-		ConnContext *subctx;
+	for (ctx = irc->otr->us->context_root; ctx; ctx = ctx->next) { \
 		irc_user_t *u;
 		char *userstring;
-		char encrypted = 0;
 
 		u = peeruser(irc, ctx->username, ctx->protocol);
@@ -1794,13 +1771,5 @@
 		}
 
-		subctx = ctx;
-		while (subctx && subctx->m_context == ctx) {
-			if (subctx->msgstate == OTRL_MSGSTATE_ENCRYPTED) {
-				encrypted = 1;
-			}
-			subctx = subctx->next;
-		}
-
-		if(encrypted) {
+		if (ctx->msgstate == OTRL_MSGSTATE_ENCRYPTED) {
 			irc_rootmsg(irc, "  \x02%s\x02", userstring);
 		} else {
@@ -1808,10 +1777,6 @@
 		}
 
-		/* Skip subcontexts/instances from output */
-		ctx = subctx;
-
 		g_free(userstring);
 	}
-
 	if (ctx == irc->otr->us->context_root) {
 		irc_rootmsg(irc, "  (none)");
@@ -1819,46 +1784,41 @@
 }
 
-void show_otr_context_info(irc_t *irc, ConnContext *ctx, ConnContext *bestctx)
-{
-	ConnContext *subctx;
-	int instcount = 0;
-
-	subctx = ctx;
-	while (subctx && subctx->m_context == ctx) {
-		if (subctx->m_context == subctx) {
-			if (subctx == bestctx) {
-				irc_rootmsg(irc, "  \x02master context (target):\x02");
-			} else {
-				irc_rootmsg(irc, "  master context:");
-			}
-			irc_rootmsg(irc, "    known fingerprints (bold = active for v1 or v2):");
-		} else {
-			if (subctx == bestctx) {
-				irc_rootmsg(irc, "  \x02instance %d (target):\x02", instcount);
-			} else {
-				irc_rootmsg(irc, "  instance %d:", instcount);
-			}
-			irc_rootmsg(irc, "    active fingerprint:");
-			instcount++;
-		}
-
-		show_fingerprints(irc, subctx);
-
-		switch (subctx->msgstate) {
-		case OTRL_MSGSTATE_PLAINTEXT:
-			irc_rootmsg(irc, "    connection state: cleartext");
-			break;
-		case OTRL_MSGSTATE_ENCRYPTED:
-			irc_rootmsg(irc, "    connection state: encrypted (v%d)", subctx->protocol_version);
-			break;
-		case OTRL_MSGSTATE_FINISHED:
-			irc_rootmsg(irc, "    connection state: shut down");
-			break;
-		default:
-			irc_rootmsg(irc, "    connection state: %d", subctx->msgstate);
-		}
-
-		subctx = subctx->next;
-	}
+void show_otr_context_info(irc_t *irc, ConnContext *ctx)
+{
+	// XXX show all instags/subcontexts
+
+	switch (ctx->otr_offer) {
+	case OFFER_NOT:
+		irc_rootmsg(irc, "  otr offer status: none sent");
+		break;
+	case OFFER_SENT:
+		irc_rootmsg(irc, "  otr offer status: awaiting reply");
+		break;
+	case OFFER_ACCEPTED:
+		irc_rootmsg(irc, "  otr offer status: accepted our offer");
+		break;
+	case OFFER_REJECTED:
+		irc_rootmsg(irc, "  otr offer status: ignored our offer");
+		break;
+	default:
+		irc_rootmsg(irc, "  otr offer status: %d", ctx->otr_offer);
+	}
+
+	switch (ctx->msgstate) {
+	case OTRL_MSGSTATE_PLAINTEXT:
+		irc_rootmsg(irc, "  connection state: cleartext");
+		break;
+	case OTRL_MSGSTATE_ENCRYPTED:
+		irc_rootmsg(irc, "  connection state: encrypted (v%d)", ctx->protocol_version);
+		break;
+	case OTRL_MSGSTATE_FINISHED:
+		irc_rootmsg(irc, "  connection state: shut down");
+		break;
+	default:
+		irc_rootmsg(irc, "  connection state: %d", ctx->msgstate);
+	}
+
+	irc_rootmsg(irc, "  fingerprints: (bold=active)");
+	show_fingerprints(irc, ctx);
 }
 
Index: protocols/bee.h
===================================================================
--- protocols/bee.h	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ protocols/bee.h	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -156,5 +156,4 @@
 G_MODULE_EXPORT void imcb_buddy_msg(struct im_connection *ic, const char *handle, const char *msg, guint32 flags,
                                     time_t sent_at);
-G_MODULE_EXPORT void imcb_notify_email(struct im_connection *ic, char *format, ...) G_GNUC_PRINTF(2, 3);
 
 /* bee_chat.c */
Index: protocols/bee_user.c
===================================================================
--- protocols/bee_user.c	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ protocols/bee_user.c	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -271,30 +271,4 @@
 }
 
-void imcb_notify_email(struct im_connection *ic, char *format, ...)
-{
-	const char *handle;
-	va_list params;
-	char *msg;
-
-	if (!set_getbool(&ic->acc->set, "mail_notifications")) {
-		return;
-	}
-
-	va_start(params, format);
-	msg = g_strdup_vprintf(format, params);
-	va_end(params);
-
-	/* up to the protocol to set_add this if they want to use this */
-	handle = set_getstr(&ic->acc->set, "mail_notifications_handle");
-
-	if (handle != NULL) {
-		imcb_buddy_msg(ic, handle, msg, 0, 0);
-	} else {
-		imcb_log(ic, "%s", msg);
-	}
-
-	g_free(msg);
-}
-
 void imcb_buddy_typing(struct im_connection *ic, const char *handle, uint32_t flags)
 {
Index: protocols/jabber/conference.c
===================================================================
--- protocols/jabber/conference.c	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ protocols/jabber/conference.c	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -354,87 +354,77 @@
 	struct xt_node *subject = xt_find_node(node->children, "subject");
 	struct xt_node *body = xt_find_node(node->children, "body");
-	struct groupchat *chat = NULL;
-	struct jabber_chat *jc = NULL;
-	char *from = NULL;
-	char *nick = NULL;
-	char *final_from = NULL;
-	char *bare_jid = NULL;
-
-	from = (bud) ? bud->full_jid : xt_find_attr(node, "from");
-
-	if (from) {
-		nick = strchr(from, '/');
+	struct groupchat *chat = bud ? jabber_chat_by_jid(ic, bud->bare_jid) : NULL;
+	struct jabber_chat *jc = chat ? chat->data : NULL;
+	char *s;
+
+	if (subject && chat) {
+		s = (bud && bud->ext_jid) ? strchr(bud->ext_jid, '/') : NULL;
+		if (s) {
+			*s = 0;
+		}
+		imcb_chat_topic(chat, bud ? bud->ext_jid : NULL, subject->text_len > 0 ?
+		                subject->text : NULL, jabber_get_timestamp(node));
+		if (s) {
+			*s = '/';
+		}
+	}
+
+	if (bud == NULL || (jc && ~jc->flags & JCFLAG_MESSAGE_SENT && bud == jc->me)) {
+		char *nick;
+
+		if (body == NULL || body->text_len == 0) {
+			/* Meh. Empty messages aren't very interesting, no matter
+			   how much some servers love to send them. */
+			return;
+		}
+
+		s = xt_find_attr(node, "from");   /* pkt_message() already NULL-checked this one. */
+		nick = strchr(s, '/');
 		if (nick) {
+			/* If this message included a resource/nick we don't know,
+			   we might still know the groupchat itself. */
 			*nick = 0;
-		}
-		chat = jabber_chat_by_jid(ic, from);
-		if (nick) {
+			chat = jabber_chat_by_jid(ic, s);
 			*nick = '/';
+
 			nick++;
-		}
-	}
-
-	jc = (chat) ? chat->data : NULL;
-
-	if (!bud) {
-		struct xt_node *c;
-		char *s;
-
-		/* Try some clever stuff to find out the real JID here */
-		c = xt_find_node_by_attr(node->children, "delay", "xmlns", XMLNS_DELAY);
-
-		if (c && ((s = xt_find_attr(c, "from")) ||
-		          (s = xt_find_attr(c, "from_jid")))) {
-			/* This won't be useful if it's the MUC JID */
-			if (!(jc && jabber_compare_jid(s, jc->name))) {
-				/* Hopefully this one makes more sense! */
-				bud = jabber_buddy_by_jid(ic, s, GET_BUDDY_FIRST | GET_BUDDY_CREAT);
-			}
-		}
-
-	}
-
-	if (subject && chat) {
-		char *subject_text = subject->text_len > 0 ? subject->text : NULL;
-		if (g_strcmp0(chat->topic, subject_text) != 0) {
-			bare_jid = (bud) ? jabber_get_bare_jid(bud->ext_jid) : NULL;
-			imcb_chat_topic(chat, bare_jid, subject_text,
-			                jabber_get_timestamp(node));
-			g_free(bare_jid);
-		}
-	}
-
-	if (body == NULL || body->text_len == 0) {
-		/* Meh. Empty messages aren't very interesting, no matter
-		   how much some servers love to send them. */
+		} else {
+			/* message.c uses the EXACT_JID option, so bud should
+			   always be NULL here for bare JIDs. */
+			chat = jabber_chat_by_jid(ic, s);
+		}
+
+		if (nick == NULL) {
+			/* This is fine, the groupchat itself isn't in jd->buddies. */
+			if (chat) {
+				imcb_chat_log(chat, "From conference server: %s", body->text);
+			} else {
+				imcb_log(ic, "System message from unknown groupchat %s: %s", s, body->text);
+			}
+		} else {
+			/* This can happen too, at least when receiving a backlog when
+			   just joining a channel. */
+			if (chat) {
+				imcb_chat_log(chat, "Message from unknown participant %s: %s", nick, body->text);
+			} else {
+				imcb_log(ic, "Groupchat message from unknown JID %s: %s", s, body->text);
+			}
+		}
+
 		return;
-	}
-
-	if (chat == NULL) {
-		if (nick == NULL) {
-			imcb_log(ic, "System message from unknown groupchat %s: %s", from, body->text);
-		} else {
-			imcb_log(ic, "Groupchat message from unknown JID %s: %s", from, body->text);
-		}
-
+	} else if (chat == NULL) {
+		/* How could this happen?? We could do kill( self, 11 )
+		   now or just wait for the OS to do it. :-) */
 		return;
-	} else if (chat != NULL && bud == NULL && nick == NULL) {
-		imcb_chat_log(chat, "From conference server: %s", body->text);
-		return;
-	} else if (jc && jc->flags & JCFLAG_MESSAGE_SENT && bud == jc->me) {
-		/* exclude self-messages since they would get filtered out
-		 * but not the ones in the backlog */
-		return;
-	}
-
-	if (bud && jc && bud != jc->me) {
-		bare_jid = jabber_get_bare_jid(bud->ext_jid ? bud->ext_jid : bud->full_jid);
-		final_from = bare_jid;
-	} else {
-		final_from = nick;
-	}
-
-	imcb_chat_msg(chat, final_from, body->text, 0, jabber_get_timestamp(node));
-
-	g_free(bare_jid);
-}
+	}
+	if (body && body->text_len > 0) {
+		s = (bud->ext_jid) ? strchr(bud->ext_jid, '/') : NULL;
+		if (s) {
+			*s = 0;
+		}
+		imcb_chat_msg(chat, bud->ext_jid, body->text, 0, jabber_get_timestamp(node));
+		if (s) {
+			*s = '/';
+		}
+	}
+}
Index: protocols/jabber/iq.c
===================================================================
--- protocols/jabber/iq.c	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ protocols/jabber/iq.c	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -27,5 +27,4 @@
 static xt_status jabber_parse_roster(struct im_connection *ic, struct xt_node *node, struct xt_node *orig);
 static xt_status jabber_iq_display_vcard(struct im_connection *ic, struct xt_node *node, struct xt_node *orig);
-static xt_status jabber_gmail_handle_new(struct im_connection *ic, struct xt_node *node);
 
 xt_status jabber_pkt_iq(struct xt_node *node, gpointer data)
@@ -142,8 +141,4 @@
 		    (strcmp(s, XMLNS_SI) == 0)) {
 			return jabber_si_handle_request(ic, node, c);
-		} else if ((c = xt_find_node(node->children, "new-mail")) &&
-		           (s = xt_find_attr(c, "xmlns")) &&
-		           (strcmp(s, XMLNS_GMAILNOTIFY) == 0)) {
-			return jabber_gmail_handle_new(ic, node);
 		} else if (!(c = xt_find_node(node->children, "query")) ||
 		           !(s = xt_find_attr(c, "xmlns"))) {
@@ -347,7 +342,4 @@
 			return XT_ABORT;
 		}
-		if (jd->flags & JFLAG_GMAILNOTIFY && node == NULL) {
-			jabber_iq_query_server(ic, jd->server, XMLNS_DISCO_INFO);
-		}
 	} else if ((jd->flags & (JFLAG_WANT_BIND | JFLAG_WANT_SESSION)) == 0) {
 		if (!jabber_get_roster(ic)) {
@@ -377,23 +369,4 @@
 
 	return st;
-}
-
-xt_status jabber_iq_query_gmail(struct im_connection *ic);
-
-static xt_status jabber_gmail_handle_new(struct im_connection *ic, struct xt_node *node)
-{
-	struct xt_node *response;
-	struct jabber_data *jd = ic->proto_data;
-
-	response = jabber_make_packet("iq", "result", g_strdup_printf("%s@%s", jd->username, jd->server), NULL);
-
-	jabber_cache_add(ic, response, NULL);
-	if (!jabber_write_packet(ic, response)) {
-		return XT_ABORT;
-	}
-
-	jabber_iq_query_gmail(ic);
-
-	return XT_HANDLED;
 }
 
@@ -737,32 +710,4 @@
 }
 
-xt_status jabber_iq_parse_gmail(struct im_connection *ic, struct xt_node *node, struct xt_node *orig);
-
-xt_status jabber_iq_query_gmail(struct im_connection *ic)
-{
-	struct xt_node *node, *query;
-	struct jabber_data *jd = ic->proto_data;
-
-	node = xt_new_node("query", NULL, NULL);
-	xt_add_attr(node, "xmlns", XMLNS_GMAILNOTIFY);
-	if (jd->gmail_time) {
-		char *formatted = g_strdup_printf("%" G_GUINT64_FORMAT, (jd->gmail_time + 1));
-		xt_add_attr(node, "newer-than-time", formatted);
-		g_free(formatted);
-	}
-	if (jd->gmail_tid) {
-		xt_add_attr(node, "newer-than-tid", jd->gmail_tid);
-	}
-
-	if (!(query = jabber_make_packet("iq", "get", jd->me, node))) {
-		imcb_log(ic, "WARNING: Couldn't generate server query");
-		xt_free_node(node);
-	}
-
-	jabber_cache_add(ic, query, jabber_iq_parse_gmail);
-
-	return jabber_write_packet(ic, query) ? XT_HANDLED : XT_ABORT;
-}
-
 xt_status jabber_iq_parse_server_features(struct im_connection *ic, struct xt_node *node, struct xt_node *orig);
 
@@ -784,61 +729,4 @@
 
 	return jabber_write_packet(ic, query) ? XT_HANDLED : XT_ABORT;
-}
-
-xt_status jabber_iq_parse_gmail(struct im_connection *ic, struct xt_node *node, struct xt_node *orig)
-{
-	struct xt_node *c;
-	struct jabber_data *jd = ic->proto_data;
-	char *xmlns, *from;
-	guint64 l_time = 0;
-	char *tid = NULL;
-	int max = 0;
-
-	if (!(c = xt_find_node(node->children, "mailbox")) ||
-	    !(from = xt_find_attr(node, "from")) ||
-	    !(xmlns = xt_find_attr(c, "xmlns")) ||
-	    (g_strcmp0(xmlns, XMLNS_GMAILNOTIFY) != 0)) {
-		imcb_log(ic, "WARNING: Received incomplete mailbox packet for gmail notify");
-		return XT_HANDLED;
-	}
-
-	max = set_getint(&ic->acc->set, "mail_notifications_limit");
-	c = c->children;
-
-	while ((max-- > 0) && (c = xt_find_node(c, "mail-thread-info"))) {
-		struct xt_node *s;
-		char *subject = "<no subject>";
-		char *sender = "<no sender>";
-		guint64 t_time;
-
-		t_time = g_ascii_strtoull(xt_find_attr(c, "date"), NULL, 10);
-		if (t_time && t_time > l_time) {
-			l_time = t_time;
-			tid = xt_find_attr(c, "tid");
-		}
-
-		if ((s = xt_find_node(c->children, "senders")) &&
-		    (s = xt_find_node_by_attr(s->children, "sender", "unread", "1"))) {
-			sender = xt_find_attr(s, "name");
-		}
-
-		if ((s = xt_find_node(c->children, "subject")) && s->text) {
-			subject = s->text;
-		}
-
-		imcb_notify_email(ic, "New mail from %s: %s", sender, subject);
-
-		c = c->next;
-	}
-
-	if (l_time && (!jd->gmail_time || l_time > jd->gmail_time)) {
-		jd->gmail_time = l_time;
-		if (tid) {
-			g_free(jd->gmail_tid);
-			jd->gmail_tid = g_strdup(tid);
-		}
-	}
-
-	return XT_HANDLED;
 }
 
@@ -893,17 +781,4 @@
 			c = c->next;
 		}
-
-		if (jd->flags & JFLAG_GMAILNOTIFY) {
-			/* search for gmail notification feature */
-			c = xt_find_node(node->children, "query");
-			c = c->children;
-			while ((c = xt_find_node(c, "feature"))) {
-				if (strcmp(xt_find_attr(c, "var"), XMLNS_GMAILNOTIFY) == 0) {
-					jabber_iq_query_gmail(ic);
-				}
-				c = c->next;
-			}
-		}
-
 	} else if (strcmp(xmlns, XMLNS_BYTESTREAMS) == 0) {
 		char *host, *jid, *port_s;
Index: protocols/jabber/jabber.c
===================================================================
--- protocols/jabber/jabber.c	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ protocols/jabber/jabber.c	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -100,14 +100,5 @@
 
 	s = set_add(&acc->set, "xmlconsole", "false", set_eval_bool, acc);
-
-	s = set_add(&acc->set, "mail_notifications", "false", set_eval_bool, acc);
 	s->flags |= ACC_SET_OFFLINE_ONLY;
-
-	/* changing this is rarely needed so keeping it secret */
-	s = set_add(&acc->set, "mail_notifications_limit", "5", set_eval_int, acc);
-	s->flags |= SET_HIDDEN_DEFAULT;
-
-	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 |
@@ -269,12 +260,4 @@
 	}
 
-	if (set_getbool(&acc->set, "mail_notifications")) {
-		/* It's gmail specific, but it checks for server support before enabling it */
-		jd->flags |= JFLAG_GMAILNOTIFY;
-		if (set_getstr(&acc->set, "mail_notifications_handle")) {
-			imcb_add_buddy(ic, set_getstr(&acc->set, "mail_notifications_handle"), NULL);
-		}
-	}
-
 	jabber_generate_id_hash(jd);
 }
@@ -351,5 +334,4 @@
 	g_free(jd->away_message);
 	g_free(jd->internal_jid);
-	g_free(jd->gmail_tid);
 	g_free(jd->username);
 	g_free(jd->me);
@@ -446,5 +428,5 @@
 	}
 
-	jabber_get_vcard(ic, who);
+	jabber_get_vcard(ic, bud ? bud->full_jid : who);
 }
 
Index: protocols/jabber/jabber.h
===================================================================
--- protocols/jabber/jabber.h	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ protocols/jabber/jabber.h	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -46,5 +46,4 @@
 	JFLAG_XMLCONSOLE = 64,          /* If the user added an xmlconsole buddy. */
 	JFLAG_STARTTLS_DONE = 128,      /* If a plaintext session was converted to TLS. */
-	JFLAG_GMAILNOTIFY = 256,        /* If gmail notification is enabled */
 
 	JFLAG_GTALK =  0x100000,        /* Is Google Talk, as confirmed by iq discovery */
@@ -103,6 +102,4 @@
 	const struct jabber_away_state *away_state;
 	char *away_message;
-	guint64 gmail_time;
-	char *gmail_tid;
 
 	md5_state_t cached_id_prefix;
@@ -227,5 +224,4 @@
 #define XMLNS_DELAY        "urn:xmpp:delay"                                      /* XEP-0203 */
 #define XMLNS_XDATA        "jabber:x:data"                                       /* XEP-0004 */
-#define XMLNS_GMAILNOTIFY  "google:mail:notify"                                  /* Not a XEP */
 #define XMLNS_CHATSTATES   "http://jabber.org/protocol/chatstates"               /* XEP-0085 */
 #define XMLNS_DISCO_INFO   "http://jabber.org/protocol/disco#info"               /* XEP-0030 */
@@ -316,5 +312,4 @@
 void jabber_error_free(struct jabber_error *err);
 gboolean jabber_set_me(struct im_connection *ic, const char *me);
-char *jabber_get_bare_jid(char *jid);
 
 extern const struct jabber_away_state jabber_away_state_list[];
Index: protocols/jabber/jabber_util.c
===================================================================
--- protocols/jabber/jabber_util.c	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ protocols/jabber/jabber_util.c	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -820,18 +820,2 @@
 	return TRUE;
 }
-
-/* Returns new reference! g_free() afterwards. */
-char *jabber_get_bare_jid(char *jid)
-{
-	char *s = NULL;
-
-	if (jid == NULL) {
-		return NULL;
-	}
-
-	if ((s = strchr(jid, '/'))) {
-		return g_strndup(jid, s - jid);
-	} else {
-		return g_strdup(jid);
-	}
-}
Index: protocols/jabber/presence.c
===================================================================
--- protocols/jabber/presence.c	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ protocols/jabber/presence.c	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -181,20 +181,4 @@
 }
 
-static char *choose_priority(struct im_connection *ic)
-{
-	struct jabber_data *jd = ic->proto_data;
-	char *prio = set_getstr(&ic->acc->set, "priority");
-
-	if (jd->away_state->code != NULL) {
-		int new_prio = (atoi(prio) - 5);
-		if (new_prio < 0) {
-			new_prio = 0;
-		}
-		return g_strdup_printf("%d", new_prio);
-	}
-
-	return g_strdup(prio);
-}
-
 /* Whenever presence information is updated, call this function to inform the
    server. */
@@ -205,8 +189,7 @@
 	GSList *l;
 	int st;
-	char *prio = choose_priority(ic);
 
 	node = jabber_make_packet("presence", NULL, NULL, NULL);
-	xt_add_child(node, xt_new_node("priority", prio, NULL));
+	xt_add_child(node, xt_new_node("priority", set_getstr(&ic->acc->set, "priority"), NULL));
 	if (jd->away_state) {
 		xt_add_child(node, xt_new_node("show", jd->away_state->code, NULL));
@@ -239,5 +222,4 @@
 
 	xt_free_node(node);
-	g_free(prio);
 	return st;
 }
Index: protocols/msn/gw.c
===================================================================
--- protocols/msn/gw.c	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ protocols/msn/gw.c	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -87,12 +87,12 @@
 	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 (req->status_code != 200) {
+		gw->callback(gw->md, -1, B_EV_IO_READ);
+		return;
 	}
 
@@ -113,8 +113,5 @@
 	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;
-		}
+		gw->callback(gw->md, -1, B_EV_IO_READ);
 	}
 
Index: protocols/msn/msn.c
===================================================================
--- protocols/msn/msn.c	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ protocols/msn/msn.c	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -46,9 +46,5 @@
 	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;
+	set_add(&acc->set, "mail_notifications", "false", set_eval_bool, acc);
 
 	acc->flags |= ACC_FLAG_AWAY_MESSAGE | ACC_FLAG_STATUS_MESSAGE |
@@ -86,8 +82,4 @@
 	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);
-	}
 }
 
@@ -152,6 +144,14 @@
 {
 	struct bee_user *bu = bee_user_by_handle(ic->bee, ic, who);
-	msn_ns_send_message(ic, bu, message);
-	return 0;
+
+#ifdef DEBUG
+	if (strcmp(who, "raw") == 0) {
+		msn_ns_write(ic, -1, "%s\r\n", message);
+		return 0;
+	}
+#endif
+
+	msn_ns_sendmessage(ic, bu, message);
+	return(0);
 }
 
@@ -277,5 +277,5 @@
 		return 0;
 	} else if (typing & OPT_TYPING) {
-		return msn_ns_send_typing(ic, bu);
+		return(msn_buddy_msg(ic, who, TYPING_NOTIFICATION_MESSAGE, 0));
 	} else {
 		return 1;
@@ -338,4 +338,28 @@
 
 	g_tree_remove(md->domaintree, bu->handle);
+}
+
+GList *msn_buddy_action_list(bee_user_t *bu)
+{
+	static GList *ret = NULL;
+
+	if (ret == NULL) {
+		static const struct buddy_action ba[2] = {
+			{ "NUDGE", "Draw attention" },
+		};
+
+		ret = g_list_prepend(ret, (void *) ba + 0);
+	}
+
+	return ret;
+}
+
+void *msn_buddy_action(struct bee_user *bu, const char *action, char * const args[], void *data)
+{
+	if (g_strcasecmp(action, "NUDGE") == 0) {
+		msn_buddy_msg(bu->ic, bu->handle, NUDGE_MESSAGE, 0);
+	}
+
+	return NULL;
 }
 
@@ -368,4 +392,6 @@
 	ret->buddy_data_add = msn_buddy_data_add;
 	ret->buddy_data_free = msn_buddy_data_free;
+	ret->buddy_action_list = msn_buddy_action_list;
+	ret->buddy_action = msn_buddy_action;
 
 	register_protocol(ret);
Index: protocols/msn/msn.h
===================================================================
--- protocols/msn/msn.h	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ protocols/msn/msn.h	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -27,4 +27,16 @@
 #define _MSN_H
 
+/* Some hackish magicstrings to make special-purpose messages/switchboards.
+ */
+#define TYPING_NOTIFICATION_MESSAGE "\r\r\rBEWARE, ME R TYPINK MESSAGE!!!!\r\r\r"
+#define NUDGE_MESSAGE "\r\r\rSHAKE THAT THING\r\r\r"
+#define GROUPCHAT_SWITCHBOARD_MESSAGE "\r\r\rME WANT TALK TO MANY PEOPLE\r\r\r"
+
+#ifdef DEBUG_MSN
+#define debug(text ...) imcb_log(ic, text);
+#else
+#define debug(text ...)
+#endif
+
 /* This should be MSN Messenger 7.0.0813
 #define MSNP11_PROD_KEY "CFHUR$52U_{VIX5T"
@@ -65,5 +77,5 @@
 #define MSN_MESSAGE_HEADERS MSN_BASE_HEADERS \
 	"Messaging: 2.0\r\n" \
-	"Message-Type: %s\r\n" \
+	"Message-Type: Text\r\n" \
 	"Content-Length: %zd\r\n" \
 	"Content-Type: text/plain; charset=UTF-8\r\n" \
@@ -91,4 +103,15 @@
 	"</user>"
 
+#define MSN_TYPING_HEADERS "MIME-Version: 1.0\r\n" \
+	"Content-Type: text/x-msmsgscontrol\r\n" \
+	"TypingUser: %s\r\n" \
+	"\r\n\r\n"
+
+#define MSN_NUDGE_HEADERS "MIME-Version: 1.0\r\n" \
+	"Content-Type: text/x-msnmsgr-datacast\r\n" \
+	"\r\n" \
+	"ID: 1\r\n" \
+	"\r\n"
+
 #define PROFILE_URL "http://members.msn.com/"
 
@@ -219,6 +242,5 @@
 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_sendmessage(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);
Index: protocols/msn/ns.c
===================================================================
--- protocols/msn/ns.c	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ protocols/msn/ns.c	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -181,5 +181,4 @@
 		imcb_error(ic, "Error while reading from server");
 		imc_logout(ic, TRUE);
-		g_free(bytes);
 		return FALSE;
 	}
@@ -189,5 +188,9 @@
 	g_free(bytes);
 
-	return msn_handler(md);
+	/* Ignore ret == 0, it's already disconnected then. */
+	msn_handler(md);
+
+	return TRUE;
+	
 }
 
@@ -394,7 +397,7 @@
 
 					if (inbox && folders) {
-						imcb_notify_email(ic,
-						        "INBOX contains %s new messages, plus %s messages in other folders.", inbox,
-						        folders);
+						imcb_log(ic,
+						         "INBOX contains %s new messages, plus %s messages in other folders.", inbox,
+						         folders);
 					}
 
@@ -408,5 +411,6 @@
 
 					if (from && fromname) {
-						imcb_notify_email(ic, "Received an e-mail message from %s <%s>.", fromname, from);
+						imcb_log(ic, "Received an e-mail message from %s <%s>.", fromname,
+						         from);
 					}
 
@@ -416,4 +420,6 @@
 			} else if (g_strncasecmp(ct, "text/x-msmsgsactivemailnotification", 35) == 0) {
 				/* Notification that a message has been read... Ignore it */
+			} else {
+				debug("Can't handle %s packet from notification server", ct);
 			}
 
@@ -620,5 +626,5 @@
 	char l[4];
 
-	if ((bd->flags & (MSN_BUDDY_FL | MSN_BUDDY_AL)) == 0 || (bd->flags & MSN_BUDDY_ADL_SYNCED)) {
+	if ((bd->flags & 7) == 0 || (bd->flags & MSN_BUDDY_ADL_SYNCED)) {
 		return FALSE;
 	}
@@ -638,5 +644,5 @@
 	}
 
-	g_snprintf(l, sizeof(l), "%d", bd->flags & (MSN_BUDDY_FL | MSN_BUDDY_AL));
+	g_snprintf(l, sizeof(l), "%d", bd->flags & 7);
 	c = xt_new_node("c", NULL, NULL);
 	xt_add_attr(c, "n", handle);
@@ -691,5 +697,5 @@
 		struct msn_buddy_data *bd = bu->data;
 
-		if (bu->ic != ic || (bd->flags & (MSN_BUDDY_FL | MSN_BUDDY_AL)) == 0) {
+		if (bu->ic != ic || (bd->flags & 7) == 0) {
 			continue;
 		}
@@ -721,5 +727,6 @@
 }
 
-static int msn_ns_send_sdg(struct im_connection *ic, bee_user_t *bu, const char *message_type, const char *text)
+// TODO: typing notifications, nudges lol, etc
+int msn_ns_sendmessage(struct im_connection *ic, bee_user_t *bu, const char *text)
 {
 	struct msn_data *md = ic->proto_data;
@@ -727,18 +734,13 @@
 	char *buf;
 
-	buf = g_strdup_printf(MSN_MESSAGE_HEADERS, bu->handle, ic->acc->user, md->uuid, message_type, strlen(text), text);
+	if (strncmp(text, "\r\r\r", 3) == 0) {
+		/* Err. Shouldn't happen but I guess it can. Don't send others
+		   any of the "SHAKE THAT THING" messages. :-D */
+		return 1;
+	}
+
+	buf = g_strdup_printf(MSN_MESSAGE_HEADERS, bu->handle, ic->acc->user, md->uuid, 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);
-}
-
Index: protocols/oscar/oscar.c
===================================================================
--- protocols/oscar/oscar.c	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ protocols/oscar/oscar.c	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -456,5 +456,4 @@
 			b_event_remove(n->inpa);
 		}
-		n->inpa = 0;
 		g_free(n->name);
 		g_free(n->show);
@@ -482,13 +481,10 @@
 	if (ic->inpa > 0) {
 		b_event_remove(ic->inpa);
-		ic->inpa = 0;
 	}
 	if (odata->cnpa > 0) {
 		b_event_remove(odata->cnpa);
-		odata->cnpa = 0;
 	}
 	if (odata->paspa > 0) {
 		b_event_remove(odata->paspa);
-		odata->paspa = 0;
 	}
 	aim_session_kill(odata->sess);
@@ -641,5 +637,4 @@
 	aim_sendcookie(sess, bosconn, info->cookie);
 	b_event_remove(ic->inpa);
-	ic->inpa = 0;
 
 	return 1;
@@ -2591,5 +2586,4 @@
 	if (cc->inpa > 0) {
 		b_event_remove(cc->inpa);
-		cc->inpa = 0;
 	}
 	aim_conn_kill(od->sess, &cc->conn);
Index: protocols/oscar/ssi.c
===================================================================
--- protocols/oscar/ssi.c	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ protocols/oscar/ssi.c	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -66,5 +66,5 @@
 				newitem->gid += 0x0001;
 				for (cur = *list, i = 0; ((cur) && (!i)); cur = cur->next) {
-					if ((cur->bid == newitem->bid) && (cur->gid == newitem->gid)) {
+					if ((cur->gid == newitem->gid) && (cur->gid == newitem->gid)) {
 						i = 1;
 					}
Index: protocols/purple/purple.c
===================================================================
--- protocols/purple/purple.c	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ protocols/purple/purple.c	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -238,7 +238,4 @@
 		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;
 	}
 
@@ -340,8 +337,4 @@
 
 	purple_account_set_enabled(pd->account, "BitlBee", TRUE);
-
-	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);
-	}
 }
 
@@ -1267,5 +1260,5 @@
 	struct im_connection *ic = purple_ic_by_gc(gc);
 
-	imcb_notify_email(ic, "Received e-mail from %s for %s: %s <%s>", from, to, subject, url);
+	imcb_log(ic, "Received e-mail from %s for %s: %s <%s>", from, to, subject, url);
 
 	return NULL;
Index: protocols/skype/Makefile
===================================================================
--- protocols/skype/Makefile	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ protocols/skype/Makefile	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -7,6 +7,15 @@
 INSTALL = install
 
-all:
+
+ifdef ASCIIDOC
+MANPAGES = skyped.1
+else
+MANPAGES =
+endif
+
+all: $(MANPAGES)
+
 clean:
+	rm -f $(MANPAGES)
 
 # take this from the kernel
@@ -17,7 +26,11 @@
 	./test.py
 
-install-doc:
+doc: $(MANPAGES)
+
+install-doc: doc
+ifdef ASCIIDOC
 	$(INSTALL) -d $(DESTDIR)$(MANDIR)/man1
-	$(INSTALL) -m644 $(_SRCDIR_)skyped.1 $(DESTDIR)$(MANDIR)/man1
+	$(INSTALL) -m644 $(MANPAGES) $(DESTDIR)$(MANDIR)/man1
+endif
 
 uninstall-doc:
@@ -25,3 +38,3 @@
 
 %.1: $(_SRCDIR_)%.txt $(_SRCDIR_)asciidoc.conf
-	a2x --asciidoc-opts="-f $(_SRCDIR_)asciidoc.conf" -a bee_date=$(DATE) -f manpage $<
+	a2x --asciidoc-opts="-f $(_SRCDIR_)asciidoc.conf" -a bee_date=$(DATE) -f manpage -D . $<
Index: otocols/skype/skyped.1
===================================================================
--- protocols/skype/skyped.1	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ 	(revision )
@@ -1,207 +1,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>
Index: protocols/twitter/twitter.c
===================================================================
--- protocols/twitter/twitter.c	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ protocols/twitter/twitter.c	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -469,13 +469,9 @@
 	g_regex_match(regex, msg, 0, &match_info);
 	while (g_match_info_matches(match_info)) {
-		gchar *s, *url;
-
-		url = g_match_info_fetch(match_info, 2);
+		gchar *url = g_match_info_fetch(match_info, 2);
 		url_len_diff += target_len - g_utf8_strlen(url, -1);
-
 		/* Add another character for https://t.co/... URLs */
-		if ((s = g_match_info_fetch(match_info, 3))) {
+		if (g_match_info_fetch(match_info, 3) != NULL) {
 			url_len_diff += 1;
-			g_free(s);
 		}
 		g_free(url);
@@ -487,6 +483,8 @@
 }
 
-int twitter_message_len(gchar *msg, int target_len)
-{
+static gboolean twitter_length_check(struct im_connection *ic, gchar * msg)
+{
+	int max = set_getint(&ic->acc->set, "message_length"), len;
+	int target_len = set_getint(&ic->acc->set, "target_url_length");
 	int url_len_diff = 0;
 
@@ -495,14 +493,5 @@
 	}
 
-	return g_utf8_strlen(msg, -1) + url_len_diff;
-}
-
-static gboolean twitter_length_check(struct im_connection *ic, gchar * msg)
-{
-	int max = set_getint(&ic->acc->set, "message_length");
-	int target_len = set_getint(&ic->acc->set, "target_url_length");
-	int len = twitter_message_len(msg, target_len);
-
-	if (max == 0 || len <= max) {
+	if (max == 0 || (len = g_utf8_strlen(msg, -1) + url_len_diff) <= max) {
 		return TRUE;
 	}
@@ -863,4 +852,19 @@
 }
 
+/* Parses a decimal or hex tweet ID, returns TRUE on success */
+static gboolean twitter_parse_id(char *string, int base, guint64 *id)
+{
+	guint64 parsed;
+	char *endptr;
+
+	errno = 0;
+	parsed = g_ascii_strtoull(string, &endptr, base);
+	if (errno || endptr == string || *endptr != '\0') {
+		return FALSE;
+	}
+	*id = parsed;
+	return TRUE;
+}
+
 bee_user_t twitter_log_local_user;
 
@@ -892,8 +896,8 @@
 			arg++;
 		}
-		if (parse_int64(arg, 16, &id) && id < TWITTER_LOG_LENGTH) {
+		if (twitter_parse_id(arg, 16, &id) && id < TWITTER_LOG_LENGTH) {
 			bu = td->log[id].bu;
 			id = td->log[id].id;
-		} else if (parse_int64(arg, 10, &id)) {
+		} else if (twitter_parse_id(arg, 10, &id)) {
 			/* Allow normal tweet IDs as well; not a very useful
 			   feature but it's always been there. Just ignore
@@ -1012,5 +1016,9 @@
 			twitter_log(ic, "Tweet `%s' does not exist", cmd[1]);
 		} else {
-			twitter_status_show_url(ic, id);
+			/* More common link is twitter.com/$UID/status/$ID (and that's
+			 * what this will 302 to) but can't generate that since for RTs,
+			 * bu here points at the retweeter while id contains the id of
+			 * the original message. */
+			twitter_log(ic, "https://twitter.com/statuses/%lld", id);
 		}
 		goto eof;
Index: protocols/twitter/twitter_lib.c
===================================================================
--- protocols/twitter/twitter_lib.c	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ protocols/twitter/twitter_lib.c	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -1578,41 +1578,2 @@
 	g_free(args[1]);
 }
-
-static void twitter_http_status_show_url(struct http_request *req)
-{
-	struct im_connection *ic = req->data;
-	json_value *parsed, *id;
-	const char *name;
-
-	// Check if the connection is still active.
-	if (!g_slist_find(twitter_connections, ic)) {
-		return;
-	}
-
-	if (!(parsed = twitter_parse_response(ic, req))) {
-		return;
-	}
-
-	/* for the parson branch:
-	name = json_object_dotget_string(json_object(parsed), "user.screen_name");
-	id = json_object_get_integer(json_object(parsed), "id");
-	*/
-
-	name = json_o_str(json_o_get(parsed, "user"), "screen_name");
-	id = json_o_get(parsed, "id");
-
-	if (name && id && id->type == json_integer) {
-		twitter_log(ic, "https://twitter.com/%s/status/%" G_GUINT64_FORMAT, name, id->u.integer);
-	} else {
-		twitter_log(ic, "Error: could not fetch tweet url.");
-	}
-
-	json_value_free(parsed);
-}
-
-void twitter_status_show_url(struct im_connection *ic, guint64 id)
-{
-	char *url = g_strdup_printf("%s%" G_GUINT64_FORMAT "%s", TWITTER_STATUS_SHOW_URL, id, ".json");
-	twitter_http(ic, url, twitter_http_status_show_url, ic, 0, NULL, 0);
-	g_free(url);
-}
Index: protocols/twitter/twitter_lib.h
===================================================================
--- protocols/twitter/twitter_lib.h	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ protocols/twitter/twitter_lib.h	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -96,5 +96,4 @@
 void twitter_report_spam(struct im_connection *ic, char *screen_name);
 void twitter_favourite_tweet(struct im_connection *ic, guint64 id);
-void twitter_status_show_url(struct im_connection *ic, guint64 id);
 
 #endif //_TWITTER_LIB_H
Index: protocols/yahoo/yahoo.c
===================================================================
--- protocols/yahoo/yahoo.c	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ protocols/yahoo/yahoo.c	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -123,11 +123,5 @@
 static void byahoo_init(account_t *acc)
 {
-	set_t *s;
-
-	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;
+	set_add(&acc->set, "mail_notifications", "false", set_eval_bool, acc);
 
 	acc->flags |= ACC_FLAG_AWAY_MESSAGE | ACC_FLAG_STATUS_MESSAGE;
@@ -151,8 +145,4 @@
 	yd->y2_id = yahoo_init(acc->user, acc->pass);
 	yahoo_login(yd->y2_id, yd->current_status);
-
-	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);
-	}
 }
 
@@ -960,8 +950,10 @@
 	struct im_connection *ic = byahoo_get_ic_by_id(id);
 
-	if (from && subj) {
-		imcb_notify_email(ic, "Received e-mail message from %s with subject `%s'", from, subj);
+	if (!set_getbool(&ic->acc->set, "mail_notifications")) {
+		; /* The user doesn't care. */
+	} else if (from && subj) {
+		imcb_log(ic, "Received e-mail message from %s with subject `%s'", from, subj);
 	} else if (cnt > 0) {
-		imcb_notify_email(ic, "Received %d new e-mails", cnt);
+		imcb_log(ic, "Received %d new e-mails", cnt);
 	}
 }
Index: protocols/yahoo/yahoo2.h
===================================================================
--- protocols/yahoo/yahoo2.h	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ protocols/yahoo/yahoo2.h	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -33,4 +33,6 @@
 #undef malloc
 #define malloc(x)             g_malloc(x)
+#undef calloc
+#define calloc(x, y)          g_calloc(x, y)
 #undef realloc
 #define realloc(x, y)         g_realloc(x, y)
Index: sock.h
===================================================================
--- sock.h	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ sock.h	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -9,4 +9,4 @@
 #define sock_make_nonblocking(fd) fcntl(fd, F_SETFL, O_NONBLOCK)
 #define sock_make_blocking(fd) fcntl(fd, F_SETFL, 0)
-#define sockerr_again() (errno == EINPROGRESS || errno == EINTR || errno == EAGAIN)
+#define sockerr_again() (errno == EINPROGRESS || errno == EINTR)
 void closesocket(int fd);
Index: unix.c
===================================================================
--- unix.c	(revision b75671d9ac15f883ddb0103e5fa33c6186c32f37)
+++ unix.c	(revision d832164bf1adf4ca5e85b469e56bb1cd6ce6add1)
@@ -212,23 +212,13 @@
 		       argv[0], argv[0], argv[0], argv[0], argv[0]);
 	} else if (strcmp(argv[2], "enc") == 0) {
-		char *encoded;
-
-		pass_len = arc_encode(argv[4], strlen(argv[4]), &pass_cr, argv[3], 12);
-
-		encoded = base64_encode(pass_cr, pass_len);
-		printf("%s\n", encoded);
-		g_free(encoded);
-		g_free(pass_cr);
+		pass_len = arc_encode(argv[4], strlen(argv[4]), (unsigned char **) &pass_cr, argv[3], 12);
+		printf("%s\n", base64_encode(pass_cr, pass_len));
 	} else if (strcmp(argv[2], "dec") == 0) {
-		pass_len = base64_decode(argv[4], &pass_cr);
+		pass_len = base64_decode(argv[4], (unsigned char **) &pass_cr);
 		arc_decode(pass_cr, pass_len, (char **) &pass_cl, argv[3]);
 		printf("%s\n", pass_cl);
-
-		g_free(pass_cr);
-		g_free(pass_cl);
 	} else if (strcmp(argv[2], "hash") == 0) {
 		md5_byte_t pass_md5[21];
 		md5_state_t md5_state;
-		char *encoded;
 
 		random_bytes(pass_md5 + 16, 5);
@@ -238,7 +228,5 @@
 		md5_finish(&md5_state, pass_md5);
 
-		encoded = base64_encode(pass_md5, 21);
-		printf("%s\n", encoded);
-		g_free(encoded);
+		printf("%s\n", base64_encode(pass_md5, 21));
 	} else if (strcmp(argv[2], "unhash") == 0) {
 		printf("Hash %s submitted to a massive Beowulf cluster of\n"
