[Pkg-cli-apps-commits] [smuxi] 01/05: Imported Upstream version 0.11~rc2

Mirco Bauer meebey at moszumanska.debian.org
Sun Feb 16 20:14:08 UTC 2014


This is an automated email from the git hooks/post-receive script.

meebey pushed a commit to branch master
in repository smuxi.

commit 1fb9a2c6af6ceea5d96df5ebf46c82d0d8b7de01
Author: Mirco Bauer <meebey at meebey.net>
Date:   Sun Feb 16 20:02:44 2014 +0100

    Imported Upstream version 0.11~rc2
---
 Makefile.am                                        |   4 +
 Makefile.in                                        |   9 +-
 aclocal.m4                                         |   6 +-
 configure                                          |  32 +-
 configure.ac                                       |   2 +-
 lib/Makefile.am                                    |   2 +-
 lib/Makefile.in                                    |   4 +-
 .../src/IrcConnection/IrcConnection.cs             |   2 +
 lib/StarkSoftProxy/HttpProxyClient.cs              |   2 +-
 .../Twitterizer2/Core/OptionalProperties.cs        |   6 +-
 .../Twitterizer2/Methods/Tweets/TwitterStatus.cs   |   4 +-
 lib/Twitterizer/Twitterizer2/Twitterizer2.csproj   |   2 -
 libtool.m4                                         |  12 +-
 ltmain.sh                                          |   4 +-
 missing                                            |   4 +-
 src/AssemblyVersion.cs                             |   2 +-
 src/Common/Defines.cs                              |   4 +-
 src/Common/Makefile.in                             |   2 +-
 src/Common/NDesk.Options.cs                        |   2 +-
 src/Engine-Campfire/Makefile.in                    |   2 +-
 src/Engine-IRC/Makefile.in                         |   2 +-
 src/Engine-IRC/Protocols/Irc/IrcMessageBuilder.cs  |   6 +-
 src/Engine-IRC/Protocols/Irc/IrcProtocolManager.cs |  39 ++-
 src/Engine-JabbR/JabbrProtocolManager.cs           |  24 +-
 src/Engine-JabbR/Makefile.in                       |   2 +-
 src/Engine-Twitter/Makefile.in                     |   2 +-
 .../Protocols/Twitter/TwitterProtocolManager.cs    |   7 +-
 src/Engine-XMPP/Config/XmppServerModel.cs          |  11 -
 src/Engine-XMPP/Makefile.am                        |   2 +-
 src/Engine-XMPP/Makefile.in                        |   4 +-
 .../Protocols/Xmpp/FacebookProtocolManager.cs}     |  27 +-
 src/Engine-XMPP/Protocols/Xmpp/IQ/OwnMessage.cs    |  85 -----
 .../Protocols/Xmpp/XmppProtocolManager.cs          | 110 ++-----
 src/Engine/CommandModel.cs                         |   2 +-
 src/Engine/Config/Config.cs                        |  44 ++-
 src/Engine/Config/MessageBuilderSettings.cs        | 343 +++++++++++++++++++++
 src/Engine/Config/MessagePatternListController.cs  | 160 ++++++++++
 src/Engine/Config/MessagePatternModel.cs           | 134 ++++++++
 src/Engine/Config/ServerModel.cs                   |  27 +-
 .../Hooks/Environments/CommandHookEnvironment.cs   |   1 +
 ...HookEnvironment.cs => PersonHookEnvironment.cs} |  21 +-
 .../Environments/ProtocolManagerHookEnvironment.cs |   1 +
 src/Engine/Hooks/HookRunner.cs                     |   2 +-
 src/Engine/Makefile.am                             |   5 +-
 src/Engine/Makefile.in                             |   7 +-
 src/Engine/Messages/MessageBuilder.cs              | 129 ++++++--
 src/Engine/Messages/MessageModel.cs                |   3 +-
 src/Engine/Messages/MessageParser.cs               | 161 ----------
 src/Engine/Messages/UrlMessagePartModel.cs         |  79 ++---
 src/Engine/Protocols/ProtocolManagerBase.cs        |  18 +-
 src/Engine/Protocols/ProtocolManagerFactory.cs     |   5 +-
 src/Engine/Session.cs                              | 233 ++++++++++++--
 src/Frontend-Curses/Makefile.in                    |   2 +-
 src/Frontend-GNOME-IRC/IrcPersonChatView.cs        |  34 +-
 src/Frontend-GNOME-IRC/Makefile.am                 |   1 +
 src/Frontend-GNOME-IRC/Makefile.in                 |   3 +-
 src/Frontend-GNOME-Twitter/Makefile.in             |   2 +-
 src/Frontend-GNOME-XMPP/Makefile.in                |   2 +-
 src/Frontend-GNOME/AboutDialog.cs                  |  10 +-
 src/Frontend-GNOME/ChatViewManager.cs              |   6 +
 src/Frontend-GNOME/Entry.cs                        |   1 +
 src/Frontend-GNOME/Frontend.cs                     |  10 +-
 src/Frontend-GNOME/MainWindow.cs                   |  12 +-
 src/Frontend-GNOME/Makefile.in                     |   2 +-
 src/Frontend-GNOME/Notebook.cs                     |   1 +
 src/Frontend-GNOME/Views/ChatTreeView.cs           |  61 +++-
 src/Frontend-GNOME/Views/Chats/ChatView.cs         |  24 +-
 src/Frontend-GNOME/Views/Chats/GroupChatView.cs    |   2 +-
 src/Frontend-GNOME/Views/Chats/ProtocolChatView.cs |  14 +-
 src/Frontend-GNOME/Views/MenuWidget.cs             |  11 +-
 src/Frontend-GNOME/Views/MessageTextView.cs        |  15 +-
 src/Frontend-GNOME/Views/ServerWidget.cs           |  83 ++++-
 .../gtk-gui/Smuxi.Frontend.Gnome.ServerWidget.cs   | 194 +++++++-----
 src/Frontend-GNOME/gtk-gui/gui.stetic              | 108 ++++++-
 src/Frontend-STFL/Makefile.in                      |   2 +-
 src/Frontend-STFL/STFL/Makefile.in                 |   2 +-
 src/Frontend-SWF/Makefile.in                       |   2 +-
 src/Frontend-Test/Makefile.in                      |   2 +-
 src/Frontend/CommandManager.cs                     | 165 +++++++++-
 src/Frontend/Makefile.in                           |   2 +-
 src/Frontend/SshTunnelManager.cs                   |   7 +-
 src/Makefile.in                                    |   2 +-
 src/Server/Makefile.in                             |   2 +-
 src/smuxi-win32.nsis.in                            |   4 +
 84 files changed, 1906 insertions(+), 685 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index c365e23..87f807f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -161,6 +161,8 @@ WIN32_FILES = \
 	$(BUILD_DIR)/smuxi-engine-twitter.dll \
 	$(BUILD_DIR)/smuxi-engine-xmpp.dll \
 	$(BUILD_DIR)/smuxi-frontend-gnome-irc.dll \
+	$(BUILD_DIR)/smuxi-frontend-gnome-twitter.dll \
+	$(BUILD_DIR)/smuxi-frontend-gnome-xmpp.dll \
 	$(BUILD_DIR)/smuxi-frontend.dll \
 	$(BUILD_DIR)/Meebey.SmartIrc4net.dll \
 	$(BUILD_DIR)/Twitterizer2.dll \
@@ -182,6 +184,8 @@ OSX_FILES = \
 	$(BUILD_DIR)/smuxi-frontend-gnome.exe \
 	$(BUILD_DIR)/smuxi-frontend-gnome.exe.config \
 	$(BUILD_DIR)/smuxi-frontend-gnome-irc.dll \
+	$(BUILD_DIR)/smuxi-frontend-gnome-twitter.dll \
+	$(BUILD_DIR)/smuxi-frontend-gnome-xmpp.dll \
 	$(BUILD_DIR)/smuxi-server.exe \
 	$(BUILD_DIR)/smuxi-common.dll \
 	$(BUILD_DIR)/smuxi-engine.dll \
diff --git a/Makefile.in b/Makefile.in
index 47925da..f98ad36 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994-2013 Free Software Foundation, Inc.
@@ -502,6 +502,8 @@ WIN32_FILES = \
 	$(BUILD_DIR)/smuxi-engine-twitter.dll \
 	$(BUILD_DIR)/smuxi-engine-xmpp.dll \
 	$(BUILD_DIR)/smuxi-frontend-gnome-irc.dll \
+	$(BUILD_DIR)/smuxi-frontend-gnome-twitter.dll \
+	$(BUILD_DIR)/smuxi-frontend-gnome-xmpp.dll \
 	$(BUILD_DIR)/smuxi-frontend.dll \
 	$(BUILD_DIR)/Meebey.SmartIrc4net.dll \
 	$(BUILD_DIR)/Twitterizer2.dll \
@@ -523,6 +525,8 @@ OSX_FILES = \
 	$(BUILD_DIR)/smuxi-frontend-gnome.exe \
 	$(BUILD_DIR)/smuxi-frontend-gnome.exe.config \
 	$(BUILD_DIR)/smuxi-frontend-gnome-irc.dll \
+	$(BUILD_DIR)/smuxi-frontend-gnome-twitter.dll \
+	$(BUILD_DIR)/smuxi-frontend-gnome-xmpp.dll \
 	$(BUILD_DIR)/smuxi-server.exe \
 	$(BUILD_DIR)/smuxi-common.dll \
 	$(BUILD_DIR)/smuxi-engine.dll \
@@ -845,9 +849,10 @@ distcheck: dist
 	  && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
 	  && am__cwd=`pwd` \
 	  && $(am__cd) $(distdir)/_build \
-	  && ../configure --srcdir=.. --prefix="$$dc_install_base" \
+	  && ../configure \
 	    $(AM_DISTCHECK_CONFIGURE_FLAGS) \
 	    $(DISTCHECK_CONFIGURE_FLAGS) \
+	    --srcdir=.. --prefix="$$dc_install_base" \
 	  && $(MAKE) $(AM_MAKEFLAGS) \
 	  && $(MAKE) $(AM_MAKEFLAGS) dvi \
 	  && $(MAKE) $(AM_MAKEFLAGS) check \
diff --git a/aclocal.m4 b/aclocal.m4
index cfd51c6..3aa004d 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -1,4 +1,4 @@
-# generated automatically by aclocal 1.14 -*- Autoconf -*-
+# generated automatically by aclocal 1.14.1 -*- Autoconf -*-
 
 # Copyright (C) 1996-2013 Free Software Foundation, Inc.
 
@@ -2625,7 +2625,7 @@ AC_DEFUN([AM_AUTOMAKE_VERSION],
 [am__api_version='1.14'
 dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
 dnl require some minimum version.  Point them to the right macro.
-m4_if([$1], [1.14], [],
+m4_if([$1], [1.14.1], [],
       [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
 ])
 
@@ -2641,7 +2641,7 @@ m4_define([_AM_AUTOCONF_VERSION], [])
 # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
 # This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
 AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
-[AM_AUTOMAKE_VERSION([1.14])dnl
+[AM_AUTOMAKE_VERSION([1.14.1])dnl
 m4_ifndef([AC_AUTOCONF_VERSION],
   [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
 _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
diff --git a/configure b/configure
index 207667e..a178b5b 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for smuxi 0.10.
+# Generated by GNU Autoconf 2.69 for smuxi 0.11.
 #
 # Report bugs to <https://smuxi.im/issues/new>.
 #
@@ -590,8 +590,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='smuxi'
 PACKAGE_TARNAME='smuxi'
-PACKAGE_VERSION='0.10'
-PACKAGE_STRING='smuxi 0.10'
+PACKAGE_VERSION='0.11'
+PACKAGE_STRING='smuxi 0.11'
 PACKAGE_BUGREPORT='https://smuxi.im/issues/new'
 PACKAGE_URL=''
 
@@ -1543,7 +1543,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures smuxi 0.10 to adapt to many kinds of systems.
+\`configure' configures smuxi 0.11 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1613,7 +1613,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of smuxi 0.10:";;
+     short | recursive ) echo "Configuration of smuxi 0.11:";;
    esac
   cat <<\_ACEOF
 
@@ -1829,7 +1829,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-smuxi configure 0.10
+smuxi configure 0.11
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2107,7 +2107,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by smuxi $as_me 0.10, which was
+It was created by smuxi $as_me 0.11, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -2973,7 +2973,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='smuxi'
- VERSION='0.10'
+ VERSION='0.11'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -6729,7 +6729,7 @@ ia64-*-hpux*)
   rm -rf conftest*
   ;;
 
-x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \
 s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
   # Find out which ABI we are using.
   echo 'int i;' > conftest.$ac_ext
@@ -6754,7 +6754,10 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
 		;;
 	    esac
 	    ;;
-	  ppc64-*linux*|powerpc64-*linux*)
+	  powerpc64le-*)
+	    LD="${LD-ld} -m elf32lppclinux"
+	    ;;
+	  powerpc64-*)
 	    LD="${LD-ld} -m elf32ppclinux"
 	    ;;
 	  s390x-*linux*)
@@ -6773,7 +6776,10 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
 	  x86_64-*linux*)
 	    LD="${LD-ld} -m elf_x86_64"
 	    ;;
-	  ppc*-*linux*|powerpc*-*linux*)
+	  powerpcle-*)
+	    LD="${LD-ld} -m elf64lppc"
+	    ;;
+	  powerpc-*)
 	    LD="${LD-ld} -m elf64ppc"
 	    ;;
 	  s390*-*linux*|s390*-*tpf*)
@@ -18789,7 +18795,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by smuxi $as_me 0.10, which was
+This file was extended by smuxi $as_me 0.11, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -18846,7 +18852,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-smuxi config.status 0.10
+smuxi config.status 0.11
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
diff --git a/configure.ac b/configure.ac
index 5566555..be2ee56 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
 AC_PREREQ([2.54])
-AC_INIT([smuxi], [0.10], [https://smuxi.im/issues/new])
+AC_INIT([smuxi], [0.11], [https://smuxi.im/issues/new])
 # using the --foreign option makes automake less strict about GNU policy 
 AC_CONFIG_MACRO_DIR([.])
 AM_INIT_AUTOMAKE([foreign tar-ustar])
diff --git a/lib/Makefile.am b/lib/Makefile.am
index b067696..017cfc2 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -37,7 +37,7 @@ SERVICESTACK_COMMON_EXTRA_FILES = $(SERVICESTACK_COMMON_BUILD_FILE)
 SERVICESTACK_COMMON_ASSEMBLY_NAME = ServiceStack.Common.dll
 SERVICESTACK_COMMON_ASSEMBLY_TARGET = $(OUTPUT_DIR)/$(SERVICESTACK_COMMON_ASSEMBLY_NAME)
 SERVICESTACK_COMMON_BUILD_FILE = $(SERVICESTACK_COMMON_SRCDIR)/ServiceStack.Common.csproj
-SERVICESTACK_COMMON_XBUILD_FLAGS = $(XBUILD_FLAGS)
+SERVICESTACK_COMMON_XBUILD_FLAGS = $(XBUILD_FLAGS) /property:DefineConstants="MONOTOUCH"
 
 EXTRA_SERVICESTACK_LIBS = \
 	$(SERVICESTACK_TEXT_ASSEMBLY_TARGET) $(SERVICESTACK_TEXT_ASSEMBLY_TARGET).mdb \
diff --git a/lib/Makefile.in b/lib/Makefile.in
index 28773d2..628e243 100644
--- a/lib/Makefile.in
+++ b/lib/Makefile.in
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994-2013 Free Software Foundation, Inc.
@@ -457,7 +457,7 @@ SERVICESTACK_COMMON_EXTRA_FILES = $(SERVICESTACK_COMMON_BUILD_FILE)
 SERVICESTACK_COMMON_ASSEMBLY_NAME = ServiceStack.Common.dll
 SERVICESTACK_COMMON_ASSEMBLY_TARGET = $(OUTPUT_DIR)/$(SERVICESTACK_COMMON_ASSEMBLY_NAME)
 SERVICESTACK_COMMON_BUILD_FILE = $(SERVICESTACK_COMMON_SRCDIR)/ServiceStack.Common.csproj
-SERVICESTACK_COMMON_XBUILD_FLAGS = $(XBUILD_FLAGS)
+SERVICESTACK_COMMON_XBUILD_FLAGS = $(XBUILD_FLAGS) /property:DefineConstants="MONOTOUCH"
 EXTRA_SERVICESTACK_LIBS = \
 	$(SERVICESTACK_TEXT_ASSEMBLY_TARGET) $(SERVICESTACK_TEXT_ASSEMBLY_TARGET).mdb \
 	$(SERVICESTACK_INTERFACES_ASSEMBLY_TARGET) $(SERVICESTACK_INTERFACES_ASSEMBLY_TARGET).mdb \
diff --git a/lib/SmartIrc4net/src/IrcConnection/IrcConnection.cs b/lib/SmartIrc4net/src/IrcConnection/IrcConnection.cs
index 4429519..afeaab9 100644
--- a/lib/SmartIrc4net/src/IrcConnection/IrcConnection.cs
+++ b/lib/SmartIrc4net/src/IrcConnection/IrcConnection.cs
@@ -812,6 +812,7 @@ namespace Meebey.SmartIrc4net
             
             IsDisconnecting = true;
             
+            _IdleWorkerThread.Stop();
             _ReadThread.Stop();
             _WriteThread.Stop();
             _TcpClient.Close();
@@ -1467,6 +1468,7 @@ namespace Meebey.SmartIrc4net
             public void Stop()
             {
                 _Thread.Abort();
+                _Thread.Join();
             }
 
             private void _Worker()
diff --git a/lib/StarkSoftProxy/HttpProxyClient.cs b/lib/StarkSoftProxy/HttpProxyClient.cs
index e4a6e9c..bbeaa76 100644
--- a/lib/StarkSoftProxy/HttpProxyClient.cs
+++ b/lib/StarkSoftProxy/HttpProxyClient.cs
@@ -53,7 +53,7 @@ namespace Starksoft.Net.Proxy
         private TcpClient _tcpClient;
 
         private const int HTTP_PROXY_DEFAULT_PORT = 8080;
-        private const string HTTP_PROXY_CONNECT_CMD = "CONNECT {0}:{1} HTTP/1.0\r\nHOST {0}:{1}\r\n\r\n";
+        private const string HTTP_PROXY_CONNECT_CMD = "CONNECT {0}:{1} HTTP/1.0\r\nHost: {0}:{1}\r\n\r\n";
         private const int WAIT_FOR_DATA_INTERVAL = 50; // 50 ms
         private const int WAIT_FOR_DATA_TIMEOUT = 15000; // 15 seconds
         private const string PROXY_NAME = "HTTP";
diff --git a/lib/Twitterizer/Twitterizer2/Core/OptionalProperties.cs b/lib/Twitterizer/Twitterizer2/Core/OptionalProperties.cs
index 21770d5..d78c9ee 100644
--- a/lib/Twitterizer/Twitterizer2/Core/OptionalProperties.cs
+++ b/lib/Twitterizer/Twitterizer2/Core/OptionalProperties.cs
@@ -50,8 +50,10 @@ namespace Twitterizer
         public OptionalProperties()
         {
             // Set the default values for the properties
-            this.UseSSL = false;
-            this.APIBaseAddress = "http://api.twitter.com/1.1/";
+            // as of 14 Janary 2014 HTTPS is required and enforced:
+            // https://dev.twitter.com/discussions/24239
+            this.UseSSL = true;
+            this.APIBaseAddress = "https://api.twitter.com/1.1/";
         }
 
         /// <include file='OptionalProperties.xml' path='OptionalProperties/Property[@name="UseSSL"]/*'/>
diff --git a/lib/Twitterizer/Twitterizer2/Methods/Tweets/TwitterStatus.cs b/lib/Twitterizer/Twitterizer2/Methods/Tweets/TwitterStatus.cs
index 96aa0d2..da61d6f 100644
--- a/lib/Twitterizer/Twitterizer2/Methods/Tweets/TwitterStatus.cs
+++ b/lib/Twitterizer/Twitterizer2/Methods/Tweets/TwitterStatus.cs
@@ -251,7 +251,7 @@ namespace Twitterizer
                     TwitterHashTagEntity tagEntity = (TwitterHashTagEntity)entity;
 
                     linkedText = string.Format(
-                        "{0}<a href=\"http://twitter.com/search?q=%23{1}\">{1}</a>{2}",
+                        "{0}<a href=\"https://twitter.com/search?q=%23{1}\">{1}</a>{2}",
                         linkedText.Substring(0, entity.StartIndex),
                         tagEntity.Text,
                         linkedText.Substring(entity.EndIndex));
@@ -273,7 +273,7 @@ namespace Twitterizer
                     TwitterMentionEntity mentionEntity = (TwitterMentionEntity)entity;
 
                     linkedText = string.Format(
-                        "{0}<a href=\"http://twitter.com/{1}\">@{1}</a>{2}",
+                        "{0}<a href=\"https://twitter.com/{1}\">@{1}</a>{2}",
                         linkedText.Substring(0, entity.StartIndex),
                         mentionEntity.ScreenName,
                         linkedText.Substring(entity.EndIndex));
diff --git a/lib/Twitterizer/Twitterizer2/Twitterizer2.csproj b/lib/Twitterizer/Twitterizer2/Twitterizer2.csproj
index 98b7e15..f0d5f6f 100644
--- a/lib/Twitterizer/Twitterizer2/Twitterizer2.csproj
+++ b/lib/Twitterizer/Twitterizer2/Twitterizer2.csproj
@@ -334,11 +334,9 @@
   <ItemGroup>
     <Content Include="..\GettingStarted.txt">
       <Link>GettingStarted.txt</Link>
-      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
     </Content>
     <Content Include="..\Twitterizer2.license.txt">
       <Link>Twitterizer2.license.txt</Link>
-      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
     </Content>
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
diff --git a/libtool.m4 b/libtool.m4
index 02b4bbe..d7c043f 100644
--- a/libtool.m4
+++ b/libtool.m4
@@ -1312,7 +1312,7 @@ ia64-*-hpux*)
   rm -rf conftest*
   ;;
 
-x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \
 s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
   # Find out which ABI we are using.
   echo 'int i;' > conftest.$ac_ext
@@ -1333,7 +1333,10 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
 		;;
 	    esac
 	    ;;
-	  ppc64-*linux*|powerpc64-*linux*)
+	  powerpc64le-*)
+	    LD="${LD-ld} -m elf32lppclinux"
+	    ;;
+	  powerpc64-*)
 	    LD="${LD-ld} -m elf32ppclinux"
 	    ;;
 	  s390x-*linux*)
@@ -1352,7 +1355,10 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
 	  x86_64-*linux*)
 	    LD="${LD-ld} -m elf_x86_64"
 	    ;;
-	  ppc*-*linux*|powerpc*-*linux*)
+	  powerpcle-*)
+	    LD="${LD-ld} -m elf64lppc"
+	    ;;
+	  powerpc-*)
 	    LD="${LD-ld} -m elf64ppc"
 	    ;;
 	  s390*-*linux*|s390*-*tpf*)
diff --git a/ltmain.sh b/ltmain.sh
index 68c6d96..9fe8f59 100644
--- a/ltmain.sh
+++ b/ltmain.sh
@@ -70,7 +70,7 @@
 #         compiler:		$LTCC
 #         compiler flags:		$LTCFLAGS
 #         linker:		$LD (gnu? $with_gnu_ld)
-#         $progname:	(GNU libtool) 2.4.2 Debian-2.4.2-1.3
+#         $progname:	(GNU libtool) 2.4.2 Debian-2.4.2-1.6
 #         automake:	$automake_version
 #         autoconf:	$autoconf_version
 #
@@ -80,7 +80,7 @@
 
 PROGRAM=libtool
 PACKAGE=libtool
-VERSION="2.4.2 Debian-2.4.2-1.3"
+VERSION="2.4.2 Debian-2.4.2-1.6"
 TIMESTAMP=""
 package_revision=1.3337
 
diff --git a/missing b/missing
index cdea514..db98974 100755
--- a/missing
+++ b/missing
@@ -1,7 +1,7 @@
 #! /bin/sh
 # Common wrapper for a few potentially missing GNU programs.
 
-scriptversion=2012-06-26.16; # UTC
+scriptversion=2013-10-28.13; # UTC
 
 # Copyright (C) 1996-2013 Free Software Foundation, Inc.
 # Originally written by Fran,cois Pinard <pinard at iro.umontreal.ca>, 1996.
@@ -160,7 +160,7 @@ give_advice ()
       ;;
    autom4te*)
       echo "You might have modified some maintainer files that require"
-      echo "the 'automa4te' program to be rebuilt."
+      echo "the 'autom4te' program to be rebuilt."
       program_details 'autom4te'
       ;;
     bison*|yacc*)
diff --git a/src/AssemblyVersion.cs b/src/AssemblyVersion.cs
index 9cd48b8..4e252c4 100644
--- a/src/AssemblyVersion.cs
+++ b/src/AssemblyVersion.cs
@@ -36,5 +36,5 @@ using System.Runtime.CompilerServices;
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
 
-[assembly: AssemblyVersion("0.10")]
+[assembly: AssemblyVersion("0.11")]
 
diff --git a/src/Common/Defines.cs b/src/Common/Defines.cs
index 2d0463b..eaeaa2e 100644
--- a/src/Common/Defines.cs
+++ b/src/Common/Defines.cs
@@ -27,10 +27,10 @@ namespace Smuxi.Common
     public static class Defines
     {
         public const string GitBranch   = "master";
-        public const string GitCommitHash = "4136a63";
+        public const string GitCommitHash = "f6b01ea";
 
         private static readonly string f_InstallPrefix = "/usr/local";
-        private static readonly string f_DistVersion = "master/4136a63";
+        private static readonly string f_DistVersion = "master/f6b01ea";
         private static readonly string f_TwitterApiKey = "60QV2qQx9cS7y1BJDbgAA|2VgD6qQKddsF5HYQ0TrRgs3tFTnCwDONBmRlTmG658";
 
         public static string InstallPrefix {
diff --git a/src/Common/Makefile.in b/src/Common/Makefile.in
index e22d866..0b8524c 100644
--- a/src/Common/Makefile.in
+++ b/src/Common/Makefile.in
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994-2013 Free Software Foundation, Inc.
diff --git a/src/Common/NDesk.Options.cs b/src/Common/NDesk.Options.cs
index 2b23d9c..2ad7124 100644
--- a/src/Common/NDesk.Options.cs
+++ b/src/Common/NDesk.Options.cs
@@ -765,7 +765,7 @@ namespace Mono.Options
 			return false;
 		}
 
-		private readonly Regex ValueOption = new Regex (
+		static readonly Regex ValueOption = new Regex (
 			@"^(?<flag>--|-|/)(?<name>[^:=]+)((?<sep>[:=])(?<value>.*))?$");
 
 		protected bool GetOptionParts (string argument, out string flag, out string name, out string sep, out string value)
diff --git a/src/Engine-Campfire/Makefile.in b/src/Engine-Campfire/Makefile.in
index f6b6b48..22d7977 100644
--- a/src/Engine-Campfire/Makefile.in
+++ b/src/Engine-Campfire/Makefile.in
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994-2013 Free Software Foundation, Inc.
diff --git a/src/Engine-IRC/Makefile.in b/src/Engine-IRC/Makefile.in
index 645b462..0e6f8ae 100644
--- a/src/Engine-IRC/Makefile.in
+++ b/src/Engine-IRC/Makefile.in
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994-2013 Free Software Foundation, Inc.
diff --git a/src/Engine-IRC/Protocols/Irc/IrcMessageBuilder.cs b/src/Engine-IRC/Protocols/Irc/IrcMessageBuilder.cs
index 953749c..64a39fe 100644
--- a/src/Engine-IRC/Protocols/Irc/IrcMessageBuilder.cs
+++ b/src/Engine-IRC/Protocols/Irc/IrcMessageBuilder.cs
@@ -55,11 +55,11 @@ namespace Smuxi.Engine
             }
 
             // strip color and formatting if configured
-            if (StripColors) {
+            if (Settings.StripColors) {
                 msg = Regex.Replace(msg, (char)IrcControlCode.Color +
                             "[0-9]{1,2}(,[0-9]{1,2})?", String.Empty);
             }
-            if (StripFormattings) {
+            if (Settings.StripFormattings) {
                 msg = Regex.Replace(msg, String.Format("({0}|{1}|{2}|{3})",
                                                     (char)IrcControlCode.Bold,
                                                     (char)IrcControlCode.Clear,
@@ -209,7 +209,7 @@ namespace Smuxi.Engine
                 msgPart.Italic = italic;
                 msgPart.ForegroundColor = fg_color;
                 msgPart.BackgroundColor = bg_color;
-                AppendText(msgPart);
+                Append(ParsePatterns(msgPart));
             } while (controlCharFound);
             return this;
         }
diff --git a/src/Engine-IRC/Protocols/Irc/IrcProtocolManager.cs b/src/Engine-IRC/Protocols/Irc/IrcProtocolManager.cs
index 04c72d8..0c258fd 100644
--- a/src/Engine-IRC/Protocols/Irc/IrcProtocolManager.cs
+++ b/src/Engine-IRC/Protocols/Irc/IrcProtocolManager.cs
@@ -1,7 +1,7 @@
 /*
  * Smuxi - Smart MUltipleXed Irc
  *
- * Copyright (c) 2005-2013 Mirco Bauer <meebey at meebey.net>
+ * Copyright (c) 2005-2014 Mirco Bauer <meebey at meebey.net>
  *
  * Full GPL License: <http://www.gnu.org/licenses/gpl.txt>
  *
@@ -48,6 +48,7 @@ namespace Smuxi.Engine
         private int             _Port;
         private string          _Network;
         private string[]        _Nicknames;
+        string _Realname;
         private int             _CurrentNickname;
         private string          _Username;
         private string          _Password;
@@ -261,6 +262,14 @@ namespace Smuxi.Engine
                 host = _IrcClient.Address;
             } else {
                 host = NetworkID;
+                var serverSettings = new ServerListController(Session.UserConfig);
+                var server = serverSettings.GetServerByNetwork(host);
+                if (server == null) {
+                    // if the network is not stored in config, we need to
+                    // fallback to the bare server address. Otherwise the
+                    // frontend will have no idea how to connect to it.
+                    host = _IrcClient.Address;
+                }
             }
             string url = String.Format("irc://{0}/{1}", host, e.Channel);
             builder.AppendUrl(url, _("Accept invite (join room)"));
@@ -396,8 +405,8 @@ namespace Smuxi.Engine
                 builder.AppendEventPrefix().AppendText(_("Logging in..."));
                 Session.AddMessageToChat(Chat, builder.ToMessage());
 
-                string realname = (string) Session.UserConfig["Connection/Realname"];
-                if (realname.Trim().Length == 0) {
+                string realname = _Realname;
+                if (realname == null || realname.Trim().Length == 0) {
                     realname = "unset";
                 }
                 if (!Regex.IsMatch(_Username, "^[a-z0-9]+$", RegexOptions.IgnoreCase)) {
@@ -1190,6 +1199,8 @@ namespace Smuxi.Engine
                 // ok, these channels will be queued
                 builder = CreateMessageBuilder();
                 builder.AppendEventPrefix();
+                // TRANSLATOR: some IRC networks dislike too many joins in a
+                // short period and thus Smuxi throttles/queues them
                 builder.AppendText(_("Queuing joins: {0}"),
                                    String.Join(" ", channels));
                 Session.AddMessageToFrontend(cd.FrontendManager, Chat,
@@ -1206,7 +1217,8 @@ namespace Smuxi.Engine
                 }
 
                 string key = keys != null && keys.Length > i ? keys[i] : null;
-                if (GetChat(chan, ChatType.Group) != null) {
+                var chat = GetChat(chan, ChatType.Group);
+                if (chat != null && chat.IsEnabled) {
                     builder = CreateMessageBuilder();
                     builder.AppendEventPrefix();
                     builder.AppendText(
@@ -2456,6 +2468,16 @@ namespace Smuxi.Engine
             } else {
                 _Network = server.Network;
             }
+            if (String.IsNullOrEmpty(server.Nickname)) {
+                _Nicknames = (string[]) config["Connection/Nicknames"];
+            } else {
+                _Nicknames = server.Nickname.Split(' ');
+            }
+            if (String.IsNullOrEmpty(server.Realname)) {
+                _Realname = (string) config["Connection/Realname"];
+            } else {
+                _Realname = server.Realname;
+            }
             if (String.IsNullOrEmpty(server.Username)) {
                 _Username = (string) config["Connection/Username"];
             } else {
@@ -2476,11 +2498,6 @@ namespace Smuxi.Engine
                 }
             }
 
-            // global fallbacks
-            if (_Nicknames == null) {
-                _Nicknames = (string[]) config["Connection/Nicknames"];
-            }
-
             // add fallbacks if only one nick was specified, else we get random
             // number nicks when nick collisions happen
             if (_Nicknames.Length == 1) {
@@ -3315,7 +3332,7 @@ namespace Smuxi.Engine
             if (!String.IsNullOrEmpty(e.PartMessage)) {
                 builder.AppendText(" [");
                 // colors in part messages are annoying
-                builder.StripColors = true;
+                builder.Settings.StripColors = true;
                 builder.AppendMessage(e.PartMessage);
                 builder.AppendText("]");
             }
@@ -3638,7 +3655,7 @@ namespace Smuxi.Engine
                                                    e.Data.Ident, e.Data.Host));
                 builder.AppendText(" [");
                 // colors are annoying in quit messages
-                builder.StripColors = true;
+                builder.Settings.StripColors = true;
                 builder.AppendMessage(e.QuitMessage);
                 builder.AppendText("]");
                 var quitMsg = builder.ToMessage();
diff --git a/src/Engine-JabbR/JabbrProtocolManager.cs b/src/Engine-JabbR/JabbrProtocolManager.cs
index d6cf983..59ac27c 100644
--- a/src/Engine-JabbR/JabbrProtocolManager.cs
+++ b/src/Engine-JabbR/JabbrProtocolManager.cs
@@ -1,6 +1,6 @@
 // Smuxi - Smart MUltipleXed Irc
 // 
-// Copyright (c) 2012-2013 Mirco Bauer <meebey at meebey.net>
+// Copyright (c) 2012-2014 Mirco Bauer <meebey at meebey.net>
 // 
 // Full GPL License: <http://www.gnu.org/licenses/gpl.txt>
 // 
@@ -101,7 +101,7 @@ namespace Smuxi.Engine
             var builder = CreateMessageBuilder().
                 AppendEventPrefix().
                 AppendHeader(_("JabbR Commands"));
-            cmd.FrontendManager.AddMessageToChat(cmd.Chat, builder.ToMessage());
+            Session.AddMessageToFrontend(cmd, builder.ToMessage());
 
             string[] help = {
                 "connect jabbr username password",
@@ -112,7 +112,7 @@ namespace Smuxi.Engine
                 builder = CreateMessageBuilder();
                 builder.AppendEventPrefix();
                 builder.AppendText(line);
-                cmd.FrontendManager.AddMessageToChat(cmd.Chat, builder.ToMessage());
+                Session.AddMessageToFrontend(cmd, builder.ToMessage());
             }
         }
 
@@ -465,7 +465,19 @@ namespace Smuxi.Engine
             if (sender != Me) {
                 builder.MarkHighlights();
             }
-            Session.AddMessageToChat(chat, builder.ToMessage());
+            var message = builder.ToMessage();
+            Session.AddMessageToChat(chat, message);
+
+            if (sender == Me) {
+                // server echos our sent messages for us
+                OnMessageSent(
+                    new MessageEventArgs(chat, message, null, chat.ID)
+                );
+            } else {
+                OnMessageReceived(
+                    new MessageEventArgs(chat, message, name, chat.ID)
+                );
+            }
         }
 
         void OnMeMessageReceived(string userName, string content, string roomName)
@@ -483,6 +495,10 @@ namespace Smuxi.Engine
             }
             var msg = builder.ToMessage();
             Session.AddMessageToChat(chat, msg);
+
+            OnMessageReceived(
+                new MessageEventArgs(chat, msg, userName, roomName)
+            );
         }
 
         void OnUserJoined(User user, string room, bool isOwner)
diff --git a/src/Engine-JabbR/Makefile.in b/src/Engine-JabbR/Makefile.in
index 48b64c5..04bbb7f 100644
--- a/src/Engine-JabbR/Makefile.in
+++ b/src/Engine-JabbR/Makefile.in
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994-2013 Free Software Foundation, Inc.
diff --git a/src/Engine-Twitter/Makefile.in b/src/Engine-Twitter/Makefile.in
index 3815277..f530179 100644
--- a/src/Engine-Twitter/Makefile.in
+++ b/src/Engine-Twitter/Makefile.in
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994-2013 Free Software Foundation, Inc.
diff --git a/src/Engine-Twitter/Protocols/Twitter/TwitterProtocolManager.cs b/src/Engine-Twitter/Protocols/Twitter/TwitterProtocolManager.cs
index 893725d..f56635e 100644
--- a/src/Engine-Twitter/Protocols/Twitter/TwitterProtocolManager.cs
+++ b/src/Engine-Twitter/Protocols/Twitter/TwitterProtocolManager.cs
@@ -1046,7 +1046,10 @@ namespace Smuxi.Engine
             } else {
                 // parameter is a screen name
                 var screenName = cmd.Parameter;
-                person = persons.Single((arg) => arg.Value.IdentityName == screenName).Value;
+                person = persons.SingleOrDefault((arg) => arg.Value.IdentityName == screenName).Value;
+                if (person == null) {
+                    return;
+                }
                 var res = TwitterFriendship.Delete(f_OAuthTokens, screenName, f_OptionalProperties);
                 CheckResponse(res);
             }
@@ -1687,7 +1690,7 @@ namespace Smuxi.Engine
             lock (StatusIndex) {
                 var slot = ++StatusIndexOffset;
                 if (slot > StatusIndex.Length) {
-                    StatusIndexOffset = 0;
+                    StatusIndexOffset = 1;
                     slot = 1;
                 }
                 StatusIndex[slot - 1] = status;
diff --git a/src/Engine-XMPP/Config/XmppServerModel.cs b/src/Engine-XMPP/Config/XmppServerModel.cs
index c29c3a7..c22127b 100644
--- a/src/Engine-XMPP/Config/XmppServerModel.cs
+++ b/src/Engine-XMPP/Config/XmppServerModel.cs
@@ -37,17 +37,6 @@ namespace Smuxi.Engine
             Protocol = "XMPP";
         }
         
-        public virtual void Load(UserConfig config, string id)
-        {
-            if (config == null) {
-                throw new ArgumentNullException("config");
-            }
-            if (String.IsNullOrEmpty(id)) {
-                throw new ArgumentNullException("id");
-            }
-            Load(config, Protocol, id);
-        }
-        
         public XmppServerModel()
         {
             InitDefaults();
diff --git a/src/Engine-XMPP/Makefile.am b/src/Engine-XMPP/Makefile.am
index 352bec8..9feb5d6 100644
--- a/src/Engine-XMPP/Makefile.am
+++ b/src/Engine-XMPP/Makefile.am
@@ -10,7 +10,7 @@ SOURCES = \
 	Protocols/Xmpp/XmppGroupChatModel.cs \
 	Protocols/Xmpp/XmppProtocolManager.cs \
 	Config/XmppPersonModel.cs \
-	Protocols/Xmpp/IQ/OwnMessage.cs
+	Protocols/Xmpp/FacebookProtocolManager.cs
 
 REFERENCES = \
 	System \
diff --git a/src/Engine-XMPP/Makefile.in b/src/Engine-XMPP/Makefile.in
index d6f5f4c..5864b1e 100644
--- a/src/Engine-XMPP/Makefile.in
+++ b/src/Engine-XMPP/Makefile.in
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994-2013 Free Software Foundation, Inc.
@@ -399,7 +399,7 @@ SOURCES = \
 	Protocols/Xmpp/XmppGroupChatModel.cs \
 	Protocols/Xmpp/XmppProtocolManager.cs \
 	Config/XmppPersonModel.cs \
-	Protocols/Xmpp/IQ/OwnMessage.cs
+	Protocols/Xmpp/FacebookProtocolManager.cs
 
 REFERENCES = \
 	System \
diff --git a/src/Engine/Hooks/Environments/CommandHookEnvironment.cs b/src/Engine-XMPP/Protocols/Xmpp/FacebookProtocolManager.cs
similarity index 60%
copy from src/Engine/Hooks/Environments/CommandHookEnvironment.cs
copy to src/Engine-XMPP/Protocols/Xmpp/FacebookProtocolManager.cs
index 963bac0..97b1c17 100644
--- a/src/Engine/Hooks/Environments/CommandHookEnvironment.cs
+++ b/src/Engine-XMPP/Protocols/Xmpp/FacebookProtocolManager.cs
@@ -1,6 +1,6 @@
 // Smuxi - Smart MUltipleXed Irc
 //
-// Copyright (c) 2013 Mirco Bauer <meebey at meebey.net>
+// Copyright (c) 2014 Oliver Schneider <smuxi at oli-obk.de>
 //
 // Full GPL License: <http://www.gnu.org/licenses/gpl.txt>
 //
@@ -18,19 +18,30 @@
 // along with this program; if not, write to the Free Software
 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 using System;
+using Smuxi.Engine;
+using Smuxi.Common;
 
 namespace Smuxi.Engine
 {
-    public class CommandHookEnvironment : HookEnvironment
+    [ProtocolManagerInfo(Name = "Facebook", Description = "Facebook XMPP", Alias = "facebook")]
+    public class FacebookProtocolManager : XmppProtocolManager
     {
-        public CommandHookEnvironment(CommandModel cmd)
-        {
-            if (cmd == null) {
-                throw new ArgumentNullException("cmd");
+        public override string Protocol {
+            get {
+                return "Facebook";
             }
+        }
 
-            this["CMD"] = cmd.Command;
-            this["CMD_PARAMETER"] = cmd.Parameter;
+        public FacebookProtocolManager(Session session) :
+                base(session)
+        {
+            Trace.Call(session);
+        }
+
+        override protected string GenerateIdString(PersonModel contact)
+        {
+            return "";
         }
     }
 }
+
diff --git a/src/Engine-XMPP/Protocols/Xmpp/IQ/OwnMessage.cs b/src/Engine-XMPP/Protocols/Xmpp/IQ/OwnMessage.cs
deleted file mode 100644
index 02e1aee..0000000
--- a/src/Engine-XMPP/Protocols/Xmpp/IQ/OwnMessage.cs
+++ /dev/null
@@ -1,85 +0,0 @@
-// Smuxi - Smart MUltipleXed Irc
-//
-// Copyright (c) 2011 <meebey at meebey.net>
-//
-// Full GPL License: <http://www.gnu.org/licenses/gpl.txt>
-//
-// 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
-
-using System;
-using System.Xml;
-
-
-using agsXMPP;
-using agsXMPP.protocol;
-using agsXMPP.protocol.client;
-using agsXMPP.Xml.Dom;
-
-namespace Smuxi.Engine
-{
-    /*
-     * <iq from="chat.facebook.com" type="set" id="fbiq4B035BDF6E005" to="username at chat.facebook.com/resource" xmlns="jabber:client">
-     *   <own-message xmlns="http://www.facebook.com/xmpp/messages" to="user_id at chat.facebook.com" self="false">
-     *     <body>message goes here</body>
-     *   </own-message>
-     * </iq>
-     */
-
-
-    internal class OwnMessageQuery : Element
-    {
-        /// <summary>
-        ///
-        /// </summary>
-        /// <param name="doc"></param>
-        public OwnMessageQuery()
-        {
-            base.Namespace = "http://www.facebook.com/xmpp/messages";
-            base.TagName = "own-message";
-        }
-
-        public Jid To {
-            get {
-                return GetAttributeJid("to");
-            }
-            set {
-                SetAttribute("to", value);
-            }
-        }
-
-        public bool Self {
-            get {
-                var value = true;
-                Boolean.TryParse(GetAttribute("self"), out value);
-                return value;
-            }
-            set {
-                SetAttribute("self", value.ToString());
-            }
-        }
-
-        /// <summary>
-        /// Message body
-        /// </summary>
-        public string Body {
-            get {
-                return GetTag("body");
-            }
-            set {
-                SetTag("body", value);
-            }
-        }
-    }
-}
diff --git a/src/Engine-XMPP/Protocols/Xmpp/XmppProtocolManager.cs b/src/Engine-XMPP/Protocols/Xmpp/XmppProtocolManager.cs
index 5934f13..a9084fc 100644
--- a/src/Engine-XMPP/Protocols/Xmpp/XmppProtocolManager.cs
+++ b/src/Engine-XMPP/Protocols/Xmpp/XmppProtocolManager.cs
@@ -1,9 +1,9 @@
 /*
  * Smuxi - Smart MUltipleXed Irc
  *
- * Copyright (c) 2005-2013 Mirco Bauer <meebey at meebey.net>
+ * Copyright (c) 2005-2014 Mirco Bauer <meebey at meebey.net>
  * Copyright (c) 2011 Tuukka Hastrup <Tuukka.Hastrup at iki.fi>
- * Copyright (c) 2013 Oliver Schneider <smuxi at oli-obk.de>
+ * Copyright (c) 2013-2014 Oliver Schneider <smuxi at oli-obk.de>
  *
  * Full GPL License: <http://www.gnu.org/licenses/gpl.txt>
  *
@@ -56,20 +56,6 @@ using agsXMPP.protocol.extensions.nickname;
 
 namespace Smuxi.Engine
 {
-    [ProtocolManagerInfo(Name = "XMPP", Description = "Extensible Messaging and Presence Protocol", Alias = "jabber")]
-    public class JabberProtocolManager : XmppProtocolManager
-    {
-        public override string Protocol {
-            get {
-                return "Jabber";
-            }
-        }
-
-        public JabberProtocolManager(Session session) : base(session)
-        {
-        }
-    }
-    
     [ProtocolManagerInfo(Name = "XMPP", Description = "Extensible Messaging and Presence Protocol", Alias = "xmpp")]
     public class XmppProtocolManager : ProtocolManagerBase
     {
@@ -86,12 +72,8 @@ namespace Smuxi.Engine
         ChatModel NetworkChat { get; set; }
         GroupChatModel ContactChat { get; set; }
         XmppServerModel Server { get; set; }
-        // facebook messed up, this is part of a hack to fix that messup
-        string LastSentMessage { get; set; }
-        bool SupressLocalMessageEcho { get; set; }
         bool AutoReconnect { get; set; }
         TimeSpan AutoReconnectDelay { get; set; }
-        bool IsFacebook { get; set; }
         bool IsDisposed { get; set; }
         bool ShowChatStates { get; set; }
         // pidgin's psychic mode
@@ -127,7 +109,6 @@ namespace Smuxi.Engine
             Contacts = new Dictionary<Jid, XmppPersonModel>();
             DiscoCache = new Dictionary<string, DiscoInfo>();
 
-            SupressLocalMessageEcho = false;
             ShowChatStates = true;
             OpenNewChatOnChatState = true;
 
@@ -144,7 +125,6 @@ namespace Smuxi.Engine
             JabberClient.OnReadXml += OnReadXml;
             JabberClient.OnWriteXml += OnWriteXml;
             JabberClient.OnAuthError += OnAuthError;
-            JabberClient.OnIq += OnIq;
             JabberClient.SendingServiceUnavailable += OnSendingServiceUnavailable;
             JabberClient.AutoAgents = false; // outdated feature
             JabberClient.EnableCapabilities = true;
@@ -162,15 +142,11 @@ namespace Smuxi.Engine
             JabberClient.DiscoInfo.AddFeature().Var = "jabber:iq:last";
             JabberClient.DiscoInfo.AddFeature().Var = "http://jabber.org/protocol/muc";
             JabberClient.DiscoInfo.AddFeature().Var = "http://jabber.org/protocol/disco#info";
-            JabberClient.DiscoInfo.AddFeature().Var = "http://www.facebook.com/xmpp/messages";
             JabberClient.DiscoInfo.AddFeature().Var = "http://jabber.org/protocol/xhtml-im";
 
             Disco = new DiscoManager(JabberClient);
             Disco.AutoAnswerDiscoInfoRequests = true;
 
-            // facebook own message echo
-            ElementFactory.AddElementType("own-message", "http://www.facebook.com/xmpp/messages", typeof(OwnMessageQuery));
-
             MucManager = new MucManager(JabberClient);
         }
 
@@ -252,7 +228,7 @@ namespace Smuxi.Engine
             } else {
                 Server = new XmppServerModel();
                 if (server.ServerID != null) {
-                    Server.Load(Session.UserConfig, server.ServerID);
+                    Server.Load(Session.UserConfig, Protocol, server.ServerID);
                 }
                 // HACK: previous line overwrites any passed values with the values from config
                 // thus we have to copy the original values:
@@ -277,6 +253,14 @@ namespace Smuxi.Engine
                 NetworkID, String.Format("{0} {1}", Protocol, Host), this
             );
             Session.AddChat(NetworkChat);
+            if (Host.EndsWith("facebook.com") && !(this is FacebookProtocolManager)) {
+                var builder = CreateMessageBuilder();
+                builder.AppendEventPrefix();
+                builder.AppendMessage(_("This engine has native Facebook support, you should be using it instead of connecting to facebook with xmpp"));
+                // cannot use AddMessageToFrontend because NetworkChat is not yet synced, causing AddMessageToFrontend to drop it.
+                // cannot sync NetworkChat before this, because then the sync would swallow the message
+                Session.AddMessageToChat(NetworkChat, builder.ToMessage());
+            }
             Session.SyncChat(NetworkChat);
 
             Connect();
@@ -298,7 +282,6 @@ namespace Smuxi.Engine
 #if LOG4NET
             _Logger.Debug("calling JabberClient.Open()");
 #endif
-            IsFacebook = (JabberClient.Server == "chat.facebook.com");
             JabberClient.Open();
         }
 
@@ -345,7 +328,6 @@ namespace Smuxi.Engine
             JabberClient.OnReadXml -= OnReadXml;
             JabberClient.OnWriteXml -= OnWriteXml;
             JabberClient.OnAuthError -= OnAuthError;
-            JabberClient.OnIq -= OnIq;
             JabberClient.ClientSocket.OnValidateCertificate -= ValidateCertificate;
             JabberClient.SendingServiceUnavailable -= OnSendingServiceUnavailable;
             JabberClient.SocketDisconnect();
@@ -1333,11 +1315,6 @@ namespace Smuxi.Engine
                     JabberClient.Send(new Message(chat.ID, XmppMessageType.groupchat, text));
                     return; // don't show now. the message will be echoed back if it's sent successfully
                 }
-                if (IsFacebook && SupressLocalMessageEcho) {
-                    // don't show, facebook is bugging again
-                    return;
-                }
-                LastSentMessage = text;
             }
 
             var builder = CreateMessageBuilder();
@@ -1491,14 +1468,8 @@ namespace Smuxi.Engine
             contact.Ask = rosterItem.Ask;
             string oldIdentityName = contact.IdentityName;
             var oldIdentityNameColored = contact.IdentityNameColored;
-            if (IsFacebook) {
-                // facebook bug. prevent clearing of name
-                if (rosterItem.Name != null) {
-                    contact.IdentityName = rosterItem.Name;
-                }
-            } else {
-                contact.IdentityName = rosterItem.Name ?? rosterItem.Jid;
-            }
+
+            contact.IdentityName = rosterItem.Name ?? rosterItem.Jid;
 
             if (oldIdentityName == contact.IdentityName) {
                 // identity name didn't change
@@ -1514,10 +1485,7 @@ namespace Smuxi.Engine
         {
             var builder = CreateMessageBuilder();
             builder.AppendEventPrefix();
-            string idstring = "";
-            if (!IsFacebook && oldIdentityName != contact.Jid) {
-                idstring = " [" + contact.Jid + "]";
-            }
+            string idstring = (oldIdentityName == contact.Jid.Bare)?"":GenerateIdString(contact);
             oldIdentityNameColored.BackgroundColor = TextColor.None;
             builder.AppendFormat("{2}{1} is now known as {0}", contact, idstring, oldIdentityNameColored);
 
@@ -1543,6 +1511,15 @@ namespace Smuxi.Engine
             }
         }
 
+        protected virtual string GenerateIdString(PersonModel contact)
+        {
+            if (contact.ID == contact.IdentityName) {
+                return "";
+            }
+            var jid = new Jid(contact.ID);
+            return String.Format(" [{0}]", jid.Bare);
+        }
+
         void RequestCapabilities(Jid jid, Capabilities caps)
         {
             string hash = caps.Node + "#" + caps.Version;
@@ -1628,11 +1605,7 @@ namespace Smuxi.Engine
         {
             var builder = CreateMessageBuilder();
             builder.AppendEventPrefix();
-            string idstring = "";
-            // print jid (except in case of facebook where it is meaningless)
-            if (!IsFacebook && jid.Bare != person.IdentityName) {
-                idstring = String.Format(" [{0}]", jid.Bare);
-            }
+            string idstring = GenerateIdString(person);
             // print the type (and in case of available detailed type)
             switch (pres.Type) {
                 case PresenceType.available:
@@ -2372,35 +2345,6 @@ namespace Smuxi.Engine
             Session.AddMessageToChat(NetworkChat, builder.ToMessage());
         }
 
-        void OnIq(object sender, IQEventArgs e)
-        {
-            Trace.Call(sender, e);
-
-            // not as pretty as the previous implementation, but it works
-            var elem = e.IQ.SelectSingleElement("own-message");
-            if (elem is OwnMessageQuery) {
-                OnIQOwnMessage((OwnMessageQuery) elem);
-                e.Handled = true;
-            }
-        }
-
-        [MethodImpl(MethodImplOptions.Synchronized)]
-        void OnIQOwnMessage(OwnMessageQuery query)
-        {
-            if (query.Self) {
-                // we send this message from Smuxi, nothing to do...
-                return;
-            }
-
-            if (!SupressLocalMessageEcho && (query.Body == LastSentMessage)) {
-                SupressLocalMessageEcho = true;
-                return;
-            }
-            var chat = GetOrCreatePersonChat(query.To);
-
-            _Say(chat, query.Body, false);
-        }
-
         [MethodImpl(MethodImplOptions.Synchronized)]
         PersonChatModel GetOrCreatePersonChat(Jid jid)
         {
@@ -2543,7 +2487,11 @@ namespace Smuxi.Engine
         [MethodImpl(MethodImplOptions.Synchronized)]
         void ApplyConfig(UserConfig config, XmppServerModel server)
         {
-            Nicknames = (string[]) config["Connection/Nicknames"];
+            if (String.IsNullOrEmpty(server.Nickname)) {
+                Nicknames = (string[]) config["Connection/Nicknames"];
+            } else {
+                Nicknames = new string[] { server.Nickname };
+            }
 
             if (server.Username.Contains("@")) {
                 var jid_user = server.Username.Split('@')[0];
diff --git a/src/Engine/CommandModel.cs b/src/Engine/CommandModel.cs
index 6167be7..994a1aa 100644
--- a/src/Engine/CommandModel.cs
+++ b/src/Engine/CommandModel.cs
@@ -170,7 +170,7 @@ namespace Smuxi.Engine
         void EnhancedParse(string data)
         {
             string regex = Regex.Escape(_CommandCharacter);
-            regex += "(?<command>[a-z]+)"; // commands can only contain english keyboard letters
+            regex += "(?<command>[a-z_-]+)"; // commands can only contain english keyboard letters
             string quoted_parameter = @"""(?<parameters>[^""]*)""";
             string normal_parameter = @"(?<parameters>[^ ]+)";
             string parameters = @"( +(" + quoted_parameter + "|" + normal_parameter + "))*";
diff --git a/src/Engine/Config/Config.cs b/src/Engine/Config/Config.cs
index b02f6dd..051c806 100644
--- a/src/Engine/Config/Config.cs
+++ b/src/Engine/Config/Config.cs
@@ -1,13 +1,7 @@
 /*
- * $Id$
- * $URL$
- * $Rev$
- * $Author$
- * $Date$
- *
  * Smuxi - Smart MUltipleXed Irc
  *
- * Copyright (c) 2005-2006 Mirco Bauer <meebey at meebey.net>
+ * Copyright (c) 2005-2014 Mirco Bauer <meebey at meebey.net>
  *
  * Full GPL License: <http://www.gnu.org/licenses/gpl.txt>
  *
@@ -325,6 +319,8 @@ namespace Smuxi.Engine
             Get(prefix + "Hostname", "irc.oftc.net");
             Get(prefix + "Port", 6667);
             Get(prefix + "Network", "OFTC");
+            Get(prefix + "Nickname", String.Empty);
+            Get(prefix + "Realname", String.Empty);
             Get(prefix + "Username", String.Empty);
             Get(prefix + "Password", String.Empty);
             Get(prefix + "UseEncryption", false);
@@ -340,6 +336,8 @@ namespace Smuxi.Engine
             Get(prefix + "Hostname", "irc.gimp.org");
             Get(prefix + "Port", 6667);
             Get(prefix + "Network", "GIMPNet");
+            Get(prefix + "Nickname", String.Empty);
+            Get(prefix + "Realname", String.Empty);
             Get(prefix + "Username", String.Empty);
             Get(prefix + "Password", String.Empty);
             Get(prefix + "UseEncryption", false);
@@ -349,6 +347,8 @@ namespace Smuxi.Engine
             Get(prefix + "Hostname", "irc.geekshed.net");
             Get(prefix + "Port", 6667);
             Get(prefix + "Network", "GeekShed");
+            Get(prefix + "Nickname", String.Empty);
+            Get(prefix + "Realname", String.Empty);
             Get(prefix + "Username", String.Empty);
             Get(prefix + "Password", String.Empty);
             Get(prefix + "UseEncryption", false);
@@ -358,6 +358,8 @@ namespace Smuxi.Engine
             Get(prefix + "Hostname", "irc.efnet.org");
             Get(prefix + "Port", 6667);
             Get(prefix + "Network", "EFnet");
+            Get(prefix + "Nickname", String.Empty);
+            Get(prefix + "Realname", String.Empty);
             Get(prefix + "Username", String.Empty);
             Get(prefix + "Password", String.Empty);
             Get(prefix + "UseEncryption", false);
@@ -367,6 +369,8 @@ namespace Smuxi.Engine
             Get(prefix + "Hostname", "irc.ircnet.org");
             Get(prefix + "Port", 6667);
             Get(prefix + "Network", "IRCnet");
+            Get(prefix + "Nickname", String.Empty);
+            Get(prefix + "Realname", String.Empty);
             Get(prefix + "Username", String.Empty);
             Get(prefix + "Password", String.Empty);
             Get(prefix + "UseEncryption", false);
@@ -376,6 +380,8 @@ namespace Smuxi.Engine
             Get(prefix + "Hostname", "irc.freenode.net");
             Get(prefix + "Port", 6667);
             Get(prefix + "Network", "freenode");
+            Get(prefix + "Nickname", String.Empty);
+            Get(prefix + "Realname", String.Empty);
             Get(prefix + "Username", String.Empty);
             Get(prefix + "Password", String.Empty);
             Get(prefix + "UseEncryption", false);
@@ -446,7 +452,7 @@ namespace Smuxi.Engine
 #endif
                 }
                 if (String.IsNullOrEmpty(realname)) {
-                    realname = "http://www.smuxi.org/";
+                    realname = "Your Name";
                 }
                 LoadUserEntry(user, "Connection/Realname", realname);
                 LoadUserEntry(user, "Connection/Encoding", String.Empty);
@@ -545,6 +551,10 @@ namespace Smuxi.Engine
                                       Get(dprefix + server + "/Encoding", null));
                             LoadEntry(sprefix + server + "/AutoConvertUTF8",
                                       Get(dprefix + server + "/AutoConvertUTF8", null));
+                            LoadEntry(sprefix + server + "/Nickname",
+                                      Get(dprefix + server + "/Nickname", null));
+                            LoadEntry(sprefix + server + "/Realname",
+                                      Get(dprefix + server + "/Realname", null));
                             LoadEntry(sprefix + server + "/Username",
                                       Get(dprefix + server + "/Username", null));
                             LoadEntry(sprefix + server + "/Password",
@@ -571,6 +581,8 @@ namespace Smuxi.Engine
                     LoadEntry(sprefix+"Network", String.Empty);
                     LoadEntry(sprefix+"Encoding", null);
                     LoadEntry(sprefix+"AutoConvertUTF8", null);
+                    LoadEntry(sprefix+"Nickname", String.Empty);
+                    LoadEntry(sprefix+"Realname", String.Empty);
                     LoadEntry(sprefix+"Username", String.Empty);
                     LoadEntry(sprefix+"Password", String.Empty);
                     LoadEntry(sprefix+"UseEncryption", false);
@@ -606,6 +618,22 @@ namespace Smuxi.Engine
                     LoadUserEntry(user, cprefix + "MessageType", null);
                     LoadUserEntry(user, cprefix + "MessagePattern", null);
                 }
+
+                string lprefix = "MessagePatterns/";
+                var linkKeys = GetList(prefix + user + "/" + lprefix + "MessagePatterns");
+                if (linkKeys == null) {
+                    linkKeys = new string[] {};
+                    m_Preferences[prefix + user + "/" + lprefix + "MessagePatterns"] = new string[] {};
+                } else {
+                    m_Preferences[prefix + user + "/" + lprefix + "MessagePatterns"] = linkKeys;
+                }
+                foreach (var linkKey in linkKeys) {
+                    lprefix = "MessagePatterns/" + linkKey + "/";
+                    LoadUserEntry(user, lprefix + "MessagePartPattern", String.Empty);
+                    LoadUserEntry(user, lprefix + "MessagePartType", String.Empty);
+                    LoadUserEntry(user, lprefix + "LinkFormat", String.Empty);
+                    LoadUserEntry(user, lprefix + "TextFormat", String.Empty);
+                }
             }
         }
 
diff --git a/src/Engine/Config/MessageBuilderSettings.cs b/src/Engine/Config/MessageBuilderSettings.cs
new file mode 100644
index 0000000..7ec0533
--- /dev/null
+++ b/src/Engine/Config/MessageBuilderSettings.cs
@@ -0,0 +1,343 @@
+// Smuxi - Smart MUltipleXed Irc
+//
+// Copyright (c) 2011, 2014 Mirco Bauer <meebey at meebey.net>
+//
+// Full GPL License: <http://www.gnu.org/licenses/gpl.txt>
+//
+// 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
+using System;
+using System.Text.RegularExpressions;
+using System.Collections.Generic;
+using Smuxi.Common;
+
+namespace Smuxi.Engine
+{
+    public class MessageBuilderSettings
+    {
+        static List<MessagePatternModel> BuiltinPatterns { get; set; }
+        public List<MessagePatternModel> UserPatterns { get; set; }
+        public List<MessagePatternModel> Patterns { get; set; }
+        public bool NickColors { get; set; }
+        public bool StripFormattings { get; set; }
+        public bool StripColors { get; set; }
+        public TextColor HighlightColor { get; set; }
+        public List<string> HighlightWords { get; set; }
+
+        static MessageBuilderSettings()
+        {
+            BuiltinPatterns = new List<MessagePatternModel>();
+            InitBuiltinSmartLinks();
+        }
+
+        public MessageBuilderSettings()
+        {
+            NickColors = true;
+
+            // No need to lock BuiltinPatterns as List<T> is thread-safe for
+            // multiple readers as long as there is no writer at the same time.
+            // BuiltinPatterns is only written once before the first instance
+            // of MessageBuilderSettings is created via the static initializer.
+            Patterns = new List<MessagePatternModel>(BuiltinPatterns);
+        }
+
+        public MessageBuilderSettings(MessageBuilderSettings settings)
+        {
+            if (settings == null) {
+                throw new ArgumentNullException("settings");
+            }
+
+            UserPatterns = new List<MessagePatternModel>(settings.UserPatterns);
+            Patterns = new List<MessagePatternModel>(settings.Patterns);
+            NickColors = settings.NickColors;
+            StripFormattings = settings.StripFormattings;
+            StripColors = settings.StripColors;
+            HighlightColor = settings.HighlightColor;
+            HighlightWords = settings.HighlightWords;
+        }
+
+        static void InitBuiltinSmartLinks()
+        {
+            string path_last_chars = @"a-zA-Z0-9#/%&@=\-_+;:~";
+            string path_chars = path_last_chars + @")(?!.,";
+            string domainchars = @"[a-z0-9\-]+";
+            string subdomain = domainchars + @"\.";
+            string common_tld = @"de|es|im|us|com|net|org|info|biz|gov|name|edu|onion|museum";
+            string any_tld = @"[a-z]+";
+            string domain = @"(?:(?:" + subdomain + ")+(?:" + any_tld + ")|localhost)";
+            string short_number = "[1-9][0-9]{,4}";
+            string port = ":" + short_number;
+            string user = "[a-z0-9._%+-]+@";
+            string domain_port = domain + "(?:" + port + ")?";
+            string user_domain = user + domain;
+            string user_domain_port = "(?:" + user + ")?" + domain_port;
+            string path = @"/(?:["+ path_chars +"]*["+ path_last_chars +"]+)?";
+            string protocol = @"[a-z][a-z0-9\-+]*://";
+            string protocol_user_domain_port_path = protocol + user_domain_port + "(?:" + path + ")?";
+
+            // facebook attachment
+            var regex = new Regex(
+                @"(<[1-9][0-9]* attachments?>) (http://www\.facebook\.com/messages/\?action=read&tid=[0-9a-f]+)",
+                RegexOptions.Compiled
+            );
+            BuiltinPatterns.Add(new MessagePatternModel(regex) {
+                LinkFormat = "{2}",
+                TextFormat = "{1}",
+            });
+
+            // protocol://user@domain:port/path
+            regex = new Regex(
+                protocol_user_domain_port_path,
+                RegexOptions.IgnoreCase | RegexOptions.Compiled
+            );
+            BuiltinPatterns.Add(new MessagePatternModel(regex));
+
+            // email
+            regex = new Regex(
+                @"(?:mailto:)?(" + user_domain + ")",
+                RegexOptions.IgnoreCase | RegexOptions.Compiled
+            );
+            BuiltinPatterns.Add(new MessagePatternModel(regex) {
+                LinkFormat = "mailto:{1}"
+            });
+
+            // addresses without protocol (heuristical)
+            // include well known TLDs to prevent autogen.sh, configure.ac or
+            // Gst.Buffer.Unref() from matching
+            string heuristic_domain = @"(?:(?:" + subdomain + ")+(?:" + common_tld + ")|localhost)";
+            string heuristic_address = heuristic_domain + "(?:" + path + ")?";
+            regex = new Regex(heuristic_address, RegexOptions.Compiled);
+            BuiltinPatterns.Add(new MessagePatternModel(regex) {
+                LinkFormat = "http://{0}"
+            });
+
+            // Smuxi bugtracker
+            regex = new Regex(@"smuxi#([0-9]+)",
+                              RegexOptions.IgnoreCase | RegexOptions.Compiled);
+            BuiltinPatterns.Add(new MessagePatternModel(regex) {
+                LinkFormat = "http://www.smuxi.org/issues/show/{1}"
+            });
+
+            // RFCs
+            regex = new Regex(@"RFC[ -]?([0-9]+) (?:s\.|ss\.|sec\.|sect\.|section) ?([1-9][0-9.]*)",
+                              RegexOptions.IgnoreCase | RegexOptions.Compiled);
+            BuiltinPatterns.Add(new MessagePatternModel(regex) {
+                LinkFormat = "http://tools.ietf.org/html/rfc{1}#section-{2}"
+            });
+            regex = new Regex(@"RFC[ -]?([0-9]+) (?:p\.|pp\.|page) ?(" + short_number + ")",
+                              RegexOptions.IgnoreCase | RegexOptions.Compiled);
+            BuiltinPatterns.Add(new MessagePatternModel(regex) {
+                LinkFormat = "http://tools.ietf.org/html/rfc{1}#page-{2}"
+            });
+            regex = new Regex(@"RFC[ -]?([0-9]+)",
+                              RegexOptions.IgnoreCase | RegexOptions.Compiled);
+            BuiltinPatterns.Add(new MessagePatternModel(regex) {
+                LinkFormat = "http://www.ietf.org/rfc/rfc{1}.txt"
+            });
+
+            // bugtracker prefixes are taken from:
+            // http://en.opensuse.org/openSUSE:Packaging_Patches_guidelines#Current_set_of_abbreviations
+
+            // boost bugtracker
+            regex = new Regex(@"boost#([0-9]+)",
+                              RegexOptions.IgnoreCase | RegexOptions.Compiled);
+            BuiltinPatterns.Add(new MessagePatternModel(regex) {
+                LinkFormat = "https://svn.boost.org/trac/boost/ticket/{1}"
+            });
+
+            // Claws bugtracker
+            regex = new Regex(@"claws#([0-9]+)",
+                              RegexOptions.IgnoreCase | RegexOptions.Compiled);
+            BuiltinPatterns.Add(new MessagePatternModel(regex) {
+                LinkFormat = "http://www.thewildbeast.co.uk/claws-mail/bugzilla/show_bug.cgi?id={1}"
+            });
+
+            // CVE list
+            regex = new Regex(@"CVE-[0-9]{4}-[0-9]{4,}",
+                              RegexOptions.IgnoreCase | RegexOptions.Compiled);
+            BuiltinPatterns.Add(new MessagePatternModel(regex) {
+                LinkFormat = "http://cve.mitre.org/cgi-bin/cvename.cgi?name={0}"
+            });
+
+            // CPAN bugtracker
+            regex = new Regex(@"RT#([0-9]+)",
+                              RegexOptions.IgnoreCase | RegexOptions.Compiled);
+            BuiltinPatterns.Add(new MessagePatternModel(regex) {
+                LinkFormat = "http://rt.cpan.org/Public/Bug/Display.html?id={1}"
+            });
+
+            // Debian bugtracker
+            regex = new Regex(@"deb#([0-9]+)",
+                              RegexOptions.IgnoreCase | RegexOptions.Compiled);
+            BuiltinPatterns.Add(new MessagePatternModel(regex) {
+                LinkFormat = "http://bugs.debian.org/{1}"
+            });
+
+            // Debian Security Advisories (DSA)
+            regex = new Regex(@"DSA-([0-9]{4})(-[0-9]{1,2})?",
+                              RegexOptions.IgnoreCase | RegexOptions.Compiled);
+            BuiltinPatterns.Add(new MessagePatternModel(regex) {
+                LinkFormat = "http://www.debian.org/security/dsa-{1}"
+            });
+
+            // openSUSE feature tracker
+            regex = new Regex(@"fate#([0-9]+)",
+                              RegexOptions.IgnoreCase | RegexOptions.Compiled);
+            BuiltinPatterns.Add(new MessagePatternModel(regex) {
+                LinkFormat = "http://features.opensuse.org/{1}"
+            });
+
+            // freedesktop bugtracker
+            regex = new Regex(@"fdo#([0-9]+)",
+                              RegexOptions.IgnoreCase | RegexOptions.Compiled);
+            BuiltinPatterns.Add(new MessagePatternModel(regex) {
+                LinkFormat = "http://bugs.freedesktop.org/{1}"
+            });
+
+            // GNU bugtracker
+            regex = new Regex(@"gnu#([0-9]+)",
+                              RegexOptions.IgnoreCase | RegexOptions.Compiled);
+            BuiltinPatterns.Add(new MessagePatternModel(regex) {
+                LinkFormat = "http://debbugs.gnu.org/{1}"
+            });
+
+            // GCC bugtracker
+            regex = new Regex(@"gcc#([0-9]+)",
+                              RegexOptions.IgnoreCase | RegexOptions.Compiled);
+            BuiltinPatterns.Add(new MessagePatternModel(regex) {
+                LinkFormat = "http://gcc.gnu.org/bugzilla/show_bug.cgi?id={1}"
+            });
+
+            // GNOME bugtracker
+            regex = new Regex(@"bgo#([0-9]+)",
+                              RegexOptions.IgnoreCase | RegexOptions.Compiled);
+            BuiltinPatterns.Add(new MessagePatternModel(regex) {
+                LinkFormat = "http://bugzilla.gnome.org/{1}"
+            });
+
+            // KDE bugtracker
+            regex = new Regex(@"kde#([0-9]+)",
+                              RegexOptions.IgnoreCase | RegexOptions.Compiled);
+            BuiltinPatterns.Add(new MessagePatternModel(regex) {
+                LinkFormat = "http://bugs.kde.org/{1}"
+            });
+
+            // kernel bugtracker
+            regex = new Regex(@"bko#([0-9]+)",
+                              RegexOptions.IgnoreCase | RegexOptions.Compiled);
+            BuiltinPatterns.Add(new MessagePatternModel(regex) {
+                LinkFormat = "http://bugzilla.kernel.org/show_bug.cgi?id={1}"
+            });
+
+            // launchpad bugtracker
+            regex = new Regex(@"LP#([0-9]+)",
+                              RegexOptions.IgnoreCase | RegexOptions.Compiled);
+            BuiltinPatterns.Add(new MessagePatternModel(regex) {
+                LinkFormat = "http://launchpad.net/bugs/{1}"
+            });
+
+            // Mozilla bugtracker
+            regex = new Regex(@"bmo#([0-9]+)",
+                              RegexOptions.IgnoreCase | RegexOptions.Compiled);
+            BuiltinPatterns.Add(new MessagePatternModel(regex) {
+                LinkFormat = "http://bugzilla.mozilla.org/{1}"
+            });
+
+            // Novell bugtracker
+            regex = new Regex(@"bnc#([0-9]+)",
+                              RegexOptions.IgnoreCase | RegexOptions.Compiled);
+            BuiltinPatterns.Add(new MessagePatternModel(regex) {
+                LinkFormat = "http://bugzilla.novell.com/{1}"
+            });
+
+            // Redhat bugtracker
+            regex = new Regex(@"rh#([0-9]+)",
+                              RegexOptions.IgnoreCase | RegexOptions.Compiled);
+            BuiltinPatterns.Add(new MessagePatternModel(regex) {
+                LinkFormat = "http://bugzilla.redhat.com/{1}"
+            });
+
+            // Samba bugtracker
+            regex = new Regex(@"bso#([0-9]+)",
+                              RegexOptions.IgnoreCase | RegexOptions.Compiled);
+            BuiltinPatterns.Add(new MessagePatternModel(regex) {
+                LinkFormat = "http://bugzilla.samba.org/show_bug.cgi?id={1}"
+            });
+
+            // sourceforge bugtracker
+            regex = new Regex(@"sf#([0-9]+)",
+                              RegexOptions.IgnoreCase | RegexOptions.Compiled);
+            BuiltinPatterns.Add(new MessagePatternModel(regex) {
+                LinkFormat = "http://sf.net/support/tracker.php?aid={1}"
+            });
+
+            // Xfce bugtracker
+            regex = new Regex(@"bxo#([0-9]+)",
+                              RegexOptions.IgnoreCase | RegexOptions.Compiled);
+            BuiltinPatterns.Add(new MessagePatternModel(regex) {
+                LinkFormat = "http://bugzilla.xfce.org/show_bug.cgi?id={1}"
+            });
+
+            // Xamarin bugtracker
+            regex = new Regex(@"bxc#([0-9]+)",
+                              RegexOptions.IgnoreCase | RegexOptions.Compiled);
+            BuiltinPatterns.Add(new MessagePatternModel(regex) {
+                LinkFormat = "http://bugzilla.xamarin.com/show_bug.cgi?id={1}"
+            });
+
+            // TODO: msgid -> http://mid.gmane.org/{1}
+            // TODO: ISSN/ISBN
+            // TODO: Path: / or X:\
+            // TODO: GPS -> Google Maps
+            // TODO: IP -> Browser / Whois
+            // TODO: Domain -> Browser / Whois
+            // TODO: ISO -> http://www.iso.org/iso/search.htm?qt={1}&published=on
+            // TODO: ANSI
+            // TODO: ECMA
+            // TODO: maybe more on http://ikiwiki.info/shortcuts/
+            // TODO: JID
+        }
+
+        public void ApplyConfig(UserConfig userConfig)
+        {
+            if (userConfig == null) {
+                throw new ArgumentNullException("userConfig");
+            }
+
+            NickColors = (bool) userConfig["Interface/Notebook/Channel/NickColors"];
+            StripColors = (bool) userConfig["Interface/Notebook/StripColors"];
+            StripFormattings = (bool) userConfig["Interface/Notebook/StripFormattings"];
+            HighlightColor = TextColor.Parse(
+                (string) userConfig["Interface/Notebook/Tab/HighlightColor"]
+            );
+            HighlightWords = new List<string>(
+                (string[]) userConfig["Interface/Chat/HighlightWords"]
+            );
+
+            var patternController = new MessagePatternListController(userConfig);
+            var userPatterns = patternController.GetList();
+            var builtinPatterns = BuiltinPatterns;
+            var patterns = new List<MessagePatternModel>(builtinPatterns.Count +
+                                                         userPatterns.Count);
+            // No need to lock BuiltinPatterns as List<T> is thread-safe for
+            // multiple readers as long as there is no writer at the same time.
+            // BuiltinPatterns is only written once before the first instance
+            // of MessageBuilderSettings is created via the static initializer.
+            patterns.AddRange(builtinPatterns);
+            patterns.AddRange(userPatterns);
+            Patterns = patterns;
+            UserPatterns = userPatterns;
+        }
+    }
+}
diff --git a/src/Engine/Config/MessagePatternListController.cs b/src/Engine/Config/MessagePatternListController.cs
new file mode 100644
index 0000000..9898d76
--- /dev/null
+++ b/src/Engine/Config/MessagePatternListController.cs
@@ -0,0 +1,160 @@
+/*
+ * Smuxi - Smart MUltipleXed Irc
+ *
+ * Copyright (c) 2014 Mirco Bauer <meebey at meebey.net>
+ *
+ * Full GPL License: <http://www.gnu.org/licenses/gpl.txt>
+ *
+ * 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
+ */
+
+using System;
+using System.Collections.Generic;
+using Smuxi.Common;
+using Smuxi.Engine;
+
+namespace Smuxi.Engine
+{
+    public class MessagePatternListController
+    {
+        UserConfig UserConfig { get; set; }
+
+        protected string[] PatternIDs {
+            get {
+                return (string[]) UserConfig["MessagePatterns/MessagePatterns"];
+            }
+            set {
+                UserConfig["MessagePatterns/MessagePatterns"] = value;
+            }
+        }
+
+        public MessagePatternListController(UserConfig userConfig)
+        {
+            if (userConfig == null) {
+                throw new ArgumentNullException("userConfig");
+            }
+
+            UserConfig = userConfig;
+        }
+
+        public List<MessagePatternModel> GetList()
+        {
+            var keys = PatternIDs;
+            var list = new List<MessagePatternModel>(keys.Length);
+            if (keys == null) {
+                return list;
+            }
+            foreach (var key in keys) {
+                int parsedKey = Int32.Parse(key);
+                var link = Get(parsedKey);
+                if (link == null) {
+                    continue;
+                }
+                list.Add(link);
+            }
+            return list;
+        }
+
+        public MessagePatternModel Get(int id)
+        {
+            Trace.Call(id);
+
+            string prefix = "MessagePatterns/" + id + "/";
+            if (UserConfig[prefix + "MessagePartPattern"] == null) {
+                // link does not exist
+                return null;
+            }
+            var link = new MessagePatternModel(id);
+            link.Load(UserConfig);
+            return link;
+        }
+
+        public int Add(MessagePatternModel link)
+        {
+            return Add(link, -1);
+        }
+
+        public int Add(MessagePatternModel link, int id)
+        {
+            Trace.Call(link, id);
+
+            if (link == null) {
+                throw new ArgumentNullException("link");
+            }
+
+            string[] keys = PatternIDs;
+            if (keys == null) {
+                keys = new string[] {};
+            }
+            int highestKey = 0;
+            int newKey = id;
+            if (id == -1) {
+                foreach (string key in keys) {
+                    int parsedKey = Int32.Parse(key);
+                    if (parsedKey > highestKey) {
+                        highestKey = parsedKey;
+                    }
+                }
+                newKey = ++highestKey;
+            }
+
+            link.ID = newKey;
+            link.Save(UserConfig);
+
+            var keyList = new List<string>(keys);
+            keyList.Add(link.ID.ToString());
+            PatternIDs = keyList.ToArray();
+            return newKey;
+        }
+
+        public void Set(MessagePatternModel link)
+        {
+            Trace.Call(link);
+
+            if (link == null) {
+                throw new ArgumentNullException("link");
+            }
+
+            link.Save(UserConfig);
+        }
+
+        public void Remove(int key)
+        {
+            Trace.Call(key);
+
+            string section = "MessagePatterns/" + key + "/";
+            string[] keys = PatternIDs;
+            if (keys == null) {
+                keys = new string[] {};
+            }
+            var keyList = new List<string>(keys);
+            int idx = keyList.IndexOf(key.ToString());
+            if (idx == -1) {
+                // key not found
+                return;
+            }
+            keyList.RemoveAt(idx);
+            UserConfig.Remove(section);
+            PatternIDs = keyList.ToArray();
+        }
+
+        public void Save()
+        {
+            Trace.Call();
+
+            UserConfig.Save();
+        }
+    }
+}
diff --git a/src/Engine/Config/MessagePatternModel.cs b/src/Engine/Config/MessagePatternModel.cs
new file mode 100644
index 0000000..b32ffe5
--- /dev/null
+++ b/src/Engine/Config/MessagePatternModel.cs
@@ -0,0 +1,134 @@
+// Smuxi - Smart MUltipleXed Irc
+//
+// Copyright (c) 2014 Mirco Bauer <meebey at meebey.net>
+//
+// Full GPL License: <http://www.gnu.org/licenses/gpl.txt>
+//
+// 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
+using System;
+using System.Text.RegularExpressions;
+
+namespace Smuxi.Engine
+{
+    public class MessagePatternModel
+    {
+        public int? ID { get; set; }
+        public Regex MessagePartPattern { get; set; }
+        public Type MessagePartType { get; set; }
+        // what is linked to
+        public string LinkFormat { get; set; }
+        // what is displayed
+        public string TextFormat { get; set; }
+
+        protected string ConfigKeyPrefix {
+            get {
+                if (ID == null) {
+                    throw new ArgumentNullException("ID");
+                }
+                return "MessagePatterns/" + ID + "/";
+            }
+        }
+
+        public MessagePatternModel(Regex pattern)
+        {
+            if (pattern == null) {
+                throw new ArgumentNullException("pattern");
+            }
+            MessagePartPattern = pattern;
+            MessagePartType = typeof(UrlMessagePartModel);
+        }
+
+        public MessagePatternModel(int id)
+        {
+            ID = id;
+        }
+
+        public void Load(UserConfig config)
+        {
+            if (ID == null) {
+                throw new InvalidOperationException("ID must not be null.");
+            }
+
+            Load(config, ID.Value);
+        }
+
+        public virtual void Load(UserConfig config, int id)
+        {
+            if (config == null) {
+                throw new ArgumentNullException("config");
+            }
+
+            // don't use ConfigKeyPrefix, so exception guarantees can be kept
+            string prefix = "MessagePatterns/" + id + "/";
+            if (config[prefix + "MessagePartPattern"] == null) {
+                // SmartLink does not exist
+                throw new ArgumentException("MessagePattern ID not found in config", "id");
+            }
+
+            ID = id;
+            // now we have a valid ID, ConfigKeyPrefix works
+            var messagePartPattern = (string) config[ConfigKeyPrefix + "MessagePartPattern"];
+            if (messagePartPattern.StartsWith("/") && messagePartPattern.EndsWith("/i")) {
+                var regexPattern = messagePartPattern.Substring(1, messagePartPattern.Length - 3);
+                MessagePartPattern = new Regex(regexPattern, RegexOptions.IgnoreCase | RegexOptions.Compiled);
+            } else {
+                MessagePartPattern = new Regex(messagePartPattern, RegexOptions.Compiled);
+            }
+            var messagePartType = (string) config[ConfigKeyPrefix + "MessagePartType"];
+            switch (messagePartType.ToLower()) {
+                case "url":
+                    MessagePartType = typeof(UrlMessagePartModel);
+                    break;
+                case "image":
+                    MessagePartType = typeof(ImageMessagePartModel);
+                    break;
+            }
+            LinkFormat = (string) config[ConfigKeyPrefix + "LinkFormat"];
+            TextFormat = (string) config[ConfigKeyPrefix + "TextFormat"];
+        }
+
+        public virtual void Save(UserConfig config)
+        {
+            if (config == null) {
+                throw new ArgumentNullException("config");
+            }
+
+            if (MessagePartPattern == null) {
+                config[ConfigKeyPrefix + "MessagePartPattern"] = String.Empty;
+            } else {
+                config[ConfigKeyPrefix + "MessagePartPattern"] = MessagePartPattern.ToString();
+            }
+            if (MessagePartType == typeof(ImageMessagePartModel)) {
+                config[ConfigKeyPrefix + "MessagePartType"] = "Image";
+            } else if (MessagePartType == typeof(UrlMessagePartModel)) {
+                config[ConfigKeyPrefix + "MessagePartType"] = "Url";
+            } else {
+                config[ConfigKeyPrefix + "MessagePartType"] = String.Empty;
+            }
+            config[ConfigKeyPrefix + "LinkFormat"] = LinkFormat ?? String.Empty;
+            config[ConfigKeyPrefix + "TextFormat"] = TextFormat ?? String.Empty;
+        }
+
+        public override string ToString()
+        {
+            return String.Format("<{0}>", ToTraceString());
+        }
+
+        public string ToTraceString()
+        {
+            return String.Format("{0}", ID);
+        }
+    }
+}
diff --git a/src/Engine/Config/ServerModel.cs b/src/Engine/Config/ServerModel.cs
index 0d6ef65..ca1d9c1 100644
--- a/src/Engine/Config/ServerModel.cs
+++ b/src/Engine/Config/ServerModel.cs
@@ -1,7 +1,7 @@
 /*
  * Smuxi - Smart MUltipleXed Irc
  *
- * Copyright (c) 2007, 2010 Mirco Bauer <meebey at meebey.net>
+ * Copyright (c) 2007, 2010, 2012-2014 Mirco Bauer <meebey at meebey.net>
  *
  * Full GPL License: <http://www.gnu.org/licenses/gpl.txt>
  *
@@ -36,6 +36,8 @@ namespace Smuxi.Engine
         public string Hostname { get; set; }
         public int Port { get; set; }
         public string Network { get; set; }
+        public string Nickname { get; set; }
+        public string Realname { get; set; }
         public string Username { get; set; }
         public string Password { get; set; }
         public bool OnStartupConnect { get; set; }
@@ -77,6 +79,12 @@ namespace Smuxi.Engine
                         ServerID = (string)e.Value;
                         foundServerID = true;
                         break;
+                    case "_Username":
+                        Username = (string) e.Value;
+                        break;
+                    case "_Realname":
+                        Realname = (string) e.Value;
+                        break;
                     // UseEncryption and ValidateServerCertificate were forgotten
                     // when moving from autoserialization to manual serialization.
                     // To prevent crashes when git users' updated engines receive a ServerModel
@@ -109,7 +117,18 @@ namespace Smuxi.Engine
 
         public virtual void GetObjectData(SerializationInfo info, StreamingContext ctx) 
         {
-            info.AddValue("_ServerID", ServerID);
+            // HACK: skip ServerID if it has no value as it breaks older
+            // ServerModel implementations that relied on automatic
+            // serialization which was the case in < 0.8.11
+            if (ServerID != null) {
+                info.AddValue("_ServerID", ServerID);
+            }
+            if (Nickname != null) {
+                info.AddValue("_Nickname", Nickname);
+            }
+            if (Realname != null) {
+                info.AddValue("_Realname", Realname);
+            }
             info.AddValue("_Protocol", Protocol);
             info.AddValue("_Hostname", Hostname);
             info.AddValue("_Port", Port);
@@ -146,6 +165,8 @@ namespace Smuxi.Engine
             Hostname    = (string) config[ConfigKeyPrefix + "Hostname"];
             Port        = (int)    config[ConfigKeyPrefix + "Port"];
             Network     = (string) config[ConfigKeyPrefix + "Network"];
+            Nickname = (string) config[ConfigKeyPrefix + "Nickname"];
+            Realname = (string) config[ConfigKeyPrefix + "Realname"];
             Username    = (string) config[ConfigKeyPrefix + "Username"];
             Password    = (string) config[ConfigKeyPrefix + "Password"];
             UseEncryption = (bool) config[ConfigKeyPrefix + "UseEncryption"];
@@ -165,6 +186,8 @@ namespace Smuxi.Engine
             config[ConfigKeyPrefix + "Hostname"] = Hostname;
             config[ConfigKeyPrefix + "Port"]     = Port;
             config[ConfigKeyPrefix + "Network"]  = Network;
+            config[ConfigKeyPrefix + "Nickname"]  = Nickname;
+            config[ConfigKeyPrefix + "Realname"]  = Realname;
             config[ConfigKeyPrefix + "Username"] = Username;
             config[ConfigKeyPrefix + "Password"] = Password;
             config[ConfigKeyPrefix + "UseEncryption"] = UseEncryption;
diff --git a/src/Engine/Hooks/Environments/CommandHookEnvironment.cs b/src/Engine/Hooks/Environments/CommandHookEnvironment.cs
index 963bac0..1fdb72e 100644
--- a/src/Engine/Hooks/Environments/CommandHookEnvironment.cs
+++ b/src/Engine/Hooks/Environments/CommandHookEnvironment.cs
@@ -31,6 +31,7 @@ namespace Smuxi.Engine
 
             this["CMD"] = cmd.Command;
             this["CMD_PARAMETER"] = cmd.Parameter;
+            this["CMD_CHARACTER"] = cmd.CommandCharacter;
         }
     }
 }
diff --git a/src/Engine/Hooks/Environments/CommandHookEnvironment.cs b/src/Engine/Hooks/Environments/PersonHookEnvironment.cs
similarity index 57%
copy from src/Engine/Hooks/Environments/CommandHookEnvironment.cs
copy to src/Engine/Hooks/Environments/PersonHookEnvironment.cs
index 963bac0..904da3b 100644
--- a/src/Engine/Hooks/Environments/CommandHookEnvironment.cs
+++ b/src/Engine/Hooks/Environments/PersonHookEnvironment.cs
@@ -1,6 +1,6 @@
 // Smuxi - Smart MUltipleXed Irc
 //
-// Copyright (c) 2013 Mirco Bauer <meebey at meebey.net>
+// Copyright (c) 2014 Mirco Bauer <meebey at meebey.net>
 //
 // Full GPL License: <http://www.gnu.org/licenses/gpl.txt>
 //
@@ -21,16 +21,23 @@ using System;
 
 namespace Smuxi.Engine
 {
-    public class CommandHookEnvironment : HookEnvironment
+    public class PersonHookEnvironment : HookEnvironment
     {
-        public CommandHookEnvironment(CommandModel cmd)
+        public PersonHookEnvironment(PersonModel person) :
+                                this(null, person)
         {
-            if (cmd == null) {
-                throw new ArgumentNullException("cmd");
+        }
+
+        public PersonHookEnvironment(string prefix, PersonModel person)
+        {
+            if (person == null) {
+                throw new ArgumentNullException("person");
             }
 
-            this["CMD"] = cmd.Command;
-            this["CMD_PARAMETER"] = cmd.Parameter;
+            this[prefix + "PERSON_ID"] = person.ID;
+            this[prefix + "PERSON_IDENTITY_NAME"] = person.IdentityName;
+            this[prefix + "PERSON_NETWORK_ID"] = person.NetworkID;
+            this[prefix + "PERSON_NETWORK_PROTOCOL"] = person.NetworkProtocol;
         }
     }
 }
diff --git a/src/Engine/Hooks/Environments/ProtocolManagerHookEnvironment.cs b/src/Engine/Hooks/Environments/ProtocolManagerHookEnvironment.cs
index bf545bf..b6220d2 100644
--- a/src/Engine/Hooks/Environments/ProtocolManagerHookEnvironment.cs
+++ b/src/Engine/Hooks/Environments/ProtocolManagerHookEnvironment.cs
@@ -36,6 +36,7 @@ namespace Smuxi.Engine
             if (protocolManager.Me != null) {
                 this["PROTOCOL_MANAGER_ME_ID"] = protocolManager.Me.ID;
             }
+            this["PROTOCOL_PRESENCE_STATUS"] = protocolManager.PresenceStatus.ToString();
         }
     }
 }
diff --git a/src/Engine/Hooks/HookRunner.cs b/src/Engine/Hooks/HookRunner.cs
index 9a3e283..d661008 100644
--- a/src/Engine/Hooks/HookRunner.cs
+++ b/src/Engine/Hooks/HookRunner.cs
@@ -153,7 +153,7 @@ namespace Smuxi.Engine
             Logger.Debug("Run(): executing " + hookPath);
 #endif
             var process = SysDiag.Process.Start(startInfo);
-            while (!process.HasExited) {
+            while (!process.StandardOutput.EndOfStream) {
                 var line = process.StandardOutput.ReadLine();
                 if (String.IsNullOrEmpty(line)) {
                     continue;
diff --git a/src/Engine/Makefile.am b/src/Engine/Makefile.am
index 6f5c494..4c6f2df 100644
--- a/src/Engine/Makefile.am
+++ b/src/Engine/Makefile.am
@@ -70,7 +70,6 @@ FILES = \
 	Messages/FeedMessageBuilder.cs \
 	Messages/MessageBuilder.cs \
 	Messages/MessageModel.cs \
-	Messages/MessageParser.cs \
 	Messages/MessagePartModel.cs \
 	Messages/TextMessagePartModel.cs \
 	Messages/UrlMessagePartModel.cs \
@@ -94,6 +93,9 @@ FILES = \
 	Config/ProxySettings.cs \
 	Config/ProxyType.cs \
 	Config/EntrySettings.cs \
+	Config/MessageBuilderSettings.cs \
+	Config/MessagePatternListController.cs \
+	Config/MessagePatternModel.cs \
 	Protocols/ProtocolManagerBase.cs \
 	Protocols/ProtocolManagerFactory.cs \
 	Protocols/ProtocolManagerInfoModel.cs \
@@ -109,6 +111,7 @@ FILES = \
 	Hooks/Environments/CommandHookEnvironment.cs \
 	Hooks/Environments/HookEnvironment.cs \
 	Hooks/Environments/MessageHookEnvironment.cs \
+	Hooks/Environments/PersonHookEnvironment.cs \
 	Hooks/Environments/ProtocolManagerHookEnvironment.cs
 
 DATA_FILES = 
diff --git a/src/Engine/Makefile.in b/src/Engine/Makefile.in
index 90cf218..505d16b 100644
--- a/src/Engine/Makefile.in
+++ b/src/Engine/Makefile.in
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994-2013 Free Software Foundation, Inc.
@@ -430,7 +430,6 @@ FILES = \
 	Messages/FeedMessageBuilder.cs \
 	Messages/MessageBuilder.cs \
 	Messages/MessageModel.cs \
-	Messages/MessageParser.cs \
 	Messages/MessagePartModel.cs \
 	Messages/TextMessagePartModel.cs \
 	Messages/UrlMessagePartModel.cs \
@@ -454,6 +453,9 @@ FILES = \
 	Config/ProxySettings.cs \
 	Config/ProxyType.cs \
 	Config/EntrySettings.cs \
+	Config/MessageBuilderSettings.cs \
+	Config/MessagePatternListController.cs \
+	Config/MessagePatternModel.cs \
 	Protocols/ProtocolManagerBase.cs \
 	Protocols/ProtocolManagerFactory.cs \
 	Protocols/ProtocolManagerInfoModel.cs \
@@ -469,6 +471,7 @@ FILES = \
 	Hooks/Environments/CommandHookEnvironment.cs \
 	Hooks/Environments/HookEnvironment.cs \
 	Hooks/Environments/MessageHookEnvironment.cs \
+	Hooks/Environments/PersonHookEnvironment.cs \
 	Hooks/Environments/ProtocolManagerHookEnvironment.cs
 
 DATA_FILES = 
diff --git a/src/Engine/Messages/MessageBuilder.cs b/src/Engine/Messages/MessageBuilder.cs
index cc15d60..83598c2 100644
--- a/src/Engine/Messages/MessageBuilder.cs
+++ b/src/Engine/Messages/MessageBuilder.cs
@@ -1,6 +1,6 @@
 // Smuxi - Smart MUltipleXed Irc
 // 
-// Copyright (c) 2010-2013 Mirco Bauer <meebey at meebey.net>
+// Copyright (c) 2010-2014 Mirco Bauer <meebey at meebey.net>
 // Copyright (c) 2013 Oliver Schneider <mail at oli-obk.de>
 // 
 // Full GPL License: <http://www.gnu.org/licenses/gpl.txt>
@@ -20,6 +20,7 @@
 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 
 using System;
+using System.Linq;
 using System.Text;
 using System.Text.RegularExpressions;
 using System.Collections.Generic;
@@ -37,12 +38,8 @@ namespace Smuxi.Engine
 #endif
         static readonly string LibraryTextDomain = "smuxi-engine";
         MessageModel Message { get; set; }
-        public bool NickColors { get; set; }
-        public bool StripFormattings { get; set; }
-        public bool StripColors { get; set; }
-        public TextColor HighlightColor { get; set; }
-        public List<string> HighlightWords { get; set; }
         public PersonModel Me { get; set; }
+        public MessageBuilderSettings Settings { get; set; }
 
         public MessageType MessageType {
             get {
@@ -71,13 +68,11 @@ namespace Smuxi.Engine
         public MessageBuilder()
         {
             Message = new MessageModel();
-            NickColors = true;
+            Settings = new MessageBuilderSettings();
         }
 
         public MessageModel ToMessage()
         {
-            //MessageParser.ParseSmileys
-            MessageParser.ParseUrls(Message);
             Message.Compact();
             return Message;
         }
@@ -88,15 +83,7 @@ namespace Smuxi.Engine
                 throw new ArgumentNullException("userConfig");
             }
 
-            NickColors = (bool) userConfig["Interface/Notebook/Channel/NickColors"];
-            StripColors = (bool) userConfig["Interface/Notebook/StripColors"];
-            StripFormattings = (bool) userConfig["Interface/Notebook/StripFormattings"];
-            HighlightColor = TextColor.Parse(
-                (string) userConfig["Interface/Notebook/Tab/HighlightColor"]
-            );
-            HighlightWords = new List<string>(
-                (string[]) userConfig["Interface/Chat/HighlightWords"]
-            );
+            Settings.ApplyConfig(userConfig);
         }
 
         public virtual MessageBuilder Append(MessagePartModel msgPart)
@@ -274,7 +261,7 @@ namespace Smuxi.Engine
 
         public virtual MessageBuilder AppendMessage(string msg)
         {
-            return AppendText(msg);
+            return Append(ParsePatterns(CreateText(msg)));
         }
 
         public  MessageBuilder AppendMessage(ContactModel sender, string msg)
@@ -309,7 +296,7 @@ namespace Smuxi.Engine
                 throw new ArgumentNullException("identity");
             }
 
-            if (!NickColors) {
+            if (!Settings.NickColors) {
                 return CreateText(identity.IdentityName);
             }
 
@@ -345,7 +332,7 @@ namespace Smuxi.Engine
             var prefix = CreateText("<");
             var suffix = CreateText(">");
             var nick = CreateIdendityName(contact);
-            if (NickColors) {
+            if (Settings.NickColors) {
                 // using bg colors for the nick texts are too intrusive, thus
                 // map the bg color to the fg color of the surrounding tags
                 var senderBgColor = contact.IdentityNameColored.BackgroundColor;
@@ -437,7 +424,7 @@ namespace Smuxi.Engine
             }
 
             // go through the user's custom highlight words and check for them.
-            foreach (string highLightWord in HighlightWords) {
+            foreach (string highLightWord in Settings.HighlightWords) {
                 if (String.IsNullOrEmpty(highLightWord)) {
                     continue;
                 }
@@ -509,7 +496,7 @@ namespace Smuxi.Engine
                 // ClearHighlights() has no chance to properly undo all
                 // highlights
                 textMsg.IsHighlight = true;
-                textMsg.ForegroundColor = HighlightColor;
+                textMsg.ForegroundColor = Settings.HighlightColor;
             }
         }
 
@@ -854,5 +841,101 @@ namespace Smuxi.Engine
         {
             return LibraryCatalog.GetString(msg, LibraryTextDomain);
         }
+
+        public static IList<MessagePartModel> ParsePatterns(TextMessagePartModel textPart,
+                                                            List<MessagePatternModel> patterns)
+        {
+            if (textPart == null) {
+                throw new ArgumentNullException("textPart");
+            }
+            if (patterns == null) {
+                throw new ArgumentNullException("patterns");
+            }
+
+            var msgParts = new List<MessagePartModel>();
+            if (patterns.Count == 0) {
+                // all patterns have been tried -> this text is PURE text
+                msgParts.Add(textPart);
+                return msgParts;
+            }
+
+            var remainingPatterns = new List<MessagePatternModel>(patterns);
+            var pattern = remainingPatterns.First();
+            remainingPatterns.Remove(pattern);
+            
+            var match = pattern.MessagePartPattern.Match(textPart.Text);
+            if (!match.Success) {
+                // no matches in this MessagePart, try other smartlinks
+                return ParsePatterns(textPart, remainingPatterns);
+            }
+            
+            int lastindex = 0;
+            do {
+                var groupValues = new string[match.Groups.Count];
+                int i = 0;
+                foreach (Group @group in match.Groups) {
+                    groupValues[i++] = @group.Value;
+                }
+                
+                string url;
+                if (String.IsNullOrEmpty(pattern.LinkFormat)) {
+                    url = match.Value;
+                } else {
+                    url = String.Format(pattern.LinkFormat, groupValues);
+                }
+                string text;
+                if (String.IsNullOrEmpty(pattern.TextFormat)) {
+                    text = match.Value;
+                } else {
+                    text = String.Format(pattern.TextFormat, groupValues);
+                }
+
+                if (lastindex != match.Index) {
+                    // there were some non-matching-chars before the match
+                    // copy that to a TextMessagePartModel
+                    var notMatchPart = new TextMessagePartModel(textPart);
+                    // only take the proper chunk of text
+                    notMatchPart.Text = textPart.Text.Substring(lastindex, match.Index - lastindex);
+                    // and try other patterns on this part
+                    var parts = ParsePatterns(notMatchPart, remainingPatterns);
+                    foreach (var part in parts) {
+                        msgParts.Add(part);
+                    }
+                }
+                
+                MessagePartModel msgPart;
+                if (pattern.MessagePartType == typeof(UrlMessagePartModel)) {
+                    // no need to set URL and text if they are the same
+                    text = text == url ? null : text;
+                    msgPart = new UrlMessagePartModel(url, text);
+                } else if (pattern.MessagePartType == typeof(ImageMessagePartModel)) {
+                    msgPart = new ImageMessagePartModel(url, text);
+                } else {
+                    msgPart = new TextMessagePartModel(text);
+                }
+                msgParts.Add(msgPart);
+                lastindex = match.Index + match.Length;
+                match = match.NextMatch();
+            } while (match.Success);
+            
+            if (lastindex != textPart.Text.Length) {
+                // there were some non-url-chars before this url
+                // copy TextMessagePartModel
+                var notMatchPart = new TextMessagePartModel(textPart);
+                // only take the proper chunk of text
+                notMatchPart.Text = textPart.Text.Substring(lastindex);
+                // and try other smartlinks on this part
+                var parts = ParsePatterns(notMatchPart, remainingPatterns);
+                foreach (var part in parts) {
+                    msgParts.Add(part);
+                }
+            }
+            return msgParts;
+        }
+        
+        public IEnumerable<MessagePartModel> ParsePatterns(TextMessagePartModel part)
+        {
+            return ParsePatterns(part, Settings.Patterns);
+        }
     }
 }
diff --git a/src/Engine/Messages/MessageModel.cs b/src/Engine/Messages/MessageModel.cs
index 081c89d..4fb360a 100644
--- a/src/Engine/Messages/MessageModel.cs
+++ b/src/Engine/Messages/MessageModel.cs
@@ -33,6 +33,7 @@ namespace Smuxi.Engine
     [Serializable]
     public class MessageModel : ISerializable
     {
+        static readonly Regex NickRegex = new Regex("^<([^ ]+)> ");
         private DateTime                f_TimeStamp;
         private IList<MessagePartModel> f_MessageParts;
         private MessageType             f_MessageType;
@@ -257,7 +258,7 @@ namespace Smuxi.Engine
             // meesage itself
             // TODO: extend MessageModel with Origin property
             var msgText = ToString();
-            var match = Regex.Match(msgText, "^<([^ ]+)>");
+            var match = NickRegex.Match(msgText);
             if (match.Success && match.Groups.Count >= 2) {
                 return match.Groups[1].Value;
             }
diff --git a/src/Engine/Messages/MessageParser.cs b/src/Engine/Messages/MessageParser.cs
deleted file mode 100644
index ec7f09a..0000000
--- a/src/Engine/Messages/MessageParser.cs
+++ /dev/null
@@ -1,161 +0,0 @@
-// Smuxi - Smart MUltipleXed Irc
-// 
-// Copyright (c) 2010 Mirco Bauer <meebey at meebey.net>
-// 
-// Full GPL License: <http://www.gnu.org/licenses/gpl.txt>
-// 
-// 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
-
-using System;
-using System.Text.RegularExpressions;
-using System.Collections.Generic;
-
-namespace Smuxi.Engine
-{
-    public static class MessageParser
-    {
-        static Regex UrlRegex { get; set; }
-        static Regex SimleyRegex { get; set; }
-
-        static MessageParser()
-        {
-            //urlRegex = "((([a-zA-Z][0-9a-zA-Z+\\-\\.]*:)?/{0,2}[0-9a-zA-Z;/?:@&=+$\\.\\-_!~*'()%]+)?(#[0-9a-zA-Z;/?:@&=+$\\.\\-_!~*'()%]+)?)");
-            // It was constructed according to the BNF grammar given in RFC 2396 (http://www.ietf.org/rfc/rfc2396.txt).
-            /*
-            urlRegex = @"^(?<s1>(?<s0>[^:/\?#]+):)?(?<a1>" +
-                                  @"//(?<a0>[^/\?#]*))?(?<p0>[^\?#]*)" +
-                                  @"(?<q1>\?(?<q0>[^#]*))?" +
-                                  @"(?<f1>#(?<f0>.*))?");
-            */
-            UrlRegex = new Regex(
-                @"(^| )(((https?|ftp):\/\/)|www\.)" +
-                @"(" +
-                    @"([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)|" +
-                    @"localhost|" +
-                    @"([a-zA-Z0-9\-]+\.)*[a-zA-Z0-9\-]+\." +
-                        @"(com|net|org|info|biz|gov|name|edu|[a-zA-Z][a-zA-Z])" +
-                @")" +
-                @"(:[0-9]+)?((\/|\?)[^ ""]*[^ ,;\.:"">)])?",
-                RegexOptions.IgnoreCase
-            );
-
-            SimleyRegex = new Regex(@":-?(\(|\))");
-        }
-
-        public static void ParseUrls(MessageModel msg)
-        {
-            // clone MessageParts
-            IList<MessagePartModel> parts = new List<MessagePartModel>(msg.MessageParts);
-            foreach (MessagePartModel part in parts) {
-                if (part is UrlMessagePartModel) {
-                    // no need to reparse URL parts
-                    continue;
-                }
-                if (!(part is TextMessagePartModel)) {
-                    continue;
-                }
-                
-                TextMessagePartModel textPart = (TextMessagePartModel) part;
-                Match urlMatch = UrlRegex.Match(textPart.Text);
-                // OPT: fast regex scan
-                if (!urlMatch.Success) {
-                    // no URLs in this MessagePart, nothing to do
-                    continue;
-                }
-                
-                // found URL(s)
-                // remove current MessagePartModel as we need to split it
-                int idx = msg.MessageParts.IndexOf(part);
-                msg.MessageParts.RemoveAt(idx);
-                
-                string[] textPartParts = textPart.Text.Split(new char[] {' '});
-                for (int i = 0; i < textPartParts.Length; i++) {
-                    string textPartPart = textPartParts[i];
-                    urlMatch = UrlRegex.Match(textPartPart);
-                    if (urlMatch.Success) {
-                        UrlMessagePartModel urlPart = new UrlMessagePartModel(textPartPart);
-                        //urlPart.ForegroundColor = new TextColor();
-                        msg.MessageParts.Insert(idx++, urlPart);
-                        msg.MessageParts.Insert(idx++, new TextMessagePartModel(" "));
-                    } else {
-                        // FIXME: we put each text part into it's own object, instead of combining them (the smart way)
-                        TextMessagePartModel notUrlPart = new TextMessagePartModel(textPartPart + " ");
-                        // restore formatting / colors from the original text part
-                        notUrlPart.IsHighlight     = textPart.IsHighlight;
-                        notUrlPart.ForegroundColor = textPart.ForegroundColor;
-                        notUrlPart.BackgroundColor = textPart.BackgroundColor;
-                        notUrlPart.Bold            = textPart.Bold;
-                        notUrlPart.Italic          = textPart.Italic;
-                        notUrlPart.Underline       = textPart.Underline;
-                        msg.MessageParts.Insert(idx++, notUrlPart);
-                    }
-                }
-            }
-        }
-
-        public static void ParseSmileys(MessageModel msg)
-        {
-            // clone MessageParts
-            IList<MessagePartModel> parts = new List<MessagePartModel>(msg.MessageParts);
-            foreach (MessagePartModel part in parts) {
-                if (!(part is TextMessagePartModel)) {
-                    continue;
-                }
-                
-                TextMessagePartModel textPart = (TextMessagePartModel) part;
-                Match simleyMatch = SimleyRegex.Match(textPart.Text);
-                // OPT: fast regex scan
-                if (!simleyMatch.Success) {
-                    // no smileys in this MessagePart, nothing to do
-                    continue;
-                }
-                
-                // found smiley(s)
-                // remove current MessagePartModel as we need to split it
-                int idx = msg.MessageParts.IndexOf(part);
-                msg.MessageParts.RemoveAt(idx);
-                
-                string[] textPartParts = textPart.Text.Split(new char[] {' '});
-                for (int i = 0; i < textPartParts.Length; i++) {
-                    string textPartPart = textPartParts[i];
-                    simleyMatch = SimleyRegex.Match(textPartPart);
-                    if (simleyMatch.Success) {
-                        string filename = null;
-                        if (textPartPart == ":-)") {
-                            filename = "smile.png";
-                        }
-                        ImageMessagePartModel imagePart = new ImageMessagePartModel(
-                            filename,
-                            textPartPart
-                        );
-                        msg.MessageParts.Insert(idx++, imagePart);
-                        msg.MessageParts.Insert(idx++, new TextMessagePartModel(" "));
-                    } else {
-                        // FIXME: we put each text part into it's own object, instead of combining them (the smart way)
-                        TextMessagePartModel notUrlPart = new TextMessagePartModel(textPartPart + " ");
-                        // restore formatting / colors from the original text part
-                        notUrlPart.IsHighlight     = textPart.IsHighlight;
-                        notUrlPart.ForegroundColor = textPart.ForegroundColor;
-                        notUrlPart.BackgroundColor = textPart.BackgroundColor;
-                        notUrlPart.Bold            = textPart.Bold;
-                        notUrlPart.Italic          = textPart.Italic;
-                        notUrlPart.Underline       = textPart.Underline;
-                        msg.MessageParts.Insert(idx++, notUrlPart);
-                    }
-                }
-            }
-        }
-    }
-}
diff --git a/src/Engine/Messages/UrlMessagePartModel.cs b/src/Engine/Messages/UrlMessagePartModel.cs
index 5a7d798..e738e2d 100644
--- a/src/Engine/Messages/UrlMessagePartModel.cs
+++ b/src/Engine/Messages/UrlMessagePartModel.cs
@@ -51,7 +51,6 @@ namespace Smuxi.Engine
 #if LOG4NET
         private static readonly log4net.ILog _Logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
 #endif
-        private UrlProtocol _Protocol;
         private string      _Url;
         
         public string Url {
@@ -65,16 +64,7 @@ namespace Smuxi.Engine
                 _Url = value;
             }
         }
-        
-        public UrlProtocol Protocol {
-            get {
-                return _Protocol;
-            }
-            set {
-                _Protocol = value;
-            }
-        }
-        
+
         public UrlMessagePartModel(string url) :
                               this(url, null)
         {
@@ -84,34 +74,17 @@ namespace Smuxi.Engine
             : base(model)
         {
             if (model is UrlMessagePartModel) {
-                _Protocol = (model as UrlMessagePartModel)._Protocol;
                 _Url = (model as UrlMessagePartModel)._Url;
             }
         }
 
         public UrlMessagePartModel(string url, string text):
-                              this(url, text, UrlProtocol.None)
-
-        {
-            _Protocol = ParseProtocol(url);
-            if (_Protocol == UrlProtocol.None) {
-                // assume http if no protocol was specified
-                _Protocol = UrlProtocol.Http;
-                // text should stay pristine
-                if (Text == null) {
-                    Text = _Url;
-                }
-                _Url = String.Format("http://{0}", _Url);
-            }
-        }
-        
-        public UrlMessagePartModel(string url, string text, UrlProtocol protocol) :
                               base(text)
+
         {
             _Url = url;
-            _Protocol = protocol;
         }
-        
+
         protected UrlMessagePartModel(SerializationInfo info, StreamingContext ctx) :
                                  base(info, ctx)
         {
@@ -121,7 +94,7 @@ namespace Smuxi.Engine
         {
             base.SetObjectData(sr);
             
-            _Protocol = (UrlProtocol) sr.ReadInt32();
+            sr.ReadInt32();
             _Url = sr.ReadString();
         }
         
@@ -129,28 +102,10 @@ namespace Smuxi.Engine
         {
             base.GetObjectData(sw);
 
-            sw.Write((Int32) _Protocol);
+            sw.Write((Int32) UrlProtocol.Unknown);
             sw.Write(_Url);
         }
 
-        protected static UrlProtocol ParseProtocol(string url)
-        {
-            Match match = Regex.Match(url, @"^([a-zA-Z0-9\-]+):");
-            if (!match.Success) {
-                return UrlProtocol.None;
-            }
-            
-            string protocol = match.Groups[1].Value;
-            try {
-                return (UrlProtocol) Enum.Parse(typeof(UrlProtocol), protocol, true);
-            } catch (ArgumentException ex) {
-#if LOG4NET
-                _Logger.Error("ParseProtocol(url): error parsing protocol: " + protocol, ex);
-#endif
-            }
-            return UrlProtocol.Unknown;
-        }
-
         public override string ToString()
         {
             if (Text == null) {
@@ -165,5 +120,29 @@ namespace Smuxi.Engine
                 return "[" + _Url + " " + Text + "]";
             }
         }
+        
+        public override bool Equals(object obj)
+        {
+            if (!(obj is UrlMessagePartModel)) {
+                return false;
+            }
+
+            var urlPart = (UrlMessagePartModel) obj;
+            return Equals(urlPart);
+        }
+        
+        public override bool Equals(MessagePartModel part)
+        {
+            var urlPart = part as UrlMessagePartModel;
+            if ((object) urlPart == null) {
+                return false;
+            }
+            
+            if (_Url != urlPart._Url) {
+                return false;
+            }
+                
+            return base.Equals(urlPart);
+        }
     }
 }
diff --git a/src/Engine/Protocols/ProtocolManagerBase.cs b/src/Engine/Protocols/ProtocolManagerBase.cs
index f25f811..a638a8f 100644
--- a/src/Engine/Protocols/ProtocolManagerBase.cs
+++ b/src/Engine/Protocols/ProtocolManagerBase.cs
@@ -150,6 +150,20 @@ namespace Smuxi.Engine
             }
         }
         
+        public override string ToString()
+        {
+            string result;
+            if (Chat == null) {
+                result = NetworkID;
+            } else {
+                result = Chat.Name;
+            }
+            if (!IsConnected) {
+                result += " (" + _("not connected") + ")";
+            }
+            return result;
+        }
+
         public abstract bool Command(CommandModel cmd);
         public abstract void Connect(FrontendManager fm,
                                      ServerModel server);
@@ -335,7 +349,9 @@ namespace Smuxi.Engine
         {
             var builder = new T();
             builder.Me = Me;
-            builder.ApplyConfig(Session.UserConfig);
+            // copy settings so the caller can override settings without
+            // changing the settings of the complete session
+            builder.Settings = new MessageBuilderSettings(Session.MessageBuilderSettings);
             return builder;
         }
 
diff --git a/src/Engine/Protocols/ProtocolManagerFactory.cs b/src/Engine/Protocols/ProtocolManagerFactory.cs
index 3fa46b4..c0140ea 100644
--- a/src/Engine/Protocols/ProtocolManagerFactory.cs
+++ b/src/Engine/Protocols/ProtocolManagerFactory.cs
@@ -118,7 +118,7 @@ namespace Smuxi.Engine
         {
             Trace.Call(path);
             
-            string[] filenames = Directory.GetFiles(path, "smuxi-engine-*.dll");
+            string[] filenames = Directory.GetFiles(path, "smuxi-engine*.dll");
             foreach (string filename in filenames) {
                 LoadProtocolManager(filename);
             }
@@ -127,7 +127,8 @@ namespace Smuxi.Engine
         public ProtocolManagerInfoModel GetProtocolManagerInfoByAlias(string alias)
         {
             foreach (ProtocolManagerInfoModel info in _ProtocolManagerTypes.Keys) {
-                if (info.Alias.Equals(alias, StringComparison.InvariantCultureIgnoreCase)) {
+                if (info.Alias.Equals(alias, StringComparison.InvariantCultureIgnoreCase) ||
+                    info.Name.Equals(alias, StringComparison.InvariantCultureIgnoreCase)) {
                     return info;
                 }
             }
diff --git a/src/Engine/Session.cs b/src/Engine/Session.cs
index 9c552c1..d082b4d 100644
--- a/src/Engine/Session.cs
+++ b/src/Engine/Session.cs
@@ -1,7 +1,7 @@
 /*
  * Smuxi - Smart MUltipleXed Irc
  *
- * Copyright (c) 2005-2013 Mirco Bauer <meebey at meebey.net>
+ * Copyright (c) 2005-2014 Mirco Bauer <meebey at meebey.net>
  *
  * Full GPL License: <http://www.gnu.org/licenses/gpl.txt>
  *
@@ -58,6 +58,11 @@ namespace Smuxi.Engine
         DateTime NewsFeedLastModified { get; set; }
         TimeSpan NewsFeedUpdateInterval { get; set; }
         TimeSpan NewsFeedRetryInterval { get; set; }
+        internal MessageBuilderSettings MessageBuilderSettings { get; private set; }
+
+        public event EventHandler<GroupChatPersonAddedEventArgs> GroupChatPersonAdded;
+        public event EventHandler<GroupChatPersonRemovedEventArgs> GroupChatPersonRemoved;
+        public event EventHandler<GroupChatPersonUpdatedEventArgs> GroupChatPersonUpdated;
 
         public IList<IProtocolManager> ProtocolManagers {
             get {
@@ -150,6 +155,8 @@ namespace Smuxi.Engine
             _UserConfig.Changed += OnUserConfigChanged;
             _FilterListController = new FilterListController(_UserConfig);
             _Filters = _FilterListController.GetFilterList().Values;
+            MessageBuilderSettings = new MessageBuilderSettings();
+            MessageBuilderSettings.ApplyConfig(_UserConfig);
             _Chats = new List<ChatModel>();
 
             InitSessionChat();
@@ -183,7 +190,9 @@ namespace Smuxi.Engine
         protected MessageBuilder CreateMessageBuilder()
         {
             var builder = new MessageBuilder();
-            builder.ApplyConfig(UserConfig);
+            // copy settings so the caller can override settings without
+            // changing the settings of the complete session
+            builder.Settings = new MessageBuilderSettings(MessageBuilderSettings);
             return builder;
         }
 
@@ -481,6 +490,7 @@ namespace Smuxi.Engine
                 "config (save|load|list)",
                 "config get key",
                 "config set key=value",
+                "config remove key",
                 "shutdown"
             };
 
@@ -726,33 +736,86 @@ namespace Smuxi.Engine
                         return;
                     }
                     string setKey = setParam.Split('=')[0];
-                    string setValue = setParam.Split('=')[1];
+                    string setValue = String.Join(
+                        "=", setParam.Split('=').Skip(1).ToArray()
+                    );
                     object oldValue = _UserConfig[setKey];
+                    if (oldValue == null && setKey.StartsWith("MessagePatterns/")) {
+                        var id = setKey.Split('/')[1];
+                        var parsedId = Int32.Parse(id);
+                        var msgPatternSettings = new MessagePatternListController(_UserConfig);
+                        var pattern = msgPatternSettings.Get(parsedId);
+                        if (pattern == null) {
+                            // pattern does not exist, create it with default values
+                            pattern = new MessagePatternModel(parsedId);
+                            msgPatternSettings.Add(pattern, parsedId);
+                            oldValue = _UserConfig[setKey];
+                        }
+                    }
                     if (oldValue == null) {
                         builder.AppendErrorText(
                             _("Invalid config key: '{0}'"),
                             setKey
                         );
-                    } else {
-                        try {
-                            object newValue = Convert.ChangeType(setValue, oldValue.GetType());
-                            _UserConfig[setKey] = newValue;
-                            builder.AppendText("{0} = {1}", setKey, newValue.ToString());
-                        } catch (InvalidCastException) {
-                            builder.AppendErrorText(
-                                _("Could not convert config value: '{0}' to type: {1}"),
-                                setValue,
-                                oldValue.GetType().Name
-                            );
-                        } catch (FormatException) {
-                            builder.AppendErrorText(
-                                _("Could not convert config value: '{0}' to type: {1}"),
-                                setValue,
-                                oldValue.GetType().Name
-                            );
+                        AddMessageToFrontend(cd, builder.ToMessage());
+                        return;
+                    }
+
+                    try {
+                        object newValue = Convert.ChangeType(setValue, oldValue.GetType());
+                        _UserConfig[setKey] = newValue;
+                        builder.AppendText("{0} = {1}", setKey, newValue.ToString());
+                        if (setKey.StartsWith("MessagePatterns/")) {
+                            MessageBuilderSettings.ApplyConfig(UserConfig);
                         }
+                    } catch (InvalidCastException) {
+                        builder.AppendErrorText(
+                            _("Could not convert config value: '{0}' to type: {1}"),
+                            setValue,
+                            oldValue.GetType().Name
+                        );
+                    } catch (FormatException) {
+                        builder.AppendErrorText(
+                            _("Could not convert config value: '{0}' to type: {1}"),
+                            setValue,
+                            oldValue.GetType().Name
+                        );
                     }
                     break;
+                case "remove": {
+                    if (cd.DataArray.Length < 3) {
+                        _NotEnoughParameters(cd);
+                        return;
+                    }
+                    var removeParam = cd.DataArray[2];
+                    if (!removeParam.StartsWith("MessagePatterns/")) {
+                        builder.AppendErrorText(
+                            _("Invalid config remove key: '{0}'. Valid remove " +
+                              "keys: MessagePatterns/{{ID}}."),
+                            removeParam
+                        );
+                        AddMessageToFrontend(cd, builder.ToMessage());
+                        return;
+                    }
+                    var id = removeParam.Split('/')[1];
+                    var parsedId = Int32.Parse(id);
+                    var patternController = new MessagePatternListController(_UserConfig);
+                    var pattern = patternController.Get(parsedId);
+                    if (pattern == null) {
+                        builder.AppendErrorText(
+                            _("Message pattern with ID: '{0}' does not exist."),
+                            id
+                        );
+                    } else {
+                        patternController.Remove(parsedId);
+                        MessageBuilderSettings.ApplyConfig(UserConfig);
+                        builder.AppendText(
+                            _("Message pattern with ID: '{0}' removed."),
+                            id
+                        );
+                    }
+                    break;
+                }
                 default:
                     builder.AppendErrorText(
                         _("Invalid parameter for config; use load, save, get or set.")
@@ -1278,6 +1341,10 @@ namespace Smuxi.Engine
                     fm.AddPersonToGroupChat(groupChat, person);
                 }
             }
+
+            OnGroupChatPersonAdded(
+                new GroupChatPersonAddedEventArgs(groupChat, person)
+            );
         }
         
         public void UpdatePersonInGroupChat(GroupChatModel groupChat, PersonModel oldPerson, PersonModel newPerson)
@@ -1308,6 +1375,10 @@ namespace Smuxi.Engine
                     fm.UpdatePersonInGroupChat(groupChat, oldPerson, newPerson);
                 }
             }
+
+            OnGroupChatPersonUpdated(
+                new GroupChatPersonUpdatedEventArgs(groupChat, oldPerson, newPerson)
+            );
         }
     
         public void UpdateTopicInGroupChat(GroupChatModel groupChat, MessageModel topic)
@@ -1348,6 +1419,10 @@ namespace Smuxi.Engine
                     fm.RemovePersonFromGroupChat(groupChat, person);
                 }
             }
+
+            OnGroupChatPersonRemoved(
+                new GroupChatPersonRemovedEventArgs(groupChat, person)
+            );
         }
         
         public void SetNetworkStatus(string status)
@@ -1827,9 +1902,127 @@ namespace Smuxi.Engine
             }
         }
 
+        protected virtual void OnGroupChatPersonAdded(GroupChatPersonAddedEventArgs e)
+        {
+            if (GroupChatPersonAdded != null) {
+                GroupChatPersonAdded(this, e);
+            }
+
+            var pm = e.GroupChat.ProtocolManager;
+            var hooks = new HookRunner("engine", "session", "on-group-chat-person-added");
+            hooks.Environments.Add(new ChatHookEnvironment(e.GroupChat));
+            if (pm != null) {
+                hooks.Environments.Add(new ProtocolManagerHookEnvironment(pm));
+            }
+            hooks.Environments.Add(new PersonHookEnvironment(e.AddedPerson));
+
+            var cmdChar = (string) UserConfig["Interface/Entry/CommandCharacter"];
+            hooks.Commands.Add(new SessionHookCommand(this, e.GroupChat, cmdChar));
+            if (pm != null) {
+                hooks.Commands.Add(new ProtocolManagerHookCommand(pm, e.GroupChat, cmdChar));
+            }
+
+            // show time
+            hooks.Init();
+            hooks.Run();
+        }
+
+        protected virtual void OnGroupChatPersonRemoved(GroupChatPersonRemovedEventArgs e)
+        {
+            if (GroupChatPersonRemoved != null) {
+                GroupChatPersonRemoved(this, e);
+            }
+
+            var pm = e.GroupChat.ProtocolManager;
+            var hooks = new HookRunner("engine", "session", "on-group-chat-person-removed");
+            hooks.Environments.Add(new ChatHookEnvironment(e.GroupChat));
+            if (pm != null) {
+                hooks.Environments.Add(new ProtocolManagerHookEnvironment(pm));
+            }
+            hooks.Environments.Add(new PersonHookEnvironment(e.RemovedPerson));
+
+            var cmdChar = (string) UserConfig["Interface/Entry/CommandCharacter"];
+            hooks.Commands.Add(new SessionHookCommand(this, e.GroupChat, cmdChar));
+            if (pm != null) {
+                hooks.Commands.Add(new ProtocolManagerHookCommand(pm, e.GroupChat, cmdChar));
+            }
+
+            // show time
+            hooks.Init();
+            hooks.Run();
+        }
+
+        protected virtual void OnGroupChatPersonUpdated(GroupChatPersonUpdatedEventArgs e)
+        {
+            if (GroupChatPersonUpdated != null) {
+                GroupChatPersonUpdated(this, e);
+            }
+
+            var pm = e.GroupChat.ProtocolManager;
+            var hooks = new HookRunner("engine", "session", "on-group-chat-person-updated");
+            hooks.Environments.Add(new ChatHookEnvironment(e.GroupChat));
+            if (pm != null) {
+                hooks.Environments.Add(new ProtocolManagerHookEnvironment(pm));
+            }
+            hooks.Environments.Add(new PersonHookEnvironment("OLD_", e.OldPerson));
+            hooks.Environments.Add(new PersonHookEnvironment("NEW_", e.NewPerson));
+
+            var cmdChar = (string) UserConfig["Interface/Entry/CommandCharacter"];
+            hooks.Commands.Add(new SessionHookCommand(this, e.GroupChat, cmdChar));
+            if (pm != null) {
+                hooks.Commands.Add(new ProtocolManagerHookCommand(pm, e.GroupChat, cmdChar));
+            }
+
+            // show time
+            hooks.Init();
+            hooks.Run();
+        }
+
         private static string _(string msg)
         {
             return LibraryCatalog.GetString(msg, _LibraryTextDomain);
         }
     }
+
+    public abstract class GroupChatEventArgs : EventArgs
+    {
+        public GroupChatModel GroupChat { get; protected set; }
+    }
+
+    public class GroupChatPersonAddedEventArgs : GroupChatEventArgs
+    {
+        public PersonModel AddedPerson { get; private set; }
+
+        public GroupChatPersonAddedEventArgs(GroupChatModel groupChat, PersonModel addedPerson)
+        {
+            GroupChat = groupChat;
+            AddedPerson = addedPerson;
+        }
+    }
+
+    public class GroupChatPersonRemovedEventArgs : GroupChatEventArgs
+    {
+        public PersonModel RemovedPerson { get; private set; }
+
+        public GroupChatPersonRemovedEventArgs(GroupChatModel groupChat, PersonModel removedPerson)
+        {
+            GroupChat = groupChat;
+            RemovedPerson = removedPerson;
+        }
+    }
+
+    public class GroupChatPersonUpdatedEventArgs : GroupChatEventArgs
+    {
+        public PersonModel OldPerson { get; private set; }
+        public PersonModel NewPerson { get; private set; }
+
+        public GroupChatPersonUpdatedEventArgs(GroupChatModel groupChat,
+                                               PersonModel oldPerson,
+                                               PersonModel newPerson)
+        {
+            GroupChat = groupChat;
+            OldPerson = oldPerson;
+            NewPerson = newPerson;
+        }
+    }
 }
diff --git a/src/Frontend-Curses/Makefile.in b/src/Frontend-Curses/Makefile.in
index ad8d128..cb8709d 100644
--- a/src/Frontend-Curses/Makefile.in
+++ b/src/Frontend-Curses/Makefile.in
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994-2013 Free Software Foundation, Inc.
diff --git a/src/Frontend-GNOME-IRC/IrcPersonChatView.cs b/src/Frontend-GNOME-IRC/IrcPersonChatView.cs
index 286bbc4..7a0b477 100644
--- a/src/Frontend-GNOME-IRC/IrcPersonChatView.cs
+++ b/src/Frontend-GNOME-IRC/IrcPersonChatView.cs
@@ -2,6 +2,7 @@
  * Smuxi - Smart MUltipleXed Irc
  *
  * Copyright (c) 2008, 2010-2011 Mirco Bauer <meebey at meebey.net>
+ * Copyright (c) 2013 Andrés G. Aragoneses <knocte at gmail.com>
  *
  * Full GPL License: <http://www.gnu.org/licenses/gpl.txt>
  *
@@ -21,8 +22,8 @@
  */
 
 using System;
+using System.Collections.Generic;
 using System.Threading;
-using System.Globalization;
 using Smuxi.Engine;
 using Smuxi.Common;
 
@@ -50,6 +51,21 @@ namespace Smuxi.Frontend.Gnome
             IrcProtocolManager = (IrcProtocolManager) ProtocolManager;
         }
 
+        protected override void OnTabMenuShown(object sender, EventArgs e)
+        {
+            base.OnTabMenuShown(sender, e);
+
+            var stack = new Stack<Gtk.MenuItem>();
+            foreach (var menu_item in CreateContextMenuItems()) {
+                stack.Push(menu_item);
+            }
+            TabMenu.Prepend(new Gtk.SeparatorMenuItem());
+            while (stack.Count != 0) {
+                TabMenu.Prepend(stack.Pop());
+            }
+            TabMenu.ShowAll();
+        }
+
         void OnOutputMessageTextViewPopulatePopup(object o, Gtk.PopulatePopupArgs args)
         {
             if (OutputMessageTextView.IsAtUrlTag) {
@@ -59,26 +75,32 @@ namespace Smuxi.Frontend.Gnome
             Gtk.Menu popup = args.Menu;
 
             popup.Append(new Gtk.SeparatorMenuItem());
+            foreach (var menu_item in CreateContextMenuItems()) {
+                popup.Append(menu_item);
+            }
 
+            popup.ShowAll();
+        }
+
+        IEnumerable<Gtk.MenuItem> CreateContextMenuItems()
+        {
             Gtk.ImageMenuItem whois_item = new Gtk.ImageMenuItem(_("Whois"));
             whois_item.Activated += OnMenuWhoisItemActivated;
-            popup.Append(whois_item);
+            yield return whois_item;
 
             Gtk.ImageMenuItem ctcp_item = new Gtk.ImageMenuItem(_("CTCP"));
             Gtk.Menu ctcp_menu_item = new CtcpMenu(IrcProtocolManager,
                                                    Frontend.MainWindow.ChatViewManager,
                                                    PersonModel);
             ctcp_item.Submenu = ctcp_menu_item;
-            popup.Append(ctcp_item);
+            yield return ctcp_item;
 
             Gtk.ImageMenuItem invite_to_item = new Gtk.ImageMenuItem(_("Invite to"));
             Gtk.Menu invite_to_menu_item = new InviteToMenu(IrcProtocolManager,
                                                             Frontend.MainWindow.ChatViewManager,
                                                             PersonModel);
             invite_to_item.Submenu = invite_to_menu_item;
-            popup.Append(invite_to_item);
-
-            popup.ShowAll();
+            yield return invite_to_item;
         }
 
         void OnMenuWhoisItemActivated(object sender, EventArgs e)
diff --git a/src/Frontend-GNOME-IRC/Makefile.am b/src/Frontend-GNOME-IRC/Makefile.am
index 1cdbe15..eaca695 100644
--- a/src/Frontend-GNOME-IRC/Makefile.am
+++ b/src/Frontend-GNOME-IRC/Makefile.am
@@ -99,6 +99,7 @@ RESOURCES =
 EXTRAS =
 
 REFERENCES =  \
+	System \
 	Mono.Posix \
 	$(GTK_SHARP_20_LIBS)
 
diff --git a/src/Frontend-GNOME-IRC/Makefile.in b/src/Frontend-GNOME-IRC/Makefile.in
index 25bb316..1850da2 100644
--- a/src/Frontend-GNOME-IRC/Makefile.in
+++ b/src/Frontend-GNOME-IRC/Makefile.in
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994-2013 Free Software Foundation, Inc.
@@ -457,6 +457,7 @@ DATA_FILES =
 RESOURCES = 
 EXTRAS = 
 REFERENCES = \
+	System \
 	Mono.Posix \
 	$(GTK_SHARP_20_LIBS)
 
diff --git a/src/Frontend-GNOME-Twitter/Makefile.in b/src/Frontend-GNOME-Twitter/Makefile.in
index 952889b..5f0b02d 100644
--- a/src/Frontend-GNOME-Twitter/Makefile.in
+++ b/src/Frontend-GNOME-Twitter/Makefile.in
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994-2013 Free Software Foundation, Inc.
diff --git a/src/Frontend-GNOME-XMPP/Makefile.in b/src/Frontend-GNOME-XMPP/Makefile.in
index 16c9d29..83f013e 100644
--- a/src/Frontend-GNOME-XMPP/Makefile.in
+++ b/src/Frontend-GNOME-XMPP/Makefile.in
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994-2013 Free Software Foundation, Inc.
diff --git a/src/Frontend-GNOME/AboutDialog.cs b/src/Frontend-GNOME/AboutDialog.cs
index 7a35e52..694b8fe 100644
--- a/src/Frontend-GNOME/AboutDialog.cs
+++ b/src/Frontend-GNOME/AboutDialog.cs
@@ -67,8 +67,14 @@ namespace Smuxi.Frontend.Gnome
             Logo = Frontend.LoadIcon(
                 Frontend.IconName, 256, "icon_256x256.png"
             );
-            // HACK: shows "not implemented" error on OS X
-            if (!Frontend.IsMacOSX) {
+            // HACK: shows "not implemented" error on OS X and
+            // "No application is registered as handling this file" on Windows.
+            // This probably relies on gvfs or similar which isn't available in
+            // the GTK{+,#} ports/installers for OS X and Windows. Thus we only
+            // show the website URL as label instead.
+            if (Frontend.IsMacOSX || Frontend.IsWindows) {
+                WebsiteLabel = "http://www.smuxi.org/";
+            } else {
                 Website = "http://www.smuxi.org/";
                 WebsiteLabel = _("Smuxi Website");
             }
diff --git a/src/Frontend-GNOME/ChatViewManager.cs b/src/Frontend-GNOME/ChatViewManager.cs
index 4da44b9..afae62a 100644
--- a/src/Frontend-GNOME/ChatViewManager.cs
+++ b/src/Frontend-GNOME/ChatViewManager.cs
@@ -77,6 +77,12 @@ namespace Smuxi.Frontend.Gnome
                 return TreeView.CurrentChatNumber;
             }
             set {
+                if (value >= f_Chats.Count) {
+                    value = 0;
+                }
+                if (value < 0) {
+                    value = f_Chats.Count - 1;
+                }
                 TreeView.CurrentChatNumber = value;
             }
         }
diff --git a/src/Frontend-GNOME/Entry.cs b/src/Frontend-GNOME/Entry.cs
index 6258c69..1fdc580 100644
--- a/src/Frontend-GNOME/Entry.cs
+++ b/src/Frontend-GNOME/Entry.cs
@@ -849,6 +849,7 @@ namespace Smuxi.Frontend.Gnome
                 _CommandManager = null;
             } else {
                 _CommandManager = new CommandManager(Frontend.Session);
+                _CommandManager.EngineVersion = Frontend.EngineVersion;
                 _CommandManager.ExceptionEvent +=
                 delegate(object sender, CommandExceptionEventArgs e) {
                     Gtk.Application.Invoke(delegate {
diff --git a/src/Frontend-GNOME/Frontend.cs b/src/Frontend-GNOME/Frontend.cs
index eb9b7ee..97e728e 100644
--- a/src/Frontend-GNOME/Frontend.cs
+++ b/src/Frontend-GNOME/Frontend.cs
@@ -1,7 +1,7 @@
 /*
  * Smuxi - Smart MUltipleXed Irc
  *
- * Copyright (c) 2005-2013 Mirco Bauer <meebey at meebey.net>
+ * Copyright (c) 2005-2014 Mirco Bauer <meebey at meebey.net>
  *
  * Full GPL License: <http://www.gnu.org/licenses/gpl.txt>
  *
@@ -456,9 +456,9 @@ namespace Smuxi.Frontend.Gnome
                             Thread.Sleep(30 * 1000);
                         }
                     }
-                    Session = _MainWindow.EngineManager.Session;
                     _UserConfig = _MainWindow.EngineManager.UserConfig;
                     EngineVersion = _MainWindow.EngineManager.EngineVersion;
+                    Session = _MainWindow.EngineManager.Session;
 
                     Gtk.Application.Invoke(delegate {
                         Frontend.ConnectEngineToGUI();
@@ -802,7 +802,7 @@ namespace Smuxi.Frontend.Gnome
                 }
             }
             var linkChat = link.Fragment;
-            if (String.IsNullOrEmpty(linkChat)) {
+            if (String.IsNullOrEmpty(linkChat) && link.AbsolutePath.Length > 0) {
                 linkChat = link.AbsolutePath.Substring(1);
             }
 
@@ -855,6 +855,10 @@ namespace Smuxi.Frontend.Gnome
                     // try to find a server with this network name and connect to it
                     var serverSettings = new ServerListController(UserConfig);
                     server = serverSettings.GetServerByNetwork(linkNetwork);
+                    if (server == null) {
+                        // in case someone tried an unknown network
+                        return false;
+                    }
                     // ignore OnConnectCommands
                     server.OnConnectCommands = null;
                 } else if (!String.IsNullOrEmpty(linkHost)) {
diff --git a/src/Frontend-GNOME/MainWindow.cs b/src/Frontend-GNOME/MainWindow.cs
index 358443f..e3c92fa 100644
--- a/src/Frontend-GNOME/MainWindow.cs
+++ b/src/Frontend-GNOME/MainWindow.cs
@@ -1,7 +1,7 @@
 /*
  * Smuxi - Smart MUltipleXed Irc
  *
- * Copyright (c) 2005-2013 Mirco Bauer <meebey at meebey.net>
+ * Copyright (c) 2005-2014 Mirco Bauer <meebey at meebey.net>
  *
  * Full GPL License: <http://www.gnu.org/licenses/gpl.txt>
  *
@@ -44,6 +44,7 @@ namespace Smuxi.Frontend.Gnome
         public Gtk.ProgressBar ProgressBar { get; private set; }
         Gtk.HBox StatusHBox { get; set; }
         public MenuWidget MenuWidget { get; private set; }
+        Gtk.HPaned TreeViewHPaned { get; set; }
 
         public IFrontendUI UI { get; private set; }
         public Entry Entry { get; private set; }
@@ -262,6 +263,7 @@ namespace Smuxi.Frontend.Gnome
             var treeviewPaned = new Gtk.HPaned();
             treeviewPaned.Pack1(treeviewScrolledWindow, false, false);
             treeviewPaned.Pack2(Notebook, true, false);
+            TreeViewHPaned = treeviewPaned;
 
             var entryPaned = new Gtk.VPaned();
             entryPaned.ButtonPressEvent += (sender, e) => {
@@ -371,6 +373,14 @@ namespace Smuxi.Frontend.Gnome
             Title = title;
         }
 
+        protected override bool OnConfigureEvent(Gdk.EventConfigure e)
+        {
+            Trace.Call(e);
+
+            TreeViewHPaned.Position = e.Width / 6;
+            return base.OnConfigureEvent(e);
+        }
+
         protected virtual void OnDeleteEvent(object sender, Gtk.DeleteEventArgs e)
         {
             Trace.Call(sender, e);
diff --git a/src/Frontend-GNOME/Makefile.in b/src/Frontend-GNOME/Makefile.in
index 995452e..dd51365 100644
--- a/src/Frontend-GNOME/Makefile.in
+++ b/src/Frontend-GNOME/Makefile.in
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994-2013 Free Software Foundation, Inc.
diff --git a/src/Frontend-GNOME/Notebook.cs b/src/Frontend-GNOME/Notebook.cs
index 4028aa2..063c506 100644
--- a/src/Frontend-GNOME/Notebook.cs
+++ b/src/Frontend-GNOME/Notebook.cs
@@ -167,6 +167,7 @@ namespace Smuxi.Frontend.Gnome
             for (int i = 0; i < npages; i++) {
                 ChatView chat = GetChat(i);
                 chat.HasActivity = false;
+                chat.HasEvent = false;
             }
         }
         
diff --git a/src/Frontend-GNOME/Views/ChatTreeView.cs b/src/Frontend-GNOME/Views/ChatTreeView.cs
index fc9c558..19f2f6a 100644
--- a/src/Frontend-GNOME/Views/ChatTreeView.cs
+++ b/src/Frontend-GNOME/Views/ChatTreeView.cs
@@ -1,6 +1,6 @@
 // Smuxi - Smart MUltipleXed Irc
 //
-// Copyright (c) 2013 Mirco Bauer <meebey at meebey.net>
+// Copyright (c) 2013-2014 Mirco Bauer <meebey at meebey.net>
 //
 // Full GPL License: <http://www.gnu.org/licenses/gpl.txt>
 //
@@ -97,12 +97,23 @@ namespace Smuxi.Frontend.Gnome
             column.SetCellDataFunc(iconRenderer, new Gtk.TreeCellDataFunc(RenderChatViewIcon));
             AppendColumn(column);
 
-            var cellRenderer = new Gtk.CellRendererText();
+            var cellRenderer = new Gtk.CellRendererText() {
+                Ellipsize = Pango.EllipsizeMode.End
+            };
             column = new Gtk.TreeViewColumn(null, cellRenderer);
             column.Spacing = 0;
+            column.Expand = true;
             column.Sizing = Gtk.TreeViewColumnSizing.Autosize;
             column.SetCellDataFunc(cellRenderer, new Gtk.TreeCellDataFunc(RenderChatViewName));
             AppendColumn(column);
+
+            cellRenderer = new Gtk.CellRendererText();
+            column = new Gtk.TreeViewColumn(null, cellRenderer);
+            column.Spacing = 0;
+            column.Alignment = 1;
+            column.Sizing = Gtk.TreeViewColumnSizing.Autosize;
+            column.SetCellDataFunc(cellRenderer, new Gtk.TreeCellDataFunc(RenderChatViewActivity));
+            AppendColumn(column);
         }
 
         public virtual void Append(ChatView chatView)
@@ -172,7 +183,9 @@ namespace Smuxi.Frontend.Gnome
             }
 
             Gtk.TreePath visibleStart, visibleEnd;
-            GetVisibleRange(out visibleStart, out visibleEnd);
+            if (!GetVisibleRange(out visibleStart, out visibleEnd)) {
+                return false;
+            }
             var chatIter = FindChatIter(chatView);
             var chatPath = TreeStore.GetPath(chatIter);
             // we ignore 0 on purpose, say if a few pixels of a row are returned
@@ -231,25 +244,17 @@ namespace Smuxi.Frontend.Gnome
             var renderer = (Gtk.CellRendererText) cellr;
 
             Gdk.Color color;
-            string text;
             if (chat.HighlightCount > 1) {
                 color = ThemeSettings.HighlightColor;
-                text = String.Format("{0} ({1})",
-                                     chat.Name,
-                                     chat.HighlightCount.ToString());
             } else if (chat.HighlightCount == 1) {
                 color = ThemeSettings.HighlightColor;
-                text = chat.Name;
             } else if (chat.HasActivity) {
                 color = ThemeSettings.ActivityColor;
-                text = chat.Name;
             } else if (chat.HasEvent) {
                 color = ThemeSettings.EventColor;
-                text = chat.Name;
             } else {
                 // no activity
                 color = ThemeSettings.NoActivityColor;
-                text = chat.Name;
             }
 
             var textColor = TextColorTools.GetBestTextColor(
@@ -261,6 +266,40 @@ namespace Smuxi.Frontend.Gnome
             renderer.Markup = String.Format(
                 "<span foreground=\"{0}\">{1}</span>",
                 GLib.Markup.EscapeText(textColor.ToString()),
+                GLib.Markup.EscapeText(chat.Name)
+            );
+        }
+
+        protected virtual void RenderChatViewActivity(Gtk.TreeViewColumn column,
+                                                      Gtk.CellRenderer cellr,
+                                                      Gtk.TreeModel model, Gtk.TreeIter iter)
+        {
+            var chat = (ChatView) model.GetValue(iter, 0);
+            var renderer = (Gtk.CellRendererText) cellr;
+
+            Gdk.Color color;
+            string text = null;
+            if (chat.HighlightCount > 1) {
+                color = ThemeSettings.HighlightColor;
+                text = chat.HighlightCount.ToString();
+            } else {
+                // no highlight counter
+                renderer.Markup = String.Empty;
+                return;
+            }
+            if (text == null) {
+                return;
+            }
+
+            var textColor = TextColorTools.GetBestTextColor(
+                ColorConverter.GetTextColor(color),
+                ColorConverter.GetTextColor(
+                Gtk.Rc.GetStyle(this).Base(Gtk.StateType.Normal)
+                ), TextColorContrast.High
+            );
+            renderer.Markup = String.Format(
+                "<span foreground=\"{0}\">({1})</span>",
+                GLib.Markup.EscapeText(textColor.ToString()),
                 GLib.Markup.EscapeText(text)
             );
         }
diff --git a/src/Frontend-GNOME/Views/Chats/ChatView.cs b/src/Frontend-GNOME/Views/Chats/ChatView.cs
index 06619b8..7c82217 100644
--- a/src/Frontend-GNOME/Views/Chats/ChatView.cs
+++ b/src/Frontend-GNOME/Views/Chats/ChatView.cs
@@ -60,7 +60,6 @@ namespace Smuxi.Frontend.Gnome
         bool                         UseLowBandwidthMode { get; set; }
         public Gtk.Image TabImage { get; protected set; }
         bool                         IsAutoScrolling { get; set; }
-        Gtk.ImageMenuItem  CloseItem { get; set; }
 
         public event EventHandler<EventArgs> StatusChanged;
 
@@ -318,11 +317,7 @@ namespace Smuxi.Frontend.Gnome
 
             // popup menu
             _TabMenu = new Gtk.Menu();
-
-            CloseItem = new Gtk.ImageMenuItem(Gtk.Stock.Close, null);
-            CloseItem.Activated += new EventHandler(OnTabMenuCloseActivated);
-            _TabMenu.Append(CloseItem);
-            _TabMenu.ShowAll();
+            _TabMenu.Shown += OnTabMenuShown;
 
             //FocusChild = _OutputTextView;
             //CanFocus = false;
@@ -382,7 +377,7 @@ namespace Smuxi.Frontend.Gnome
                 // HACK: this shouldn't be needed but GTK# keeps GC handles
                 // these callbacks for some reason and thus leaks :(
                 _OutputMessageTextView.Dispose();
-                CloseItem.Activated -= OnTabMenuCloseActivated;
+                _TabMenu.Shown -= OnTabMenuShown;
                 _OutputScrolledWindow.Vadjustment.ValueChanged -= OnVadjustmentValueChanged;
             }
         }
@@ -663,7 +658,20 @@ namespace Smuxi.Frontend.Gnome
                 Frontend.ShowException(ex);
             }
         }
-        
+
+        protected virtual void OnTabMenuShown(object sender, EventArgs e)
+        {
+            Trace.Call(sender, e);
+
+            foreach (var child in _TabMenu.Children) {
+                _TabMenu.Remove(child);
+            }
+            var closeItem = new Gtk.ImageMenuItem(Gtk.Stock.Close, null);
+            closeItem.Activated += OnTabMenuCloseActivated;
+            _TabMenu.Append(closeItem);
+            _TabMenu.ShowAll();
+        }
+
         protected virtual void OnTabMenuCloseActivated(object sender, EventArgs e)
         {
             Trace.Call(sender, e);
diff --git a/src/Frontend-GNOME/Views/Chats/GroupChatView.cs b/src/Frontend-GNOME/Views/Chats/GroupChatView.cs
index 8b2c4a3..a011c1c 100644
--- a/src/Frontend-GNOME/Views/Chats/GroupChatView.cs
+++ b/src/Frontend-GNOME/Views/Chats/GroupChatView.cs
@@ -570,7 +570,7 @@ namespace Smuxi.Frontend.Gnome
                 // TODO: do we need to optimize this? it's called very often...
                 Gdk.Color bgColor = _PersonTreeView.Style.Base(Gtk.StateType.Normal);
                 var builder = new MessageBuilder();
-                builder.NickColors = true;
+                builder.Settings.NickColors = true;
                 builder.AppendNick(person);
                 renderer.Markup = PangoTools.ToMarkup(builder.ToMessage(),
                                                       bgColor);
diff --git a/src/Frontend-GNOME/Views/Chats/ProtocolChatView.cs b/src/Frontend-GNOME/Views/Chats/ProtocolChatView.cs
index 0a59dfa..c6861f0 100644
--- a/src/Frontend-GNOME/Views/Chats/ProtocolChatView.cs
+++ b/src/Frontend-GNOME/Views/Chats/ProtocolChatView.cs
@@ -1,7 +1,7 @@
 /*
  * Smuxi - Smart MUltipleXed Irc
  *
- * Copyright (c) 2005-2006, 2009-2013 Mirco Bauer <meebey at meebey.net>
+ * Copyright (c) 2005-2006, 2009-2014 Mirco Bauer <meebey at meebey.net>
  *
  * Full GPL License: <http://www.gnu.org/licenses/gpl.txt>
  *
@@ -131,8 +131,6 @@ namespace Smuxi.Frontend.Gnome
             ReconnectItem = new Gtk.ImageMenuItem(_("Reconnect"));
             ReconnectItem.Image = new Gtk.Image(Gtk.Stock.Refresh, Gtk.IconSize.Menu);
             ReconnectItem.Activated += new EventHandler(OnTabMenuReconnectActivated);
-            TabMenu.Prepend(ReconnectItem);
-            TabMenu.ShowAll();
 
             ShowAll();
         }
@@ -370,6 +368,16 @@ namespace Smuxi.Frontend.Gnome
             });
         }
 
+        protected override void OnTabMenuShown(object sender, EventArgs e)
+        {
+            Trace.Call(sender, e);
+
+            base.OnTabMenuShown(sender, e);
+
+            TabMenu.Prepend(ReconnectItem);
+            TabMenu.ShowAll();
+        }
+
         protected virtual void OnTabMenuReconnectActivated(object sender, EventArgs e)
         {
             Trace.Call(sender, e);
diff --git a/src/Frontend-GNOME/Views/MenuWidget.cs b/src/Frontend-GNOME/Views/MenuWidget.cs
index 16accbf..e40bf66 100644
--- a/src/Frontend-GNOME/Views/MenuWidget.cs
+++ b/src/Frontend-GNOME/Views/MenuWidget.cs
@@ -1,6 +1,6 @@
 // Smuxi - Smart MUltipleXed Irc
 //
-// Copyright (c) 2012 Mirco Bauer <meebey at meebey.net>
+// Copyright (c) 2012-2014 Mirco Bauer <meebey at meebey.net>
 //
 // Full GPL License: <http://www.gnu.org/licenses/gpl.txt>
 //
@@ -219,6 +219,15 @@ namespace Smuxi.Frontend.Gnome
                 // do connect as background task as it might take a while
                 ThreadPool.QueueUserWorkItem(delegate {
                     try {
+                        if (Frontend.EngineVersion < new Version(0, 8, 11)) {
+                            // HACK: Smuxi < 0.8.11 used auto serialization for
+                            // ServerModel and thus breaks on unknown fields,
+                            // which we skip by setting this to null, see:
+                            // ServerModel.GetObjectData()
+                            server.ServerID = null;
+                            server.Nickname = null;
+                            server.Realname = null;
+                        }
                         Frontend.Session.Connect(server, Frontend.FrontendManager);
                     } catch (Exception ex) {
                         Frontend.ShowException(Parent, ex);
diff --git a/src/Frontend-GNOME/Views/MessageTextView.cs b/src/Frontend-GNOME/Views/MessageTextView.cs
index 7c48961..c246cb8 100644
--- a/src/Frontend-GNOME/Views/MessageTextView.cs
+++ b/src/Frontend-GNOME/Views/MessageTextView.cs
@@ -38,6 +38,7 @@ namespace Smuxi.Frontend.Gnome
 #endif        
         private static readonly Gdk.Cursor _NormalCursor = new Gdk.Cursor(Gdk.CursorType.Xterm);
         private static readonly Gdk.Cursor _LinkCursor = new Gdk.Cursor(Gdk.CursorType.Hand2);
+        static readonly Regex NickRegex = new Regex("^(<([^ ]+)> )");
         static bool IsGtk2_17 { get; set; }
         private Gtk.TextTagTable _MessageTextTagTable;
         private MessageModel _LastMessage;
@@ -334,13 +335,12 @@ namespace Smuxi.Frontend.Gnome
                     var urlPart = (UrlMessagePartModel) msgPart;
                     var linkText = urlPart.Text ?? urlPart.Url;
 
-                    var url = urlPart.Url;
                     Uri uri;
                     try {
-                        uri = new Uri(url);
+                        uri = new Uri(urlPart.Url);
                     } catch (UriFormatException ex) {
 #if LOG4NET
-                        _Logger.Error("AddMessage(): Invalid URL: " + url, ex);
+                        _Logger.Error("AddMessage(): Invalid URL: " + urlPart.Url, ex);
 #endif
                         buffer.Insert(ref iter, linkText);
                         continue;
@@ -789,7 +789,7 @@ namespace Smuxi.Frontend.Gnome
                          tagName.StartsWith("bg_color:"))) {
                         continue;
                     }
-                    if (tag.IndentSet || tag is LinkTag) {
+                    if (tag.IndentSet || tag is LinkTag || tag is PersonTag) {
                         buffer.RemoveTag(tag, start_iter, end_iter);
                         _MessageTextTagTable.Remove(tag);
                         tag.Dispose();
@@ -814,7 +814,7 @@ namespace Smuxi.Frontend.Gnome
             // HACK: try to obtain the nickname from the message
             // TODO: extend MessageModel with Origin property
             var msgText = msg.ToString();
-            var nickMatch = Regex.Match(msgText, "^(<([^ ]+)> )");
+            var nickMatch = NickRegex.Match(msgText);
             if (nickMatch.Success) {
                 // HACK: the nick can be bold
                 if (msg.MessageParts.Count >= 3) {
@@ -844,9 +844,8 @@ namespace Smuxi.Frontend.Gnome
                 }
                 return GetPangoWidth(nickMatch.Groups[1].Value, false);
             } else {
-                var eventMatch = Regex.Match(msgText, "^(-!- )");
-                if (eventMatch.Success && eventMatch.Groups.Count >= 2) {
-                    return GetPangoWidth(eventMatch.Groups[1].Value, false);
+                if (msgText.StartsWith("-!- ")) {
+                    return GetPangoWidth("-!- ", false);
                 }
             }
             return 0;
diff --git a/src/Frontend-GNOME/Views/ServerWidget.cs b/src/Frontend-GNOME/Views/ServerWidget.cs
index a71b9e6..8a5a166 100644
--- a/src/Frontend-GNOME/Views/ServerWidget.cs
+++ b/src/Frontend-GNOME/Views/ServerWidget.cs
@@ -1,6 +1,6 @@
 // Smuxi - Smart MUltipleXed Irc
 // 
-// Copyright (c) 2010-2013 Mirco Bauer <meebey at meebey.net>
+// Copyright (c) 2010-2014 Mirco Bauer <meebey at meebey.net>
 // 
 // Full GPL License: <http://www.gnu.org/licenses/gpl.txt>
 // 
@@ -72,6 +72,18 @@ namespace Smuxi.Frontend.Gnome
             }
         }
 
+        public Gtk.Entry NicknameEntry {
+            get {
+                return f_NicknameEntry;
+            }
+        }
+
+        public Gtk.Entry RealnameEntry {
+            get {
+                return f_RealnameEntry;
+            }
+        }
+
         public Gtk.CheckButton OnStartupConnectCheckButton {
             get {
                 return f_OnStartupConnectCheckButton;
@@ -94,7 +106,29 @@ namespace Smuxi.Frontend.Gnome
             }
         }
 
-        public bool ShowPassword {
+        public bool ShowNickname {
+            set {
+                // Smuxi < 0.11 does not support server specific nickname
+                if (Frontend.EngineVersion < new Version(0, 11)) {
+                    value = false;
+                }
+                f_NicknameLabel.Visible = value;
+                f_NicknameEntry.Visible = value;
+            }
+        }
+
+        public bool ShowRealname {
+            set {
+                // Smuxi < 0.11 does not support server specific realname
+                if (Frontend.EngineVersion < new Version(0, 11)) {
+                    value = false;
+                }
+                f_RealnameLabel.Visible = value;
+                f_RealnameEntry.Visible = value;
+            }
+        }
+
+       public bool ShowPassword {
             set {
                 f_PasswordLabel.Visible = value;
                 f_PasswordEntry.Visible = value;
@@ -135,10 +169,24 @@ namespace Smuxi.Frontend.Gnome
             ServerID = server.ServerID;
             f_HostnameEntry.Text = server.Hostname;
             f_NetworkComboBoxEntry.Entry.Text = server.Network;
+            if (String.IsNullOrEmpty(server.Nickname)) {
+                var defaultNicknames = (string[]) Frontend.UserConfig["Connection/Nicknames"];
+                f_NicknameEntry.Text = String.Join(" ", defaultNicknames);
+            } else {
+                f_NicknameEntry.Text = server.Nickname;
+            }
+            if (String.IsNullOrEmpty(server.Realname)) {
+                var defaultRealname = (string) Frontend.UserConfig["Connection/Realname"];
+                f_RealnameEntry.Text = defaultRealname;
+            } else {
+                f_RealnameEntry.Text = server.Realname;
+            }
             f_UsernameEntry.Text = server.Username;
             // HACK: Twitter username is part of the PKEY, not allowed to change
             if (server.Protocol == "Twitter") {
                 f_UsernameEntry.Sensitive = false;
+            } else {
+                f_UsernameEntry.Sensitive = true;
             }
             f_PasswordEntry.Text = server.Password;
             f_UseEncryptionCheckButton.Active = server.UseEncryption;
@@ -173,6 +221,8 @@ namespace Smuxi.Frontend.Gnome
                 server.Hostname = server.Username;
             }
             server.Password = f_PasswordEntry.Text;
+            server.Nickname = f_NicknameEntry.Text.Trim();
+            server.Realname = f_RealnameEntry.Text.Trim();
             server.UseEncryption = f_UseEncryptionCheckButton.Active;
             server.ValidateServerCertificate =
                 f_ValidateServerCertificateCheckButton.Active;
@@ -247,6 +297,11 @@ namespace Smuxi.Frontend.Gnome
             f_UseEncryptionCheckButton.Clicked += delegate {
                 CheckUseEncryptionCheckButton();
             };
+
+            var defaultNicknames = (string[]) Frontend.UserConfig["Connection/Nicknames"];
+            f_NicknameEntry.Text = String.Join(" ", defaultNicknames);
+            var defaultRealname = (string) Frontend.UserConfig["Connection/Realname"];
+            f_RealnameEntry.Text = defaultRealname;
         }
 
         protected virtual void CheckIgnoreOnConnectCommandsCheckButton()
@@ -301,6 +356,8 @@ namespace Smuxi.Frontend.Gnome
                 case "IRC":
                     ShowHostname = true;
                     ShowNetwork = true;
+                    ShowNickname = true;
+                    ShowRealname = true;
                     ShowPassword = true;
                     SupportUseEncryption = true;
 
@@ -310,9 +367,21 @@ namespace Smuxi.Frontend.Gnome
                     f_PortSpinButton.Value = 6667;
                     f_PortSpinButton.Sensitive = true;
                     break;
+                case "Facebook":
+                    ShowHostname = false;
+                    ShowNetwork = false;
+                    ShowNickname = false;
+                    ShowRealname = false;
+                    ShowPassword = true;
+                    SupportUseEncryption = true;
+                    f_HostnameEntry.Text = "chat.facebook.com";
+                    f_PortSpinButton.Value = 5222;
+                    break;
                 case "XMPP":
                     ShowHostname = true;
                     ShowNetwork = false;
+                    ShowNickname = false;
+                    ShowRealname = false;
                     ShowPassword = true;
                     SupportUseEncryption = true;
                 
@@ -329,6 +398,8 @@ namespace Smuxi.Frontend.Gnome
                 case "MSNP":
                     ShowHostname = false;
                     ShowNetwork = false;
+                    ShowNickname = false;
+                    ShowRealname = false;
                     ShowPassword = true;
                     SupportUseEncryption = false;
 
@@ -343,6 +414,8 @@ namespace Smuxi.Frontend.Gnome
                 case "Twitter":
                     ShowHostname = false;
                     ShowNetwork = false;
+                    ShowNickname = false;
+                    ShowRealname = false;
                     ShowPassword = false;
                     SupportUseEncryption = true;
                     // engine always uses https
@@ -358,6 +431,8 @@ namespace Smuxi.Frontend.Gnome
                 case "Campfire":
                     ShowHostname = true;
                     ShowNetwork = false;
+                    ShowNickname = false;
+                    ShowRealname = false;
                     ShowPassword = true;
                     SupportUseEncryption = true;
                     // engine always uses https
@@ -374,6 +449,8 @@ namespace Smuxi.Frontend.Gnome
                 case "JabbR":
                     ShowHostname = true;
                     ShowNetwork = false;
+                    ShowNickname = false;
+                    ShowRealname = false;
                     ShowPassword = true;
                     SupportUseEncryption = true;
 
@@ -390,6 +467,8 @@ namespace Smuxi.Frontend.Gnome
                 default:
                     ShowHostname = true;
                     ShowNetwork = true;
+                    ShowNickname = true;
+                    ShowRealname = true;
                     ShowPassword = true;
                     SupportUseEncryption = true;
 
diff --git a/src/Frontend-GNOME/gtk-gui/Smuxi.Frontend.Gnome.ServerWidget.cs b/src/Frontend-GNOME/gtk-gui/Smuxi.Frontend.Gnome.ServerWidget.cs
index 887016f..af5cdd5 100644
--- a/src/Frontend-GNOME/gtk-gui/Smuxi.Frontend.Gnome.ServerWidget.cs
+++ b/src/Frontend-GNOME/gtk-gui/Smuxi.Frontend.Gnome.ServerWidget.cs
@@ -9,8 +9,12 @@ namespace Smuxi.Frontend.Gnome
 		private global::Gtk.Label f_HostnameLabel;
 		private global::Gtk.ComboBoxEntry f_NetworkComboBoxEntry;
 		private global::Gtk.Label f_NetworkLabel;
+		private global::Gtk.Entry f_NicknameEntry;
+		private global::Gtk.Label f_NicknameLabel;
 		private global::Gtk.Label f_PasswordLabel;
 		private global::Gtk.ComboBox f_ProtocolComboBox;
+		private global::Gtk.Entry f_RealnameEntry;
+		private global::Gtk.Label f_RealnameLabel;
 		private global::Gtk.Entry f_UsernameEntry;
 		private global::Gtk.HBox hbox10;
 		private global::Gtk.Entry f_HostnameEntry;
@@ -31,7 +35,7 @@ namespace Smuxi.Frontend.Gnome
 		private global::Gtk.CheckButton f_IgnoreOnConnectCommandsCheckButton;
 		private global::Gtk.ScrolledWindow scrolledwindow1;
 		private global::Gtk.TextView f_OnConnectCommandsTextView;
-        
+
 		protected virtual void Build ()
 		{
 			global::Stetic.Gui.Initialize (this);
@@ -43,7 +47,7 @@ namespace Smuxi.Frontend.Gnome
 			this.vbox16.Name = "vbox16";
 			this.vbox16.Spacing = 5;
 			// Container child vbox16.Gtk.Box+BoxChild
-			this.table2 = new global::Gtk.Table (((uint)(5)), ((uint)(2)), false);
+			this.table2 = new global::Gtk.Table (((uint)(7)), ((uint)(2)), false);
 			this.table2.Name = "table2";
 			this.table2.RowSpacing = ((uint)(5));
 			this.table2.ColumnSpacing = ((uint)(5));
@@ -81,33 +85,83 @@ namespace Smuxi.Frontend.Gnome
 			w3.XOptions = ((global::Gtk.AttachOptions)(4));
 			w3.YOptions = ((global::Gtk.AttachOptions)(4));
 			// Container child table2.Gtk.Table+TableChild
+			this.f_NicknameEntry = new global::Gtk.Entry ();
+			this.f_NicknameEntry.CanFocus = true;
+			this.f_NicknameEntry.Name = "f_NicknameEntry";
+			this.f_NicknameEntry.IsEditable = true;
+			this.f_NicknameEntry.InvisibleChar = '●';
+			this.table2.Add (this.f_NicknameEntry);
+			global::Gtk.Table.TableChild w4 = ((global::Gtk.Table.TableChild)(this.table2 [this.f_NicknameEntry]));
+			w4.TopAttach = ((uint)(3));
+			w4.BottomAttach = ((uint)(4));
+			w4.LeftAttach = ((uint)(1));
+			w4.RightAttach = ((uint)(2));
+			w4.XOptions = ((global::Gtk.AttachOptions)(4));
+			w4.YOptions = ((global::Gtk.AttachOptions)(4));
+			// Container child table2.Gtk.Table+TableChild
+			this.f_NicknameLabel = new global::Gtk.Label ();
+			this.f_NicknameLabel.Name = "f_NicknameLabel";
+			this.f_NicknameLabel.Xalign = 0F;
+			this.f_NicknameLabel.LabelProp = global::Mono.Unix.Catalog.GetString ("Nickname:");
+			this.table2.Add (this.f_NicknameLabel);
+			global::Gtk.Table.TableChild w5 = ((global::Gtk.Table.TableChild)(this.table2 [this.f_NicknameLabel]));
+			w5.TopAttach = ((uint)(3));
+			w5.BottomAttach = ((uint)(4));
+			w5.XOptions = ((global::Gtk.AttachOptions)(4));
+			w5.YOptions = ((global::Gtk.AttachOptions)(4));
+			// Container child table2.Gtk.Table+TableChild
 			this.f_PasswordLabel = new global::Gtk.Label ();
 			this.f_PasswordLabel.Name = "f_PasswordLabel";
 			this.f_PasswordLabel.Xalign = 0F;
 			this.f_PasswordLabel.LabelProp = global::Mono.Unix.Catalog.GetString ("_Password:");
 			this.f_PasswordLabel.UseUnderline = true;
 			this.table2.Add (this.f_PasswordLabel);
-			global::Gtk.Table.TableChild w4 = ((global::Gtk.Table.TableChild)(this.table2 [this.f_PasswordLabel]));
-			w4.TopAttach = ((uint)(4));
-			w4.BottomAttach = ((uint)(5));
+			global::Gtk.Table.TableChild w6 = ((global::Gtk.Table.TableChild)(this.table2 [this.f_PasswordLabel]));
+			w6.TopAttach = ((uint)(6));
+			w6.BottomAttach = ((uint)(7));
 			// Container child table2.Gtk.Table+TableChild
 			this.f_ProtocolComboBox = new global::Gtk.ComboBox ();
 			this.f_ProtocolComboBox.Name = "f_ProtocolComboBox";
 			this.table2.Add (this.f_ProtocolComboBox);
-			global::Gtk.Table.TableChild w5 = ((global::Gtk.Table.TableChild)(this.table2 [this.f_ProtocolComboBox]));
-			w5.LeftAttach = ((uint)(1));
-			w5.RightAttach = ((uint)(2));
+			global::Gtk.Table.TableChild w7 = ((global::Gtk.Table.TableChild)(this.table2 [this.f_ProtocolComboBox]));
+			w7.LeftAttach = ((uint)(1));
+			w7.RightAttach = ((uint)(2));
+			// Container child table2.Gtk.Table+TableChild
+			this.f_RealnameEntry = new global::Gtk.Entry ();
+			this.f_RealnameEntry.CanFocus = true;
+			this.f_RealnameEntry.Name = "f_RealnameEntry";
+			this.f_RealnameEntry.IsEditable = true;
+			this.f_RealnameEntry.InvisibleChar = '●';
+			this.table2.Add (this.f_RealnameEntry);
+			global::Gtk.Table.TableChild w8 = ((global::Gtk.Table.TableChild)(this.table2 [this.f_RealnameEntry]));
+			w8.TopAttach = ((uint)(4));
+			w8.BottomAttach = ((uint)(5));
+			w8.LeftAttach = ((uint)(1));
+			w8.RightAttach = ((uint)(2));
+			w8.XOptions = ((global::Gtk.AttachOptions)(4));
+			w8.YOptions = ((global::Gtk.AttachOptions)(4));
+			// Container child table2.Gtk.Table+TableChild
+			this.f_RealnameLabel = new global::Gtk.Label ();
+			this.f_RealnameLabel.Name = "f_RealnameLabel";
+			this.f_RealnameLabel.Xalign = 0F;
+			this.f_RealnameLabel.LabelProp = global::Mono.Unix.Catalog.GetString ("Realname:");
+			this.table2.Add (this.f_RealnameLabel);
+			global::Gtk.Table.TableChild w9 = ((global::Gtk.Table.TableChild)(this.table2 [this.f_RealnameLabel]));
+			w9.TopAttach = ((uint)(4));
+			w9.BottomAttach = ((uint)(5));
+			w9.XOptions = ((global::Gtk.AttachOptions)(4));
+			w9.YOptions = ((global::Gtk.AttachOptions)(4));
 			// Container child table2.Gtk.Table+TableChild
 			this.f_UsernameEntry = new global::Gtk.Entry ();
 			this.f_UsernameEntry.Name = "f_UsernameEntry";
 			this.f_UsernameEntry.IsEditable = true;
 			this.f_UsernameEntry.InvisibleChar = '●';
 			this.table2.Add (this.f_UsernameEntry);
-			global::Gtk.Table.TableChild w6 = ((global::Gtk.Table.TableChild)(this.table2 [this.f_UsernameEntry]));
-			w6.TopAttach = ((uint)(3));
-			w6.BottomAttach = ((uint)(4));
-			w6.LeftAttach = ((uint)(1));
-			w6.RightAttach = ((uint)(2));
+			global::Gtk.Table.TableChild w10 = ((global::Gtk.Table.TableChild)(this.table2 [this.f_UsernameEntry]));
+			w10.TopAttach = ((uint)(5));
+			w10.BottomAttach = ((uint)(6));
+			w10.LeftAttach = ((uint)(1));
+			w10.RightAttach = ((uint)(2));
 			// Container child table2.Gtk.Table+TableChild
 			this.hbox10 = new global::Gtk.HBox ();
 			this.hbox10.Name = "hbox10";
@@ -117,8 +171,8 @@ namespace Smuxi.Frontend.Gnome
 			this.f_HostnameEntry.IsEditable = true;
 			this.f_HostnameEntry.InvisibleChar = '●';
 			this.hbox10.Add (this.f_HostnameEntry);
-			global::Gtk.Box.BoxChild w7 = ((global::Gtk.Box.BoxChild)(this.hbox10 [this.f_HostnameEntry]));
-			w7.Position = 0;
+			global::Gtk.Box.BoxChild w11 = ((global::Gtk.Box.BoxChild)(this.hbox10 [this.f_HostnameEntry]));
+			w11.Position = 0;
 			// Container child hbox10.Gtk.Box+BoxChild
 			this.hbox11 = new global::Gtk.HBox ();
 			this.hbox11.Name = "hbox11";
@@ -129,8 +183,8 @@ namespace Smuxi.Frontend.Gnome
 			this.f_PortLabel.LabelProp = global::Mono.Unix.Catalog.GetString ("_Port:");
 			this.f_PortLabel.UseUnderline = true;
 			this.hbox11.Add (this.f_PortLabel);
-			global::Gtk.Box.BoxChild w8 = ((global::Gtk.Box.BoxChild)(this.hbox11 [this.f_PortLabel]));
-			w8.Position = 0;
+			global::Gtk.Box.BoxChild w12 = ((global::Gtk.Box.BoxChild)(this.hbox11 [this.f_PortLabel]));
+			w12.Position = 0;
 			// Container child hbox11.Gtk.Box+BoxChild
 			this.f_PortSpinButton = new global::Gtk.SpinButton (0, 65535, 1);
 			this.f_PortSpinButton.Name = "f_PortSpinButton";
@@ -139,17 +193,17 @@ namespace Smuxi.Frontend.Gnome
 			this.f_PortSpinButton.ClimbRate = 1;
 			this.f_PortSpinButton.Numeric = true;
 			this.hbox11.Add (this.f_PortSpinButton);
-			global::Gtk.Box.BoxChild w9 = ((global::Gtk.Box.BoxChild)(this.hbox11 [this.f_PortSpinButton]));
-			w9.Position = 1;
+			global::Gtk.Box.BoxChild w13 = ((global::Gtk.Box.BoxChild)(this.hbox11 [this.f_PortSpinButton]));
+			w13.Position = 1;
 			this.hbox10.Add (this.hbox11);
-			global::Gtk.Box.BoxChild w10 = ((global::Gtk.Box.BoxChild)(this.hbox10 [this.hbox11]));
-			w10.Position = 1;
+			global::Gtk.Box.BoxChild w14 = ((global::Gtk.Box.BoxChild)(this.hbox10 [this.hbox11]));
+			w14.Position = 1;
 			this.table2.Add (this.hbox10);
-			global::Gtk.Table.TableChild w11 = ((global::Gtk.Table.TableChild)(this.table2 [this.hbox10]));
-			w11.TopAttach = ((uint)(1));
-			w11.BottomAttach = ((uint)(2));
-			w11.LeftAttach = ((uint)(1));
-			w11.RightAttach = ((uint)(2));
+			global::Gtk.Table.TableChild w15 = ((global::Gtk.Table.TableChild)(this.table2 [this.hbox10]));
+			w15.TopAttach = ((uint)(1));
+			w15.BottomAttach = ((uint)(2));
+			w15.LeftAttach = ((uint)(1));
+			w15.RightAttach = ((uint)(2));
 			// Container child table2.Gtk.Table+TableChild
 			this.hbox2 = new global::Gtk.HBox ();
 			this.hbox2.Name = "hbox2";
@@ -161,8 +215,8 @@ namespace Smuxi.Frontend.Gnome
 			this.f_PasswordEntry.Visibility = false;
 			this.f_PasswordEntry.InvisibleChar = '●';
 			this.hbox2.Add (this.f_PasswordEntry);
-			global::Gtk.Box.BoxChild w12 = ((global::Gtk.Box.BoxChild)(this.hbox2 [this.f_PasswordEntry]));
-			w12.Position = 0;
+			global::Gtk.Box.BoxChild w16 = ((global::Gtk.Box.BoxChild)(this.hbox2 [this.f_PasswordEntry]));
+			w16.Position = 0;
 			// Container child hbox2.Gtk.Box+BoxChild
 			this.f_ShowPasswordCheckButton = new global::Gtk.CheckButton ();
 			this.f_ShowPasswordCheckButton.CanFocus = true;
@@ -171,16 +225,16 @@ namespace Smuxi.Frontend.Gnome
 			this.f_ShowPasswordCheckButton.DrawIndicator = true;
 			this.f_ShowPasswordCheckButton.UseUnderline = true;
 			this.hbox2.Add (this.f_ShowPasswordCheckButton);
-			global::Gtk.Box.BoxChild w13 = ((global::Gtk.Box.BoxChild)(this.hbox2 [this.f_ShowPasswordCheckButton]));
-			w13.Position = 1;
+			global::Gtk.Box.BoxChild w17 = ((global::Gtk.Box.BoxChild)(this.hbox2 [this.f_ShowPasswordCheckButton]));
+			w17.Position = 1;
 			this.table2.Add (this.hbox2);
-			global::Gtk.Table.TableChild w14 = ((global::Gtk.Table.TableChild)(this.table2 [this.hbox2]));
-			w14.TopAttach = ((uint)(4));
-			w14.BottomAttach = ((uint)(5));
-			w14.LeftAttach = ((uint)(1));
-			w14.RightAttach = ((uint)(2));
-			w14.XOptions = ((global::Gtk.AttachOptions)(4));
-			w14.YOptions = ((global::Gtk.AttachOptions)(4));
+			global::Gtk.Table.TableChild w18 = ((global::Gtk.Table.TableChild)(this.table2 [this.hbox2]));
+			w18.TopAttach = ((uint)(6));
+			w18.BottomAttach = ((uint)(7));
+			w18.LeftAttach = ((uint)(1));
+			w18.RightAttach = ((uint)(2));
+			w18.XOptions = ((global::Gtk.AttachOptions)(4));
+			w18.YOptions = ((global::Gtk.AttachOptions)(4));
 			// Container child table2.Gtk.Table+TableChild
 			this.label21 = new global::Gtk.Label ();
 			this.label21.Name = "label21";
@@ -188,9 +242,9 @@ namespace Smuxi.Frontend.Gnome
 			this.label21.LabelProp = global::Mono.Unix.Catalog.GetString ("_Username:");
 			this.label21.UseUnderline = true;
 			this.table2.Add (this.label21);
-			global::Gtk.Table.TableChild w15 = ((global::Gtk.Table.TableChild)(this.table2 [this.label21]));
-			w15.TopAttach = ((uint)(3));
-			w15.BottomAttach = ((uint)(4));
+			global::Gtk.Table.TableChild w19 = ((global::Gtk.Table.TableChild)(this.table2 [this.label21]));
+			w19.TopAttach = ((uint)(5));
+			w19.BottomAttach = ((uint)(6));
 			// Container child table2.Gtk.Table+TableChild
 			this.label5 = new global::Gtk.Label ();
 			this.label5.Name = "label5";
@@ -199,9 +253,9 @@ namespace Smuxi.Frontend.Gnome
 			this.label5.UseUnderline = true;
 			this.table2.Add (this.label5);
 			this.vbox16.Add (this.table2);
-			global::Gtk.Box.BoxChild w17 = ((global::Gtk.Box.BoxChild)(this.vbox16 [this.table2]));
-			w17.Position = 0;
-			w17.Expand = false;
+			global::Gtk.Box.BoxChild w21 = ((global::Gtk.Box.BoxChild)(this.vbox16 [this.table2]));
+			w21.Position = 0;
+			w21.Expand = false;
 			// Container child vbox16.Gtk.Box+BoxChild
 			this.f_OnStartupConnectCheckButton = new global::Gtk.CheckButton ();
 			this.f_OnStartupConnectCheckButton.CanFocus = true;
@@ -211,10 +265,10 @@ namespace Smuxi.Frontend.Gnome
 			this.f_OnStartupConnectCheckButton.UseUnderline = true;
 			this.f_OnStartupConnectCheckButton.Xalign = 0F;
 			this.vbox16.Add (this.f_OnStartupConnectCheckButton);
-			global::Gtk.Box.BoxChild w18 = ((global::Gtk.Box.BoxChild)(this.vbox16 [this.f_OnStartupConnectCheckButton]));
-			w18.Position = 1;
-			w18.Expand = false;
-			w18.Fill = false;
+			global::Gtk.Box.BoxChild w22 = ((global::Gtk.Box.BoxChild)(this.vbox16 [this.f_OnStartupConnectCheckButton]));
+			w22.Position = 1;
+			w22.Expand = false;
+			w22.Fill = false;
 			// Container child vbox16.Gtk.Box+BoxChild
 			this.f_UseEncryptionCheckButton = new global::Gtk.CheckButton ();
 			this.f_UseEncryptionCheckButton.CanFocus = true;
@@ -223,10 +277,10 @@ namespace Smuxi.Frontend.Gnome
 			this.f_UseEncryptionCheckButton.DrawIndicator = true;
 			this.f_UseEncryptionCheckButton.UseUnderline = true;
 			this.vbox16.Add (this.f_UseEncryptionCheckButton);
-			global::Gtk.Box.BoxChild w19 = ((global::Gtk.Box.BoxChild)(this.vbox16 [this.f_UseEncryptionCheckButton]));
-			w19.Position = 2;
-			w19.Expand = false;
-			w19.Fill = false;
+			global::Gtk.Box.BoxChild w23 = ((global::Gtk.Box.BoxChild)(this.vbox16 [this.f_UseEncryptionCheckButton]));
+			w23.Position = 2;
+			w23.Expand = false;
+			w23.Fill = false;
 			// Container child vbox16.Gtk.Box+BoxChild
 			this.f_ValidateServerCertificateCheckButton = new global::Gtk.CheckButton ();
 			this.f_ValidateServerCertificateCheckButton.CanFocus = true;
@@ -235,10 +289,10 @@ namespace Smuxi.Frontend.Gnome
 			this.f_ValidateServerCertificateCheckButton.DrawIndicator = true;
 			this.f_ValidateServerCertificateCheckButton.UseUnderline = true;
 			this.vbox16.Add (this.f_ValidateServerCertificateCheckButton);
-			global::Gtk.Box.BoxChild w20 = ((global::Gtk.Box.BoxChild)(this.vbox16 [this.f_ValidateServerCertificateCheckButton]));
-			w20.Position = 3;
-			w20.Expand = false;
-			w20.Fill = false;
+			global::Gtk.Box.BoxChild w24 = ((global::Gtk.Box.BoxChild)(this.vbox16 [this.f_ValidateServerCertificateCheckButton]));
+			w24.Position = 3;
+			w24.Expand = false;
+			w24.Fill = false;
 			// Container child vbox16.Gtk.Box+BoxChild
 			this.vbox2 = new global::Gtk.VBox ();
 			this.vbox2.Name = "vbox2";
@@ -254,10 +308,10 @@ namespace Smuxi.Frontend.Gnome
 			this.label37.LabelProp = global::Mono.Unix.Catalog.GetString ("_On Connect Commands:");
 			this.label37.UseUnderline = true;
 			this.hbox3.Add (this.label37);
-			global::Gtk.Box.BoxChild w21 = ((global::Gtk.Box.BoxChild)(this.hbox3 [this.label37]));
-			w21.Position = 0;
-			w21.Expand = false;
-			w21.Fill = false;
+			global::Gtk.Box.BoxChild w25 = ((global::Gtk.Box.BoxChild)(this.hbox3 [this.label37]));
+			w25.Position = 0;
+			w25.Expand = false;
+			w25.Fill = false;
 			// Container child hbox3.Gtk.Box+BoxChild
 			this.f_IgnoreOnConnectCommandsCheckButton = new global::Gtk.CheckButton ();
 			this.f_IgnoreOnConnectCommandsCheckButton.CanFocus = true;
@@ -266,13 +320,13 @@ namespace Smuxi.Frontend.Gnome
 			this.f_IgnoreOnConnectCommandsCheckButton.DrawIndicator = true;
 			this.f_IgnoreOnConnectCommandsCheckButton.UseUnderline = true;
 			this.hbox3.Add (this.f_IgnoreOnConnectCommandsCheckButton);
-			global::Gtk.Box.BoxChild w22 = ((global::Gtk.Box.BoxChild)(this.hbox3 [this.f_IgnoreOnConnectCommandsCheckButton]));
-			w22.Position = 1;
+			global::Gtk.Box.BoxChild w26 = ((global::Gtk.Box.BoxChild)(this.hbox3 [this.f_IgnoreOnConnectCommandsCheckButton]));
+			w26.Position = 1;
 			this.vbox2.Add (this.hbox3);
-			global::Gtk.Box.BoxChild w23 = ((global::Gtk.Box.BoxChild)(this.vbox2 [this.hbox3]));
-			w23.Position = 0;
-			w23.Expand = false;
-			w23.Fill = false;
+			global::Gtk.Box.BoxChild w27 = ((global::Gtk.Box.BoxChild)(this.vbox2 [this.hbox3]));
+			w27.Position = 0;
+			w27.Expand = false;
+			w27.Fill = false;
 			// Container child vbox2.Gtk.Box+BoxChild
 			this.scrolledwindow1 = new global::Gtk.ScrolledWindow ();
 			this.scrolledwindow1.WidthRequest = 350;
@@ -287,18 +341,20 @@ namespace Smuxi.Frontend.Gnome
 			this.f_OnConnectCommandsTextView.WrapMode = ((global::Gtk.WrapMode)(2));
 			this.scrolledwindow1.Add (this.f_OnConnectCommandsTextView);
 			this.vbox2.Add (this.scrolledwindow1);
-			global::Gtk.Box.BoxChild w25 = ((global::Gtk.Box.BoxChild)(this.vbox2 [this.scrolledwindow1]));
-			w25.Position = 1;
+			global::Gtk.Box.BoxChild w29 = ((global::Gtk.Box.BoxChild)(this.vbox2 [this.scrolledwindow1]));
+			w29.Position = 1;
 			this.vbox16.Add (this.vbox2);
-			global::Gtk.Box.BoxChild w26 = ((global::Gtk.Box.BoxChild)(this.vbox16 [this.vbox2]));
-			w26.Position = 4;
+			global::Gtk.Box.BoxChild w30 = ((global::Gtk.Box.BoxChild)(this.vbox16 [this.vbox2]));
+			w30.Position = 4;
 			this.Add (this.vbox16);
 			if ((this.Child != null)) {
 				this.Child.ShowAll ();
 			}
 			this.f_HostnameLabel.MnemonicWidget = this.f_HostnameEntry;
 			this.f_NetworkLabel.MnemonicWidget = this.f_NetworkComboBoxEntry;
+			this.f_NicknameLabel.MnemonicWidget = this.f_NicknameEntry;
 			this.f_PasswordLabel.MnemonicWidget = this.f_PasswordEntry;
+			this.f_RealnameLabel.MnemonicWidget = this.f_RealnameEntry;
 			this.f_PortLabel.MnemonicWidget = this.f_PortSpinButton;
 			this.label21.MnemonicWidget = this.f_UsernameEntry;
 			this.label5.MnemonicWidget = this.f_ProtocolComboBox;
diff --git a/src/Frontend-GNOME/gtk-gui/gui.stetic b/src/Frontend-GNOME/gtk-gui/gui.stetic
index ecb1367..837beed 100644
--- a/src/Frontend-GNOME/gtk-gui/gui.stetic
+++ b/src/Frontend-GNOME/gtk-gui/gui.stetic
@@ -3772,7 +3772,7 @@ Click "Forward" to begin.</property>
       </widget>
     </child>
   </widget>
-  <widget class="Gtk.Bin" id="Smuxi.Frontend.Gnome.ServerWidget" design-size="380 374">
+  <widget class="Gtk.Bin" id="Smuxi.Frontend.Gnome.ServerWidget" design-size="380 466">
     <property name="MemberName" />
     <property name="Visible">False</property>
     <child>
@@ -3782,7 +3782,7 @@ Click "Forward" to begin.</property>
         <child>
           <widget class="Gtk.Table" id="table2">
             <property name="MemberName" />
-            <property name="NRows">5</property>
+            <property name="NRows">7</property>
             <property name="NColumns">2</property>
             <property name="RowSpacing">5</property>
             <property name="ColumnSpacing">5</property>
@@ -3851,6 +3851,50 @@ Click "Forward" to begin.</property>
               </packing>
             </child>
             <child>
+              <widget class="Gtk.Entry" id="f_NicknameEntry">
+                <property name="MemberName" />
+                <property name="CanFocus">True</property>
+                <property name="IsEditable">True</property>
+                <property name="InvisibleChar">●</property>
+              </widget>
+              <packing>
+                <property name="TopAttach">3</property>
+                <property name="BottomAttach">4</property>
+                <property name="LeftAttach">1</property>
+                <property name="RightAttach">2</property>
+                <property name="AutoSize">True</property>
+                <property name="XOptions">Fill</property>
+                <property name="YOptions">Fill</property>
+                <property name="XExpand">False</property>
+                <property name="XFill">True</property>
+                <property name="XShrink">False</property>
+                <property name="YExpand">False</property>
+                <property name="YFill">True</property>
+                <property name="YShrink">False</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="Gtk.Label" id="f_NicknameLabel">
+                <property name="MemberName" />
+                <property name="Xalign">0</property>
+                <property name="LabelProp" translatable="yes">Nickname:</property>
+                <property name="MnemonicWidget">f_NicknameEntry</property>
+              </widget>
+              <packing>
+                <property name="TopAttach">3</property>
+                <property name="BottomAttach">4</property>
+                <property name="AutoSize">True</property>
+                <property name="XOptions">Fill</property>
+                <property name="YOptions">Fill</property>
+                <property name="XExpand">False</property>
+                <property name="XFill">True</property>
+                <property name="XShrink">False</property>
+                <property name="YExpand">False</property>
+                <property name="YFill">True</property>
+                <property name="YShrink">False</property>
+              </packing>
+            </child>
+            <child>
               <widget class="Gtk.Label" id="f_PasswordLabel">
                 <property name="MemberName" />
                 <property name="Xalign">0</property>
@@ -3859,8 +3903,8 @@ Click "Forward" to begin.</property>
                 <property name="MnemonicWidget">f_PasswordEntry</property>
               </widget>
               <packing>
-                <property name="TopAttach">4</property>
-                <property name="BottomAttach">5</property>
+                <property name="TopAttach">6</property>
+                <property name="BottomAttach">7</property>
                 <property name="AutoSize">False</property>
                 <property name="XExpand">True</property>
                 <property name="XFill">True</property>
@@ -3889,14 +3933,58 @@ Click "Forward" to begin.</property>
               </packing>
             </child>
             <child>
+              <widget class="Gtk.Entry" id="f_RealnameEntry">
+                <property name="MemberName" />
+                <property name="CanFocus">True</property>
+                <property name="IsEditable">True</property>
+                <property name="InvisibleChar">●</property>
+              </widget>
+              <packing>
+                <property name="TopAttach">4</property>
+                <property name="BottomAttach">5</property>
+                <property name="LeftAttach">1</property>
+                <property name="RightAttach">2</property>
+                <property name="AutoSize">True</property>
+                <property name="XOptions">Fill</property>
+                <property name="YOptions">Fill</property>
+                <property name="XExpand">False</property>
+                <property name="XFill">True</property>
+                <property name="XShrink">False</property>
+                <property name="YExpand">False</property>
+                <property name="YFill">True</property>
+                <property name="YShrink">False</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="Gtk.Label" id="f_RealnameLabel">
+                <property name="MemberName" />
+                <property name="Xalign">0</property>
+                <property name="LabelProp" translatable="yes">Realname:</property>
+                <property name="MnemonicWidget">f_RealnameEntry</property>
+              </widget>
+              <packing>
+                <property name="TopAttach">4</property>
+                <property name="BottomAttach">5</property>
+                <property name="AutoSize">True</property>
+                <property name="XOptions">Fill</property>
+                <property name="YOptions">Fill</property>
+                <property name="XExpand">False</property>
+                <property name="XFill">True</property>
+                <property name="XShrink">False</property>
+                <property name="YExpand">False</property>
+                <property name="YFill">True</property>
+                <property name="YShrink">False</property>
+              </packing>
+            </child>
+            <child>
               <widget class="Gtk.Entry" id="f_UsernameEntry">
                 <property name="MemberName" />
                 <property name="IsEditable">True</property>
                 <property name="InvisibleChar">●</property>
               </widget>
               <packing>
-                <property name="TopAttach">3</property>
-                <property name="BottomAttach">4</property>
+                <property name="TopAttach">5</property>
+                <property name="BottomAttach">6</property>
                 <property name="LeftAttach">1</property>
                 <property name="RightAttach">2</property>
                 <property name="AutoSize">False</property>
@@ -4006,8 +4094,8 @@ Click "Forward" to begin.</property>
                 </child>
               </widget>
               <packing>
-                <property name="TopAttach">4</property>
-                <property name="BottomAttach">5</property>
+                <property name="TopAttach">6</property>
+                <property name="BottomAttach">7</property>
                 <property name="LeftAttach">1</property>
                 <property name="RightAttach">2</property>
                 <property name="AutoSize">True</property>
@@ -4030,8 +4118,8 @@ Click "Forward" to begin.</property>
                 <property name="MnemonicWidget">f_UsernameEntry</property>
               </widget>
               <packing>
-                <property name="TopAttach">3</property>
-                <property name="BottomAttach">4</property>
+                <property name="TopAttach">5</property>
+                <property name="BottomAttach">6</property>
                 <property name="AutoSize">False</property>
                 <property name="XExpand">True</property>
                 <property name="XFill">True</property>
diff --git a/src/Frontend-STFL/Makefile.in b/src/Frontend-STFL/Makefile.in
index 2473587..969f0be 100644
--- a/src/Frontend-STFL/Makefile.in
+++ b/src/Frontend-STFL/Makefile.in
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994-2013 Free Software Foundation, Inc.
diff --git a/src/Frontend-STFL/STFL/Makefile.in b/src/Frontend-STFL/STFL/Makefile.in
index 33d3959..c5ef767 100644
--- a/src/Frontend-STFL/STFL/Makefile.in
+++ b/src/Frontend-STFL/STFL/Makefile.in
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994-2013 Free Software Foundation, Inc.
diff --git a/src/Frontend-SWF/Makefile.in b/src/Frontend-SWF/Makefile.in
index 1c8f2ee..ca6bb41 100644
--- a/src/Frontend-SWF/Makefile.in
+++ b/src/Frontend-SWF/Makefile.in
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994-2013 Free Software Foundation, Inc.
diff --git a/src/Frontend-Test/Makefile.in b/src/Frontend-Test/Makefile.in
index 65375dc..3ad6aae 100644
--- a/src/Frontend-Test/Makefile.in
+++ b/src/Frontend-Test/Makefile.in
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994-2013 Free Software Foundation, Inc.
diff --git a/src/Frontend/CommandManager.cs b/src/Frontend/CommandManager.cs
index 397db86..1aa946b 100644
--- a/src/Frontend/CommandManager.cs
+++ b/src/Frontend/CommandManager.cs
@@ -1,6 +1,6 @@
 // Smuxi - Smart MUltipleXed Irc
 // 
-// Copyright (c) 2010, 2012-2013 Mirco Bauer <meebey at meebey.net>
+// Copyright (c) 2010, 2012-2014 Mirco Bauer <meebey at meebey.net>
 // 
 // Full GPL License: <http://www.gnu.org/licenses/gpl.txt>
 // 
@@ -19,6 +19,7 @@
 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 
 using System;
+using System.IO;
 using System.Linq;
 using System.Reflection;
 using System.Collections.Generic;
@@ -52,6 +53,8 @@ namespace Smuxi.Frontend
         TaskQueue       f_TaskQueue;
         TimeSpan        f_LastCommandTimeSpan;
 
+        public Version EngineVersion { get; set; }
+
         public TimeSpan LastCommandTimeSpan {
             get {
                 return f_LastCommandTimeSpan;
@@ -113,7 +116,18 @@ namespace Smuxi.Frontend
             }
 
             f_TaskQueue.Queue(delegate {
-                DoExecute(cmd);
+                try {
+                    DoExecute(cmd);
+                } catch (Exception ex) {
+#if LOG4NET
+                    f_Logger.Error("Execute(): DoExecute() threw exception!", ex);
+#endif
+                    var msg = new MessageBuilder().
+                        AppendErrorText("Command '{0}' failed. Reason: {1}",
+                                        cmd.Command, ex.Message).
+                        ToMessage();
+                    AddMessageToFrontend(cmd, msg);
+                }
             });
         }
 
@@ -132,6 +146,12 @@ namespace Smuxi.Frontend
                         CommandEcho(cmd);
                         handled = true;
                         break;
+                    case "benchmark_message_builder":
+                        CommandBenchmarkMessageBuilder(cmd);
+                        handled = true;
+                        break;
+                    case "exception":
+                        throw new Exception("You asked for it.");
                 }
             }
             if (handled) {
@@ -145,7 +165,7 @@ namespace Smuxi.Frontend
             handled = f_Session.Command(cmd);
             IProtocolManager pm = null;
             if (!handled) {
-                if (cmd.Chat is SessionChatModel) {
+                if (cmd.Chat is SessionChatModel && cmd.FrontendManager != null) {
                     pm = cmd.FrontendManager.CurrentProtocolManager;
                 } else {
                     pm = cmd.Chat.ProtocolManager;
@@ -163,6 +183,7 @@ namespace Smuxi.Frontend
                 var hooks = new HookRunner("frontend", "command-manager",
                                            "command-" + filteredCmd);
                 hooks.EnvironmentVariables.Add("FRONTEND_VERSION", FrontendVersion);
+                hooks.Environments.Add(new CommandHookEnvironment(cmd));
                 hooks.Environments.Add(new ChatHookEnvironment(cmd.Chat));
                 if (pm != null) {
                     hooks.Environments.Add(new ProtocolManagerHookEnvironment(pm));
@@ -230,12 +251,12 @@ namespace Smuxi.Frontend
                         output = String.Format("{0}{1}",
                                                cmd.CommandCharacter, output);
                     }
-                    Execute(new CommandModel(cmd.FrontendManager,
-                                             cmd.Chat,
-                                             cmd.CommandCharacter, output));
+                    DoExecute(new CommandModel(cmd.FrontendManager,
+                                               cmd.Chat,
+                                               cmd.CommandCharacter, output));
                 } else {
                     var msg = new MessageBuilder().AppendText(output).ToMessage();
-                    f_Session.AddMessageToFrontend(cmd, msg);
+                    AddMessageToFrontend(cmd, msg);
                 }
             };
 
@@ -243,8 +264,8 @@ namespace Smuxi.Frontend
             string args = null;
             if (Environment.OSVersion.Platform == PlatformID.Unix) {
                 file = "sh";
-                args = String.Format("-c '{0}'",
-                                     parameter.Replace("'", @"\'"));
+                args = String.Format("-c \"{0}\"",
+                                     parameter.Replace("\"", @"\"""));
             } else {
                 file = parameters[1];
                 if (parameters.Length > 1) {
@@ -282,7 +303,7 @@ namespace Smuxi.Frontend
                         AppendErrorText("Executing '{0}' failed with: {1}",
                                         command, ex.Message).
                         ToMessage();
-                    f_Session.AddMessageToFrontend(cmd, msg);
+                    AddMessageToFrontend(cmd, msg);
                 }
             }
         }
@@ -295,7 +316,7 @@ namespace Smuxi.Frontend
                 AppendEventPrefix().
                     AppendText(cmd.Parameter).
                     ToMessage();
-            f_Session.AddMessageToFrontend(cmd, msg);
+            AddMessageToFrontend(cmd, msg);
         }
 
         public void CommandGenerateMessages(CommandModel cmd, IChatView chat)
@@ -336,13 +357,115 @@ namespace Smuxi.Frontend
             chat.AddMessage(builder.ToMessage());
         }
 
+        public void CommandBenchmarkMessageBuilder(CommandModel cmd)
+        {
+            Trace.Call(cmd);
+
+            var count = 1000;
+            var showHelp = false;
+            var appendMessage = false;
+            var appendText = false;
+            var appendEvent = false;
+            var appendFormat = false;
+            var toMessage = false;
+            try {
+                var opts = new NDesk.Options.OptionSet() {
+                    { "c|count=", v => count = Int32.Parse(v) },
+                    { "m|append-message", v => appendMessage = true },
+                    { "t|append-text", v => appendText = true },
+                    { "e|append-event", v => appendEvent = true },
+                    { "f|append-format", v => appendFormat = true },
+                    { "T|to-message", v => toMessage = true },
+                };
+                opts.Add("h|?|help", x => {
+                    showHelp = true;
+                    var writer = new StringWriter();
+                    opts.WriteOptionDescriptions(writer);
+                    AddMessageToFrontend(
+                        cmd,
+                        CreateMessageBuilder().
+                            AppendHeader("{0} usage", cmd.Command).
+                            AppendText("\n").
+                            AppendText("Parameters:\n").
+                            AppendText(writer.ToString()).
+                            ToMessage()
+                    );
+                    return;
+                });
+                opts.Parse(cmd.Parameter.Split(' '));
+                if (showHelp) {
+                    return;
+                }
+            } catch (Exception ex) {
+                AddMessageToFrontend(
+                    cmd,
+                    CreateMessageBuilder().
+                        AppendErrorText("Invalid parameter: {0}", ex.Message).
+                        ToMessage()
+                );
+                return;
+            }
+
+            DateTime start, stop;
+            start = DateTime.UtcNow;
+            MessageBuilder builder;
+            for (var i = 0; i < count; i++) {
+                builder = new MessageBuilder();
+                if (appendMessage) {
+                    builder.AppendMessage("This is message with a link to https://www.smuxi.org/.");
+                }
+                if (appendText) {
+                    builder.AppendText("This is message with just text.");
+                }
+                if (appendEvent) {
+                    builder.AppendEventPrefix();
+                }
+                if (appendFormat) {
+                    builder.AppendFormat("{0} [{1}] has joined {2}",
+                                         "meebey3",
+                                         "~smuxi at 31-18-115-252-dynip.superkabel.de",
+                                         "#smuxi-devel");
+                }
+                if (toMessage) {
+                    var msg = builder.ToMessage();
+                }
+            }
+            stop = DateTime.UtcNow;
+
+            builder = new MessageBuilder();
+            builder.AppendText("MessageBuilder().");
+            if (appendMessage) {
+                builder.AppendText("AppendMessage().");
+            }
+            if (appendText) {
+                builder.AppendText("AppendText().");
+            }
+            if (appendEvent) {
+                builder.AppendText("AppendEventPrefix().");
+            }
+            if (appendFormat) {
+                builder.AppendText("AppendFormat().");
+            }
+            if (toMessage) {
+                builder.AppendText("ToMessage()");
+            }
+            builder.AppendText(
+                " count: {1} took: {2:0} ms avg: {3:0.00} ms",
+                cmd.Data,
+                count,
+                (stop - start).TotalMilliseconds,
+                (stop - start).TotalMilliseconds / count
+            );
+            AddMessageToFrontend(cmd, builder.ToMessage());
+        }
+
         private void Unknown(CommandModel cmd)
         {
             var msg = CreateMessageBuilder().
                 AppendEventPrefix().
                 AppendText(_("Unknown Command: {0}"), cmd.Command).
                 ToMessage();
-            f_Session.AddMessageToFrontend(cmd, msg);
+            AddMessageToFrontend(cmd, msg);
         }
 
         void NotEnoughParameters(CommandModel cmd)
@@ -351,7 +474,7 @@ namespace Smuxi.Frontend
                 AppendEventPrefix().
                 AppendText(_("Not enough parameters for {0} command"), cmd.Command).
                 ToMessage();
-            f_Session.AddMessageToFrontend(cmd, msg);
+            AddMessageToFrontend(cmd, msg);
         }
 
         MessageBuilder CreateMessageBuilder()
@@ -359,6 +482,22 @@ namespace Smuxi.Frontend
             return new MessageBuilder();
         }
 
+        void AddMessageToFrontend(CommandModel cmd, MessageModel msg)
+        {
+            if (cmd == null) {
+                throw new ArgumentNullException("cmd");
+            }
+            if (msg == null) {
+                throw new ArgumentNullException("msg");
+            }
+
+            if (EngineVersion != null && EngineVersion >= new Version(0, 10)) {
+                f_Session.AddMessageToFrontend(cmd, msg);
+            } else {
+                f_Session.AddMessageToChat(cmd.Chat, msg);
+            }
+        }
+
         protected virtual void OnTaskQueueExceptionEvent(object sender, TaskQueueExceptionEventArgs e)
         {
             Trace.Call(sender, e);
diff --git a/src/Frontend/Makefile.in b/src/Frontend/Makefile.in
index c1eda15..955ed74 100644
--- a/src/Frontend/Makefile.in
+++ b/src/Frontend/Makefile.in
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994-2013 Free Software Foundation, Inc.
diff --git a/src/Frontend/SshTunnelManager.cs b/src/Frontend/SshTunnelManager.cs
index e082def..3f76dd2 100644
--- a/src/Frontend/SshTunnelManager.cs
+++ b/src/Frontend/SshTunnelManager.cs
@@ -25,6 +25,7 @@ using System.IO;
 using System.Net;
 using System.Net.Sockets;
 using System.Text.RegularExpressions;
+using System.Reflection;
 using SysDiag = System.Diagnostics;
 using Smuxi.Common;
 
@@ -133,8 +134,10 @@ namespace Smuxi.Frontend
 
             if (String.IsNullOrEmpty(f_Program)) {
                 // use plink by default if it's there
-                if (File.Exists("plink.exe")) {
-                    f_Program = "plink.exe";
+                var location = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
+                var plinkPath = Path.Combine(location, "plink.exe");
+                if (File.Exists(plinkPath)) {
+                    f_Program = plinkPath;
                 } else {
                     // TODO: find ssh
                     f_Program = "/usr/bin/ssh";
diff --git a/src/Makefile.in b/src/Makefile.in
index fc7b7aa..84f9fce 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994-2013 Free Software Foundation, Inc.
diff --git a/src/Server/Makefile.in b/src/Server/Makefile.in
index b19d708..7e01318 100644
--- a/src/Server/Makefile.in
+++ b/src/Server/Makefile.in
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.14 from Makefile.am.
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994-2013 Free Software Foundation, Inc.
diff --git a/src/smuxi-win32.nsis.in b/src/smuxi-win32.nsis.in
index ca5e46f..81af9e8 100644
--- a/src/smuxi-win32.nsis.in
+++ b/src/smuxi-win32.nsis.in
@@ -534,6 +534,8 @@ Section "Main" SEC01
   File "../bin-win32/smuxi-engine-xmpp.dll"
   File "../bin-win32/smuxi-engine.dll"
   File "../bin-win32/smuxi-frontend-gnome-irc.dll"
+  File "../bin-win32/smuxi-frontend-gnome-twitter.dll"
+  File "../bin-win32/smuxi-frontend-gnome-xmpp.dll"
   File "../bin-win32/smuxi-frontend-gnome.exe"
   File "../bin-win32/smuxi-frontend-gnome.exe.config"
   File "../bin-win32/smuxi-frontend.dll"
@@ -603,6 +605,8 @@ Section Uninstall
   Delete "$INSTDIR\smuxi-frontend-gnome.exe"
   Delete "$INSTDIR\smuxi-frontend-gnome.log"
   Delete "$INSTDIR\smuxi-frontend-gnome-irc.dll"
+  Delete "$INSTDIR\smuxi-frontend-gnome-twitter.dll"
+  Delete "$INSTDIR\smuxi-frontend-gnome-xmpp.dll"
   Delete "$INSTDIR\smuxi-engine.dll"
   Delete "$INSTDIR\smuxi-engine-campfire.dll"
   Delete "$INSTDIR\smuxi-engine-irc.dll"

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-cli-apps/packages/smuxi.git



More information about the Pkg-cli-apps-commits mailing list