Merged silc_1_0_branch to trunk.
authorPekka Riikonen <priikone@silcnet.org>
Thu, 16 Oct 2003 10:35:36 +0000 (10:35 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Thu, 16 Oct 2003 10:35:36 +0000 (10:35 +0000)
123 files changed:
CHANGES
INSTALL
Makefile.am.pre
README
TODO
TODO-1.0
apps/irssi/docs/help/in/cmode.in
apps/irssi/docs/help/in/join.in
apps/irssi/docs/help/in/key.in
apps/irssi/docs/help/in/smsg.in
apps/irssi/docs/help/in/whois.in
apps/irssi/docs/signals.txt
apps/irssi/src/fe-common/silc/module-formats.c
apps/irssi/src/fe-common/silc/module-formats.h
apps/irssi/src/silc/core/Makefile.am
apps/irssi/src/silc/core/client_ops.c
apps/irssi/src/silc/core/client_ops.h
apps/irssi/src/silc/core/clientutil.c
apps/irssi/src/silc/core/silc-channels.c
apps/irssi/src/silc/core/silc-core.c
apps/irssi/src/silc/core/silc-lag.c [new file with mode: 0644]
apps/irssi/src/silc/core/silc-nicklist.c
apps/irssi/src/silc/core/silc-servers.c
apps/silcd/command.c
apps/silcd/command_reply.c
apps/silcd/command_reply.h
apps/silcd/idlist.c
apps/silcd/idlist.h
apps/silcd/packet_receive.c
apps/silcd/packet_send.c
apps/silcd/packet_send.h
apps/silcd/protocol.c
apps/silcd/protocol.h
apps/silcd/server.c
apps/silcd/server.h
apps/silcd/server_backup.c
apps/silcd/server_backup.h
apps/silcd/server_internal.h
apps/silcd/server_query.c
apps/silcd/server_util.c
apps/silcd/server_util.h
apps/silcd/serverconfig.c
apps/silcd/serverconfig.h
apps/silcd/silcd.c
configure.in.pre
doc/Makefile.am.pre
doc/draft-riikonen-presence-attrs-02.nroff [new file with mode: 0644]
doc/draft-riikonen-silc-commands-05.nroff [new file with mode: 0644]
doc/draft-riikonen-silc-commands-06.nroff [new file with mode: 0644]
doc/draft-riikonen-silc-flags-payloads-03.nroff [new file with mode: 0644]
doc/draft-riikonen-silc-ke-auth-07.nroff [new file with mode: 0644]
doc/draft-riikonen-silc-pp-07.nroff [new file with mode: 0644]
doc/draft-riikonen-silc-pp-08.nroff [new file with mode: 0644]
doc/draft-riikonen-silc-spec-07.nroff
doc/draft-riikonen-silc-spec-08.nroff [new file with mode: 0644]
doc/example_silcd.conf.in
includes/silcincludes.h.in
includes/silcwin32.h
lib/doc/LIBINDEX
lib/doc/command_reply_args.html
lib/doc/notifyargs.html
lib/doc/silcstatus_args.html [new file with mode: 0644]
lib/silcclient/DIRECTORY
lib/silcclient/client.c
lib/silcclient/client_channel.c
lib/silcclient/client_internal.h
lib/silcclient/client_notify.c
lib/silcclient/client_prvmsg.c
lib/silcclient/client_resume.c
lib/silcclient/command.c
lib/silcclient/command_reply.c
lib/silcclient/command_reply.h
lib/silcclient/idlist.c
lib/silcclient/protocol.c
lib/silcclient/silcclient.h
lib/silccore/Makefile.am
lib/silccore/silcargument.c
lib/silccore/silcattrs.c
lib/silccore/silcauth.c
lib/silccore/silcauth.h
lib/silccore/silcchannel.c
lib/silccore/silccommand.h
lib/silccore/silcid.h
lib/silccore/silcidcache.c
lib/silccore/silcmessage.c
lib/silccore/silcmode.h
lib/silccore/silcpacket.c
lib/silccore/silcstatus.c [new file with mode: 0644]
lib/silccore/silcstatus.h
lib/silccrypt/Makefile.am
lib/silccrypt/pkcs1.c
lib/silccrypt/rsa.c
lib/silccrypt/silcpkcs.c
lib/silccrypt/silcpkcs.h
lib/silccrypt/tests/test_aes.c
lib/silcutil/silcapputil.c
lib/silcutil/silcbuffer.h
lib/silcutil/silcbuffmt.h
lib/silcutil/silcconfig.c
lib/silcutil/silcconfig.h
lib/silcutil/silcdlist.h
lib/silcutil/silchashtable.c
lib/silcutil/silchashtable.h
lib/silcutil/silclist.h
lib/silcutil/silclog.h
lib/silcutil/silcschedule.c
lib/silcutil/silcsockconn.c
lib/silcutil/silcstrutil.c
lib/silcutil/silcstrutil.h
lib/silcutil/silcutil.c
lib/silcutil/silcutil.h
lib/silcutil/win32/silcwin32util.c
prepare
win32/Makefile.am
win32/README [new file with mode: 0644]
win32/all.dsp [new file with mode: 0644]
win32/clean_dist.pl [new file with mode: 0644]
win32/libsilc/libsilc.def
win32/libsilc/libsilc.dsp
win32/libsilc_static/libsilc_static.dsp [new file with mode: 0644]
win32/libsilcclient/libsilcclient.def
win32/libsilcclient_static/libsilcclient_static.dsp [new file with mode: 0644]
win32/silc.dsw

diff --git a/CHANGES b/CHANGES
index abc7a30abeeec793f0bb5548c472c102b8396886..06d20905e194009a33056066241d5d893c8b2e60 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,229 @@
+Tue Oct 14 18:24:53 EEST 2003  Pekka Riikonen <priikone@silcnet.org>
+
+       * Save old channel keys in list to allow more rapid change
+         of channel keys if server for some reason does that.  This
+         avoids loosing so many channel messages due to not having
+         key to decrypt.  Affected file lib/silcclient/silcclient.h,
+         idlist.c and client_channel.c.
+
+Mon Oct 13 21:37:47 EEST 2003  Pekka Riikonen <priikone@silcnet.org>
+
+       * Continued backup router tests and fixes.  Affected files
+         silcd/server_backup, server_util.c, server.c.  See TODO.
+
+Sun Oct 12 19:58:18 EEST 2003  Pekka Riikonen <priikone@silcnet.org>
+
+       * Fixed SERVER_SIGNOFF handling in servers.  The client
+         was removed from wrong list thus not removing the client
+         at all.  Affected file silcd/packet_receive.c.
+
+       * Do not execute rekey protocol for disabled connections as
+         it would never go through.  Affected file silcd/server.c.
+
+       * Added timeout for rekey protocol to catch if the protocol
+         never executes successfully.  Affected files silcd/server.c
+         and protocol.h.
+
+Sat Oct 11 15:39:22 EEST 2003  Pekka Riikonen <priikone@silcnet.org>
+
+       * Abandon packet processing for disconnected sockets.  Check
+         this always after calling packet processing callback.
+         Affected file lib/silccore/silcpacket.c.
+
+       * Fixed double registration disconnection code in server.
+         Closed wrong connection.  Affected file silcd/packet_receive.c.
+
+Fri Oct 10 16:27:12 EEST 2003  Pekka Riikonen <priikone@silcnet.org>
+
+       * On normal server reconnect to primary during resuming 4
+         times, then give up.  Affected file silcd/server_backup.c.
+
+       * If during reconnecting to routers we notice we have router
+         connection but no primary router set, the server is in desync.
+         Reconnect to primary to restore network.  Affected file
+         silcd/server.c.
+
+       * Assure that only one protocol is exeucting at the same time.
+         Added checks for all protocols.  Affected files are
+         silcd/server.c and server_backup.c.
+
+Thu Oct  9 20:24:09 EEST 2003  Pekka Riikonen <priikone@silcnet.org>
+
+       * Check that a string is not already part on invite/ban
+         string when processing it.  Affected file silcd/server_util.c.
+
+Thu Oct  9 12:06:40 CEST 2003  Pekka Riikonen <priikone@silcnet.org>
+
+       * Fixed the CUMODE_CHANGE for founder mode changes to comply
+         with 1.2 version of the protocol.  Affected file is
+         silcd/packet_receive.c.
+
+Wed Oct  8 19:41:15 EEST 2003  Pekka Riikonen <priikone@silcnet.org>
+
+       * ERR_BAD_PASSWORD now returns the Channel ID of the channel
+         where the passphrase was given.  Affected file is
+         silcd/command.c.
+
+Wed Oct  8 09:32:12 CEST 2003  Pekka Riikonen <priikone@silcnet.org>
+
+       * INVITE and BAN notifys are now delivered from routers to
+         servers (but not clients) on the channel.  Updated specs and
+         code.  Affected files silcd/packet_[send|receive].[ch],
+         command.c, server.c and server_util.c.
+
+       * Implemented INVITE and BAN announcing.  Affected files are
+         silcd/server.[ch], server_util.c.
+
+       * Implemented SilcStatus error type argument returning in
+         command reply error in server.  Affected file silcd/command.c.
+
+       * Implemented SilcStatus argument returning in comand reply
+         in client library.  The command_reply client operation now
+         returns error specific arguments as well.  Affected files
+         are lib/silcclient/command_reply.[ch], client_resume.c,
+         lib/silccore/silcstatus.[ch].
+
+Sun Oct  5 20:22:08 EEST 2003  Pekka Riikonen <priikone@silcnet.org>
+
+       * Backup router protocol version 1.2 implemented.  Testing still
+         required.  Affected files in silcd/server_backup.[ch], server.c,
+         packet_receive.c and server_internal.h.
+
+Sun Oct  5 12:36:37 EEST 2003  Pekka Riikonen <priikone@silcnet.org>
+
+       * silc_client_send_[channel|private]_message now return TRUE
+         or FALSE.  Affected file lib/silcclien/client_channel.c and
+         client_prvmsg.c.
+
+Thu Oct  2 17:03:09 EEST 2003  Pekka Riikonen <priikone@silcnet.org>
+
+       * Check for explicit nickname in INVITE and BAN processing
+         during join as well (and don't expect only wildcards in
+         invite/ban strings).  Affected file silcd/command.c.
+
+       * Fixed the INVITE and BAN by public key.  The public key saved
+         is the PK payload (as specified) not the raw data.  Affected
+         file silcd/server_util.c.
+
+Wed Oct  1 20:29:06 EEST 2003  Pekka Riikonen <priikone@silcnet.org>
+
+       * UTF-8 text message support for actions and notices in SILC
+         Client.  Affected file irssi/src/silc/core/client_ops.c.
+
+       * silc_get_username and silc_get_real_name now returns sensible
+         data on Win32.  Patch by Toni Willberg.  Affected file is
+         lib/silcutil/win32/silcwin32util.c.
+
+Sun Aug 24 23:35:19 CEST 2003  Jochen Eisinger <c0ffee@penguin-breeder.org>
+
+       * Provide a signal handler to send MIME encoded messages and emit
+         a signal when a MIME encoded message is received. Also document
+         the signals for usage with the perl interface.
+
+         A sample perl script will be supplied at a later point.
+
+         Affected files are irssi/docs/signals.txt,
+         irssi/src/silc/core/client_ops.[ch],
+         irssi/src/silc/core/silc-{channels,servers}.c
+
+Sun Aug 24 12:58:30 CEST 2003  Jochen Eisinger <c0ffee@penguin-breeder.org>
+
+       * Use SILC_COMMAND_PING to estimate the round-trip time to the
+         server. Use this time to display a lag and disconnect when it
+         exceeds a specified limit.
+
+         Affected files are irssi/src/silc/core/silc-{lag,core}.c.
+
+Mon Aug 11 17:14:17 EEST 2003  Pekka Riikonen <priikone@silcnet.org>
+
+       * Remove the channel auth list in normal server if router
+         encofrces its list during connecting.  Send notify to channel
+         to remove the mode to remove the list.  Affected files are
+         silcd/server_util.c and silcd/packet_receive.c.
+
+Wed Aug  6 14:52:04 EEST 2003  Pekka Riikonen <priikone@silcnet.org>
+
+       * Added support for channel public keys.  Updated protocol specs
+         and implemented it.  Affected files are
+         silcd/command.c, command_reply.c, lib/silcclient/command.c,
+         lib/silcclient/command_reply.c.
+
+Wed Jul 23 12:17:01 EEST 2003  Pekka Riikonen <priikone@silcnet.org>
+
+       * Ignore SIGXFSZ and SIGXCPU signals in server.  They can
+         terminate the process on Linux.  Affected file silcd/silcd.c.
+
+Mon Jun  2 19:13:27 EEST 2003  Pekka Riikonen <priikone@silcnet.org>
+
+       * Check for NULL buffer in silc_buffer_clear.  Affected file
+         is lib/silcutil/silcbuffer.h.
+
+       * Simplified the backup router protocol by removing the _GLOBAL
+         types.  Updated protocol specs and the code.  Affected files
+         are silcd/server_backup.[ch].
+
+Thu Apr 24 19:50:25 EEST 2003  Pekka Riikonen <priikone@silcnet.org>
+
+       * Deny '@' and '!' from nicknames since they are reserved
+         by the SILC_COMMAND_INVITE and SILC_COMMAND_BAN commands.
+         Updated protocol specs and the code.
+
+         Affected files are silcd/server_util.[ch].
+
+Wed Apr  9 18:51:59 EEST 2003  Pekka Riikonen <priikone@silcnet.org>
+
+       * Fixed stack overflow in Irssi SILC client.  Affected
+         file irssi/src/silc/core/client_ops.c.
+
+       * Check that Host is set in ServerConnection and RouterConnection
+         in silcd.conf.  Affected file silcd/serverconfig.c.
+
+       * Fixed crash in server with protocol completion callbacks,
+         namely rekey and backup resuming protocols.  Affected files
+         are silcd/server_backup.c and silcd/server.c.
+
+       * Fixed rekey protocol to not restart if it is started already.
+         Affected files are lib/silcclient/client.c and
+         silcd/server.c.c
+
+Mon Mar 17 18:35:24 EET 2003  Pekka Riikonen <priikone@silcnet.org>
+
+       * Rewrote SilcList, affected file lib/silcutil/silc*list.h.
+
+       * Fixed EOF handling in SILC Config, affected file
+         lib/silcutil/silcconfig.c.
+
+       * Fixed buffer overflows in lib/silcutil/silcstrutil.c.
+
+       * Fixed RESOLVING flag handling in JOIN notify and other
+         notifys to handle the resolvings correctly in client library.
+         Affected file lib/silcclient/client_notify.c.
+
+       * Do not send full INVITE and BAN lists in INVITE and BAN
+         notifys, only the changed information.  Affected file
+         silcd/command.c.
+
+       * Fixed INVITE notify sending in INVITE command, send it
+         only when needed.  Affected file silcd/command.c.
+
+       * Handle the founder key change properly in CMODE_CHANGE
+         notify.  Bug #122.  Affected file silcd/packet_receive.c.
+
+Sun Mar  9 16:29:20 EET 2003  Pekka Riikonen <priikone@silcnet.org>
+
+       * Remove the mark for output (mark it only for input) after
+         purging outgoing queue.  Prevents the "Error in select()"
+         floods.  Affected file silcd/packet_send.c.
+
+       * Fixed incorrect connection deletion from client library
+         after calling "connect" client operation.  Could cause
+         crashes for example during reconnect timeouts.  Affected
+         files are lib/silcclient/client.c and
+         irssi/src/silc/core/client_ops.c.
+
+       * Check server private key file permissions before starting
+         the server.  Affected file silcd/serverconfig.c.
+
 Tue Feb  4 22:53:26 EET 2003  Pekka Riikonen <priikone@silcnet.org>
 
        * NULL terminate allocated string in silc_buffer_strformat.
@@ -146,13 +372,13 @@ Thu Dec 12 23:22:50 EET 2002  Pekka Riikonen <priikone@silcnet.org>
          lib/silcutil/silcschedule.c.
 
        * Changed Win32 implementation of SilcThread to use modern
-         Win32 interface.  Affected file is 
+         Win32 interface.  Affected file is
          lib/silcutil/win32/silcwin32thread.c  A patch by Mikko L.
 
 Thu Dec 12 12:06:59 CET 2002 Jochen Eisinger <c0ffee@penguin-breeder.org>
 
        * Don't print signed messages when sending failed.  Affected files
-         irssi/src/silc/core/silc-[servers.c/commands.h] 
+         irssi/src/silc/core/silc-[servers.c/commands.h]
 
        * Send adquate signal when founding a channel by joing it.  Affect
          file irssi/src/silc/core/client_ops.c
@@ -183,7 +409,7 @@ Wed Dec 11 10:01:26 CET 2002 Pekka Riikonen <priikone@silcnet.org>
        * Fixed double free in SKE library error hadling when signature
          error occurred.  Affected file lib/silcske/silcske.c.
 
-       * Save the fingerprint to new SilcClientEntry after changing 
+       * Save the fingerprint to new SilcClientEntry after changing
          nickname.  Affected file lib/silcclient/client_notify.c.
 
        * Print SIGNOFF in Irssi SILC client only if the nickname is
@@ -259,7 +485,7 @@ Wed Dec  4 21:08:52 CET 2002  Jochen Eisinger <c0ffee@penguin-breeder.org>
 
        * Fixed bugs in Irssi's theme parsing. Affected files
          irssi/src/fe-common/core/themes.c
-         
+
 Wed Dec  4 18:29:13 EET 2002  Pekka Riikonen <priikone@silcnet.org>
 
        * Calculate the correct length for signed messages before
@@ -392,7 +618,7 @@ Thu Nov 28 17:17:11 CET 2002  Jochen Eisinger <c0ffee@penguin-breeder.org>
        * Do reverse lookups for server when /connecting. Affected files
          irssi/silc.conf, irssi/src/core/servers.c, irssi/src/core/network.c,
          irssi/src/core/net-nonblock.*
-       
+
 Thu Nov 28 16:19:18 CET 2002  Pekka Riikonen <priikone@silcnet.org>
 
        * Added library versioning for shared libraries.  Affected
@@ -559,7 +785,7 @@ Thu Nov 14 09:44:54 CET 2002  Jochen Eisinger <c0ffee@penguin-breeder.org>
 
        * SILC_UMODE_GONE changes are now propagated correctly to the
          Irssi client. Closes #54
-       
+
 Tue Nov 12 19:42:18 CET 2002  Jochen Eisinger <c0ffee@penguin-breeder.org>
 
        * Fixed example in /HELP KEY
@@ -661,7 +887,7 @@ Wed Nov  6 17:18:13 EET 2002  Pekka Riikonen <priikone@silcnet.org>
          the command call simpler for the application.  The library
          now handles the command line parsing, command finding and
          execution.  Application only needs to call the function
-         with the command line.  Affected files are 
+         with the command line.  Affected files are
          lib/silcclient/silcclient.h, command.[ch].
 
        * Fixed silc_get_input to NULL-terminate the returned input.
@@ -738,7 +964,7 @@ Sat Nov  2 12:53:09 EET 2002  Pekka Riikonen <priikone@silcnet.org>
 
        * Fixed connection closing in client library to not crash.
          Moved the connection freeing totally to function
-         silc_clinet_del_connection.  Affected file 
+         silc_clinet_del_connection.  Affected file
          lib/silcclinet/client.c.
 
 Fri Nov  1 18:57:02 EET 2002  Pekka Riikonen <priikone@silcnet.org>
@@ -798,7 +1024,7 @@ Sun Oct 27 11:44:32 EET 2002  Pekka Riikonen <priikone@silcnet.org>
          usage.  Affected files lib/silcclient/client_internal.h
          lib/silcclient/silcclient.h.
 
-       * Fixed a bug in query resolving in server.  Used wrong 
+       * Fixed a bug in query resolving in server.  Used wrong
          variable in a for loop and crashed.  Affected file is
          silcd/server_query.c.
 
@@ -819,7 +1045,7 @@ Sun Oct 27 11:44:32 EET 2002  Pekka Riikonen <priikone@silcnet.org>
          over.  Affected file silcd/packet_receive.c.  Bug #37.
 
        * Resolve incomplete client entrys in CUMODE_CHANGE and
-         CMODE_CHANGE notifys.  Affected file is 
+         CMODE_CHANGE notifys.  Affected file is
          lib/silcclient/client_notify.c.  Bug #42.
 
 Thu Oct 24 12:22:35 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
@@ -969,7 +1195,7 @@ Mon Oct 14 17:55:44 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
        * Fixed attribute encoding and decoding bugs.  Affected
          files lib/silccore/silcattrs.[ch].
 
-       * Added ATTR command to Irssi SILC Client which is used to      
+       * Added ATTR command to Irssi SILC Client which is used to
          manage user's Requested Attributes sending and values for
          WHOIS command.  Affected files around Irssi SILC client.
 
@@ -993,7 +1219,7 @@ Fri Oct 11 23:52:17 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
          Affected files lib/silcske/silcske.c, silcske_status.h and
          payload.c.
 
-       * Save the PKCS key length even if only private key is set to   
+       * Save the PKCS key length even if only private key is set to
          SilcPKCS.  Affected file lib/silccrypt/silcpkcs.[ch] and rsa.c.
 
        * Fixed the usage of silc_pkcs_get_key_len since it returns the
@@ -1215,7 +1441,7 @@ Sat Sep  7 16:02:09 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
          silcd/packet_receive.c.
 
        * From now on distribution versions are used as protocol versions
-         instead of by default using the Toolkit base version as protocol 
+         instead of by default using the Toolkit base version as protocol
          version.  Affected file prepare.
 
        * Do not set the locally resolved hostname for local client
@@ -1337,7 +1563,7 @@ Sun Jun 30 01:30:22 EEST 2002 Pekka Riikonen <priikone@silcnet.org>
 
        * Fixed pending command deletion in server and client library
          to check the whole list instead of breaking after first found.
-         The affected files are silcd/command.[ch] and 
+         The affected files are silcd/command.[ch] and
          lib/silcclient/command.[ch].
 
 Sat Jun 29 17:40:12 EEST 2002 Pekka Riikonen <priikone@silcnet.org>
@@ -1657,7 +1883,7 @@ Wed Jun 19 17:46:31 EEST 2002 Pekka Riikonen <priikone@silcnet.org>
          It expected it to always be only client and ignored the
          notify.  Affected file silcd/packet_recieve.c.
 
-       * Removed some (unnecessary) debug printing from 
+       * Removed some (unnecessary) debug printing from
          lib/silccore/silcid.c and lib/silccore/silcargument.c.
 
        * Do not force CMODE_CHANGE when server is announcing new
@@ -1670,7 +1896,7 @@ Wed Jun 19 17:46:31 EEST 2002 Pekka Riikonen <priikone@silcnet.org>
          fixes some problems too.  Affected file silcd/packet_receive.c.
 
        * Fixed SERVER_SIGNOFF sending to local clients.  It was
-         totally broken and sent the notify to all local clients, 
+         totally broken and sent the notify to all local clients,
          instead of only to those that was on same channel as the
          signing off clients.  Affected file silcd/server_util.c.
 
@@ -1994,7 +2220,7 @@ Mon May  6 19:46:12 EEST 2002 Pekka Riikonen <priikone@silcnet.org>
          when that mode is set.  Protocol TODO #17.  Affected
          files are silcd/server.[ch], server_util.[ch],
          silcd/command.c, silcd/packet_receive.c and
-         lib/silcclient/command.c. 
+         lib/silcclient/command.c.
 
 Fri May  3 18:36:51 EEST 2002 Pekka Riikonen <priikone@silcnet.org>
 
@@ -2021,7 +2247,7 @@ Fri May  3 11:37:10 EEST 2002 Pekka Riikonen <priikone@silcnet.org>
          silcd/command.c and silcd/command_reply.c.
 
        * Fixed client info resolving on LEAVE command in client
-         library to not crash.  Affected file is 
+         library to not crash.  Affected file is
          lib/silcclient/client_notify.c.
 
 Thu May  2 08:45:11 CEST 2002 Pekka Riikonen <priikone@silcnet.org>
@@ -2076,7 +2302,7 @@ Sun Apr 21 19:44:38 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
          Moved the silc_client_command_status_messages table to the
          lib/silcutil/silcutil.c and added new funtion
          silc_get_status_message, which deprecates function
-         silc_client_status_message.  Affected files are 
+         silc_client_status_message.  Affected files are
          lib/silccore/silcstatus.h, lib/silcclient/command_reply.[ch],
          lib/silcutil/silcutil.[ch].
 
@@ -2166,14 +2392,14 @@ Mon Apr 15 19:57:57 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
 
        * Defined the use of extra WHOIS attributes in WHOIS command.
          The <Requested Attributes> (defined in a separate document)
-         can be used to request additional information about user 
+         can be used to request additional information about user
          not returned by standard WHOIS command.  Defined that server
          can send WHOIS command directly to client.  Client provides
          the requested attributes to the server.  Updated the protocol
          specs.  Protocol TODO #4.  Implementation is not done yet
           (Protocol TODO #24).
 
-       * Renamed function silc_client_command_status_message to        
+       * Renamed function silc_client_command_status_message to
          silc_client_status_message.  Affected files are
          lib/silcclient/command_reply.[ch].
 
@@ -2199,7 +2425,7 @@ Sat Apr 13 13:09:24 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
 Fri Apr 12 20:09:08 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
 
        * Added resolve_cmd_ident field to the SilcClientEntry structure
-         too so that if the entry is for example being resolved so 
+         too so that if the entry is for example being resolved so
          another command may attach to the same pending command reply
          without requiring to resolve the same entry again.  Added
           support for adding multiple pending commands for one
@@ -2268,7 +2494,7 @@ Tue Apr  9 17:15:42 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
          Private Message Key flag is set (using private keys to protect
          private messages).  Updated protocol specs and code in client
          and server and core library.  Protocol TODO #23.  Affected
-         files are lib/silccore/silcmode.h, silcd/server.[ch], 
+         files are lib/silccore/silcmode.h, silcd/server.[ch],
          irssi/src/silc/core/client_ops.c, silcd/packet_receive.c,
          irssi/docs/help/in/umode.in, lib/silcclient/command.c.
 
@@ -2314,7 +2540,7 @@ Mon Apr  8 17:00:41 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
        * Added more IM-like features by introducing new user modes
          for setting various presence information.  Added new modes:
          INDISPOSED, BUSY, PAGE, HYPER and ROBOT.  Updated protocol
-          specs and code.  Protocol TODO #19. Affected files are 
+          specs and code.  Protocol TODO #19. Affected files are
           lib/silccore/silcmode.h, irssi/src/silc/core/client_ops.c,
          irssi/docs/help/in/umode.in and lib/silcclient/command.c.
 
@@ -2323,7 +2549,7 @@ Sun Apr  7 17:07:59 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
        * Added STATS command to the protocol after all, to return
          various statistical information about the network.  It can
          be used by clients to retrieve statistical information, and
-         servers may use it to to fetch cell and network wide 
+         servers may use it to to fetch cell and network wide
          statistics from router.  Updated the protocol specs and
          implemented it to the server.  Protocol TODO #16.
          Affected files are lib/silccore/silccommand, silcd/command.[ch],
@@ -2332,7 +2558,7 @@ Sun Apr  7 17:07:59 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
 Sat Apr  6 17:08:58 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
 
        * The LIST command reply in client libary now adds new channel
-         entry if the returned channel doesn't exist yet in cache, 
+         entry if the returned channel doesn't exist yet in cache,
          and returns the channel entry to the application in the
          command_reply client operation.  Affected file is
          lib/silcclient/command_reply.c.
@@ -2361,12 +2587,12 @@ Fri Apr  5 16:03:03 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
 
        * Defined that the security property fields in SKE SHOULD be
          UTF-8 encoded, defined that version string MUST be US-ASCII
-         encoded, defined that passphrases sent in connection 
+         encoded, defined that passphrases sent in connection
          authentication protocol MUST be UTF-8 encoded.  Implemented
          these to the client and server.  Defined also that other
          passphrases sent in the protocol MUST be UTF-8 encoded.
-         Affected files are lib/silcske/silcske.c, 
-         lib/silcclient/protocol.c, silcd/protocol.c, 
+         Affected files are lib/silcske/silcske.c,
+         lib/silcclient/protocol.c, silcd/protocol.c,
          silcd/serverconfig.c, and lib/silccore/silcauth.c.
 
        * Changed the silc_client_close_connection interface to not
@@ -2391,7 +2617,7 @@ Wed Apr  3 16:24:51 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
        * Added the killer's client ID to the KILLED notify and added
          it to protocol specs and implemented it to client and server.
          Protocol TODO #13.  Affected files are silcd/command.c,
-         silcd/packet_receive.c, packet_send.[ch], 
+         silcd/packet_receive.c, packet_send.[ch],
          lib/silcclient/client_notify.c, irssi/src/silc/core/client_ops.c.
          The killer's client entry is now returned to application in
          the `notify' client operation.
@@ -2425,7 +2651,7 @@ Wed Apr  3 16:24:51 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
 
          Changed the client library to return the message length
          to application as well in the channel_message and private_message
-         client operations.  Affected files are 
+         client operations.  Affected files are
          lib/silcclient/client_prvmsg, lib/silcclient/client_channel.c,
          lib/silcclient/silcclient.h, irssi/src/silc/core/client_ops.c,
          and lib/silcclient/client_ops_example.c.
@@ -2442,7 +2668,7 @@ Wed Apr  3 16:24:51 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
 
        * Deprecated all administrative commands from SILC protocol
          since they are highly implementation specific commands.
-         Updated protocol specs.  Moved the old commands in 
+         Updated protocol specs.  Moved the old commands in
          implementations to private range of command types.  Affected
          files are silcd/command.c, lib/silcclient/command.c and
          lib/silcclient/command_reply.c.  Protocol TODO #8.
@@ -2453,7 +2679,7 @@ Wed Apr  3 16:24:51 EEST 2002  Pekka Riikonen <priikone@silcnet.org>
 Wed Apr  3 09:57:47 CEST 2002  Pekka Riikonen <priikone@silcnet.org>
 
        * Added SILC_PROTOCOLVERSION macro to check protocol version
-         of a socket connection.  The affected file is 
+         of a socket connection.  The affected file is
          lib/silcutil/silcsockconn.h.
 
        * Added better error logging in rekey protocol.  Affected file
@@ -2468,9 +2694,9 @@ Wed Apr  3 09:57:47 CEST 2002  Pekka Riikonen <priikone@silcnet.org>
 Tue Apr  2 14:55:06 CEST 2002  Pekka Riikonen <priikone@silcnet.org>
 
        * Some client implementations quit network by doing first LEAVE
-         and then immediately SIGNOFF (like Bombyx).  We now do check 
-         after a short time after LEAVE notify and check whether the 
-         client is still valid after LEAVE, and if not we remove it from 
+         and then immediately SIGNOFF (like Bombyx).  We now do check
+         after a short time after LEAVE notify and check whether the
+         client is still valid after LEAVE, and if not we remove it from
          cache.  Affected file is lib/silcclient/client_notify.c.
 
 Tue Apr  2 13:39:04 CEST 2002  Johnny Mnemonic <johnny@themnemonic.org>
@@ -2589,7 +2815,7 @@ Thu Mar 28 17:01:43 EET 2002  Pekka Riikonen <priikone@silcnet.org>
        * Fixed the silc_log_quick handling in the logging routines.
          It didn't log quickly when it was TRUE.  Affected file is
          lib/silcutil/silclog.c.  Also the flush delay was set even
-         if it was 0 in config file.  Affected file is 
+         if it was 0 in config file.  Affected file is
          silcd/serverconfig.c.
 
        * Added support for changing key pair of the server in rehash.
@@ -2811,7 +3037,7 @@ Tue Mar 19 16:32:43 CET 2002  Pekka Riikonen <priikone@silcnet.org>
          called the application does not call silc_packet_send_prepare
          because the library will call it automatically.  These
          interfaces now also return a reference to the outgoing buffer
-         which includes the assembled packet, which the application can 
+         which includes the assembled packet, which the application can
          use to encrypt the packet.
 
          Affected files are lib/silccore/silcpacket.[ch],
@@ -2826,7 +3052,7 @@ Tue Mar 19 16:32:43 CET 2002  Pekka Riikonen <priikone@silcnet.org>
 Mon Mar 18 21:00:41 EET 2002  Pekka Riikonen <priikone@silcnet.org>
 
        * Added macro SILC_PACKET_DATALEN which can be used during
-         packet assembling to check whether the data to be added to    
+         packet assembling to check whether the data to be added to
          the packet will fit to SILC_PACKET_MAX_LEN.  If not the data
          len is truncated until it fits it.
 
@@ -2852,7 +3078,7 @@ Sun Mar 17 19:26:16 EET 2002  Pekka Riikonen <priikone@silcnet.org>
 
        * Added the deleting of server's own ID cache entry to the
          silc_server_free function.  Free also everything else that
-         has been allocated in silc_server_init.  The affected file 
+         has been allocated in silc_server_init.  The affected file
          is silcd/server.c.
 
 Sun Mar 17 15:44:56 EET 2002  Pekka Riikonen <priikone@silcnet.org>
@@ -2865,7 +3091,7 @@ Sun Mar 17 15:44:56 EET 2002  Pekka Riikonen <priikone@silcnet.org>
        * Added new configuration params: version_protocol, version_software
          and version_software_vendor to specify what version the remote
          host must at least be to be able to connect to server.  The vendor
-         string can be regex matched too.  Added new function 
+         string can be regex matched too.  Added new function
          silc_server_connection_allowed to check maximum number of allowed
          connections, and allowed versions for incoming connections.
          Affected files are silcd/server.c, server_util.[ch] and
@@ -2883,7 +3109,7 @@ Sun Mar 17 10:24:50 EET 2002  Pekka Riikonen <priikone@silcnet.org>
          Renamed silc_schedule_wakeup_init and silc_schedule_wakeup_uninit
          to silc_schedule_internal_init and silc_schedule_internal_uninit.
          Added new platform specific routines
-         silc_schedule_internal_signals_[un]block and 
+         silc_schedule_internal_signals_[un]block and
          silc_schedule_internal_signal_[un]register.
 
          Added new functions to SILC Schedule API:
@@ -2947,7 +3173,7 @@ Sat Mar 16 18:04:30 EET 2002  Pekka Riikonen <priikone@silcnet.org>
          it was mistakenly updated to SILC Protocol 1.0 even though it
          is to be included in 1.1.  Since it is not in 1.0 it is not
          mandatory, and this fix now handles it only if it is provided,
-         and it is not error if it is not provided.  Affected file 
+         and it is not error if it is not provided.  Affected file
          lib/silcclient/client_notify.c.
 
 Sat Mar 16 09:07:27 EET 2002  Pekka Riikonen <priikone@silcnet.org>
@@ -3022,7 +3248,7 @@ Sun Mar 10 20:07:49 EET 2002  Pekka Riikonen <priikone@silcnet.org>
        * Fixed the server to check correctly the amount of connections
          from single host, by checking also the type of the connection.
          Fixed also the comparison of number of connections and number
-         of allowed connections.  Affected files are silcd/server.c, 
+         of allowed connections.  Affected files are silcd/server.c,
          server_util.[ch].
 
 Fri Mar  8 17:16:41 EET 2002  Pekka Riikonen <priikone@silcnet.org>
@@ -3251,7 +3477,7 @@ Thu Feb 14 22:03:58 EET 2002  Pekka Riikonen <priikone@silcnet.org>
          reconnect_interval_max, reconnect_keep_trying and
          require_reverser_lookup.  Added ConnectionParam block, and
          implemented the connection parameters when connecting as
-         initiator and when accepting connections as responder. 
+         initiator and when accepting connections as responder.
 
          Added CONFIG_IS_DOUBLE macro in config file parsing, to check
          whether given configuration value has been given already.
@@ -3288,7 +3514,7 @@ Wed Feb 13 20:51:13 EET 2002  Pekka Riikonen <priikone@silcnet.org>
        * Removed doc/example_silc.conf.in since it is redundant.
          The make install will now install irssi/silc.conf file.
 
-       * Added new Passphrase and Publickey authentication methods to  
+       * Added new Passphrase and Publickey authentication methods to
          config file, allowing both public key and passphrase based
          authentication to be set at the same time.
 
@@ -3352,7 +3578,7 @@ Sun Feb  3 17:20:52 EET 2002  Pekka Riikonen <priikone@silcnet.org>
 
        * Fixed the file transfer's key agreement payload to include
          zero port also if the hostname is NULL because it could not
-         be bound.  
+         be bound.
 
          Call file transfer monitor callback now also if error occurs
          during key agreement protocol.
@@ -3421,12 +3647,12 @@ Thu Jan 31 23:34:33 EET 2002  Pekka Riikonen <priikone@silcnet.org>
 
 Thu Jan 31 19:06:22 EET 2002  Pekka Riikonen <priikone@silcnet.org>
 
-       * Added function silc_client_add_channel, 
+       * Added function silc_client_add_channel,
          silc_client_replace_channel_id, and removed functions
          silc_client_new_channel_id and silc_idlist_get_channel_by_id
          from client library.
 
-       * Added cross reference of the joined channels to the 
+       * Added cross reference of the joined channels to the
          SilcClientEntry, and changed the SilcChannelEntry's
          users list to SilcHashTable.  The affected files are
          lib/silcclient/idlist.[ch].
@@ -3443,7 +3669,7 @@ Thu Jan 31 19:06:22 EET 2002  Pekka Riikonen <priikone@silcnet.org>
        * Changed all hash table traversing to call the new
          silc_hash_table_list_reset in server and in client library.
 
-       * Added function silc_client_on_channel to return the 
+       * Added function silc_client_on_channel to return the
          SilcChannelUser entry if the specified client entry is joined
          on the specified channel.  This is exported to application as
          well.  Affected files lib/silcclient/client_channel.c, silcapi.h.
@@ -3505,7 +3731,7 @@ Mon Jan 28 17:49:42 EET 2002  Pekka Riikonen <priikone@silcnet.org>
 
        * Fixed the CHANNEL_CHANGE notify to re-announce the channel
          which ID was changed.  This way the router will send the
-         user list for the channel again, and server won't be in 
+         user list for the channel again, and server won't be in
          desync in some rare circumstances.  Affected file is
          silcd/packet_receive.c.
 
@@ -3585,7 +3811,7 @@ Mon Jan 21 19:07:53 EET 2002  Pekka Riikonen <priikone@silcnet.org>
 
        * Added silc_client_start_key_exchange_cb and lookup the
          remote hostname and IP address before starting the key
-         exchange with server.  The affected file is 
+         exchange with server.  The affected file is
          lib/silcclient/client.c.
 
        * The server's public key is now saved using the IP address
@@ -3626,7 +3852,7 @@ Thu Jan 17 18:59:11 EET 2002  Pekka Riikonen <priikone@silcnet.org>
          context.  When error occurs during socket operation (read
          or write) the error is saved.  Added also new function
          silc_socket_get_error to return human readable socket error
-         message.  Affected files are lib/silcutil/silcsockconn.[ch], 
+         message.  Affected files are lib/silcutil/silcsockconn.[ch],
          lib/silcutil/unix/silcunixsockconn.c, and
          lib/silcutil/win32/silcwin32sockconn.c.
 
@@ -3635,12 +3861,12 @@ Thu Jan 17 18:59:11 EET 2002  Pekka Riikonen <priikone@silcnet.org>
 
        * Fixed the `created' channel information sending from router
          to server in JOIN command.  Checks now whether the channel
-         really was created or not and set it according that. 
+         really was created or not and set it according that.
 
          Fixed the JOIN command to use the client entry's current
          ID during the joining procedure instead of the one it sent
          in the command (it is checked though), since it can change
-         between the packet processing and command processing, and 
+         between the packet processing and command processing, and
          would just case unnecessary pain in the client end.  Affected
          file silcd/command.c.
 
@@ -3793,7 +4019,7 @@ Thu Dec 20 16:14:52 CET 2001  Pekka Riikonen <priikone@silcnet.org>
 
          The server now checks that if unauthenticated connection
          sends data and its processing fails the server will close
-         the connection since it could be a malicious flooder. 
+         the connection since it could be a malicious flooder.
 
          Affected files lib/silccore/silcpacket.[ch], silcd/server.c.
 
@@ -3804,20 +4030,20 @@ Wed Dec 19 21:31:25 EET 2001  Pekka Riikonen <priikone@silcnet.org>
          too much useless log).  Affected file lib/silcutil/silclog.c.
 
 Wed Dec 19 18:21:51 CET 2001  Johnny Mnemonic <johnny@themnemonic.org>
+
        * Made the silc_server_daemonise() function more readable.
          Affected file silcd/server.c.
+
        * Pid file is now optional, the user may comment it out from
          the config file. Removed define SILC_SERVER_PID_FILE, we
          don't need a default any longer.  Affected file
          configure.in.pre, lib/Makefile.am.pre.
+
        * Make some use of the pid file. The server now dies at startup
          if it detects a valid pid file on his path. The server would
          die anyway in this circumstance, because of the bind() failure.
          Affected file silcd/silcd.c.
+
        * No longer compiling lib/dotconf.
 
 Mon Dec 17 18:24:27 EET 2001  Pekka Riikonen <priikone@silcnet.org>
@@ -3827,7 +4053,7 @@ Mon Dec 17 18:24:27 EET 2001  Pekka Riikonen <priikone@silcnet.org>
 
        * Fied the NICK_CHANGE notify to add the new client entry
          even it is resolved.  This removes an <[unknown]> nick
-         thingy bug in the client.  Affected file is 
+         thingy bug in the client.  Affected file is
          lib/silcclient/client_notify.c.
 
        * Do not try to allocate 0 bytes (efence does not like it)
@@ -3983,7 +4209,7 @@ Sun Dec  2 23:29:07 EET 2001  Pekka Riikonen <priikone@silcnet.org>
          in WHOIS or IDENTIFY from router, and it is global client,
          we'll check whether it is on some channel.  If it is not
          then we cannot be sure about its validity and will resolve it
-         from router.  Fixes a bug in WHOIS and IDENTIFY.  Affected 
+         from router.  Fixes a bug in WHOIS and IDENTIFY.  Affected
          file silcd/command.c.
 
        * Search channel by name (if possible) rather than by ID
@@ -3998,7 +4224,7 @@ Sun Dec  2 13:48:46 EET 2001  Pekka Riikonen <priikone@silcnet.org>
 
        * Implemented the <founder auth> payload handling in the JOIN
          command.  If provided all conditions for channel joining
-         except requirement to provide correct passphrase can be 
+         except requirement to provide correct passphrase can be
          overrided by the channel founder.  Updated the protocol specs.
          Affected file silcd/command.c.
 
@@ -4131,10 +4357,10 @@ Sun Nov 25 18:01:45 EET 2001  Pekka Riikonen <priikone@silcnet.org>
          IP/hostname.  Affected file lib/silcutil/silcnet.c.
 
        * Defined <founder auth> argument to the SILC_COMMAND_JOIN
-         command.  It can be used to gain founder privileges at 
+         command.  It can be used to gain founder privileges at
          the same time when joining the channel.
 
-         Defined that the SILC_NOTIFY_TYPE_KICKED send the 
+         Defined that the SILC_NOTIFY_TYPE_KICKED send the
          kicker's client ID as well.  Updated protocol specs.
 
          Defined that the server must send SILC_COMMAND_IDENTIFY
@@ -4169,7 +4395,7 @@ Sat Nov 24 20:08:22 EET 2001  Pekka Riikonen <priikone@silcnet.org>
 Fri Nov 23 23:30:59 EET 2001  Pekka Riikonen <priikone@silcnet.org>
 
        * Pid file configuration, and server's config file fixes
-         patch by toma.  Updated CREDITS file. 
+         patch by toma.  Updated CREDITS file.
 
 Sun Nov 18 01:34:41 EET 2001  Pekka Riikonen <priikone@silcnet.org>
 
@@ -4260,7 +4486,7 @@ Sun Nov 11 10:49:10 EET 2001  Pekka Riikonen <priikone@silcnet.org>
          Should fix /NAMES bit more.  The affected file is
          irssi/src/silc/core/silc-channels.c.
 
-       * Added `fingerprint' field to the SilcIDListData in the 
+       * Added `fingerprint' field to the SilcIDListData in the
          silcd/idlist.h to hold the fingerprint of the client's
          public key.
 
@@ -4442,7 +4668,7 @@ Sat Nov  3 22:04:00 PST 2001  Brian Costello <bc@mksecure.com>
 
 Sat Nov  3 17:48:55 EET 2001  Pekka Riikonen <priikone@silcnet.org>
 
-       * Added silc_pkcs_public_key_compare to compare two 
+       * Added silc_pkcs_public_key_compare to compare two
          public keys.  Affected file lib/silccrypt/silcpkcs.[ch].
 
        * Check that the client who set the founder mode on the
@@ -4460,7 +4686,7 @@ Fri Nov  2 18:52:08 EST 2001  Pekka Riikonen <priikone@silcnet.org>
          client library.  Affected file lib/silcclient/client.c.
 
        * Fixed the silc_client_packet_parse to not to increase
-         the packet sequence number if the conn->sock and the 
+         the packet sequence number if the conn->sock and the
          current socket connection is not same.  This can happen
          for example during key agreement when the conn includes
          multiple socket connections (listeners).  Affected file
@@ -4491,7 +4717,7 @@ Thu Nov  1 22:10:07 EST 2001  Pekka Riikonen <priikone@silcnet.org>
          corresponding private key is verified by the server).
          Updated to the protocol specification.
 
-       * Added support of receiving the client's public key's 
+       * Added support of receiving the client's public key's
          fingerprint in command reply in client library.  Affected
          file is lib/silcclient/command_reply.c, and
          lib/silcclient/idlist.[ch].
@@ -4548,7 +4774,7 @@ Mon Oct 29 17:43:04 EST 2001  Pekka Riikonen <priikone@silcnet.org>
          the provided table of client entries.  Affected file
          silcd/packet_send.[ch].
 
-       * Fixed a crash in client resolving in client_prvmsg.c in 
+       * Fixed a crash in client resolving in client_prvmsg.c in
          client library.  Affected file lib/silcclient/client_prvmsg.c.
 
        * Do not actually remove the client directly from ID cache
@@ -4563,7 +4789,7 @@ Mon Oct 29 17:43:04 EST 2001  Pekka Riikonen <priikone@silcnet.org>
          silcd/packet_receive.c.
 
        * Check for partial packet in data queue after every packet that
-         was found from the queue.  Return and wait for more data if 
+         was found from the queue.  Return and wait for more data if
          there is partial data in queue.  Affected file is
          lib/silccore/silcpacket.c.
 
@@ -4651,7 +4877,7 @@ Mon Oct 22 16:35:05 EDT 2001  Pekka Riikonen <priikone@silcnet.org>
          lib/silcclient/client.c.
 
        * SilcPacketParserCallback now returns TRUE or FALSE to indicate
-         whether library should continue processing the packet. 
+         whether library should continue processing the packet.
          Affected file lib/silccore/silcpacket.h.
 
        * Added SilcSFTPMonitor callback, SilcSFTPMonitors and
@@ -4670,7 +4896,7 @@ Mon Oct 22 16:35:05 EDT 2001  Pekka Riikonen <priikone@silcnet.org>
        * Added new local command FILE to the Irssi SILC Client.
          It is used to perform the file transfer.  It has subcommands
          SEND, RECEIVE, SHOW and CLOSE.  Affected files
-         irssi/src/silc/core/client_ops.c, 
+         irssi/src/silc/core/client_ops.c,
          irssi/src/silc/core/silc-server.[ch].
 
 Mon Oct 22 12:50:08 EDT 2001  Pekka Riikonen <priikone@silcnet.org>
@@ -4682,7 +4908,7 @@ Sun Oct 21 20:21:02 EDT 2001  Pekka Riikonen <priikone@silcnet.org>
 
        * Renamed silc_file_read and silc_file_write to functions
          silc_file_readfile and silc_file_writefile.  Added function
-         silc_file_open and silc_file_close.  Affected files 
+         silc_file_open and silc_file_close.  Affected files
          lib/silcutil/silcutil.[ch].
 
 Thu Oct 18 20:58:13 EDT 2001  Pekka Riikonen <priikone@silcnet.org>
@@ -4967,7 +5193,7 @@ Thu Sep 27 22:52:30 EEST 2001  Pekka Riikonen <priikone@silcnet.org>
          (SSH File Transfer Protocol).  Affected file in addition
          of the internet draft is lib/silccore/silcpacket.h.
 
-       * Deprecated the SILC_PACKET_CELL_ROUTERS and defined new 
+       * Deprecated the SILC_PACKET_CELL_ROUTERS and defined new
          packet SILC_PACKET_RESUME_ROUTER instead.  The new packet
          is used as part of backup router protocol when the primary
          router of the cell is back online and wishes to resume
@@ -4980,7 +5206,7 @@ Thu Sep 27 22:52:30 EEST 2001  Pekka Riikonen <priikone@silcnet.org>
          change causes incompatibilities in the protocol.
 
        * Redefined also the MAC computation from the packet.
-         An packet sequence number is now added to the MAC 
+         An packet sequence number is now added to the MAC
          computation.  This prevents possible replay attacks against
          the protocol.  This change too causes incompatibilities
          in the protocol.
@@ -5094,7 +5320,7 @@ Sun Sep 16 12:32:58 EEST 2001  Pekka Riikonen <priikone@silcnet.org>
          case all found clients are already disconnected (WHOWAS would
          found them) in the server.  Affected file silcd/command.c.
 
-       * Update the last_receive (time of last data received) to be 
+       * Update the last_receive (time of last data received) to be
          updated only when received private or channel message so that
          the idle time showed in WHOIS makes more sense.
 
@@ -5153,7 +5379,7 @@ Thu Sep 13 20:24:52 EEST 2001  Pekka Riikonen <priikone@silcnet.org>
 
        * Removed channel key rekey task deleting from the function
          silc_server_save_channel_key.  Affected file silcd/server.c.
-         Added explicit timeout task context instead that is used to   
+         Added explicit timeout task context instead that is used to
          delete the task if we are registering a new task before the
          new task has elapsed.
 
@@ -5188,7 +5414,7 @@ Sun Sep  9 15:49:16 EEST 2001  Pekka Riikonen <priikone@silcnet.org>
          as well.  This replaced the old boolean registered field as well.
 
          Added resolve_cmd_ident field to the SilcClientEntry structure
-         too so that if the entry is for example being resolved so 
+         too so that if the entry is for example being resolved so
          another command may attach to the same pending command reply
          without requiring to resolve the same entry again.  This concept
          should optimize the WHOIS and the IDENTIFY resolving under
@@ -5294,7 +5520,7 @@ Thu Sep  6 12:47:37 EEST 2001  Pekka Riikonen <priikone@silcnet.org>
 
        * Changed the silc_client_get_clients_local to accept the formatted
          nickname as argument.  It accepts the real nickname too but the
-         formatted nickname can be used to find the true entry from 
+         formatted nickname can be used to find the true entry from
          multiple entries.  Affected file lib/silcclient/silcapi.h and
          lib/silcclient/idlist.c.
 
@@ -5308,7 +5534,7 @@ Thu Sep  6 12:47:37 EEST 2001  Pekka Riikonen <priikone@silcnet.org>
          provided then the library will use the string as is.  The
          affected file is lib/silcclient/silcapi.h.
 
-       * All the nickname strings passed to the client library in 
+       * All the nickname strings passed to the client library in
          commands are now expected to be formatted nickname strings.
          If the command does not support the formatted nickname string
          it will assume that the sent string is the actual nickname.
@@ -5335,7 +5561,7 @@ Tue Sep  4 12:39:17 EEST 2001  Pekka Riikonen <priikone@silcnet.org>
          application can call this function if it does not know the
          current authentication method.
 
-         Affected files are lib/silcclient/client.c and 
+         Affected files are lib/silcclient/client.c and
          lib/silcclient/silcapi.h.
 
        * The Irssi SILC client now automatically resolves the authentication
@@ -5395,7 +5621,7 @@ Sat Sep  1 00:29:33 EEST 2001  Pekka Riikonen <priikone@silcnet.org>
 
        * Changed the silc_id_create_client_id to be collision
          resistant.  It is now assured that there cannot be created
-         two same client ID's.  I suspect that some weird bugs in 
+         two same client ID's.  I suspect that some weird bugs in
          the server were actually caused by duplicate Client IDs.
          Affected file silcd/serverid.[ch].  A router receiving
          new ID now also assures and informs the sending server
@@ -5463,7 +5689,7 @@ Sat Aug 11 00:29:57 EEST 2001  Pekka Riikonen <priikone@silcnet.org>
          if client could not be added to ID cache.  Affected files
          silcd/packet_receive.c and silcd/server.c.
 
-       * When client's sock->user_data is freed, NULL also the 
+       * When client's sock->user_data is freed, NULL also the
          client->router and client->connection pointers.  Added check
          for these pointers being NULL to various places around the
          code.  Affected file silcd/server.c.
@@ -5473,7 +5699,7 @@ Sat Aug 11 00:29:57 EEST 2001  Pekka Riikonen <priikone@silcnet.org>
          are not handled when it is not allowed.  Affected file
          silcd/server.c.
 
-       * Added `bool registered' fields to all 
+       * Added `bool registered' fields to all
          silc_idlist_[server|client]_get_* routines to indicate whether
          the fetched client needs to be registered or not.  Affected
          file silcd/idlist.[ch].
@@ -5623,7 +5849,7 @@ Thu Jul 19 14:47:30 EEST 2001  Pekka Riikonen <priikone@silcnet.org>
 
 Wed Jul 18 18:34:01 EEST 2001  Pekka Riikonen <priikone@silcnet.org>
 
-       * Call silc_schedule_task_del_by_context in the 
+       * Call silc_schedule_task_del_by_context in the
          silc_protocol_cancel instead of silc_schedule_task_del_by_callback.
          Affected file lib/silccore/silcprotocol.c.
 
@@ -5727,7 +5953,7 @@ Wed Jul 11 18:31:57 EEST 2001  Pekka Riikonen <priikone@silcnet.org>
          updated the protocol specs.
 
        * Completed the GETKEY command in client. It can be now used
-         to fetch also servers public key not only some clients. 
+         to fetch also servers public key not only some clients.
          Affected files lib/silcclient/command[_reply].c.
 
        * Added silc_client_get_server to return server entry by the
@@ -5762,7 +5988,7 @@ Tue Jul 10 18:05:38 EEST 2001  Pekka Riikonen <priikone@silcnet.org>
 
          The INFO command now allocates the SilcServerEntry context
          and saves the server info there.  The COMMAND_REPLY in
-         the INFO now returns the parameters to application in 
+         the INFO now returns the parameters to application in
          same order as defined in the protocol specification.
 
          The entries are cached in the client->server_cache.
@@ -5792,7 +6018,7 @@ Tue Jul 10 18:05:38 EEST 2001  Pekka Riikonen <priikone@silcnet.org>
        * Fixed a channel joining bug in router.  The router must also
          check the channel modes, invite and ban lists etc. when serving
          the JOIN command sent by normal server.  Affected file is
-         silcd/command.c.  The router now resolves the client's 
+         silcd/command.c.  The router now resolves the client's
          information from the server who sent the JOIN command if it
          does not know it, and processes the JOIN command only after
          that.
@@ -5875,7 +6101,7 @@ Sun Jul  8 18:44:53 EEST 2001  Pekka Riikonen <priikone@silcnet.org>
 
        * Added SILC_MUTEX_DEFINE to define the mutex on environments
          that may or may not compile the mutex support in.
-       
+
          Changed the silc_mutex_alloc interface. It allocates the
          mutex now to the sent pointer and returns TRUE or FALSE.
 
@@ -6142,7 +6368,7 @@ Fri Jun 22 10:44:14 EEST 2001  Pekka Riikonen <priikone@silcnet.org>
 
        * Fixed the KICK notify handling in the Irssi SILC client to
          update the channel records so that the kicked client does not
-         appear to be on the channel.  The affected file is 
+         appear to be on the channel.  The affected file is
          irssi/src/silc/core/silc-channels.c.
 
        * Always update the conn->current_channel when executing command
@@ -6171,13 +6397,13 @@ Thu Jun 21 17:10:08 CEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
        * Fixed KILL notify handling, client does not crash anymore.
          Affected file irssi/src/silc/core/silc-channels.c.
 
-       * Reduced the default packet buffer size from 2048 to 1024 in   
+       * Reduced the default packet buffer size from 2048 to 1024 in
          lib/silccore/silcpacket.c.
 
        * Added SILC_SKE_STATUS_FREED SKE status type and a reference
          counter to the SKE context that is incresed when the SKE library
          performs async operation outside the library.  If the outside
-         process frees the SKE context and FREED status will be set 
+         process frees the SKE context and FREED status will be set
          and the library will detect after the sync operation that the
          libary is freed.  The affected files are
          lib/silcske/silcske[_status].[ch].
@@ -6187,7 +6413,7 @@ Thu Jun 21 17:10:08 CEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
          passed as client entry to the application. */
 
        * Fixed the task timeout calculation to assure that there is
-         never negative timeouts.  The affected file is 
+         never negative timeouts.  The affected file is
          lib/silcutil/silcschedule.c.
 
        * Fixed the channel user mode notification sending in server.
@@ -6205,7 +6431,7 @@ Tue Jun 19 22:10:36 EEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
        * Fixed a possible crash in silc_packet_send_prepare.  It now
          assures always that there is enough space in the buffer and
-         at the tail area of the buffer (for MAC). 
+         at the tail area of the buffer (for MAC).
 
          Fixed the inbound buffer reallocation in silc_packet_read.
          It was old code and did not handle the reallocation correctly.
@@ -6267,7 +6493,7 @@ Mon Jun 18 18:49:07 EEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
          Irssi SILC client's message modules formats.
 
          Added the handing of the KILL notify to the Irssi SILC client
-         as it was missing.  Added the kill message module formats 
+         as it was missing.  Added the kill message module formats
          as well.
 
          The affected file is irssi/src/silc/core/silc-channels.c.
@@ -6348,7 +6574,7 @@ Thu Jun  7 16:29:56 EEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
 Thu Jun  7 08:57:16 CEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
-       * Close log file after open.  Affected file 
+       * Close log file after open.  Affected file
          lib/silcutil/silclog.c.
 
        * Check whether sock == NULL in silc_client_send_packet and return
@@ -6360,7 +6586,7 @@ Thu Jun  7 08:57:16 CEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
 Tue Jun  5 08:08:21 CEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
-       * Merged a splitted window bugfix from Irssi CVS tree.  The 
+       * Merged a splitted window bugfix from Irssi CVS tree.  The
          affected file is irssi/src/fe-text/textbuffer-view.c.
 
        * Fixed the ME, ACTION and NOTICE printing in Irssi Client.
@@ -6431,7 +6657,7 @@ Fri Jun  1 22:19:37 EEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
          silcd/serverconfig.[h] and silcd/server.c.
 
        * Changed the layout of the header files of the public interfaces
-         in the SILC libraries.  The new layout supports ROBODoc 
+         in the SILC libraries.  The new layout supports ROBODoc
          documentation tool (and some others) so that it is easy to create
          a library reference manual.  All the other headers and source
          code must still follow the CodingStyle document.  Also source
@@ -6516,7 +6742,7 @@ Sun May 27 15:57:17 EEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
          error message printing to module formats in the Irssi SILC client.
 
        * Added new silc_client_set_away_message to set the away message
-         that is back to the person who sent private message.  The 
+         that is back to the person who sent private message.  The
          affected file lib/silcclient/silcapi.h and the
          lib/silcclient/client_prvmsg.c.
 
@@ -6554,7 +6780,7 @@ Sat May 26 17:43:42 EEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 Sat May 26 12:13:37 EEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
        * Changed the ask_passphrase client operation to be ascynchronous.
-         It has now a completion callback and a context that the 
+         It has now a completion callback and a context that the
          application must call after it has got the passphrase from
          the user.  Affected files lib/silcclient/silcapi.h,
          lib/silcclient/protocol.c, lib/silcclient/command.c and
@@ -6586,7 +6812,7 @@ Sat May 26 12:13:37 EEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
          as well.  Defined SilcVerifyPublicKey callback that is used to
          indicate the success of the public key verification process.
 
-         Changed the server and client to use the new async client 
+         Changed the server and client to use the new async client
          operations.
 
        * Changed the Irssi SILC client's internal scheduler to be called
@@ -6654,7 +6880,7 @@ Mon May 21 21:46:20 EEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
        * Replaced the client entry's `channel' list and channel entry's
          `user_list' list to hash tables for optimized lookup.  Changed
-         the code to use the hash table interface around the code. 
+         the code to use the hash table interface around the code.
          Affected file lib/silcd/idlist.[ch].
 
        * Added `auto_rehash' boolean argument to the function
@@ -6690,7 +6916,7 @@ Sat May 19 16:30:03 EEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
          with Client ID but with the hash of the ID (which is a hash of
          the nickname) as well without any difference in performance.
 
-         Added also silc_idcache_find_by_id_one_ext to do one on one 
+         Added also silc_idcache_find_by_id_one_ext to do one on one
          searching when we have the actual ID.  Added also function
          silc_hash_client_id_compare.  The affected files are
          lib/silccore/idcache.[ch] and lib/silcutil/silcutil.[ch].
@@ -6701,7 +6927,7 @@ Sat May 19 16:30:03 EEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
          case sensitive.
 
        * Fixed a bug in server with channel message sending.  It put
-         wrong ID type as destination ID.  The affected file 
+         wrong ID type as destination ID.  The affected file
          silcd/packet_send.c.
 
        * silc_idcache_del_by_context now deletes from all hash tables
@@ -6844,8 +7070,8 @@ Sun May  6 13:59:48 EEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
          The affected files are lib/silccore/id.[ch] and other files
          around the tree using these routines.
 
-       * Removed the ID length arguments in server from various 
-         silc_server_send_notify_* routines -> they are not needed 
+       * Removed the ID length arguments in server from various
+         silc_server_send_notify_* routines -> they are not needed
          anymore.
 
 Sat May  5 13:56:33 EEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
@@ -6886,7 +7112,7 @@ Wed May  2 13:31:26 EEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 Tue May  1 14:18:13 EEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
        * Fixed the silc_verify_public_key client operation function to
-         save the public keys differently.  The fingerprint is now 
+         save the public keys differently.  The fingerprint is now
          used as filename and not the hostname.  This way also the
          client keys are saved uniquely and not with hostnames.  The
          affected file is silc/client_ops.c.
@@ -7032,8 +7258,8 @@ Tue Apr 17 21:18:19 EEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
          incoming connection before executing any KE or authentication
          protocols.
 
-       * The connection configuration is now saved to the KE and 
-         connection auth protocol contexts and not fetched anymore in 
+       * The connection configuration is now saved to the KE and
+         connection auth protocol contexts and not fetched anymore in
          the protocol.  Affected files silcd/server.c, silcd/protocol.[ch].
 
        * The local hosts listenning address and port is also resolved
@@ -7053,7 +7279,7 @@ Tue Apr 17 21:18:19 EEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
        * Added function silc_server_config_is_primary_route to check
          whether primary router connection has been configured (a router
-         configuration that we are initiating).  If there is not, we 
+         configuration that we are initiating).  If there is not, we
          will assume that there is only two routers in the SILC network
          and we will use the incoming router connection as our primary
          route.  Affected files silcd/serverconfig.[ch], silcd/server.c.
@@ -7107,7 +7333,7 @@ Fri Apr 13 17:12:46 EEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
        * Removed the client's failure_callback handling with timeout
          and handle it immediately when received.
 
-       * The SKE library returned wrong type in SUCCESS and FAILURE 
+       * The SKE library returned wrong type in SUCCESS and FAILURE
          packets.  They must be 32 bit MSB not 16 bit MSB.
 
 Fri Apr 13 00:09:08 EEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
@@ -7146,7 +7372,7 @@ Wed Apr 11 22:10:15 EEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
          function is silc_[server/client]_packet_send_real to check
          the situation.
 
-       * Replaced the SIM paths from example config files to 
+       * Replaced the SIM paths from example config files to
          /usr/local/modules.  Also, make install creates now
          /usr/local/silc/logs directory to hold all the SILC server
          logs.
@@ -7255,10 +7481,10 @@ Thu Apr  5 17:42:30 EEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 Wed Apr  4 16:32:31 EEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
        * Do not ask whether user wants to use the negotiated private key
-         for private messages, just use it.  Affected file is 
+         for private messages, just use it.  Affected file is
          silc/local_command.c.
 
-       * Added `send_enc_key' and `enc_key_len' fields to the 
+       * Added `send_enc_key' and `enc_key_len' fields to the
          SilcIDListData structure since they are needed in the re-key
          phase.  Affected file is silcd/idlist.[ch].
 
@@ -7283,7 +7509,7 @@ Tue Apr  3 21:52:42 EEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
          int64 of at least the xintXX size.  If void * is less that 4
          bytes uint32 * will be used.  Defined bool as boolean.
 
-       * Changed _ALL_ unsigned long and unsigned int to uint32, 
+       * Changed _ALL_ unsigned long and unsigned int to uint32,
          unsgined short to uint16 in the source tree.
 
        * Fixed a fatal bug in silc_server_remove_clients_by_server.  Do
@@ -7321,7 +7547,7 @@ Tue Apr  3 16:39:19 EEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
          This fixes some bugs with WHOIS, WHOWAS and IDENTIFY commands
          and command replies.
 
-       * All command reply functions in the server now calls the 
+       * All command reply functions in the server now calls the
          pending command callback even if error occured.  This way the
          error will be delivered to the client as well.  Affected files
          silcd/command.c and silcd/command_reply.c.
@@ -7382,7 +7608,7 @@ Sun Apr  1 19:49:34 EEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
          code and the protocol specs.
 
        * A little fix to IDENTIFY command in the server.  Search the
-         client first by hash not nickname.  Affected file is 
+         client first by hash not nickname.  Affected file is
          silcd/command.c.
 
        * Fixed the silc_client_close_connection to support closing
@@ -7420,14 +7646,14 @@ Sun Apr  1 19:49:34 EEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
          server's CMODE command.  Affected file silcd/command.c.
 
        * Added the following new functions into lib/silccore/silcauth.[ch]:
-         silc_auth_get_method and silc_auth_get_data.    
+         silc_auth_get_method and silc_auth_get_data.
 
        * The server now saves the remote hosts public key to the
          SilcIDListData pointer.  Affected file silcd/protocol.c.
 
        * The normal server now does not remove the channel entry from
          the cache if the founder authentication data is set.  It used
-         to remove it if the founder was the last one on the channel on 
+         to remove it if the founder was the last one on the channel on
          the server and left the channel.  The auth data is saved and
          if the channel is re-joined later the old entry is used with
          the old auth data.  Affected files silcd/command_reply.c and
@@ -7520,7 +7746,7 @@ Wed Mar 28 23:55:54 EEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
          message to a channel with SILC_MESSAGE_FLAG_ACTION to indicate
          some action.  Affected file silc/local_command.[ch].
 
-       * Changed channel_message and private_message client operations 
+       * Changed channel_message and private_message client operations
          to deliver the message flags to the application.  Added also
          the `flags' arguments to the silc_client_send_channel_message
          and silc_client_send_private_message functions.  Affected file
@@ -7571,7 +7797,7 @@ Wed Mar 28 15:52:36 EEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
        * Added `sockets' and `sockets_count' fields to the SilcClient
          object.  They hold the sockets of the listenning sockets in
-         the client.  Listenning sockets may be for example the key 
+         the client.  Listenning sockets may be for example the key
          agreement server.  Affected file lib/silcclient/client.[ch].
          Added functions the silc_client_add_socket and the
          silc_client_del_socket.  They are exported to the application
@@ -7619,7 +7845,7 @@ Tue Mar 27 12:49:56 EEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
        * Added <cipher> and <hmac> argument to the CMODE_CHANGE notify
          type to indicate the change of the current cipher and hmac
          on the channel.  Client can safely ignore the <cipher> argument
-         (if it chooses to do so) since the CHANNEL_KEY packet will 
+         (if it chooses to do so) since the CHANNEL_KEY packet will
          force the channel key change anyway.  The <hmac> argument is
          important since the client is responsible of setting the new
          HMAC and the hmac key into use.
@@ -7638,7 +7864,7 @@ Mon Mar 26 14:39:48 EEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
          client must be removed from all channels when receiving the
          KILLED notify.
 
-         Also, do not remove the client entry when giving the KILL 
+         Also, do not remove the client entry when giving the KILL
          command but when the KILLED notify is received.
 
        * Removed silc_idlist_find_client_by_nickname from the server.
@@ -7683,7 +7909,7 @@ Sun Mar 25 13:52:51 EEST 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
        * Added silc_server_send_notify_ban to send the BAN notify
          type between routers.
 
-       * Chaned the silc_notify_payload_encode to support that if 
+       * Chaned the silc_notify_payload_encode to support that if
          argument is NULL it ignores and checks the next argument.
          Affected file lib/silccore/silcnotify.c.
 
@@ -7714,7 +7940,7 @@ Fri Mar 23 16:25:11 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
        * Added new command SILC_COMMAND_BAN that can be used to manage
          the ban list of the channel.  Updated the protocol specs.
 
-       * Removed the channel modes: the SILC_CMODE_BAN and the 
+       * Removed the channel modes: the SILC_CMODE_BAN and the
          SILC_CMODE_INVITE_LIST as they were a bit kludge to be included
          in the CMODE command.  The equivalent features are now available
          using INVITE and BAN commands.  Updated the protocol specs.
@@ -7723,7 +7949,7 @@ Fri Mar 23 16:25:11 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
          in the network about change in the current ban list.  The notify
          type is not used by the client.
 
-       * Redefined parts of the SILC_NOTIFY_TYPE_INVITE command to 
+       * Redefined parts of the SILC_NOTIFY_TYPE_INVITE command to
          support the invite lists.
 
 Thu Mar 22 22:52:23 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
@@ -7795,7 +8021,7 @@ Tue Mar 20 21:05:57 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
        * Fixed various bugs in WHOIS and IDENTIFY command handling as
          they were buggy because of the WHOWAS information.
 
-       * Fixed local command MSG to handle the async resolving of 
+       * Fixed local command MSG to handle the async resolving of
          the remote client properly.  It used to fail the first MSG.
          Affected file silc/local_command.c.
 
@@ -7812,7 +8038,7 @@ Tue Mar 20 15:45:14 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
          about the changed user mode.
 
          Implemented the notify handling in the server.  Affected file is
-         silcd/packet_receive.c.  Added the function 
+         silcd/packet_receive.c.  Added the function
          silc_server_send_notify_umode to the silcd/packet_send.[ch].
 
        * Added new generic Channel Payload and deprecated the New Channel
@@ -7880,7 +8106,7 @@ Mon Mar 19 16:13:07 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
          like _send_private_message_key, _relay_notify etc.  Affected
          file is silcd/packet_send.[ch].
 
-         Removed silc_server_send_key_agreement, 
+         Removed silc_server_send_key_agreement,
          silc_server_send_private_message_key and
          silc_server_packet_relay_notify functions from the file
          silcd/packet_send.[ch].
@@ -7900,7 +8126,7 @@ Mon Mar 19 16:13:07 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
          library in the file lib/silcclient/command.c.
 
        * Changed the silc_server_send_notify_on_channels's `sender'
-         argument from SilcSocketConnection to SilcClientEntry to 
+         argument from SilcSocketConnection to SilcClientEntry to
          check the sender as entry and not as connection object and not
          to send to the client provided as argument.  The affected file
          is silcd/packet_send.[ch].
@@ -7929,7 +8155,7 @@ Sun Mar 18 21:02:47 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
          it to the client.  Affected file silcd/packet_send.[ch].
 
          Added also silc_server_packet_process_relay_notify to check
-         whereto relay the notify.  Affected file is 
+         whereto relay the notify.  Affected file is
          silcd/packet_receive.[ch].
 
        * Implemented the KILL command to the server.
@@ -8061,7 +8287,7 @@ Tue Mar 13 22:17:34 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 Tue Mar 13 13:26:18 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
        * Added support to the server to enforce that commands are not
-         executed more than once in 2 seconds.  If server receives 
+         executed more than once in 2 seconds.  If server receives
          commands from client more frequently, timeout is registered
          to process the commands.  Affected file silcd/command.c.
          Added new function silc_server_command_process_timeout.
@@ -8072,12 +8298,12 @@ Tue Mar 13 13:26:18 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
        * Removed error printing from the WHOIS and IDENTIFY commands.
          If error occurs then it is ignored silently in the client library.
-         The application, however, may map the received error to 
+         The application, however, may map the received error to
          human readable error string.  The application currently maps
          the NO_SUCH_NICKNAME error to string.
 
        * Made the command status message public to the application.  Moved
-         them from lib/silcclient/command_reply.c to 
+         them from lib/silcclient/command_reply.c to
          lib/silcclient/command_reply.h.  The application can map the
          received command status to the string with the
          silc_client_command_status_message function.
@@ -8143,8 +8369,8 @@ Sun Mar 11 14:59:05 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
        * Added SilcChannelPrivateKey argument to the function
          silc_client_send_channel_message so that application can choose
          to use specific private ke if it wants to.  If it is not provided,
-         the normal channel key is used, unless private keys are set. 
-         In this case the first (key that was added first) is used 
+         the normal channel key is used, unless private keys are set.
+         In this case the first (key that was added first) is used
          as the encryption key.
 
        * Implemented the support for channel private key handling.
@@ -8170,7 +8396,7 @@ Sat Mar 10 21:36:22 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
        * Removed the statement that server (or router) must send USERS
          command reply when joining to the channel so that the client
-         knows who are on the channel.  Instead, the client list and 
+         knows who are on the channel.  Instead, the client list and
          client's mode list is now sent in the JOIN command reply to the
          client who joined channel.  This is better solution.
 
@@ -8207,7 +8433,7 @@ Fri Mar  9 12:40:42 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
          lib/silccore/silcchannel.[ch].
 
        * Moved the channel message etc, check from silc_packet_decrypt
-         to applications.  The library calls now a generic 
+         to applications.  The library calls now a generic
          SilcPacketCheckDecrypt callback which is to return TRUE or FALSE
          when the packet is either normal or special.  This was done to
          allow more wide range of checking that was not allowed when
@@ -8240,7 +8466,7 @@ Thu Mar  8 21:39:03 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
          file: lib/silcutil/silcbuffmt.c.
 
        * Changed to auto-reconnect to check whether the remote host is
-         router and register the re-connect timeout if it is.  It used 
+         router and register the re-connect timeout if it is.  It used
          to check that whether we are normal server, but router must do
          auto-reconnect with another router as well.  Affected file
          silcd/server.c.
@@ -8284,7 +8510,7 @@ Wed Mar  7 20:58:50 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
        * Redefined the mandatory HMAC algorithms and added new algorithms.
          Added hmac-sha1-96 and hmac-md5-96 which are normal hmac-sha1
-         and hmac-md5 truncated to 96 bits.  The mandatory is now 
+         and hmac-md5 truncated to 96 bits.  The mandatory is now
          hmac-sha1-96.  Rest are optional (including the one that used
          to be mandatory).  Rationale for this is that the truncated HMAC
          length is sufficient from security point of view and can actually
@@ -8355,7 +8581,7 @@ Tue Mar  6 15:36:11 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
          another remote client.  The key material is passed to the
          application after the protocol is over.
 
-       * Created client_keyagr.c to include all the key agreement 
+       * Created client_keyagr.c to include all the key agreement
          routines.
 
        * Added macro SILC_TASK_CALLBACK_GLOBAL which is equal to the
@@ -8425,7 +8651,7 @@ Tue Feb 27 20:24:25 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
          files: lib/silccrypt/silccipher.[ch].
 
        * Implemented silc silc_client_add_private_message_key,
-         silc_client_add_private_message_key_ske, 
+         silc_client_add_private_message_key_ske,
          silc_client_del_private_message_key,
          silc_client_list_private_message_keys and
          silc_client_free_private_message_keys functions in the
@@ -8474,7 +8700,7 @@ Mon Feb 26 12:13:58 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
          code accordingly.  The default key length is now 256 bits.
 
        * Fixed SKE key distribution function silc_ske_process_key_material
-         when the key length is more than 128 bits.  The default key 
+         when the key length is more than 128 bits.  The default key
          length in SILC is now 256 bits.
 
        * Added new command status type: SILC_STATUS_ERR_UNKOWN_ALGORITHM
@@ -8574,7 +8800,7 @@ Thu Feb 22 15:08:20 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
        * Also deprecated the following packet types: REPLACE_ID,
          NEW_CHANNEL_USER and REMOVE_CHANNEL_USER packet types.
-        
+
        * Added list support for Notify packet in server.
 
        * Added silc_server_send_notify_channel_change to send the
@@ -8591,12 +8817,12 @@ Thu Feb 22 15:08:20 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
        * Added silc_server_send_notify_leave to send LEAVE notify type.
          Deprecates the function silc_server_send_remove_channel_user.
 
-       * Added silc_server_send_notify_cmode and 
+       * Added silc_server_send_notify_cmode and
          silc_server_send_notify_cumode to send CMODE and CUMODE notify
          types.  Deprecates the silc_server_send_set_mode function.
 
        * Added SERVER_SIGNOFF notify type to indicate that server has
-         quit.  This means that all clients on the channel from that 
+         quit.  This means that all clients on the channel from that
          server will drop.  This can be also used when netsplit happens.
 
          Deprecated REMOVE_ID packet type since it is not needed anymore
@@ -8610,7 +8836,7 @@ Thu Feb 22 15:08:20 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
          SIGNOFF notify type.
 
        * Employed the PKCS #1. It is the mandatory way to do RSA in the
-         SILC protocol from this day on.  Changed the protocol 
+         SILC protocol from this day on.  Changed the protocol
          specification as well.
 
        * Added silc_server_send_notify_topic_set to send TOPIC_SET
@@ -8625,7 +8851,7 @@ Thu Feb 22 15:08:20 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
        * The JOIN notify type now takes one extra argument <Channel ID>.
          The packet used to be destined to the channel but now the
-         JOIN type may be sent as list thus it is impossible to 
+         JOIN type may be sent as list thus it is impossible to
          destine it to any specific channel.  By adding this argument
          it is again possible.
 
@@ -8678,7 +8904,7 @@ Tue Feb 20 14:14:14 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
        * Created Global RNG API which is global RNG that application can
          initialize.  After initializing, any routine anywhere in the
          code (including library) can use RNG without allocating a new
-         RNG object.  This was done to allow this sort of use of the 
+         RNG object.  This was done to allow this sort of use of the
          RNG in code that has no chance to allocate RNG object.  All
          applications currently allocate this and many routines in the
          library use this.  Affected file lib/silccrypt/silcrng.[ch].
@@ -8700,12 +8926,12 @@ Tue Feb 20 14:14:14 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
        * Added silc_pkcs_encrypt, silc_pkcs_decrypt, silc_pkcs_sign,
          silc_pkcs_verify and silc_pkcs_sign_with_hash and
-         silc_pkcs_verify_with_hash functions into the file 
+         silc_pkcs_verify_with_hash functions into the file
          lib/silccrypt/silcpkcs.[ch].
 
 Mon Feb 19 19:59:28 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
-       * The client entry's userinfo pointer must be always valid. 
+       * The client entry's userinfo pointer must be always valid.
          Otherwise the [<unknown>] bug will surface beacuse the WHOIS
          will fail since it requires the userinfo.  Now, the userinfo
          is allocated as "" if actual userinfo does not exist.  Actually,
@@ -8733,18 +8959,18 @@ Mon Feb 19 14:26:49 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
          All this applies for client library code as well.  Similar
          changes were made there as well for the pending commands.
 
-         In the client, the application must now allocate the 
+         In the client, the application must now allocate the
          SilcClientCommandContext with the silc_client_command_alloc
          function.
 
        * Added reference counter to the SilcServerCommandContext.  Added
-         function silc_server_command_alloc and silc_server_command_dup 
+         function silc_server_command_alloc and silc_server_command_dup
          functions.
 
          Same type of functions added to the client library for the same
          purpose as well.
 
-       * Removed the cmd_ident from IDListData away since it is now 
+       * Removed the cmd_ident from IDListData away since it is now
          global for all connections.  It is the command identifier used
          in command sending and with pending commands.  The affected file
          is silcd/idlist.h.
@@ -8843,7 +9069,7 @@ Fri Feb 16 23:57:29 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
        * Added new functions into the silcd/packet_receive.[ch]:
          silc_server_new_id_list, silc_server_new_channel_list and
-         silc_server_new_channel_user_list to handle the incoming 
+         silc_server_new_channel_user_list to handle the incoming
          NEW_ID_LIST, NEW_CHANNEL_LIST and NEW_CHANNEL_USER_LIST packets.
 
        * Added support of changing Channel ID in the function
@@ -8872,12 +9098,12 @@ Fri Feb 16 14:14:00 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 Thu Feb 15 20:07:37 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
        * Added new packet type SILC_PACKET_HEARTBEAT that is used to
-         send keepalive packets.  The packet can be sent by clients, 
+         send keepalive packets.  The packet can be sent by clients,
          servers and routers.
 
          Added function silc_socket_set_heartbeat into the file
          lib/silccore/silcsockconn.[ch] to set the heartbeat timeout.
-         If not set, the heartbeat is not performed.  The actual 
+         If not set, the heartbeat is not performed.  The actual
          heartbeat is implemented in the low level socket connection
          library.  However, application is responsible of actually
          sending the packet.
@@ -8910,7 +9136,7 @@ Thu Feb 15 20:07:37 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
          reverse order.  For this reason, MAC check failed.  Now, this
          is fixed by not sending the Channel Key packet immediately but
          putting it to queue.  However, this is more fundamental problem:
-         packets that are in queue should actually not be encrypted 
+         packets that are in queue should actually not be encrypted
          because packets that are sent immediately gets encrypted
          actually with wrong IV (and thus MAC check fails).  So, packets
          that are in queue should be encrypted when they are sent to
@@ -8951,7 +9177,7 @@ Wed Feb 14 16:03:25 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
          whether the requested user and group actually exists.
 
        * Added sanity check to SKE's silc_ske_responder_finish to check
-         that the public and private key actually is valid. 
+         that the public and private key actually is valid.
 
        * Invalidate the client's nickname when receiving Replace ID
          packet and the Client ID is being replaced.  This means that the
@@ -8970,8 +9196,8 @@ Wed Feb 14 16:03:25 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
        * Fixed some places where client was added to the IDList.  The
          rule of thumb is following (in order to get everything right):
-         If the client is directly connected local client then the 
-         `connection' argument must be set and `router' argument must be 
+         If the client is directly connected local client then the
+         `connection' argument must be set and `router' argument must be
          NULL to silc_idlist_add_client function.  If the client is not
          directly connected client then the `router' argument must
          bet set and the `connection' argument must be NULL to the
@@ -9025,7 +9251,7 @@ Sun Feb 11 18:19:51 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
 Sat Feb 10 21:13:45 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
-       * A big code auditing weekend happening.  Auditing code for 
+       * A big code auditing weekend happening.  Auditing code for
          obvious mistakes, bugs and errors.  Also, removing any code
          that is obsolete.
 
@@ -9040,11 +9266,11 @@ Sat Feb 10 21:13:45 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
          o The buffer formatting routines now check that the destination
          buffer really has enough space to add the data.  This applies for
-         both buffer formatting and unformatting 
+         both buffer formatting and unformatting
          (lib/silcutil/silcbuffmt.[ch]).  Also, the entire buffer
-         unformatting was changed to accomodate following rules: 
+         unformatting was changed to accomodate following rules:
          XXX_*STRING_ALLOC will allocate space for the data into the pointer
-         sent to the function while XXX_*STRING will not allocate or copy 
+         sent to the function while XXX_*STRING will not allocate or copy
          the data into the buffer.  Instead it sets the pointer from the
          buffer into the pointer sent as argument (XXX_*STRING used to
          require that the pointer must be allocated already).  This change
@@ -9081,8 +9307,8 @@ Sun Feb  4 13:18:32 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
          channels and clients channel modes) to all routers in the
          network.  Updated the protocol specification accordingly.
 
-         Added functions into silcd/packet_send.c and 
-         silcd/packet_receive.c: silc_server_send_set_mode, 
+         Added functions into silcd/packet_send.c and
+         silcd/packet_receive.c: silc_server_send_set_mode,
          silc_server_set_mode.
 
          Added new files silcmode.[ch] into lib/silccore that implements
@@ -9092,7 +9318,7 @@ Sun Feb  4 13:18:32 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
 Sat Feb  3 15:44:54 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
-       * Oops, a little mistake in server's connection authentication 
+       * Oops, a little mistake in server's connection authentication
          protocol.  The protocol is not ended with FAILURE but with
          SUCCESS if the authentication is Ok. :)  Affected file is
          silcd/protocol.c.
@@ -9102,13 +9328,13 @@ Sat Feb  3 15:44:54 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
          the local clients on the channel.  After the changing nickname
          in router environment snhould work and the [<unknown>] nickname
          should appear no more.
+
          The silc_server_replace_id function that receives the Replace ID
          payload now sends the NICK_CHANGE notify type also in the file
          silcd/packet_receive.c
 
        * Changed WHOIS and IDENTIFY command to support the maximum amount
-         of arguments defined in protocol specs (3328 arguments).  This 
+         of arguments defined in protocol specs (3328 arguments).  This
          fixed a bug that caused problems when there were more than three
          users on a channel.
 
@@ -9161,7 +9387,7 @@ Thu Feb  1 21:32:27 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
        * Fixed some minor bugs in client when sending WHOIS command.  The
          arguments was in wrong order.
 
-       * Removed statis function add_to_channel from server in 
+       * Removed statis function add_to_channel from server in
          silcd/command.c that was previously used with the joining but
          is obsolete now.
 
@@ -9201,7 +9427,7 @@ Tue Jan 30 22:39:15 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
          Changed the function silc_client_command_pending and
          silc_client_command_pending_del and added new function
-         silc_client_command_pending_check.  Removed the 
+         silc_client_command_pending_check.  Removed the
          SILC_CLIENT_CMD_REPLY_EXEC, and SILC_CLIENT_PENDING_COMMAND_CHECK
          macros.
 
@@ -9275,13 +9501,13 @@ Sun Jan 28 16:19:49 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
          global list who is joining and JOINs it to the channel.  This is
          for normal server, that is.
 
-         Changed silc_server_send_notify_on_channel, 
-         silc_server_packet_relay_to_channel and 
+         Changed silc_server_send_notify_on_channel,
+         silc_server_packet_relay_to_channel and
          silc_server_packet_send_to_channel check if we are normal server
          and client has router set (ie. global client) do not send the
          message to that client, as it is already routed to our router.
 
-       * Implemented LEAVE notify type handling in silc_server_notify 
+       * Implemented LEAVE notify type handling in silc_server_notify
          function.
 
        * Tested LEAVE command in router environment successfully.  Tested
@@ -9328,7 +9554,7 @@ Thu Jan 11 03:22:57 EET 2001  Pekka Riikonen <priikone@poseidon.pspt.fi>
          client.[ch] into client library.
 
        * Changed JOIN command reply to send information whether the channel
-         was created or not (is existing already) and the channel key 
+         was created or not (is existing already) and the channel key
          payload.  Changed protocol specs accordingly.
 
        * Fixed bugs in WHOIS and IDENTIFY command reply sending when
@@ -9340,7 +9566,7 @@ Sat Dec 23 21:55:07 EET 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
        * Fixed a bug in Client library.  IDENTIFY and WHOIS reply functions
          now correctly save the received data.
 
-       * silc_server_free_sock_user_data now notifies routers in the 
+       * silc_server_free_sock_user_data now notifies routers in the
          network about entities leaving the network.
 
          At the same time implemented functions silc_server_remove_id
@@ -9362,7 +9588,7 @@ Sat Dec 23 21:55:07 EET 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
          IDENTIFY command now also checks that client->nickname must be
          valid. If it is not if will request the data from the server who
-         owns the client.  Added new function 
+         owns the client.  Added new function
          silc_server_command_identify_check.
 
        * Added silc_command_set_command into lib/silccore/silcommand.[ch]
@@ -9390,7 +9616,7 @@ Sun Dec 17 14:40:08 EET 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
 Sat Dec 16 17:39:54 EET 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
        * Implemented version string checking to both client and server.
-         The check is incomplete currently due to the abnormal version 
+         The check is incomplete currently due to the abnormal version
          strings used in development version of SILC.
 
        * Changed all command functions in server to use the new
@@ -9402,7 +9628,7 @@ Fri Dec 15 15:55:12 EET 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
          support binary data as ID Cache data. Changed code to support
          binary data in lib/silccore/idcache.c.
 
-       * Renamed silc_server_packet_relay_command_reply to 
+       * Renamed silc_server_packet_relay_command_reply to
          silc_server_command_reply as it is normal packet receiving
          function. Rewrote the function to accept command replys for
          servers and not only for clients.
@@ -9491,7 +9717,7 @@ Mon Nov 27 21:39:40 EET 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
        * Fixed the JOIN command to really work in router environment.  If the
          channel is created it is always created by the router.  Router is
          also responsible of making the initial joining to the channel,
-         sending JOIN notify to the sending server and distributing 
+         sending JOIN notify to the sending server and distributing
          NEW_CHANNEL and NEW_CHANNEL_USER packets.  Hence, if the channel
          does not exist server doesn't do anything else but forward the
          command to the router which performs everything.
@@ -9552,7 +9778,7 @@ Tue Nov 21 19:49:31 EET 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
        * The channel key is now distributed to the local client as soon
          as it is received from the router (in router environment) so that
-         no other packet may be sent for the channel until client has 
+         no other packet may be sent for the channel until client has
          received the key.
 
        * silc_server_remove_channel_user now broadcasts the received
@@ -9575,7 +9801,7 @@ Tue Nov 21 19:49:31 EET 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
          silc_[client/server]_packet_parse_type the packet context must
          be duplicated by calling silc_packet_context_dup.  Otherwise it
          gets free'd after silc_[client/server]_packet_parse_type returns.
-         Also, one must remember that if packet is duplicated then its 
+         Also, one must remember that if packet is duplicated then its
          reference count must be decresed by calling the free function as
          many times as it was duplicated.
 
@@ -9685,7 +9911,7 @@ Sun Nov  5 22:28:44 EET 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
 Thu Nov  2 16:28:01 EET 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
-       * Changed client's channel table to SilcList and changed code 
+       * Changed client's channel table to SilcList and changed code
          accordingly.  Also changed SilcChannelClientEntry to include back-
          pointer to the channel so that client entry can use that structure
          as list as well and we have fast cross-reference to the channel.
@@ -9711,7 +9937,7 @@ Wed Nov  1 17:21:26 EET 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
        * NAMES command reply now shows users mode with the nickname when
          joining to channel.
 
-       * Moved silc_client_ch[u]mode[_char] functions from 
+       * Moved silc_client_ch[u]mode[_char] functions from
          silc/clientutil.[ch] to lib/silcclient/client.[ch].  Though, that
          place sucks, they are utility functions and should be in some
          other file.
@@ -9734,7 +9960,7 @@ Tue Oct 31 20:10:37 EET 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
          already defined as a list.  It is not suitable to add just some
          context to the list (in TRQ, the context is the list actually).
 
-         So, I defined SilcDList that can be used for the purpose where 
+         So, I defined SilcDList that can be used for the purpose where
          predefined list structure does not exit.  This can be used as
          such list.  Now some context just can be added to the SilcDList.
          Currently this list is not used in the SILC just yet, though there
@@ -9746,7 +9972,7 @@ Tue Oct 31 20:10:37 EET 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
          Also fixed some annoying warning messages that the original TRQ
          code generated.  Also minor changes to TRQ's Makefile.in.
 
-       * Added support for querying by Client ID to both WHOIS and 
+       * Added support for querying by Client ID to both WHOIS and
          IDENTIFY commands into server, as required by the protocol.
 
        * Removed method function pointers from SilcBuffer structure. They
@@ -9754,7 +9980,7 @@ Tue Oct 31 20:10:37 EET 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
          no good reason.  This change also made silc_buffer_alloc and
          silc_buffer_free functions inline functions.
 
-       * Disabled command flooding detection support until it's fixed so 
+       * Disabled command flooding detection support until it's fixed so
          that it accepts commands in but does not execute them more than once
          in two seconds.
 
@@ -9767,7 +9993,7 @@ Tue Oct 31 20:10:37 EET 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
          that the message is sent only once per client.
 
        * Moved silc_log_format (from lib/silcutil/silclog.[ch] into
-         lib/silcutil/silcutil.[ch] as silc_format function.  The new 
+         lib/silcutil/silcutil.[ch] as silc_format function.  The new
          function is generic and is used by server as well, not only by
          the logging routines.
 
@@ -9778,7 +10004,7 @@ Tue Oct 31 20:10:37 EET 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
          does not reside in the SKE library.  The function checks the version
          string remote end sent.
 
-       * Added back pointers (to opaque context and to SilcSocketConnection) 
+       * Added back pointers (to opaque context and to SilcSocketConnection)
          into SilcPacketContext structure into lib/silccore/silcpacket.h.
 
        * Added silc_packet_context_dup into lib/silccore/silcpacket.[ch] to
@@ -9791,14 +10017,14 @@ Tue Oct 31 20:10:37 EET 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
          to application (otherwise application doesn't know that it is for
          channel (library gets it from packet's Destination ID)).
 
-       * Added silc_client_remove_from_channels into client library to 
-         remove a client from all channels it has joined to.  Used when 
+       * Added silc_client_remove_from_channels into client library to
+         remove a client from all channels it has joined to.  Used when
          received SIGNOFF notify from server.  Added also new function
          silc_client_replace_from_channels to replace old ID entry with
          new ID entry on all channels.  Used when received NICK_CHANGE
          notify from server.
 
-       * Fixed ID Cache list handling in silc_idlist_get_client in 
+       * Fixed ID Cache list handling in silc_idlist_get_client in
          lib/silcclient/idlist.c.  Also, added silc_idlist_get_client_by_id
          to get (or query) client by ID.
 
@@ -9878,7 +10104,7 @@ Tue Oct 31 20:10:37 EET 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
 Mon Oct  9 20:57:02 EEST 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
-       * Changed SILC_COMMAND_IDENTIFY in protocol specification to 
+       * Changed SILC_COMMAND_IDENTIFY in protocol specification to
          accept searching by Client ID as well.
 
        * Added support for LEAVE and SIGNOFF notify types in client library.
@@ -10177,7 +10403,7 @@ Wed Jul 12 18:28:07 EEST 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
        * Added into lib/silccore/silcbufutil.[ch] new function;
          silc_buffer_realloc.
 
-       * Moved generic packet sending/encryption functions to 
+       * Moved generic packet sending/encryption functions to
          lib/silccore/silcpacket.[ch] from client and server.  Some
          rewriting of the functions.
 
@@ -10192,7 +10418,7 @@ Wed Jul 12 18:28:07 EEST 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
 Tue Jul 11 20:27:26 EEST 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
-       * Rewrote major parts of the ID cache system.  Don't know 
+       * Rewrote major parts of the ID cache system.  Don't know
          whether it is better now or not but at least the API is more
          cleaner now.
 
@@ -10249,7 +10475,7 @@ Thu Jul  6 18:12:24 EEST 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
        * Added public key verification process into client's protocol.c.
          The client now verifies the public key from user and saves
-         it into ~./silc/serverkeys/ directory. 
+         it into ~./silc/serverkeys/ directory.
 
          Added into: clientutil.[ch]: silc_client_verify_server_key.
 
@@ -10270,7 +10496,7 @@ Wed Jul  5 19:19:02 EEST 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
        * Removed wrong way of sending command status messages from
          server to client in server's command.c.  The old way violated
-         protocol specification.  
+         protocol specification.
 
          Changes to silccore/silccommand.[ch]: removed
          silc_command_encode_status_payload -> not needed anymore,
@@ -10320,7 +10546,7 @@ Sun Jul  2 18:23:01 EEST 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
 
        * Implemented LEAVE command on client and server.
 
-       * Previously deprecated SILC_PACKET_FORWARDED flag is now in use 
+       * Previously deprecated SILC_PACKET_FORWARDED flag is now in use
          again.  This change was made to the protocol as well.  Server
          should not violate the protocol specification anymore.
 
diff --git a/INSTALL b/INSTALL
index bca665aa58c77dc22198c5c71ae7ba7b89d038a3..25b5ea0464df3caf400658aba5d3891200bef981 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -14,8 +14,8 @@ into the /etc/silc/ directory.
 You may need to add the /usr/local/silc path to your PATH environment
 variable after the installation.
 
-Some Configuration Options
-==========================
+Configuration Options
+=====================
 
    You can give various options to the `configure' shell script.  You should
 give --help command to the `configure' to see all of them.  Here is listed
@@ -30,7 +30,7 @@ give the --with-gmp[=DIR] option to the `configure'.  The DIR is the upper
 path in your system which contains lib/ and include/ for GMP library.
    Note that MPI is the prefered arbitrary precision arithmetic library and
 GMP can be used as a fall-back if you have problems with the MPI library
-included within this package (GMP was used as a default library in the past).
+included within this package.
 
 '--with-iconv[=DIR]'
 
index e20a823ba1a666c4fa4d7d14d26135876147555d..2c1eae371f80b3ea10812edaba96cadf677785f6 100644 (file)
@@ -3,7 +3,7 @@
 #
 #  Author: Pekka Riikonen <priikone@silcnet.org>
 #
-#  Copyright (C) 2000 - 2002Pekka Riikonen
+#  Copyright (C) 2000 - 200Pekka Riikonen
 #
 #  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
@@ -44,6 +44,7 @@ modulesdir = $(DESTDIR)$(silc_modulesdir)
 helpdir = $(DESTDIR)$(silc_helpdir)
 docdir = $(DESTDIR)$(silc_docdir)
 logsdir = $(DESTDIR)$(silc_logsdir)
+mandir = $(DESTDIR)@mandir@
 
 install-dirs:
        -mkdir -p $(etcdir)
@@ -125,7 +126,7 @@ if SILC_DIST_CLIENT
 install-data-hook: install-dirs-client sim-install doc-install-client etc-install-client
 else
 if SILC_DIST_TOOLKIT
-install-data-hook: install-dirs-client install-dirs-server sim-install doc-install-client doc-install-server toolkit-install examples-install etc-install-client etc-install-server generate-server-key
+install-data-hook: install-dirs-client install-dirs-server sim-install doc-install-client doc-install-server toolkit-install examples-install etc-install-client etc-install-server
 else
 install-data-hook: install-dirs-server sim-install doc-install-server examples-install etc-install-server generate-server-key
 endif
diff --git a/README b/README
index af28918b39fe37cf809b7625b207ac5fcfa30f3c..4ed2fba46b2cbae88c5fb6a5382ed14b85d04192 100644 (file)
--- a/README
+++ b/README
@@ -116,3 +116,4 @@ Official SILC project web site      : http://silcnet.org/
 FTP archive for SILC project        : ftp://ftp.silcnet.org/
 Development mailing list address    : silc-devel@lists.silcnet.org
 SILC Server                         : /server silc.silcnet.org
+
diff --git a/TODO b/TODO
index fb406ebf08244fe59856794c6d19d51355ec9b14..416a3cf15cc1344ccdf0f98fcf948d344ea144b8 100644 (file)
--- a/TODO
+++ b/TODO
@@ -9,15 +9,6 @@ TODO for Irssi SILC Client 1.0
 TODO for SILC Server 1.0
 ========================
 
- o INVITE and BAN notifys send the entire list as notify, but only the
-   added/removed info should be sent.
-
- o The CMODE cipher & hmac change problem (#101).
-
- o Fix CUMODE_CHANGE and CMODE_CHANGE for founder key things.
-
- o 1.2 backup router support
-
  o Testing
 
 
@@ -43,5 +34,5 @@ Manual (Do these to 0.9.x).
    example), and how external projects can use Toolkit without gluing into
    it (how to link etc), debugging, architecture, types, etc.
 
- o Searching of predefined keywords, exact and partial matches (would be 
+ o Searching of predefined keywords, exact and partial matches (would be
    nice).
index b3f341265de848319fbd4489974af063d0d30766..73e5a27bc4c2bbffb83c63e54fe1872255e611ff 100644 (file)
--- a/TODO-1.0
+++ b/TODO-1.0
@@ -124,6 +124,14 @@ least could be done.
          SIGNOFF of notify at all (using SIGNOFF takes the idea about
          SERVER_SIGNOFF away entirely).
 
+        o Another SERVER_SIGNOFF opt/bugfix:  Currently the signoff is
+          sent to a client if it is on same channel as the client that
+          signoffed.  However, the entire SERVER_SIGNOFF list is sent to
+          the client, ie. it may receive clients that was not on the 
+          same channel.  This is actually against the specs.  It must be
+          done per channel.  It shouldn't receive the whole list just
+          because one client happened to be on same channel.
+
        o See also ~/silcserver
 
  o Add SilcAsyncOperation to utility library.  Any function that takes
@@ -172,3 +180,4 @@ least could be done.
 
  o Check whether we can fully comply with RFC 2779.
 
+ o The CMODE cipher & hmac change problem (#101).
index e4cf6b4cddf93df9b84ef12a1d8d41a09205a664..ccf77840552b338b7688f20e2f99bba65acdffcc 100644 (file)
@@ -14,7 +14,7 @@ The following modes are available:
     s               Set/unset channel as secret channel
     k               Enable/disable channel private key usage (*)
     i               Set/unset channel as invite only channel
-    t               Set/unset that only channel operator or 
+    t               Set/unset that only channel operator or
                     founder may set channel topic
     m               Set/unset user silencing.  Normal users
                     are not able to talk on channel. (*)
@@ -41,6 +41,29 @@ The following modes are available:
                     server.  If these are omitted then the default
                     SILC keypair is used.  Normally you do not need
                     to provide these arguments.
+    C [{[+|-]<pubkeyfile> }]                                (*)
+                    Set/unset channel public key mode, and add/remove
+                    channel publics key from the channel public key
+                    list.  When this mode is set only those users
+                    whose public keys has been added to the list are
+                    able to join the channel.  Channel founder may set
+                    this mode and operate on the channel public key
+                    list.
+
+                    To add public key to the list give command:
+                    CMODE +C +/path/to/the/public_key_file.pub
+
+                    To remove one public key from the list give
+                    command:
+                    CMODE +C -/path/to/the/public_key_file.pub
+
+                    To add or remove more than one public keys add as
+                    many public key file paths as necessary.
+
+                    When this mode is unset (-C), all public keys are
+                    removed from the list.  If +C is given without
+                    arguments the current channel public key list is
+                    displayed.
 
 Multiple modes can be set/unset at once if the modes does not
 require any arguments.  If mode requires an argument then only
index bd95134542b70bd610b752ff9ca680a07b0dd1c1..3812019b0bccbb19c02d8d19e3d1d6ce8cdd22b7 100644 (file)
@@ -1,8 +1,9 @@
 
 @SYNTAX:join@
 
-Joins a specified channel. Channel names usually begin with #-sign,
-but note that the #-sign is not mandatory in channel names.
+Joins a specified channel.  Note that, in SILC the #-sign is NOT
+mandatory part of the channel names, and names "#foo" and "foo" will
+join to two different channels.
 
 If -cipher is provided and the channel does not exist the cipher to
 secure the channel messages on the channel will be set to <cipher>.  If
@@ -16,9 +17,17 @@ or is invite-only channel the founder can override these conditions
 and join the channel.  Only the client who set the founder mode on the
 channel is able to use -founder option.
 
+If the channel has the +C (channel public key authentication,
+see /HELP CMODE) mode set then the user joining the channel must
+provide the -auth option to JOIN command.  This option will attempt to
+authenticate the user on the channel.  If the user's public key has
+not been added to the channel's public key list, user will not be
+able to join.  User may optionally provide the <pubkeyfile>,
+<privkeyfile> and <privkey passphrase> to authenticate with some other
+key pair than with the user's default key pair.
+
 JOIN is aliased to J by default.
 
 Description
 
 See also: LEAVE, WINDOW CLOSE, CMODE, CUMODE
-
index a14b49f1d681177ea7e0abd76f07e4664eb0355c..054904d89286aea6d15c3d34218d86197f1f58a2 100644 (file)
@@ -75,14 +75,14 @@ Commands:
     sender with the hostname and port of your key agreement
     server with this command.
 
-    If the hostname and port are ommitted, the irssi boolean
+    If the hostname and port are ommitted, the boolean
     variable use_auto_addr will be examined.  If it is set
     the value of auto_bind_ip will be used as the IP address
     to listen for the return reply, the value of auto_public_ip
     will be the IP address sent to the remote client, and the
     auto_bind_port will be the port value to be bound to and
     sent to the remote client.  If auto_public_ip is unset, but
-    auto_bind_ip is set, irssi will send the auto_bind_ip
+    auto_bind_ip is set, silc client will send the auto_bind_ip
     variable's value to the remote client.
 
   negotiate  [<hostname> [<port>]]
index 86d3fb19e92a7b609d36cbf44072ee7e6cd3fc95..3a3ac2721c61072de16102afe812916c7b830f93 100644 (file)
@@ -15,7 +15,7 @@ The default theme of Irssi SILC Client shows the digital signed
 messages with [S] at start of the nickname who sent the message, when
 the message was successfully verified, [?] if the message could not
 be verified since the public key of the sender isn't cached locally,
-or [F] if the signature verificationn failed.  If you do not have
+or [F] if the signature verification failed.  If you do not have
 the sender's public key you can fetch it with GETKEY command.
 
 If you don't want to verify the signatures from received messages
index d153a023e55f76e54f2a410ef1d22c88bdfc0361..b47f9b9ad4f504bd5021a4af4f21882ee1bcd775 100644 (file)
@@ -2,10 +2,11 @@
 @SYNTAX:whois@
 
 Shows WHOIS information of the specified client. By default,
-this is aliased to /WI. If the -details option is used WHOIS
-will retrieve as detailed information about the user as possible.
-Using this option WHOIS MAY return following information about
-the user:
+this is aliased to /WI.
+
+If the -details option is used WHOIS will retrieve as detailed
+information about the user as possible.  Using this option WHOIS
+MAY return following information about the user:
 
   o User's public key
   o Business card of the user (VCard)
@@ -18,10 +19,13 @@ the user:
   o User's geographical location
   o Information about the device user is using (computer, PDA, etc)
 
-It is also possible to receive other information. Note that all
-users do not want to send these informations or may send only
+NOTE: It is also possible to receive other information. Note that
+all users do not want to send these informations or may send only
 some of the information. It also possible that none of these
-informations is received.
+informations is received.  It also possible that some server
+responds to your request on the behalf of the user if the user
+does not want to respond to you.  In this case the returned
+information may be incomplete.
 
 If you want to send your information in WHOIS you can set the
 information with ATTR command.  See HELP ATTR.
index df582873684ceb8a2429812ddff940d0398c4337..7c03fad5584641bfe80fffb6bdbef06bff5a85f5 100644 (file)
@@ -324,3 +324,12 @@ gui-readline.c:
 
 gui-printtext.c:
  "beep"
+
+SILC
+---
+
+silc-channels.c:
+ "mime", SERVER_REC, CHANNEL_REC, char *blob, char *enc, char *type, char *nick
+
+silc-servers.c:
+ "mime-send", SERVER_REC, WI_ITEM_REC, char *blob, char *enc, char *type
index 09440ca5c9c5c4606944c3566f705fe22c73785f..367702286edf0a26d78673a2eb526c0402b0c40a 100644 (file)
@@ -1,16 +1,15 @@
 /*
 
-  modules-formats.c
+  module-formats.c
 
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+  Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2001 Pekka Riikonen
+  Copyright (C) 2001 - 2003 Pekka Riikonen
 
   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.
-  
+  the Free Software Foundation; version 2 of the License.
+
   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
@@ -80,6 +79,9 @@ FORMAT_REC fecommon_silc_formats[] = {
        { "no_msgs_sent", "You have not sent a message to anyone yet", 0 },
        { "own_msg_private_signed", "{ownprivmsg_signed msg $0}$1", 2, { 0, 0 } },
        { "own_msg_private_query_signed", "{ownprivmsgnick_signed {ownprivnick $2}}$1", 3, { 0, 0, 0 } },
+       { "channel_pk_list", "Channel {channel $0} Public Key List:", 1, { 0 } },
+       { "channel_pk_list_entry", "$0 - {channel $1}: $2 $3: Fingerprint (SHA1) {ban $4} (Babbleprint (SHA1) {ban $5})", 6, { 1, 0, 0, 0, 0, 0 } },
+       { "channel_pk_no_list", "No Channel Public Key List for {channel $0}", 1, { 0 } },
 
        /* WHOIS, WHOWAS and USERS (alias WHO) messages */
        { NULL, "Who Queries", 0 },
index 7df09206b9ec5be9a67ed4a584c2eb715e912e71..f46e6ea2862d7b8e4edbdfc35be8b452de825b22 100644 (file)
@@ -1,16 +1,15 @@
 /*
 
-  modules-formats.h
+  module-formats.h
 
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+  Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2001 Pekka Riikonen
+  Copyright (C) 2001 - 2003 Pekka Riikonen
 
   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.
-  
+  the Free Software Foundation; version 2 of the License.
+
   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
@@ -22,9 +21,9 @@
 
 enum {
   SILCTXT_MODULE_NAME,
-  
+
   SILCTXT_FILL_1,
-  
+
   SILCTXT_CHANNEL_FOUNDER_YOU,
   SILCTXT_CHANNEL_FOUNDER,
   SILCTXT_CHANNEL_TOPIC,
@@ -77,6 +76,9 @@ enum {
   SILCTXT_NO_MSGS_SENT,
   SILCTXT_OWN_MSG_PRIVATE_SIGNED,
   SILCTXT_OWN_MSG_PRIVATE_QUERY_SIGNED,
+  SILCTXT_CHANNEL_PK_LIST,
+  SILCTXT_CHANNEL_PK_LIST_ENTRY,
+  SILCTXT_CHANNEL_PK_NO_LIST,
 
   SILCTXT_FILL_2,
 
index 006178be04b154c42d9eeac195a41d68019c63c6..98f3398f0b3c3f717bfdc9b85ee67b8e290132dc 100644 (file)
@@ -22,7 +22,8 @@ libsilc_core_a_SOURCES = \
        silc-queries.c \
        silc-servers.c \
        silc-expandos.c \
-       silc-servers-reconnect.c
+       silc-servers-reconnect.c \
+       silc-lag.c
 
 noinst_HEADERS = \
        module.h \
@@ -33,5 +34,5 @@ noinst_HEADERS = \
        silc-nicklist.h \
        silc-commands.h \
        silc-queries.h \
-       silc-servers.h
+       silc-servers.h 
 
index 2f9c7541ca5382d9976b8b6a2896b2e86f861640..476fbeda80d86fcaf14452563f78aa176807ef19 100644 (file)
@@ -4,13 +4,13 @@
 
   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
 
-  Copyright (C) 2001 Pekka Riikonen
+  Copyright (C) 2001 - 2003 Pekka Riikonen
 
   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
 
 #include "core.h"
 
-static void 
+static void
 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
-                               const char *name, SilcSocketType conn_type, 
-                               unsigned char *pk, SilcUInt32 pk_len, 
+                               const char *name, SilcSocketType conn_type,
+                               unsigned char *pk, SilcUInt32 pk_len,
                                SilcSKEPKType pk_type,
                                SilcVerifyPublicKey completion, void *context);
 
-static void silc_get_umode_string(SilcUInt32 mode, char *buf, 
+static void silc_get_umode_string(SilcUInt32 mode, char *buf,
                                  SilcUInt32 buf_size)
 {
   if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
@@ -84,7 +84,7 @@ static void silc_get_umode_string(SilcUInt32 mode, char *buf,
 }
 
 /* print "nick appears as" message to every channel of a server */
-static void 
+static void
 silc_print_nick_change_channel(SILC_SERVER_REC *server, const char *channel,
                              const char *newnick, const char *oldnick,
                              const char *address)
@@ -92,7 +92,7 @@ silc_print_nick_change_channel(SILC_SERVER_REC *server, const char *channel,
   if (ignore_check(SERVER(server), oldnick, address,
                   channel, newnick, MSGLEVEL_NICKS))
     return;
-  
+
   printformat_module("fe-common/silc", server, channel, MSGLEVEL_NICKS,
                     SILCTXT_CHANNEL_APPEARS,
                     oldnick, newnick, channel, address);
@@ -107,7 +107,7 @@ silc_print_nick_change(SILC_SERVER_REC *server, const char *newnick,
   /* Print to each channel/query where the nick is.
      Don't print more than once to the same window. */
   windows = NULL;
-    
+
   for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
     CHANNEL_REC *channel = tmp->data;
     WINDOW_REC *window = window_item_window((WI_ITEM_REC *) channel);
@@ -124,6 +124,53 @@ silc_print_nick_change(SILC_SERVER_REC *server, const char *newnick,
   g_slist_free(windows);
 }
 
+static void silc_parse_channel_public_keys(SILC_SERVER_REC *server,
+                                          SilcChannelEntry channel_entry,
+                                          SilcBuffer channel_pubkeys)
+{
+  SilcUInt16 argc;
+  SilcArgumentPayload chpks;
+  unsigned char *pk;
+  SilcUInt32 pk_len, type;
+  int c = 1;
+  char *fingerprint, *babbleprint;
+  SilcPublicKey pubkey;
+  SilcPublicKeyIdentifier ident;
+
+  printformat_module("fe-common/silc", server, NULL,
+                    MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_LIST,
+                    channel_entry->channel_name);
+
+  SILC_GET16_MSB(argc, channel_pubkeys->data);
+  chpks = silc_argument_payload_parse(channel_pubkeys->data + 2,
+                                     channel_pubkeys->len - 2, argc);
+  if (!chpks)
+    return;
+
+  pk = silc_argument_get_first_arg(chpks, &type, &pk_len);
+  while (pk) {
+    fingerprint = silc_hash_fingerprint(NULL, pk + 4, pk_len - 4);
+    babbleprint = silc_hash_babbleprint(NULL, pk + 4, pk_len - 4);
+    silc_pkcs_public_key_payload_decode(pk, pk_len, &pubkey);
+    ident = silc_pkcs_decode_identifier(pubkey->identifier);
+
+    printformat_module("fe-common/silc", server, NULL,
+                      MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_LIST_ENTRY,
+                      c++, channel_entry->channel_name,
+                      type == 0x00 ? "Added" : "Removed",
+                      ident->realname ? ident->realname : "",
+                      fingerprint, babbleprint);
+
+    silc_free(fingerprint);
+    silc_free(babbleprint);
+    silc_pkcs_public_key_free(pubkey);
+    silc_pkcs_free_identifier(ident);
+    pk = silc_argument_get_next_arg(chpks, &type, &pk_len);
+  }
+
+  silc_argument_payload_free(chpks);
+}
+
 void silc_say(SilcClient client, SilcClientConnection conn,
              SilcClientMessageType type, char *msg, ...)
 {
@@ -132,7 +179,7 @@ void silc_say(SilcClient client, SilcClientConnection conn,
   char *str;
 
   server = conn == NULL ? NULL : conn->context;
-  
+
   va_start(va, msg);
   str = g_strdup_vprintf(msg, va);
   printtext(server, NULL, MSGLEVEL_CRAP, "%s", str);
@@ -194,17 +241,17 @@ int verify_message_signature(SilcClientEntry sender,
   else
     /* no idea, who or what signed that message ... */
     return SILC_MSG_SIGNED_UNKNOWN;
-  
+
   /* search our local client key cache */
   for (i = 0; i < strlen(fingerprint); i++)
     if (fingerprint[i] == ' ')
       fingerprint[i] = '_';
-    
+
   snprintf(file, sizeof(file) - 1, "clientkey_%s.pub", fingerprint);
-  snprintf(filename, sizeof(filename) - 1, "%s/clientkeys/%s", 
+  snprintf(filename, sizeof(filename) - 1, "%s/clientkeys/%s",
           get_irssi_dir(), file);
   silc_free(fingerprint);
-  
+
   if (stat(filename, &st) < 0)
     /* we don't have the public key cached ... use the one from the sig */
     ret = SILC_MSG_SIGNED_UNKNOWN;
@@ -213,9 +260,9 @@ int verify_message_signature(SilcClientEntry sender,
 
     /* try to load the file */
     if (!silc_pkcs_load_public_key(filename, &cached_pk, SILC_PKCS_FILE_PEM) &&
-       !silc_pkcs_load_public_key(filename, &cached_pk, 
+       !silc_pkcs_load_public_key(filename, &cached_pk,
                                   SILC_PKCS_FILE_BIN)) {
-      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
+      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_PUBKEY_COULD_NOT_LOAD, "client");
       if (pk == NULL)
        return SILC_MSG_SIGNED_UNKNOWN;
@@ -226,12 +273,12 @@ int verify_message_signature(SilcClientEntry sender,
     if (cached_pk) {
       if (pk)
         silc_pkcs_public_key_free(pk);
-      pk = cached_pk; 
+      pk = cached_pk;
     }
   }
 
   /* the public key is now in pk, our "level of trust" in ret */
-  if ((pk) && silc_message_signed_verify(sig, message, pk, 
+  if ((pk) && silc_message_signed_verify(sig, message, pk,
                                         silc_client->sha1hash)!= SILC_AUTH_OK)
     ret = SILC_MSG_SIGNED_FAILED;
 
@@ -241,7 +288,69 @@ int verify_message_signature(SilcClientEntry sender,
   return ret;
 }
 
-/* Message for a channel. The `sender' is the nickname of the sender 
+char * silc_unescape_data(const char *escaped_data, SilcUInt32 *length)
+{
+  SilcUInt32 ctr, dest=0;
+  char *data;
+
+  data = silc_calloc(strlen(escaped_data), sizeof(char));
+  
+  for (ctr = 0; ctr < strlen(escaped_data); ctr++)
+    if (escaped_data[ctr] == 1)
+      data[dest++] = escaped_data[++ctr] - 1;
+    else
+      data[dest++] = escaped_data[ctr];
+
+  *length = dest;
+  return data;
+}
+
+char * silc_escape_data(const char *data, SilcUInt32 len)
+{
+  char *escaped_data;
+  SilcUInt32 ctr, zeros=0;
+
+  for (ctr = 0; ctr < len; ctr++)
+    if (data[ctr] == 0 || data[ctr] == 1)
+      zeros++;
+
+  escaped_data = silc_calloc(zeros + len, sizeof(char));
+
+  zeros=0;
+  for (ctr = 0; ctr < len; ctr++)
+    switch (data[ctr]) {
+      case 0:
+       escaped_data[zeros++] = 1;
+       escaped_data[zeros++] = 1;
+       break;
+
+      case 1:
+       escaped_data[zeros++] = 1;
+       escaped_data[zeros++] = 2;
+       break;
+
+      default:
+       escaped_data[zeros++] = data[ctr];
+    } 
+
+    return escaped_data;
+}
+
+void silc_emit_mime_sig(SILC_SERVER_REC *server, SILC_CHANNEL_REC *channel,
+               const char *data, SilcUInt32 data_len,
+               const char *encoding, const char *type, const char *nick)
+{
+   char *escaped_data;
+
+   escaped_data = silc_escape_data(data, data_len);
+
+   signal_emit("mime", 6, server, channel, escaped_data, encoding, type, nick);
+   silc_free(escaped_data);
+}
+
+
+/* Message for a channel. The `sender' is the nickname of the sender
    received in the packet. The `channel_name' is the name of the channel. */
 
 void silc_channel_message(SilcClient client, SilcClientConnection conn,
@@ -254,7 +363,7 @@ void silc_channel_message(SilcClient client, SilcClientConnection conn,
   SILC_NICK_REC *nick;
   SILC_CHANNEL_REC *chanrec;
   int verified = 0;
-  
+
   SILC_LOG_DEBUG(("Start"));
 
   if (!message)
@@ -264,7 +373,7 @@ void silc_channel_message(SilcClient client, SilcClientConnection conn,
   chanrec = silc_channel_find_entry(server, channel);
   if (!chanrec)
     return;
-  
+
   nick = silc_nicklist_find(chanrec, sender);
   if (!nick) {
     /* We didn't find client but it clearly exists, add it. */
@@ -282,7 +391,7 @@ void silc_channel_message(SilcClient client, SilcClientConnection conn,
       flags &= ~SILC_MESSAGE_FLAG_SIGNED;
     }
   }
-  
+
   if (flags & SILC_MESSAGE_FLAG_DATA) {
     /* MIME object received, try to display it as well as we can */
     char type[128], enc[128];
@@ -301,9 +410,8 @@ void silc_channel_message(SilcClient client, SilcClientConnection conn,
       /* It is something textual, display it */
       message = (const unsigned char *)data;
     } else {
-      printformat_module("fe-common/silc", server, channel->channel_name,
-                        MSGLEVEL_CRAP, SILCTXT_MESSAGE_DATA,
-                        nick == NULL ? "[<unknown>]" : nick->nick, type);
+      silc_emit_mime_sig(server, chanrec, data, data_len,
+               enc, type, nick == NULL ? NULL : nick->nick);
       message = NULL;
     }
   }
@@ -314,13 +422,47 @@ void silc_channel_message(SilcClient client, SilcClientConnection conn,
   /* FIXME: replace those printformat calls with signals and add signature
             information to them (if present) */
   if (flags & SILC_MESSAGE_FLAG_ACTION)
-    printformat_module("fe-common/silc", server, channel->channel_name,
-                      MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION, 
-                       nick == NULL ? "[<unknown>]" : nick->nick, message);
+    if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
+      char tmp[256], *cp, *dm = NULL;
+      memset(tmp, 0, sizeof(tmp));
+      cp = tmp;
+      if(message_len > sizeof(tmp) - 1) {
+        dm = silc_calloc(message_len + 1, sizeof(*dm));
+        cp = dm;
+      }
+      silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
+                       cp, message_len);
+      printformat_module("fe-common/silc", server, channel->channel_name,
+                         MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION,
+                         nick == NULL ? "[<unknown>]" : nick->nick, cp);
+      silc_free(dm);
+    } else {
+      printformat_module("fe-common/silc", server, channel->channel_name,
+                         MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION,
+                         nick == NULL ? "[<unknown>]" : nick->nick,
+                         message);
+    }
   else if (flags & SILC_MESSAGE_FLAG_NOTICE)
-    printformat_module("fe-common/silc", server, channel->channel_name,
-                      MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE, 
-                       nick == NULL ? "[<unknown>]" : nick->nick, message);
+    if(flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
+      char tmp[256], *cp, *dm = NULL;
+      memset(tmp, 0, sizeof(tmp));
+      cp = tmp;
+      if(message_len > sizeof(tmp) - 1) {
+        dm = silc_calloc(message_len + 1, sizeof(*dm));
+        cp = dm;
+      }
+      silc_utf8_decode(message, message_len, SILC_STRING_LANGUAGE,
+                       cp, message_len);
+      printformat_module("fe-common/silc", server, channel->channel_name,
+                         MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE,
+                         nick == NULL ? "[<unknown>]" : nick->nick, cp);
+      silc_free(dm);
+    } else {
+      printformat_module("fe-common/silc", server, channel->channel_name,
+                         MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE,
+                         nick == NULL ? "[<unknown>]" : nick->nick,
+                         message);
+    }
   else {
     if (flags & SILC_MESSAGE_FLAG_UTF8 && !silc_term_utf8()) {
       char tmp[256], *cp, *dm = NULL;
@@ -373,7 +515,7 @@ void silc_private_message(SilcClient client, SilcClientConnection conn,
   SILC_SERVER_REC *server;
   char userhost[256];
   int verified = 0;
-  
+
   SILC_LOG_DEBUG(("Start"));
 
   server = conn == NULL ? NULL : conn->context;
@@ -391,7 +533,7 @@ void silc_private_message(SilcClient client, SilcClientConnection conn,
       flags &= ~SILC_MESSAGE_FLAG_SIGNED;
     }
   }
-  
+
   if (flags & SILC_MESSAGE_FLAG_DATA) {
     /* MIME object received, try to display it as well as we can */
     char type[128], enc[128];
@@ -410,10 +552,9 @@ void silc_private_message(SilcClient client, SilcClientConnection conn,
       /* It is something textual, display it */
       message = (const unsigned char *)data;
     } else {
-      printformat_module("fe-common/silc", server, NULL,
-                        MSGLEVEL_CRAP, SILCTXT_MESSAGE_DATA,
-                        sender->nickname ? sender->nickname : "[<unknown>]",
-                        type);
+      silc_emit_mime_sig(server, NULL, data, data_len,
+                       enc, type, sender->nickname ? sender->nickname :
+                                  "[<unknown>]");
       message = NULL;
     }
   }
@@ -479,13 +620,14 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
   char buf[512];
   char *name, *tmp;
   GSList *list1, *list_tmp;
+  SilcBuffer buffer;
 
   SILC_LOG_DEBUG(("Start"));
 
   va_start(va, type);
 
   server = conn == NULL ? NULL : conn->context;
-  
+
   switch(type) {
   case SILC_NOTIFY_TYPE_NONE:
     /* Some generic notice from server */
@@ -514,7 +656,7 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
     /*
      * Joined channel.
      */
+
     SILC_LOG_DEBUG(("Notify: JOIN"));
 
     client_entry = va_arg(va, SilcClientEntry);
@@ -533,7 +675,7 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
          nickrec = silc_nicklist_insert(chanrec, chu, TRUE);
       }
     }
-    
+
     memset(buf, 0, sizeof(buf));
     if (client_entry->username)
     snprintf(buf, sizeof(buf) - 1, "%s@%s",
@@ -552,13 +694,13 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
 
     client_entry = va_arg(va, SilcClientEntry);
     channel = va_arg(va, SilcChannelEntry);
-    
+
     memset(buf, 0, sizeof(buf));
     if (client_entry->username)
       snprintf(buf, sizeof(buf) - 1, "%s@%s",
               client_entry->username, client_entry->hostname);
     signal_emit("message part", 5, server, channel->channel_name,
-               client_entry->nickname,  client_entry->username ? 
+               client_entry->nickname,  client_entry->username ?
                buf : "", client_entry->nickname);
 
     chanrec = silc_channel_find_entry(server, channel);
@@ -578,7 +720,7 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
 
     client_entry = va_arg(va, SilcClientEntry);
     tmp = va_arg(va, char *);
-    
+
     silc_server_free_ftp(server, client_entry);
 
     /* Print only if we have the nickname.  If this cliente has just quit
@@ -590,16 +732,16 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
         snprintf(buf, sizeof(buf) - 1, "%s@%s",
                 client_entry->username, client_entry->hostname);
       signal_emit("message quit", 4, server, client_entry->nickname,
-                 client_entry->username ? buf : "", 
+                 client_entry->username ? buf : "",
                  tmp ? tmp : "");
     }
 
     list1 = nicklist_get_same_unique(SERVER(server), client_entry);
-    for (list_tmp = list1; list_tmp != NULL; list_tmp = 
+    for (list_tmp = list1; list_tmp != NULL; list_tmp =
           list_tmp->next->next) {
       CHANNEL_REC *channel = list_tmp->data;
       NICK_REC *nickrec = list_tmp->next->data;
-      
+
       nicklist_remove(channel, nickrec);
     }
     break;
@@ -615,7 +757,7 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
     entry = va_arg(va, void *);
     tmp = va_arg(va, char *);
     channel = va_arg(va, SilcChannelEntry);
-    
+
     chanrec = silc_channel_find_entry(server, channel);
     if (chanrec != NULL) {
       char tmp2[256], *cp, *dm = NULL;
@@ -639,7 +781,7 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
 
       silc_free(dm);
     }
-    
+
     if (idtype == SILC_ID_CLIENT) {
       client_entry = (SilcClientEntry)entry;
       memset(buf, 0, sizeof(buf));
@@ -650,7 +792,7 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
     } else if (idtype == SILC_ID_SERVER) {
       server_entry = (SilcServerEntry)entry;
       signal_emit("message topic", 5, server, channel->channel_name,
-                 tmp, server_entry->server_name, 
+                 tmp, server_entry->server_name,
                  server_entry->server_name);
     } else if (idtype == SILC_ID_CHANNEL) {
       channel = (SilcChannelEntry)entry;
@@ -671,14 +813,14 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
 
     if (!strcmp(client_entry->nickname, client_entry2->nickname))
       break;
-    
+
     memset(buf, 0, sizeof(buf));
     snprintf(buf, sizeof(buf) - 1, "%s@%s",
             client_entry2->username, client_entry2->hostname);
     nicklist_rename_unique(SERVER(server),
                           client_entry, client_entry->nickname,
                           client_entry2, client_entry2->nickname);
-    signal_emit("message nick", 4, server, client_entry2->nickname, 
+    signal_emit("message nick", 4, server, client_entry2->nickname,
                client_entry->nickname, buf);
     break;
 
@@ -692,23 +834,26 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
     idtype = va_arg(va, int);
     entry = va_arg(va, void *);
     mode = va_arg(va, SilcUInt32);
-    (void)va_arg(va, char *);
-    (void)va_arg(va, char *);
+    (void)va_arg(va, char *);                 /* cipher */
+    (void)va_arg(va, char *);                 /* hmac */
+    (void)va_arg(va, char *);                 /* passphrase */
+    (void)va_arg(va, SilcPublicKey);          /* founder key */
+    buffer = va_arg(va, SilcBuffer);          /* channel public keys */
     channel = va_arg(va, SilcChannelEntry);
 
     tmp = silc_client_chmode(mode,
-                            channel->channel_key ? 
+                            channel->channel_key ?
                             silc_cipher_get_name(channel->channel_key) : "",
-                            channel->hmac ? 
+                            channel->hmac ?
                             silc_hmac_get_name(channel->hmac) : "");
-    
+
     chanrec = silc_channel_find_entry(server, channel);
     if (chanrec != NULL) {
       g_free_not_null(chanrec->mode);
       chanrec->mode = g_strdup(tmp == NULL ? "" : tmp);
       signal_emit("channel mode changed", 1, chanrec);
     }
-    
+
     if (idtype == SILC_ID_CLIENT) {
       client_entry = (SilcClientEntry)entry;
       printformat_module("fe-common/silc", server, channel->channel_name,
@@ -729,6 +874,10 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
                         channel2->channel_name);
     }
 
+    /* Print the channel public key list */
+    if (buffer)
+      silc_parse_channel_public_keys(server, channel, buffer);
+
     silc_free(tmp);
     break;
 
@@ -752,7 +901,7 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
 
       if (client_entry2 == server->conn->local_entry)
        chanrec->chanop = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
-      
+
       nick = silc_nicklist_find(chanrec, client_entry2);
       if (nick != NULL) {
        nick->op = (mode & SILC_CHANNEL_UMODE_CHANOP) != 0;
@@ -765,33 +914,33 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
       client_entry = (SilcClientEntry)entry;
       printformat_module("fe-common/silc", server, channel->channel_name,
                         MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
-                        channel->channel_name, client_entry2->nickname, 
+                        channel->channel_name, client_entry2->nickname,
                         tmp ? tmp : "removed all",
                         client_entry->nickname);
     } else if (idtype == SILC_ID_SERVER) {
       server_entry = (SilcServerEntry)entry;
       printformat_module("fe-common/silc", server, channel->channel_name,
                         MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
-                        channel->channel_name, client_entry2->nickname, 
+                        channel->channel_name, client_entry2->nickname,
                         tmp ? tmp : "removed all",
                         server_entry->server_name);
     } else if (idtype == SILC_ID_CHANNEL) {
       channel2 = (SilcChannelEntry)entry;
       printformat_module("fe-common/silc", server, channel->channel_name,
                         MSGLEVEL_MODES, SILCTXT_CHANNEL_CUMODE,
-                        channel->channel_name, client_entry2->nickname, 
+                        channel->channel_name, client_entry2->nickname,
                         tmp ? tmp : "removed all",
                         channel2->channel_name);
     }
 
     if (mode & SILC_CHANNEL_UMODE_CHANFO)
-      printformat_module("fe-common/silc", 
+      printformat_module("fe-common/silc",
                         server, channel->channel_name, MSGLEVEL_CRAP,
                         SILCTXT_CHANNEL_FOUNDER,
                         channel->channel_name, client_entry2->nickname);
 
     if (mode & SILC_CHANNEL_UMODE_QUIET && conn->local_entry == client_entry2)
-      printformat_module("fe-common/silc", 
+      printformat_module("fe-common/silc",
                         server, channel->channel_name, MSGLEVEL_CRAP,
                         SILCTXT_CHANNEL_QUIETED, channel->channel_name);
 
@@ -824,11 +973,11 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
     channel = va_arg(va, SilcChannelEntry);
 
     chanrec = silc_channel_find_entry(server, channel);
-  
+
     if (client_entry == conn->local_entry) {
       printformat_module("fe-common/silc", server, channel->channel_name,
-                        MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU, 
-                        channel->channel_name, 
+                        MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED_YOU,
+                        channel->channel_name,
                         client_entry ? client_entry2->nickname : "",
                         tmp ? tmp : "");
       if (chanrec) {
@@ -837,9 +986,9 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
       }
     } else {
       printformat_module("fe-common/silc", server, channel->channel_name,
-                        MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED, 
-                        client_entry->nickname, channel->channel_name, 
-                        client_entry2 ? client_entry2->nickname : "", 
+                        MSGLEVEL_CRAP, SILCTXT_CHANNEL_KICKED,
+                        client_entry->nickname, channel->channel_name,
+                        client_entry2 ? client_entry2->nickname : "",
                         tmp ? tmp : "");
 
       if (chanrec) {
@@ -861,28 +1010,28 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
     tmp = va_arg(va, char *);
     idtype = va_arg(va, int);
     entry = va_arg(va, SilcClientEntry);
-  
+
     if (client_entry == conn->local_entry) {
       if (idtype == SILC_ID_CLIENT) {
        client_entry2 = (SilcClientEntry)entry;
        printformat_module("fe-common/silc", server, NULL,
-                          MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU, 
+                          MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
                           client_entry2 ? client_entry2->nickname : "",
                           tmp ? tmp : "");
       } else if (idtype == SILC_ID_SERVER) {
        server_entry = (SilcServerEntry)entry;
        printformat_module("fe-common/silc", server, NULL,
-                          MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU, 
+                          MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
                           server_entry->server_name, tmp ? tmp : "");
       } else if (idtype == SILC_ID_CHANNEL) {
        channel = (SilcChannelEntry)entry;
        printformat_module("fe-common/silc", server, NULL,
-                          MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU, 
+                          MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
                           channel->channel_name, tmp ? tmp : "");
       }
     } else {
       list1 = nicklist_get_same_unique(SERVER(server), client_entry);
-      for (list_tmp = list1; list_tmp != NULL; list_tmp = 
+      for (list_tmp = list1; list_tmp != NULL; list_tmp =
             list_tmp->next->next) {
        CHANNEL_REC *channel = list_tmp->data;
        NICK_REC *nickrec = list_tmp->next->data;
@@ -892,20 +1041,20 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
       if (idtype == SILC_ID_CLIENT) {
        client_entry2 = (SilcClientEntry)entry;
        printformat_module("fe-common/silc", server, NULL,
-                          MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED, 
+                          MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
                           client_entry->nickname,
                           client_entry2 ? client_entry2->nickname : "",
                           tmp ? tmp : "");
       } else if (idtype == SILC_ID_SERVER) {
        server_entry = (SilcServerEntry)entry;
        printformat_module("fe-common/silc", server, NULL,
-                          MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED, 
+                          MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
                           client_entry->nickname,
                           server_entry->server_name, tmp ? tmp : "");
       } else if (idtype == SILC_ID_CHANNEL) {
        channel = (SilcChannelEntry)entry;
        printformat_module("fe-common/silc", server, NULL,
-                          MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED, 
+                          MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
                           client_entry->nickname,
                           channel->channel_name, tmp ? tmp : "");
       }
@@ -925,11 +1074,11 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
       SilcUInt32 clients_count;
 
       SILC_LOG_DEBUG(("Notify: SIGNOFF"));
-      
+
       (void)va_arg(va, void *);
       clients = va_arg(va, SilcClientEntry *);
       clients_count = va_arg(va, SilcUInt32);
-  
+
       for (i = 0; i < clients_count; i++) {
        memset(buf, 0, sizeof(buf));
 
@@ -941,14 +1090,14 @@ void silc_notify(SilcClient client, SilcClientConnection conn,
            snprintf(buf, sizeof(buf) - 1, "%s@%s",
                     clients[i]->username, clients[i]->hostname);
          signal_emit("message quit", 4, server, clients[i]->nickname,
-                     clients[i]->username ? buf : "", 
+                     clients[i]->username ? buf : "",
                      "server signoff");
        }
 
        silc_server_free_ftp(server, clients[i]);
-       
+
        list1 = nicklist_get_same_unique(SERVER(server), clients[i]);
-       for (list_tmp = list1; list_tmp != NULL; list_tmp = 
+       for (list_tmp = list1; list_tmp != NULL; list_tmp =
               list_tmp->next->next) {
          CHANNEL_REC *channel = list_tmp->data;
          NICK_REC *nickrec = list_tmp->next->data;
@@ -1061,13 +1210,13 @@ void silc_connect(SilcClient client, SilcClientConnection conn,
     server->connected = TRUE;
     signal_emit("event connected", 1, server);
 
-    /* If we resumed old session check whether we need to update 
+    /* If we resumed old session check whether we need to update
        our nickname */
     if (strcmp(server->nick, conn->local_entry->nickname)) {
       char *old;
       old = g_strdup(server->nick);
       server_change_nick(SERVER(server), conn->local_entry->nickname);
-      nicklist_rename_unique(SERVER(server), 
+      nicklist_rename_unique(SERVER(server),
                             conn->local_entry, server->nick,
                             conn->local_entry, conn->local_entry->nickname);
       signal_emit("message own_nick", 4, server, server->nick, old, "");
@@ -1087,7 +1236,7 @@ void silc_connect(SilcClient client, SilcClientConnection conn,
 /* Called to indicate that connection was disconnected to the server. */
 
 void silc_disconnect(SilcClient client, SilcClientConnection conn,
-                    SilcStatus status, const char *message)
+                    SilcStatus status, const char *message)
 {
   SILC_SERVER_REC *server = conn->context;
 
@@ -1099,7 +1248,7 @@ void silc_disconnect(SilcClient client, SilcClientConnection conn,
   if (server->conn && server->conn->local_entry) {
     nicklist_rename_unique(SERVER(server),
                           server->conn->local_entry, server->nick,
-                          server->conn->local_entry, 
+                          server->conn->local_entry,
                           silc_client->username);
     silc_change_nick(server, silc_client->username);
   }
@@ -1110,7 +1259,8 @@ void silc_disconnect(SilcClient client, SilcClientConnection conn,
             silc_get_status_message(status), status,
             message ? message : "");
 
-  server->conn->context = NULL;
+  if (server->conn)
+    server->conn->context = NULL;
   server->conn = NULL;
   server->connection_lost = TRUE;
   server_disconnect(SERVER(server));
@@ -1125,7 +1275,9 @@ void silc_disconnect(SilcClient client, SilcClientConnection conn,
    after application has called the command. Just to tell application
    that the command really was processed. */
 
-void silc_command(SilcClient client, SilcClientConnection conn, 
+static bool cmode_list_chpks = FALSE;
+
+void silc_command(SilcClient client, SilcClientConnection conn,
                  SilcClientCommandContext cmd_context, bool success,
                  SilcCommand command, SilcStatus status)
 {
@@ -1144,7 +1296,7 @@ void silc_command(SilcClient client, SilcClientConnection conn,
     if (cmd_context->argc > 2)
       printformat_module("fe-common/silc", server, NULL,
                         MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITING,
-                        cmd_context->argv[2], 
+                        cmd_context->argv[2],
                         (cmd_context->argv[1][0] == '*' ?
                          (char *)conn->current_channel->channel_name :
                          (char *)cmd_context->argv[1]));
@@ -1154,11 +1306,24 @@ void silc_command(SilcClient client, SilcClientConnection conn,
     server->no_reconnect = TRUE;
     break;
 
+  case SILC_COMMAND_CMODE:
+    if (cmd_context->argc == 3 &&
+       !strcmp(cmd_context->argv[2], "+C"))
+      cmode_list_chpks = TRUE;
+    else
+      cmode_list_chpks = FALSE;
+    break;
+
   default:
     break;
   }
 }
 
+typedef struct {
+  SilcChannelEntry channel;
+  bool retry;
+} *SilcJoinResolve;
+
 /* Client info resolving callback when JOIN command reply is received.
    This will cache all users on the channel. */
 
@@ -1168,7 +1333,8 @@ static void silc_client_join_get_users(SilcClient client,
                                       SilcUInt32 clients_count,
                                       void *context)
 {
-  SilcChannelEntry channel = (SilcChannelEntry)context;
+  SilcJoinResolve r = context;
+  SilcChannelEntry channel = r->channel;
   SilcHashTableList htl;
   SilcChannelUser chu;
   SILC_SERVER_REC *server = conn->context;
@@ -1179,8 +1345,13 @@ static void silc_client_join_get_users(SilcClient client,
   SILC_LOG_DEBUG(("Start, channel %s, %d users", channel->channel_name,
                  silc_hash_table_count(channel->user_list)));
 
-  if (!clients)
+  if (!clients && r->retry < 1) {
+    /* Retry to resolve */
+    r->retry++;
+    silc_client_get_clients_by_channel(client, conn, channel,
+                                      silc_client_join_get_users, context);
     return;
+  }
 
   chanrec = silc_channel_find(server, channel->channel_name);
   if (chanrec == NULL)
@@ -1208,13 +1379,13 @@ static void silc_client_join_get_users(SilcClient client,
 
   if (founder) {
     if (founder == conn->local_entry) {
-      printformat_module("fe-common/silc", 
+      printformat_module("fe-common/silc",
                         server, channel->channel_name, MSGLEVEL_CRAP,
                         SILCTXT_CHANNEL_FOUNDER_YOU,
                         channel->channel_name);
       signal_emit("nick mode changed", 2, chanrec, ownnick);
     } else
-      printformat_module("fe-common/silc", 
+      printformat_module("fe-common/silc",
                         server, channel->channel_name, MSGLEVEL_CRAP,
                         SILCTXT_CHANNEL_FOUNDER,
                         channel->channel_name, founder->nickname);
@@ -1233,7 +1404,7 @@ void silc_getkey_cb(bool success, void *context)
 {
   GetkeyContext getkey = (GetkeyContext)context;
   char *entity = (getkey->id_type == SILC_ID_CLIENT ? "user" : "server");
-  char *name = (getkey->id_type == SILC_ID_CLIENT ? 
+  char *name = (getkey->id_type == SILC_ID_CLIENT ?
                ((SilcClientEntry)getkey->entry)->nickname :
                ((SilcServerEntry)getkey->entry)->server_name);
 
@@ -1251,12 +1422,12 @@ void silc_getkey_cb(bool success, void *context)
 }
 
 /* Parse an invite or ban list */
-void  silc_parse_inviteban_list(SilcClient client,
-                               SilcClientConnection conn,
-                               SILC_SERVER_REC *server, 
-                               SilcChannelEntry channel, 
-                               const char *list_type,
-                               SilcArgumentPayload list)
+void silc_parse_inviteban_list(SilcClient client,
+                              SilcClientConnection conn,
+                              SILC_SERVER_REC *server,
+                              SilcChannelEntry channel,
+                              const char *list_type,
+                              SilcArgumentPayload list)
 {
   unsigned char *tmp;
   SilcUInt32 type, len;
@@ -1270,7 +1441,7 @@ void  silc_parse_inviteban_list(SilcClient client,
                       channel->channel_name, list_type);
     return;
   }
-  
+
   printformat_module("fe-common/silc", server,
                     (chanrec ? chanrec->visible_name : NULL),
                     MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_LIST,
@@ -1285,10 +1456,10 @@ void  silc_parse_inviteban_list(SilcClient client,
          /* an invite string */
          char **list;
          int i=0;
-               
+
          if (tmp[len-1] == ',')
            tmp[len-1] = '\0';
-         
+
          list = g_strsplit(tmp, ",", -1);
          while (list[i])
            printformat_module("fe-common/silc", server,
@@ -1308,7 +1479,7 @@ void  silc_parse_inviteban_list(SilcClient client,
          /* tmp is Public Key Payload, take public key from it. */
          fingerprint = silc_hash_fingerprint(NULL, tmp + 4, len - 4);
          babbleprint = silc_hash_babbleprint(NULL, tmp + 4, len - 4);
-         
+
          printformat_module("fe-common/silc", server,
                             (chanrec ? chanrec->visible_name : NULL),
                             MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_PUBKEY,
@@ -1316,15 +1487,15 @@ void  silc_parse_inviteban_list(SilcClient client,
                             fingerprint, babbleprint);
        }
        break;
-       
+
       case 3:
        {
          /* a client ID */
          SilcClientID *client_id;
          SilcClientEntry client_entry;
-         
+
          client_id = silc_id_payload_parse_id(tmp, len, NULL);
-                         
+
          if (client_id == NULL) {
            silc_say_error("Invalid data in %s list encountered", list_type);
            break;
@@ -1347,7 +1518,7 @@ void  silc_parse_inviteban_list(SilcClient client,
          silc_free(client_id);
        }
        break;
-       
+
       default:
        /* "trash" */
        silc_say_error("Unkown type in %s list: %u (len %u)",
@@ -1357,7 +1528,7 @@ void  silc_parse_inviteban_list(SilcClient client,
   }
 
   if (resolving)
-    printformat_module("fe-common/silc", server, 
+    printformat_module("fe-common/silc", server,
                       (chanrec ? chanrec->visible_name : NULL),
                       MSGLEVEL_CRAP, SILCTXT_CHANNEL_INVITEBAN_REGET,
                       list_type, channel->channel_name);
@@ -1367,7 +1538,7 @@ void  silc_parse_inviteban_list(SilcClient client,
    function. If error occurs it will be called as well. Normal scenario
    is that it will be called after the received command data has been parsed
    and processed. The function is used to pass the received command data to
-   the application. 
+   the application.
 
    `conn' is the associated client connection. `cmd_payload' is the command
    payload data received from server and it can be ignored. It is provided
@@ -1379,7 +1550,7 @@ void  silc_parse_inviteban_list(SilcClient client,
    and each command defines the number and type of arguments it passes to the
    application (on error they are not sent). */
 
-void 
+void
 silc_command_reply(SilcClient client, SilcClientConnection conn,
                   SilcCommandPayload cmd_payload, bool success,
                   SilcCommand command, SilcStatus status, ...)
@@ -1402,14 +1573,14 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
       SilcBuffer channels, user_modes;
       SilcClientEntry client_entry;
       SilcDList attrs;
-      
+
       if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
        /* Print the unknown nick for user */
        unsigned char *tmp =
          silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
                                     3, NULL);
        if (tmp)
-         silc_say_error("%s: %s", tmp, 
+         silc_say_error("%s: %s", tmp,
                         silc_get_status_message(status));
        break;
       } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
@@ -1420,7 +1591,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
          silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
                                     2, &tmp_len);
        if (tmp) {
-         SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, 
+         SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len,
                                                             NULL);
          if (client_id) {
            client_entry = silc_client_get_client_by_id(client, conn,
@@ -1447,10 +1618,10 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
       fingerprint = va_arg(vp, unsigned char *);
       user_modes = va_arg(vp, SilcBuffer);
       attrs = va_arg(vp, SilcDList);
-      
+
       silc_parse_userfqdn(nickname, &nick, NULL);
       printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
-                        SILCTXT_WHOIS_USERINFO, nickname, 
+                        SILCTXT_WHOIS_USERINFO, nickname,
                         client_entry->username, client_entry->hostname,
                         nick, client_entry->nickname);
       printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
@@ -1472,11 +1643,11 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
            SilcUInt32 name_len;
            char *m = silc_client_chumode_char(umodes[i++]);
            char *name = silc_channel_get_name(entry, &name_len);
-           
+
            if (m)
-             strncat(buf, m, strlen(m));
-           strncat(buf, name, name_len);
-           strncat(buf, " ", 1);
+             silc_strncat(buf, sizeof(buf) - 1, m, strlen(m));
+           silc_strncat(buf, sizeof(buf) - 1, name, name_len);
+           silc_strncat(buf, sizeof(buf) - 1, " ", 1);
            silc_free(m);
          }
 
@@ -1486,14 +1657,14 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
          silc_free(umodes);
        }
       }
-      
+
       if (mode) {
        memset(buf, 0, sizeof(buf));
        silc_get_umode_string(mode, buf, sizeof(buf - 1));
        printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
                           SILCTXT_WHOIS_MODES, buf);
       }
-      
+
       if (idle && nickname) {
        memset(buf, 0, sizeof(buf));
        snprintf(buf, sizeof(buf) - 1, "%lu %s",
@@ -1516,18 +1687,18 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
                                    client_entry);
     }
     break;
-    
+
   case SILC_COMMAND_IDENTIFY:
     {
       SilcClientEntry client_entry;
-      
+
       if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
        /* Print the unknown nick for user */
        unsigned char *tmp =
          silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
                                     3, NULL);
        if (tmp)
-         silc_say_error("%s: %s", tmp, 
+         silc_say_error("%s: %s", tmp,
                         silc_get_status_message(status));
        break;
       } else if (status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
@@ -1558,51 +1729,51 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
   case SILC_COMMAND_WHOWAS:
     {
       char *nickname, *username, *realname;
-      
+
       if (status == SILC_STATUS_ERR_NO_SUCH_NICK ||
          status == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
        char *tmp;
        tmp = silc_argument_get_arg_type(silc_command_get_args(cmd_payload),
                                         3, NULL);
        if (tmp)
-         silc_say_error("%s: %s", tmp, 
+         silc_say_error("%s: %s", tmp,
                         silc_get_status_message(status));
        break;
       } else if (!success) {
        silc_say_error("WHOWAS: %s", silc_get_status_message(status));
        return;
       }
-      
+
       (void)va_arg(vp, SilcClientEntry);
       nickname = va_arg(vp, char *);
       username = va_arg(vp, char *);
       realname = va_arg(vp, char *);
-      
+
       printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
-                        SILCTXT_WHOWAS_USERINFO, nickname, username, 
+                        SILCTXT_WHOWAS_USERINFO, nickname, username,
                         realname ? realname : "");
     }
     break;
-    
+
   case SILC_COMMAND_INVITE:
     {
       SilcChannelEntry channel;
       SilcBuffer payload;
       SilcArgumentPayload invite_list;
-      SilcUInt32 argc;
-      
+      SilcUInt16 argc;
+
       if (!success)
        return;
-      
+
       channel = va_arg(vp, SilcChannelEntry);
       payload = va_arg(vp, SilcBuffer);
 
       if (payload) {
        SILC_GET16_MSB(argc, payload->data);
-       invite_list = silc_argument_payload_parse(payload->data + 2, 
+       invite_list = silc_argument_payload_parse(payload->data + 2,
                                                  payload->len - 2, argc);
        if (invite_list) {
-         silc_parse_inviteban_list(client, conn, server, channel, 
+         silc_parse_inviteban_list(client, conn, server, channel,
                                    "invite", invite_list);
          silc_argument_payload_free(invite_list);
        }
@@ -1610,7 +1781,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
     }
     break;
 
-  case SILC_COMMAND_JOIN: 
+  case SILC_COMMAND_JOIN:
     {
       char *channel, *mode, *topic;
       SilcUInt32 modei;
@@ -1660,35 +1831,39 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
        silc_free(dm);
       }
 
-      mode = silc_client_chmode(modei, 
-                               channel_entry->channel_key ? 
+      mode = silc_client_chmode(modei,
+                               channel_entry->channel_key ?
                                silc_cipher_get_name(channel_entry->
                                                     channel_key) : "",
-                               channel_entry->hmac ? 
+                               channel_entry->hmac ?
                                silc_hmac_get_name(channel_entry->hmac) : "");
       g_free_not_null(chanrec->mode);
       chanrec->mode = g_strdup(mode == NULL ? "" : mode);
       signal_emit("channel mode changed", 1, chanrec);
 
       /* Resolve the client information */
-      silc_client_get_clients_by_list(client, conn, list_count, client_id_list,
-                                     silc_client_join_get_users, 
-                                     channel_entry);
+      {
+       SilcJoinResolve r = silc_calloc(1, sizeof(*r));
+       r->channel = channel_entry;
+       silc_client_get_clients_by_list(client, conn, list_count,
+                                       client_id_list,
+                                       silc_client_join_get_users, r);
+      }
 
       break;
     }
 
-  case SILC_COMMAND_NICK: 
+  case SILC_COMMAND_NICK:
     {
       char *old;
       SilcClientEntry client_entry = va_arg(vp, SilcClientEntry);
       GSList *nicks;
-      
+
       if (!success)
        return;
 
       nicks = nicklist_get_same(SERVER(server), client_entry->nickname);
-      if ((nicks != NULL) && 
+      if ((nicks != NULL) &&
         (strcmp(SERVER(server)->nick, client_entry->nickname))) {
        char buf[512];
        SilcClientEntry collider, old;
@@ -1696,7 +1871,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
        old = ((SILC_NICK_REC *)(nicks->next->data))->silc_user->client;
        collider = silc_client_get_client_by_id(client, conn,
                                                old->id);
-       
+
         memset(buf, 0, sizeof(buf));
         snprintf(buf, sizeof(buf) - 1, "%s@%s",
                 collider->username, collider->hostname);
@@ -1717,17 +1892,17 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
       g_free(old);
       break;
     }
-    
+
   case SILC_COMMAND_LIST:
     {
       char *topic, *name;
       int usercount;
       char users[20];
       char tmp[256], *cp, *dm = NULL;
-      
+
       if (!success)
        return;
-      
+
       (void)va_arg(vp, SilcChannelEntry);
       name = va_arg(vp, char *);
       topic = va_arg(vp, char *);
@@ -1746,7 +1921,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
                         cp, strlen(topic));
        topic = cp;
       }
-      
+
       if (status == SILC_STATUS_LIST_START ||
          status == SILC_STATUS_OK)
        printformat_module("fe-common/silc", server, NULL,
@@ -1762,17 +1937,17 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
       silc_free(dm);
     }
     break;
-    
+
   case SILC_COMMAND_UMODE:
     {
       SilcUInt32 mode;
       char *reason;
-      
+
       if (!success)
        return;
-      
+
       mode = va_arg(vp, SilcUInt32);
-      
+
       if (mode & SILC_UMODE_SERVER_OPERATOR &&
          !(server->umode & SILC_UMODE_SERVER_OPERATOR))
        printformat_module("fe-common/silc", server, NULL,
@@ -1784,7 +1959,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
                           MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
 
       if ((mode & SILC_UMODE_GONE) != (server->umode & SILC_UMODE_GONE)) {
-       if (mode & SILC_UMODE_GONE) {      
+       if (mode & SILC_UMODE_GONE) {
          if ((server->away_reason != NULL) && (server->away_reason[0] != '\0'))
            reason = g_strdup(server->away_reason);
          else
@@ -1801,7 +1976,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
       signal_emit("user mode changed", 2, server, NULL);
     }
     break;
-    
+
   case SILC_COMMAND_OPER:
     if (!success)
       return;
@@ -1812,7 +1987,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
     printformat_module("fe-common/silc", server, NULL,
                       MSGLEVEL_CRAP, SILCTXT_SERVER_OPER);
     break;
-    
+
   case SILC_COMMAND_SILCOPER:
     if (!success)
       return;
@@ -1823,18 +1998,18 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
     printformat_module("fe-common/silc", server, NULL,
                       MSGLEVEL_CRAP, SILCTXT_ROUTER_OPER);
     break;
-    
-  case SILC_COMMAND_USERS: 
+
+  case SILC_COMMAND_USERS:
     {
       SilcHashTableList htl;
       SilcChannelEntry channel;
       SilcChannelUser chu;
-      
+
       if (!success)
        return;
-      
+
       channel = va_arg(vp, SilcChannelEntry);
-      
+
       printformat_module("fe-common/silc", server, channel->channel_name,
                         MSGLEVEL_CRAP, SILCTXT_USERS_HEADER,
                         channel->channel_name);
@@ -1846,7 +2021,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
 
        if (!e->nickname)
          continue;
-       
+
        memset(stat, 0, sizeof(stat));
        mode = silc_client_chumode_char(chu->mode);
        if (e->mode & SILC_UMODE_GONE)
@@ -1870,7 +2045,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
 
        printformat_module("fe-common/silc", server, channel->channel_name,
                           MSGLEVEL_CRAP, SILCTXT_USERS,
-                          e->nickname, stat, 
+                          e->nickname, stat,
                           e->username ? e->username : "",
                           e->hostname ? e->hostname : "",
                           e->realname ? e->realname : "");
@@ -1886,27 +2061,27 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
       SilcChannelEntry channel;
       SilcBuffer payload;
       SilcArgumentPayload ban_list;
-      SilcUInt32 argc;
-      
+      SilcUInt16 argc;
+
       if (!success)
        return;
-      
+
       channel = va_arg(vp, SilcChannelEntry);
       payload = va_arg(vp, SilcBuffer);
 
       if (payload) {
        SILC_GET16_MSB(argc, payload->data);
-       ban_list = silc_argument_payload_parse(payload->data + 2, 
+       ban_list = silc_argument_payload_parse(payload->data + 2,
                                               payload->len - 2, argc);
        if (ban_list) {
-         silc_parse_inviteban_list(client, conn, server, channel, 
+         silc_parse_inviteban_list(client, conn, server, channel,
                                    "ban", ban_list);
          silc_argument_payload_free(ban_list);
        }
       }
     }
     break;
-    
+
   case SILC_COMMAND_GETKEY:
     {
       SilcIdType id_type;
@@ -1916,10 +2091,10 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
       SilcUInt32 pk_len;
       GetkeyContext getkey;
       char *name;
-      
+
       if (!success)
        return;
-      
+
       id_type = va_arg(vp, SilcUInt32);
       entry = va_arg(vp, void *);
       public_key = va_arg(vp, SilcPublicKey);
@@ -1934,7 +2109,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
        getkey->conn = conn;
        getkey->fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
 
-       name = (id_type == SILC_ID_CLIENT ? 
+       name = (id_type == SILC_ID_CLIENT ?
                ((SilcClientEntry)entry)->nickname :
                ((SilcServerEntry)entry)->server_name);
 
@@ -1960,7 +2135,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
 
       if (!success)
        return;
-      
+
       server_entry = va_arg(vp, SilcServerEntry);
       server_name = va_arg(vp, char *);
       server_info = va_arg(vp, char *);
@@ -1972,16 +2147,16 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
        }
     }
     break;
-    
+
   case SILC_COMMAND_TOPIC:
     {
       SilcChannelEntry channel;
       char *topic;
       char tmp[256], *cp, *dm = NULL;
-      
+
       if (!success)
        return;
-      
+
       channel = va_arg(vp, SilcChannelEntry);
       topic = va_arg(vp, char *);
 
@@ -2020,7 +2195,7 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
 
   case SILC_COMMAND_WATCH:
     break;
-  
+
   case SILC_COMMAND_STATS:
     {
       SilcUInt32 starttime, uptime, my_clients, my_channels, my_server_ops,
@@ -2149,6 +2324,30 @@ silc_command_reply(SilcClient client, SilcClientConnection conn,
     }
     break;
 
+  case SILC_COMMAND_CMODE:
+    {
+      SilcChannelEntry channel_entry;
+      SilcBuffer channel_pubkeys;
+
+      channel_entry = va_arg(vp, SilcChannelEntry);
+      (void)va_arg(vp, SilcUInt32);
+      (void)va_arg(vp, SilcPublicKey);
+      channel_pubkeys = va_arg(vp, SilcBuffer);
+
+      if (!success || !cmode_list_chpks ||
+         !channel_entry || !channel_entry->channel_name)
+       return;
+
+      /* Print the channel public key list */
+      if (channel_pubkeys)
+       silc_parse_channel_public_keys(server, channel_entry, channel_pubkeys);
+      else
+       printformat_module("fe-common/silc", server, NULL,
+                          MSGLEVEL_CRAP, SILCTXT_CHANNEL_PK_NO_LIST,
+                          channel_entry->channel_name);
+    }
+    break;
+
   }
 
   va_end(vp);
@@ -2177,7 +2376,7 @@ static void verify_public_key_completion(const char *line, void *context)
       verify->completion(TRUE, verify->context);
 
     /* Save the key for future checking */
-    silc_pkcs_save_public_key_data(verify->filename, verify->pk, 
+    silc_pkcs_save_public_key_data(verify->filename, verify->pk,
                                   verify->pk_len, SILC_PKCS_FILE_PEM);
   } else {
     /* Call the completion */
@@ -2185,7 +2384,7 @@ static void verify_public_key_completion(const char *line, void *context)
       verify->completion(FALSE, verify->context);
 
     printformat_module("fe-common/silc", NULL, NULL,
-                      MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD, 
+                      MSGLEVEL_CRAP, SILCTXT_PUBKEY_DISCARD,
                       verify->entity_name ? verify->entity_name :
                       verify->entity);
   }
@@ -2202,10 +2401,10 @@ static void verify_public_key_completion(const char *line, void *context)
    server/router public key this will check for filename that includes the
    remote host's IP address and remote host's hostname. */
 
-static void 
+static void
 silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
-                               const char *name, SilcSocketType conn_type, 
-                               unsigned char *pk, SilcUInt32 pk_len, 
+                               const char *name, SilcSocketType conn_type,
+                               unsigned char *pk, SilcUInt32 pk_len,
                                SilcSKEPKType pk_type,
                                SilcVerifyPublicKey completion, void *context)
 {
@@ -2215,13 +2414,13 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
   struct passwd *pw;
   struct stat st;
   char *entity = ((conn_type == SILC_SOCKET_TYPE_SERVER ||
-                  conn_type == SILC_SOCKET_TYPE_ROUTER) ? 
+                  conn_type == SILC_SOCKET_TYPE_ROUTER) ?
                  "server" : "client");
   PublicKeyVerify verify;
 
   if (pk_type != SILC_SKE_PK_TYPE_SILC) {
     printformat_module("fe-common/silc", NULL, NULL,
-                      MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED, 
+                      MSGLEVEL_CRAP, SILCTXT_PUBKEY_UNSUPPORTED,
                       entity, pk_type);
     if (completion)
       completion(FALSE, context);
@@ -2242,24 +2441,24 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
   if (conn_type == SILC_SOCKET_TYPE_SERVER ||
       conn_type == SILC_SOCKET_TYPE_ROUTER) {
     if (!name) {
-      snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, 
+      snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
               conn->sock->ip, conn->sock->port);
-      snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s", 
+      snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
               get_irssi_dir(), entity, file);
-      
-      snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, 
+
+      snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
               conn->sock->hostname, conn->sock->port);
-      snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s", 
+      snprintf(filename2, sizeof(filename2) - 1, "%s/%skeys/%s",
               get_irssi_dir(), entity, file);
-      
+
       ipf = filename;
       hostf = filename2;
     } else {
-      snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity, 
+      snprintf(file, sizeof(file) - 1, "%skey_%s_%d.pub", entity,
               name, conn->sock->port);
-      snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s", 
+      snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
               get_irssi_dir(), entity, file);
-      
+
       ipf = filename;
     }
   } else {
@@ -2268,9 +2467,9 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
     for (i = 0; i < strlen(fingerprint); i++)
       if (fingerprint[i] == ' ')
        fingerprint[i] = '_';
-    
+
     snprintf(file, sizeof(file) - 1, "%skey_%s.pub", entity, fingerprint);
-    snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s", 
+    snprintf(filename, sizeof(filename) - 1, "%s/%skeys/%s",
             get_irssi_dir(), entity, file);
     silc_free(fingerprint);
 
@@ -2299,12 +2498,12 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
   if (stat(ipf, &st) < 0 && (!hostf || stat(hostf, &st) < 0)) {
     /* Key does not exist, ask user to verify the key and save it */
 
-    printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
-                      SILCTXT_PUBKEY_RECEIVED,verify->entity_name ? 
+    printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+                      SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
                       verify->entity_name : entity);
-    printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
+    printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                       SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
-    printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
+    printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                       SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
     format = format_get_text("fe-common/silc", NULL, NULL, NULL,
                             SILCTXT_PUBKEY_ACCEPT);
@@ -2320,22 +2519,22 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
     SilcUInt32 encpk_len;
 
     /* Load the key file, try for both IP filename and hostname filename */
-    if (!silc_pkcs_load_public_key(ipf, &public_key, 
+    if (!silc_pkcs_load_public_key(ipf, &public_key,
                                   SILC_PKCS_FILE_PEM) &&
-       !silc_pkcs_load_public_key(ipf, &public_key, 
+       !silc_pkcs_load_public_key(ipf, &public_key,
                                   SILC_PKCS_FILE_BIN) &&
-       (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key, 
+       (!hostf || (!silc_pkcs_load_public_key(hostf, &public_key,
                                               SILC_PKCS_FILE_PEM) &&
-                   !silc_pkcs_load_public_key(hostf, &public_key, 
+                   !silc_pkcs_load_public_key(hostf, &public_key,
                                               SILC_PKCS_FILE_BIN)))) {
-      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
-                        SILCTXT_PUBKEY_RECEIVED,verify->entity_name ? 
+      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+                        SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
                         verify->entity_name : entity);
-      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
+      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
-      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
+      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
-      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
+      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_PUBKEY_COULD_NOT_LOAD, entity);
       format = format_get_text("fe-common/silc", NULL, NULL, NULL,
                               SILCTXT_PUBKEY_ACCEPT_ANYWAY);
@@ -2349,14 +2548,14 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
     /* Encode the key data */
     encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
     if (!encpk) {
-      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
-                        SILCTXT_PUBKEY_RECEIVED,verify->entity_name ? 
+      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+                        SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
                         verify->entity_name : entity);
-      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
+      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
-      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
+      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
-      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
+      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_PUBKEY_MALFORMED, entity);
       format = format_get_text("fe-common/silc", NULL, NULL, NULL,
                               SILCTXT_PUBKEY_ACCEPT_ANYWAY);
@@ -2369,18 +2568,18 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
 
     /* Compare the keys */
     if (memcmp(encpk, pk, encpk_len)) {
-      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
-                        SILCTXT_PUBKEY_RECEIVED,verify->entity_name ? 
+      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
+                        SILCTXT_PUBKEY_RECEIVED,verify->entity_name ?
                         verify->entity_name : entity);
-      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
+      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_PUBKEY_FINGERPRINT, entity, fingerprint);
-      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
+      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_PUBKEY_BABBLEPRINT, babbleprint);
-      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
+      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_PUBKEY_NO_MATCH, entity);
-      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
+      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_PUBKEY_MAYBE_EXPIRED, entity);
-      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
+      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_PUBKEY_MITM_ATTACK, entity);
 
       /* Ask user to verify the key and save it */
@@ -2407,12 +2606,12 @@ silc_verify_public_key_internal(SilcClient client, SilcClientConnection conn,
 
 /* Verifies received public key. The `conn_type' indicates which entity
    (server, client etc.) has sent the public key. If user decides to trust
-   the key may be saved as trusted public key for later use. The 
+   the key may be saved as trusted public key for later use. The
    `completion' must be called after the public key has been verified. */
 
-void 
+void
 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
-                      SilcSocketType conn_type, unsigned char *pk, 
+                      SilcSocketType conn_type, unsigned char *pk,
                       SilcUInt32 pk_len, SilcSKEPKType pk_type,
                       SilcVerifyPublicKey completion, void *context)
 {
@@ -2433,7 +2632,7 @@ void ask_passphrase_completion(const char *passphrase, void *context)
   AskPassphrase p = (AskPassphrase)context;
   if (passphrase && passphrase[0] == '\0')
     passphrase = NULL;
-  p->completion((unsigned char *)passphrase, 
+  p->completion((unsigned char *)passphrase,
                passphrase ? strlen(passphrase) : 0, p->context);
   silc_free(p);
 }
@@ -2483,7 +2682,7 @@ static void silc_get_auth_method_callback(SilcClient client,
        (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
        break;
       }
-      
+
       (*internal->completion)(TRUE, auth_meth, setup->password,
                              strlen(setup->password), internal->context);
     }
@@ -2521,7 +2720,7 @@ void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
   internal->completion = completion;
   internal->context = context;
 
-  silc_client_request_authentication_method(client, conn, 
+  silc_client_request_authentication_method(client, conn,
                                            silc_get_auth_method_callback,
                                            internal);
 }
@@ -2533,40 +2732,40 @@ void silc_get_auth_method(SilcClient client, SilcClientConnection conn,
    must explicitly cast it to correct type.  Usually `failure' is 32 bit
    failure type (see protocol specs for all protocol failure types). */
 
-void silc_failure(SilcClient client, SilcClientConnection conn, 
+void silc_failure(SilcClient client, SilcClientConnection conn,
                  SilcProtocol protocol, void *failure)
 {
   SILC_LOG_DEBUG(("Start"));
 
   if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
     SilcSKEStatus status = (SilcSKEStatus)failure;
-    
+
     if (status == SILC_SKE_STATUS_BAD_VERSION)
-      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
+      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_KE_BAD_VERSION);
     if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
-      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
+      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_KE_UNSUPPORTED_PUBLIC_KEY);
     if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
-      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
+      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_KE_UNKNOWN_GROUP);
     if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
-      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
+      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_KE_UNKNOWN_CIPHER);
     if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
-      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
+      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_KE_UNKNOWN_PKCS);
     if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
-      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
+      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_KE_UNKNOWN_HASH_FUNCTION);
     if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
-      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
+      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_KE_UNKNOWN_HMAC);
     if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
-      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
+      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_KE_INCORRECT_SIGNATURE);
     if (status == SILC_SKE_STATUS_INVALID_COOKIE)
-      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
+      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_KE_INVALID_COOKIE);
   }
 
@@ -2574,7 +2773,7 @@ void silc_failure(SilcClient client, SilcClientConnection conn,
     SilcUInt32 err = (SilcUInt32)failure;
 
     if (err == SILC_AUTH_FAILED)
-      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP, 
+      printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
                         SILCTXT_AUTH_FAILED);
   }
 }
@@ -2598,7 +2797,7 @@ bool silc_key_agreement(SilcClient client, SilcClientConnection conn,
   /* We will just display the info on the screen and return FALSE and user
      will have to start the key agreement with a command. */
 
-  if (hostname) 
+  if (hostname)
     snprintf(portstr, sizeof(portstr) - 1, "%d", port);
 
   if (!hostname)
@@ -2606,7 +2805,7 @@ bool silc_key_agreement(SilcClient client, SilcClientConnection conn,
                       SILCTXT_KEY_AGREEMENT_REQUEST, client_entry->nickname);
   else
     printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
-                      SILCTXT_KEY_AGREEMENT_REQUEST_HOST, 
+                      SILCTXT_KEY_AGREEMENT_REQUEST_HOST,
                       client_entry->nickname, hostname, portstr);
 
   *completion = NULL;
@@ -2652,7 +2851,7 @@ void silc_ftp(SilcClient client, SilcClientConnection conn,
     server->current_session = ftp;
   }
 
-  if (hostname) 
+  if (hostname)
     snprintf(portstr, sizeof(portstr) - 1, "%d", port);
 
   if (!hostname)
@@ -2660,7 +2859,7 @@ void silc_ftp(SilcClient client, SilcClientConnection conn,
                       SILCTXT_FILE_REQUEST, client_entry->nickname);
   else
     printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
-                      SILCTXT_FILE_REQUEST_HOST, 
+                      SILCTXT_FILE_REQUEST_HOST,
                       client_entry->nickname, hostname, portstr);
 }
 
index 8c3f7630e0d5d6236496b7c196fa561c8c56e7dc..31f5ad2989bc03af515ee948be049a5af09ec0eb 100644 (file)
@@ -70,5 +70,9 @@ void silc_ftp(SilcClient client, SilcClientConnection conn,
 void
 silc_detach(SilcClient client, SilcClientConnection conn,
             const unsigned char *detach_data, SilcUInt32 detach_data_len);
+char *
+silc_unescape_data(const char *escaped_data, SilcUInt32 *length);
+char * 
+silc_escape_data(const char *data, SilcUInt32 len);
 
 #endif
index 818444dd3e52e636ef70f1998b2999478a8e5438..8f1639329813e77636874510c9b35420ee2eca08 100644 (file)
@@ -307,8 +307,13 @@ int silc_client_check_silc_dir()
            SILC_CLIENT_KEY_EXPIRES, SILC_CLIENT_KEY_EXPIRES);
 
     answer = silc_get_input("Would you like to create a new key pair "
-                           "([y]/n)?: ", FALSE);
-    if (!answer || answer[0] == 'Y' || answer[0] == 'y') {
+                           "(y/n)?: ", FALSE);
+    while (!answer) {
+      printf("Answer 'y' or 'n' and press Enter\n");
+      answer = silc_get_input("Would you like to create a new key pair "
+                             "(y/n)?: ", FALSE);
+    }
+    if (answer[0] == 'Y' || answer[0] == 'y') {
       silc_create_key_pair(SILC_CLIENT_DEF_PKCS,
                           SILC_CLIENT_DEF_PKCS_LEN,
                           file_public_key, file_private_key, NULL,
index e28768bdb7bee005437df383e98ec901c0c681c0..2ebdcc7ab42de108834ae6b9405a080ad8b704ba 100644 (file)
 
 #include "silc-commands.h"
 
+void sig_mime(SILC_SERVER_REC *server, SILC_CHANNEL_REC *channel,
+               const char *blob, const char *enc, const char *type,
+               const char *nick)
+{
+
+  if (!(IS_SILC_SERVER(server)))
+    return;
+  
+  printformat_module("fe-common/silc", server, 
+                        channel == NULL ? NULL : channel->name,
+                        MSGLEVEL_CRAP, SILCTXT_MESSAGE_DATA,
+                        nick == NULL ? "[<unknown>]" : nick, type);
+
+}
+
 SILC_CHANNEL_REC *silc_channel_create(SILC_SERVER_REC *server,
                                      const char *name,
                                      const char *visible_name,
@@ -1007,6 +1022,7 @@ void silc_channels_init(void)
   signal_add("server connected", (SIGNAL_FUNC) sig_connected);
   signal_add("server quit", (SIGNAL_FUNC) sig_server_quit);
   signal_add("gui exit", (SIGNAL_FUNC) sig_gui_quit);
+  signal_add("mime", (SIGNAL_FUNC) sig_mime);
 
   command_bind_silc("part", MODULE_NAME, (SIGNAL_FUNC) command_part);
   command_bind_silc("me", MODULE_NAME, (SIGNAL_FUNC) command_me);
@@ -1014,7 +1030,7 @@ void silc_channels_init(void)
   command_bind_silc("notice", MODULE_NAME, (SIGNAL_FUNC) command_notice);
   command_bind_silc("away", MODULE_NAME, (SIGNAL_FUNC) command_away);
   command_bind_silc("key", MODULE_NAME, (SIGNAL_FUNC) command_key);
-  command_bind_silc("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys);
+/*  command_bind_silc("listkeys", MODULE_NAME, (SIGNAL_FUNC) command_listkeys); */
 
   silc_nicklist_init();
 }
@@ -1025,6 +1041,7 @@ void silc_channels_deinit(void)
   signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
   signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
   signal_remove("gui exit", (SIGNAL_FUNC) sig_gui_quit);
+  signal_remove("mime", (SIGNAL_FUNC) sig_mime);
 
   command_unbind("part", (SIGNAL_FUNC) command_part);
   command_unbind("me", (SIGNAL_FUNC) command_me);
@@ -1032,7 +1049,7 @@ void silc_channels_deinit(void)
   command_unbind("notice", (SIGNAL_FUNC) command_notice);
   command_unbind("away", (SIGNAL_FUNC) command_away);
   command_unbind("key", (SIGNAL_FUNC) command_key);
-  command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys);
+/*  command_unbind("listkeys", (SIGNAL_FUNC) command_listkeys); */
 
   silc_nicklist_deinit();
 }
index bf572810b301fbd6dd4d3dbdc54a2d3f114693a2..421fe6fc5874bd4ef432666f32c78bf229c94d53 100644 (file)
@@ -52,6 +52,9 @@ extern bool silc_debug_hexdump;
 void silc_expandos_init(void);
 void silc_expandos_deinit(void);
 
+void silc_lag_init(void);
+void silc_lag_deinit(void);
+
 static int my_silc_scheduler(void)
 {
   silc_client_run_one(silc_client);
@@ -478,6 +481,7 @@ void silc_core_init(void)
   silc_channels_init();
   silc_queries_init();
   silc_expandos_init();
+  silc_lag_init();
 
   idletag = g_timeout_add(5, (GSourceFunc) my_silc_scheduler, NULL);
 
@@ -498,6 +502,7 @@ void silc_core_deinit(void)
     silc_channels_deinit();
     silc_queries_deinit();
     silc_expandos_deinit();
+    silc_lag_deinit();
     
     chat_protocol_unregister("SILC");
     
diff --git a/apps/irssi/src/silc/core/silc-lag.c b/apps/irssi/src/silc/core/silc-lag.c
new file mode 100644 (file)
index 0000000..1c5ad51
--- /dev/null
@@ -0,0 +1,106 @@
+#include "module.h"
+#include "signals.h"
+#include "misc.h"
+#include "settings.h"
+
+#include "silc-servers.h"
+
+#define        SILC_CLIENT_LAG_PING_ID 0x1337
+
+static int timeout_tag;
+static void lag_event_pong(SILC_SERVER_REC *server, 
+               SilcClientCommandReplyContext cmd);
+
+static void lag_get(SILC_SERVER_REC *server)
+{
+       SilcBuffer idp;
+       g_get_current_time(&server->lag_sent);
+       server->lag_last_check = time(NULL);
+
+       /* register pending callback & send ping */
+       silc_client_command_pending(server->conn, SILC_COMMAND_PING,
+                       SILC_CLIENT_LAG_PING_ID,
+                       (SilcCommandCb)lag_event_pong, (void *)server);
+       idp = silc_id_payload_encode(server->conn->remote_id, SILC_ID_SERVER);
+       silc_client_command_send(silc_client, server->conn,
+                       SILC_COMMAND_PING, SILC_CLIENT_LAG_PING_ID,
+                       1, 1, idp->data, idp->len);
+       silc_buffer_free(idp);
+}
+
+static void lag_event_pong(SILC_SERVER_REC *server,
+                          SilcClientCommandReplyContext cmd)
+{
+       GTimeVal now;
+
+       if (cmd->error != SILC_STATUS_OK) {
+
+               /* if the ping failed for some reason, try it again */
+               lag_get(server);
+               return;
+
+       }
+
+       if (server->lag_sent.tv_sec == 0) {
+               /* not expecting lag reply.. */
+               return;
+       }
+
+       g_get_current_time(&now);
+       server->lag = (int) get_timeval_diff(&now, &server->lag_sent);
+       memset(&server->lag_sent, 0, sizeof(server->lag_sent));
+
+       signal_emit("server lag", 1, server);
+}
+
+static int sig_check_lag(void)
+{
+       GSList *tmp, *next;
+       time_t now;
+       int lag_check_time, max_lag;
+
+       lag_check_time = settings_get_int("lag_check_time");
+       max_lag = settings_get_int("lag_max_before_disconnect");
+
+       if (lag_check_time <= 0)
+               return 1;
+
+       now = time(NULL);
+       for (tmp = servers; tmp != NULL; tmp = next) {
+               SILC_SERVER_REC *rec = tmp->data;
+
+               next = tmp->next;
+               if (!IS_SILC_SERVER(rec))
+                       continue;
+
+               if (rec->lag_sent.tv_sec != 0) {
+                       /* waiting for lag reply */
+                       if (max_lag > 1 && now-rec->lag_sent.tv_sec > max_lag) {
+                               /* too much lag, disconnect */
+                               signal_emit("server lag disconnect", 1, rec);
+                               rec->connection_lost = TRUE;
+                               server_disconnect((SERVER_REC *) rec);
+                       }
+               } else if (rec->lag_last_check+lag_check_time < now &&
+                        rec->cmdcount == 0 && rec->connected) {
+                       /* no commands in buffer - get the lag */
+                       lag_get(rec);
+               }
+       }
+
+       return 1;
+}
+
+void silc_lag_init(void)
+{
+       /* silc-client will need those... silc-plugin uses irc defaults */
+       settings_add_int("misc", "lag_check_time", 60);
+       settings_add_int("misc", "lag_max_before_disconnect", 300); 
+
+       timeout_tag = g_timeout_add(1000, (GSourceFunc) sig_check_lag, NULL);
+}
+
+void silc_lag_deinit(void)
+{
+       g_source_remove(timeout_tag);
+}
index a8c302bca499c9fb424caced1af589bcdd811842..6d4b65f876ca3b7ec2086dfb2e81a0073d3467fa 100644 (file)
@@ -1,7 +1,7 @@
 /*
  silc-nicklist.c : irssi
 
-    Copyright (C) 2000 Timo Sirainen
+    Copyright (C) 2000, 2003 Timo Sirainen, Pekka Riikonen
 
     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
@@ -32,7 +32,12 @@ SILC_NICK_REC *silc_nicklist_insert(SILC_CHANNEL_REC *channel,
   SILC_NICK_REC *rec;
 
   g_return_val_if_fail(IS_SILC_CHANNEL(channel), NULL);
-  g_return_val_if_fail(user != NULL, NULL);
+  if (!user)
+    return NULL;
+  if (!user->client)
+    return NULL;
+  if (!user->client->nickname)
+    return NULL;
 
   rec = g_new0(SILC_NICK_REC, 1);
   rec->nick = g_strdup(user->client->nickname);
@@ -42,9 +47,9 @@ SILC_NICK_REC *silc_nicklist_insert(SILC_CHANNEL_REC *channel,
   rec->silc_user = user;
   rec->unique_id = user->client;
 
-  if (user->mode & SILC_CHANNEL_UMODE_CHANOP) 
+  if (user->mode & SILC_CHANNEL_UMODE_CHANOP)
     rec->op = TRUE;
-  if (user->mode & SILC_CHANNEL_UMODE_CHANFO) 
+  if (user->mode & SILC_CHANNEL_UMODE_CHANFO)
     rec->founder = TRUE;
   rec->send_massjoin = send_massjoin;
 
@@ -73,7 +78,7 @@ char *silc_nick_strip(const char *nick)
   char *stripped, *spos;
 
   g_return_val_if_fail(nick != NULL, NULL);
-  
+
   spos = stripped = g_strdup(nick);
   while (isnickchar(*nick)) {
     if (isalnum((int) *nick))
@@ -99,15 +104,15 @@ int silc_nick_match(const char *nick, const char *msg)
   len = strlen(nick);
   if (g_strncasecmp(msg, nick, len) == 0 && !isalnum((int) msg[len]))
     return TRUE;
-  
+
   stripnick = silc_nick_strip(nick);
   stripmsg = silc_nick_strip(msg);
-  
+
   len = strlen(stripnick);
   ret = len > 0 && g_strncasecmp(stripmsg, stripnick, len) == 0 &&
     !isalnum((int) stripmsg[len]) &&
     (unsigned char) stripmsg[len] < 128;
-  
+
   g_free(stripnick);
   g_free(stripmsg);
 
index c6cbdb4889ce46b0bc7fb4a4cd4715fee43f8dd1..0287eb772649ac12d94a9766660881d03276f01b 100644 (file)
@@ -1,14 +1,14 @@
 /*
   silc-server.c : irssi
 
-  Copyright (C) 2000 - 2001 Timo Sirainen
-                            Pekka Riikonen <priikone@poseidon.pspt.fi>
+  Copyright (C) 2000 - 2003 Timo Sirainen
+                            Pekka Riikonen <priikone@silcnet.org>
 
   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
@@ -55,13 +55,13 @@ static int silc_send_channel(SILC_SERVER_REC *server,
                              SilcMessageFlags flags)
 {
   SILC_CHANNEL_REC *rec;
-  
+
   rec = silc_channel_find(server, channel);
   if (rec == NULL || rec->entry == NULL) {
     cmd_return_error_value(CMDERR_NOT_JOINED, FALSE);
   }
 
-  silc_client_send_channel_message(silc_client, server->conn, rec->entry, 
+  silc_client_send_channel_message(silc_client, server->conn, rec->entry,
                                   NULL, flags, msg, strlen(msg), TRUE);
   return TRUE;
 }
@@ -89,7 +89,7 @@ static void silc_send_msg_clients(SilcClient client,
   char *nickname = NULL;
 
   if (!clients_count) {
-    printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, 
+    printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
              "%s: There is no such client", rec->nick);
   } else {
     if (clients_count > 1) {
@@ -97,11 +97,11 @@ static void silc_send_msg_clients(SilcClient client,
 
       /* Find the correct one. The rec->nick might be a formatted nick
         so this will find the correct one. */
-      clients = silc_client_get_clients_local(silc_client, server->conn, 
-                                             nickname, rec->nick, 
+      clients = silc_client_get_clients_local(silc_client, server->conn,
+                                             nickname, rec->nick,
                                              &clients_count);
       if (!clients) {
-       printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, 
+       printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
                  "%s: There is no such client", rec->nick);
        silc_free(nickname);
        goto out;
@@ -113,21 +113,21 @@ static void silc_send_msg_clients(SilcClient client,
 
     /* Still check for exact math for nickname, this compares the
        real (formatted) nickname and the nick (maybe formatted) that
-       use gave. This is to assure that `nick' does not match 
+       use gave. This is to assure that `nick' does not match
        `nick@host'. */
     if (strcasecmp(rec->nick, clients[0]->nickname)) {
-      printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, 
+      printtext(NULL, NULL, MSGLEVEL_CLIENTERROR,
                "%s: There is no such client", rec->nick);
       goto out;
     }
 
     /* Send the private message */
-    silc_client_send_private_message(client, conn, target, 
+    silc_client_send_private_message(client, conn, target,
                                     rec->flags,
                                     rec->msg, rec->len,
                                     TRUE);
   }
-  
+
  out:
   g_free(rec->nick);
   g_free(rec->msg);
@@ -149,7 +149,7 @@ static int silc_send_msg(SILC_SERVER_REC *server, char *nick, char *msg,
   }
 
   /* Find client entry */
-  clients = silc_client_get_clients_local(silc_client, server->conn, 
+  clients = silc_client_get_clients_local(silc_client, server->conn,
                                          nickname, nick, &clients_count);
   if (!clients) {
     rec = g_new0(PRIVMSG_REC, 1);
@@ -168,28 +168,32 @@ static int silc_send_msg(SILC_SERVER_REC *server, char *nick, char *msg,
 
   /* Send the private message directly */
   silc_free(nickname);
-  silc_client_send_private_message(silc_client, server->conn, 
+  silc_client_send_private_message(silc_client, server->conn,
                                   clients[0], flags,
                                   msg, msg_len, TRUE);
   return TRUE;
 }
 
 void silc_send_mime(SILC_SERVER_REC *server, WI_ITEM_REC *to,
-                   const char *data, int data_len,
+                   const char *data,
                    const char *enc, const char *type)
 {
   SILC_CHANNEL_REC *channel;
   QUERY_REC *query;
+  char *unescaped_data;
+  SilcUInt32 unescaped_data_len;
   char *mime_data;
   int mime_data_len;
-  
-  if (!(IS_SILC_SERVER(server)) || (data == NULL) || (to == NULL) || 
+
+  if (!(IS_SILC_SERVER(server)) || (data == NULL) || (to == NULL) ||
       (enc == NULL) || (type == NULL))
     return;
-           
+
+  unescaped_data = silc_unescape_data(data, &unescaped_data_len);
+
 #define SILC_MIME_HEADER "MIME-Version: 1.0\r\nContent-Type: %s\r\nContent-Transfer-Encoding: %s\r\n\r\n"
 
-  mime_data_len = data_len + strlen(SILC_MIME_HEADER) - 4
+  mime_data_len = unescaped_data_len + strlen(SILC_MIME_HEADER) - 4
     + strlen(enc) + strlen(type);
   if (mime_data_len >= SILC_PACKET_MAX_LEN)
     return;
@@ -198,23 +202,24 @@ void silc_send_mime(SILC_SERVER_REC *server, WI_ITEM_REC *to,
   mime_data = silc_calloc(mime_data_len, sizeof(*mime_data));
   snprintf(mime_data, mime_data_len, SILC_MIME_HEADER, type, enc);
   memmove(mime_data + strlen(SILC_MIME_HEADER) - 4 + strlen(enc) + strlen(type),
-         data, data_len);
+         unescaped_data, unescaped_data_len);
 
 #undef SILC_MIME_HEADER
 
   if (IS_SILC_CHANNEL(to)) {
     channel = SILC_CHANNEL(to);
-    silc_client_send_channel_message(silc_client, server->conn, channel->entry, 
+    silc_client_send_channel_message(silc_client, server->conn, channel->entry,
                                     NULL, SILC_MESSAGE_FLAG_DATA,
                                     mime_data, mime_data_len, TRUE);
   } else if (IS_SILC_QUERY(to)) {
     query = SILC_QUERY(to);
     silc_send_msg(server, query->name, mime_data, mime_data_len,
                  SILC_MESSAGE_FLAG_DATA);
-    
+
   }
 
   silc_free(mime_data);
+  silc_free(unescaped_data);
 }
 
 static int isnickflag_func(char flag)
@@ -260,7 +265,7 @@ static void send_message(SILC_SERVER_REC *server, char *target,
   silc_free(message);
 }
 
-void silc_send_heartbeat(SilcSocketConnection sock, 
+void silc_send_heartbeat(SilcSocketConnection sock,
                         void *hb_context)
 {
   SILC_SERVER_REC *server = SILC_SERVER(hb_context);
@@ -349,7 +354,7 @@ SERVER_REC *silc_server_init_connect(SERVER_CONNECT_REC *conn)
   SILC_SERVER_REC *server;
 
   g_return_val_if_fail(IS_SILC_SERVER_CONNECT(conn), NULL);
-  if (conn->address == NULL || *conn->address == '\0') 
+  if (conn->address == NULL || *conn->address == '\0')
     return NULL;
   if (conn->nick == NULL || *conn->nick == '\0') {
     silc_say_error("Cannot connect: nickname is not set");
@@ -361,7 +366,7 @@ SERVER_REC *silc_server_init_connect(SERVER_CONNECT_REC *conn)
   server->connrec = (SILC_SERVER_CONNECT_REC *)conn;
   server_connect_ref(conn);
 
-  if (server->connrec->port <= 0) 
+  if (server->connrec->port <= 0)
     server->connrec->port = 706;
 
   server_connect_init((SERVER_REC *)server);
@@ -377,7 +382,7 @@ void silc_server_connect(SERVER_REC *server)
   }
 }
 
-/* Return a string of all channels in server in server->channels_join() 
+/* Return a string of all channels in server in server->channels_join()
    format */
 
 char *silc_server_get_channels(SILC_SERVER_REC *server)
@@ -391,7 +396,7 @@ char *silc_server_get_channels(SILC_SERVER_REC *server)
   chans = g_string_new(NULL);
   for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
     CHANNEL_REC *channel = tmp->data;
-    
+
     g_string_sprintfa(chans, "%s,", channel->name);
   }
 
@@ -400,7 +405,7 @@ char *silc_server_get_channels(SILC_SERVER_REC *server)
 
   ret = chans->str;
   g_string_free(chans, FALSE);
-  
+
   return ret;
 }
 
@@ -441,7 +446,7 @@ char *silc_server_get_channels(SILC_SERVER_REC *server)
 /* SYNTAX: FILE ACCEPT [<nickname>] */
 /* SYNTAX: FILE CLOSE [<nickname>] */
 /* SYNTAX: FILE */
-/* SYNTAX: JOIN <channel> [<passphrase>] [-cipher <cipher>] [-hmac <hmac>] [-founder] */
+/* SYNTAX: JOIN <channel> [<passphrase>] [-cipher <cipher>] [-hmac <hmac>] [-founder] [-auth [<pubkeyfile> <privkeyfile> [<privkey passphrase>]]]*/
 /* SYNTAX: DETACH */
 /* SYNTAX: WATCH [<-add | -del> <nickname>] */
 /* SYNTAX: STATS */
@@ -507,7 +512,7 @@ static void command_smsg(const char *data, SILC_SERVER_REC *server,
   char *target, *origtarget, *msg;
   void *free_arg;
   int free_ret, target_type;
-  
+
   g_return_if_fail(data != NULL);
   if (server == NULL || !server->connected)
     cmd_param_error(CMDERR_NOT_CONNECTED);
@@ -614,12 +619,12 @@ static void silc_client_file_monitor(SilcClient client,
   if (status == SILC_CLIENT_FILE_MONITOR_ERROR) {
     if (error == SILC_CLIENT_FILE_NO_SUCH_FILE)
       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
-                        SILCTXT_FILE_ERROR_NO_SUCH_FILE, 
-                        client_entry->nickname, 
+                        SILCTXT_FILE_ERROR_NO_SUCH_FILE,
+                        client_entry->nickname,
                         filepath ? filepath : "[N/A]");
     else if (error == SILC_CLIENT_FILE_PERMISSION_DENIED)
       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
-                        SILCTXT_FILE_ERROR_PERMISSION_DENIED, 
+                        SILCTXT_FILE_ERROR_PERMISSION_DENIED,
                         client_entry->nickname);
     else
       printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
@@ -708,7 +713,7 @@ static void silc_client_command_file_get_clients(SilcClient client,
   FileGetClients internal = (FileGetClients)context;
 
   if (!clients) {
-    printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown nick: %s", 
+    printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Unknown nick: %s",
              internal->nick);
     silc_free(internal->data);
     silc_free(internal->nick);
@@ -764,7 +769,7 @@ static void command_file(const char *data, SILC_SERVER_REC *server,
     if (!strcasecmp(argv[1], "close"))
       type = 3;
   }
-  
+
   if (type == 0)
     cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
 
@@ -779,7 +784,7 @@ static void command_file(const char *data, SILC_SERVER_REC *server,
                         MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[3]);
       goto out;
     }
-    
+
     /* Find client entry */
     entrys = silc_client_get_clients_local(silc_client, conn, nickname,
                                           argv[3], &entry_count);
@@ -813,8 +818,8 @@ static void command_file(const char *data, SILC_SERVER_REC *server,
        do_not_bind = TRUE;
     }
 
-    ret = 
-      silc_client_file_send(silc_client, conn, silc_client_file_monitor, 
+    ret =
+      silc_client_file_send(silc_client, conn, silc_client_file_monitor,
                            server, local_ip, local_port, do_not_bind,
                            client_entry, argv[2], &session_id);
     if (ret == SILC_CLIENT_FILE_OK) {
@@ -838,7 +843,7 @@ static void command_file(const char *data, SILC_SERVER_REC *server,
                           client_entry->nickname);
       if (ret == SILC_CLIENT_FILE_NO_SUCH_FILE)
        printformat_module("fe-common/silc", NULL, NULL, MSGLEVEL_CRAP,
-                          SILCTXT_FILE_ERROR_NO_SUCH_FILE, 
+                          SILCTXT_FILE_ERROR_NO_SUCH_FILE,
                           client_entry->nickname, argv[2]);
     }
 
@@ -852,7 +857,7 @@ static void command_file(const char *data, SILC_SERVER_REC *server,
                           MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
        goto out;
       }
-    
+
       /* Find client entry */
       entrys = silc_client_get_clients_local(silc_client, conn, nickname,
                                             argv[2], &entry_count);
@@ -875,7 +880,7 @@ static void command_file(const char *data, SILC_SERVER_REC *server,
        goto out;
       }
 
-      ret = silc_client_file_receive(silc_client, conn, 
+      ret = silc_client_file_receive(silc_client, conn,
                                     silc_client_file_monitor, server, NULL,
                                     server->current_session->session_id);
       if (ret != SILC_CLIENT_FILE_OK) {
@@ -895,7 +900,7 @@ static void command_file(const char *data, SILC_SERVER_REC *server,
     silc_dlist_start(server->ftp_sessions);
     while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
       if (ftp->client_entry == client_entry && !ftp->filepath) {
-       ret = silc_client_file_receive(silc_client, conn, 
+       ret = silc_client_file_receive(silc_client, conn,
                                       silc_client_file_monitor, server,
                                       NULL, ftp->session_id);
        if (ret != SILC_CLIENT_FILE_OK) {
@@ -928,7 +933,7 @@ static void command_file(const char *data, SILC_SERVER_REC *server,
                           MSGLEVEL_CRAP, SILCTXT_BAD_NICK, argv[2]);
        goto out;
       }
-    
+
       /* Find client entry */
       entrys = silc_client_get_clients_local(silc_client, conn, nickname,
                                             argv[2], &entry_count);
@@ -950,8 +955,8 @@ static void command_file(const char *data, SILC_SERVER_REC *server,
                           MSGLEVEL_CRAP, SILCTXT_FILE_NA);
        goto out;
       }
-      silc_client_file_close(silc_client, conn, 
+
+      silc_client_file_close(silc_client, conn,
                             server->current_session->session_id);
       printformat_module("fe-common/silc", server, NULL,
                         MSGLEVEL_CRAP, SILCTXT_FILE_CLOSED,
@@ -1005,7 +1010,7 @@ static void command_file(const char *data, SILC_SERVER_REC *server,
     while ((ftp = silc_dlist_get(server->ftp_sessions)) != SILC_LIST_END) {
       printformat_module("fe-common/silc", server, NULL,
                         MSGLEVEL_CRAP, SILCTXT_FILE_SHOW_LINE,
-                        ftp->client_entry->nickname, 
+                        ftp->client_entry->nickname,
                         ftp->send ? "send" : "receive",
                         (SilcUInt32)(ftp->offset + 1023) / 1024,
                         (SilcUInt32)(ftp->filesize + 1023) / 1024,
index f5fcb1b4846bf6d5dc3e1bcb6741268decb8ace7..0d594b9d9891049af8823d33408054cd9316dc73 100644 (file)
@@ -4,12 +4,12 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2002 Pekka Riikonen
+  Copyright (C) 1997 - 2003 Pekka Riikonen
 
   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; version 2 of the License.
-  
+
   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
@@ -25,12 +25,12 @@ static int silc_server_is_registered(SilcServer server,
                                     SilcSocketConnection sock,
                                     SilcServerCommandContext cmd,
                                     SilcCommand command);
-static void 
+static void
 silc_server_command_send_status_reply(SilcServerCommandContext cmd,
                                      SilcCommand command,
                                      SilcStatus status,
                                      SilcStatus error);
-static void 
+static void
 silc_server_command_send_status_data(SilcServerCommandContext cmd,
                                     SilcCommand command,
                                     SilcStatus status,
@@ -75,11 +75,11 @@ SilcServerCommand silc_command_list[] =
   SILC_SERVER_CMD(users, USERS, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(getkey, GETKEY, SILC_CF_LAG | SILC_CF_REG),
 
-  SILC_SERVER_CMD(connect, PRIV_CONNECT, 
+  SILC_SERVER_CMD(connect, PRIV_CONNECT,
                  SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
   SILC_SERVER_CMD(close, PRIV_CLOSE,
                  SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
-  SILC_SERVER_CMD(shutdown, PRIV_SHUTDOWN, SILC_CF_LAG | SILC_CF_REG | 
+  SILC_SERVER_CMD(shutdown, PRIV_SHUTDOWN, SILC_CF_LAG | SILC_CF_REG |
                  SILC_CF_OPER),
 
   { NULL, 0 },
@@ -88,7 +88,7 @@ SilcServerCommand silc_command_list[] =
 /* Performs several checks to the command. It first checks whether this
    command was called as pending command callback. If it was then it checks
    whether error occurred in the command reply where the pending command
-   callback was called. 
+   callback was called.
 
    It also checks that the requested command includes correct amount
    of arguments. */
@@ -170,9 +170,9 @@ SILC_TASK_CALLBACK(silc_server_command_process_timeout)
     SILC_LOG_DEBUG(("Calling %s command",
                    silc_get_command_name(timeout->cmd->cmd)));
     timeout->cmd->cb(timeout->ctx, NULL);
-  } else if (silc_server_is_registered(timeout->ctx->server, 
-                                      timeout->ctx->sock, 
-                                      timeout->ctx, 
+  } else if (silc_server_is_registered(timeout->ctx->server,
+                                      timeout->ctx->sock,
+                                      timeout->ctx,
                                       timeout->cmd->cmd)) {
     SILC_LOG_DEBUG(("Calling %s command",
                    silc_get_command_name(timeout->cmd->cmd)));
@@ -201,7 +201,7 @@ void silc_server_command_process(SilcServer server,
   ctx->server = server;
   ctx->sock = silc_socket_dup(sock);
   ctx->packet = silc_packet_context_dup(packet); /* Save original packet */
-  
+
   /* Parse the command payload in the packet */
   ctx->payload = silc_command_payload_parse(packet->buffer->data,
                                            packet->buffer->len);
@@ -260,14 +260,14 @@ void silc_server_command_process(SilcServer server,
 
     if (!fast && ((cmd->flags & SILC_CF_LAG_STRICT) ||
                  (client->fast_command > 5 && cmd->flags & SILC_CF_LAG)))
-      silc_schedule_task_add(server->schedule, sock->sock, 
+      silc_schedule_task_add(server->schedule, sock->sock,
                             silc_server_command_process_timeout, timeout,
                             (client->fast_command < 3 ? 0 :
                              2 - (time(NULL) - client->last_command)),
                             (client->fast_command < 3 ? 200000 : 0),
                             SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
     else
-      silc_schedule_task_add(server->schedule, sock->sock, 
+      silc_schedule_task_add(server->schedule, sock->sock,
                             silc_server_command_process_timeout, timeout,
                             0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
     return;
@@ -317,7 +317,7 @@ void silc_server_command_free(SilcServerCommandContext ctx)
 /* Duplicate Command Context by adding reference counter. The context won't
    be free'd untill it hits zero. */
 
-SilcServerCommandContext 
+SilcServerCommandContext
 silc_server_command_dup(SilcServerCommandContext ctx)
 {
   ctx->users++;
@@ -343,9 +343,9 @@ SILC_TASK_CALLBACK(silc_server_command_pending_timeout)
   cmdr = silc_calloc(1, sizeof(*cmdr));
   cmdr->server = server;
   cmdr->ident = reply->ident;
-      
+
   /* Check for pending commands and mark to be exeucted */
-  cmdr->callbacks = 
+  cmdr->callbacks =
     silc_server_command_pending_check(server, reply->reply_cmd,
                                      reply->ident, &cmdr->callbacks_count);
 
@@ -449,7 +449,7 @@ void silc_server_command_pending_del(SilcServer server,
 
 SilcServerCommandPendingCallbacks
 silc_server_command_pending_check(SilcServer server,
-                                 SilcCommand command, 
+                                 SilcCommand command,
                                  SilcUInt16 ident,
                                  SilcUInt32 *callbacks_count)
 {
@@ -475,7 +475,7 @@ silc_server_command_pending_check(SilcServer server,
 
 /* Sends simple status message as command reply packet */
 
-static void 
+static void
 silc_server_command_send_status_reply(SilcServerCommandContext cmd,
                                      SilcCommand command,
                                      SilcStatus status,
@@ -485,12 +485,12 @@ silc_server_command_send_status_reply(SilcServerCommandContext cmd,
 
   SILC_LOG_DEBUG(("Sending command status %d", status));
 
-  buffer = 
+  buffer =
     silc_command_reply_payload_encode_va(command, status, error,
                                         silc_command_get_ident(cmd->payload),
                                         0);
   silc_server_packet_send(cmd->server, cmd->sock,
-                         SILC_PACKET_COMMAND_REPLY, 0, 
+                         SILC_PACKET_COMMAND_REPLY, 0,
                          buffer->data, buffer->len, FALSE);
   silc_buffer_free(buffer);
 }
@@ -498,7 +498,7 @@ silc_server_command_send_status_reply(SilcServerCommandContext cmd,
 /* Sends command status reply with one extra argument. The argument
    type must be sent as argument. */
 
-static void 
+static void
 silc_server_command_send_status_data(SilcServerCommandContext cmd,
                                     SilcCommand command,
                                     SilcStatus status,
@@ -511,19 +511,46 @@ silc_server_command_send_status_data(SilcServerCommandContext cmd,
 
   SILC_LOG_DEBUG(("Sending command status %d", status));
 
-  buffer = 
+  buffer =
     silc_command_reply_payload_encode_va(command, status, 0,
                                         silc_command_get_ident(cmd->payload),
                                         1, arg_type, arg, arg_len);
   silc_server_packet_send(cmd->server, cmd->sock,
-                         SILC_PACKET_COMMAND_REPLY, 0, 
+                         SILC_PACKET_COMMAND_REPLY, 0,
+                         buffer->data, buffer->len, FALSE);
+  silc_buffer_free(buffer);
+}
+
+static void
+silc_server_command_send_status_data2(SilcServerCommandContext cmd,
+                                     SilcCommand command,
+                                     SilcStatus status,
+                                     SilcStatus error,
+                                     SilcUInt32 arg_type1,
+                                     const unsigned char *arg1,
+                                     SilcUInt32 arg_len1,
+                                     SilcUInt32 arg_type2,
+                                     const unsigned char *arg2,
+                                     SilcUInt32 arg_len2)
+{
+  SilcBuffer buffer;
+
+  SILC_LOG_DEBUG(("Sending command status %d", status));
+
+  buffer =
+    silc_command_reply_payload_encode_va(command, status, 0,
+                                        silc_command_get_ident(cmd->payload),
+                                        2, arg_type1, arg1, arg_len1,
+                                        arg_type2, arg2, arg_len2);
+  silc_server_packet_send(cmd->server, cmd->sock,
+                         SILC_PACKET_COMMAND_REPLY, 0,
                          buffer->data, buffer->len, FALSE);
   silc_buffer_free(buffer);
 }
 
 /* This function can be called to check whether in the command reply
    an error occurred. This function has no effect if this is called
-   when the command function was not called as pending command callback. 
+   when the command function was not called as pending command callback.
    This returns TRUE if error had occurred. */
 
 static bool
@@ -539,11 +566,11 @@ silc_server_command_pending_error_check(SilcServerCommandContext cmd,
 
     /* Send the same command reply payload */
     silc_command_set_command(cmdr->payload, silc_command_get(cmd->payload));
-    silc_command_set_ident(cmdr->payload, 
+    silc_command_set_ident(cmdr->payload,
                           silc_command_get_ident(cmd->payload));
     buffer = silc_command_payload_encode_payload(cmdr->payload);
     silc_server_packet_send(cmd->server, cmd->sock,
-                           SILC_PACKET_COMMAND_REPLY, 0, 
+                           SILC_PACKET_COMMAND_REPLY, 0,
                            buffer->data, buffer->len, FALSE);
     silc_buffer_free(buffer);
     return TRUE;
@@ -625,8 +652,8 @@ SILC_SERVER_CMD_FUNC(nick)
   }
 
   /* Create new Client ID */
-  while (!silc_id_create_client_id(cmd->server, cmd->server->id, 
-                                  cmd->server->rng, 
+  while (!silc_id_create_client_id(cmd->server, cmd->server->id,
+                                  cmd->server->rng,
                                   cmd->server->md5hash, nick,
                                   &new_id)) {
     nickfail++;
@@ -662,17 +689,17 @@ SILC_SERVER_CMD_FUNC(nick)
   client->nickname = strdup(nick);
 
   /* Update client cache */
-  silc_idcache_add(server->local_list->clients, client->nickname, 
+  silc_idcache_add(server->local_list->clients, client->nickname,
                   client->id, (void *)client, 0, NULL);
 
   nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
 
   /* Send NICK_CHANGE notify to the client's channels */
-  silc_server_send_notify_on_channels(server, NULL, client, 
+  silc_server_send_notify_on_channels(server, NULL, client,
                                      SILC_NOTIFY_TYPE_NICK_CHANGE, 3,
-                                     oidp->data, oidp->len, 
+                                     oidp->data, oidp->len,
                                      nidp->data, nidp->len,
-                                     client->nickname, 
+                                     client->nickname,
                                      strlen(client->nickname));
 
   /* Check if anyone is watching the new nickname */
@@ -682,7 +709,7 @@ SILC_SERVER_CMD_FUNC(nick)
 
  send_reply:
   /* Send the new Client ID as reply command back to client */
-  packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NICK, 
+  packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NICK,
                                                SILC_STATUS_OK, 0, ident, 2,
                                                2, nidp->data, nidp->len,
                                                3, nick, strlen(nick));
@@ -693,7 +720,7 @@ SILC_SERVER_CMD_FUNC(nick)
   silc_buffer_free(nidp);
   if (oidp)
     silc_buffer_free(oidp);
-  
+
  out:
   silc_server_command_free(cmd);
 }
@@ -702,7 +729,7 @@ SILC_SERVER_CMD_FUNC(nick)
 
 static void
 silc_server_command_list_send_reply(SilcServerCommandContext cmd,
-                                   SilcChannelEntry *lch, 
+                                   SilcChannelEntry *lch,
                                    SilcUInt32 lch_count,
                                    SilcChannelEntry *gch,
                                    SilcUInt32 gch_count)
@@ -757,16 +784,16 @@ silc_server_command_list_send_reply(SilcServerCommandContext cmd,
     }
 
     /* Send the reply */
-    packet = 
-      silc_command_reply_payload_encode_va(SILC_COMMAND_LIST, 
+    packet =
+      silc_command_reply_payload_encode_va(SILC_COMMAND_LIST,
                                           status, 0, ident, 4,
                                           2, idp->data, idp->len,
-                                          3, entry->channel_name, 
+                                          3, entry->channel_name,
                                           strlen(entry->channel_name),
                                           4, topic, topic ? strlen(topic) : 0,
                                           5, usercount, 4);
-    silc_server_packet_send(cmd->server, cmd->sock, 
-                           SILC_PACKET_COMMAND_REPLY, 0, packet->data, 
+    silc_server_packet_send(cmd->server, cmd->sock,
+                           SILC_PACKET_COMMAND_REPLY, 0, packet->data,
                            packet->len, FALSE);
     silc_buffer_free(packet);
     silc_buffer_free(idp);
@@ -796,16 +823,16 @@ silc_server_command_list_send_reply(SilcServerCommandContext cmd,
     }
 
     /* Send the reply */
-    packet = 
-      silc_command_reply_payload_encode_va(SILC_COMMAND_LIST, 
+    packet =
+      silc_command_reply_payload_encode_va(SILC_COMMAND_LIST,
                                           status, 0, ident, 4,
                                           2, idp->data, idp->len,
-                                          3, entry->channel_name, 
+                                          3, entry->channel_name,
                                           strlen(entry->channel_name),
                                           4, topic, topic ? strlen(topic) : 0,
                                           5, usercount, 4);
-    silc_server_packet_send(cmd->server, cmd->sock, 
-                           SILC_PACKET_COMMAND_REPLY, 0, packet->data, 
+    silc_server_packet_send(cmd->server, cmd->sock,
+                           SILC_PACKET_COMMAND_REPLY, 0, packet->data,
                            packet->len, FALSE);
     silc_buffer_free(packet);
     silc_buffer_free(idp);
@@ -830,11 +857,11 @@ SILC_SERVER_CMD_FUNC(list)
 
   /* If we are normal server, send the command to router, since we
      want to know all channels in the network. */
-  if (!cmd->pending && server->server_type != SILC_ROUTER && 
+  if (!cmd->pending && server->server_type != SILC_ROUTER &&
       !server->standalone) {
     SilcBuffer tmpbuf;
     SilcUInt16 old_ident;
-    
+
     old_ident = silc_command_get_ident(cmd->payload);
     silc_command_set_ident(cmd->payload, ++server->cmd_ident);
     tmpbuf = silc_command_payload_encode_payload(cmd->payload);
@@ -843,9 +870,9 @@ SILC_SERVER_CMD_FUNC(list)
                            tmpbuf->data, tmpbuf->len, TRUE);
 
     /* Reprocess this packet after received reply from router */
-    silc_server_command_pending(server, SILC_COMMAND_LIST, 
+    silc_server_command_pending(server, SILC_COMMAND_LIST,
                                silc_command_get_ident(cmd->payload),
-                               silc_server_command_list, 
+                               silc_server_command_list,
                                silc_server_command_dup(cmd));
     cmd->pending = TRUE;
     silc_command_set_ident(cmd->payload, old_ident);
@@ -867,13 +894,13 @@ SILC_SERVER_CMD_FUNC(list)
   /* Get the channels from local list */
   lchannels = silc_idlist_get_channels(server->local_list, channel_id,
                                       &lch_count);
-  
+
   /* Get the channels from global list */
   gchannels = silc_idlist_get_channels(server->global_list, channel_id,
                                       &gch_count);
 
   /* Send the reply */
-  silc_server_command_list_send_reply(cmd, lchannels, lch_count, 
+  silc_server_command_list_send_reply(cmd, lchannels, lch_count,
                                      gchannels, gch_count);
 
   silc_free(lchannels);
@@ -921,15 +948,15 @@ SILC_SERVER_CMD_FUNC(topic)
   }
 
   /* Check whether the channel exists */
-  channel = silc_idlist_find_channel_by_id(server->local_list, 
+  channel = silc_idlist_find_channel_by_id(server->local_list,
                                           channel_id, NULL);
   if (!channel) {
-    channel = silc_idlist_find_channel_by_id(server->global_list, 
+    channel = silc_idlist_find_channel_by_id(server->global_list,
                                             channel_id, NULL);
     if (!channel) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
-                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL,
-                                           0);
+      silc_server_command_send_status_data(cmd, SILC_COMMAND_TOPIC,
+                                          SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
+                                          0, 2, tmp, tmp_len);
       goto out;
     }
   }
@@ -953,18 +980,20 @@ SILC_SERVER_CMD_FUNC(topic)
 
     /* See whether the client is on channel and has rights to change topic */
     if (!silc_server_client_on_channel(client, channel, &chl)) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
-                                           SILC_STATUS_ERR_NOT_ON_CHANNEL,
-                                           0);
+      tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+      silc_server_command_send_status_data(cmd, SILC_COMMAND_TOPIC,
+                                          SILC_STATUS_ERR_NOT_ON_CHANNEL,
+                                          0, 2, tmp, tmp_len);
       goto out;
     }
 
     if (channel->mode & SILC_CHANNEL_MODE_TOPIC &&
        !(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
        !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
-                                           SILC_STATUS_ERR_NO_CHANNEL_PRIV,
-                                           0);
+      tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+      silc_server_command_send_status_data(cmd, SILC_COMMAND_TOPIC,
+                                          SILC_STATUS_ERR_NO_CHANNEL_PRIV,
+                                          0, 2, tmp, tmp_len);
       goto out;
     }
 
@@ -981,7 +1010,7 @@ SILC_SERVER_CMD_FUNC(topic)
 
       /* Send notify about topic change to all clients on the channel */
       idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
-      silc_server_send_notify_to_channel(server, NULL, channel, FALSE, 
+      silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
                                         SILC_NOTIFY_TYPE_TOPIC_SET, 2,
                                         idp->data, idp->len,
                                         channel->topic,
@@ -992,11 +1021,11 @@ SILC_SERVER_CMD_FUNC(topic)
 
   /* Send the topic to client as reply packet */
   idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
-  packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC, 
-                                               SILC_STATUS_OK, 0, ident, 2, 
+  packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC,
+                                               SILC_STATUS_OK, 0, ident, 2,
                                                2, idp->data, idp->len,
-                                               3, channel->topic, 
-                                               channel->topic ? 
+                                               3, channel->topic,
+                                               channel->topic ?
                                                strlen(channel->topic) : 0);
   silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
                          0, packet->data, packet->len, FALSE);
@@ -1009,7 +1038,7 @@ SILC_SERVER_CMD_FUNC(topic)
   silc_server_command_free(cmd);
 }
 
-/* Server side of INVITE command. Invites some client to join some channel. 
+/* Server side of INVITE command. Invites some client to join some channel.
    This command is also used to manage the invite list of the channel. */
 
 SILC_SERVER_CMD_FUNC(invite)
@@ -1026,8 +1055,9 @@ SILC_SERVER_CMD_FUNC(invite)
   SilcArgumentPayload args;
   SilcHashTableList htl;
   SilcBuffer packet, list, tmp2;
-  unsigned char *tmp;
-  SilcUInt32 len, type;
+  SilcBufferStruct alist;
+  unsigned char *tmp, *atype = NULL;
+  SilcUInt32 len, type, len2;
   SilcUInt16 argc = 0, ident = silc_command_get_ident(cmd->payload);
 
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_INVITE, cmd, 1, 4);
@@ -1047,15 +1077,15 @@ SILC_SERVER_CMD_FUNC(invite)
   }
 
   /* Get the channel entry */
-  channel = silc_idlist_find_channel_by_id(server->local_list, 
+  channel = silc_idlist_find_channel_by_id(server->local_list,
                                           channel_id, NULL);
   if (!channel) {
-    channel = silc_idlist_find_channel_by_id(server->global_list, 
+    channel = silc_idlist_find_channel_by_id(server->global_list,
                                             channel_id, NULL);
     if (!channel) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
-                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL,
-                                           0);
+      silc_server_command_send_status_data(cmd, SILC_COMMAND_INVITE,
+                                          SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
+                                          0, 2, tmp, len);
       goto out;
     }
   }
@@ -1063,8 +1093,9 @@ SILC_SERVER_CMD_FUNC(invite)
   /* Check whether the sender of this command is on the channel. */
   sender = (SilcClientEntry)sock->user_data;
   if (!sender || !silc_server_client_on_channel(sender, channel, &chl)) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
-                                         SILC_STATUS_ERR_NOT_ON_CHANNEL, 0);
+    silc_server_command_send_status_data(cmd, SILC_COMMAND_INVITE,
+                                        SILC_STATUS_ERR_NOT_ON_CHANNEL, 0,
+                                        2, tmp, len);
     goto out;
   }
 
@@ -1073,9 +1104,9 @@ SILC_SERVER_CMD_FUNC(invite)
   if (channel->mode & SILC_CHANNEL_MODE_INVITE &&
       !(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
       !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
-                                         SILC_STATUS_ERR_NO_CHANNEL_PRIV,
-                                         0);
+    silc_server_command_send_status_data(cmd, SILC_COMMAND_INVITE,
+                                        SILC_STATUS_ERR_NO_CHANNEL_PRIV,
+                                        0, 2, tmp, len);
     goto out;
   }
 
@@ -1095,17 +1126,18 @@ SILC_SERVER_CMD_FUNC(invite)
     dest = silc_server_query_client(server, dest_id, FALSE, &resolve);
     if (!dest) {
       if (server->server_type != SILC_SERVER || !resolve || cmd->pending) {
-       silc_server_command_send_status_reply(
+       silc_server_command_send_status_data(
                                        cmd, SILC_COMMAND_INVITE,
-                                       SILC_STATUS_ERR_NO_SUCH_CLIENT_ID, 0);
+                                       SILC_STATUS_ERR_NO_SUCH_CLIENT_ID, 0,
+                                       2, tmp, len);
        goto out;
       }
-      
+
       /* The client info is being resolved. Reprocess this packet after
         receiving the reply to the query. */
-      silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
+      silc_server_command_pending(server, SILC_COMMAND_WHOIS,
                                  server->cmd_ident,
-                                 silc_server_command_invite, 
+                                 silc_server_command_invite,
                                  silc_server_command_dup(cmd));
       cmd->pending = TRUE;
       goto out;
@@ -1113,19 +1145,21 @@ SILC_SERVER_CMD_FUNC(invite)
 
     /* Check whether the requested client is already on the channel. */
     if (silc_server_client_on_channel(dest, channel, NULL)) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+      atype = silc_argument_get_arg_type(cmd->args, 1, &len2);
+      silc_server_command_send_status_data2(cmd, SILC_COMMAND_INVITE,
                                            SILC_STATUS_ERR_USER_ON_CHANNEL,
-                                           0);
+                                           0, 2, tmp, len,
+                                           3, atype, len2);
       goto out;
     }
-    
+
     /* Get route to the client */
-    dest_sock = silc_server_get_client_route(server, NULL, 0, dest_id, 
+    dest_sock = silc_server_get_client_route(server, NULL, 0, dest_id,
                                             &idata, NULL);
     if (!dest_sock) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
-                                           SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
-                                           0);
+      silc_server_command_send_status_data(cmd, SILC_COMMAND_INVITE,
+                                          SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
+                                          0, 2, tmp, len);
       goto out;
     }
 
@@ -1160,11 +1194,11 @@ SILC_SERVER_CMD_FUNC(invite)
       SilcBuffer idp, idp2;
       idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
       idp2 = silc_id_payload_encode(sender->id, SILC_ID_CLIENT);
-      silc_server_send_notify_dest(server, dest_sock, FALSE, dest_id, 
+      silc_server_send_notify_dest(server, dest_sock, FALSE, dest_id,
                                   SILC_ID_CLIENT,
-                                  SILC_NOTIFY_TYPE_INVITE, 3, 
-                                  idp->data, idp->len, 
-                                  channel->channel_name, 
+                                  SILC_NOTIFY_TYPE_INVITE, 3,
+                                  idp->data, idp->len,
+                                  channel->channel_name,
                                   strlen(channel->channel_name),
                                   idp2->data, idp2->len);
       silc_buffer_free(idp);
@@ -1173,11 +1207,11 @@ SILC_SERVER_CMD_FUNC(invite)
   }
 
   /* Get the invite information */
-  tmp = silc_argument_get_arg_type(cmd->args, 4, &len);
-  if (tmp && len > 2) {
+  tmp = silc_argument_get_arg_type(cmd->args, 4, &len2);
+  if (tmp && len2 > 2) {
     /* Parse the arguments to see they are constructed correctly */
     SILC_GET16_MSB(argc, tmp);
-    args = silc_argument_payload_parse(tmp + 2, len - 2, argc);
+    args = silc_argument_payload_parse(tmp + 2, len2 - 2, argc);
     if (!args) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
                                            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
@@ -1186,9 +1220,9 @@ SILC_SERVER_CMD_FUNC(invite)
     }
 
     /* Get the type of action */
-    tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
-    if (tmp && len == 1) {
-      if (tmp[0] == 0x00) {
+    atype = silc_argument_get_arg_type(cmd->args, 3, &len);
+    if (atype && len == 1) {
+      if (atype[0] == 0x00) {
        /* Allocate hash table for invite list if it doesn't exist yet */
        if (!channel->invite_list)
          channel->invite_list =
@@ -1196,7 +1230,7 @@ SILC_SERVER_CMD_FUNC(invite)
                                  NULL, NULL, NULL,
                                  silc_server_inviteban_destruct, channel,
                                  TRUE);
-    
+
        /* Check for resource limit */
        if (silc_hash_table_count(channel->invite_list) > 64) {
          silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
@@ -1208,7 +1242,7 @@ SILC_SERVER_CMD_FUNC(invite)
 
       /* Now add or delete the information. */
       silc_server_inviteban_process(server, channel->invite_list,
-                                   (SilcUInt8)tmp[0], args);
+                                   (SilcUInt8)atype[0], args);
     }
     silc_argument_payload_free(args);
   }
@@ -1228,14 +1262,36 @@ SILC_SERVER_CMD_FUNC(invite)
     silc_hash_table_list_reset(&htl);
   }
 
-  /* Send notify to the primary router */
-  silc_server_send_notify_invite(
-                        server, SILC_PRIMARY_ROUTE(server),
-                        SILC_BROADCAST(server), channel, sender->id,
-                        silc_argument_get_arg_type(cmd->args, 3, NULL),
-                        list);
+  /* The notify is sent to local servers (not clients), and to network. */
+  if (atype && tmp && len2) {
+    silc_buffer_set(&alist, tmp, len2);
+
+    /* Send to local servers if we are router */
+    if (server->server_type == SILC_ROUTER) {
+      SilcBuffer idp, idp2;
+      idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
+      idp2 = silc_id_payload_encode(sender->id, SILC_ID_CLIENT);
+      silc_server_send_notify_to_channel(server, NULL, channel, FALSE, FALSE,
+                                         SILC_NOTIFY_TYPE_INVITE, 5,
+                                        idp->data, idp->len,
+                                        channel->channel_name,
+                                        strlen(channel->channel_name),
+                                        idp2->data, idp2->len,
+                                        atype, 1,
+                                        tmp ? alist.data : NULL,
+                                        tmp ? alist.len : 0);
+      silc_buffer_free(idp);
+      silc_buffer_free(idp2);
+    }
+
+    /* Send to network */
+    silc_server_send_notify_invite(server, SILC_PRIMARY_ROUTE(server),
+                                  SILC_BROADCAST(server), channel,
+                                  sender->id, atype,
+                                  tmp ? &alist : NULL);
+  }
 
-  /* Send invite list back only if the list was modified, or now arguments
+  /* Send invite list back only if the list was modified, or no arguments
      was given. */
   type = 0;
   argc = silc_argument_get_arg_num(cmd->args);
@@ -1249,10 +1305,10 @@ SILC_SERVER_CMD_FUNC(invite)
   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INVITE,
                                                SILC_STATUS_OK, 0, ident, 2,
                                                2, tmp, len,
-                                               3, type && list ? 
+                                               3, type && list ?
                                                list->data : NULL,
                                                type && list ? list->len : 0);
-  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
+  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
                          packet->data, packet->len, FALSE);
   silc_buffer_free(packet);
   silc_buffer_free(list);
@@ -1291,7 +1347,7 @@ SILC_TASK_CALLBACK(silc_server_command_quit_cb)
 }
 
 /* Quits SILC session. This is the normal way to disconnect client. */
+
 SILC_SERVER_CMD_FUNC(quit)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
@@ -1373,22 +1429,22 @@ SILC_SERVER_CMD_FUNC(kill)
   }
   client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
   if (!client_id) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
-                                         SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
-                                         0);
+    silc_server_command_send_status_data(cmd, SILC_COMMAND_KILL,
+                                        SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
+                                        0, 2, tmp, tmp_len);
     goto out;
   }
 
   /* Get the client entry */
-  remote_client = silc_idlist_find_client_by_id(server->local_list, 
+  remote_client = silc_idlist_find_client_by_id(server->local_list,
                                                client_id, TRUE, NULL);
   if (!remote_client) {
-    remote_client = silc_idlist_find_client_by_id(server->global_list, 
+    remote_client = silc_idlist_find_client_by_id(server->global_list,
                                                  client_id, TRUE, NULL);
     if (!remote_client) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
-                                           SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
-                                           0);
+      silc_server_command_send_status_data(cmd, SILC_COMMAND_KILL,
+                                          SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
+                                          0, 2, tmp, tmp_len);
       goto out;
     }
   }
@@ -1418,14 +1474,14 @@ SILC_SERVER_CMD_FUNC(kill)
                               server->sha1hash, remote_client->id,
                               SILC_ID_CLIENT)) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
-                                           SILC_STATUS_ERR_AUTH_FAILED,
-                                           0);
+                                           SILC_STATUS_ERR_AUTH_FAILED, 0);
       goto out;
     }
 
     /* Send reply to the sender */
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
-                                         SILC_STATUS_OK, 0);
+    silc_server_command_send_status_data(cmd, SILC_COMMAND_KILL,
+                                        SILC_STATUS_OK, 0,
+                                        2, tmp, tmp_len);
 
     /* Do normal signoff for the destination client */
     sock = remote_client->connection;
@@ -1440,8 +1496,9 @@ SILC_SERVER_CMD_FUNC(kill)
     /* Router operator killing */
 
     /* Send reply to the sender */
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
-                                         SILC_STATUS_OK, 0);
+    silc_server_command_send_status_data(cmd, SILC_COMMAND_KILL,
+                                        SILC_STATUS_OK, 0,
+                                        2, tmp, tmp_len);
 
     /* Check if anyone is watching this nickname */
     if (server->server_type == SILC_ROUTER)
@@ -1458,8 +1515,8 @@ SILC_SERVER_CMD_FUNC(kill)
   silc_server_command_free(cmd);
 }
 
-/* Server side of command INFO. This sends information about us to 
-   the client. If client requested specific server we will send the 
+/* Server side of command INFO. This sends information about us to
+   the client. If client requested specific server we will send the
    command to that server. */
 
 SILC_SERVER_CMD_FUNC(info)
@@ -1498,9 +1555,9 @@ SILC_SERVER_CMD_FUNC(info)
       entry = silc_idlist_find_server_by_id(server->global_list,
                                            server_id, TRUE, NULL);
       if (!entry && server->server_type != SILC_SERVER) {
-       silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
-                                             SILC_STATUS_ERR_NO_SUCH_SERVER,
-                                             0);
+       silc_server_command_send_status_data(cmd, SILC_COMMAND_INFO,
+                                            SILC_STATUS_ERR_NO_SUCH_SERVER_ID,
+                                            0, 2, tmp, tmp_len);
        goto out;
       }
     }
@@ -1510,15 +1567,15 @@ SILC_SERVER_CMD_FUNC(info)
   if (server->server_type != SILC_SERVER && cmd->sock->user_data == entry)
     goto out;
 
-  if ((!dest_server && !server_id && !entry) || (entry && 
+  if ((!dest_server && !server_id && !entry) || (entry &&
                                                 entry == server->id_entry) ||
-      (dest_server && !cmd->pending && 
+      (dest_server && !cmd->pending &&
        !strncasecmp(dest_server, server->server_name, strlen(dest_server)))) {
     /* Send our reply */
     char info_string[256];
 
     memset(info_string, 0, sizeof(info_string));
-    snprintf(info_string, sizeof(info_string), 
+    snprintf(info_string, sizeof(info_string),
             "location: %s server: %s admin: %s <%s>",
             server->config->server_info->location,
             server->config->server_info->server_type,
@@ -1553,7 +1610,7 @@ SILC_SERVER_CMD_FUNC(info)
                              tmpbuf->data, tmpbuf->len, TRUE);
 
       /* Reprocess this packet after received reply from router */
-      silc_server_command_pending(server, SILC_COMMAND_INFO, 
+      silc_server_command_pending(server, SILC_COMMAND_INFO,
                                  silc_command_get_ident(cmd->payload),
                                  silc_server_command_info,
                                  silc_server_command_dup(cmd));
@@ -1577,7 +1634,7 @@ SILC_SERVER_CMD_FUNC(info)
                              tmpbuf->data, tmpbuf->len, TRUE);
 
       /* Reprocess this packet after received reply from router */
-      silc_server_command_pending(server, SILC_COMMAND_INFO, 
+      silc_server_command_pending(server, SILC_COMMAND_INFO,
                                  silc_command_get_ident(cmd->payload),
                                  silc_server_command_info,
                                  silc_server_command_dup(cmd));
@@ -1591,8 +1648,11 @@ SILC_SERVER_CMD_FUNC(info)
   silc_free(server_id);
 
   if (!entry) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
-                                         SILC_STATUS_ERR_NO_SUCH_SERVER, 0);
+    if (dest_server)
+      silc_server_command_send_status_data(cmd, SILC_COMMAND_INFO,
+                                          SILC_STATUS_ERR_NO_SUCH_SERVER, 0,
+                                          2, dest_server,
+                                          strlen(dest_server));
     goto out;
   }
 
@@ -1605,14 +1665,14 @@ SILC_SERVER_CMD_FUNC(info)
   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
                                                SILC_STATUS_OK, 0, ident, 3,
                                                2, idp->data, idp->len,
-                                               3, server_name, 
+                                               3, server_name,
                                                strlen(server_name),
-                                               4, server_info, 
-                                               server_info ? 
+                                               4, server_info,
+                                               server_info ?
                                                strlen(server_info) : 0);
-  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
+  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
                          packet->data, packet->len, FALSE);
-    
+
   silc_buffer_free(packet);
   silc_buffer_free(idp);
 
@@ -1636,7 +1696,8 @@ SILC_SERVER_CMD_FUNC(ping)
   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
   if (!tmp) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
-                                         SILC_STATUS_ERR_NO_SERVER_ID, 0);
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
+                                         0);
     goto out;
   }
   server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
@@ -1648,8 +1709,9 @@ SILC_SERVER_CMD_FUNC(ping)
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
                                          SILC_STATUS_OK, 0);
   } else {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
-                                         SILC_STATUS_ERR_NO_SUCH_SERVER, 0);
+    silc_server_command_send_status_data(cmd, SILC_COMMAND_PING,
+                                        SILC_STATUS_ERR_NO_SUCH_SERVER_ID, 0,
+                                        2, tmp, tmp_len);
     goto out;
   }
 
@@ -1676,7 +1738,7 @@ SILC_SERVER_CMD_FUNC(stats)
   /* Get Server ID */
   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
   if (!tmp) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_STATS,
                                          SILC_STATUS_ERR_NO_SERVER_ID, 0);
     goto out;
   }
@@ -1686,8 +1748,9 @@ SILC_SERVER_CMD_FUNC(stats)
 
   /* The ID must be ours */
   if (!SILC_ID_SERVER_COMPARE(server->id, server_id)) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
-                                         SILC_STATUS_ERR_NO_SUCH_SERVER, 0);
+    silc_server_command_send_status_data(cmd, SILC_COMMAND_STATS,
+                                        SILC_STATUS_ERR_NO_SUCH_SERVER_ID, 0,
+                                        2, tmp, tmp_len);
     silc_free(server_id);
     goto out;
   }
@@ -1696,12 +1759,12 @@ SILC_SERVER_CMD_FUNC(stats)
   /* If we are router then just send everything we got. If we are normal
      server then we'll send this to our router to get all the latest
      statistical information. */
-  if (!cmd->pending && server->server_type != SILC_ROUTER && 
+  if (!cmd->pending && server->server_type != SILC_ROUTER &&
       !server->standalone) {
     /* Send request to our router */
-    SilcBuffer idp = silc_id_payload_encode(server->router->id, 
+    SilcBuffer idp = silc_id_payload_encode(server->router->id,
                                            SILC_ID_SERVER);
-    packet = silc_command_payload_encode_va(SILC_COMMAND_STATS, 
+    packet = silc_command_payload_encode_va(SILC_COMMAND_STATS,
                                            ++server->cmd_ident, 1,
                                            1, idp->data, idp->len);
     silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
@@ -1709,7 +1772,7 @@ SILC_SERVER_CMD_FUNC(stats)
                            packet->len, FALSE);
 
     /* Reprocess this packet after received reply from router */
-    silc_server_command_pending(server, SILC_COMMAND_STATS, 
+    silc_server_command_pending(server, SILC_COMMAND_STATS,
                                server->cmd_ident,
                                silc_server_command_stats,
                                silc_server_command_dup(cmd));
@@ -1741,7 +1804,7 @@ SILC_SERVER_CMD_FUNC(stats)
                     SILC_STR_UI_INT(server->stat.router_ops),
                     SILC_STR_END);
 
-  packet = silc_command_reply_payload_encode_va(SILC_COMMAND_STATS, 
+  packet = silc_command_reply_payload_encode_va(SILC_COMMAND_STATS,
                                                SILC_STATUS_OK, 0, ident, 2,
                                                2, tmp, tmp_len,
                                                3, stats->data, stats->len);
@@ -1758,7 +1821,7 @@ SILC_SERVER_CMD_FUNC(stats)
    has been either created or resolved from ID lists. This joins the sent
    client to the channel. */
 
-static void silc_server_command_join_channel(SilcServer server, 
+static void silc_server_command_join_channel(SilcServer server,
                                             SilcServerCommandContext cmd,
                                             SilcChannelEntry channel,
                                             SilcClientID *client_id,
@@ -1766,7 +1829,9 @@ static void silc_server_command_join_channel(SilcServer server,
                                             bool create_key,
                                             SilcUInt32 umode,
                                             const unsigned char *auth,
-                                            SilcUInt32 auth_len)
+                                            SilcUInt32 auth_len,
+                                            const unsigned char *cauth,
+                                            SilcUInt32 cauth_len)
 {
   SilcSocketConnection sock = cmd->sock;
   unsigned char *tmp;
@@ -1780,7 +1845,7 @@ static void silc_server_command_join_channel(SilcServer server,
   char check[512], check2[512];
   bool founder = FALSE;
   bool resolve;
-  SilcBuffer fkey = NULL;
+  SilcBuffer fkey = NULL, chpklist = NULL;
   const char *cipher;
 
   SILC_LOG_DEBUG(("Joining client to channel"));
@@ -1794,7 +1859,7 @@ static void silc_server_command_join_channel(SilcServer server,
     if (!client)
       return;
   } else {
-    client = silc_server_query_client(server, client_id, FALSE, 
+    client = silc_server_query_client(server, client_id, FALSE,
                                      &resolve);
     if (!client) {
       if (!resolve || cmd->pending) {
@@ -1806,19 +1871,21 @@ static void silc_server_command_join_channel(SilcServer server,
 
       /* The client info is being resolved. Reprocess this packet after
         receiving the reply to the query. */
-      silc_server_command_pending(server, SILC_COMMAND_WHOIS, 
+      silc_server_command_pending(server, SILC_COMMAND_WHOIS,
                                  server->cmd_ident,
-                                 silc_server_command_join, 
+                                 silc_server_command_join,
                                  silc_server_command_dup(cmd));
       cmd->pending = TRUE;
       goto out;
     }
 
-    if (auth && auth_len && !client->data.public_key) {
+    if (!client->data.public_key &&
+       (auth || cauth || channel->ban_list ||
+        (channel->mode & SILC_CHANNEL_MODE_INVITE))) {
       if (cmd->pending == 2)
        goto out;
 
-      /* We must retrieve the detached client's public key by sending
+      /* We must retrieve the client's public key by sending
         GETKEY command. Reprocess this packet after receiving the key */
       clidp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
       silc_server_send_command(server, cmd->sock,
@@ -1827,7 +1894,7 @@ static void silc_server_command_join_channel(SilcServer server,
       silc_buffer_free(clidp);
       silc_server_command_pending(server, SILC_COMMAND_GETKEY,
                                  server->cmd_ident,
-                                 silc_server_command_join, 
+                                 silc_server_command_join,
                                  silc_server_command_dup(cmd));
       cmd->pending = 2;
       goto out;
@@ -1847,7 +1914,7 @@ static void silc_server_command_join_channel(SilcServer server,
     SilcHashTableList htl;
 
     if (channel->founder_key && idata->public_key &&
-       silc_pkcs_public_key_compare(channel->founder_key, 
+       silc_pkcs_public_key_compare(channel->founder_key,
                                     idata->public_key)) {
       /* Check whether the client is to become founder */
       if (silc_auth_verify_data(auth, auth_len, SILC_AUTH_PUBLIC_KEY,
@@ -1905,7 +1972,7 @@ static void silc_server_command_join_channel(SilcServer server,
       silc_strncat(check2, sizeof(check2),
                   cmd->sock->hostname, strlen(cmd->sock->hostname));
     }
-    
+
     /* Check invite list if channel is invite-only channel */
     if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
       if (!channel->invite_list ||
@@ -1914,12 +1981,17 @@ static void silc_server_command_join_channel(SilcServer server,
                                        3, client->id) &&
           !silc_server_inviteban_match(server, channel->invite_list,
                                        2, client->data.public_key) &&
+          !silc_server_inviteban_match(server, channel->invite_list,
+                                       1, client->nickname) &&
           !silc_server_inviteban_match(server, channel->invite_list,
                                        1, check) &&
           !silc_server_inviteban_match(server, channel->invite_list,
                                        1, check2))) {
-       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
-                                             SILC_STATUS_ERR_NOT_INVITED, 0);
+       chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+       silc_server_command_send_status_data(cmd, SILC_COMMAND_JOIN,
+                                            SILC_STATUS_ERR_NOT_INVITED, 0,
+                                            2, chidp->data, chidp->len);
+       silc_buffer_free(chidp);
        goto out;
       }
     }
@@ -1932,24 +2004,31 @@ static void silc_server_command_join_channel(SilcServer server,
                                      3, client->id) ||
          silc_server_inviteban_match(server, channel->ban_list,
                                      2, client->data.public_key) ||
+         silc_server_inviteban_match(server, channel->ban_list,
+                                     1, client->nickname) ||
          silc_server_inviteban_match(server, channel->ban_list,
                                      1, check) ||
          silc_server_inviteban_match(server, channel->ban_list,
                                      1, check2)) {
-       silc_server_command_send_status_reply(
+       chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+       silc_server_command_send_status_data(
                                      cmd, SILC_COMMAND_JOIN,
-                                     SILC_STATUS_ERR_BANNED_FROM_CHANNEL, 0);
+                                     SILC_STATUS_ERR_BANNED_FROM_CHANNEL, 0,
+                                     2, chidp->data, chidp->len);
+       silc_buffer_free(chidp);
        goto out;
       }
     }
-    
+
     /* Check user count limit if set. */
     if (channel->mode & SILC_CHANNEL_MODE_ULIMIT) {
-      if (silc_hash_table_count(channel->user_list) + 1 > 
+      if (silc_hash_table_count(channel->user_list) + 1 >
          channel->user_limit) {
-       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
-                                             SILC_STATUS_ERR_CHANNEL_IS_FULL,
-                                             0);
+       chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+       silc_server_command_send_status_data(cmd, SILC_COMMAND_JOIN,
+                                            SILC_STATUS_ERR_CHANNEL_IS_FULL,
+                                            0, 2, chidp->data, chidp->len);
+       silc_buffer_free(chidp);
        goto out;
       }
     }
@@ -1961,11 +2040,24 @@ static void silc_server_command_join_channel(SilcServer server,
     tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
     if (tmp)
       passphrase = silc_memdup(tmp, tmp_len);
-  
+
     if (!passphrase || !channel->passphrase ||
         memcmp(passphrase, channel->passphrase, strlen(channel->passphrase))) {
+      chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+      silc_server_command_send_status_data(cmd, SILC_COMMAND_JOIN,
+                                          SILC_STATUS_ERR_BAD_PASSWORD, 0,
+                                          2, chidp->data, chidp->len);
+      silc_buffer_free(chidp);
+      goto out;
+    }
+  }
+
+  /* Verify channel authentication with channel public keys if set. */
+  if (channel->mode & SILC_CHANNEL_MODE_CHANNEL_AUTH) {
+    if (!silc_server_verify_channel_auth(server, channel, client->id,
+                                        cauth, cauth_len)) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
-                                           SILC_STATUS_ERR_BAD_PASSWORD, 0);
+                                           SILC_STATUS_ERR_PERM_DENIED, 0);
       goto out;
     }
   }
@@ -1976,8 +2068,14 @@ static void silc_server_command_join_channel(SilcServer server,
 
   /* Check whether the client already is on the channel */
   if (silc_server_client_on_channel(client, channel, NULL)) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
-                                         SILC_STATUS_ERR_USER_ON_CHANNEL, 0);
+    clidp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
+    chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+    silc_server_command_send_status_data2(cmd, SILC_COMMAND_JOIN,
+                                         SILC_STATUS_ERR_USER_ON_CHANNEL, 0,
+                                         2, clidp->data, clidp->len,
+                                         3, chidp->data, chidp->len);
+    silc_buffer_free(clidp);
+    silc_buffer_free(chidp);
     goto out;
   }
 
@@ -1989,8 +2087,8 @@ static void silc_server_command_join_channel(SilcServer server,
     /* Send the channel key. This is broadcasted to the channel but is not
        sent to the client who is joining to the channel. */
     if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
-      silc_server_send_channel_key(server, NULL, channel, 
-                                  server->server_type == SILC_ROUTER ? 
+      silc_server_send_channel_key(server, NULL, channel,
+                                  server->server_type == SILC_ROUTER ?
                                   FALSE : !server->standalone);
   }
 
@@ -2023,7 +2121,7 @@ static void silc_server_command_join_channel(SilcServer server,
     tmp = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
     cipher = silc_cipher_get_name(channel->channel_key);
     keyp = silc_channel_key_payload_encode(silc_id_get_len(channel->id,
-                                                          SILC_ID_CHANNEL), 
+                                                          SILC_ID_CHANNEL),
                                           tmp,
                                           strlen(cipher), cipher,
                                           channel->key_len / 8, channel->key);
@@ -2071,16 +2169,19 @@ static void silc_server_command_join_channel(SilcServer server,
     silc_hash_table_list_reset(&htl);
   }
 
-  reply = 
+  if (channel->channel_pubkeys)
+    chpklist = silc_server_get_channel_pk_list(server, channel, FALSE, FALSE);
+
+  reply =
     silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
-                                        SILC_STATUS_OK, 0, ident, 14,
+                                        SILC_STATUS_OK, 0, ident, 15,
                                         2, channel->channel_name,
                                         strlen(channel->channel_name),
                                         3, chidp->data, chidp->len,
                                         4, clidp->data, clidp->len,
                                         5, mode, 4,
                                         6, tmp2, 4,
-                                        7, keyp ? keyp->data : NULL, 
+                                        7, keyp ? keyp->data : NULL,
                                         keyp ? keyp->len : 0,
                                         8, ban_list ? ban_list->data : NULL,
                                         ban_list ? ban_list->len : 0,
@@ -2095,13 +2196,15 @@ static void silc_server_command_join_channel(SilcServer server,
                                                                   hmac)),
                                         12, tmp3, 4,
                                         13, user_list->data, user_list->len,
-                                        14, mode_list->data, 
+                                        14, mode_list->data,
                                         mode_list->len,
                                         15, fkey ? fkey->data : NULL,
-                                        fkey ? fkey->len : 0);
+                                        fkey ? fkey->len : 0,
+                                        16, chpklist ? chpklist->data : NULL,
+                                        chpklist ? chpklist->len : 0);
 
   /* Send command reply */
-  silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0, 
+  silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
                          reply->data, reply->len, FALSE);
 
   /* Send JOIN notify to locally connected clients on the channel. If
@@ -2111,7 +2214,7 @@ static void silc_server_command_join_channel(SilcServer server,
      we are router then this will send it to local clients and local
      servers. */
   SILC_LOG_DEBUG(("Send JOIN notify to channel"));
-  silc_server_send_notify_to_channel(server, NULL, channel, FALSE, 
+  silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
                                     SILC_NOTIFY_TYPE_JOIN, 2,
                                     clidp->data, clidp->len,
                                     chidp->data, chidp->len);
@@ -2138,7 +2241,7 @@ static void silc_server_command_join_channel(SilcServer server,
     if (founder) {
       SILC_PUT32_MSB(chl->mode, mode);
       SILC_LOG_DEBUG(("Send CUMODE_CHANGE notify to channel"));
-      silc_server_send_notify_to_channel(server, NULL, channel, FALSE, 
+      silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
                                         SILC_NOTIFY_TYPE_CUMODE_CHANGE, 4,
                                         clidp->data, clidp->len,
                                         mode, 4, clidp->data, clidp->len,
@@ -2161,6 +2264,7 @@ static void silc_server_command_join_channel(SilcServer server,
   silc_buffer_free(user_list);
   silc_buffer_free(mode_list);
   silc_buffer_free(fkey);
+  silc_buffer_free(chpklist);
   silc_buffer_free(invite_list);
   silc_buffer_free(ban_list);
 
@@ -2170,22 +2274,22 @@ static void silc_server_command_join_channel(SilcServer server,
   silc_free(passphrase);
 }
 
-/* Server side of command JOIN. Joins client into requested channel. If 
+/* Server side of command JOIN. Joins client into requested channel. If
    the channel does not exist it will be created. */
 
 SILC_SERVER_CMD_FUNC(join)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
   SilcServer server = cmd->server;
-  unsigned char *auth;
-  SilcUInt32 tmp_len, auth_len;
+  unsigned char *auth, *cauth;
+  SilcUInt32 tmp_len, auth_len, cauth_len;
   char *tmp, *channel_name = NULL, *cipher, *hmac;
   SilcChannelEntry channel;
   SilcUInt32 umode = 0;
   bool created = FALSE, create_key = TRUE;
   SilcClientID *client_id;
 
-  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_JOIN, cmd, 2, 6);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_JOIN, cmd, 2, 7);
 
   /* Get channel name */
   tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
@@ -2200,7 +2304,7 @@ SILC_SERVER_CMD_FUNC(join)
   if (tmp_len > 256)
     channel_name[255] = '\0';
 
-  if (silc_server_name_bad_chars(channel_name, tmp_len) == TRUE) {
+  if (silc_server_name_bad_chchars(channel_name, tmp_len) == TRUE) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
                                          SILC_STATUS_ERR_BAD_CHANNEL, 0);
     goto out;
@@ -2226,9 +2330,10 @@ SILC_SERVER_CMD_FUNC(join)
   cipher = silc_argument_get_arg_type(cmd->args, 4, NULL);
   hmac = silc_argument_get_arg_type(cmd->args, 5, NULL);
   auth = silc_argument_get_arg_type(cmd->args, 6, &auth_len);
+  cauth = silc_argument_get_arg_type(cmd->args, 7, &cauth_len);
 
   /* See if the channel exists */
-  channel = silc_idlist_find_channel_by_name(server->local_list, 
+  channel = silc_idlist_find_channel_by_name(server->local_list,
                                             channel_name, NULL);
 
   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
@@ -2243,34 +2348,34 @@ SILC_SERVER_CMD_FUNC(join)
     silc_free(client_id);
     client_id = silc_id_dup(entry->id, SILC_ID_CLIENT);
 
-    if (!channel || 
+    if (!channel ||
        (channel->disabled && server->server_type != SILC_ROUTER)) {
       /* Channel not found or not valid */
 
-      /* If we are standalone server we don't have a router, we just create 
+      /* If we are standalone server we don't have a router, we just create
         the channel by ourselves (unless it existed). */
       if (server->standalone) {
        if (!channel) {
-         channel = silc_server_create_new_channel(server, server->id, cipher, 
+         channel = silc_server_create_new_channel(server, server->id, cipher,
                                                   hmac, channel_name, TRUE);
          if (!channel) {
-           silc_server_command_send_status_reply(
+           silc_server_command_send_status_data(
                                  cmd, SILC_COMMAND_JOIN,
                                  SILC_STATUS_ERR_UNKNOWN_ALGORITHM,
-                                 0);
+                                 0, 2, cipher, strlen(cipher));
            silc_free(client_id);
            goto out;
          }
-       
+
          umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
          created = TRUE;
          create_key = FALSE;
        }
       } else {
 
-       /* The channel does not exist on our server. If we are normal server 
+       /* The channel does not exist on our server. If we are normal server
           we will send JOIN command to our router which will handle the
-          joining procedure (either creates the channel if it doesn't exist 
+          joining procedure (either creates the channel if it doesn't exist
           or joins the client to it). */
        if (server->server_type != SILC_ROUTER) {
          SilcBuffer tmpbuf;
@@ -2283,19 +2388,19 @@ SILC_SERVER_CMD_FUNC(join)
            silc_free(client_id);
            goto out;
          }
-         
+
          old_ident = silc_command_get_ident(cmd->payload);
          silc_command_set_ident(cmd->payload, ++server->cmd_ident);
          tmpbuf = silc_command_payload_encode_payload(cmd->payload);
-         
+
          /* Send JOIN command to our router */
          silc_server_packet_send(server, (SilcSocketConnection)
                                  SILC_PRIMARY_ROUTE(server),
                                  SILC_PACKET_COMMAND, cmd->packet->flags,
                                  tmpbuf->data, tmpbuf->len, TRUE);
-         
+
          /* Reprocess this packet after received reply from router */
-         silc_server_command_pending(server, SILC_COMMAND_JOIN, 
+         silc_server_command_pending(server, SILC_COMMAND_JOIN,
                                      silc_command_get_ident(cmd->payload),
                                      silc_server_command_join,
                                      silc_server_command_dup(cmd));
@@ -2305,19 +2410,20 @@ SILC_SERVER_CMD_FUNC(join)
          silc_free(client_id);
          goto out;
        }
-       
+
        /* We are router and the channel does not seem exist so we will check
           our global list as well for the channel. */
-       channel = silc_idlist_find_channel_by_name(server->global_list, 
+       channel = silc_idlist_find_channel_by_name(server->global_list,
                                                   channel_name, NULL);
        if (!channel) {
          /* Channel really does not exist, create it */
-         channel = silc_server_create_new_channel(server, server->id, cipher, 
+         channel = silc_server_create_new_channel(server, server->id, cipher,
                                                   hmac, channel_name, TRUE);
          if (!channel) {
-           silc_server_command_send_status_reply(
+           silc_server_command_send_status_data(
                                       cmd, SILC_COMMAND_JOIN,
-                                      SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0);
+                                      SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0,
+                                      2, cipher, strlen(cipher));
            silc_free(client_id);
            goto out;
          }
@@ -2340,19 +2446,20 @@ SILC_SERVER_CMD_FUNC(join)
        silc_free(client_id);
        goto out;
       }
-      
+
       /* We are router and the channel does not seem exist so we will check
         our global list as well for the channel. */
-      channel = silc_idlist_find_channel_by_name(server->global_list, 
+      channel = silc_idlist_find_channel_by_name(server->global_list,
                                                 channel_name, NULL);
       if (!channel) {
        /* Channel really does not exist, create it */
-       channel = silc_server_create_new_channel(server, server->id, cipher, 
+       channel = silc_server_create_new_channel(server, server->id, cipher,
                                                 hmac, channel_name, TRUE);
        if (!channel) {
-         silc_server_command_send_status_reply(
+         silc_server_command_send_status_data(
                                       cmd, SILC_COMMAND_JOIN,
-                                      SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0);
+                                      SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0,
+                                      2, cipher, strlen(cipher));
          silc_free(client_id);
          goto out;
        }
@@ -2401,7 +2508,7 @@ SILC_SERVER_CMD_FUNC(join)
   /* Join to the channel */
   silc_server_command_join_channel(server, cmd, channel, client_id,
                                   created, create_key, umode,
-                                  auth, auth_len);
+                                  auth, auth_len, cauth, cauth_len);
 
   silc_free(client_id);
 
@@ -2420,14 +2527,15 @@ SILC_SERVER_CMD_FUNC(motd)
   char *motd, *dest_server;
   SilcUInt32 motd_len;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
-  
+
   SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_MOTD, cmd, 1, 1);
 
   /* Get server name */
   dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
   if (!dest_server) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_MOTD,
-                                         SILC_STATUS_ERR_NO_SUCH_SERVER, 0);
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
+                                         0);
     goto out;
   }
 
@@ -2443,22 +2551,22 @@ SILC_SERVER_CMD_FUNC(motd)
                                &motd_len);
       if (!motd)
        goto out;
-      
+
       motd[motd_len] = 0;
       packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
-                                                   SILC_STATUS_OK, 0, 
+                                                   SILC_STATUS_OK, 0,
                                                    ident, 2,
                                                    2, idp, idp->len,
                                                    3, motd, motd_len);
     } else {
       /* No motd */
       packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
-                                                   SILC_STATUS_OK, 0, 
+                                                   SILC_STATUS_OK, 0,
                                                    ident, 1,
                                                    2, idp, idp->len);
     }
 
-    silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
+    silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
                            packet->data, packet->len, FALSE);
     silc_buffer_free(packet);
     silc_buffer_free(idp);
@@ -2473,7 +2581,7 @@ SILC_SERVER_CMD_FUNC(motd)
                                              dest_server, TRUE, NULL);
     }
 
-    if (server->server_type != SILC_SERVER && !cmd->pending && 
+    if (server->server_type != SILC_SERVER && !cmd->pending &&
        entry && !entry->motd) {
       /* Send to the server */
       SilcBuffer tmpbuf;
@@ -2488,7 +2596,7 @@ SILC_SERVER_CMD_FUNC(motd)
                              tmpbuf->data, tmpbuf->len, TRUE);
 
       /* Reprocess this packet after received reply from router */
-      silc_server_command_pending(server, SILC_COMMAND_MOTD, 
+      silc_server_command_pending(server, SILC_COMMAND_MOTD,
                                  silc_command_get_ident(cmd->payload),
                                  silc_server_command_motd,
                                  silc_server_command_dup(cmd));
@@ -2512,7 +2620,7 @@ SILC_SERVER_CMD_FUNC(motd)
                              tmpbuf->data, tmpbuf->len, TRUE);
 
       /* Reprocess this packet after received reply from router */
-      silc_server_command_pending(server, SILC_COMMAND_MOTD, 
+      silc_server_command_pending(server, SILC_COMMAND_MOTD,
                                  silc_command_get_ident(cmd->payload),
                                  silc_server_command_motd,
                                  silc_server_command_dup(cmd));
@@ -2523,8 +2631,10 @@ SILC_SERVER_CMD_FUNC(motd)
     }
 
     if (!entry) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_MOTD,
-                                           SILC_STATUS_ERR_NO_SUCH_SERVER, 0);
+      silc_server_command_send_status_data(cmd, SILC_COMMAND_MOTD,
+                                          SILC_STATUS_ERR_NO_SUCH_SERVER, 0,
+                                          2, dest_server,
+                                          strlen(dest_server));
       goto out;
     }
 
@@ -2533,9 +2643,9 @@ SILC_SERVER_CMD_FUNC(motd)
                                                  SILC_STATUS_OK, 0, ident, 2,
                                                  2, idp, idp->len,
                                                  3, entry->motd,
-                                                 entry->motd ? 
+                                                 entry->motd ?
                                                  strlen(entry->motd) : 0);
-    silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
+    silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
                            packet->data, packet->len, FALSE);
     silc_buffer_free(packet);
     silc_buffer_free(idp);
@@ -2623,7 +2733,7 @@ SILC_SERVER_CMD_FUNC(umode)
   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_UMODE,
                                                SILC_STATUS_OK, 0, ident, 1,
                                                2, m, sizeof(m));
-  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
+  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
                          packet->data, packet->len, FALSE);
   silc_buffer_free(packet);
 
@@ -2643,20 +2753,21 @@ SILC_SERVER_CMD_FUNC(cmode)
   SilcChannelEntry channel;
   SilcChannelClientEntry chl;
   SilcBuffer packet, cidp;
-  unsigned char *tmp, *tmp_id, *tmp_mask;
+  unsigned char *tmp, *tmp_id, *tmp_mask, *chpkdata = NULL;
   char *cipher = NULL, *hmac = NULL, *passphrase = NULL;
-  SilcUInt32 mode_mask = 0, old_mask = 0, tmp_len, tmp_len2;
+  SilcUInt32 mode_mask = 0, old_mask = 0, tmp_len, tmp_len2, chpklen;
   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
-  bool set_mask = FALSE;
+  bool set_mask = FALSE, set_chpk = FALSE;
   SilcPublicKey founder_key = NULL;
-  SilcBuffer fkey = NULL;
+  SilcBuffer fkey = NULL, chpklist = NULL;
+  SilcBufferStruct chpk;
 
   if (!client) {
     silc_server_command_free(cmd);
     return;
   }
 
-  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_CMODE, cmd, 1, 8);
+  SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_CMODE, cmd, 1, 9);
 
   /* Get Channel ID */
   tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
@@ -2675,15 +2786,15 @@ SILC_SERVER_CMD_FUNC(cmode)
   }
 
   /* Get channel entry */
-  channel = silc_idlist_find_channel_by_id(server->local_list, 
+  channel = silc_idlist_find_channel_by_id(server->local_list,
                                           channel_id, NULL);
   if (!channel) {
-    channel = silc_idlist_find_channel_by_id(server->global_list, 
+    channel = silc_idlist_find_channel_by_id(server->global_list,
                                             channel_id, NULL);
     if (!channel) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
-                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL,
-                                           0);
+      silc_server_command_send_status_data(cmd, SILC_COMMAND_CMODE,
+                                          SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
+                                          0, 2, tmp_id, tmp_len2);
       silc_free(channel_id);
       silc_server_command_free(cmd);
       return;
@@ -2700,32 +2811,44 @@ SILC_SERVER_CMD_FUNC(cmode)
 
   /* Check whether this client is on the channel */
   if (!silc_server_client_on_channel(client, channel, &chl)) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
-                                         SILC_STATUS_ERR_NOT_ON_CHANNEL, 0);
+    silc_server_command_send_status_data(cmd, SILC_COMMAND_CMODE,
+                                        SILC_STATUS_ERR_NOT_ON_CHANNEL, 0,
+                                        2, tmp_id, tmp_len2);
     goto out;
   }
 
   /* Check that client has rights to change any requested channel modes */
-  if (set_mask && !silc_server_check_cmode_rights(server, channel, chl, 
+  if (set_mask && !silc_server_check_cmode_rights(server, channel, chl,
                                                  mode_mask)) {
     SILC_LOG_DEBUG(("Client does not have rights to change mode"));
-    silc_server_command_send_status_reply(
+    silc_server_command_send_status_data(
                             cmd, SILC_COMMAND_CMODE,
-                            (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP) ? 
+                            (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP) ?
                              SILC_STATUS_ERR_NO_CHANNEL_PRIV :
-                             SILC_STATUS_ERR_NO_CHANNEL_FOPRIV), 0);
+                             SILC_STATUS_ERR_NO_CHANNEL_FOPRIV), 0,
+                            2, tmp_id, tmp_len2);
     goto out;
   }
 
   /* If mode mask was not sent as argument then merely return the current
-     mode mask to the sender. */
+     mode mask, founder key and channel public key list to the sender. */
   if (!set_mask) {
     unsigned char m[4];
     SILC_PUT32_MSB(channel->mode, m);
-    packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
-                                                 SILC_STATUS_OK, 0, ident, 2,
-                                                 2, tmp_id, tmp_len2,
-                                                 3, m, sizeof(m));
+    if (channel->founder_key)
+      fkey = silc_pkcs_public_key_payload_encode(channel->founder_key);
+    if (channel->channel_pubkeys)
+      chpklist = silc_server_get_channel_pk_list(server, channel,
+                                                FALSE, FALSE);
+    packet =
+      silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
+                                          SILC_STATUS_OK, 0, ident, 4,
+                                          2, tmp_id, tmp_len2,
+                                          3, m, sizeof(m),
+                                          4, fkey ? fkey->data : NULL,
+                                          fkey ? fkey->len : 0,
+                                          5, chpklist ? chpklist->data : NULL,
+                                          chpklist ? chpklist->len : 0);
     silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
                            packet->data, packet->len, FALSE);
     silc_buffer_free(packet);
@@ -2746,15 +2869,15 @@ SILC_SERVER_CMD_FUNC(cmode)
       /* The mode is removed and we need to generate and distribute
         new channel key. Clients are not using private channel keys
         anymore after this. */
-      
+
       /* Re-generate channel key */
       if (!silc_server_create_channel_key(server, channel, 0))
        goto out;
-       
+
       /* Send the channel key. This sends it to our local clients and if
         we are normal server to our router as well. */
-      silc_server_send_channel_key(server, NULL, channel, 
-                                  server->server_type == SILC_ROUTER ? 
+      silc_server_send_channel_key(server, NULL, channel,
+                                  server->server_type == SILC_ROUTER ?
                                   FALSE : !server->standalone);
 
       cipher = (char *)silc_cipher_get_name(channel->channel_key);
@@ -2765,7 +2888,7 @@ SILC_SERVER_CMD_FUNC(cmode)
   if (mode_mask & SILC_CHANNEL_MODE_ULIMIT) {
     /* User limit is set on channel */
     SilcUInt32 user_limit;
-      
+
     /* Get user limit */
     tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
     if (!tmp) {
@@ -2787,7 +2910,7 @@ SILC_SERVER_CMD_FUNC(cmode)
   if (mode_mask & SILC_CHANNEL_MODE_PASSPHRASE) {
     if (!(channel->mode & SILC_CHANNEL_MODE_PASSPHRASE)) {
       /* Passphrase has been set to channel */
-      
+
       /* Get the passphrase */
       tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
       if (!tmp) {
@@ -2822,8 +2945,10 @@ SILC_SERVER_CMD_FUNC(cmode)
 
       /* Delete old cipher and allocate the new one */
       if (!silc_cipher_alloc(cipher, &newkey)) {
-       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
-                                      SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0);
+       silc_server_command_send_status_data(
+                                        cmd, SILC_COMMAND_CMODE,
+                                        SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0,
+                                        2, cipher, strlen(cipher));
        goto out;
       }
 
@@ -2842,21 +2967,23 @@ SILC_SERVER_CMD_FUNC(cmode)
 
       /* Send the channel key. This sends it to our local clients and if
         we are normal server to our router as well. */
-      silc_server_send_channel_key(server, NULL, channel, 
-                                  server->server_type == SILC_ROUTER ? 
+      silc_server_send_channel_key(server, NULL, channel,
+                                  server->server_type == SILC_ROUTER ?
                                   FALSE : !server->standalone);
     }
   } else {
     if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
-      /* Cipher mode is unset. Remove the cipher and revert back to 
+      /* Cipher mode is unset. Remove the cipher and revert back to
         default cipher */
       SilcCipher newkey, oldkey;
       cipher = channel->cipher;
 
       /* Delete old cipher and allocate default one */
       if (!silc_cipher_alloc(cipher ? cipher : SILC_DEFAULT_CIPHER, &newkey)) {
-       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
-                                  SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0);
+       silc_server_command_send_status_data(
+                                     cmd, SILC_COMMAND_CMODE,
+                                     SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0,
+                                     2, cipher, strlen(cipher));
        goto out;
       }
 
@@ -2869,14 +2996,14 @@ SILC_SERVER_CMD_FUNC(cmode)
        channel->channel_key = oldkey;
        goto out;
       }
-      
+
       /* Remove old channel key for good */
       silc_cipher_free(oldkey);
 
       /* Send the channel key. This sends it to our local clients and if
         we are normal server to our router as well. */
-      silc_server_send_channel_key(server, NULL, channel, 
-                                  server->server_type == SILC_ROUTER ? 
+      silc_server_send_channel_key(server, NULL, channel,
+                                  server->server_type == SILC_ROUTER ?
                                   FALSE : !server->standalone);
     }
   }
@@ -2897,8 +3024,10 @@ SILC_SERVER_CMD_FUNC(cmode)
 
       /* Delete old hmac and allocate the new one */
       if (!silc_hmac_alloc(hmac, NULL, &newhmac)) {
-       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
-                                      SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0);
+       silc_server_command_send_status_data(
+                                       cmd, SILC_COMMAND_CMODE,
+                                       SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0,
+                                       2, hmac, strlen(hmac));
        goto out;
       }
 
@@ -2907,15 +3036,15 @@ SILC_SERVER_CMD_FUNC(cmode)
 
       /* Set the HMAC key out of current channel key. The client must do
         this locally. */
-      silc_hash_make(silc_hmac_get_hash(channel->hmac), channel->key, 
+      silc_hash_make(silc_hmac_get_hash(channel->hmac), channel->key,
                     channel->key_len / 8, hash);
-      silc_hmac_set_key(channel->hmac, hash, 
+      silc_hmac_set_key(channel->hmac, hash,
                        silc_hash_len(silc_hmac_get_hash(channel->hmac)));
       memset(hash, 0, sizeof(hash));
     }
   } else {
     if (channel->mode & SILC_CHANNEL_MODE_HMAC) {
-      /* Hmac mode is unset. Remove the hmac and revert back to 
+      /* Hmac mode is unset. Remove the hmac and revert back to
         default hmac */
       SilcHmac newhmac;
       unsigned char hash[32];
@@ -2923,8 +3052,10 @@ SILC_SERVER_CMD_FUNC(cmode)
 
       /* Delete old hmac and allocate default one */
       if (!silc_hmac_alloc(hmac ? hmac : SILC_DEFAULT_HMAC, NULL, &newhmac)) {
-       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
-                                      SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0);
+       silc_server_command_send_status_data(
+                                       cmd, SILC_COMMAND_CMODE,
+                                       SILC_STATUS_ERR_UNKNOWN_ALGORITHM, 0,
+                                       2, hmac, strlen(hmac));
        goto out;
       }
 
@@ -2933,10 +3064,10 @@ SILC_SERVER_CMD_FUNC(cmode)
 
       /* Set the HMAC key out of current channel key. The client must do
         this locally. */
-      silc_hash_make(silc_hmac_get_hash(channel->hmac), channel->key, 
-                    channel->key_len / 8, 
+      silc_hash_make(silc_hmac_get_hash(channel->hmac), channel->key,
+                    channel->key_len / 8,
                     hash);
-      silc_hmac_set_key(channel->hmac, hash, 
+      silc_hmac_set_key(channel->hmac, hash,
                        silc_hash_len(silc_hmac_get_hash(channel->hmac)));
       memset(hash, 0, sizeof(hash));
     }
@@ -2971,7 +3102,7 @@ SILC_SERVER_CMD_FUNC(cmode)
       }
 
       /* Verify the payload before setting the mode */
-      if (!silc_auth_verify_data(tmp, tmp_len, SILC_AUTH_PUBLIC_KEY, 
+      if (!silc_auth_verify_data(tmp, tmp_len, SILC_AUTH_PUBLIC_KEY,
                                 founder_key, 0, server->sha1hash,
                                 client->id, SILC_ID_CLIENT)) {
        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
@@ -3015,36 +3146,78 @@ SILC_SERVER_CMD_FUNC(cmode)
     }
   }
 
+  if (mode_mask & SILC_CHANNEL_MODE_CHANNEL_AUTH) {
+    if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
+      SilcStatus st;
+
+      chpkdata = silc_argument_get_arg_type(cmd->args, 9, &chpklen);
+
+      if (!chpkdata && channel->mode & SILC_CHANNEL_MODE_CHANNEL_AUTH)
+       goto has_pk_list;
+
+      set_chpk = TRUE;
+
+      /* Process the channel public key(s) */
+      st = silc_server_set_channel_pk_list(server, NULL, channel,
+                                          chpkdata, chpklen);
+      if (st != SILC_STATUS_OK) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE, st, 0);
+       goto out;
+      }
+    has_pk_list:
+    }
+  } else {
+    if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
+      if (channel->mode & SILC_CHANNEL_MODE_CHANNEL_AUTH) {
+       if (channel->channel_pubkeys)
+         silc_hash_table_free(channel->channel_pubkeys);
+       channel->channel_pubkeys = NULL;
+       set_chpk = TRUE;
+      }
+    }
+  }
+
   /* Finally, set the mode */
   old_mask = channel->mode = mode_mask;
 
   /* Send CMODE_CHANGE notify. */
   cidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
-  silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
-                                    SILC_NOTIFY_TYPE_CMODE_CHANGE, 6,
-                                    cidp->data, cidp->len, 
+  silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
+                                    SILC_NOTIFY_TYPE_CMODE_CHANGE, 7,
+                                    cidp->data, cidp->len,
                                     tmp_mask, 4,
                                     cipher, cipher ? strlen(cipher) : 0,
                                     hmac, hmac ? strlen(hmac) : 0,
-                                    passphrase, passphrase ? 
+                                    passphrase, passphrase ?
                                     strlen(passphrase) : 0,
                                     fkey ? fkey->data : NULL,
-                                    fkey ? fkey->len : 0);
+                                    fkey ? fkey->len : 0,
+                                    chpkdata ? chpkdata : NULL,
+                                    chpkdata ? chpklen : 0);
 
   /* Set CMODE notify type to network */
+  if (chpkdata && chpklen)
+    silc_buffer_set(&chpk, chpkdata, chpklen);
   silc_server_send_notify_cmode(server, SILC_PRIMARY_ROUTE(server),
                                SILC_BROADCAST(server), channel,
                                mode_mask, client->id, SILC_ID_CLIENT,
-                               cipher, hmac, passphrase, founder_key);
+                               cipher, hmac, passphrase, founder_key,
+                               chpkdata ? &chpk : NULL);
+
+  if (set_chpk)
+    chpklist = silc_server_get_channel_pk_list(server, channel, FALSE, FALSE);
 
   /* Send command reply to sender */
   packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
-                                               SILC_STATUS_OK, 0, ident, 3,
+                                               SILC_STATUS_OK, 0, ident, 4,
                                                2, tmp_id, tmp_len2,
                                                3, tmp_mask, 4,
                                                4, fkey ? fkey->data : NULL,
-                                               fkey ? fkey->len : 0);
-  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
+                                               fkey ? fkey->len : 0,
+                                               5, chpklist ? chpklist->data :
+                                               NULL, chpklist ? chpklist->len
+                                               : 0);
+  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
                          packet->data, packet->len, FALSE);
 
   silc_buffer_free(packet);
@@ -3052,6 +3225,7 @@ SILC_SERVER_CMD_FUNC(cmode)
 
  out:
   channel->mode = old_mask;
+  silc_buffer_free(chpklist);
   silc_buffer_free(fkey);
   silc_free(channel_id);
   silc_server_command_free(cmd);
@@ -3097,27 +3271,28 @@ SILC_SERVER_CMD_FUNC(cumode)
   }
 
   /* Get channel entry */
-  channel = silc_idlist_find_channel_by_id(server->local_list, 
+  channel = silc_idlist_find_channel_by_id(server->local_list,
                                           channel_id, NULL);
   if (!channel) {
-    channel = silc_idlist_find_channel_by_id(server->global_list, 
+    channel = silc_idlist_find_channel_by_id(server->global_list,
                                             channel_id, NULL);
     if (!channel) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
-                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL,
-                                           0);
+      silc_server_command_send_status_data(cmd, SILC_COMMAND_CUMODE,
+                                          SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
+                                          0, 2, tmp_ch_id, tmp_ch_len);
       goto out;
     }
   }
 
   /* Check whether sender is on the channel */
   if (!silc_server_client_on_channel(client, channel, &chl)) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
-                                         SILC_STATUS_ERR_NOT_ON_CHANNEL, 0);
+    silc_server_command_send_status_data(cmd, SILC_COMMAND_CUMODE,
+                                        SILC_STATUS_ERR_NOT_ON_CHANNEL, 0,
+                                        2, tmp_ch_id, tmp_ch_len);
     goto out;
   }
   sender_mask = chl->mode;
-  
+
   /* Get the target client's channel mode mask */
   tmp_mask = silc_argument_get_arg_type(cmd->args, 2, NULL);
   if (!tmp_mask) {
@@ -3143,40 +3318,44 @@ SILC_SERVER_CMD_FUNC(cumode)
   }
 
   /* Get target client's entry */
-  target_client = silc_idlist_find_client_by_id(server->local_list, 
+  target_client = silc_idlist_find_client_by_id(server->local_list,
                                                client_id, TRUE, NULL);
   if (!target_client) {
-    target_client = silc_idlist_find_client_by_id(server->global_list, 
+    target_client = silc_idlist_find_client_by_id(server->global_list,
                                                  client_id, TRUE, NULL);
   }
 
   if (target_client != client &&
       !(sender_mask & SILC_CHANNEL_UMODE_CHANFO) &&
       !(sender_mask & SILC_CHANNEL_UMODE_CHANOP)) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
-                                         SILC_STATUS_ERR_NO_CHANNEL_PRIV, 0);
+    silc_server_command_send_status_data(cmd, SILC_COMMAND_CUMODE,
+                                        SILC_STATUS_ERR_NO_CHANNEL_PRIV, 0,
+                                        2, tmp_ch_id, tmp_ch_len);
     goto out;
   }
 
   /* Check whether target client is on the channel */
   if (target_client != client) {
     if (!silc_server_client_on_channel(target_client, channel, &chl)) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
-                                SILC_STATUS_ERR_USER_NOT_ON_CHANNEL, 0);
+      silc_server_command_send_status_data2(
+                                 cmd, SILC_COMMAND_CUMODE,
+                                 SILC_STATUS_ERR_USER_NOT_ON_CHANNEL, 0,
+                                 2, tmp_id, tmp_len,
+                                 3, tmp_ch_id, tmp_ch_len);
       goto out;
     }
   }
 
-  /* 
-   * Change the mode 
+  /*
+   * Change the mode
    */
 
   /* If the target client is founder, no one else can change their mode
      but themselves. */
   if (chl->mode & SILC_CHANNEL_UMODE_CHANFO && client != target_client) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
-                                         SILC_STATUS_ERR_NO_CHANNEL_FOPRIV,
-                                         0);
+    silc_server_command_send_status_data(cmd, SILC_COMMAND_CUMODE,
+                                        SILC_STATUS_ERR_NO_CHANNEL_FOPRIV,
+                                        0, 2, tmp_ch_id, tmp_ch_len);
     goto out;
   }
 
@@ -3257,11 +3436,11 @@ SILC_SERVER_CMD_FUNC(cumode)
   if (target_mask & SILC_CHANNEL_UMODE_CHANOP) {
     /* Promote to operator */
     if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
-      if (!(sender_mask & SILC_CHANNEL_UMODE_CHANOP) && 
+      if (!(sender_mask & SILC_CHANNEL_UMODE_CHANOP) &&
           !(sender_mask & SILC_CHANNEL_UMODE_CHANFO)) {
-        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
-                                              SILC_STATUS_ERR_NO_CHANNEL_PRIV,
-                                              0);
+        silc_server_command_send_status_data(cmd, SILC_COMMAND_CUMODE,
+                                            SILC_STATUS_ERR_NO_CHANNEL_PRIV,
+                                            0, 2, tmp_ch_id, tmp_ch_len);
         goto out;
       }
 
@@ -3272,12 +3451,12 @@ SILC_SERVER_CMD_FUNC(cumode)
     if (chl->mode & SILC_CHANNEL_UMODE_CHANOP) {
       if (!(sender_mask & SILC_CHANNEL_UMODE_CHANOP) &&
           !(sender_mask & SILC_CHANNEL_UMODE_CHANFO)) {
-        silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,   
-                                              SILC_STATUS_ERR_NO_CHANNEL_PRIV,
-                                              0);
+        silc_server_command_send_status_data(cmd, SILC_COMMAND_CUMODE,
+                                            SILC_STATUS_ERR_NO_CHANNEL_PRIV,
+                                            0, 2, tmp_ch_id, tmp_ch_len);
         goto out;
       }
-      
+
       /* Demote to normal user */
       chl->mode &= ~SILC_CHANNEL_UMODE_CHANOP;
       notify = TRUE;
@@ -3383,10 +3562,10 @@ SILC_SERVER_CMD_FUNC(cumode)
 
   /* Send notify to channel, notify only if mode was actually changed. */
   if (notify) {
-    silc_server_send_notify_to_channel(server, NULL, channel, FALSE, 
+    silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
                                       SILC_NOTIFY_TYPE_CUMODE_CHANGE, 4,
                                       idp->data, idp->len,
-                                      tmp_mask, 4, 
+                                      tmp_mask, 4,
                                       tmp_id, tmp_len,
                                       fkey ? fkey->data : NULL,
                                       fkey ? fkey->len : 0);
@@ -3404,9 +3583,9 @@ SILC_SERVER_CMD_FUNC(cumode)
                                                2, tmp_mask, 4,
                                                3, tmp_ch_id, tmp_ch_len,
                                                4, tmp_id, tmp_len);
-  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
+  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
                          packet->data, packet->len, FALSE);
-    
+
   silc_buffer_free(packet);
   silc_buffer_free(idp);
 
@@ -3429,8 +3608,9 @@ SILC_SERVER_CMD_FUNC(kick)
   SilcClientID *client_id;
   SilcChannelEntry channel;
   SilcChannelClientEntry chl;
-  SilcBuffer idp;
-  SilcUInt32 tmp_len, target_idp_len;
+  SilcBuffer idp, packet;
+  SilcUInt32 tmp_len, target_idp_len, clen;
+  SilcUInt16 ident = silc_command_get_ident(cmd->payload);
   unsigned char *tmp, *comment, *target_idp;
 
   if (!client)
@@ -3447,40 +3627,43 @@ SILC_SERVER_CMD_FUNC(kick)
   }
   channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
   if (!channel_id) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
-                                         SILC_STATUS_ERR_NO_CHANNEL_ID, 0);
+    silc_server_command_send_status_data(cmd, SILC_COMMAND_KICK,
+                                        SILC_STATUS_ERR_BAD_CHANNEL_ID, 0,
+                                         2, tmp, tmp_len);
     goto out;
   }
 
   /* Get channel entry */
-  channel = silc_idlist_find_channel_by_id(server->local_list, 
+  channel = silc_idlist_find_channel_by_id(server->local_list,
                                           channel_id, NULL);
   if (!channel) {
-    channel = silc_idlist_find_channel_by_id(server->local_list, 
+    channel = silc_idlist_find_channel_by_id(server->local_list,
                                             channel_id, NULL);
     if (!channel) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
-                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL,
-                                           0);
+      silc_server_command_send_status_data(cmd, SILC_COMMAND_KICK,
+                                          SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
+                                          0, 2, tmp, tmp_len);
       goto out;
     }
   }
 
   /* Check whether sender is on the channel */
   if (!silc_server_client_on_channel(client, channel, &chl)) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
-                                         SILC_STATUS_ERR_NOT_ON_CHANNEL, 0);
+    silc_server_command_send_status_data(cmd, SILC_COMMAND_KICK,
+                                        SILC_STATUS_ERR_NOT_ON_CHANNEL,
+                                        0, 2, tmp, tmp_len);
     goto out;
   }
 
   /* Check that the kicker is channel operator or channel founder */
   if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
       !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
-                                         SILC_STATUS_ERR_NO_CHANNEL_PRIV, 0);
+    silc_server_command_send_status_data(cmd, SILC_COMMAND_KICK,
+                                        SILC_STATUS_ERR_NO_CHANNEL_PRIV,
+                                        0, 2, tmp, tmp_len);
     goto out;
   }
-  
+
   /* Get target Client ID */
   target_idp = silc_argument_get_arg_type(cmd->args, 2, &target_idp_len);
   if (!target_idp) {
@@ -3490,49 +3673,61 @@ SILC_SERVER_CMD_FUNC(kick)
   }
   client_id = silc_id_payload_parse_id(target_idp, target_idp_len, NULL);
   if (!client_id) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
-                                         SILC_STATUS_ERR_NO_CLIENT_ID, 0);
+    silc_server_command_send_status_data(cmd, SILC_COMMAND_KICK,
+                                        SILC_STATUS_ERR_BAD_CLIENT_ID,
+                                        0, 2, target_idp, target_idp_len);
     goto out;
   }
 
   /* Get target client's entry */
-  target_client = silc_idlist_find_client_by_id(server->local_list, 
+  target_client = silc_idlist_find_client_by_id(server->local_list,
                                                client_id, TRUE, NULL);
   if (!target_client) {
-    target_client = silc_idlist_find_client_by_id(server->global_list, 
+    target_client = silc_idlist_find_client_by_id(server->global_list,
                                                  client_id, TRUE, NULL);
   }
 
   /* Check whether target client is on the channel */
   if (!silc_server_client_on_channel(target_client, channel, &chl)) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
+    silc_server_command_send_status_data2(cmd, SILC_COMMAND_KICK,
                                          SILC_STATUS_ERR_USER_NOT_ON_CHANNEL,
-                                         0);
+                                         0, 2, target_idp, target_idp_len,
+                                         3, tmp, tmp_len);
     goto out;
   }
 
   /* Check that the target client is not channel founder. Channel founder
      cannot be kicked from the channel. */
   if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
-                                         SILC_STATUS_ERR_NO_CHANNEL_FOPRIV,
-                                         0);
+    silc_server_command_send_status_data(cmd, SILC_COMMAND_KICK,
+                                        SILC_STATUS_ERR_NO_CHANNEL_FOPRIV,
+                                        0, 2, tmp, tmp_len);
     goto out;
   }
-  
+
   /* Get comment */
-  tmp_len = 0;
-  comment = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
-  if (tmp_len > 128)
+  comment = silc_argument_get_arg_type(cmd->args, 3, &clen);
+  if (clen > 128)
     comment = NULL;
 
+
+  /* Send the reply back to the client */
+  packet =
+    silc_command_reply_payload_encode_va(SILC_COMMAND_KICK,
+                                        SILC_STATUS_OK, 0, ident, 2,
+                                        2, tmp, tmp_len,
+                                        3, target_idp, target_idp_len);
+  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
+                         packet->data, packet->len, FALSE);
+  silc_buffer_free(packet);
+
   /* Send command reply to sender */
-  silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK, 
+  silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
                                        SILC_STATUS_OK, 0);
 
   /* Send KICKED notify to local clients on the channel */
   idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
-  silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
+  silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
                                     SILC_NOTIFY_TYPE_KICKED, 3,
                                     target_idp, target_idp_len,
                                     comment, comment ? strlen(comment) : 0,
@@ -3558,7 +3753,7 @@ SILC_SERVER_CMD_FUNC(kick)
   /* Remove the client from the channel. If the channel does not exist
      after removing the client then the client kicked itself off the channel
      and we don't have to send anything after that. */
-  if (!silc_server_remove_from_one_channel(server, NULL, channel, 
+  if (!silc_server_remove_from_one_channel(server, NULL, channel,
                                           target_client, FALSE))
     goto out;
 
@@ -3566,11 +3761,11 @@ SILC_SERVER_CMD_FUNC(kick)
     /* Re-generate channel key */
     if (!silc_server_create_channel_key(server, channel, 0))
       goto out;
-    
+
     /* Send the channel key to the channel. The key of course is not sent
        to the client who was kicked off the channel. */
-    silc_server_send_channel_key(server, target_client->connection, channel, 
-                                server->server_type == SILC_ROUTER ? 
+    silc_server_send_channel_key(server, target_client->connection, channel,
+                                server->server_type == SILC_ROUTER ?
                                 FALSE : !server->standalone);
   }
 
@@ -3644,7 +3839,7 @@ SILC_SERVER_CMD_FUNC(oper)
     if (!cached_key)
       goto out;
     result = silc_auth_verify_data(auth, tmp_len, SILC_AUTH_PUBLIC_KEY,
-                                  cached_key, 0, idata->hash, 
+                                  cached_key, 0, idata->hash,
                                   client->id, SILC_ID_CLIENT);
   }
   if (!result) {
@@ -3780,7 +3975,7 @@ SILC_SERVER_CMD_FUNC(detach)
   if (server->config->detach_timeout) {
     q = silc_calloc(1, sizeof(*q));
     q->sock = silc_id_dup(client->id, SILC_ID_CLIENT);
-    silc_schedule_task_add(server->schedule, 0, 
+    silc_schedule_task_add(server->schedule, 0,
                           silc_server_command_detach_timeout,
                           q, server->config->detach_timeout * 60,
                           0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
@@ -3859,19 +4054,19 @@ SILC_SERVER_CMD_FUNC(watch)
   }
   client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
   if (!client_id) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
-                                         SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
-                                         0);
+    silc_server_command_send_status_data(cmd, SILC_COMMAND_WATCH,
+                                        SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
+                                        0, 2, tmp, tmp_len);
     goto out;
   }
 
   /* Get the client entry which must be in local list */
-  client = silc_idlist_find_client_by_id(server->local_list, 
+  client = silc_idlist_find_client_by_id(server->local_list,
                                         client_id, TRUE, NULL);
   if (!client) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
-                                         SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
-                                         0);
+    silc_server_command_send_status_data(cmd, SILC_COMMAND_WATCH,
+                                        SILC_STATUS_ERR_NO_SUCH_CLIENT_ID, 0,
+                                        2, tmp, tmp_len);
     goto out;
   }
 
@@ -3906,7 +4101,7 @@ SILC_SERVER_CMD_FUNC(watch)
     silc_hash_make(server->md5hash, nick, strlen(nick), hash);
 
     /* Check whether this client is already watching this nickname */
-    if (silc_hash_table_find_by_context(server->watcher_list, hash, 
+    if (silc_hash_table_find_by_context(server->watcher_list, hash,
                                        client, NULL)) {
       /* Nickname is alredy being watched for this client */
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
@@ -3938,11 +4133,12 @@ SILC_SERVER_CMD_FUNC(watch)
     silc_hash_make(server->md5hash, nick, strlen(nick), hash);
 
     /* Check that this client is watching for this nickname */
-    if (!silc_hash_table_find_by_context(server->watcher_list, hash, 
+    if (!silc_hash_table_find_by_context(server->watcher_list, hash,
                                         client, (void **)&tmp)) {
       /* Nickname is alredy being watched for this client */
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
-                                           SILC_STATUS_ERR_NO_SUCH_NICK, 0);
+      silc_server_command_send_status_data(cmd, SILC_COMMAND_WATCH,
+                                          SILC_STATUS_ERR_NO_SUCH_NICK, 0,
+                                          2, nick, strlen(nick));
       goto out;
     }
 
@@ -4045,7 +4241,7 @@ SILC_SERVER_CMD_FUNC(silcoper)
     if (!cached_key)
       goto out;
     result = silc_auth_verify_data(auth, tmp_len, SILC_AUTH_PUBLIC_KEY,
-                                  cached_key, 0, idata->hash, 
+                                  cached_key, 0, idata->hash,
                                   client->id, SILC_ID_CLIENT);
   }
   if (!result) {
@@ -4094,12 +4290,13 @@ SILC_SERVER_CMD_FUNC(ban)
   SilcChannelEntry channel;
   SilcChannelClientEntry chl;
   SilcChannelID *channel_id = NULL;
-  unsigned char *id, *tmp;
-  SilcUInt32 id_len, len;
+  unsigned char *id, *tmp, *atype = NULL;
+  SilcUInt32 id_len, len, len2;
   SilcArgumentPayload args;
   SilcHashTableList htl;
   SilcUInt32 type;
   SilcUInt16 argc = 0, ident = silc_command_get_ident(cmd->payload);
+  SilcBufferStruct blist;
 
   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
     goto out;
@@ -4119,39 +4316,41 @@ SILC_SERVER_CMD_FUNC(ban)
 
   /* Get channel entry. The server must know about the channel since the
      client is expected to be on the channel. */
-  channel = silc_idlist_find_channel_by_id(server->local_list, 
+  channel = silc_idlist_find_channel_by_id(server->local_list,
                                           channel_id, NULL);
   if (!channel) {
-    channel = silc_idlist_find_channel_by_id(server->global_list, 
+    channel = silc_idlist_find_channel_by_id(server->global_list,
                                             channel_id, NULL);
     if (!channel) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
-                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL,
-                                           0);
+      silc_server_command_send_status_data(cmd, SILC_COMMAND_BAN,
+                                          SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
+                                          0, 2, id, id_len);
       goto out;
     }
   }
 
   /* Check whether this client is on the channel */
   if (!silc_server_client_on_channel(client, channel, &chl)) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
-                                         SILC_STATUS_ERR_NOT_ON_CHANNEL, 0);
+    silc_server_command_send_status_data(cmd, SILC_COMMAND_BAN,
+                                        SILC_STATUS_ERR_NOT_ON_CHANNEL, 0,
+                                        2, id, id_len);
     goto out;
   }
 
   /* The client must be at least channel operator. */
   if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
-                                         SILC_STATUS_ERR_NO_CHANNEL_PRIV, 0);
+    silc_server_command_send_status_data(cmd, SILC_COMMAND_BAN,
+                                        SILC_STATUS_ERR_NO_CHANNEL_PRIV, 0,
+                                        2, id, id_len);
     goto out;
   }
 
   /* Get the ban information */
-  tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
-  if (tmp && len > 2) {
+  tmp = silc_argument_get_arg_type(cmd->args, 3, &len2);
+  if (tmp && len2 > 2) {
     /* Parse the arguments to see they are constructed correctly */
     SILC_GET16_MSB(argc, tmp);
-    args = silc_argument_payload_parse(tmp + 2, len - 2, argc);
+    args = silc_argument_payload_parse(tmp + 2, len2 - 2, argc);
     if (!args) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
                                            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
@@ -4160,9 +4359,9 @@ SILC_SERVER_CMD_FUNC(ban)
     }
 
     /* Get the type of action */
-    tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
-    if (tmp && len == 1) {
-      if (tmp[0] == 0x00) {
+    atype = silc_argument_get_arg_type(cmd->args, 2, &len);
+    if (atype && len == 1) {
+      if (atype[0] == 0x00) {
        /* Allocate hash table for ban list if it doesn't exist yet */
        if (!channel->ban_list)
          channel->ban_list =
@@ -4170,7 +4369,7 @@ SILC_SERVER_CMD_FUNC(ban)
                                  NULL, NULL, NULL,
                                  silc_server_inviteban_destruct, channel,
                                  TRUE);
-    
+
        /* Check for resource limit */
        if (silc_hash_table_count(channel->ban_list) > 64) {
          silc_server_command_send_status_reply(cmd, SILC_COMMAND_BAN,
@@ -4182,7 +4381,7 @@ SILC_SERVER_CMD_FUNC(ban)
 
       /* Now add or delete the information. */
       silc_server_inviteban_process(server, channel->ban_list,
-                                   (SilcUInt8)tmp[0], args);
+                                   (SilcUInt8)atype[0], args);
     }
     silc_argument_payload_free(args);
   }
@@ -4202,23 +4401,36 @@ SILC_SERVER_CMD_FUNC(ban)
     silc_hash_table_list_reset(&htl);
   }
 
-  /* Send the BAN notify type to our primary router. */
-  if (list)
+  /* Send BAN notify type to local servers (but not clients) and to
+     network. */
+  if (atype && tmp && len2) {
+    silc_buffer_set(&blist, tmp, len2);
+
+    /* Send to local servers if we are router */
+    if (server->server_type == SILC_ROUTER)
+      silc_server_send_notify_to_channel(server, NULL, channel, FALSE, FALSE,
+                                         SILC_NOTIFY_TYPE_BAN, 3,
+                                        id, id_len,
+                                        atype, 1,
+                                        tmp ? blist.data : NULL,
+                                        tmp ? blist.len : 0);
+
+    /* Send to network. */
     silc_server_send_notify_ban(server, SILC_PRIMARY_ROUTE(server),
-                               SILC_BROADCAST(server), channel,
-                               silc_argument_get_arg_type(cmd->args, 2, NULL),
-                               list);
+                               SILC_BROADCAST(server), channel, atype,
+                               &blist);
+  }
 
   /* Send the reply back to the client */
-  packet = 
+  packet =
     silc_command_reply_payload_encode_va(SILC_COMMAND_BAN,
                                         SILC_STATUS_OK, 0, ident, 2,
                                         2, id, id_len,
                                         3, list ? list->data : NULL,
                                         list ? list->len : 0);
-  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
+  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
                          packet->data, packet->len, FALSE);
-    
+
   silc_buffer_free(packet);
   silc_buffer_free(list);
 
@@ -4264,17 +4476,18 @@ SILC_SERVER_CMD_FUNC(leave)
   if (!channel) {
     channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
     if (!channel) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
-                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL,
-                                           0);
+      silc_server_command_send_status_data(cmd, SILC_COMMAND_LEAVE,
+                                          SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID,
+                                          0, 2, tmp, len);
       goto out;
     }
   }
 
   /* Check whether this client is on the channel */
   if (!silc_server_client_on_channel(id_entry, channel, NULL)) {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
-                                         SILC_STATUS_ERR_NOT_ON_CHANNEL, 0);
+    silc_server_command_send_status_data(cmd, SILC_COMMAND_LEAVE,
+                                        SILC_STATUS_ERR_NOT_ON_CHANNEL, 0,
+                                        2, tmp, len);
     goto out;
   }
 
@@ -4298,8 +4511,8 @@ SILC_SERVER_CMD_FUNC(leave)
       goto out;
 
     /* Send the channel key */
-    silc_server_send_channel_key(server, NULL, channel, 
-                                server->server_type == SILC_ROUTER ? 
+    silc_server_send_channel_key(server, NULL, channel,
+                                server->server_type == SILC_ROUTER ?
                                 FALSE : !server->standalone);
   }
 
@@ -4345,8 +4558,9 @@ SILC_SERVER_CMD_FUNC(users)
   if (channel_id) {
     id = silc_id_payload_parse_id(channel_id, channel_id_len, NULL);
     if (!id) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
-                                           SILC_STATUS_ERR_BAD_CHANNEL_ID, 0);
+      silc_server_command_send_status_data(cmd, SILC_COMMAND_USERS,
+                                          SILC_STATUS_ERR_BAD_CHANNEL_ID, 0,
+                                          2, channel_id, channel_id_len);
       goto out;
     }
   }
@@ -4357,25 +4571,25 @@ SILC_SERVER_CMD_FUNC(users)
   if (id)
     channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
   else
-    channel = silc_idlist_find_channel_by_name(server->local_list, 
+    channel = silc_idlist_find_channel_by_name(server->local_list,
                                               channel_name, NULL);
 
-  if (!channel || (!server->standalone && (channel->disabled || 
+  if (!channel || (!server->standalone && (channel->disabled ||
                    !channel->users_resolved))) {
     if (server->server_type != SILC_ROUTER && !server->standalone &&
        !cmd->pending) {
       SilcBuffer tmpbuf;
-      
+
       silc_command_set_ident(cmd->payload, ++server->cmd_ident);
       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
-      
+
       /* Send USERS command */
       silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                              SILC_PACKET_COMMAND, cmd->packet->flags,
                              tmpbuf->data, tmpbuf->len, TRUE);
-      
+
       /* Reprocess this packet after received reply */
-      silc_server_command_pending(server, SILC_COMMAND_USERS, 
+      silc_server_command_pending(server, SILC_COMMAND_USERS,
                                  silc_command_get_ident(cmd->payload),
                                  silc_server_command_users,
                                  silc_server_command_dup(cmd));
@@ -4390,13 +4604,20 @@ SILC_SERVER_CMD_FUNC(users)
     if (id)
       channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
     else
-      channel = silc_idlist_find_channel_by_name(server->global_list, 
+      channel = silc_idlist_find_channel_by_name(server->global_list,
                                                 channel_name, NULL);
     if (!channel) {
       /* Channel really does not exist */
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
-                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL,
-                                           0);
+      if (id)
+       silc_server_command_send_status_data(
+                                   cmd, SILC_COMMAND_USERS,
+                                   SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID, 0,
+                                   2, channel_id, channel_id_len);
+      else
+       silc_server_command_send_status_data(
+                                   cmd, SILC_COMMAND_USERS,
+                                   SILC_STATUS_ERR_NO_SUCH_CHANNEL, 0,
+                                   2, channel_name, strlen(channel_name));
       goto out;
     }
   }
@@ -4405,11 +4626,12 @@ SILC_SERVER_CMD_FUNC(users)
      user requesting this command is on the channel or is server */
   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
     if (channel->mode & (SILC_CHANNEL_MODE_PRIVATE | SILC_CHANNEL_MODE_SECRET)
-       && !silc_server_client_on_channel(cmd->sock->user_data, channel, 
+       && !silc_server_client_on_channel(cmd->sock->user_data, channel,
                                          NULL)) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
-                                           SILC_STATUS_ERR_NO_SUCH_CHANNEL,
-                                           0);
+      silc_server_command_send_status_data(cmd, SILC_COMMAND_USERS,
+                                          SILC_STATUS_ERR_NO_SUCH_CHANNEL, 0,
+                                          2, channel->channel_name,
+                                          strlen(channel->channel_name));
       goto out;
     }
   }
@@ -4431,7 +4653,7 @@ SILC_SERVER_CMD_FUNC(users)
                                                SILC_STATUS_OK, 0, ident, 4,
                                                2, idp->data, idp->len,
                                                3, lc, 4,
-                                               4, client_id_list ? 
+                                               4, client_id_list ?
                                                client_id_list->data : NULL,
                                                client_id_list ?
                                                client_id_list->len : 0,
@@ -4439,9 +4661,9 @@ SILC_SERVER_CMD_FUNC(users)
                                                client_mode_list->data : NULL,
                                                client_mode_list ?
                                                client_mode_list->len : 0);
-  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
+  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
                          packet->data, packet->len, FALSE);
-    
+
   silc_buffer_free(idp);
   silc_buffer_free(packet);
   if (client_id_list)
@@ -4495,12 +4717,12 @@ SILC_SERVER_CMD_FUNC(getkey)
 
     /* If the client is not found from local list there is no chance it
        would be locally connected client so send the command further. */
-    client = silc_idlist_find_client_by_id(server->local_list, 
+    client = silc_idlist_find_client_by_id(server->local_list,
                                           client_id, TRUE, NULL);
     if (!client)
-      client = silc_idlist_find_client_by_id(server->global_list, 
+      client = silc_idlist_find_client_by_id(server->global_list,
                                             client_id, TRUE, NULL);
-    
+
     if ((!client && !cmd->pending && !server->standalone) ||
        (client && !client->connection && !cmd->pending &&
         !(client->mode & SILC_UMODE_DETACHED)) ||
@@ -4508,22 +4730,22 @@ SILC_SERVER_CMD_FUNC(getkey)
       SilcBuffer tmpbuf;
       SilcUInt16 old_ident;
       SilcSocketConnection dest_sock;
-      
-      dest_sock = silc_server_get_client_route(server, NULL, 0, 
+
+      dest_sock = silc_server_get_client_route(server, NULL, 0,
                                               client_id, NULL, NULL);
       if (!dest_sock)
        goto out;
-      
+
       old_ident = silc_command_get_ident(cmd->payload);
       silc_command_set_ident(cmd->payload, ++server->cmd_ident);
       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
-      
+
       silc_server_packet_send(server, dest_sock,
                              SILC_PACKET_COMMAND, cmd->packet->flags,
                              tmpbuf->data, tmpbuf->len, TRUE);
-      
+
       /* Reprocess this packet after received reply from router */
-      silc_server_command_pending(server, SILC_COMMAND_GETKEY, 
+      silc_server_command_pending(server, SILC_COMMAND_GETKEY,
                                  silc_command_get_ident(cmd->payload),
                                  silc_server_command_getkey,
                                  silc_server_command_dup(cmd));
@@ -4534,14 +4756,14 @@ SILC_SERVER_CMD_FUNC(getkey)
     }
 
     if (!client) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY,
-                                           SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
-                                           0);
+      silc_server_command_send_status_data(cmd, SILC_COMMAND_GETKEY,
+                                          SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
+                                          0, 2, tmp, tmp_len);
       goto out;
     }
 
     /* The client is locally connected, just get the public key and
-       send it back. If they key does not exist then do not send it, 
+       send it back. If they key does not exist then do not send it,
        send just OK reply */
     public_key = client->data.public_key;
     if (public_key)
@@ -4551,12 +4773,12 @@ SILC_SERVER_CMD_FUNC(getkey)
 
     /* If the server is not found from local list there is no chance it
        would be locally connected server so send the command further. */
-    server_entry = silc_idlist_find_server_by_id(server->local_list, 
+    server_entry = silc_idlist_find_server_by_id(server->local_list,
                                                 server_id, TRUE, NULL);
     if (!server_entry)
-      server_entry = silc_idlist_find_server_by_id(server->global_list, 
+      server_entry = silc_idlist_find_server_by_id(server->global_list,
                                                   server_id, TRUE, NULL);
-    
+
     if (server_entry != server->id_entry &&
        ((!server_entry && !cmd->pending && !server->standalone) ||
         (server_entry && !server_entry->connection && !cmd->pending &&
@@ -4565,17 +4787,17 @@ SILC_SERVER_CMD_FUNC(getkey)
          !server->standalone))) {
       SilcBuffer tmpbuf;
       SilcUInt16 old_ident;
-      
+
       old_ident = silc_command_get_ident(cmd->payload);
       silc_command_set_ident(cmd->payload, ++server->cmd_ident);
       tmpbuf = silc_command_payload_encode_payload(cmd->payload);
-      
+
       silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                              SILC_PACKET_COMMAND, cmd->packet->flags,
                              tmpbuf->data, tmpbuf->len, TRUE);
-      
+
       /* Reprocess this packet after received reply from router */
-      silc_server_command_pending(server, SILC_COMMAND_GETKEY, 
+      silc_server_command_pending(server, SILC_COMMAND_GETKEY,
                                  silc_command_get_ident(cmd->payload),
                                  silc_server_command_getkey,
                                  silc_server_command_dup(cmd));
@@ -4586,14 +4808,14 @@ SILC_SERVER_CMD_FUNC(getkey)
     }
 
     if (!server_entry) {
-      silc_server_command_send_status_reply(cmd, SILC_COMMAND_GETKEY,
-                                           SILC_STATUS_ERR_NO_SUCH_SERVER_ID,
-                                           0);
+      silc_server_command_send_status_data(cmd, SILC_COMMAND_GETKEY,
+                                          SILC_STATUS_ERR_NO_SUCH_SERVER_ID,
+                                          0, 2, tmp, tmp_len);
       goto out;
     }
 
     /* If they key does not exist then do not send it, send just OK reply */
-    public_key = (!server_entry->data.public_key ? 
+    public_key = (!server_entry->data.public_key ?
                  (server_entry == server->id_entry ? server->public_key :
                   NULL) : server_entry->data.public_key);
     if (public_key)
@@ -4608,7 +4830,7 @@ SILC_SERVER_CMD_FUNC(getkey)
                                                2, tmp, tmp_len,
                                                3, pk ? pk->data : NULL,
                                                pk ? pk->len : 0);
-  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
+  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
                          packet->data, packet->len, FALSE);
   silc_buffer_free(packet);
 
@@ -4682,7 +4904,7 @@ SILC_SERVER_CMD_FUNC(connect)
 }
 
 /* Server side command of CLOSE. Closes connection to a specified server. */
+
 SILC_SERVER_CMD_FUNC(close)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
@@ -4766,7 +4988,7 @@ SILC_SERVER_CMD_FUNC(close)
 
 /* Server side command of SHUTDOWN. Shutdowns the server and closes all
    active connections. */
+
 SILC_SERVER_CMD_FUNC(shutdown)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
index a72e6c206a8ccdef7d0f727f6fe7ec6fbbd94fba..1350aee19ddb515a8a6e549b49f941bb9eeedf07 100644 (file)
@@ -4,13 +4,12 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2002 Pekka Riikonen
+  Copyright (C) 1997 - 2003 Pekka Riikonen
 
   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.
-  
+  the Free Software Foundation; version 2 of the License.
+
   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
@@ -53,6 +52,7 @@ SilcServerCommandReply silc_command_reply_list[] =
   SILC_SERVER_CMD_REPLY(getkey, GETKEY),
   SILC_SERVER_CMD_REPLY(list, LIST),
   SILC_SERVER_CMD_REPLY(watch, WATCH),
+  SILC_SERVER_CMD_REPLY(ping, PING),
 
   { NULL, 0 },
 };
@@ -77,7 +77,7 @@ void silc_server_command_reply_process(SilcServer server,
     SILC_LOG_DEBUG(("Bad command reply packet"));
     return;
   }
-  
+
   /* Allocate command reply context. This must be free'd by the
      command reply routine receiving it. */
   ctx = silc_calloc(1, sizeof(*ctx));
@@ -94,9 +94,9 @@ void silc_server_command_reply_process(SilcServer server,
     silc_server_command_reply_free(ctx);
     return;
   }
-      
+
   /* Check for pending commands and mark to be exeucted */
-  ctx->callbacks = 
+  ctx->callbacks =
     silc_server_command_pending_check(server, command,
                                      ctx->ident, &ctx->callbacks_count);
 
@@ -126,7 +126,7 @@ void silc_server_command_reply_free(SilcServerCommandReplyContext cmd)
   }
 }
 
-static void 
+static void
 silc_server_command_process_error(SilcServerCommandReplyContext cmd,
                                  SilcStatus error)
 {
@@ -144,10 +144,10 @@ silc_server_command_process_error(SilcServerCommandReplyContext cmd,
       if (client_id) {
        SILC_LOG_DEBUG(("Received invalid client ID notification, deleting "
                        "the entry from cache"));
-       client = silc_idlist_find_client_by_id(server->global_list, 
+       client = silc_idlist_find_client_by_id(server->global_list,
                                               client_id, FALSE, NULL);
        if (client) {
-         silc_server_remove_from_channels(server, NULL, client, TRUE, 
+         silc_server_remove_from_channels(server, NULL, client, TRUE,
                                           NULL, TRUE, FALSE);
          silc_idlist_del_data(client);
          silc_idlist_del_client(server->global_list, client);
@@ -193,10 +193,10 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
 
   /* Check if we have this client cached already. */
 
-  client = silc_idlist_find_client_by_id(server->local_list, client_id, 
+  client = silc_idlist_find_client_by_id(server->local_list, client_id,
                                         FALSE, NULL);
   if (!client) {
-    client = silc_idlist_find_client_by_id(server->global_list, client_id, 
+    client = silc_idlist_find_client_by_id(server->global_list, client_id,
                                           FALSE, NULL);
     global = TRUE;
   }
@@ -211,18 +211,18 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
     silc_parse_userfqdn(nickname, &nick, &servername);
 
     /* We don't have that client anywhere, add it. The client is added
-       to global list since server didn't have it in the lists so it must be 
+       to global list since server didn't have it in the lists so it must be
        global. */
-    client = silc_idlist_add_client(server->global_list, nick, 
-                                   strdup(username), 
-                                   strdup(realname), client_id, 
+    client = silc_idlist_add_client(server->global_list, nick,
+                                   strdup(username),
+                                   strdup(realname), client_id,
                                    cmd->sock->user_data, NULL, 0);
     if (!client) {
       SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
       return FALSE;
     }
 
-    client->data.status |= 
+    client->data.status |=
       (SILC_IDLIST_STATUS_REGISTERED | SILC_IDLIST_STATUS_RESOLVED);
     client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
     client->mode = mode;
@@ -243,7 +243,7 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
     silc_free(client->username);
     silc_free(client->userinfo);
     silc_free(client->servername);
-    
+
     client->nickname = nick;
     client->username = strdup(username);
     client->userinfo = strdup(realname);
@@ -254,8 +254,8 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
 
     /* Create new cache entry */
     silc_idcache_add(global ? server->global_list->clients :
-                    server->local_list->clients, nick, client->id, 
-                    client, 0, NULL); 
+                    server->local_list->clients, nick, client->id,
+                    client, 0, NULL);
     silc_free(client_id);
   }
 
@@ -392,7 +392,7 @@ silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
   client = silc_idlist_find_client_by_id(server->local_list, client_id,
                                         FALSE, &cache);
   if (!client) {
-    client = silc_idlist_find_client_by_id(server->global_list, 
+    client = silc_idlist_find_client_by_id(server->global_list,
                                           client_id, FALSE, &cache);
     global = TRUE;
   }
@@ -407,11 +407,11 @@ silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
     silc_parse_userfqdn(nickname, &nick, &servername);
 
     /* We don't have that client anywhere, add it. The client is added
-       to global list since server didn't have it in the lists so it must be 
+       to global list since server didn't have it in the lists so it must be
        global. */
     client = silc_idlist_add_client(server->global_list, nick,
-                                   strdup(username), strdup(realname), 
-                                   silc_id_dup(client_id, SILC_ID_CLIENT), 
+                                   strdup(username), strdup(realname),
+                                   silc_id_dup(client_id, SILC_ID_CLIENT),
                                    cmd->sock->user_data, NULL,
                                    SILC_ID_CACHE_EXPIRE_DEF);
     if (!client) {
@@ -421,7 +421,7 @@ silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
 
     client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
     client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
-    client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED; 
+    client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
     client->servername = servername;
   } else {
     /* We have the client already, update the data */
@@ -432,7 +432,7 @@ silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
     silc_free(client->nickname);
     silc_free(client->username);
     silc_free(client->servername);
-    
+
     client->nickname = nick;
     client->username = strdup(username);
     client->servername = servername;
@@ -443,7 +443,7 @@ silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
     silc_idcache_del_by_context(global ? server->global_list->clients :
                                server->local_list->clients, client);
     silc_idcache_add(global ? server->global_list->clients :
-                    server->local_list->clients, nick, client->id, 
+                    server->local_list->clients, nick, client->id,
                     client, 0, NULL);
   }
 
@@ -535,7 +535,7 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
 
     SILC_LOG_DEBUG(("Received client information"));
 
-    client = silc_idlist_find_client_by_id(server->local_list, 
+    client = silc_idlist_find_client_by_id(server->local_list,
                                           client_id, FALSE, NULL);
     if (!client) {
       client = silc_idlist_find_client_by_id(server->global_list, client_id,
@@ -553,9 +553,9 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
        silc_parse_userfqdn(name, &nick, NULL);
 
       /* We don't have that client anywhere, add it. The client is added
-        to global list since server didn't have it in the lists so it must be 
+        to global list since server didn't have it in the lists so it must be
         global. */
-      client = silc_idlist_add_client(server->global_list, nick, 
+      client = silc_idlist_add_client(server->global_list, nick,
                                      info ? strdup(info) : NULL, NULL,
                                      client_id, cmd->sock->user_data,
                                      NULL, time(NULL) + 300);
@@ -568,9 +568,9 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
       client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
     } else {
       /* We have the client already, update the data */
-      
+
       SILC_LOG_DEBUG(("Updating client data"));
-      
+
       /* Take nickname */
       if (name) {
        silc_parse_userfqdn(name, &nick, NULL);
@@ -582,7 +582,7 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
        silc_free(client->nickname);
        client->nickname = nick;
       }
-      
+
       if (info) {
        silc_free(client->username);
        client->username = strdup(info);
@@ -590,11 +590,11 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
 
       client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
       client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
-      
+
       if (name) {
        /* Add new cache entry */
        silc_idcache_add(global ? server->global_list->clients :
-                        server->local_list->clients, nick, client->id, 
+                        server->local_list->clients, nick, client->id,
                         client, expire, NULL);
       }
 
@@ -625,19 +625,19 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
 
     SILC_LOG_DEBUG(("Received server information"));
 
-    server_entry = silc_idlist_find_server_by_id(server->local_list, 
+    server_entry = silc_idlist_find_server_by_id(server->local_list,
                                                 server_id, FALSE, NULL);
     if (!server_entry)
-      server_entry = silc_idlist_find_server_by_id(server->global_list, 
+      server_entry = silc_idlist_find_server_by_id(server->global_list,
                                                   server_id, FALSE, NULL);
     if (!server_entry) {
       /* If router did not find such Server ID in its lists then this must
         be bogus server or some router in the net is buggy. */
       if (server->server_type != SILC_SERVER)
        goto error;
-      
+
       /* We don't have that server anywhere, add it. */
-      server_entry = silc_idlist_add_server(server->global_list, 
+      server_entry = silc_idlist_add_server(server->global_list,
                                            strdup(name), 0,
                                            server_id, server->router,
                                            SILC_PRIMARY_ROUTE(server));
@@ -664,20 +664,20 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
 
     SILC_LOG_DEBUG(("Received channel information"));
 
-    channel = silc_idlist_find_channel_by_name(server->local_list, 
+    channel = silc_idlist_find_channel_by_name(server->local_list,
                                               name, NULL);
     if (!channel)
-      channel = silc_idlist_find_channel_by_name(server->global_list, 
+      channel = silc_idlist_find_channel_by_name(server->global_list,
                                                 name, NULL);
     if (!channel) {
       /* If router did not find such Channel ID in its lists then this must
         be bogus channel or some router in the net is buggy. */
       if (server->server_type != SILC_SERVER)
        goto error;
-      
+
       /* We don't have that channel anywhere, add it. */
       channel = silc_idlist_add_channel(server->global_list, strdup(name),
-                                       SILC_CHANNEL_MODE_NONE, channel_id, 
+                                       SILC_CHANNEL_MODE_NONE, channel_id,
                                        server->router, NULL, NULL, 0);
       if (!channel) {
        silc_free(channel_id);
@@ -758,10 +758,10 @@ SILC_SERVER_CMD_REPLY_FUNC(info)
   if (tmp_len > 256)
     goto out;
 
-  entry = silc_idlist_find_server_by_id(server->local_list, server_id, 
+  entry = silc_idlist_find_server_by_id(server->local_list, server_id,
                                        FALSE, NULL);
   if (!entry) {
-    entry = silc_idlist_find_server_by_id(server->global_list, server_id, 
+    entry = silc_idlist_find_server_by_id(server->global_list, server_id,
                                          FALSE, NULL);
     if (!entry) {
       /* Add the server to global list */
@@ -812,10 +812,10 @@ SILC_SERVER_CMD_REPLY_FUNC(motd)
   if (!server_id)
     goto out;
 
-  entry = silc_idlist_find_server_by_id(server->local_list, server_id, 
+  entry = silc_idlist_find_server_by_id(server->local_list, server_id,
                                        TRUE, NULL);
   if (!entry) {
-    entry = silc_idlist_find_server_by_id(server->global_list, server_id, 
+    entry = silc_idlist_find_server_by_id(server->global_list, server_id,
                                          TRUE, NULL);
     if (!entry)
       goto out;
@@ -942,12 +942,12 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
     silc_pkcs_public_key_payload_decode(tmp, len, &founder_key);
 
   /* See whether we already have the channel. */
-  entry = silc_idlist_find_channel_by_name(server->local_list, 
+  entry = silc_idlist_find_channel_by_name(server->local_list,
                                           channel_name, &cache);
   if (!entry) {
     /* Add new channel */
 
-    SILC_LOG_DEBUG(("Adding new [%s] channel %s id(%s)", 
+    SILC_LOG_DEBUG(("Adding new [%s] channel %s id(%s)",
                    (created == 0 ? "existing" : "created"), channel_name,
                    silc_id_render(id, SILC_ID_CHANNEL)));
 
@@ -1049,7 +1049,12 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
     entry->topic = strdup(tmp);
   }
 
-  /* If channel was not created we know there is global users on the 
+  /* Get channel public key list */
+  tmp = silc_argument_get_arg_type(cmd->args, 16, &len);
+  if (tmp && server->server_type == SILC_SERVER)
+    silc_server_set_channel_pk_list(server, NULL, entry, tmp, len);
+
+  /* If channel was not created we know there is global users on the
      channel. */
   entry->global_users = (created == 0 ? TRUE : FALSE);
 
@@ -1071,7 +1076,7 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
   }
 
   /* Save the users to the channel */
-  silc_server_save_users_on_channel(server, cmd->sock, entry, 
+  silc_server_save_users_on_channel(server, cmd->sock, entry,
                                    client_id, client_id_list,
                                    client_mode_list, list_count);
   entry->users_resolved = TRUE;
@@ -1157,10 +1162,10 @@ SILC_SERVER_CMD_REPLY_FUNC(users)
     goto out;
 
   /* Get channel entry */
-  channel = silc_idlist_find_channel_by_id(server->local_list, 
+  channel = silc_idlist_find_channel_by_id(server->local_list,
                                           channel_id, NULL);
   if (!channel) {
-    channel = silc_idlist_find_channel_by_id(server->global_list, 
+    channel = silc_idlist_find_channel_by_id(server->global_list,
                                             channel_id, NULL);
     if (!channel) {
       SilcBuffer idp;
@@ -1177,7 +1182,7 @@ SILC_SERVER_CMD_REPLY_FUNC(users)
       /* Register pending command callback. After we've received the channel
         information we will reprocess this command reply by re-calling this
         USERS command reply callback. */
-      silc_server_command_pending(server, SILC_COMMAND_IDENTIFY, 
+      silc_server_command_pending(server, SILC_COMMAND_IDENTIFY,
                                  server->cmd_ident,
                                  silc_server_command_reply_users, cmd);
       return;
@@ -1210,7 +1215,7 @@ SILC_SERVER_CMD_REPLY_FUNC(users)
 
   /* Save the users to the channel */
   silc_server_save_users_on_channel(server, cmd->sock, channel, NULL,
-                                   client_id_list, client_mode_list, 
+                                   client_id_list, client_mode_list,
                                    list_count);
 
   channel->global_users = silc_server_channel_has_global(channel);
@@ -1266,7 +1271,7 @@ SILC_SERVER_CMD_REPLY_FUNC(getkey)
     client = silc_idlist_find_client_by_id(server->local_list, client_id,
                                           TRUE, NULL);
     if (!client) {
-      client = silc_idlist_find_client_by_id(server->global_list, 
+      client = silc_idlist_find_client_by_id(server->global_list,
                                             client_id, TRUE, NULL);
       if (!client)
        goto out;
@@ -1280,7 +1285,7 @@ SILC_SERVER_CMD_REPLY_FUNC(getkey)
     server_entry = silc_idlist_find_server_by_id(server->local_list, server_id,
                                                 TRUE, NULL);
     if (!server_entry) {
-      server_entry = silc_idlist_find_server_by_id(server->global_list, 
+      server_entry = silc_idlist_find_server_by_id(server->global_list,
                                                   server_id, TRUE, NULL);
       if (!server_entry)
        goto out;
@@ -1331,10 +1336,10 @@ SILC_SERVER_CMD_REPLY_FUNC(list)
     SILC_GET32_MSB(usercount, tmp);
 
   /* Add the channel entry if we do not have it already */
-  channel = silc_idlist_find_channel_by_name(server->local_list, 
+  channel = silc_idlist_find_channel_by_name(server->local_list,
                                             name, &cache);
   if (!channel) {
-    channel = silc_idlist_find_channel_by_name(server->global_list, 
+    channel = silc_idlist_find_channel_by_name(server->global_list,
                                               name, &cache);
     global_list = TRUE;
   }
@@ -1343,10 +1348,10 @@ SILC_SERVER_CMD_REPLY_FUNC(list)
        be bogus channel or some router in the net is buggy. */
     if (server->server_type != SILC_SERVER)
       goto out;
-    
+
     channel = silc_idlist_add_channel(server->global_list, strdup(name),
-                                     SILC_CHANNEL_MODE_NONE, channel_id, 
-                                     server->router, NULL, NULL, 
+                                     SILC_CHANNEL_MODE_NONE, channel_id,
+                                     server->router, NULL, NULL,
                                      time(NULL) + 60);
     if (!channel)
       goto out;
@@ -1394,3 +1399,16 @@ SILC_SERVER_CMD_REPLY_FUNC(watch)
  err:
   silc_server_command_reply_free(cmd);
 }
+
+SILC_SERVER_CMD_REPLY_FUNC(ping)
+{
+  SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
+  SilcStatus status, error;
+
+  COMMAND_CHECK_STATUS;
+
+ out:
+  SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_PING);
+ err:
+  silc_server_command_reply_free(cmd);
+}
index 7a06fd6e590ee8f2f2952af203dcc1b42911214b..371cce46d4ecb572012d01c6612225aae98ef227 100644 (file)
@@ -4,13 +4,13 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2002 Pekka Riikonen
+  Copyright (C) 1997 - 2003 Pekka Riikonen
 
   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
@@ -77,5 +77,6 @@ SILC_SERVER_CMD_REPLY_FUNC(users);
 SILC_SERVER_CMD_REPLY_FUNC(getkey);
 SILC_SERVER_CMD_REPLY_FUNC(list);
 SILC_SERVER_CMD_REPLY_FUNC(watch);
+SILC_SERVER_CMD_REPLY_FUNC(ping);
 
 #endif
index fb457b6c44335fe596b732bccd50aed9d8f0b605..2562c0f03d39ec1db2f4c252dd78a0fc9d0c0e38 100644 (file)
@@ -4,13 +4,13 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2002 Pekka Riikonen
+  Copyright (C) 1997 - 2003 Pekka Riikonen
 
   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
@@ -112,8 +112,8 @@ SILC_TASK_CALLBACK_GLOBAL(silc_idlist_purge)
    when new server connects to us. We also add ourselves to cache with
    this function. */
 
-SilcServerEntry 
-silc_idlist_add_server(SilcIDList id_list, 
+SilcServerEntry
+silc_idlist_add_server(SilcIDList id_list,
                       char *server_name, int server_type,
                       SilcServerID *id, SilcServerEntry router,
                       void *connection)
@@ -129,7 +129,7 @@ silc_idlist_add_server(SilcIDList id_list,
   server->router = router;
   server->connection = connection;
 
-  if (!silc_idcache_add(id_list->servers, server->server_name, 
+  if (!silc_idcache_add(id_list->servers, server->server_name,
                        (void *)server->id, (void *)server, 0, NULL)) {
     silc_free(server);
     return NULL;
@@ -153,13 +153,13 @@ silc_idlist_find_server_by_id(SilcIDList id_list, SilcServerID *id,
   SILC_LOG_DEBUG(("Server ID (%s)",
                  silc_id_render(id, SILC_ID_SERVER)));
 
-  if (!silc_idcache_find_by_id_one(id_list->servers, (void *)id, 
+  if (!silc_idcache_find_by_id_one(id_list->servers, (void *)id,
                                   &id_cache))
     return NULL;
 
   server = (SilcServerEntry)id_cache->context;
 
-  if (server && registered && 
+  if (server && registered &&
       !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
     return NULL;
 
@@ -186,7 +186,7 @@ silc_idlist_find_server_by_name(SilcIDList id_list, char *name,
     return NULL;
 
   server = (SilcServerEntry)id_cache->context;
-  
+
   if (server && registered &&
       !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
     return NULL;
@@ -210,7 +210,7 @@ silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname,
   SilcIDCacheEntry id_cache = NULL;
   SilcServerEntry server = NULL;
   SilcSocketConnection sock;
+
   SILC_LOG_DEBUG(("Server by hostname %s and port %d", hostname, port));
 
   if (!silc_idcache_get_all(id_list->servers, &list))
@@ -224,7 +224,7 @@ silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname,
   while (id_cache) {
     server = (SilcServerEntry)id_cache->context;
     sock = (SilcSocketConnection)server->connection;
-    
+
     if (sock && ((sock->hostname && !strcasecmp(sock->hostname, hostname)) ||
                 (sock->ip && !strcasecmp(sock->ip, hostname)))
        && server->id->port == SILC_SWAB_16(port))
@@ -236,7 +236,7 @@ silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname,
     if (!silc_idcache_list_next(list, &id_cache))
       break;
   }
-  
+
   silc_idcache_list_free(list);
 
   if (server && registered &&
@@ -251,7 +251,7 @@ silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname,
   return server;
 }
 
-/* Replaces old Server ID with new one */ 
+/* Replaces old Server ID with new one */
 
 SilcServerEntry
 silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id,
@@ -265,7 +265,7 @@ silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id,
 
   SILC_LOG_DEBUG(("Replacing Server ID"));
 
-  if (!silc_idcache_find_by_id_one(id_list->servers, (void *)old_id, 
+  if (!silc_idcache_find_by_id_one(id_list->servers, (void *)old_id,
                                   &id_cache))
     return NULL;
 
@@ -278,7 +278,7 @@ silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id,
   silc_free(server->id);
   server->id = new_id;
 
-  silc_idcache_add(id_list->servers, server->server_name, server->id, 
+  silc_idcache_add(id_list->servers, server->server_name, server->id,
                   server, 0, NULL);
 
   SILC_LOG_DEBUG(("Found"));
@@ -292,8 +292,10 @@ int silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry)
 {
   if (entry) {
     /* Remove from cache */
-    if (!silc_idcache_del_by_context(id_list->servers, entry))
+    if (!silc_idcache_del_by_context(id_list->servers, entry)) {
+      SILC_LOG_DEBUG(("Unknown server, did not delete"));
       return FALSE;
+    }
 
     SILC_LOG_DEBUG(("Deleting server %s id %s", entry->server_name ?
                    entry->server_name : "",
@@ -329,8 +331,8 @@ int silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry)
    to be directly connected local client and `router' must be NULL. */
 
 SilcClientEntry
-silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username, 
-                      char *userinfo, SilcClientID *id, 
+silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username,
+                      char *userinfo, SilcClientID *id,
                       SilcServerEntry router, void *connection,
                       int expire)
 {
@@ -348,7 +350,7 @@ silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username,
   client->channels = silc_hash_table_alloc(3, silc_hash_ptr, NULL,
                                           NULL, NULL, NULL, NULL, TRUE);
 
-  if (!silc_idcache_add(id_list->clients, nickname, (void *)client->id, 
+  if (!silc_idcache_add(id_list->clients, nickname, (void *)client->id,
                        (void *)client, expire, NULL)) {
     silc_hash_table_free(client->channels);
     silc_free(client);
@@ -367,8 +369,10 @@ int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry)
 
   if (entry) {
     /* Remove from cache */
-    if (!silc_idcache_del_by_context(id_list->clients, entry))
+    if (!silc_idcache_del_by_context(id_list->clients, entry)) {
+      SILC_LOG_DEBUG(("Unknown client, did not delete"));
       return FALSE;
+    }
 
     assert(!silc_hash_table_count(entry->channels));
 
@@ -394,7 +398,7 @@ int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry)
    returned to `clients_count'. Caller must free the returned table. */
 
 int silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname,
-                                       char *server, 
+                                       char *server,
                                        SilcClientEntry **clients,
                                        SilcUInt32 *clients_count)
 {
@@ -406,8 +410,8 @@ int silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname,
   if (!silc_idcache_find_by_name(id_list->clients, nickname, &list))
     return FALSE;
 
-  *clients = silc_realloc(*clients, 
-                         (silc_idcache_list_count(list) + *clients_count) * 
+  *clients = silc_realloc(*clients,
+                         (silc_idcache_list_count(list) + *clients_count) *
                          sizeof(**clients));
 
   silc_idcache_list_first(list, &id_cache);
@@ -415,9 +419,9 @@ int silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname,
 
   while (silc_idcache_list_next(list, &id_cache))
     (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
-  
+
   silc_idcache_list_free(list);
-  
+
   SILC_LOG_DEBUG(("Found total %d clients", *clients_count));
 
   return TRUE;
@@ -452,8 +456,8 @@ int silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname,
   if (!silc_idcache_find_by_id(id_list->clients, &client_id, &list))
     return FALSE;
 
-  *clients = silc_realloc(*clients, 
-                         (silc_idcache_list_count(list) + *clients_count) * 
+  *clients = silc_realloc(*clients,
+                         (silc_idcache_list_count(list) + *clients_count) *
                          sizeof(**clients));
 
   silc_idcache_list_first(list, &id_cache);
@@ -461,9 +465,9 @@ int silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname,
 
   while (silc_idcache_list_next(list, &id_cache))
     (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
-  
+
   silc_idcache_list_free(list);
-  
+
   SILC_LOG_DEBUG(("Found total %d clients", *clients_count));
 
   return TRUE;
@@ -481,15 +485,15 @@ silc_idlist_find_client_by_id(SilcIDList id_list, SilcClientID *id,
   if (!id)
     return NULL;
 
-  SILC_LOG_DEBUG(("Client ID (%s)", 
+  SILC_LOG_DEBUG(("Client ID (%s)",
                  silc_id_render(id, SILC_ID_CLIENT)));
 
   /* Do extended search since the normal ID comparison function for
      Client ID's compares only the hash from the Client ID and not the
      entire ID. The silc_hash_client_id_compare compares the entire
      Client ID as we want to find one specific Client ID. */
-  if (!silc_idcache_find_by_id_one_ext(id_list->clients, (void *)id, 
-                                      NULL, NULL, 
+  if (!silc_idcache_find_by_id_one_ext(id_list->clients, (void *)id,
+                                      NULL, NULL,
                                       silc_hash_client_id_compare, NULL,
                                       &id_cache))
     return NULL;
@@ -527,8 +531,8 @@ silc_idlist_replace_client_id(SilcServer server,
      Client ID's compares only the hash from the Client ID and not the
      entire ID. The silc_hash_client_id_compare compares the entire
      Client ID as we want to find one specific Client ID. */
-  if (!silc_idcache_find_by_id_one_ext(id_list->clients, (void *)old_id, 
-                                      NULL, NULL, 
+  if (!silc_idcache_find_by_id_one_ext(id_list->clients, (void *)old_id,
+                                      NULL, NULL,
                                       silc_hash_client_id_compare, NULL,
                                       &id_cache))
     return NULL;
@@ -555,7 +559,7 @@ silc_idlist_replace_client_id(SilcServer server,
     silc_server_check_watcher_list(server, client, nickname,
                                   SILC_NOTIFY_TYPE_NICK_CHANGE);
 
-  if (!silc_idcache_add(id_list->clients, client->nickname, client->id, 
+  if (!silc_idcache_add(id_list->clients, client->nickname, client->id,
                        client, 0, NULL))
     return NULL;
 
@@ -622,7 +626,7 @@ silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode,
   channel->user_list = silc_hash_table_alloc(3, silc_hash_ptr, NULL, NULL,
                                             NULL, NULL, NULL, TRUE);
 
-  if (!silc_idcache_add(id_list->channels, channel->channel_name, 
+  if (!silc_idcache_add(id_list->channels, channel->channel_name,
                        (void *)channel->id, (void *)channel, expire, NULL)) {
     silc_hmac_free(channel->hmac);
     silc_hash_table_free(channel->user_list);
@@ -657,13 +661,15 @@ int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
 {
   if (entry) {
     /* Remove from cache */
-    if (!silc_idcache_del_by_context(id_list->channels, entry))
+    if (!silc_idcache_del_by_context(id_list->channels, entry)) {
+      SILC_LOG_DEBUG(("Unknown channel, did not delete"));
       return FALSE;
+    }
 
     SILC_LOG_DEBUG(("Deleting channel %s", entry->channel_name));
 
     /* Free all client entrys from the users list. The silc_hash_table_free
-       will free all the entries so they are not freed at the foreach 
+       will free all the entries so they are not freed at the foreach
        callback. */
     silc_hash_table_foreach(entry->user_list, silc_idlist_del_channel_foreach,
                            NULL);
@@ -692,6 +698,8 @@ int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
     silc_free(entry->rekey);
     if (entry->founder_key)
       silc_pkcs_public_key_free(entry->founder_key);
+    if (entry->channel_pubkeys)
+      silc_hash_table_free(entry->channel_pubkeys);
 
     memset(entry, 'F', sizeof(*entry));
     silc_free(entry);
@@ -772,7 +780,7 @@ silc_idlist_replace_channel_id(SilcIDList id_list, SilcChannelID *old_id,
 
   SILC_LOG_DEBUG(("Replacing Channel ID"));
 
-  if (!silc_idcache_find_by_id_one(id_list->channels, (void *)old_id, 
+  if (!silc_idcache_find_by_id_one(id_list->channels, (void *)old_id,
                                   &id_cache))
     return NULL;
 
@@ -785,7 +793,7 @@ silc_idlist_replace_channel_id(SilcIDList id_list, SilcChannelID *old_id,
   silc_free(channel->id);
   channel->id = new_id;
 
-  silc_idcache_add(id_list->channels, channel->channel_name, channel->id, 
+  silc_idcache_add(id_list->channels, channel->channel_name, channel->id,
                   channel, 0, NULL);
 
   SILC_LOG_DEBUG(("Replaced"));
@@ -815,14 +823,14 @@ silc_idlist_get_channels(SilcIDList id_list, SilcChannelID *channel_id,
       return NULL;
 
     channels = silc_calloc(silc_idcache_list_count(list), sizeof(*channels));
-    
+
     i = 0;
     silc_idcache_list_first(list, &id_cache);
     channels[i++] = (SilcChannelEntry)id_cache->context;
-    
+
     while (silc_idcache_list_next(list, &id_cache))
       channels[i++] = (SilcChannelEntry)id_cache->context;
-    
+
     silc_idcache_list_free(list);
   } else {
     if (!silc_idcache_find_by_id_one(id_list->channels, channel_id, &id_cache))
index ac67e10ad5a06cc950476c76f706d1d185828a78..cfb46feaddf2847f56cea06e3aba6296646dfbd1 100644 (file)
@@ -4,13 +4,13 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2002 Pekka Riikonen
+  Copyright (C) 1997 - 2003 Pekka Riikonen
 
   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
@@ -111,12 +111,12 @@ typedef struct {
   SilcIDListStatus status;     /* Status mask of the entry */
 } *SilcIDListData, SilcIDListDataStruct;
 
-/* 
+/*
    SILC Server entry object.
 
-   This entry holds information about servers in SILC network. However, 
-   contents of this entry is highly dependent of what kind of server we are 
-   (normal server or router server) and whether the entry is used as a local 
+   This entry holds information about servers in SILC network. However,
+   contents of this entry is highly dependent of what kind of server we are
+   (normal server or router server) and whether the entry is used as a local
    list or a global list. These factors dictates the contents of this entry.
 
    This entry is defined as follows:
@@ -158,8 +158,8 @@ typedef struct {
 
    SilcServerEntry router
 
-       This is a pointer back to the server list. This is the router server 
-       where this server is connected to. If this is the router itself and 
+       This is a pointer back to the server list. This is the router server
+       where this server is connected to. If this is the router itself and
        it doesn't have a route this is NULL.
 
    SilcCipher send_key
@@ -173,7 +173,7 @@ typedef struct {
        the data used in connection with this server.  This may be anything
        but as just said, this is usually pointer to the socket connection
        list.
-   
+
 */
 struct SilcServerEntryStruct {
   /* Generic data structure. DO NOT add anything before this! */
@@ -192,7 +192,7 @@ struct SilcServerEntryStruct {
   void *connection;
 };
 
-/* 
+/*
    SILC Channel Client entry structure.
 
    This entry used only by the SilcChannelEntry object and it holds
@@ -220,11 +220,11 @@ typedef struct SilcChannelClientEntryStruct {
   SilcChannelEntry channel;
 } *SilcChannelClientEntry;
 
-/* 
+/*
    SILC Client entry object.
 
    This entry holds information about connected clients ie. users in the SILC
-   network. The contents of this entrt is depended on whether we are normal 
+   network. The contents of this entrt is depended on whether we are normal
    server or router server and whether the list is a local or global list.
 
    This entry is defined as follows:
@@ -260,7 +260,7 @@ typedef struct SilcChannelClientEntryStruct {
        router        local list     NULL
        router        global list    NULL
 
-       Router doesn't hold this information since it is not vital data 
+       Router doesn't hold this information since it is not vital data
        for the router. If this information is needed by the client it is
        fetched when it is needed.
 
@@ -268,14 +268,14 @@ typedef struct SilcChannelClientEntryStruct {
 
        Information about user. This is free information and can be virtually
        anything. This is defined in following manner:
-       
+
        Server type   List type      Contents
        ====================================================
        server        local list     User's information
        router        local list     NULL
        router        global list    NULL
 
-       Router doesn't hold this information since it is not vital data 
+       Router doesn't hold this information since it is not vital data
        for the router. If this information is needed by the client it is
        fetched when it is needed.
 
@@ -283,9 +283,9 @@ typedef struct SilcChannelClientEntryStruct {
 
        ID of the client. This includes all the information SILC will ever
        need. Notice that no nickname of the user is saved anywhere. This is
-       beacuse of SilcClientID includes 88 bit hash value of the user's 
-       nickname which can be used to track down specific user by their 
-       nickname. Nickname is not relevant information that would need to be 
+       beacuse of SilcClientID includes 88 bit hash value of the user's
+       nickname which can be used to track down specific user by their
+       nickname. Nickname is not relevant information that would need to be
        saved as plain.
 
    SilcUInt32 mode
@@ -307,8 +307,8 @@ typedef struct SilcChannelClientEntryStruct {
 
    SilcServerEntry router
 
-       This is a pointer to the server list. This is the router server whose 
-       cell this client is coming from. This is used to route messages to 
+       This is a pointer to the server list. This is the router server whose
+       cell this client is coming from. This is used to route messages to
        this client.
 
    SilcHashTable channels;
@@ -363,16 +363,16 @@ struct SilcClientEntryStruct {
   /* Last time updated/accessed */
   unsigned long updated;
 
-  /* data.status is RESOLVING and this includes the resolving command 
+  /* data.status is RESOLVING and this includes the resolving command
      reply identifier. */
   SilcUInt16 resolve_cmd_ident;
 };
 
-/* 
+/*
    SILC Channel entry object.
 
-   This entry holds information about channels in SILC network. The contents 
-   of this entry is depended on whether we are normal server or router server 
+   This entry holds information about channels in SILC network. The contents
+   of this entry is depended on whether we are normal server or router server
    and whether the list is a local or global list.
 
    This entry is defined as follows:
@@ -401,12 +401,12 @@ struct SilcClientEntryStruct {
        need.
 
    bool global_users
+
        Boolean value to tell whether there are users outside this server
        on this channel. This is set to TRUE if router sends message to
        the server that there are users outside your server on your
        channel as well. This way server knows that messages needs to be
-       sent to the router for further routing. If this is a normal 
+       sent to the router for further routing. If this is a normal
        server and this channel is not created on this server this field
        is always TRUE. If this server is a router this field is ignored.
 
@@ -438,8 +438,8 @@ struct SilcClientEntryStruct {
 
    SilcServerEntry router
 
-       This is a pointer to the server list. This is the router server 
-       whose cell this channel belongs to. This is used to route messages 
+       This is a pointer to the server list. This is the router server
+       whose cell this channel belongs to. This is used to route messages
        to this channel.
 
    SilcCipher channel_key
@@ -473,6 +473,7 @@ struct SilcChannelEntryStruct {
   char *cipher;
   char *hmac_name;
   SilcPublicKey founder_key;
+  SilcHashTable channel_pubkeys;
 
   SilcUInt32 user_limit;
   unsigned char *passphrase;
@@ -502,7 +503,7 @@ struct SilcChannelEntryStruct {
   unsigned int users_resolved : 1;
 };
 
-/* 
+/*
    SILC ID List object.
 
    As for remainder these lists are defined as follows:
@@ -547,7 +548,7 @@ typedef struct SilcIDListStruct {
 /*
    ID Entry for Unknown connections.
 
-   This is used during authentication phases where we still don't know 
+   This is used during authentication phases where we still don't know
    what kind of connection remote connection is, hence, we will use this
    structure instead until we know what type of connection remote end is.
 
@@ -564,8 +565,8 @@ typedef struct {
 void silc_idlist_add_data(void *entry, SilcIDListData idata);
 void silc_idlist_del_data(void *entry);
 SILC_TASK_CALLBACK_GLOBAL(silc_idlist_purge);
-SilcServerEntry 
-silc_idlist_add_server(SilcIDList id_list, 
+SilcServerEntry
+silc_idlist_add_server(SilcIDList id_list,
                       char *server_name, int server_type,
                       SilcServerID *id, SilcServerEntry router,
                       void *connection);
@@ -584,13 +585,13 @@ silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id,
                              SilcServerID *new_id);
 int silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry);
 SilcClientEntry
-silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username, 
-                      char *userinfo, SilcClientID *id, 
+silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username,
+                      char *userinfo, SilcClientID *id,
                       SilcServerEntry router, void *connection,
                       int expire);
 int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry);
 int silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname,
-                                       char *server, 
+                                       char *server,
                                        SilcClientEntry **clients,
                                        SilcUInt32 *clients_count);
 int silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname,
index ee45290f0b1b779625c1142f201f2f8bc126f9e7..b9a0224f052f99174af426457632390cdc458960 100644 (file)
@@ -4,13 +4,13 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2002 Pekka Riikonen
+  Copyright (C) 1997 - 2003 Pekka Riikonen
 
   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
@@ -25,7 +25,7 @@
 #include "serverincludes.h"
 #include "server_internal.h"
 
-/* Received notify packet. Server can receive notify packets from router. 
+/* Received notify packet. Server can receive notify packets from router.
    Server then relays the notify messages to clients if needed. */
 
 void silc_server_notify(SilcServer server,
@@ -64,7 +64,7 @@ void silc_server_notify(SilcServer server,
 
     /* Get the route to the client */
     dst_sock = silc_server_get_client_route(server, packet->dst_id,
-                                           packet->dst_id_len, NULL, 
+                                           packet->dst_id_len, NULL,
                                            &idata, NULL);
     if (dst_sock)
       /* Relay the packet */
@@ -94,27 +94,27 @@ void silc_server_notify(SilcServer server,
       if (!channel_id)
        goto out;
 
-      silc_server_packet_send_dest(server, SILC_PRIMARY_ROUTE(server), 
-                                  packet->type, packet->flags | 
-                                  SILC_PACKET_FLAG_BROADCAST, 
+      silc_server_packet_send_dest(server, SILC_PRIMARY_ROUTE(server),
+                                  packet->type, packet->flags |
+                                  SILC_PACKET_FLAG_BROADCAST,
                                   channel_id, SILC_ID_CHANNEL,
-                                  packet->buffer->data, 
+                                  packet->buffer->data,
                                   packet->buffer->len, FALSE);
-      silc_server_backup_send_dest(server, sock->user_data, 
+      silc_server_backup_send_dest(server, sock->user_data,
                                   packet->type, packet->flags,
                                   channel_id, SILC_ID_CHANNEL,
-                                  packet->buffer->data, packet->buffer->len, 
+                                  packet->buffer->data, packet->buffer->len,
                                   FALSE, TRUE);
     } else {
       /* Packet is destined to client or server */
-      silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server), 
+      silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
                              packet->type,
-                             packet->flags | SILC_PACKET_FLAG_BROADCAST, 
-                             packet->buffer->data, packet->buffer->len, 
+                             packet->flags | SILC_PACKET_FLAG_BROADCAST,
+                             packet->buffer->data, packet->buffer->len,
                              FALSE);
       silc_server_backup_send(server, sock->user_data,
                              packet->type, packet->flags,
-                             packet->buffer->data, packet->buffer->len, 
+                             packet->buffer->data, packet->buffer->len,
                              FALSE, TRUE);
     }
   }
@@ -126,7 +126,7 @@ void silc_server_notify(SilcServer server,
 
   switch(type) {
   case SILC_NOTIFY_TYPE_JOIN:
-    /* 
+    /*
      * Distribute the notify to local clients on the channel
      */
     SILC_LOG_DEBUG(("JOIN notify"));
@@ -143,10 +143,10 @@ void silc_server_notify(SilcServer server,
       goto out;
 
     /* Get channel entry */
-    channel = silc_idlist_find_channel_by_id(server->global_list, 
+    channel = silc_idlist_find_channel_by_id(server->global_list,
                                             channel_id, NULL);
     if (!channel) {
-      channel = silc_idlist_find_channel_by_id(server->local_list, 
+      channel = silc_idlist_find_channel_by_id(server->local_list,
                                               channel_id, NULL);
       if (!channel) {
        SILC_LOG_DEBUG(("Notify for unknown channel"));
@@ -167,11 +167,11 @@ void silc_server_notify(SilcServer server,
     /* If the the client is not in local list we check global list (ie. the
        channel will be global channel) and if it does not exist then create
        entry for the client. */
-    client = silc_idlist_find_client_by_id(server->global_list, 
-                                          client_id, server->server_type, 
+    client = silc_idlist_find_client_by_id(server->global_list,
+                                          client_id, server->server_type,
                                           &cache);
     if (!client) {
-      client = silc_idlist_find_client_by_id(server->local_list, 
+      client = silc_idlist_find_client_by_id(server->local_list,
                                             client_id, server->server_type,
                                             &cache);
       if (!client) {
@@ -181,9 +181,9 @@ void silc_server_notify(SilcServer server,
          goto out;
        }
 
-       client = 
+       client =
          silc_idlist_add_client(server->global_list, NULL, NULL, NULL,
-                                silc_id_dup(client_id, SILC_ID_CLIENT), 
+                                silc_id_dup(client_id, SILC_ID_CLIENT),
                                 sock->user_data, NULL, 0);
        if (!client) {
          SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
@@ -208,18 +208,18 @@ void silc_server_notify(SilcServer server,
     }
 
     /* Send to channel */
-    silc_server_packet_send_to_channel(server, sock, channel, packet->type, 
-                                      FALSE, packet->buffer->data, 
+    silc_server_packet_send_to_channel(server, sock, channel, packet->type,
+                                      FALSE, TRUE, packet->buffer->data,
                                       packet->buffer->len, FALSE);
 
-    if (server->server_type != SILC_ROUTER && 
+    if (server->server_type != SILC_ROUTER &&
        sock->type == SILC_SOCKET_TYPE_ROUTER)
       /* The channel is global now */
       channel->global_users = TRUE;
 
     SILC_LOG_DEBUG(("Joining to channel %s", channel->channel_name));
 
-    /* JOIN the global client to the channel (local clients (if router 
+    /* JOIN the global client to the channel (local clients (if router
        created the channel) is joined in the pending JOIN command). */
     chl = silc_calloc(1, sizeof(*chl));
     chl->client = client;
@@ -256,7 +256,7 @@ void silc_server_notify(SilcServer server,
     break;
 
   case SILC_NOTIFY_TYPE_LEAVE:
-    /* 
+    /*
      * Distribute the notify to local clients on the channel
      */
     SILC_LOG_DEBUG(("LEAVE notify"));
@@ -269,10 +269,10 @@ void silc_server_notify(SilcServer server,
     }
 
     /* Get channel entry */
-    channel = silc_idlist_find_channel_by_id(server->global_list, 
+    channel = silc_idlist_find_channel_by_id(server->global_list,
                                             channel_id, NULL);
-    if (!channel) { 
-      channel = silc_idlist_find_channel_by_id(server->local_list, 
+    if (!channel) {
+      channel = silc_idlist_find_channel_by_id(server->local_list,
                                               channel_id, NULL);
       if (!channel) {
        SILC_LOG_DEBUG(("Notify for unknown channel"));
@@ -294,10 +294,10 @@ void silc_server_notify(SilcServer server,
     }
 
     /* Get client entry */
-    client = silc_idlist_find_client_by_id(server->global_list, 
+    client = silc_idlist_find_client_by_id(server->global_list,
                                           client_id, TRUE, NULL);
     if (!client) {
-      client = silc_idlist_find_client_by_id(server->local_list, 
+      client = silc_idlist_find_client_by_id(server->local_list,
                                             client_id, TRUE, NULL);
       if (!client) {
        silc_free(client_id);
@@ -313,8 +313,8 @@ void silc_server_notify(SilcServer server,
       break;
 
     /* Send the leave notify to channel */
-    silc_server_packet_send_to_channel(server, sock, channel, packet->type, 
-                                      FALSE, packet->buffer->data, 
+    silc_server_packet_send_to_channel(server, sock, channel, packet->type,
+                                      FALSE, TRUE, packet->buffer->data,
                                       packet->buffer->len, FALSE);
 
     /* Remove the user from channel */
@@ -322,7 +322,7 @@ void silc_server_notify(SilcServer server,
     break;
 
   case SILC_NOTIFY_TYPE_SIGNOFF:
-    /* 
+    /*
      * Distribute the notify to local clients on the channel
      */
     SILC_LOG_DEBUG(("SIGNOFF notify"));
@@ -336,10 +336,10 @@ void silc_server_notify(SilcServer server,
       goto out;
 
     /* Get client entry */
-    client = silc_idlist_find_client_by_id(server->global_list, 
+    client = silc_idlist_find_client_by_id(server->global_list,
                                           client_id, TRUE, &cache);
     if (!client) {
-      client = silc_idlist_find_client_by_id(server->local_list, 
+      client = silc_idlist_find_client_by_id(server->local_list,
                                             client_id, TRUE, &cache);
       if (!client) {
        silc_free(client_id);
@@ -378,7 +378,7 @@ void silc_server_notify(SilcServer server,
     break;
 
   case SILC_NOTIFY_TYPE_TOPIC_SET:
-    /* 
+    /*
      * Distribute the notify to local clients on the channel
      */
 
@@ -394,10 +394,10 @@ void silc_server_notify(SilcServer server,
 
     /* Get client entry */
     if (id_type == SILC_ID_CLIENT) {
-      client = silc_idlist_find_client_by_id(server->global_list, 
+      client = silc_idlist_find_client_by_id(server->global_list,
                                             client_id, TRUE, &cache);
       if (!client) {
-       client = silc_idlist_find_client_by_id(server->local_list, 
+       client = silc_idlist_find_client_by_id(server->local_list,
                                               client_id, TRUE, &cache);
        if (!client) {
          silc_free(client_id);
@@ -422,10 +422,10 @@ void silc_server_notify(SilcServer server,
     }
 
     /* Get channel entry */
-    channel = silc_idlist_find_channel_by_id(server->global_list, 
+    channel = silc_idlist_find_channel_by_id(server->global_list,
                                             channel_id, NULL);
     if (!channel) {
-      channel = silc_idlist_find_channel_by_id(server->local_list, 
+      channel = silc_idlist_find_channel_by_id(server->local_list,
                                               channel_id, NULL);
       if (!channel) {
        SILC_LOG_DEBUG(("Notify for unknown channel"));
@@ -457,14 +457,14 @@ void silc_server_notify(SilcServer server,
     channel->topic = strdup(tmp);
 
     /* Send the same notify to the channel */
-    silc_server_packet_send_to_channel(server, NULL, channel, packet->type, 
-                                      FALSE, packet->buffer->data, 
+    silc_server_packet_send_to_channel(server, NULL, channel, packet->type,
+                                      FALSE, TRUE, packet->buffer->data,
                                       packet->buffer->len, FALSE);
     break;
 
   case SILC_NOTIFY_TYPE_NICK_CHANGE:
     {
-      /* 
+      /*
        * Distribute the notify to local clients on the channel
        */
       unsigned char *id, *id2;
@@ -472,7 +472,7 @@ void silc_server_notify(SilcServer server,
       SilcUInt32 nickname_len;
 
       SILC_LOG_DEBUG(("NICK CHANGE notify"));
-      
+
       /* Get old client ID */
       id = silc_argument_get_arg_type(args, 1, &tmp_len);
       if (!id)
@@ -480,7 +480,7 @@ void silc_server_notify(SilcServer server,
       client_id = silc_id_payload_parse_id(id, tmp_len, NULL);
       if (!client_id)
        goto out;
-      
+
       /* Get new client ID */
       id2 = silc_argument_get_arg_type(args, 2, &tmp_len);
       if (!id2)
@@ -490,10 +490,10 @@ void silc_server_notify(SilcServer server,
        silc_free(client_id);
        goto out;
       }
-      
-      SILC_LOG_DEBUG(("Old Client ID id(%s)", 
+
+      SILC_LOG_DEBUG(("Old Client ID id(%s)",
                      silc_id_render(client_id, SILC_ID_CLIENT)));
-      SILC_LOG_DEBUG(("New Client ID id(%s)", 
+      SILC_LOG_DEBUG(("New Client ID id(%s)",
                      silc_id_render(client_id2, SILC_ID_CLIENT)));
 
       /* From protocol version 1.1 we also get the new nickname */
@@ -505,7 +505,7 @@ void silc_server_notify(SilcServer server,
                                             client_id2, nickname);
       if (!client)
        client = silc_idlist_replace_client_id(server,
-                                              server->local_list, client_id, 
+                                              server->local_list, client_id,
                                               client_id2, nickname);
 
       if (client) {
@@ -525,7 +525,7 @@ void silc_server_notify(SilcServer server,
     }
 
   case SILC_NOTIFY_TYPE_CMODE_CHANGE:
-    /* 
+    /*
      * Distribute the notify to local clients on the channel
      */
 
@@ -541,10 +541,10 @@ void silc_server_notify(SilcServer server,
 
     /* Get client entry */
     if (id_type == SILC_ID_CLIENT) {
-      client = silc_idlist_find_client_by_id(server->global_list, 
+      client = silc_idlist_find_client_by_id(server->global_list,
                                             client_id, TRUE, &cache);
       if (!client) {
-       client = silc_idlist_find_client_by_id(server->local_list, 
+       client = silc_idlist_find_client_by_id(server->local_list,
                                               client_id, TRUE, &cache);
        if (!client) {
          silc_free(client_id);
@@ -562,10 +562,10 @@ void silc_server_notify(SilcServer server,
     }
 
     /* Get channel entry */
-    channel = silc_idlist_find_channel_by_id(server->global_list, 
+    channel = silc_idlist_find_channel_by_id(server->global_list,
                                             channel_id, NULL);
     if (!channel) {
-      channel = silc_idlist_find_channel_by_id(server->local_list, 
+      channel = silc_idlist_find_channel_by_id(server->local_list,
                                               channel_id, NULL);
       if (!channel) {
        SILC_LOG_DEBUG(("Notify for unknown channel"));
@@ -596,7 +596,7 @@ void silc_server_notify(SilcServer server,
                                      SILC_ID_SERVER, channel->cipher,
                                      channel->hmac_name,
                                      channel->passphrase,
-                                     channel->founder_key);
+                                     channel->founder_key, NULL);
       }
 
       /* If we received same mode from our primary check whether founder
@@ -617,6 +617,48 @@ void silc_server_notify(SilcServer server,
                                            &channel->founder_key);
       }
 
+      /* Check also for channel public key list */
+      if (server->server_type == SILC_SERVER &&
+         sock == SILC_PRIMARY_ROUTE(server) &&
+         mode & SILC_CHANNEL_MODE_CHANNEL_AUTH) {
+       SilcBuffer chpklist;
+       SilcBuffer sidp;
+       unsigned char mask[4];
+
+       SILC_LOG_DEBUG(("Channel public key list received from router"));
+       tmp = silc_argument_get_arg_type(args, 7, &tmp_len);
+       if (!tmp)
+         break;
+
+       /* Set the router's list, and send the notify to channel too so that
+          channel gets the list */
+       silc_server_set_channel_pk_list(server, sock, channel, tmp, tmp_len);
+       chpklist = silc_server_get_channel_pk_list(server, channel,
+                                                  FALSE, FALSE);
+       if (!chpklist)
+         break;
+       sidp = silc_id_payload_encode(server->router->id, SILC_ID_SERVER);
+       SILC_PUT32_MSB(channel->mode, mask);
+       silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
+                                          SILC_NOTIFY_TYPE_CMODE_CHANGE, 7,
+                                          sidp->data, sidp->len,
+                                          mask, 4,
+                                          channel->cipher,
+                                          channel->cipher ?
+                                          strlen(channel->cipher) : 0,
+                                          channel->hmac_name,
+                                          channel->hmac_name ?
+                                          strlen(channel->hmac_name) : 0,
+                                          channel->passphrase,
+                                          channel->passphrase ?
+                                          strlen(channel->passphrase) : 0,
+                                          NULL, 0,
+                                          chpklist->data, chpklist->len);
+       silc_buffer_free(sidp);
+       silc_buffer_free(chpklist);
+       goto out;
+      }
+
       break;
     }
 
@@ -631,7 +673,7 @@ void silc_server_notify(SilcServer server,
                                      SILC_ID_SERVER, channel->cipher,
                                      channel->hmac_name,
                                      channel->passphrase,
-                                     channel->founder_key);
+                                     channel->founder_key, NULL);
        goto out;
       }
     } else {
@@ -646,7 +688,7 @@ void silc_server_notify(SilcServer server,
                                      SILC_ID_SERVER, channel->cipher,
                                      channel->hmac_name,
                                      channel->passphrase,
-                                     channel->founder_key);
+                                     channel->founder_key, NULL);
        goto out;
       }
 
@@ -665,7 +707,7 @@ void silc_server_notify(SilcServer server,
                                          SILC_ID_SERVER, channel->cipher,
                                          channel->hmac_name,
                                          channel->passphrase,
-                                         channel->founder_key);
+                                         channel->founder_key, NULL);
            silc_hash_table_list_reset(&htl);
            goto out;
          }
@@ -680,11 +722,11 @@ void silc_server_notify(SilcServer server,
       /* Re-generate channel key */
       if (!silc_server_create_channel_key(server, channel, 0))
        goto out;
-      
+
       /* Send the channel key. This sends it to our local clients and if
         we are normal server to our router as well. */
-      silc_server_send_channel_key(server, NULL, channel, 
-                                  server->server_type == SILC_ROUTER ? 
+      silc_server_send_channel_key(server, NULL, channel,
+                                  server->server_type == SILC_ROUTER ?
                                   FALSE : !server->standalone);
     }
 
@@ -700,9 +742,9 @@ void silc_server_notify(SilcServer server,
 
       /* Set the HMAC key out of current channel key. The client must do
         this locally. */
-      silc_hash_make(silc_hmac_get_hash(channel->hmac), channel->key, 
+      silc_hash_make(silc_hmac_get_hash(channel->hmac), channel->key,
                     channel->key_len / 8, hash);
-      silc_hmac_set_key(channel->hmac, hash, 
+      silc_hmac_set_key(channel->hmac, hash,
                        silc_hash_len(silc_hmac_get_hash(channel->hmac)));
       memset(hash, 0, sizeof(hash));
     }
@@ -720,30 +762,18 @@ void silc_server_notify(SilcServer server,
       if (channel->founder_key)
        silc_pkcs_public_key_free(channel->founder_key);
       channel->founder_key = NULL;
-      silc_pkcs_public_key_payload_decode(tmp, tmp_len, &channel->founder_key);
-
-      if (!channel->founder_key || 
-         (client && client->data.public_key && 
-          server->server_type == SILC_ROUTER &&
-          !silc_pkcs_public_key_compare(channel->founder_key,
-                                        client->data.public_key))) {
-       /* A really buggy server isn't checking public keys correctly.
-          It's not possible that the mode setter and founder wouldn't
-          have same public key. */
+      if (!silc_pkcs_public_key_payload_decode(tmp, tmp_len,
+                                              &channel->founder_key)) {
        SILC_LOG_DEBUG(("Enforcing sender to change channel mode"));
-
        mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
        silc_server_send_notify_cmode(server, sock, FALSE, channel,
                                      mode, server->id, SILC_ID_SERVER,
-                                     channel->cipher, 
+                                     channel->cipher,
                                      channel->hmac_name,
-                                     channel->passphrase, NULL);
+                                     channel->passphrase, NULL, NULL);
        if (channel->founder_key)
          silc_pkcs_public_key_free(channel->founder_key);
        channel->founder_key = NULL;
-      } else if (client && !client->data.public_key) {
-       client->data.public_key = 
-         silc_pkcs_public_key_copy(channel->founder_key);
       }
     }
 
@@ -753,30 +783,58 @@ void silc_server_notify(SilcServer server,
       mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
       silc_server_send_notify_cmode(server, sock, FALSE, channel,
                                    mode, server->id, SILC_ID_SERVER,
-                                   channel->cipher, 
+                                   channel->cipher,
                                    channel->hmac_name,
-                                   channel->passphrase, NULL);
+                                   channel->passphrase, NULL, NULL);
+    }
+
+    /* Process channel public key(s). */
+    tmp = silc_argument_get_arg_type(args, 7, &tmp_len);
+    if (tmp && mode & SILC_CHANNEL_MODE_CHANNEL_AUTH) {
+      SilcStatus ret =
+       silc_server_set_channel_pk_list(server, sock, channel, tmp, tmp_len);
+
+      /* If list was set already we will enforce the same list to server. */
+      if (ret == SILC_STATUS_ERR_OPERATION_ALLOWED) {
+       SilcBuffer chpklist = silc_server_get_channel_pk_list(server, channel,
+                                                             TRUE, FALSE);
+       silc_server_send_notify_cmode(server, sock, FALSE, channel,
+                                     mode, server->id, SILC_ID_SERVER,
+                                     channel->cipher,
+                                     channel->hmac_name,
+                                     channel->passphrase, NULL,
+                                     chpklist);
+       silc_buffer_free(chpklist);
+      }
     }
 
     /* Send the same notify to the channel */
-    silc_server_packet_send_to_channel(server, NULL, channel, packet->type, 
-                                      FALSE, packet->buffer->data, 
+    silc_server_packet_send_to_channel(server, NULL, channel, packet->type,
+                                      FALSE, TRUE, packet->buffer->data,
                                       packet->buffer->len, FALSE);
 
     /* Change mode */
     channel->mode = mode;
 
+    /* Cleanup if some modes are removed */
+
     if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) &&
        channel->founder_key) {
       silc_pkcs_public_key_free(channel->founder_key);
       channel->founder_key = NULL;
     }
 
+    if (!(channel->mode & SILC_CHANNEL_MODE_CHANNEL_AUTH) &&
+       channel->channel_pubkeys) {
+      silc_hash_table_free(channel->channel_pubkeys);
+      channel->channel_pubkeys = NULL;
+    }
+
     break;
 
   case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
     {
-      /* 
+      /*
        * Distribute the notify to local clients on the channel
        */
       SilcChannelClientEntry chl2 = NULL;
@@ -794,10 +852,10 @@ void silc_server_notify(SilcServer server,
 
       /* Get client entry */
       if (id_type == SILC_ID_CLIENT) {
-       client = silc_idlist_find_client_by_id(server->global_list, 
+       client = silc_idlist_find_client_by_id(server->global_list,
                                               client_id, TRUE, &cache);
        if (!client) {
-         client = silc_idlist_find_client_by_id(server->local_list, 
+         client = silc_idlist_find_client_by_id(server->local_list,
                                                 client_id, TRUE, &cache);
          if (!client) {
            silc_free(client_id);
@@ -815,10 +873,10 @@ void silc_server_notify(SilcServer server,
       }
 
       /* Get channel entry */
-      channel = silc_idlist_find_channel_by_id(server->global_list, 
+      channel = silc_idlist_find_channel_by_id(server->global_list,
                                               channel_id, NULL);
       if (!channel) {
-       channel = silc_idlist_find_channel_by_id(server->local_list, 
+       channel = silc_idlist_find_channel_by_id(server->local_list,
                                                 channel_id, NULL);
        if (!channel) {
          SILC_LOG_DEBUG(("Notify for unknown channel"));
@@ -833,9 +891,9 @@ void silc_server_notify(SilcServer server,
        silc_free(channel_id);
        goto out;
       }
-      
+
       SILC_GET32_MSB(mode, tmp);
-      
+
       /* Get target client */
       tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
       if (!tmp)
@@ -843,12 +901,12 @@ void silc_server_notify(SilcServer server,
       client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
       if (!client_id)
        goto out;
-      
+
       /* Get client entry */
-      client2 = silc_idlist_find_client_by_id(server->global_list, 
+      client2 = silc_idlist_find_client_by_id(server->global_list,
                                              client_id, TRUE, NULL);
       if (!client2) {
-       client2 = silc_idlist_find_client_by_id(server->local_list, 
+       client2 = silc_idlist_find_client_by_id(server->local_list,
                                                client_id, TRUE, NULL);
        if (!client2) {
          silc_free(client_id);
@@ -861,7 +919,7 @@ void silc_server_notify(SilcServer server,
        /* Check that sender is on channel */
        if (!silc_server_client_on_channel(client, channel, &chl))
          goto out;
-       
+
        if (client != client2 && server->server_type == SILC_ROUTER) {
          /* Sender must be operator */
          if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
@@ -890,6 +948,11 @@ void silc_server_notify(SilcServer server,
        break;
       }
 
+      /* Check whether to give founder rights to this user or not.  The
+        problem here is that we get only the public key of the client,
+        but no authentication data.  We must assume that server has
+        already authenticated the user (and thus we must trust the
+        server). */
       if (mode & SILC_CHANNEL_UMODE_CHANFO &&
          !(chl->mode & SILC_CHANNEL_UMODE_CHANFO) &&
          server->server_type == SILC_ROUTER &&
@@ -899,7 +962,8 @@ void silc_server_notify(SilcServer server,
        /* If channel doesn't have founder auth mode then it's impossible
           that someone would be getting founder rights with CUMODE command.
           In that case there already either is founder or there isn't
-          founder at all on the channel. */
+          founder at all on the channel (valid only when 'client' is
+          valid). */
        if (client && !(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)) {
          /* Force the mode to not have founder mode */
          chl->mode = mode &= ~SILC_CHANNEL_UMODE_CHANFO;
@@ -911,22 +975,12 @@ void silc_server_notify(SilcServer server,
        /* Get the founder of the channel and if found then this client
           cannot be the founder since there already is one. */
        silc_hash_table_list(channel->user_list, &htl);
-       while (silc_hash_table_get(&htl, NULL, (void *)&chl2))
+       while (silc_hash_table_get(&htl, NULL, (void **)&chl2))
          if (chl2->mode & SILC_CHANNEL_UMODE_CHANFO) {
-           /* If the founder on the channel is not the one whom has set
-              the founder mode, then it's possible that this CUMODE_CHANGE
-              is correct.  Due to netsplits it's possible that this
-              situation happens. */
-           if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) ||
-               (channel->founder_key && chl2->client->data.public_key &&
-                silc_pkcs_public_key_compare(
-                                       channel->founder_key,
-                                       chl2->client->data.public_key))) {
-             chl->mode = mode &= ~SILC_CHANNEL_UMODE_CHANFO;
-             silc_server_force_cumode_change(server, sock, channel,
-                                             chl, mode);
-             notify_sent = TRUE;
-           }
+           chl->mode = mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+           silc_server_force_cumode_change(server, sock, channel,
+                                           chl, mode);
+           notify_sent = TRUE;
            break;
          }
        silc_hash_table_list_reset(&htl);
@@ -950,16 +1004,6 @@ void silc_server_notify(SilcServer server,
 
          /* Now match the public key we have cached and public key sent.
             They must match. */
-#if 0 /* The key may be other than the client's in 1.2 */
-         if (client && client->data.public_key && 
-             !silc_pkcs_public_key_compare(channel->founder_key,
-                                           client->data.public_key)) {
-           chl->mode = mode &= ~SILC_CHANNEL_UMODE_CHANFO;
-           silc_server_force_cumode_change(server, sock, channel, chl, mode);
-           notify_sent = TRUE;
-           break;
-         }
-#endif
          if (!silc_pkcs_public_key_compare(channel->founder_key,
                                            founder_key)) {
            chl->mode = mode &= ~SILC_CHANNEL_UMODE_CHANFO;
@@ -970,7 +1014,8 @@ void silc_server_notify(SilcServer server,
        }
 
        /* There cannot be anyone else as founder on the channel now.  This
-          client is definitely the founder due to this authentication */
+          client is definitely the founder due to this 'authentication'.
+          We trust the server did the actual authentication earlier. */
        silc_hash_table_list(channel->user_list, &htl);
        while (silc_hash_table_get(&htl, NULL, (void *)&chl2))
          if (chl2->mode & SILC_CHANNEL_UMODE_CHANFO) {
@@ -1001,9 +1046,9 @@ void silc_server_notify(SilcServer server,
       if (!notify_sent)
        silc_server_packet_send_to_channel(server, NULL, channel,
                                           packet->type,
-                                          FALSE, packet->buffer->data,
+                                          FALSE, TRUE, packet->buffer->data,
                                           packet->buffer->len, FALSE);
-      
+
       silc_free(channel_id);
       break;
     }
@@ -1024,10 +1069,10 @@ void silc_server_notify(SilcServer server,
       goto out;
 
     /* Get channel entry */
-    channel = silc_idlist_find_channel_by_id(server->global_list, 
+    channel = silc_idlist_find_channel_by_id(server->global_list,
                                             channel_id, NULL);
     if (!channel) {
-      channel = silc_idlist_find_channel_by_id(server->local_list, 
+      channel = silc_idlist_find_channel_by_id(server->local_list,
                                               channel_id, NULL);
       if (!channel) {
        SILC_LOG_DEBUG(("Notify for unknown channel"));
@@ -1037,6 +1082,10 @@ void silc_server_notify(SilcServer server,
     }
     silc_free(channel_id);
 
+#if 0 /* These aren't actually used anywhere or needed, since this
+        notify is for handling the invite list (direct invite
+        goes to client and is not handled here at all). */
+
     /* Get client ID */
     tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
     if (!tmp)
@@ -1046,10 +1095,10 @@ void silc_server_notify(SilcServer server,
       goto out;
 
     /* Get client entry */
-    client = silc_idlist_find_client_by_id(server->global_list, 
+    client = silc_idlist_find_client_by_id(server->global_list,
                                           client_id, TRUE, &cache);
     if (!client) {
-      client = silc_idlist_find_client_by_id(server->local_list, 
+      client = silc_idlist_find_client_by_id(server->local_list,
                                             client_id, TRUE, &cache);
       if (!client) {
        silc_free(client_id);
@@ -1059,14 +1108,17 @@ void silc_server_notify(SilcServer server,
     silc_free(client_id);
 
     /* Get user's channel entry and check that inviting is allowed. */
-    if (!silc_server_client_on_channel(client, channel, &chl))
-      goto out;
-    if (channel->mode & SILC_CHANNEL_MODE_INVITE &&
-       !(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
-       !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
-      SILC_LOG_DEBUG(("Inviting is not allowed"));
-      goto out;
+    if (server->server_type == SILC_ROUTER) {
+      if (!silc_server_client_on_channel(client, channel, &chl))
+        goto out;
+      if (channel->mode & SILC_CHANNEL_MODE_INVITE &&
+         !(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
+         !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
+        SILC_LOG_DEBUG(("Inviting is not allowed"));
+        goto out;
+      }
     }
+#endif
 
     /* Get the invite action */
     tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
@@ -1086,7 +1138,7 @@ void silc_server_notify(SilcServer server,
       if (!iargs)
        goto out;
 
-      if (action == 0 && !channel->invite_list)
+      if (action != 0x01 && !channel->invite_list)
        channel->invite_list =
          silc_hash_table_alloc(0, silc_hash_ptr,
                                NULL, NULL, NULL,
@@ -1096,6 +1148,15 @@ void silc_server_notify(SilcServer server,
       silc_server_inviteban_process(server, channel->invite_list, action,
                                    iargs);
       silc_argument_payload_free(iargs);
+
+      /* If we are router we must send this notify to our local servers on
+         the channel.  Normal server does nothing.  The notify is not
+         sent to clients. */
+      if (server->server_type == SILC_ROUTER)
+       silc_server_packet_send_to_channel(server, sock, channel,
+                                          packet->type, FALSE, FALSE,
+                                          packet->buffer->data,
+                                          packet->buffer->len, FALSE);
     }
 
     break;
@@ -1120,10 +1181,10 @@ void silc_server_notify(SilcServer server,
       goto out;
 
     /* Get the channel entry */
-    channel = silc_idlist_find_channel_by_id(server->local_list, 
+    channel = silc_idlist_find_channel_by_id(server->local_list,
                                             channel_id, NULL);
     if (!channel) {
-      channel = silc_idlist_find_channel_by_id(server->global_list, 
+      channel = silc_idlist_find_channel_by_id(server->global_list,
                                               channel_id, NULL);
       if (!channel) {
        SILC_LOG_DEBUG(("Notify for unknown channel"));
@@ -1133,8 +1194,8 @@ void silc_server_notify(SilcServer server,
     }
 
     /* Send the notify to the channel */
-    silc_server_packet_send_to_channel(server, sock, channel, packet->type, 
-                                      FALSE, packet->buffer->data, 
+    silc_server_packet_send_to_channel(server, sock, channel, packet->type,
+                                      FALSE, TRUE, packet->buffer->data,
                                       packet->buffer->len, FALSE);
 
     /* Get the new Channel ID */
@@ -1145,9 +1206,9 @@ void silc_server_notify(SilcServer server,
     if (!channel_id2)
       goto out;
 
-    SILC_LOG_DEBUG(("Old Channel ID id(%s)", 
+    SILC_LOG_DEBUG(("Old Channel ID id(%s)",
                    silc_id_render(channel_id, SILC_ID_CHANNEL)));
-    SILC_LOG_DEBUG(("New Channel ID id(%s)", 
+    SILC_LOG_DEBUG(("New Channel ID id(%s)",
                    silc_id_render(channel_id2, SILC_ID_CHANNEL)));
 
     /* Replace the Channel ID */
@@ -1164,8 +1225,8 @@ void silc_server_notify(SilcServer server,
 
       /* Re-announce this channel which ID was changed. */
       silc_server_send_new_channel(server, sock, FALSE, channel->channel_name,
-                                  channel->id, 
-                                  silc_id_get_len(channel->id, 
+                                  channel->id,
+                                  silc_id_get_len(channel->id,
                                                   SILC_ID_CHANNEL),
                                   channel->mode);
 
@@ -1192,7 +1253,7 @@ void silc_server_notify(SilcServer server,
        silc_server_packet_send_dest(server, sock,
                                     SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
                                     channel->id, SILC_ID_CHANNEL,
-                                    users_modes->data, 
+                                    users_modes->data,
                                     users_modes->len, FALSE);
        silc_buffer_free(users_modes);
       }
@@ -1201,7 +1262,7 @@ void silc_server_notify(SilcServer server,
       if (channel->topic) {
        silc_server_send_notify_topic_set(server, sock,
                                          server->server_type == SILC_ROUTER ?
-                                         TRUE : FALSE, channel, 
+                                         TRUE : FALSE, channel,
                                          server->id, SILC_ID_SERVER,
                                          channel->topic);
       }
@@ -1212,12 +1273,18 @@ void silc_server_notify(SilcServer server,
     break;
 
   case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
-    /* 
+    /*
      * Remove the server entry and all clients that this server owns.
      */
 
     SILC_LOG_DEBUG(("SERVER SIGNOFF notify"));
 
+    /* Backup router shouldn't accept SERVER_SIGNOFF's from normal routers
+       when the backup isn't acting as primary router. */
+    if (sock->type == SILC_SOCKET_TYPE_SERVER &&
+       server->backup_router && server->server_type == SILC_BACKUP_ROUTER)
+      return;
+
     /* Get Server ID */
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
@@ -1233,11 +1300,11 @@ void silc_server_notify(SilcServer server,
     }
 
     /* Get server entry */
-    server_entry = silc_idlist_find_server_by_id(server->global_list, 
+    server_entry = silc_idlist_find_server_by_id(server->global_list,
                                                 server_id, TRUE, NULL);
     local = FALSE;
     if (!server_entry) {
-      server_entry = silc_idlist_find_server_by_id(server->local_list, 
+      server_entry = silc_idlist_find_server_by_id(server->local_list,
                                                   server_id, TRUE, NULL);
       local = TRUE;
       if (!server_entry) {
@@ -1259,13 +1326,13 @@ void silc_server_notify(SilcServer server,
              continue;
 
            /* Get client entry */
-           client = silc_idlist_find_client_by_id(server->global_list, 
+           client = silc_idlist_find_client_by_id(server->global_list,
                                                   client_id, TRUE, &cache);
-           local = TRUE;
+           local = FALSE;
            if (!client) {
-             client = silc_idlist_find_client_by_id(server->local_list, 
+             client = silc_idlist_find_client_by_id(server->local_list,
                                                     client_id, TRUE, &cache);
-             local = FALSE;
+             local = TRUE;
              if (!client) {
                silc_free(client_id);
                continue;
@@ -1281,7 +1348,7 @@ void silc_server_notify(SilcServer server,
            SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
 
            /* Remove the client from all channels. */
-           silc_server_remove_from_channels(server, NULL, client, 
+           silc_server_remove_from_channels(server, NULL, client,
                                             TRUE, NULL, FALSE, FALSE);
 
            /* Check if anyone is watching this nickname */
@@ -1314,9 +1381,9 @@ void silc_server_notify(SilcServer server,
        sock = server_entry->connection;
        SILC_LOG_DEBUG(("Closing connection %s after SERVER_SIGNOFF",
                       sock->hostname));
-       SILC_SET_DISCONNECTING(sock);
        if (sock->user_data)
          silc_server_free_sock_user_data(server, sock, NULL);
+       SILC_SET_DISCONNECTING(sock);
        silc_server_close_connection(server, sock);
       }
 
@@ -1344,12 +1411,12 @@ void silc_server_notify(SilcServer server,
     break;
 
   case SILC_NOTIFY_TYPE_KICKED:
-    /* 
+    /*
      * Distribute the notify to local clients on the channel
      */
-    
+
     SILC_LOG_DEBUG(("KICKED notify"));
-      
+
     if (!channel_id) {
       channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
                                  packet->dst_id_type);
@@ -1358,10 +1425,10 @@ void silc_server_notify(SilcServer server,
     }
 
     /* Get channel entry */
-    channel = silc_idlist_find_channel_by_id(server->global_list, 
+    channel = silc_idlist_find_channel_by_id(server->global_list,
                                             channel_id, NULL);
     if (!channel) {
-      channel = silc_idlist_find_channel_by_id(server->local_list, 
+      channel = silc_idlist_find_channel_by_id(server->local_list,
                                               channel_id, NULL);
       if (!channel) {
        SILC_LOG_DEBUG(("Notify for unknown channel"));
@@ -1380,10 +1447,10 @@ void silc_server_notify(SilcServer server,
       goto out;
 
     /* If the the client is not in local list we check global list */
-    client = silc_idlist_find_client_by_id(server->global_list, 
+    client = silc_idlist_find_client_by_id(server->global_list,
                                           client_id, TRUE, NULL);
     if (!client) {
-      client = silc_idlist_find_client_by_id(server->local_list, 
+      client = silc_idlist_find_client_by_id(server->local_list,
                                             client_id, TRUE, NULL);
       if (!client) {
        silc_free(client_id);
@@ -1397,7 +1464,7 @@ void silc_server_notify(SilcServer server,
       goto out;
     if (chl->mode & SILC_CHANNEL_UMODE_CHANFO)
       goto out;
-    
+
     /* Get the kicker's Client ID */
     tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
     if (!tmp)
@@ -1407,10 +1474,10 @@ void silc_server_notify(SilcServer server,
       goto out;
 
     /* If the the client is not in local list we check global list */
-    client2 = silc_idlist_find_client_by_id(server->global_list, 
+    client2 = silc_idlist_find_client_by_id(server->global_list,
                                            client_id, TRUE, NULL);
     if (!client2) {
-      client2 = silc_idlist_find_client_by_id(server->local_list, 
+      client2 = silc_idlist_find_client_by_id(server->local_list,
                                              client_id, TRUE, NULL);
       if (!client2) {
        silc_free(client_id);
@@ -1429,8 +1496,8 @@ void silc_server_notify(SilcServer server,
     }
 
     /* Send to channel */
-    silc_server_packet_send_to_channel(server, sock, channel, packet->type, 
-                                      FALSE, packet->buffer->data, 
+    silc_server_packet_send_to_channel(server, sock, channel, packet->type,
+                                      FALSE, TRUE, packet->buffer->data,
                                       packet->buffer->len, FALSE);
 
     /* Remove the client from channel's invite list */
@@ -1452,14 +1519,14 @@ void silc_server_notify(SilcServer server,
 
   case SILC_NOTIFY_TYPE_KILLED:
     {
-      /* 
+      /*
        * Distribute the notify to local clients on channels
        */
       unsigned char *id, *comment;
       SilcUInt32 id_len, comment_len;
-    
+
       SILC_LOG_DEBUG(("KILLED notify"));
-      
+
       /* Get client ID */
       id = silc_argument_get_arg_type(args, 1, &id_len);
       if (!id)
@@ -1469,10 +1536,10 @@ void silc_server_notify(SilcServer server,
        goto out;
 
       /* If the the client is not in local list we check global list */
-      client = silc_idlist_find_client_by_id(server->global_list, 
+      client = silc_idlist_find_client_by_id(server->global_list,
                                             client_id, TRUE, &cache);
       if (!client) {
-       client = silc_idlist_find_client_by_id(server->local_list, 
+       client = silc_idlist_find_client_by_id(server->local_list,
                                               client_id, TRUE, &cache);
        if (!client) {
          silc_free(client_id);
@@ -1505,10 +1572,10 @@ void silc_server_notify(SilcServer server,
 
       if (id_type == SILC_ID_CLIENT) {
        /* If the the client is not in local list we check global list */
-       client2 = silc_idlist_find_client_by_id(server->global_list, 
+       client2 = silc_idlist_find_client_by_id(server->global_list,
                                                client_id, TRUE, NULL);
        if (!client2) {
-         client2 = silc_idlist_find_client_by_id(server->local_list, 
+         client2 = silc_idlist_find_client_by_id(server->local_list,
                                                  client_id, TRUE, NULL);
          if (!client2) {
            silc_free(client_id);
@@ -1533,7 +1600,7 @@ void silc_server_notify(SilcServer server,
                                          tmp, tmp_len);
 
       /* Remove the client from all channels */
-      silc_server_remove_from_channels(server, NULL, client, FALSE, NULL, 
+      silc_server_remove_from_channels(server, NULL, client, FALSE, NULL,
                                       FALSE, TRUE);
 
       /* Check if anyone is watching this nickname */
@@ -1575,10 +1642,10 @@ void silc_server_notify(SilcServer server,
       goto out;
 
     /* Get client entry */
-    client = silc_idlist_find_client_by_id(server->global_list, 
+    client = silc_idlist_find_client_by_id(server->global_list,
                                           client_id, TRUE, NULL);
     if (!client) {
-      client = silc_idlist_find_client_by_id(server->local_list, 
+      client = silc_idlist_find_client_by_id(server->local_list,
                                             client_id, TRUE, NULL);
       if (!client) {
        silc_free(client_id);
@@ -1633,7 +1700,7 @@ void silc_server_notify(SilcServer server,
      */
 
     SILC_LOG_DEBUG(("BAN notify"));
-    
+
     /* Get Channel ID */
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
@@ -1641,12 +1708,12 @@ void silc_server_notify(SilcServer server,
     channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
     if (!channel_id)
       goto out;
-    
+
     /* Get channel entry */
-    channel = silc_idlist_find_channel_by_id(server->global_list, 
+    channel = silc_idlist_find_channel_by_id(server->global_list,
                                             channel_id, NULL);
     if (!channel) {
-      channel = silc_idlist_find_channel_by_id(server->local_list, 
+      channel = silc_idlist_find_channel_by_id(server->local_list,
                                               channel_id, NULL);
       if (!channel) {
        SILC_LOG_DEBUG(("Notify for unknown channel"));
@@ -1674,7 +1741,7 @@ void silc_server_notify(SilcServer server,
       if (!iargs)
        goto out;
 
-      if (action == 0 && !channel->ban_list)
+      if (action != 0x01 && !channel->ban_list)
        channel->ban_list =
          silc_hash_table_alloc(0, silc_hash_ptr,
                                NULL, NULL, NULL,
@@ -1684,6 +1751,15 @@ void silc_server_notify(SilcServer server,
       silc_server_inviteban_process(server, channel->ban_list, action,
                                    iargs);
       silc_argument_payload_free(iargs);
+
+      /* If we are router we must send this notify to our local servers on
+         the channel.  Normal server does nothing.  The notify is not
+         sent to clients. */
+      if (server->server_type == SILC_ROUTER)
+       silc_server_packet_send_to_channel(server, sock, channel,
+                                          packet->type, FALSE, FALSE,
+                                          packet->buffer->data,
+                                          packet->buffer->len, FALSE);
     }
     break;
 
@@ -1710,10 +1786,10 @@ void silc_server_notify(SilcServer server,
          client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
          if (!client_id)
            goto out;
-         client = silc_idlist_find_client_by_id(server->global_list, 
+         client = silc_idlist_find_client_by_id(server->global_list,
                                                 client_id, FALSE, NULL);
          if (client) {
-           silc_server_remove_from_channels(server, NULL, client, TRUE, 
+           silc_server_remove_from_channels(server, NULL, client, TRUE,
                                             NULL, TRUE, FALSE);
            silc_idlist_del_data(client);
            silc_idlist_del_client(server->global_list, client);
@@ -1789,7 +1865,7 @@ void silc_server_notify_list(SilcServer server,
   silc_free(new);
 }
 
-/* Received private message. This resolves the destination of the message 
+/* Received private message. This resolves the destination of the message
    and sends the packet. This is used by both server and router.  If the
    destination is our locally connected client this sends the packet to
    the client. This may also send the message for further routing if
@@ -1811,7 +1887,7 @@ void silc_server_private_message(SilcServer server,
 
   /* Get the route to the client */
   dst_sock = silc_server_get_client_route(server, packet->dst_id,
-                                         packet->dst_id_len, NULL, 
+                                         packet->dst_id_len, NULL,
                                          &idata, &client);
   if (!dst_sock) {
     SilcBuffer idp;
@@ -1888,7 +1964,7 @@ void silc_server_private_message_key(SilcServer server,
 
   /* Get the route to the client */
   dst_sock = silc_server_get_client_route(server, packet->dst_id,
-                                         packet->dst_id_len, NULL, 
+                                         packet->dst_id_len, NULL,
                                          &idata, NULL);
   if (!dst_sock)
     return;
@@ -1899,7 +1975,7 @@ void silc_server_private_message_key(SilcServer server,
 }
 
 /* Processes incoming command reply packet. The command reply packet may
-   be destined to one of our clients or it may directly for us. We will 
+   be destined to one of our clients or it may directly for us. We will
    call the command reply routine after processing the packet. */
 
 void silc_server_command_reply(SilcServer server,
@@ -1944,11 +2020,11 @@ void silc_server_command_reply(SilcServer server,
   if (packet->dst_id_type == SILC_ID_CLIENT && client && id) {
     /* Relay the packet to the client */
     const SilcBufferStruct p;
-    
+
     dst_sock = (SilcSocketConnection)client->connection;
     idata = (SilcIDListData)client;
-    
-    silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len 
+
+    silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
                     + packet->dst_id_len + packet->padlen);
     if (!silc_packet_send_prepare(dst_sock, 0, 0, buffer->len,
                                   idata->hmac_send, (const SilcBuffer)&p)) {
@@ -1956,11 +2032,11 @@ void silc_server_command_reply(SilcServer server,
       return;
     }
     silc_buffer_put((SilcBuffer)&p, buffer->data, buffer->len);
-    
+
     /* Encrypt packet */
     silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++,
                        (SilcBuffer)&p, buffer->len);
-    
+
     /* Send the packet */
     silc_server_packet_send_real(server, dst_sock, TRUE);
 
@@ -2024,7 +2100,7 @@ void silc_server_channel_message(SilcServer server,
                                SILC_NOTIFY_TYPE_ERROR, 2,
                                &error, 1, idp->data, idp->len);
       }
-      
+
       silc_buffer_free(idp);
       goto out;
     }
@@ -2032,19 +2108,19 @@ void silc_server_channel_message(SilcServer server,
 
   /* See that this client is on the channel. If the original sender is
      not client (as it can be server as well) we don't do the check. */
-  sender_id = silc_id_str2id(packet->src_id, packet->src_id_len, 
+  sender_id = silc_id_str2id(packet->src_id, packet->src_id_len,
                             packet->src_id_type);
   if (!sender_id)
     goto out;
   if (packet->src_id_type == SILC_ID_CLIENT) {
-    sender_entry = silc_idlist_find_client_by_id(server->local_list, 
+    sender_entry = silc_idlist_find_client_by_id(server->local_list,
                                                 sender_id, TRUE, NULL);
     if (!sender_entry) {
       local = FALSE;
-      sender_entry = silc_idlist_find_client_by_id(server->global_list, 
+      sender_entry = silc_idlist_find_client_by_id(server->global_list,
                                                   sender_id, TRUE, NULL);
     }
-    if (!sender_entry || !silc_server_client_on_channel(sender_entry, 
+    if (!sender_entry || !silc_server_client_on_channel(sender_entry,
                                                        channel, &chl)) {
       SILC_LOG_DEBUG(("Client not on channel"));
       goto out;
@@ -2052,13 +2128,13 @@ void silc_server_channel_message(SilcServer server,
 
     /* If channel is moderated check that client is allowed to send
        messages. */
-    if (channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS && 
+    if (channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS &&
        !(chl->mode & SILC_CHANNEL_UMODE_CHANOP) &&
        !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
       SILC_LOG_DEBUG(("Channel is silenced from normal users"));
       goto out;
     }
-    if (channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS && 
+    if (channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS &&
        chl->mode & SILC_CHANNEL_UMODE_CHANOP &&
        !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
       SILC_LOG_DEBUG(("Channel is silenced from operators"));
@@ -2069,8 +2145,8 @@ void silc_server_channel_message(SilcServer server,
       goto out;
     }
 
-    /* If the packet is coming from router, but the client entry is local 
-       entry to us then some router is rerouting this to us and it is not 
+    /* If the packet is coming from router, but the client entry is local
+       entry to us then some router is rerouting this to us and it is not
        allowed. When the client is local to us it means that we've routed
        this packet to network, and now someone is routing it back to us. */
     if (server->server_type == SILC_ROUTER &&
@@ -2114,14 +2190,14 @@ void silc_server_channel_key(SilcServer server,
                    sock->hostname, sock->ip));
     return;
   }
-    
+
   /* Distribute the key to everybody who is on the channel. If we are router
      we will also send it to locally connected servers. */
   silc_server_send_channel_key(server, sock, channel, FALSE);
-  
+
   if (server->server_type != SILC_BACKUP_ROUTER) {
     /* Distribute to local cell backup routers. */
-    silc_server_backup_send(server, sock->user_data, 
+    silc_server_backup_send(server, sock->user_data,
                            SILC_PACKET_CHANNEL_KEY, 0,
                            buffer->data, buffer->len, FALSE, TRUE);
   }
@@ -2157,7 +2233,7 @@ SilcClientEntry silc_server_new_client(SilcServer server,
   /* Remove the old cache entry. */
   if (!silc_idcache_del_by_context(server->local_list->clients, client)) {
     SILC_LOG_INFO(("Unauthenticated client attempted to register to network"));
-    silc_server_disconnect_remote(server, sock, 
+    silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_NOT_AUTHENTICATED, NULL);
     if (sock->user_data)
       silc_server_free_sock_user_data(server, sock, NULL);
@@ -2166,7 +2242,7 @@ SilcClientEntry silc_server_new_client(SilcServer server,
 
   /* Make sure this client hasn't registered already */
   if (idata->status & SILC_IDLIST_STATUS_REGISTERED) {
-    silc_server_disconnect_remote(server, sock, 
+    silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_OPERATION_ALLOWED,
                                  "Too many registrations");
     if (sock->user_data)
@@ -2176,7 +2252,7 @@ SilcClientEntry silc_server_new_client(SilcServer server,
 
   /* Parse incoming packet */
   ret = silc_buffer_unformat(buffer,
-                            SILC_STR_UI16_NSTRING_ALLOC(&username, 
+                            SILC_STR_UI16_NSTRING_ALLOC(&username,
                                                         &username_len),
                             SILC_STR_UI16_STRING_ALLOC(&realname),
                             SILC_STR_END);
@@ -2185,8 +2261,8 @@ SilcClientEntry silc_server_new_client(SilcServer server,
     silc_free(realname);
     SILC_LOG_ERROR(("Client %s (%s) sent incomplete information, closing "
                    "connection", sock->hostname, sock->ip));
-    silc_server_disconnect_remote(server, sock, 
-                                 SILC_STATUS_ERR_INCOMPLETE_INFORMATION, 
+    silc_server_disconnect_remote(server, sock,
+                                 SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                  NULL);
     if (sock->user_data)
       silc_server_free_sock_user_data(server, sock, NULL);
@@ -2198,7 +2274,7 @@ SilcClientEntry silc_server_new_client(SilcServer server,
     silc_free(realname);
     SILC_LOG_ERROR(("Client %s (%s) did not send its username, closing "
                    "connection", sock->hostname, sock->ip));
-    silc_server_disconnect_remote(server, sock, 
+    silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                  NULL);
     if (sock->user_data)
@@ -2229,28 +2305,28 @@ SilcClientEntry silc_server_new_client(SilcServer server,
 
     hostname = silc_memdup(username + tlen + 1, strlen(username) - tlen - 1);
 
-    if (strcmp(sock->hostname, sock->ip) && 
+    if (strcmp(sock->hostname, sock->ip) &&
        strcmp(sock->hostname, hostname)) {
       silc_free(username);
       silc_free(hostname);
       silc_free(realname);
       SILC_LOG_ERROR(("Client %s (%s) sent incomplete information, closing "
                      "connection", sock->hostname, sock->ip));
-      silc_server_disconnect_remote(server, sock, 
+      silc_server_disconnect_remote(server, sock,
                                    SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                    NULL);
       if (sock->user_data)
        silc_server_free_sock_user_data(server, sock, NULL);
       return NULL;
     }
-    
+
     pident = silc_pkcs_decode_identifier(client->data.public_key->identifier);
     if (pident) {
       phostname = strdup(pident->host);
       silc_pkcs_free_identifier(pident);
     }
 
-    if (!strcmp(sock->hostname, sock->ip) && 
+    if (!strcmp(sock->hostname, sock->ip) &&
        phostname && strcmp(phostname, hostname)) {
       silc_free(username);
       silc_free(hostname);
@@ -2258,14 +2334,14 @@ SilcClientEntry silc_server_new_client(SilcServer server,
       silc_free(realname);
       SILC_LOG_ERROR(("Client %s (%s) sent incomplete information, closing "
                      "connection", sock->hostname, sock->ip));
-      silc_server_disconnect_remote(server, sock, 
+      silc_server_disconnect_remote(server, sock,
                                    SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                    NULL);
       if (sock->user_data)
        silc_server_free_sock_user_data(server, sock, NULL);
       return NULL;
     }
-    
+
     silc_free(phostname);
   } else {
     /* The hostname is not present, add it. */
@@ -2276,7 +2352,7 @@ SilcClientEntry silc_server_new_client(SilcServer server,
 #if 0
     if (strcmp(sock->hostname, sock->ip)) {
 #endif
-      newusername = silc_calloc(strlen(username) + 
+      newusername = silc_calloc(strlen(username) +
                                strlen(sock->hostname) + 2,
                                sizeof(*newusername));
       strncat(newusername, username, strlen(username));
@@ -2286,11 +2362,11 @@ SilcClientEntry silc_server_new_client(SilcServer server,
       username = newusername;
 #if 0
     } else {
-      SilcPublicKeyIdentifier pident = 
+      SilcPublicKeyIdentifier pident =
        silc_pkcs_decode_identifier(client->data.public_key->identifier);
-      
+
       if (pident) {
-       newusername = silc_calloc(strlen(username) + 
+       newusername = silc_calloc(strlen(username) +
                                  strlen(pident->host) + 2,
                                  sizeof(*newusername));
        strncat(newusername, username, strlen(username));
@@ -2305,11 +2381,11 @@ SilcClientEntry silc_server_new_client(SilcServer server,
   }
 
   /* Create Client ID */
-  while (!silc_id_create_client_id(server, server->id, server->rng, 
+  while (!silc_id_create_client_id(server, server->id, server->rng,
                                   server->md5hash, nickname, &client_id)) {
     nickfail++;
     if (nickfail > 9) {
-      silc_server_disconnect_remote(server, sock, 
+      silc_server_disconnect_remote(server, sock,
                                    SILC_STATUS_ERR_BAD_NICKNAME, NULL);
       if (sock->user_data)
        silc_server_free_sock_user_data(server, sock, NULL);
@@ -2378,7 +2454,7 @@ SilcClientEntry silc_server_new_client(SilcServer server,
 
 /* Create new server. This processes received New Server packet and
    saves the received Server ID. The server is our locally connected
-   server thus we save all the information and save it to local list. 
+   server thus we save all the information and save it to local list.
    This funtion can be used by both normal server and router server.
    If normal server uses this it means that its router has connected
    to the server. If router uses this it means that one of the cell's
@@ -2409,12 +2485,12 @@ SilcServerEntry silc_server_new_server(SilcServer server,
 
   /* Remove the old cache entry */
   if (!silc_idcache_del_by_context(server->local_list->servers, new_server)) {
-    if (!silc_idcache_del_by_context(server->global_list->servers, 
+    if (!silc_idcache_del_by_context(server->global_list->servers,
                                     new_server)) {
       SILC_LOG_INFO(("Unauthenticated %s attempted to register to "
                     "network", (sock->type == SILC_SOCKET_TYPE_SERVER ?
                                 "server" : "router")));
-      silc_server_disconnect_remote(server, sock, 
+      silc_server_disconnect_remote(server, sock,
                                    SILC_STATUS_ERR_NOT_AUTHENTICATED, NULL);
       if (sock->user_data)
        silc_server_free_sock_user_data(server, sock, NULL);
@@ -2425,7 +2501,7 @@ SilcServerEntry silc_server_new_server(SilcServer server,
 
   /* Make sure this server hasn't registered already */
   if (idata->status & SILC_IDLIST_STATUS_REGISTERED) {
-    silc_server_disconnect_remote(server, sock, 
+    silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_OPERATION_ALLOWED,
                                  "Too many registrations");
     if (sock->user_data)
@@ -2436,13 +2512,13 @@ SilcServerEntry silc_server_new_server(SilcServer server,
   /* Parse the incoming packet */
   ret = silc_buffer_unformat(buffer,
                             SILC_STR_UI16_NSTRING_ALLOC(&id_string, &id_len),
-                            SILC_STR_UI16_NSTRING_ALLOC(&server_name, 
+                            SILC_STR_UI16_NSTRING_ALLOC(&server_name,
                                                         &name_len),
                             SILC_STR_END);
   if (ret == -1) {
     silc_free(id_string);
     silc_free(server_name);
-    silc_server_disconnect_remote(server, sock, 
+    silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                  NULL);
     if (sock->user_data)
@@ -2453,7 +2529,7 @@ SilcServerEntry silc_server_new_server(SilcServer server,
   if (id_len > buffer->len) {
     silc_free(id_string);
     silc_free(server_name);
-    silc_server_disconnect_remote(server, sock, 
+    silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                  NULL);
     if (sock->user_data)
@@ -2469,7 +2545,7 @@ SilcServerEntry silc_server_new_server(SilcServer server,
   if (!server_id) {
     silc_free(id_string);
     silc_free(server_name);
-    silc_server_disconnect_remote(server, sock, 
+    silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_INCOMPLETE_INFORMATION,
                                  NULL);
     if (sock->user_data)
@@ -2482,7 +2558,7 @@ SilcServerEntry silc_server_new_server(SilcServer server,
   if (!silc_id_is_valid_server_id(server, server_id, sock)) {
     SILC_LOG_INFO(("Invalid server ID sent by %s (%s)",
                   sock->ip, sock->hostname));
-    silc_server_disconnect_remote(server, sock, 
+    silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_BAD_SERVER_ID, NULL);
     if (sock->user_data)
       silc_server_free_sock_user_data(server, sock, NULL);
@@ -2491,29 +2567,30 @@ SilcServerEntry silc_server_new_server(SilcServer server,
   }
 
   /* Check that we do not have this ID already */
-  server_entry = silc_idlist_find_server_by_id(server->local_list, 
+  server_entry = silc_idlist_find_server_by_id(server->local_list,
                                               server_id, TRUE, NULL);
   if (server_entry) {
     if (SILC_IS_LOCAL(server_entry)) {
-      silc_server_disconnect_remote(server, server_entry->connection, 
+      silc_server_disconnect_remote(server, sock,
                                    SILC_STATUS_ERR_OPERATION_ALLOWED,
                                    "Too many registrations");
-      if (((SilcSocketConnection)server_entry->connection)->user_data)
+      if (sock->user_data)
        silc_server_free_sock_user_data(server, sock, NULL);
+      return NULL;
     } else {
       silc_idcache_del_by_context(server->local_list->servers, server_entry);
     }
   } else {
-    server_entry = silc_idlist_find_server_by_id(server->global_list, 
+    server_entry = silc_idlist_find_server_by_id(server->global_list,
                                                 server_id, TRUE, NULL);
     if (server_entry) {
       if (SILC_IS_LOCAL(server_entry)) {
-       silc_server_disconnect_remote(server, server_entry->connection, 
+       silc_server_disconnect_remote(server, sock,
                                      SILC_STATUS_ERR_OPERATION_ALLOWED,
                                      "Too many registrations");
-       if (((SilcSocketConnection)server_entry->connection)->user_data)
-         silc_server_free_sock_user_data(server, server_entry->connection,
-                                         NULL);
+       if (sock->user_data)
+         silc_server_free_sock_user_data(server, sock, NULL);
+       return NULL;
       } else {
        silc_idcache_del_by_context(server->global_list->servers,
                                    server_entry);
@@ -2530,8 +2607,8 @@ SilcServerEntry silc_server_new_server(SilcServer server,
                  silc_id_render(server_id, SILC_ID_SERVER)));
 
   /* Add again the entry to the ID cache. */
-  silc_idcache_add(local ? server->local_list->servers : 
-                  server->global_list->servers, server_name, server_id, 
+  silc_idcache_add(local ? server->local_list->servers :
+                  server->global_list->servers, server_name, server_id,
                   new_server, 0, NULL);
 
   /* Distribute the information about new server in the SILC network
@@ -2540,7 +2617,7 @@ SilcServerEntry silc_server_new_server(SilcServer server,
   if (server->server_type == SILC_ROUTER && !server->standalone &&
       SILC_PRIMARY_ROUTE(server) != sock)
     silc_server_send_new_id(server, SILC_PRIMARY_ROUTE(server),
-                           TRUE, new_server->id, SILC_ID_SERVER, 
+                           TRUE, new_server->id, SILC_ID_SERVER,
                            silc_id_get_len(server_id, SILC_ID_SERVER));
 
   if (server->server_type == SILC_ROUTER) {
@@ -2560,25 +2637,19 @@ SilcServerEntry silc_server_new_server(SilcServer server,
      protocol has been completed. */
   if (sock->type == SILC_SOCKET_TYPE_ROUTER &&
       silc_server_backup_replaced_get(server, server_id, NULL)) {
-    /* Send packet to the server indicating that it cannot use this
+    /* Send packet to the router indicating that it cannot use this
        connection as it has been replaced by backup router. */
-    SilcBuffer packet = silc_buffer_alloc(2);
-    silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
-    silc_buffer_format(packet,
-                      SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_REPLACED),
-                      SILC_STR_UI_CHAR(0),
-                      SILC_STR_END);
-    silc_server_packet_send(server, sock, 
-                           SILC_PACKET_RESUME_ROUTER, 0, 
-                           packet->data, packet->len, TRUE);
-    silc_buffer_free(packet);
+    SILC_LOG_DEBUG(("Remote router has been replaced by backup router, "
+                   "disabling its connection"));
+
+    silc_server_backup_send_replaced(server, sock);
 
     /* Mark the router disabled. The data sent earlier will go but nothing
-       after this does not go to this connection. */
+       after this goes to this connection. */
     idata->status |= SILC_IDLIST_STATUS_DISABLED;
   } else {
     /* If it is router announce our stuff to it. */
-    if (sock->type == SILC_SOCKET_TYPE_ROUTER && 
+    if (sock->type == SILC_SOCKET_TYPE_ROUTER &&
        server->server_type == SILC_ROUTER) {
       silc_server_announce_servers(server, FALSE, 0, sock);
       silc_server_announce_clients(server, 0, sock);
@@ -2622,7 +2693,7 @@ SilcServerEntry silc_server_new_server(SilcServer server,
 /* Processes incoming New ID packet. New ID Payload is used to distribute
    information about newly registered clients and servers. */
 
-static void silc_server_new_id_real(SilcServer server, 
+static void silc_server_new_id_real(SilcServer server,
                                    SilcSocketConnection sock,
                                    SilcPacketContext *packet,
                                    int broadcast)
@@ -2668,8 +2739,8 @@ static void silc_server_new_id_real(SilcServer server,
 
     /* If the sender is backup router and ID is server (and we are not
        backup router) then switch the entry to global list. */
-    if (server_entry->server_type == SILC_BACKUP_ROUTER && 
-       id_type == SILC_ID_SERVER && 
+    if (server_entry->server_type == SILC_BACKUP_ROUTER &&
+       id_type == SILC_ID_SERVER &&
        server->id_entry->server_type != SILC_BACKUP_ROUTER) {
       id_list = server->global_list;
       router_sock = server->router ? SILC_PRIMARY_ROUTE(server) : sock;
@@ -2696,11 +2767,11 @@ static void silc_server_new_id_real(SilcServer server,
       SilcClientEntry entry;
 
       /* Check that we do not have this client already */
-      entry = silc_idlist_find_client_by_id(server->global_list, 
-                                           id, server->server_type, 
+      entry = silc_idlist_find_client_by_id(server->global_list,
+                                           id, server->server_type,
                                            NULL);
       if (!entry)
-       entry = silc_idlist_find_client_by_id(server->local_list, 
+       entry = silc_idlist_find_client_by_id(server->local_list,
                                              id, server->server_type,
                                              NULL);
       if (entry) {
@@ -2712,11 +2783,11 @@ static void silc_server_new_id_real(SilcServer server,
                      silc_id_render(id, SILC_ID_CLIENT),
                      sock->type == SILC_SOCKET_TYPE_SERVER ?
                      "Server" : "Router", sock->hostname));
-    
+
       /* As a router we keep information of all global information in our
         global list. Cell wide information however is kept in the local
         list. */
-      entry = silc_idlist_add_client(id_list, NULL, NULL, NULL, 
+      entry = silc_idlist_add_client(id_list, NULL, NULL, NULL,
                                     id, router, NULL, 0);
       if (!entry) {
        SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
@@ -2753,13 +2824,13 @@ static void silc_server_new_id_real(SilcServer server,
        SILC_LOG_DEBUG(("Ignoring sender's own ID"));
        break;
       }
-      
+
       /* Check that we do not have this server already */
-      entry = silc_idlist_find_server_by_id(server->global_list, 
-                                           id, server->server_type, 
+      entry = silc_idlist_find_server_by_id(server->global_list,
+                                           id, server->server_type,
                                            NULL);
       if (!entry)
-       entry = silc_idlist_find_server_by_id(server->local_list, 
+       entry = silc_idlist_find_server_by_id(server->local_list,
                                              id, server->server_type,
                                              NULL);
       if (entry) {
@@ -2771,18 +2842,18 @@ static void silc_server_new_id_real(SilcServer server,
                      silc_id_render(id, SILC_ID_SERVER),
                      sock->type == SILC_SOCKET_TYPE_SERVER ?
                      "Server" : "Router", sock->hostname));
-      
-      /* As a router we keep information of all global information in our 
+
+      /* As a router we keep information of all global information in our
         global list. Cell wide information however is kept in the local
         list. */
-      entry = silc_idlist_add_server(id_list, NULL, 0, id, router, 
+      entry = silc_idlist_add_server(id_list, NULL, 0, id, router,
                                     router_sock);
       if (!entry) {
        SILC_LOG_ERROR(("Could not add new server to the ID Cache"));
        goto out;
       }
       entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
-      
+
       if (sock->type == SILC_SOCKET_TYPE_SERVER)
        server->stat.cell_servers++;
       server->stat.servers++;
@@ -2806,12 +2877,12 @@ static void silc_server_new_id_real(SilcServer server,
       !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
     SILC_LOG_DEBUG(("Broadcasting received New ID packet"));
     silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
-                           packet->type, 
+                           packet->type,
                            packet->flags | SILC_PACKET_FLAG_BROADCAST,
                            buffer->data, buffer->len, FALSE);
-    silc_server_backup_send(server, sock->user_data, 
+    silc_server_backup_send(server, sock->user_data,
                            packet->type, packet->flags,
-                           packet->buffer->data, packet->buffer->len, 
+                           packet->buffer->data, packet->buffer->len,
                            FALSE, TRUE);
   }
 
@@ -2853,13 +2924,13 @@ void silc_server_new_id_list(SilcServer server, SilcSocketConnection sock,
       !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
     SILC_LOG_DEBUG(("Broadcasting received New ID List packet"));
     silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
-                           packet->type, 
+                           packet->type,
                            packet->flags | SILC_PACKET_FLAG_BROADCAST,
-                           packet->buffer->data, 
+                           packet->buffer->data,
                            packet->buffer->len, FALSE);
-    silc_server_backup_send(server, sock->user_data, 
+    silc_server_backup_send(server, sock->user_data,
                            packet->type, packet->flags,
-                           packet->buffer->data, packet->buffer->len, 
+                           packet->buffer->data, packet->buffer->len,
                            FALSE, TRUE);
   }
 
@@ -2898,7 +2969,7 @@ void silc_server_new_id_list(SilcServer server, SilcSocketConnection sock,
   silc_free(new_id);
 }
 
-/* Received New Channel packet. Information about new channels in the 
+/* Received New Channel packet. Information about new channels in the
    network are distributed using this packet. Save the information about
    the new channel. This usually comes from router but also normal server
    can send this to notify channels it has when it connects to us. */
@@ -2927,7 +2998,7 @@ void silc_server_new_channel(SilcServer server,
                                       packet->buffer->len);
   if (!payload)
     return;
-    
+
   /* Get the channel ID */
   channel_id = silc_channel_get_id_parse(payload);
   if (!channel_id) {
@@ -2944,22 +3015,22 @@ void silc_server_new_channel(SilcServer server,
   server_entry = (SilcServerEntry)sock->user_data;
 
   if (sock->type == SILC_SOCKET_TYPE_ROUTER) {
-    /* Add the channel to global list as it is coming from router. It 
+    /* Add the channel to global list as it is coming from router. It
        cannot be our own channel as it is coming from router. */
 
     /* Check that we don't already have this channel */
-    channel = silc_idlist_find_channel_by_name(server->local_list, 
+    channel = silc_idlist_find_channel_by_name(server->local_list,
                                               channel_name, NULL);
     if (!channel)
-      channel = silc_idlist_find_channel_by_name(server->global_list, 
+      channel = silc_idlist_find_channel_by_name(server->global_list,
                                                 channel_name, NULL);
     if (!channel) {
       SILC_LOG_DEBUG(("New channel id(%s) from [Router] %s",
-                     silc_id_render(channel_id, SILC_ID_CHANNEL), 
+                     silc_id_render(channel_id, SILC_ID_CHANNEL),
                      sock->hostname));
-    
-      channel = 
-       silc_idlist_add_channel(server->global_list, strdup(channel_name), 
+
+      channel =
+       silc_idlist_add_channel(server->global_list, strdup(channel_name),
                                0, channel_id, sock->user_data, NULL, NULL, 0);
       if (!channel) {
        silc_channel_payload_free(payload);
@@ -2978,14 +3049,14 @@ void silc_server_new_channel(SilcServer server,
     SilcBuffer chk;
 
     SILC_LOG_DEBUG(("Channel id(%s) from [Server] %s",
-                   silc_id_render(channel_id, SILC_ID_CHANNEL), 
+                   silc_id_render(channel_id, SILC_ID_CHANNEL),
                    sock->hostname));
 
     /* Check that we don't already have this channel */
-    channel = silc_idlist_find_channel_by_name(server->local_list, 
+    channel = silc_idlist_find_channel_by_name(server->local_list,
                                               channel_name, NULL);
     if (!channel)
-      channel = silc_idlist_find_channel_by_name(server->global_list, 
+      channel = silc_idlist_find_channel_by_name(server->global_list,
                                                 channel_name, NULL);
 
     /* If the channel does not exist, then create it. This creates a new
@@ -3002,7 +3073,7 @@ void silc_server_new_channel(SilcServer server,
        SilcChannelID *tmp;
        SILC_LOG_DEBUG(("Forcing the server to change Channel ID"));
        if (silc_id_create_channel_id(server, server->id, server->rng, &tmp)) {
-         silc_server_send_notify_channel_change(server, sock, FALSE, 
+         silc_server_send_notify_channel_change(server, sock, FALSE,
                                                 channel_id, tmp);
          silc_channel_payload_free(payload);
          silc_free(channel_id);
@@ -3040,9 +3111,9 @@ void silc_server_new_channel(SilcServer server,
       cipher_len = strlen(cipher);
       chk = silc_channel_key_payload_encode(id_len, id,
                                            cipher_len, cipher,
-                                           channel->key_len / 8, 
+                                           channel->key_len / 8,
                                            channel->key);
-      silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0, 
+      silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0,
                              chk->data, chk->len, FALSE);
       silc_buffer_free(chk);
       silc_free(id);
@@ -3058,7 +3129,7 @@ void silc_server_new_channel(SilcServer server,
        /* They don't match, send CHANNEL_CHANGE notify to the server to
           force the ID change. */
        SILC_LOG_DEBUG(("Forcing the server to change Channel ID"));
-       silc_server_send_notify_channel_change(server, sock, FALSE, 
+       silc_server_send_notify_channel_change(server, sock, FALSE,
                                               channel_id, channel->id);
        silc_channel_payload_free(payload);
        silc_free(channel_id);
@@ -3106,9 +3177,9 @@ void silc_server_new_channel(SilcServer server,
        cipher_len = strlen(cipher);
        chk = silc_channel_key_payload_encode(id_len, id,
                                              cipher_len, cipher,
-                                             channel->key_len / 8, 
+                                             channel->key_len / 8,
                                              channel->key);
-       silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0, 
+       silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0,
                                chk->data, chk->len, FALSE);
        silc_buffer_free(chk);
        silc_free(id);
@@ -3141,14 +3212,14 @@ void silc_server_new_channel(SilcServer server,
        silc_server_packet_send_dest(server, sock,
                                     SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
                                     channel->id, SILC_ID_CHANNEL,
-                                    users_modes->data, 
+                                    users_modes->data,
                                     users_modes->len, FALSE);
        silc_buffer_free(users_modes);
       }
       if (channel->topic) {
        silc_server_send_notify_topic_set(server, sock,
                                          server->server_type == SILC_ROUTER ?
-                                         TRUE : FALSE, channel, 
+                                         TRUE : FALSE, channel,
                                          server->id, SILC_ID_SERVER,
                                          channel->topic);
       }
@@ -3163,13 +3234,13 @@ void silc_server_new_channel(SilcServer server,
       !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
     SILC_LOG_DEBUG(("Broadcasting received New Channel packet"));
     silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
-                           packet->type, 
+                           packet->type,
                            packet->flags | SILC_PACKET_FLAG_BROADCAST,
-                           packet->buffer->data, 
+                           packet->buffer->data,
                            packet->buffer->len, FALSE);
-    silc_server_backup_send(server, sock->user_data, 
+    silc_server_backup_send(server, sock->user_data,
                            packet->type, packet->flags,
-                           packet->buffer->data, packet->buffer->len, 
+                           packet->buffer->data, packet->buffer->len,
                            FALSE, TRUE);
   }
 
@@ -3257,7 +3328,7 @@ void silc_server_key_agreement(SilcServer server,
 
   /* Get the route to the client */
   dst_sock = silc_server_get_client_route(server, packet->dst_id,
-                                         packet->dst_id_len, NULL, 
+                                         packet->dst_id_len, NULL,
                                          &idata, NULL);
   if (!dst_sock)
     return;
@@ -3336,19 +3407,28 @@ void silc_server_rekey(SilcServer server,
   SilcServerRekeyInternalContext *proto_ctx;
   SilcIDListData idata = (SilcIDListData)sock->user_data;
 
-  SILC_LOG_DEBUG(("Start"));
+  SILC_LOG_DEBUG(("Received rekey request"));
+
+  /* If we have other protocol executing we have no other choice but to
+     not execute rekey. XXX This is very bad thing.  Let's hope this
+     doesn't happen often. */
+  if (sock->protocol) {
+    SILC_LOG_WARNING(("Cannot execute REKEY protocol because other protocol "
+                     "is executing at the same time"));
+    return;
+  }
 
   /* Allocate internal protocol context. This is sent as context
      to the protocol. */
   proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
   proto_ctx->server = (void *)server;
-  proto_ctx->sock = sock;
+  proto_ctx->sock = silc_socket_dup(sock);
   proto_ctx->responder = TRUE;
   proto_ctx->pfs = idata->rekey->pfs;
-      
+
   /* Perform rekey protocol. Will call the final callback after the
      protocol is over. */
-  silc_protocol_alloc(SILC_PROTOCOL_SERVER_REKEY, 
+  silc_protocol_alloc(SILC_PROTOCOL_SERVER_REKEY,
                      &protocol, proto_ctx, silc_server_rekey_final);
   sock->protocol = protocol;
 
@@ -3380,7 +3460,7 @@ void silc_server_ftp(SilcServer server,
 
   /* Get the route to the client */
   dst_sock = silc_server_get_client_route(server, packet->dst_id,
-                                         packet->dst_id_len, NULL, 
+                                         packet->dst_id_len, NULL,
                                          &idata, NULL);
   if (!dst_sock)
     return;
@@ -3421,7 +3501,7 @@ SILC_SERVER_CMD_FUNC(resume_resolve)
 
   if (reply && silc_command_get(reply->payload) == SILC_COMMAND_WHOIS) {
     /* Get entry to the client, and resolve it if we don't have it. */
-    client = silc_idlist_find_client_by_id(server->local_list, 
+    client = silc_idlist_find_client_by_id(server->local_list,
                                           r->data, TRUE, NULL);
     if (!client) {
       client = silc_idlist_find_client_by_id(server->global_list,
@@ -3608,12 +3688,12 @@ void silc_server_resume_client(SilcServer server,
        /* We must retrieve the detached client's public key by sending
           GETKEY command. Reprocess this packet after receiving the key */
        SilcBuffer idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
-       SilcSocketConnection dest_sock = 
+       SilcSocketConnection dest_sock =
          silc_server_get_client_route(server, NULL, 0, client_id, NULL, NULL);
 
        SILC_LOG_DEBUG(("Resolving client public key"));
 
-       silc_server_send_command(server, dest_sock ? dest_sock : 
+       silc_server_send_command(server, dest_sock ? dest_sock :
                                 SILC_PRIMARY_ROUTE(server),
                                 SILC_COMMAND_GETKEY, ++server->cmd_ident,
                                 1, 1, idp->data, idp->len);
@@ -3655,7 +3735,7 @@ void silc_server_resume_client(SilcServer server,
     if (!idata->hash ||
        !silc_auth_verify_data(auth, auth_len, SILC_AUTH_PUBLIC_KEY,
                               detached_client->data.public_key, 0,
-                              idata->hash, detached_client->id, 
+                              idata->hash, detached_client->id,
                               SILC_ID_CLIENT)) {
       SILC_LOG_ERROR(("Client %s (%s) resume authentication failed, "
                      "closing connection", sock->hostname, sock->ip));
@@ -3694,7 +3774,7 @@ void silc_server_resume_client(SilcServer server,
 
     /* Send to primary router */
     silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
-                           SILC_PACKET_RESUME_CLIENT, 0, 
+                           SILC_PACKET_RESUME_CLIENT, 0,
                            buf->data, buf->len, TRUE);
     silc_server_backup_send(server, detached_client->router,
                            SILC_PACKET_RESUME_CLIENT, 0,
@@ -3705,7 +3785,7 @@ void silc_server_resume_client(SilcServer server,
     if (server->server_type == SILC_ROUTER && detached_client->router &&
        detached_client->router->server_type != SILC_ROUTER)
       silc_server_packet_send(server, detached_client->router->connection,
-                             SILC_PACKET_RESUME_CLIENT, 0, 
+                             SILC_PACKET_RESUME_CLIENT, 0,
                              buf->data, buf->len, TRUE);
     silc_buffer_free(buf);
 
@@ -3728,18 +3808,18 @@ void silc_server_resume_client(SilcServer server,
     /* If the ID is not based in our ID then change it */
     if (!SILC_ID_COMPARE(client->id, server->id, server->id->ip.data_len)) {
       silc_free(client_id);
-      while (!silc_id_create_client_id(server, server->id, server->rng, 
-                                      server->md5hash, client->nickname, 
+      while (!silc_id_create_client_id(server, server->id, server->rng,
+                                      server->md5hash, client->nickname,
                                       &client_id)) {
        nickfail++;
        if (nickfail > 9) {
-         silc_server_disconnect_remote(server, sock, 
+         silc_server_disconnect_remote(server, sock,
                                        SILC_STATUS_ERR_BAD_NICKNAME, NULL);
          if (sock->user_data)
            silc_server_free_sock_user_data(server, sock, NULL);
          return;
        }
-       snprintf(&client->nickname[strlen(client->nickname) - 1], 1, 
+       snprintf(&client->nickname[strlen(client->nickname) - 1], 1,
                 "%d", nickfail);
       }
       nick_change = TRUE;
@@ -3759,7 +3839,7 @@ void silc_server_resume_client(SilcServer server,
       silc_hash_table_list(client->channels, &htl);
       while (silc_hash_table_get(&htl, NULL, (void **)&chl)) {
        channel = chl->channel;
-       SILC_LOG_DEBUG(("Resolving users for %s channel", 
+       SILC_LOG_DEBUG(("Resolving users for %s channel",
                        channel->channel_name));
        if (channel->disabled || !channel->users_resolved) {
          silc_server_send_command(server, SILC_PRIMARY_ROUTE(server),
@@ -3781,11 +3861,11 @@ void silc_server_resume_client(SilcServer server,
       SilcBuffer oidp, nidp;
       oidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
       nidp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
-      silc_server_send_notify_on_channels(server, NULL, client, 
+      silc_server_send_notify_on_channels(server, NULL, client,
                                          SILC_NOTIFY_TYPE_NICK_CHANGE, 3,
-                                         oidp->data, oidp->len, 
+                                         oidp->data, oidp->len,
                                          nidp->data, nidp->len,
-                                         client->nickname, 
+                                         client->nickname,
                                          strlen(client->nickname));
       silc_buffer_free(oidp);
       silc_buffer_free(nidp);
@@ -3821,22 +3901,22 @@ void silc_server_resume_client(SilcServer server,
 
       id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
       cipher = silc_cipher_get_name(channel->channel_key);
-      keyp = 
+      keyp =
        silc_channel_key_payload_encode(silc_id_get_len(channel->id,
-                                                       SILC_ID_CHANNEL), 
+                                                       SILC_ID_CHANNEL),
                                        id_string,
                                        strlen(cipher), cipher,
                                        channel->key_len / 8, channel->key);
       silc_free(id_string);
 
       /* Send the channel key to the client */
-      silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0, 
+      silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0,
                              keyp->data, keyp->len, FALSE);
 
       /* Distribute the channel key to channel */
       if (created) {
        silc_server_send_channel_key(server, NULL, channel,
-                                    server->server_type == SILC_ROUTER ? 
+                                    server->server_type == SILC_ROUTER ?
                                     FALSE : !server->standalone);
        silc_server_backup_send(server, NULL, SILC_PACKET_CHANNEL_KEY, 0,
                                keyp->data, keyp->len, FALSE, TRUE);
@@ -3858,7 +3938,7 @@ void silc_server_resume_client(SilcServer server,
     }
 
     /* Get entry to the client, and resolve it if we don't have it. */
-    detached_client = silc_idlist_find_client_by_id(server->local_list, 
+    detached_client = silc_idlist_find_client_by_id(server->local_list,
                                                    client_id, TRUE,
                                                    &id_cache);
     if (!detached_client) {
@@ -3903,12 +3983,12 @@ void silc_server_resume_client(SilcServer server,
        !(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
       SILC_LOG_DEBUG(("Broadcasting received Resume Client packet"));
       silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
-                             packet->type, 
+                             packet->type,
                              packet->flags | SILC_PACKET_FLAG_BROADCAST,
                              buffer->data, buffer->len, FALSE);
-      silc_server_backup_send(server, sock->user_data, 
+      silc_server_backup_send(server, sock->user_data,
                              packet->type, packet->flags,
-                             packet->buffer->data, packet->buffer->len, 
+                             packet->buffer->data, packet->buffer->len,
                              FALSE, TRUE);
     }
 
@@ -3931,11 +4011,11 @@ void silc_server_resume_client(SilcServer server,
     }
 
     /* Get server entry */
-    server_entry = silc_idlist_find_server_by_id(server->global_list, 
+    server_entry = silc_idlist_find_server_by_id(server->global_list,
                                                 server_id, TRUE, NULL);
     local = FALSE;
     if (!server_entry) {
-      server_entry = silc_idlist_find_server_by_id(server->local_list, 
+      server_entry = silc_idlist_find_server_by_id(server->local_list,
                                                   server_id, TRUE, NULL);
       local = TRUE;
       if (!server_entry) {
@@ -3968,7 +4048,7 @@ void silc_server_resume_client(SilcServer server,
     if (server->server_type != SILC_ROUTER) {
       silc_hash_table_list(detached_client->channels, &htl);
       while (silc_hash_table_get(&htl, NULL, (void **)&chl))
-       chl->channel->global_users = 
+       chl->channel->global_users =
          silc_server_channel_has_global(chl->channel);
       silc_hash_table_list_reset(&htl);
     }
index 80d2d71bfc73cc91b48ddaeb8a40a13fb39f8d00..b72ac0f3012379add36543e2f4e3b8ad19baafb8 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  packet_send.c 
+  packet_send.c
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2002 Pekka Riikonen
+  Copyright (C) 1997 - 2003 Pekka Riikonen
 
   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
@@ -17,7 +17,7 @@
 
 */
 /*
- * Server packet routines to send packets. 
+ * Server packet routines to send packets.
  */
 /* $Id$ */
 
@@ -49,9 +49,9 @@ int silc_server_packet_send_real(SilcServer server,
                       sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
                       "Router")));
 
-      SILC_SET_DISCONNECTING(sock);
       if (sock->user_data)
        silc_server_free_sock_user_data(server, sock, NULL);
+      SILC_SET_DISCONNECTING(sock);
       silc_server_close_connection(server, sock);
       return ret;
     }
@@ -60,9 +60,9 @@ int silc_server_packet_send_real(SilcServer server,
     return ret;
   }
 
-  /* Mark that there is some outgoing data available for this connection. 
+  /* Mark that there is some outgoing data available for this connection.
      This call sets the connection both for input and output (the input
-     is set always and this call keeps the input setting, actually). 
+     is set always and this call keeps the input setting, actually).
      Actual data sending is performed by silc_server_packet_process. */
   SILC_SET_CONNECTION_FOR_OUTPUT(server->schedule, sock->sock);
 
@@ -76,15 +76,15 @@ int silc_server_packet_send_real(SilcServer server,
 
 /* Assembles a new packet to be sent out to network. This doesn't actually
    send the packet but creates the packet and fills the outgoing data
-   buffer and marks the packet ready to be sent to network. However, If 
-   argument force_send is TRUE the packet is sent immediately and not put 
+   buffer and marks the packet ready to be sent to network. However, If
+   argument force_send is TRUE the packet is sent immediately and not put
    to queue. Normal case is that the packet is not sent immediately. */
 
 void silc_server_packet_send(SilcServer server,
-                            SilcSocketConnection sock, 
-                            SilcPacketType type, 
+                            SilcSocketConnection sock,
+                            SilcPacketType type,
                             SilcPacketFlags flags,
-                            unsigned char *data, 
+                            unsigned char *data,
                             SilcUInt32 data_len,
                             bool force_send)
 {
@@ -104,9 +104,9 @@ void silc_server_packet_send(SilcServer server,
   /* If entry is disabled do not sent anything.  Allow hearbeat and
      rekeys, though */
   if ((idata && idata->status & SILC_IDLIST_STATUS_DISABLED &&
-       type != SILC_PACKET_HEARTBEAT && type != SILC_PACKET_REKEY && 
+       type != SILC_PACKET_HEARTBEAT && type != SILC_PACKET_REKEY &&
        type != SILC_PACKET_REKEY_DONE) ||
-      sock->user_data == server->id_entry) {
+      (sock->user_data == server->id_entry)) {
     SILC_LOG_DEBUG(("Connection is disabled"));
     return;
   }
@@ -136,18 +136,18 @@ void silc_server_packet_send(SilcServer server,
 
 /* Assembles a new packet to be sent out to network. This doesn't actually
    send the packet but creates the packet and fills the outgoing data
-   buffer and marks the packet ready to be sent to network. However, If 
-   argument force_send is TRUE the packet is sent immediately and not put 
-   to queue. Normal case is that the packet is not sent immediately. 
+   buffer and marks the packet ready to be sent to network. However, If
+   argument force_send is TRUE the packet is sent immediately and not put
+   to queue. Normal case is that the packet is not sent immediately.
    Destination information is sent as argument for this function. */
 
 void silc_server_packet_send_dest(SilcServer server,
-                                 SilcSocketConnection sock, 
-                                 SilcPacketType type, 
+                                 SilcSocketConnection sock,
+                                 SilcPacketType type,
                                  SilcPacketFlags flags,
                                  void *dst_id,
                                  SilcIdType dst_id_type,
-                                 unsigned char *data, 
+                                 unsigned char *data,
                                  SilcUInt32 data_len,
                                  bool force_send)
 {
@@ -206,9 +206,9 @@ void silc_server_packet_send_dest(SilcServer server,
   packetdata.dst_id_len = dst_id_len;
   packetdata.dst_id_type = dst_id_type;
   data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
-                                           packetdata.src_id_len + 
+                                           packetdata.src_id_len +
                                            packetdata.dst_id_len));
-  packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
+  packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
     packetdata.src_id_len + dst_id_len;
   if (type == SILC_PACKET_CONNECTION_AUTH)
     SILC_PACKET_PADLEN_MAX(packetdata.truelen, block_len, packetdata.padlen);
@@ -238,21 +238,21 @@ void silc_server_packet_send_dest(SilcServer server,
 
 /* Assembles a new packet to be sent out to network. This doesn't actually
    send the packet but creates the packet and fills the outgoing data
-   buffer and marks the packet ready to be sent to network. However, If 
-   argument force_send is TRUE the packet is sent immediately and not put 
-   to queue. Normal case is that the packet is not sent immediately. 
+   buffer and marks the packet ready to be sent to network. However, If
+   argument force_send is TRUE the packet is sent immediately and not put
+   to queue. Normal case is that the packet is not sent immediately.
    The source and destination information is sent as argument for this
    function. */
 
 void silc_server_packet_send_srcdest(SilcServer server,
-                                    SilcSocketConnection sock, 
-                                    SilcPacketType type, 
+                                    SilcSocketConnection sock,
+                                    SilcPacketType type,
                                     SilcPacketFlags flags,
                                     void *src_id,
                                     SilcIdType src_id_type,
                                     void *dst_id,
                                     SilcIdType dst_id_type,
-                                    unsigned char *data, 
+                                    unsigned char *data,
                                     SilcUInt32 data_len,
                                     bool force_send)
 {
@@ -316,9 +316,9 @@ void silc_server_packet_send_srcdest(SilcServer server,
   packetdata.dst_id_len = dst_id_len;
   packetdata.dst_id_type = dst_id_type;
   data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
-                                           packetdata.src_id_len + 
+                                           packetdata.src_id_len +
                                            dst_id_len));
-  packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
+  packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
     packetdata.src_id_len + dst_id_len;
   SILC_PACKET_PADLEN(packetdata.truelen, block_len, packetdata.padlen);
 
@@ -425,7 +425,7 @@ void silc_server_packet_route(SilcServer server,
   silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++,
                      (SilcBuffer)&p, p.len);
 
-  SILC_LOG_HEXDUMP(("Routed packet (%d), len %d", idata->psn_send - 1, 
+  SILC_LOG_HEXDUMP(("Routed packet (%d), len %d", idata->psn_send - 1,
                   p.len), p.data, p.len);
 
   /* Now actually send the packet */
@@ -444,10 +444,10 @@ void silc_server_packet_route(SilcServer server,
 
 void silc_server_packet_send_clients(SilcServer server,
                                     SilcHashTable clients,
-                                    SilcPacketType type, 
+                                    SilcPacketType type,
                                     SilcPacketFlags flags,
                                     bool route,
-                                    unsigned char *data, 
+                                    unsigned char *data,
                                     SilcUInt32 data_len,
                                     bool force_send)
 {
@@ -471,7 +471,7 @@ void silc_server_packet_send_clients(SilcServer server,
     /* If client has router set it is not locally connected client and
        we will route the message to the router set in the client. Though,
        send locally connected server in all cases. */
-    if (server->server_type == SILC_ROUTER && client->router && 
+    if (server->server_type == SILC_ROUTER && client->router &&
        ((!route && client->router->router == server->id_entry) || route)) {
 
       /* Check if we have sent the packet to this route already */
@@ -540,9 +540,9 @@ silc_server_packet_send_to_channel_real(SilcServer server,
     return;
 
   data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
-                                           packet->src_id_len + 
+                                           packet->src_id_len +
                                            packet->dst_id_len));
-  packet->truelen = data_len + SILC_PACKET_HEADER_LEN + 
+  packet->truelen = data_len + SILC_PACKET_HEADER_LEN +
     packet->src_id_len + packet->dst_id_len;
 
   block_len = cipher ? silc_cipher_get_block_len(cipher) : 0;
@@ -563,12 +563,12 @@ silc_server_packet_send_to_channel_real(SilcServer server,
   }
 
   if (channel_message)
-    silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&p, 
-                       SILC_PACKET_HEADER_LEN + packet->src_id_len + 
+    silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&p,
+                       SILC_PACKET_HEADER_LEN + packet->src_id_len +
                        packet->dst_id_len + packet->padlen);
   else
     silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&p, p.len);
-    
+
   SILC_LOG_HEXDUMP(("Channel packet (%d), len %d", sequence, p.len),
                   p.data, p.len);
 
@@ -576,10 +576,10 @@ silc_server_packet_send_to_channel_real(SilcServer server,
   silc_server_packet_send_real(server, sock, force_send);
 }
 
-/* This routine is used by the server to send packets to channel. The 
+/* This routine is used by the server to send packets to channel. The
    packet sent with this function is distributed to all clients on
    the channel. Usually this is used to send notify messages to the
-   channel, things like notify about new user joining to the channel. 
+   channel, things like notify about new user joining to the channel.
    If `route' is FALSE then the packet is sent only locally and will not
    be routed anywhere (for router locally means cell wide). If `sender'
    is provided then the packet is not sent to that connection since it
@@ -591,6 +591,7 @@ void silc_server_packet_send_to_channel(SilcServer server,
                                        SilcChannelEntry channel,
                                        SilcPacketType type,
                                        bool route,
+                                       bool send_to_clients,
                                        unsigned char *data,
                                        SilcUInt32 data_len,
                                        bool force_send)
@@ -608,7 +609,7 @@ void silc_server_packet_send_to_channel(SilcServer server,
 
   /* This doesn't send channel message packets */
   assert(type != SILC_PACKET_CHANNEL_MESSAGE);
-  
+
   /* Set the packet context pointers. */
   packetdata.flags = 0;
   packetdata.type = type;
@@ -629,14 +630,14 @@ void silc_server_packet_send_to_channel(SilcServer server,
     router = server->router;
     sock = (SilcSocketConnection)router->connection;
     idata = (SilcIDListData)router;
-    
+
     if (sock != sender) {
       SILC_LOG_DEBUG(("Sending packet to router for routing"));
       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                             idata->send_key, 
-                                             idata->hmac_send, 
+                                             idata->send_key,
+                                             idata->hmac_send,
                                              idata->psn_send++,
-                                             data, data_len, FALSE, 
+                                             data, data_len, FALSE,
                                              force_send);
     }
   }
@@ -649,7 +650,7 @@ void silc_server_packet_send_to_channel(SilcServer server,
   SILC_LOG_DEBUG(("Sending %s to channel %s",
                  silc_get_packet_name(type), channel->channel_name));
 
-  routed = silc_calloc(silc_hash_table_count(channel->user_list), 
+  routed = silc_calloc(silc_hash_table_count(channel->user_list),
                       sizeof(*routed));
 
   /* Send the message to clients on the channel's client list. */
@@ -662,7 +663,7 @@ void silc_server_packet_send_to_channel(SilcServer server,
     /* If client has router set it is not locally connected client and
        we will route the message to the router set in the client. Though,
        send locally connected server in all cases. */
-    if (server->server_type == SILC_ROUTER && client->router && 
+    if (server->server_type == SILC_ROUTER && client->router &&
        ((!route && client->router->router == server->id_entry) || route)) {
 
       /* Check if we have sent the packet to this route already */
@@ -693,10 +694,10 @@ void silc_server_packet_send_to_channel(SilcServer server,
 
       /* Send the packet */
       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                             idata->send_key, 
-                                             idata->hmac_send, 
+                                             idata->send_key,
+                                             idata->hmac_send,
                                              idata->psn_send++,
-                                             data, data_len, FALSE, 
+                                             data, data_len, FALSE,
                                              force_send);
 
       /* Mark this route routed already */
@@ -704,7 +705,7 @@ void silc_server_packet_send_to_channel(SilcServer server,
       continue;
     }
 
-    if (client->router)
+    if (client->router || !send_to_clients)
       continue;
 
     /* Send to locally connected client */
@@ -712,7 +713,7 @@ void silc_server_packet_send_to_channel(SilcServer server,
     /* Get data used in packet header encryption, keys and stuff. */
     sock = (SilcSocketConnection)client->connection;
     idata = (SilcIDListData)client;
-    
+
     if (!sock || (sender && sock == sender))
       continue;
 
@@ -722,10 +723,10 @@ void silc_server_packet_send_to_channel(SilcServer server,
 
     /* Send the packet */
     silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                           idata->send_key, 
-                                           idata->hmac_send, 
-                                           idata->psn_send++, 
-                                           data, data_len, FALSE, 
+                                           idata->send_key,
+                                           idata->hmac_send,
+                                           idata->psn_send++,
+                                           data, data_len, FALSE,
                                            force_send);
   }
   silc_hash_table_list_reset(&htl);
@@ -786,7 +787,7 @@ silc_server_packet_relay_to_channel_encrypt(SilcServer server,
 /* This routine is explicitly used to relay messages to some channel.
    Packets sent with this function we have received earlier and are
    totally encrypted. This just sends the packet to all clients on
-   the channel. If the sender of the packet is someone on the channel 
+   the channel. If the sender of the packet is someone on the channel
    the message will not be sent to that client. The SILC Packet header
    is encrypted with the session key shared between us and the client.
    MAC is also computed before encrypting the header. Rest of the
@@ -853,15 +854,15 @@ void silc_server_packet_relay_to_channel(SilcServer server,
       SILC_LOG_DEBUG(("Sending message to router for routing"));
 
       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                             idata->send_key, 
-                                             idata->hmac_send, 
-                                             idata->psn_send++, 
-                                             data, data_len, TRUE, 
+                                             idata->send_key,
+                                             idata->hmac_send,
+                                             idata->psn_send++,
+                                             data, data_len, TRUE,
                                              force_send);
     }
   }
 
-  routed = silc_calloc(silc_hash_table_count(channel->user_list), 
+  routed = silc_calloc(silc_hash_table_count(channel->user_list),
                       sizeof(*routed));
 
   /* Assure we won't route the message back to the sender's way. */
@@ -906,13 +907,13 @@ void silc_server_packet_relay_to_channel(SilcServer server,
       if (sender_sock && sock == sender_sock)
        continue;
 
-      SILC_LOG_DEBUG(("Relaying packet to client ID(%s) %s (%s)", 
+      SILC_LOG_DEBUG(("Relaying packet to client ID(%s) %s (%s)",
                      silc_id_render(client->id, SILC_ID_CLIENT),
                      sock->hostname, sock->ip));
 
       /* Mark this route routed already. */
       routed[routed_count++] = client->router;
-       
+
       if (sock->type == SILC_SOCKET_TYPE_ROUTER) {
        /* The remote connection is router then we'll decrypt the
           channel message and re-encrypt it with the session key shared
@@ -944,7 +945,7 @@ void silc_server_packet_relay_to_channel(SilcServer server,
 
        /* If private key mode is not set then decrypt the packet
           and re-encrypt it */
-       if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY) && 
+       if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY) &&
            channel->channel_key) {
          unsigned char tmp[SILC_PACKET_MAX_LEN];
 
@@ -995,16 +996,16 @@ void silc_server_packet_relay_to_channel(SilcServer server,
     if (!sock || (sender_sock && sock == sender_sock))
       continue;
 
-    SILC_LOG_DEBUG(("Sending packet to client ID(%s) %s (%s)", 
+    SILC_LOG_DEBUG(("Sending packet to client ID(%s) %s (%s)",
                    silc_id_render(client->id, SILC_ID_CLIENT),
                    sock->hostname, sock->ip));
 
     /* Send the packet */
     silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                           idata->send_key, 
-                                           idata->hmac_send, 
-                                           idata->psn_send++, 
-                                           data, data_len, TRUE, 
+                                           idata->send_key,
+                                           idata->hmac_send,
+                                           idata->psn_send++,
+                                           data, data_len, TRUE,
                                            force_send);
   }
 
@@ -1016,7 +1017,7 @@ void silc_server_packet_relay_to_channel(SilcServer server,
 
 /* This function is used to send packets strictly to all local clients
    on a particular channel.  This is used for example to distribute new
-   channel key to all our locally connected clients on the channel. 
+   channel key to all our locally connected clients on the channel.
    The packets are always encrypted with the session key shared between
    the client, this means these are not _to the channel_ but _to the client_
    on the channel. */
@@ -1067,7 +1068,7 @@ void silc_server_send_private_message(SilcServer server,
   SilcBuffer buffer = packet->buffer;
   const SilcBufferStruct p;
 
-  silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len 
+  silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
                   + packet->dst_id_len + packet->padlen);
   if (!silc_packet_send_prepare(dst_sock, 0, 0, buffer->len, hmac,
                                 (const SilcBuffer)&p)) {
@@ -1082,8 +1083,8 @@ void silc_server_send_private_message(SilcServer server,
     silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&p, buffer->len);
   } else {
     /* Key exist so encrypt just header and send it */
-    silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&p, 
-                       SILC_PACKET_HEADER_LEN + packet->src_id_len + 
+    silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&p,
+                       SILC_PACKET_HEADER_LEN + packet->src_id_len +
                        packet->dst_id_len + packet->padlen);
   }
 
@@ -1120,7 +1121,7 @@ void silc_server_send_motd(SilcServer server,
   }
 }
 
-/* Sends error message. Error messages may or may not have any 
+/* Sends error message. Error messages may or may not have any
    implications. */
 
 void silc_server_send_error(SilcServer server,
@@ -1135,7 +1136,7 @@ void silc_server_send_error(SilcServer server,
   vsnprintf(buf, sizeof(buf) - 1, fmt, ap);
   va_end(ap);
 
-  silc_server_packet_send(server, sock, SILC_PACKET_ERROR, 0, 
+  silc_server_packet_send(server, sock, SILC_PACKET_ERROR, 0,
                          buf, strlen(buf), FALSE);
 }
 
@@ -1156,7 +1157,7 @@ void silc_server_send_notify(SilcServer server,
   va_start(ap, argc);
 
   packet = silc_notify_payload_encode(type, argc, ap);
-  silc_server_packet_send(server, sock, SILC_PACKET_NOTIFY, 
+  silc_server_packet_send(server, sock, SILC_PACKET_NOTIFY,
                          broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
                          packet->data, packet->len, FALSE);
 
@@ -1185,7 +1186,7 @@ void silc_server_send_notify_args(SilcServer server,
   SilcBuffer packet;
 
   packet = silc_notify_payload_encode_args(type, argc, args);
-  silc_server_packet_send(server, sock, SILC_PACKET_NOTIFY, 
+  silc_server_packet_send(server, sock, SILC_PACKET_NOTIFY,
                          broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
                          packet->data, packet->len, FALSE);
   silc_buffer_free(packet);
@@ -1227,7 +1228,7 @@ void silc_server_send_notify_nick_change(SilcServer server,
   idp1 = silc_id_payload_encode((void *)old_id, SILC_ID_CLIENT);
   idp2 = silc_id_payload_encode((void *)new_id, SILC_ID_CLIENT);
 
-  silc_server_send_notify(server, sock, broadcast, 
+  silc_server_send_notify(server, sock, broadcast,
                          SILC_NOTIFY_TYPE_NICK_CHANGE,
                          3, idp1->data, idp1->len, idp2->data, idp2->len,
                          nickname, nickname ? strlen(nickname) : 0);
@@ -1285,7 +1286,8 @@ void silc_server_send_notify_cmode(SilcServer server,
                                   void *id, SilcIdType id_type,
                                   const char *cipher, const char *hmac,
                                   const char *passphrase,
-                                  SilcPublicKey founder_key)
+                                  SilcPublicKey founder_key,
+                                  SilcBuffer channel_pubkeys)
 {
   SilcBuffer idp, fkey = NULL;
   unsigned char mode[4];
@@ -1297,14 +1299,16 @@ void silc_server_send_notify_cmode(SilcServer server,
 
   silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id,
                               SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_CMODE_CHANGE,
-                              6, idp->data, idp->len,
+                              7, idp->data, idp->len,
                               mode, 4,
                               cipher, cipher ? strlen(cipher) : 0,
                               hmac, hmac ? strlen(hmac) : 0,
-                              passphrase, passphrase ? 
+                              passphrase, passphrase ?
                               strlen(passphrase) : 0,
-                              fkey ? fkey->data : NULL, fkey ? fkey->len : 0);
-  silc_buffer_free(fkey),
+                              fkey ? fkey->data : NULL, fkey ? fkey->len : 0,
+                              channel_pubkeys ? channel_pubkeys->data : NULL,
+                              channel_pubkeys ? channel_pubkeys->len : 0);
+  silc_buffer_free(fkey);
   silc_buffer_free(idp);
 }
 
@@ -1331,8 +1335,8 @@ void silc_server_send_notify_cumode(SilcServer server,
     fkey = silc_pkcs_public_key_payload_encode(founder_key);
 
   silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id,
-                              SILC_ID_CHANNEL, 
-                              SILC_NOTIFY_TYPE_CUMODE_CHANGE, 4, 
+                              SILC_ID_CHANNEL,
+                              SILC_NOTIFY_TYPE_CUMODE_CHANGE, 4,
                               idp1->data, idp1->len,
                               mode, 4,
                               idp2->data, idp2->len,
@@ -1381,8 +1385,8 @@ void silc_server_send_notify_topic_set(SilcServer server,
   silc_server_send_notify_dest(server, sock, broadcast,
                               (void *)channel->id, SILC_ID_CHANNEL,
                               SILC_NOTIFY_TYPE_TOPIC_SET,
-                              topic ? 2 : 1, 
-                              idp->data, idp->len, 
+                              topic ? 2 : 1,
+                              idp->data, idp->len,
                               topic, topic ? strlen(topic) : 0);
   silc_buffer_free(idp);
 }
@@ -1457,7 +1461,7 @@ void silc_server_send_notify_umode(SilcServer server,
 
   silc_server_send_notify(server, sock, broadcast,
                          SILC_NOTIFY_TYPE_UMODE_CHANGE, 2,
-                         idp->data, idp->len, 
+                         idp->data, idp->len,
                          mode, 4);
   silc_buffer_free(idp);
 }
@@ -1532,7 +1536,7 @@ void silc_server_send_notify_watch(SilcServer server,
                               SILC_ID_CLIENT, SILC_NOTIFY_TYPE_WATCH,
                               4, idp->data, idp->len,
                               nickname, nickname ? strlen(nickname) : 0,
-                              mode, sizeof(mode), 
+                              mode, sizeof(mode),
                               type != SILC_NOTIFY_TYPE_NONE ?
                               n : NULL, sizeof(n));
   silc_buffer_free(idp);
@@ -1554,7 +1558,7 @@ void silc_server_send_notify_dest(SilcServer server,
   va_start(ap, argc);
 
   packet = silc_notify_payload_encode(type, argc, ap);
-  silc_server_packet_send_dest(server, sock, SILC_PACKET_NOTIFY, 
+  silc_server_packet_send_dest(server, sock, SILC_PACKET_NOTIFY,
                               broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
                               dest_id, dest_id_type,
                               packet->data, packet->len, FALSE);
@@ -1572,7 +1576,7 @@ void silc_server_send_notify_dest(SilcServer server,
   va_end(ap);
 }
 
-/* Sends notify message to a channel. The notify message sent is 
+/* Sends notify message to a channel. The notify message sent is
    distributed to all clients on the channel. If `route_notify' is TRUE
    then the notify may be routed to primary route or to some other routers.
    If FALSE it is assured that the notify is sent only locally. If `sender'
@@ -1583,6 +1587,7 @@ void silc_server_send_notify_to_channel(SilcServer server,
                                        SilcSocketConnection sender,
                                        SilcChannelEntry channel,
                                        bool route_notify,
+                                       bool send_to_clients,
                                        SilcNotifyType type,
                                        SilcUInt32 argc, ...)
 {
@@ -1592,8 +1597,9 @@ void silc_server_send_notify_to_channel(SilcServer server,
   va_start(ap, argc);
 
   packet = silc_notify_payload_encode(type, argc, ap);
-  silc_server_packet_send_to_channel(server, sender, channel, 
+  silc_server_packet_send_to_channel(server, sender, channel,
                                     SILC_PACKET_NOTIFY, route_notify,
+                                    send_to_clients,
                                     packet->data, packet->len, FALSE);
   silc_buffer_free(packet);
   va_end(ap);
@@ -1657,7 +1663,7 @@ void silc_server_send_notify_on_channels(SilcServer server,
     silc_hash_table_list(channel->user_list, &htl2);
     while (silc_hash_table_get(&htl2, NULL, (void **)&chl2)) {
       c = chl2->client;
-      
+
       if (sender && c == sender)
        continue;
 
@@ -1678,7 +1684,7 @@ void silc_server_send_notify_on_channels(SilcServer server,
            break;
        if (k < routed_count)
          continue;
-       
+
        /* Get data used in packet header encryption, keys and stuff. */
        sock = (SilcSocketConnection)c->router->connection;
        idata = (SilcIDListData)c->router;
@@ -1697,12 +1703,12 @@ void silc_server_send_notify_on_channels(SilcServer server,
 
        /* Send the packet */
        silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                               idata->send_key, 
-                                               idata->hmac_send, 
-                                               idata->psn_send++, 
-                                               data, data_len, FALSE, 
+                                               idata->send_key,
+                                               idata->hmac_send,
+                                               idata->psn_send++,
+                                               data, data_len, FALSE,
                                                force_send);
-       
+
        silc_free(packetdata.dst_id);
 
        /* We want to make sure that the packet is routed to same router
@@ -1717,11 +1723,11 @@ void silc_server_send_notify_on_channels(SilcServer server,
 
       /* Send to locally connected client */
       if (c) {
-       
+
        /* Get data used in packet header encryption, keys and stuff. */
        sock = (SilcSocketConnection)c->connection;
        idata = (SilcIDListData)c;
-       
+
         if (!sock)
           continue;
 
@@ -1731,16 +1737,16 @@ void silc_server_send_notify_on_channels(SilcServer server,
 
        /* Send the packet */
        silc_server_packet_send_to_channel_real(server, sock, &packetdata,
-                                               idata->send_key, 
-                                               idata->hmac_send, 
-                                               idata->psn_send++, 
-                                               data, data_len, FALSE, 
+                                               idata->send_key,
+                                               idata->hmac_send,
+                                               idata->psn_send++,
+                                               data, data_len, FALSE,
                                                force_send);
 
        silc_free(packetdata.dst_id);
 
        /* Make sure that we send the notify only once per client. */
-       sent_clients = silc_realloc(sent_clients, sizeof(*sent_clients) * 
+       sent_clients = silc_realloc(sent_clients, sizeof(*sent_clients) *
                                    (sent_clients_count + 1));
        sent_clients[sent_clients_count++] = c;
       }
@@ -1758,14 +1764,14 @@ void silc_server_send_notify_on_channels(SilcServer server,
 
 /* Sends New ID Payload to remote end. The packet is used to distribute
    information about new registered clients, servers, channel etc. usually
-   to routers so that they can keep these information up to date. 
+   to routers so that they can keep these information up to date.
    If the argument `broadcast' is TRUE then the packet is sent as
    broadcast packet. */
 
 void silc_server_send_new_id(SilcServer server,
                             SilcSocketConnection sock,
                             bool broadcast,
-                            void *id, SilcIdType id_type, 
+                            void *id, SilcIdType id_type,
                             SilcUInt32 id_len)
 {
   SilcBuffer idp;
@@ -1773,21 +1779,21 @@ void silc_server_send_new_id(SilcServer server,
   SILC_LOG_DEBUG(("Sending new ID"));
 
   idp = silc_id_payload_encode(id, id_type);
-  silc_server_packet_send(server, sock, SILC_PACKET_NEW_ID, 
-                         broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, 
+  silc_server_packet_send(server, sock, SILC_PACKET_NEW_ID,
+                         broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
                          idp->data, idp->len, FALSE);
   silc_buffer_free(idp);
 }
 
 /* Send New Channel Payload to notify about newly created channel in the
-   SILC network. Router uses this to notify other routers in the network 
+   SILC network. Router uses this to notify other routers in the network
    about new channel. This packet is broadcasted by router. */
 
 void silc_server_send_new_channel(SilcServer server,
                                  SilcSocketConnection sock,
                                  bool broadcast,
                                  char *channel_name,
-                                 void *channel_id, 
+                                 void *channel_id,
                                  SilcUInt32 channel_id_len,
                                  SilcUInt32 mode)
 {
@@ -1805,8 +1811,8 @@ void silc_server_send_new_channel(SilcServer server,
   packet = silc_channel_payload_encode(channel_name, name_len,
                                       cid, channel_id_len, mode);
 
-  silc_server_packet_send(server, sock, SILC_PACKET_NEW_CHANNEL, 
-                         broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, 
+  silc_server_packet_send(server, sock, SILC_PACKET_NEW_CHANNEL,
+                         broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
                          packet->data, packet->len, FALSE);
 
   silc_free(cid);
@@ -1818,7 +1824,7 @@ void silc_server_send_new_channel(SilcServer server,
    sends this to the local server who sent the join command in case where
    the channel did not exist yet. Both normal and router servers uses this
    also to send this to locally connected clients on the channel. This
-   must not be broadcasted packet. Routers do not send this to each other. 
+   must not be broadcasted packet. Routers do not send this to each other.
    If `sender is provided then the packet is not sent to that connection since
    it originally came from it. */
 
@@ -1831,16 +1837,16 @@ void silc_server_send_channel_key(SilcServer server,
   unsigned char *chid;
   SilcUInt32 tmp_len;
   const char *cipher;
+
   SILC_LOG_DEBUG(("Sending key to channel %s", channel->channel_name));
+
   chid = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
   if (!chid)
     return;
 
   if (!channel->channel_key)
     return;
+
   /* Encode channel key packet */
   cipher = silc_cipher_get_name(channel->channel_key);
   tmp_len = strlen(cipher);
@@ -1848,9 +1854,9 @@ void silc_server_send_channel_key(SilcServer server,
                                                           SILC_ID_CHANNEL),
                                           chid, tmp_len, cipher,
                                            channel->key_len / 8, channel->key);
-  silc_server_packet_send_to_channel(server, sender, channel, 
+  silc_server_packet_send_to_channel(server, sender, channel,
                                     SILC_PACKET_CHANNEL_KEY,
-                                     route, packet->data, packet->len, 
+                                     route, TRUE, packet->data, packet->len,
                                     FALSE);
   silc_buffer_free(packet);
   silc_free(chid);
@@ -1859,9 +1865,9 @@ void silc_server_send_channel_key(SilcServer server,
 /* Generic function to send any command. The arguments must be sent already
    encoded into correct form in correct order. */
 
-void silc_server_send_command(SilcServer server, 
+void silc_server_send_command(SilcServer server,
                              SilcSocketConnection sock,
-                             SilcCommand command, 
+                             SilcCommand command,
                              SilcUInt16 ident,
                              SilcUInt32 argc, ...)
 {
@@ -1880,9 +1886,9 @@ void silc_server_send_command(SilcServer server,
 /* Generic function to send any command reply. The arguments must be sent
    already encoded into correct form in correct order. */
 
-void silc_server_send_command_reply(SilcServer server, 
+void silc_server_send_command_reply(SilcServer server,
                                    SilcSocketConnection sock,
-                                   SilcCommand command, 
+                                   SilcCommand command,
                                    SilcStatus status,
                                    SilcStatus error,
                                    SilcUInt16 ident,
@@ -1904,11 +1910,11 @@ void silc_server_send_command_reply(SilcServer server,
 /* Generic function to send any command reply. The arguments must be sent
    already encoded into correct form in correct order. */
 
-void silc_server_send_dest_command_reply(SilcServer server, 
+void silc_server_send_dest_command_reply(SilcServer server,
                                         SilcSocketConnection sock,
                                         void *dst_id,
                                         SilcIdType dst_id_type,
-                                        SilcCommand command, 
+                                        SilcCommand command,
                                         SilcStatus status,
                                         SilcStatus error,
                                         SilcUInt16 ident,
@@ -1922,7 +1928,7 @@ void silc_server_send_dest_command_reply(SilcServer server,
   packet = silc_command_reply_payload_encode_vap(command, status, error,
                                                 ident, argc, ap);
   silc_server_packet_send_dest(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
-                              dst_id, dst_id_type, packet->data, 
+                              dst_id, dst_id_type, packet->data,
                               packet->len, FALSE);
   silc_buffer_free(packet);
   va_end(ap);
@@ -1950,7 +1956,7 @@ void silc_server_relay_packet(SilcServer server,
 {
   const SilcBufferStruct p;
 
-  silc_buffer_push(packet->buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len 
+  silc_buffer_push(packet->buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
                   + packet->dst_id_len + packet->padlen);
   if (!silc_packet_send_prepare(dst_sock, 0, 0, packet->buffer->len, hmac,
                                 (const SilcBuffer)&p)) {
@@ -1961,11 +1967,11 @@ void silc_server_relay_packet(SilcServer server,
 
   /* Re-encrypt packet */
   silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&p, p.len);
-  
+
   /* Send the packet */
   silc_server_packet_send_real(server, dst_sock, force_send);
 
-  silc_buffer_pull(packet->buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len 
+  silc_buffer_pull(packet->buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len
                   + packet->dst_id_len + packet->padlen);
 
   /* Check for mandatory rekey */
@@ -2003,12 +2009,13 @@ void silc_server_send_connection_auth_request(SilcServer server,
 void silc_server_packet_queue_purge(SilcServer server,
                                    SilcSocketConnection sock)
 {
-  if (sock && SILC_IS_OUTBUF_PENDING(sock) && 
-      (SILC_IS_DISCONNECTED(sock) == FALSE)) {
-    SILC_LOG_DEBUG(("Purging ourgoing queue"));
+  if (sock && SILC_IS_OUTBUF_PENDING(sock) &&
+      !(SILC_IS_DISCONNECTING(sock)) && !(SILC_IS_DISCONNECTED(sock))) {
+    SILC_LOG_DEBUG(("Purging outgoing queue"));
     server->stat.packets_sent++;
     silc_packet_send(sock, TRUE);
     SILC_UNSET_OUTBUF_PENDING(sock);
+    SILC_SET_CONNECTION_FOR_INPUT(server->schedule, sock->sock);
     silc_buffer_clear(sock->outbuf);
   }
 }
@@ -2025,7 +2032,7 @@ void silc_server_send_opers(SilcServer server,
                            SilcPacketType type,
                            SilcPacketFlags flags,
                            bool route, bool local,
-                           unsigned char *data, 
+                           unsigned char *data,
                            SilcUInt32 data_len,
                            bool force_send)
 {
@@ -2074,7 +2081,7 @@ void silc_server_send_opers(SilcServer server,
        !(client->mode & SILC_UMODE_ROUTER_OPERATOR))
       goto next;
 
-    if (server->server_type != SILC_SERVER && client->router && 
+    if (server->server_type != SILC_SERVER && client->router &&
        ((!route && client->router->router == server->id_entry) || route)) {
 
       /* Check if we have sent the packet to this route already */
@@ -2127,7 +2134,7 @@ void silc_server_send_opers(SilcServer server,
        !(client->mode & SILC_UMODE_ROUTER_OPERATOR))
       goto nextg;
 
-    if (server->server_type != SILC_SERVER && client->router && 
+    if (server->server_type != SILC_SERVER && client->router &&
        ((!route && client->router->router == server->id_entry) || route)) {
 
       /* Check if we have sent the packet to this route already */
index 2dac801278ab9638f91c8df138fd1d1c291e9cba..6c85c3a8c6c8a52d7bba8deced511e7a201bfd01 100644 (file)
@@ -4,13 +4,13 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2002 Pekka Riikonen
+  Copyright (C) 1997 - 2003 Pekka Riikonen
 
   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
@@ -27,30 +27,30 @@ int silc_server_packet_send_real(SilcServer server,
                                 SilcSocketConnection sock,
                                 bool force_send);
 void silc_server_packet_send(SilcServer server,
-                            SilcSocketConnection sock, 
-                            SilcPacketType type, 
+                            SilcSocketConnection sock,
+                            SilcPacketType type,
                             SilcPacketFlags flags,
-                            unsigned char *data, 
+                            unsigned char *data,
                             SilcUInt32 data_len,
                             bool force_send);
 void silc_server_packet_send_dest(SilcServer server,
-                                 SilcSocketConnection sock, 
-                                 SilcPacketType type, 
+                                 SilcSocketConnection sock,
+                                 SilcPacketType type,
                                  SilcPacketFlags flags,
                                  void *dst_id,
                                  SilcIdType dst_id_type,
-                                 unsigned char *data, 
+                                 unsigned char *data,
                                  SilcUInt32 data_len,
                                  bool force_send);
 void silc_server_packet_send_srcdest(SilcServer server,
-                                    SilcSocketConnection sock, 
-                                    SilcPacketType type, 
+                                    SilcSocketConnection sock,
+                                    SilcPacketType type,
                                     SilcPacketFlags flags,
                                     void *src_id,
                                     SilcIdType src_id_type,
                                     void *dst_id,
                                     SilcIdType dst_id_type,
-                                    unsigned char *data, 
+                                    unsigned char *data,
                                     SilcUInt32 data_len,
                                     bool force_send);
 void silc_server_packet_broadcast(SilcServer server,
@@ -64,7 +64,7 @@ void silc_server_packet_send_clients(SilcServer server,
                                     SilcPacketType type,
                                     SilcPacketFlags flags,
                                     bool route,
-                                    unsigned char *data, 
+                                    unsigned char *data,
                                     SilcUInt32 data_len,
                                     bool force_send);
 void silc_server_packet_send_to_channel(SilcServer server,
@@ -72,13 +72,14 @@ void silc_server_packet_send_to_channel(SilcServer server,
                                        SilcChannelEntry channel,
                                        SilcPacketType type,
                                        bool route,
+                                       bool send_to_clients,
                                        unsigned char *data,
                                        SilcUInt32 data_len,
                                        bool force_send);
 void silc_server_packet_relay_to_channel(SilcServer server,
                                         SilcSocketConnection sender_sock,
                                         SilcChannelEntry channel,
-                                        void *sender_id, 
+                                        void *sender_id,
                                         SilcIdType sender_type,
                                         SilcClientEntry sender_entry,
                                         unsigned char *data,
@@ -142,7 +143,8 @@ void silc_server_send_notify_cmode(SilcServer server,
                                   void *id, SilcIdType id_type,
                                   const char *cipher, const char *hmac,
                                   const char *passphrase,
-                                  SilcPublicKey founder_key);
+                                  SilcPublicKey founder_key,
+                                  SilcBuffer channel_pubkeys);
 void silc_server_send_notify_cumode(SilcServer server,
                                    SilcSocketConnection sock,
                                    bool broadcast,
@@ -210,6 +212,7 @@ void silc_server_send_notify_to_channel(SilcServer server,
                                        SilcSocketConnection sender,
                                        SilcChannelEntry channel,
                                        bool route_notify,
+                                       bool send_to_clients,
                                        SilcNotifyType type,
                                        SilcUInt32 argc, ...);
 void silc_server_send_notify_on_channels(SilcServer server,
@@ -220,36 +223,36 @@ void silc_server_send_notify_on_channels(SilcServer server,
 void silc_server_send_new_id(SilcServer server,
                             SilcSocketConnection sock,
                             bool broadcast,
-                            void *id, SilcIdType id_type, 
+                            void *id, SilcIdType id_type,
                             SilcUInt32 id_len);
 void silc_server_send_new_channel(SilcServer server,
                                  SilcSocketConnection sock,
                                  bool broadcast,
                                  char *channel_name,
-                                 void *channel_id, 
+                                 void *channel_id,
                                  SilcUInt32 channel_id_len,
                                  SilcUInt32 mode);
 void silc_server_send_channel_key(SilcServer server,
                                  SilcSocketConnection sender,
                                  SilcChannelEntry channel,
                                  unsigned char route);
-void silc_server_send_command(SilcServer server, 
+void silc_server_send_command(SilcServer server,
                              SilcSocketConnection sock,
-                             SilcCommand command, 
+                             SilcCommand command,
                              SilcUInt16 ident,
                              SilcUInt32 argc, ...);
-void silc_server_send_command_reply(SilcServer server, 
+void silc_server_send_command_reply(SilcServer server,
                                    SilcSocketConnection sock,
-                                   SilcCommand command, 
+                                   SilcCommand command,
                                    SilcStatus status,
                                    SilcStatus error,
                                    SilcUInt16 ident,
                                    SilcUInt32 argc, ...);
-void silc_server_send_dest_command_reply(SilcServer server, 
+void silc_server_send_dest_command_reply(SilcServer server,
                                         SilcSocketConnection sock,
                                         void *dst_id,
                                         SilcIdType dst_id_type,
-                                        SilcCommand command, 
+                                        SilcCommand command,
                                         SilcStatus status,
                                         SilcStatus error,
                                         SilcUInt16 ident,
@@ -273,7 +276,7 @@ void silc_server_send_opers(SilcServer server,
                            SilcPacketType type,
                            SilcPacketFlags flags,
                            bool route, bool local,
-                           unsigned char *data, 
+                           unsigned char *data,
                            SilcUInt32 data_len,
                            bool force_send);
 void silc_server_send_opers_notify(SilcServer server,
index aac2ff7f81254937dacd6d01315f433bd5d54c0a..f232c3d84f94cb86384443fe1b7f766a502451d9 100644 (file)
@@ -4,13 +4,13 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2002 Pekka Riikonen
+  Copyright (C) 1997 - 2003 Pekka Riikonen
 
   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
@@ -33,17 +33,17 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey);
  * Key Exhange protocol functions
  */
 
-static bool 
+static bool
 silc_verify_public_key_internal(SilcServer server, SilcSocketConnection sock,
                                SilcSocketType conn_type,
-                               unsigned char *pk, SilcUInt32 pk_len, 
+                               unsigned char *pk, SilcUInt32 pk_len,
                                SilcSKEPKType pk_type)
 {
   char file[256], filename[256], *fingerprint;
   struct stat st;
 
   if (pk_type != SILC_SKE_PK_TYPE_SILC) {
-    SILC_LOG_WARNING(("We don't support %s (%s) port %d public key type %d", 
+    SILC_LOG_WARNING(("We don't support %s (%s) port %d public key type %d",
                      sock->hostname, sock->ip, sock->port, pk_type));
     return FALSE;
   }
@@ -60,20 +60,20 @@ silc_verify_public_key_internal(SilcServer server, SilcSocketConnection sock,
      conn auth protocol with public key we MUST have the key already. */
   return TRUE;
   /* Rest is unreachable code! */
-  
+
   memset(filename, 0, sizeof(filename));
   memset(file, 0, sizeof(file));
-  snprintf(file, sizeof(file) - 1, "serverkey_%s_%d.pub", sock->hostname, 
+  snprintf(file, sizeof(file) - 1, "serverkey_%s_%d.pub", sock->hostname,
           sock->port);
-  snprintf(filename, sizeof(filename) - 1, SILC_ETCDIR "/serverkeys/%s", 
+  snprintf(filename, sizeof(filename) - 1, SILC_ETCDIR "/serverkeys/%s",
           file);
 
   /* Create serverkeys directory if it doesn't exist. */
   if (stat(SILC_ETCDIR "/serverkeys", &st) < 0) {
     /* If dir doesn't exist */
-    if (errno == ENOENT) {  
+    if (errno == ENOENT) {
       if (mkdir(SILC_ETCDIR "/serverkeys", 0755) < 0) {
-       SILC_LOG_ERROR(("Couldn't create `%s' directory\n", 
+       SILC_LOG_ERROR(("Couldn't create `%s' directory\n",
                        SILC_ETCDIR "/serverkeys"));
        return TRUE;
       }
@@ -85,7 +85,7 @@ silc_verify_public_key_internal(SilcServer server, SilcSocketConnection sock,
 
   /* Take fingerprint of the public key */
   fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
-  SILC_LOG_DEBUG(("Received server %s (%s) port %d public key (%s)", 
+  SILC_LOG_DEBUG(("Received server %s (%s) port %d public key (%s)",
                  sock->hostname, sock->ip, sock->port, fingerprint));
   silc_free(fingerprint);
 
@@ -94,7 +94,7 @@ silc_verify_public_key_internal(SilcServer server, SilcSocketConnection sock,
     /* We don't have it, then cache it. */
     SILC_LOG_DEBUG(("New public key from server"));
 
-    silc_pkcs_save_public_key_data(filename, pk, pk_len, 
+    silc_pkcs_save_public_key_data(filename, pk, pk_len,
                                   SILC_PKCS_FILE_PEM);
     return TRUE;
   } else {
@@ -106,12 +106,12 @@ silc_verify_public_key_internal(SilcServer server, SilcSocketConnection sock,
     SILC_LOG_DEBUG(("We have the public key saved locally"));
 
     /* Load the key file */
-    if (!silc_pkcs_load_public_key(filename, &public_key, 
+    if (!silc_pkcs_load_public_key(filename, &public_key,
                                   SILC_PKCS_FILE_PEM))
-      if (!silc_pkcs_load_public_key(filename, &public_key, 
+      if (!silc_pkcs_load_public_key(filename, &public_key,
                                     SILC_PKCS_FILE_BIN)) {
        SILC_LOG_WARNING(("Could not load local copy of the %s (%s) port %d "
-                         "server public key", sock->hostname, sock->ip, 
+                         "server public key", sock->hostname, sock->ip,
                          sock->port));
 
        /* Save the key for future checking */
@@ -120,7 +120,7 @@ silc_verify_public_key_internal(SilcServer server, SilcSocketConnection sock,
                                       SILC_PKCS_FILE_PEM);
        return TRUE;
       }
-  
+
     /* Encode the key data */
     encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
     if (!encpk) {
@@ -135,7 +135,7 @@ silc_verify_public_key_internal(SilcServer server, SilcSocketConnection sock,
 
     if (memcmp(pk, encpk, encpk_len)) {
       SILC_LOG_WARNING(("%s (%s) port %d server public key does not match "
-                       "with local copy", sock->hostname, sock->ip, 
+                       "with local copy", sock->hostname, sock->ip,
                        sock->port));
       SILC_LOG_WARNING(("It is possible that the key has expired or changed"));
       SILC_LOG_WARNING(("It is also possible that some one is performing "
@@ -154,7 +154,7 @@ silc_verify_public_key_internal(SilcServer server, SilcSocketConnection sock,
 /* Callback that is called when we have received KE2 payload from
    responder. We try to verify the public key now. */
 
-static void 
+static void
 silc_server_protocol_ke_verify_key(SilcSKE ske,
                                   unsigned char *pk_data,
                                   SilcUInt32 pk_len,
@@ -164,14 +164,14 @@ silc_server_protocol_ke_verify_key(SilcSKE ske,
                                   void *completion_context)
 {
   SilcProtocol protocol = (SilcProtocol)context;
-  SilcServerKEInternalContext *ctx = 
+  SilcServerKEInternalContext *ctx =
     (SilcServerKEInternalContext *)protocol->context;
   SilcServer server = (SilcServer)ctx->server;
 
   SILC_LOG_DEBUG(("Verifying received public key"));
 
   if (silc_verify_public_key_internal(
-                 server, ctx->sock, 
+                 server, ctx->sock,
                  (ctx->responder == FALSE ?
                   SILC_SOCKET_TYPE_ROUTER:
                   ctx->sconfig.ref_ptr ? SILC_SOCKET_TYPE_SERVER :
@@ -180,7 +180,7 @@ silc_server_protocol_ke_verify_key(SilcSKE ske,
                  pk_data, pk_len, pk_type))
     completion(ske, SILC_SKE_STATUS_OK, completion_context);
   else
-    completion(ske, SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY, 
+    completion(ske, SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY,
               completion_context);
 }
 
@@ -193,7 +193,7 @@ static void silc_server_protocol_ke_send_packet(SilcSKE ske,
                                                void *context)
 {
   SilcProtocol protocol = (SilcProtocol)context;
-  SilcServerKEInternalContext *ctx = 
+  SilcServerKEInternalContext *ctx =
     (SilcServerKEInternalContext *)protocol->context;
   SilcServer server = (SilcServer)ctx->server;
 
@@ -235,49 +235,49 @@ int silc_server_protocol_ke_set_keys(SilcServer server,
     SILC_LOG_ERROR(("Cannot allocate algorithm: %s", cname));
     return FALSE;
   }
-  
-  if (!silc_hmac_alloc((char *)silc_hmac_get_name(hmac), NULL, 
+
+  if (!silc_hmac_alloc((char *)silc_hmac_get_name(hmac), NULL,
                       &idata->hmac_send)) {
     silc_cipher_free(idata->send_key);
     silc_cipher_free(idata->receive_key);
     silc_free(conn_data);
-    SILC_LOG_ERROR(("Cannot allocate algorithm: %s", 
+    SILC_LOG_ERROR(("Cannot allocate algorithm: %s",
                    silc_hmac_get_name(hmac)));
     return FALSE;
   }
 
-  if (!silc_hmac_alloc((char *)silc_hmac_get_name(hmac), NULL, 
+  if (!silc_hmac_alloc((char *)silc_hmac_get_name(hmac), NULL,
                       &idata->hmac_receive)) {
     silc_cipher_free(idata->send_key);
     silc_cipher_free(idata->receive_key);
     silc_hmac_free(idata->hmac_send);
     silc_free(conn_data);
-    SILC_LOG_ERROR(("Cannot allocate algorithm: %s", 
+    SILC_LOG_ERROR(("Cannot allocate algorithm: %s",
                    silc_hmac_get_name(hmac)));
     return FALSE;
   }
 
   if (is_responder == TRUE) {
-    silc_cipher_set_key(idata->send_key, keymat->receive_enc_key, 
+    silc_cipher_set_key(idata->send_key, keymat->receive_enc_key,
                        keymat->enc_key_len);
     silc_cipher_set_iv(idata->send_key, keymat->receive_iv);
-    silc_cipher_set_key(idata->receive_key, keymat->send_enc_key, 
+    silc_cipher_set_key(idata->receive_key, keymat->send_enc_key,
                        keymat->enc_key_len);
     silc_cipher_set_iv(idata->receive_key, keymat->send_iv);
-    silc_hmac_set_key(idata->hmac_send, keymat->receive_hmac_key, 
+    silc_hmac_set_key(idata->hmac_send, keymat->receive_hmac_key,
                      keymat->hmac_key_len);
-    silc_hmac_set_key(idata->hmac_receive, keymat->send_hmac_key, 
+    silc_hmac_set_key(idata->hmac_receive, keymat->send_hmac_key,
                      keymat->hmac_key_len);
   } else {
-    silc_cipher_set_key(idata->send_key, keymat->send_enc_key, 
+    silc_cipher_set_key(idata->send_key, keymat->send_enc_key,
                        keymat->enc_key_len);
     silc_cipher_set_iv(idata->send_key, keymat->send_iv);
-    silc_cipher_set_key(idata->receive_key, keymat->receive_enc_key, 
+    silc_cipher_set_key(idata->receive_key, keymat->receive_enc_key,
                        keymat->enc_key_len);
     silc_cipher_set_iv(idata->receive_key, keymat->receive_iv);
-    silc_hmac_set_key(idata->hmac_send, keymat->send_hmac_key, 
+    silc_hmac_set_key(idata->hmac_send, keymat->send_hmac_key,
                      keymat->hmac_key_len);
-    silc_hmac_set_key(idata->hmac_receive, keymat->receive_hmac_key, 
+    silc_hmac_set_key(idata->hmac_receive, keymat->receive_hmac_key,
                      keymat->hmac_key_len);
   }
 
@@ -297,13 +297,13 @@ int silc_server_protocol_ke_set_keys(SilcServer server,
     silc_hmac_free(idata->hmac_send);
     silc_hmac_free(idata->hmac_receive);
     silc_free(conn_data);
-    SILC_LOG_ERROR(("Cannot allocate algorithm: %s", 
+    SILC_LOG_ERROR(("Cannot allocate algorithm: %s",
                    silc_hash_get_name(hash)));
     return FALSE;
   }
 
   /* Save the remote host's public key */
-  silc_pkcs_public_key_decode(ske->ke1_payload->pk_data, 
+  silc_pkcs_public_key_decode(ske->ke1_payload->pk_data,
                              ske->ke1_payload->pk_len, &idata->public_key);
   if (ske->prop->flags & SILC_SKE_SP_FLAG_MUTUAL)
     silc_hash_make(server->sha1hash, ske->ke1_payload->pk_data,
@@ -311,7 +311,7 @@ int silc_server_protocol_ke_set_keys(SilcServer server,
 
   sock->user_data = (void *)conn_data;
 
-  SILC_LOG_INFO(("%s (%s) security properties: %s %s %s %s", 
+  SILC_LOG_INFO(("%s (%s) security properties: %s %s %s %s",
                 sock->hostname, sock->ip,
                 silc_cipher_get_name(idata->send_key),
                 (char *)silc_hmac_get_name(idata->hmac_send),
@@ -333,22 +333,22 @@ SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version,
 
   if (!silc_parse_version_string(version, &r_protocol_version, NULL, NULL,
                                 NULL, NULL)) {
-    SILC_LOG_ERROR(("%s (%s) %s is not allowed/supported version", 
+    SILC_LOG_ERROR(("%s (%s) %s is not allowed/supported version",
                    ske->sock->hostname, ske->sock->ip, version));
     return SILC_SKE_STATUS_BAD_VERSION;
   }
 
-  if (!silc_parse_version_string(silc_version_string, 
+  if (!silc_parse_version_string(silc_version_string,
                                 &l_protocol_version, NULL, NULL,
                                 NULL, NULL)) {
-    SILC_LOG_ERROR(("%s (%s) %s is not allowed/supported version", 
+    SILC_LOG_ERROR(("%s (%s) %s is not allowed/supported version",
                    ske->sock->hostname, ske->sock->ip, version));
     return SILC_SKE_STATUS_BAD_VERSION;
   }
 
   /* If remote is too new, don't connect */
   if (l_protocol_version < r_protocol_version) {
-    SILC_LOG_ERROR(("%s (%s) %s is not allowed/supported version", 
+    SILC_LOG_ERROR(("%s (%s) %s is not allowed/supported version",
                    ske->sock->hostname, ske->sock->ip, version));
     return SILC_SKE_STATUS_BAD_VERSION;
   }
@@ -369,7 +369,7 @@ SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version,
 static void silc_server_protocol_ke_continue(SilcSKE ske, void *context)
 {
   SilcProtocol protocol = (SilcProtocol)context;
-  SilcServerKEInternalContext *ctx = 
+  SilcServerKEInternalContext *ctx =
     (SilcServerKEInternalContext *)protocol->context;
   SilcServer server = (SilcServer)ctx->server;
 
@@ -393,7 +393,7 @@ static void silc_server_protocol_ke_continue(SilcSKE ske, void *context)
     protocol->state = SILC_PROTOCOL_STATE_END;
   }
 
-  /* Advance protocol state and call the next state if we are responder. 
+  /* Advance protocol state and call the next state if we are responder.
      This happens when this callback was sent to silc_ske_responder_phase_2
      function. */
   if (ctx->responder == TRUE) {
@@ -409,7 +409,7 @@ static void silc_server_protocol_ke_continue(SilcSKE ske, void *context)
 SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
 {
   SilcProtocol protocol = (SilcProtocol)context;
-  SilcServerKEInternalContext *ctx = 
+  SilcServerKEInternalContext *ctx =
     (SilcServerKEInternalContext *)protocol->context;
   SilcServer server = (SilcServer)ctx->server;
   SilcSKEStatus status = SILC_SKE_STATUS_OK;
@@ -429,12 +429,12 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
 
       /* Allocate Key Exchange object */
       ctx->ske = ske = silc_ske_alloc(server->rng, server);
-      
+
       silc_ske_set_callbacks(ske, silc_server_protocol_ke_send_packet, NULL,
                             silc_server_protocol_ke_verify_key,
                             silc_server_protocol_ke_continue,
                             silc_ske_check_version, context);
-      
+
       if (ctx->responder == TRUE) {
        /* Start the key exchange by processing the received security
           properties packet from initiator. */
@@ -448,7 +448,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
        SILC_LOG_DEBUG(("Send security property list (KE)"));
 
        /* Assemble security properties. */
-       silc_ske_assemble_security_properties(ske, ctx->flags, 
+       silc_ske_assemble_security_properties(ske, ctx->flags,
                                              silc_version_string,
                                              &start_payload);
 
@@ -480,8 +480,8 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
     break;
   case 2:
     {
-      /* 
-       * Phase 1 
+      /*
+       * Phase 1
        */
       if (ctx->responder == TRUE) {
        /* Sends the selected security properties to the initiator. */
@@ -518,8 +518,8 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
     break;
   case 3:
     {
-      /* 
-       * Phase 2 
+      /*
+       * Phase 2
        */
       if (ctx->responder == TRUE) {
        /* Process the received Key Exchange 1 Payload packet from
@@ -557,15 +557,15 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
     break;
   case 4:
     {
-      /* 
+      /*
        * Finish protocol
        */
       if (ctx->responder == TRUE) {
        /* This creates the key exchange material and sends our
           public parts to the initiator inside Key Exchange 2 Payload. */
        SILC_LOG_DEBUG(("Process KE2 packet"));
-       status = silc_ske_responder_finish(ctx->ske, 
-                                          server->public_key, 
+       status = silc_ske_responder_finish(ctx->ske,
+                                          server->public_key,
                                           server->private_key,
                                           SILC_SKE_PK_TYPE_SILC);
 
@@ -597,7 +597,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
 
   case SILC_PROTOCOL_STATE_END:
     {
-      /* 
+      /*
        * End protocol
        */
       SilcSKEKeyMaterial *keymat;
@@ -628,14 +628,14 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
        silc_ske_end(ctx->ske);
       }
 
-      /* Unregister the timeout task since the protocol has ended. 
+      /* Unregister the timeout task since the protocol has ended.
         This was the timeout task to be executed if the protocol is
         not completed fast enough. */
       if (ctx->timeout_task)
        silc_schedule_task_del(server->schedule, ctx->timeout_task);
 
       /* Assure that after calling final callback there cannot be pending
-        executions for this protocol anymore. This just unregisters any 
+        executions for this protocol anymore. This just unregisters any
         timeout callbacks for this protocol. */
       silc_protocol_cancel(protocol, server->schedule);
 
@@ -655,14 +655,14 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
     /* Send abort notification */
     silc_ske_abort(ctx->ske, ctx->ske->status);
 
-    /* Unregister the timeout task since the protocol has ended. 
+    /* Unregister the timeout task since the protocol has ended.
        This was the timeout task to be executed if the protocol is
        not completed fast enough. */
     if (ctx->timeout_task)
       silc_schedule_task_del(server->schedule, ctx->timeout_task);
 
     /* Assure that after calling final callback there cannot be pending
-       executions for this protocol anymore. This just unregisters any 
+       executions for this protocol anymore. This just unregisters any
        timeout callbacks for this protocol. */
     silc_protocol_cancel(protocol, server->schedule);
 
@@ -678,17 +678,17 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
      * We have received failure from remote
      */
 
-    /* Unregister the timeout task since the protocol has ended. 
+    /* Unregister the timeout task since the protocol has ended.
        This was the timeout task to be executed if the protocol is
        not completed fast enough. */
     if (ctx->timeout_task)
       silc_schedule_task_del(server->schedule, ctx->timeout_task);
 
     /* Assure that after calling final callback there cannot be pending
-       executions for this protocol anymore. This just unregisters any 
+       executions for this protocol anymore. This just unregisters any
        timeout callbacks for this protocol. */
     silc_protocol_cancel(protocol, server->schedule);
-    
+
     /* On error the final callback is always called. */
     if (protocol->final_callback)
       silc_protocol_execute_final(protocol, server->schedule);
@@ -705,8 +705,8 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
  * Connection Authentication protocol functions
  */
 
-static int 
-silc_server_password_authentication(SilcServer server, char *local_auth, 
+static int
+silc_server_password_authentication(SilcServer server, char *local_auth,
                                    char *remote_auth)
 {
   if (!remote_auth || !local_auth || strlen(local_auth) != strlen(remote_auth))
@@ -750,7 +750,7 @@ silc_server_public_key_authentication(SilcServer server,
                     SILC_STR_END);
 
   /* Verify signature */
-  if (silc_pkcs_verify_with_hash(pkcs, ske->prop->hash, sign, sign_len, 
+  if (silc_pkcs_verify_with_hash(pkcs, ske->prop->hash, sign, sign_len,
                                 auth->data, auth->len)) {
     silc_pkcs_free(pkcs);
     silc_buffer_free(auth);
@@ -787,7 +787,7 @@ silc_server_get_public_key_auth(SilcServer server,
 
   *auth_data = silc_calloc((silc_pkcs_get_key_len(pkcs) / 8) + 1,
                           sizeof(**auth_data));
-  if (silc_pkcs_sign_with_hash(pkcs, ske->prop->hash, auth->data, 
+  if (silc_pkcs_sign_with_hash(pkcs, ske->prop->hash, auth->data,
                               auth->len, *auth_data, auth_data_len)) {
     silc_buffer_free(auth);
     return TRUE;
@@ -803,7 +803,7 @@ silc_server_get_public_key_auth(SilcServer server,
 /* Function that actually performs the authentication to the remote. This
    supports both passphrase and public key authentication. */
 
-static bool 
+static bool
 silc_server_get_authentication(SilcServerConnAuthInternalContext *ctx,
                               char *local_passphrase,
                               SilcHashTable local_publickeys,
@@ -816,7 +816,7 @@ silc_server_get_authentication(SilcServerConnAuthInternalContext *ctx,
 
   /* If we don't have authentication data set at all we do not require
      authentication at all */
-  if (!local_passphrase && (!local_publickeys || 
+  if (!local_passphrase && (!local_publickeys ||
                            !silc_hash_table_count(local_publickeys))) {
     SILC_LOG_DEBUG(("No authentication required"));
     return TRUE;
@@ -836,7 +836,7 @@ silc_server_get_authentication(SilcServerConnAuthInternalContext *ctx,
   /* Try public key authenetication */
   if (!result && local_publickeys) {
     SilcPublicKey cached_key;
-    SilcPublicKey remote_key = 
+    SilcPublicKey remote_key =
       ((SilcIDListData)ctx->sock->user_data)->public_key;
 
     SILC_LOG_DEBUG(("Public key authentication"));
@@ -857,14 +857,14 @@ silc_server_get_authentication(SilcServerConnAuthInternalContext *ctx,
   return result;
 }
 
-/* Performs connection authentication protocol. If responder, we 
+/* Performs connection authentication protocol. If responder, we
    authenticate the remote data received. If initiator, we will send
    authentication data to the remote end. */
 
 SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
 {
   SilcProtocol protocol = (SilcProtocol)context;
-  SilcServerConnAuthInternalContext *ctx = 
+  SilcServerConnAuthInternalContext *ctx =
     (SilcServerConnAuthInternalContext *)protocol->context;
   SilcServer server = (SilcServer)ctx->server;
 
@@ -876,7 +876,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
   switch(protocol->state) {
   case SILC_PROTOCOL_STATE_START:
     {
-      /* 
+      /*
        * Start protocol.
        */
 
@@ -904,17 +904,17 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
          silc_protocol_execute(protocol, server->schedule, 0, 300000);
          return;
        }
-       
+
        if (payload_len != ctx->packet->buffer->len) {
          SILC_LOG_ERROR(("Bad payload length in authentication packet"));
          protocol->state = SILC_PROTOCOL_STATE_ERROR;
          silc_protocol_execute(protocol, server->schedule, 0, 300000);
          return;
        }
-       
+
        payload_len -= 4;
-       
-       if (conn_type < SILC_SOCKET_TYPE_CLIENT || 
+
+       if (conn_type < SILC_SOCKET_TYPE_CLIENT ||
            conn_type > SILC_SOCKET_TYPE_ROUTER) {
          SILC_LOG_ERROR(("Bad connection type (%d) in authentication packet",
                          conn_type));
@@ -922,12 +922,12 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
          silc_protocol_execute(protocol, server->schedule, 0, 300000);
          return;
        }
-       
+
        if (payload_len > 0) {
          /* Get authentication data */
          silc_buffer_pull(ctx->packet->buffer, 4);
          ret = silc_buffer_unformat(ctx->packet->buffer,
-                                    SILC_STR_UI_XNSTRING_ALLOC(&auth_data, 
+                                    SILC_STR_UI_XNSTRING_ALLOC(&auth_data,
                                                                payload_len),
                                     SILC_STR_END);
          if (ret == -1) {
@@ -938,7 +938,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
          }
        }
 
-       /* 
+       /*
         * Check the remote connection type and make sure that we have
         * configured this connection. If we haven't allowed this connection
         * the authentication must be failed.
@@ -967,12 +967,12 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
            SILC_LOG_ERROR(("Authentication failed"));
            silc_free(auth_data);
            protocol->state = SILC_PROTOCOL_STATE_ERROR;
-           silc_protocol_execute(protocol, server->schedule, 
+           silc_protocol_execute(protocol, server->schedule,
                                  0, 300000);
            return;
          }
        }
-       
+
        /* Remote end is server */
        if (conn_type == SILC_SOCKET_TYPE_SERVER) {
          SilcServerConfigServer *serv = ctx->sconfig.ref_ptr;
@@ -993,13 +993,13 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
            SILC_LOG_ERROR(("Remote server connection not configured"));
            SILC_LOG_ERROR(("Authentication failed"));
            protocol->state = SILC_PROTOCOL_STATE_ERROR;
-           silc_protocol_execute(protocol, server->schedule, 
+           silc_protocol_execute(protocol, server->schedule,
                                  0, 300000);
            silc_free(auth_data);
            return;
          }
        }
-       
+
        /* Remote end is router */
        if (conn_type == SILC_SOCKET_TYPE_ROUTER) {
          SilcServerConfigRouter *serv = ctx->rconfig.ref_ptr;
@@ -1021,38 +1021,38 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
            SILC_LOG_ERROR(("Authentication failed"));
            silc_free(auth_data);
            protocol->state = SILC_PROTOCOL_STATE_ERROR;
-           silc_protocol_execute(protocol, server->schedule, 
+           silc_protocol_execute(protocol, server->schedule,
                                  0, 300000);
            return;
          }
        }
-       
+
        silc_free(auth_data);
 
        /* Save connection type. This is later used to create the
           ID for the connection. */
        ctx->conn_type = conn_type;
-         
+
        /* Advance protocol state. */
        protocol->state = SILC_PROTOCOL_STATE_END;
        silc_protocol_execute(protocol, server->schedule, 0, 0);
 
       } else {
-       /* 
+       /*
         * We are initiator. We are authenticating ourselves to a
         * remote server. We will send the authentication data to the
-        * other end for verify. 
+        * other end for verify.
         */
        SilcBuffer packet;
        int payload_len = 0;
        unsigned char *auth_data = NULL;
        SilcUInt32 auth_data_len = 0;
-       
+
        switch(ctx->auth_meth) {
        case SILC_AUTH_NONE:
          /* No authentication required */
          break;
-         
+
        case SILC_AUTH_PASSWORD:
          /* Password authentication */
          if (ctx->auth_data && ctx->auth_data_len) {
@@ -1061,7 +1061,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
            break;
          }
          break;
-         
+
        case SILC_AUTH_PUBLIC_KEY:
          {
            /* Public key authentication */
@@ -1070,30 +1070,30 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
            break;
          }
        }
-       
+
        payload_len = 4 + auth_data_len;
        packet = silc_buffer_alloc(payload_len);
        silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
        silc_buffer_format(packet,
                           SILC_STR_UI_SHORT(payload_len),
-                          SILC_STR_UI_SHORT(server->server_type 
+                          SILC_STR_UI_SHORT(server->server_type
                                              == SILC_SERVER ?
                                              SILC_SOCKET_TYPE_SERVER :
                                              SILC_SOCKET_TYPE_ROUTER),
                           SILC_STR_UI_XNSTRING(auth_data, auth_data_len),
                           SILC_STR_END);
-       
+
        /* Send the packet to server */
        silc_server_packet_send(server, ctx->sock,
-                               SILC_PACKET_CONNECTION_AUTH, 0, 
+                               SILC_PACKET_CONNECTION_AUTH, 0,
                                packet->data, packet->len, TRUE);
-       
+
        if (auth_data) {
          memset(auth_data, 0, auth_data_len);
          silc_free(auth_data);
        }
        silc_buffer_free(packet);
-       
+
        /* Next state is end of protocol */
        protocol->state = SILC_PROTOCOL_STATE_END;
       }
@@ -1102,7 +1102,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
 
   case SILC_PROTOCOL_STATE_END:
     {
-      /* 
+      /*
        * End protocol
        */
       unsigned char ok[4];
@@ -1113,17 +1113,17 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
       silc_server_packet_send(server, ctx->sock, SILC_PACKET_SUCCESS,
                              0, ok, 4, TRUE);
 
-      /* Unregister the timeout task since the protocol has ended. 
+      /* Unregister the timeout task since the protocol has ended.
         This was the timeout task to be executed if the protocol is
         not completed fast enough. */
       if (ctx->timeout_task)
        silc_schedule_task_del(server->schedule, ctx->timeout_task);
 
       /* Assure that after calling final callback there cannot be pending
-        executions for this protocol anymore. This just unregisters any 
+        executions for this protocol anymore. This just unregisters any
         timeout callbacks for this protocol. */
       silc_protocol_cancel(protocol, server->schedule);
-    
+
       /* Protocol has ended, call the final callback */
       if (protocol->final_callback)
        silc_protocol_execute_final(protocol, server->schedule);
@@ -1143,17 +1143,17 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
       silc_server_packet_send(server, ctx->sock, SILC_PACKET_FAILURE,
                              0, error, 4, TRUE);
 
-      /* Unregister the timeout task since the protocol has ended. 
+      /* Unregister the timeout task since the protocol has ended.
         This was the timeout task to be executed if the protocol is
         not completed fast enough. */
       if (ctx->timeout_task)
        silc_schedule_task_del(server->schedule, ctx->timeout_task);
 
       /* Assure that after calling final callback there cannot be pending
-        executions for this protocol anymore. This just unregisters any 
+        executions for this protocol anymore. This just unregisters any
         timeout callbacks for this protocol. */
       silc_protocol_cancel(protocol, server->schedule);
-    
+
       /* On error the final callback is always called. */
       if (protocol->final_callback)
        silc_protocol_execute_final(protocol, server->schedule);
@@ -1169,17 +1169,17 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
 
     SILC_LOG_ERROR(("Received Authentication Failure"));
 
-    /* Unregister the timeout task since the protocol has ended. 
+    /* Unregister the timeout task since the protocol has ended.
        This was the timeout task to be executed if the protocol is
        not completed fast enough. */
     if (ctx->timeout_task)
       silc_schedule_task_del(server->schedule, ctx->timeout_task);
 
     /* Assure that after calling final callback there cannot be pending
-       executions for this protocol anymore. This just unregisters any 
+       executions for this protocol anymore. This just unregisters any
        timeout callbacks for this protocol. */
     silc_protocol_cancel(protocol, server->schedule);
-    
+
     /* On error the final callback is always called. */
     if (protocol->final_callback)
       silc_protocol_execute_final(protocol, server->schedule);
@@ -1198,7 +1198,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
 
 /* Actually takes the new keys into use. */
 
-static void 
+static void
 silc_server_protocol_rekey_validate(SilcServer server,
                                    SilcServerRekeyInternalContext *ctx,
                                    SilcIDListData idata,
@@ -1207,30 +1207,30 @@ silc_server_protocol_rekey_validate(SilcServer server,
 {
   if (ctx->responder == TRUE) {
     if (send) {
-      silc_cipher_set_key(idata->send_key, keymat->receive_enc_key, 
+      silc_cipher_set_key(idata->send_key, keymat->receive_enc_key,
                          keymat->enc_key_len);
       silc_cipher_set_iv(idata->send_key, keymat->receive_iv);
-      silc_hmac_set_key(idata->hmac_send, keymat->receive_hmac_key, 
+      silc_hmac_set_key(idata->hmac_send, keymat->receive_hmac_key,
                        keymat->hmac_key_len);
     } else {
-      silc_cipher_set_key(idata->receive_key, keymat->send_enc_key, 
+      silc_cipher_set_key(idata->receive_key, keymat->send_enc_key,
                          keymat->enc_key_len);
       silc_cipher_set_iv(idata->receive_key, keymat->send_iv);
-      silc_hmac_set_key(idata->hmac_receive, keymat->send_hmac_key, 
+      silc_hmac_set_key(idata->hmac_receive, keymat->send_hmac_key,
                        keymat->hmac_key_len);
     }
   } else {
     if (send) {
-      silc_cipher_set_key(idata->send_key, keymat->send_enc_key, 
+      silc_cipher_set_key(idata->send_key, keymat->send_enc_key,
                          keymat->enc_key_len);
       silc_cipher_set_iv(idata->send_key, keymat->send_iv);
-      silc_hmac_set_key(idata->hmac_send, keymat->send_hmac_key, 
+      silc_hmac_set_key(idata->hmac_send, keymat->send_hmac_key,
                        keymat->hmac_key_len);
     } else {
-      silc_cipher_set_key(idata->receive_key, keymat->receive_enc_key, 
+      silc_cipher_set_key(idata->receive_key, keymat->receive_enc_key,
                          keymat->enc_key_len);
       silc_cipher_set_iv(idata->receive_key, keymat->receive_iv);
-      silc_hmac_set_key(idata->hmac_receive, keymat->receive_hmac_key, 
+      silc_hmac_set_key(idata->hmac_receive, keymat->receive_hmac_key,
                        keymat->hmac_key_len);
     }
   }
@@ -1264,7 +1264,7 @@ void silc_server_protocol_rekey_generate(SilcServer server,
   keymat = silc_calloc(1, sizeof(*keymat));
   silc_ske_process_key_material_data(idata->rekey->send_enc_key,
                                     idata->rekey->enc_key_len,
-                                    16, key_len, hash_len, 
+                                    16, key_len, hash_len,
                                     idata->hash, keymat);
 
   /* Set the keys into use */
@@ -1276,7 +1276,7 @@ void silc_server_protocol_rekey_generate(SilcServer server,
 /* This function actually re-generates (with PFS) the keys and
    takes them into use. */
 
-void 
+void
 silc_server_protocol_rekey_generate_pfs(SilcServer server,
                                        SilcServerRekeyInternalContext *ctx,
                                        bool send)
@@ -1296,7 +1296,7 @@ silc_server_protocol_rekey_generate_pfs(SilcServer server,
 
   /* Generate the new key */
   keymat = silc_calloc(1, sizeof(*keymat));
-  silc_ske_process_key_material_data(tmpbuf, klen, 16, key_len, hash_len, 
+  silc_ske_process_key_material_data(tmpbuf, klen, 16, key_len, hash_len,
                                     idata->hash, keymat);
 
   /* Set the keys into use */
@@ -1310,14 +1310,14 @@ silc_server_protocol_rekey_generate_pfs(SilcServer server,
 /* Packet sending callback. This function is provided as packet sending
    routine to the Key Exchange functions. */
 
-static void 
+static void
 silc_server_protocol_rekey_send_packet(SilcSKE ske,
                                       SilcBuffer packet,
                                       SilcPacketType type,
                                       void *context)
 {
   SilcProtocol protocol = (SilcProtocol)context;
-  SilcServerRekeyInternalContext *ctx = 
+  SilcServerRekeyInternalContext *ctx =
     (SilcServerRekeyInternalContext *)protocol->context;
   SilcServer server = (SilcServer)ctx->server;
 
@@ -1331,7 +1331,7 @@ silc_server_protocol_rekey_send_packet(SilcSKE ske,
 SILC_TASK_CALLBACK(silc_server_protocol_rekey)
 {
   SilcProtocol protocol = (SilcProtocol)context;
-  SilcServerRekeyInternalContext *ctx = 
+  SilcServerRekeyInternalContext *ctx =
     (SilcServerRekeyInternalContext *)protocol->context;
   SilcServer server = (SilcServer)ctx->server;
   SilcIDListData idata = (SilcIDListData)ctx->sock->user_data;
@@ -1345,7 +1345,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey)
   switch(protocol->state) {
   case SILC_PROTOCOL_STATE_START:
     {
-      /* 
+      /*
        * Start protocol.
        */
 
@@ -1355,7 +1355,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey)
         */
 
        if (ctx->pfs == TRUE) {
-         /* 
+         /*
           * Use Perfect Forward Secrecy, ie. negotiate the key material
           * using the SKE protocol.
           */
@@ -1363,7 +1363,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey)
          if (ctx->packet->type != SILC_PACKET_KEY_EXCHANGE_1) {
            SILC_LOG_ERROR(("Error during Re-key (R PFS): re-key state is "
                            "incorrect (received %d, expected %d packet), "
-                           "with %s (%s)", ctx->packet->type, 
+                           "with %s (%s)", ctx->packet->type,
                            SILC_PACKET_KEY_EXCHANGE_1, ctx->sock->hostname,
                            ctx->sock->ip));
            protocol->state = SILC_PROTOCOL_STATE_ERROR;
@@ -1376,11 +1376,11 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey)
          silc_ske_group_get_by_number(idata->rekey->ske_group,
                                       &ctx->ske->prop->group);
 
-         silc_ske_set_callbacks(ctx->ske, 
-                                silc_server_protocol_rekey_send_packet, 
+         silc_ske_set_callbacks(ctx->ske,
+                                silc_server_protocol_rekey_send_packet,
                                 NULL, NULL, NULL, silc_ske_check_version,
                                 context);
-      
+
          status = silc_ske_responder_phase_2(ctx->ske, ctx->packet->buffer);
          if (status != SILC_SKE_STATUS_OK) {
            SILC_LOG_ERROR(("Error (%s) during Re-key (R PFS), with %s (%s)",
@@ -1407,11 +1407,12 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey)
             key to the new key since all packets after this packet must
             encrypted with the new key. */
          silc_server_protocol_rekey_generate(server, ctx, TRUE);
+         silc_server_packet_queue_purge(server, ctx->sock);
 
          /* The protocol ends in next stage. */
          protocol->state = SILC_PROTOCOL_STATE_END;
        }
-      
+
       } else {
        /*
         * We are the initiator of this protocol
@@ -1422,7 +1423,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey)
                                0, NULL, 0, FALSE);
 
        if (ctx->pfs == TRUE) {
-         /* 
+         /*
           * Use Perfect Forward Secrecy, ie. negotiate the key material
           * using the SKE protocol.
           */
@@ -1431,11 +1432,11 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey)
          silc_ske_group_get_by_number(idata->rekey->ske_group,
                                       &ctx->ske->prop->group);
 
-         silc_ske_set_callbacks(ctx->ske, 
-                                silc_server_protocol_rekey_send_packet, 
+         silc_ske_set_callbacks(ctx->ske,
+                                silc_server_protocol_rekey_send_packet,
                                 NULL, NULL, NULL, silc_ske_check_version,
                                 context);
-      
+
          status = silc_ske_initiator_phase_2(ctx->ske, NULL, NULL, 0);
          if (status != SILC_SKE_STATUS_OK) {
            SILC_LOG_ERROR(("Error (%s) during Re-key (I PFS), with %s (%s)",
@@ -1453,8 +1454,8 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey)
           * Do normal and simple re-key.
           */
 
-         /* Send the REKEY_DONE to indicate we will take new keys into use 
-            now. */ 
+         /* Send the REKEY_DONE to indicate we will take new keys into use
+            now. */
          silc_server_packet_send(server, ctx->sock, SILC_PACKET_REKEY_DONE,
                                  0, NULL, 0, FALSE);
 
@@ -1462,6 +1463,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey)
             key to the new key since all packets after this packet must
             encrypted with the new key. */
          silc_server_protocol_rekey_generate(server, ctx, TRUE);
+         silc_server_packet_queue_purge(server, ctx->sock);
 
          /* The protocol ends in next stage. */
          protocol->state = SILC_PROTOCOL_STATE_END;
@@ -1472,15 +1474,15 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey)
 
   case 2:
     /*
-     * Second state, used only when oding re-key with PFS.
+     * Second state, used only when doing re-key with PFS.
      */
     if (ctx->responder == TRUE) {
       if (ctx->pfs == TRUE) {
        /*
-        * Send our KE packe to the initiator now that we've processed
+        * Send our KE packet to the initiator now that we've processed
         * the initiator's KE packet.
         */
-       status = silc_ske_responder_finish(ctx->ske, NULL, NULL, 
+       status = silc_ske_responder_finish(ctx->ske, NULL, NULL,
                                           SILC_SKE_PK_TYPE_SILC);
        if (status != SILC_SKE_STATUS_OK) {
          SILC_LOG_ERROR(("Error (%s) during Re-key (R PFS), with %s (%s)",
@@ -1500,14 +1502,14 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey)
        if (ctx->packet->type != SILC_PACKET_KEY_EXCHANGE_2) {
          SILC_LOG_ERROR(("Error during Re-key (I PFS): re-key state is "
                          "incorrect (received %d, expected %d packet), "
-                         "with %s (%s)", ctx->packet->type, 
+                         "with %s (%s)", ctx->packet->type,
                          SILC_PACKET_KEY_EXCHANGE_2, ctx->sock->hostname,
                          ctx->sock->ip));
          protocol->state = SILC_PROTOCOL_STATE_ERROR;
          silc_protocol_execute(protocol, server->schedule, 0, 300000);
          return;
        }
-       
+
        status = silc_ske_initiator_finish(ctx->ske, ctx->packet->buffer);
        if (status != SILC_SKE_STATUS_OK) {
          SILC_LOG_ERROR(("Error (%s) during Re-key (I PFS), with %s (%s)",
@@ -1520,11 +1522,11 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey)
       }
     }
 
-    /* Send the REKEY_DONE to indicate we will take new keys into use 
-       now. */ 
+    /* Send the REKEY_DONE to indicate we will take new keys into use
+       now. */
     silc_server_packet_send(server, ctx->sock, SILC_PACKET_REKEY_DONE,
                            0, NULL, 0, FALSE);
-    
+
     /* After we send REKEY_DONE we must set the sending encryption
        key to the new key since all packets after this packet must
        encrypted with the new key. */
@@ -1535,7 +1537,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey)
     break;
 
   case SILC_PROTOCOL_STATE_END:
-    /* 
+    /*
      * End protocol
      */
 
@@ -1558,10 +1560,10 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey)
       silc_server_protocol_rekey_generate(server, ctx, FALSE);
 
     /* Assure that after calling final callback there cannot be pending
-       executions for this protocol anymore. This just unregisters any 
+       executions for this protocol anymore. This just unregisters any
        timeout callbacks for this protocol. */
     silc_protocol_cancel(protocol, server->schedule);
-    
+
     /* Protocol has ended, call the final callback */
     if (protocol->final_callback)
       silc_protocol_execute_final(protocol, server->schedule);
@@ -1579,10 +1581,10 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey)
       silc_ske_abort(ctx->ske, ctx->ske->status);
 
     /* Assure that after calling final callback there cannot be pending
-       executions for this protocol anymore. This just unregisters any 
+       executions for this protocol anymore. This just unregisters any
        timeout callbacks for this protocol. */
     silc_protocol_cancel(protocol, server->schedule);
-    
+
     /* On error the final callback is always called. */
     if (protocol->final_callback)
       silc_protocol_execute_final(protocol, server->schedule);
@@ -1598,10 +1600,10 @@ SILC_TASK_CALLBACK(silc_server_protocol_rekey)
     SILC_LOG_ERROR(("Error during Re-Key: received Failure"));
 
     /* Assure that after calling final callback there cannot be pending
-       executions for this protocol anymore. This just unregisters any 
+       executions for this protocol anymore. This just unregisters any
        timeout callbacks for this protocol. */
     silc_protocol_cancel(protocol, server->schedule);
-    
+
     /* On error the final callback is always called. */
     if (protocol->final_callback)
       silc_protocol_execute_final(protocol, server->schedule);
index 75e58c7d007a987f2448ab07c7449c10aef97a4d..3c184abce2ae2363f1193d1f1dd38ee316037258 100644 (file)
@@ -4,13 +4,12 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2002 Pekka Riikonen
+  Copyright (C) 1997 - 2003 Pekka Riikonen
 
   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.
-  
+  the Free Software Foundation; version 2 of the License.
+
   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
@@ -98,6 +97,7 @@ typedef struct {
   bool pfs;                        /* TRUE if PFS is to be used */
   SilcSKE ske;                     /* Defined if PFS is used */
   SilcPacketContext *packet;
+  SilcTask timeout_task;
 } SilcServerRekeyInternalContext;
 
 /* Prototypes */
index 0c55b28d0e87f5c411bfdfe62069e4b15dd0deba..963746f9045acc439a214a8294b17724b529f0cd 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  server.c 
+  server.c
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2002 Pekka Riikonen
+  Copyright (C) 1997 - 2003 Pekka Riikonen
 
   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
@@ -214,7 +214,7 @@ bool silc_server_init_secondary(SilcServer server)
   SilcSocketConnection newsocket = NULL;
   SilcServerConfigServerInfoInterface *interface;
 
-  for (interface = server->config->server_info->secondary; interface; 
+  for (interface = server->config->server_info->secondary; interface;
        interface = interface->next, sock++) {
 
     if (!silc_server_listen(server,
@@ -286,6 +286,14 @@ bool silc_server_init(SilcServer server)
   silc_server_config_ref(&server->config_ref, server->config,
                         server->config);
 
+#ifdef SILC_DEBUG
+  /* Set debugging on if configured */
+  if (server->config->debug_string) {
+    silc_debug = TRUE;
+    silc_log_set_debug_string(server->config->debug_string);
+  }
+#endif /* SILC_DEBUG */
+
   /* Steal public and private key from the config object */
   server->public_key = server->config->server_info->public_key;
   server->private_key = server->config->server_info->private_key;
@@ -426,10 +434,7 @@ bool silc_server_init(SilcServer server)
   /* Register protocols */
   silc_server_protocols_register();
 
-  /* Add the first task to the scheduler. This is task that is executed by
-     timeout. It expires as soon as the caller calls silc_server_run. This
-     task performs authentication protocol and key exchange with our
-     primary router. */
+  /* Create connections to configured routers. */
   silc_server_create_connections(server);
 
   /* Add listener task to the scheduler. This task receives new connections
@@ -443,7 +448,7 @@ bool silc_server_init(SilcServer server)
 
   if (silc_server_init_secondary(server) == FALSE)
     goto err;
-  
+
   server->listenning = TRUE;
 
   /* If server connections has been configured then we must be router as
@@ -552,7 +557,7 @@ bool silc_server_rehash(SilcServer server)
 
   /* Reinit scheduler if necessary */
   if (newconfig->param.connections_max > server->config->param.connections_max)
-    if (!silc_schedule_reinit(server->schedule, 
+    if (!silc_schedule_reinit(server->schedule,
                              newconfig->param.connections_max))
       return FALSE;
 
@@ -565,7 +570,7 @@ bool silc_server_rehash(SilcServer server)
     /* Update the idcache list with a fresh pointer */
     silc_free(server->id_entry->server_name);
     server->id_entry->server_name = strdup(server->server_name);
-    if (!silc_idcache_del_by_context(server->local_list->servers, 
+    if (!silc_idcache_del_by_context(server->local_list->servers,
                                     server->id_entry))
       return FALSE;
     if (!silc_idcache_add(server->local_list->servers,
@@ -609,7 +614,7 @@ bool silc_server_rehash(SilcServer server)
 
       /* Check whether new config has this one too */
       for (newptr = newconfig->routers; newptr; newptr = newptr->next) {
-       if (silc_string_compare(newptr->host, ptr->host) && 
+       if (silc_string_compare(newptr->host, ptr->host) &&
            newptr->port == ptr->port &&
            newptr->initiator == ptr->initiator) {
          found = TRUE;
@@ -720,6 +725,16 @@ bool silc_server_rehash(SilcServer server)
   server->config = newconfig;
   silc_server_config_ref(&server->config_ref, server->config, server->config);
 
+#ifdef SILC_DEBUG
+  /* Set debugging on if configured */
+  if (server->config->debug_string) {
+    silc_debug = TRUE;
+    silc_log_set_debug_string(server->config->debug_string);
+  } else {
+    silc_debug = FALSE;
+  }
+#endif /* SILC_DEBUG */
+
   SILC_LOG_DEBUG(("Server rehashed"));
 
   return TRUE;
@@ -764,13 +779,17 @@ void silc_server_stop(SilcServer server)
 
        silc_schedule_task_del_by_context(server->schedule,
                                          server->sockets[i]);
-       silc_server_disconnect_remote(server, server->sockets[i], 
-                                     SILC_STATUS_OK, 
+       silc_schedule_task_del_by_fd(server->schedule,
+                                    server->sockets[i]->sock);
+       silc_server_disconnect_remote(server, server->sockets[i],
+                                     SILC_STATUS_OK,
                                      "Server is shutting down");
-       if (sock->user_data)
-         silc_server_free_sock_user_data(server, sock,
-                                         "Server is shutting down");
-       silc_socket_free(sock);
+       if (server->sockets[i]) {
+         if (sock->user_data)
+           silc_server_free_sock_user_data(server, sock,
+                                           "Server is shutting down");
+         silc_socket_free(sock);
+       }
       } else {
        silc_socket_free(server->sockets[i]);
        server->sockets[i] = NULL;
@@ -1040,16 +1059,41 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_connect_to_router)
 
     if (ptr->initiator) {
       /* Check whether we are connecting or connected to this host already */
-      if (silc_server_num_sockets_by_remote(server, 
+      if (silc_server_num_sockets_by_remote(server,
                                            silc_net_is_ip(ptr->host) ?
                                            ptr->host : NULL,
                                            silc_net_is_ip(ptr->host) ?
                                            NULL : ptr->host, ptr->port,
                                            SILC_SOCKET_TYPE_ROUTER)) {
        SILC_LOG_DEBUG(("We are already connected to this router"));
-       continue;
+
+       /* If we don't have primary router and this connection is our
+          primary router we are in desync.  Reconnect to the primary. */
+       if (server->standalone && !server->router) {
+         SilcServerConfigRouter *primary =
+           silc_server_config_get_primary_router(server);
+         if (primary == ptr) {
+           SilcSocketConnection sock =
+             silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_ROUTER,
+                                             ptr->host, ptr->port);
+           if (sock) {
+             server->backup_noswitch = TRUE;
+             if (sock->user_data)
+               silc_server_free_sock_user_data(server, sock, NULL);
+             silc_server_disconnect_remote(server, sock, 0, NULL);
+             server->backup_noswitch = FALSE;
+             SILC_LOG_DEBUG(("Reconnecting to primary router"));
+           } else {
+             continue;
+           }
+         } else {
+           continue;
+         }
+       } else {
+         continue;
+       }
       }
-      if (silc_server_num_sockets_by_remote(server, 
+      if (silc_server_num_sockets_by_remote(server,
                                            silc_net_is_ip(ptr->host) ?
                                            ptr->host : NULL,
                                            silc_net_is_ip(ptr->host) ?
@@ -1108,7 +1152,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
       silc_ske_free(ctx->ske);
     silc_free(ctx->dest_id);
     silc_free(ctx);
-    silc_server_disconnect_remote(server, sock, 
+    silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
 
     /* Try reconnecting if configuration wants it */
@@ -1151,7 +1195,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
       silc_ske_free(ctx->ske);
     silc_free(ctx->dest_id);
     silc_free(ctx);
-    silc_server_disconnect_remote(server, sock, 
+    silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
 
     /* Try reconnecting if configuration wants it */
@@ -1225,7 +1269,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second)
     silc_free(sconn->remote_host);
     silc_free(sconn->backup_replace_ip);
     silc_free(sconn);
-    silc_server_disconnect_remote(server, sock, 
+    silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
     return;
   }
@@ -1284,8 +1328,10 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
       protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
     /* Error occured during protocol */
     silc_free(ctx->dest_id);
+    sock->protocol = NULL;
     silc_server_disconnect_remote(server, sock, SILC_STATUS_ERR_AUTH_FAILED,
                                  NULL);
+    sock->protocol = protocol;
 
     /* Try reconnecting if configuration wants it */
     if (!sconn->no_reconnect) {
@@ -1355,8 +1401,10 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
   if (!id_entry) {
     silc_free(ctx->dest_id);
     SILC_LOG_ERROR(("Cannot add new server entry to cache"));
+    sock->protocol = NULL;
     silc_server_disconnect_remote(server, sock, SILC_STATUS_ERR_AUTH_FAILED,
                                  NULL);
+    sock->protocol = protocol;
     goto out;
   }
 
@@ -1391,18 +1439,27 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
       SILC_LOG_DEBUG(("This connection is our primary router"));
       server->id_entry->router = id_entry;
       server->router = id_entry;
+      server->router->server_type = SILC_ROUTER;
       server->standalone = FALSE;
+      server->backup_primary = FALSE;
 
-      /* If we are router then announce our possible servers.  Backup
-        router announces also global servers. */
-      if (server->server_type == SILC_ROUTER)
-       silc_server_announce_servers(server,
-                                    server->backup_router ? TRUE : FALSE,
-                                    0, SILC_PRIMARY_ROUTE(server));
+      /* Announce data if we are not backup router (unless not as primary
+        currently).  Backup router announces later at the end of
+        resuming protocol. */
+      if (server->backup_router && server->server_type == SILC_ROUTER) {
+       SILC_LOG_DEBUG(("Announce data after resume protocol"));
+      } else {
+       /* If we are router then announce our possible servers.  Backup
+          router announces also global servers. */
+       if (server->server_type == SILC_ROUTER)
+         silc_server_announce_servers(server,
+                                      server->backup_router ? TRUE : FALSE,
+                                      0, SILC_PRIMARY_ROUTE(server));
 
-      /* Announce our clients and channels to the router */
-      silc_server_announce_clients(server, 0, SILC_PRIMARY_ROUTE(server));
-      silc_server_announce_channels(server, 0, SILC_PRIMARY_ROUTE(server));
+       /* Announce our clients and channels to the router */
+       silc_server_announce_clients(server, 0, SILC_PRIMARY_ROUTE(server));
+       silc_server_announce_channels(server, 0, SILC_PRIMARY_ROUTE(server));
+      }
 
       /* If we are backup router then this primary router is whom we are
         backing up. */
@@ -1412,6 +1469,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
     }
   } else {
     /* Add this server to be our backup router */
+    id_entry->server_type = SILC_BACKUP_ROUTER;
     silc_server_backup_add(server, id_entry, sconn->backup_replace_ip,
                           sconn->backup_replace_port, FALSE);
   }
@@ -1653,7 +1711,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second)
   if ((protocol->state == SILC_PROTOCOL_STATE_ERROR) ||
       (protocol->state == SILC_PROTOCOL_STATE_FAILURE)) {
     /* Error occured during protocol */
-    SILC_LOG_DEBUG(("Error key exchange protocol"));
+    SILC_LOG_DEBUG(("Error in key exchange protocol"));
     silc_protocol_free(protocol);
     sock->protocol = NULL;
     silc_ske_free_key_material(ctx->keymat);
@@ -1666,9 +1724,19 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second)
     silc_server_config_unref(&ctx->sconfig);
     silc_server_config_unref(&ctx->rconfig);
     silc_free(ctx);
-    silc_server_disconnect_remote(server, sock, 
-                                 SILC_STATUS_ERR_KEY_EXCHANGE_FAILED,
-                                 NULL);
+
+    if (!SILC_IS_DISCONNECTING(sock)) {
+      SILC_LOG_INFO(("Key exchange failed for %s:%d [%s]", sock->hostname,
+                    sock->port,
+                    (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
+                     sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
+                     sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
+                     "Router")));
+      silc_server_disconnect_remote(server, sock,
+                                   SILC_STATUS_ERR_KEY_EXCHANGE_FAILED,
+                                   NULL);
+    }
+
     server->stat.auth_failures++;
     return;
   }
@@ -1697,7 +1765,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second)
     silc_server_config_unref(&ctx->sconfig);
     silc_server_config_unref(&ctx->rconfig);
     silc_free(ctx);
-    silc_server_disconnect_remote(server, sock, 
+    silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
     server->stat.auth_failures++;
     return;
@@ -1744,7 +1812,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second)
                           SILC_TASK_PRI_LOW);
 }
 
-/* After this is called, server don't wait for backup router anymore.  
+/* After this is called, server don't wait for backup router anymore.
    This gets called automatically even after we have backup router
    connection established. */
 
@@ -1784,8 +1852,17 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
     silc_server_config_unref(&ctx->sconfig);
     silc_server_config_unref(&ctx->rconfig);
     silc_free(ctx);
-    silc_server_disconnect_remote(server, sock, SILC_STATUS_ERR_AUTH_FAILED,
-                                 NULL);
+
+    if (!SILC_IS_DISCONNECTING(sock)) {
+      SILC_LOG_INFO(("Authentication failed for %s:%d [%s]", sock->hostname,
+                    sock->port,
+                    (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
+                     sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
+                     sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
+                     "Router")));
+      silc_server_disconnect_remote(server, sock, SILC_STATUS_ERR_AUTH_FAILED,
+                                   NULL);
+    }
     server->stat.auth_failures++;
     return;
   }
@@ -1820,7 +1897,8 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
                                            router->backup_replace_ip, 0)) {
          SILC_LOG_INFO(("Will not accept connections because we do "
                         "not have backup router connection established"));
-         silc_server_disconnect_remote(server, sock, 
+         sock->protocol = NULL;
+         silc_server_disconnect_remote(server, sock,
                                        SILC_STATUS_ERR_PERM_DENIED,
                                        "We do not have connection to backup "
                                        "router established, try later");
@@ -1848,7 +1926,8 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
       if (!client) {
        SILC_LOG_ERROR(("Could not add new client to cache"));
        silc_free(sock->user_data);
-       silc_server_disconnect_remote(server, sock, 
+       sock->protocol = NULL;
+       silc_server_disconnect_remote(server, sock,
                                      SILC_STATUS_ERR_AUTH_FAILED, NULL);
        server->stat.auth_failures++;
        goto out;
@@ -1903,7 +1982,8 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
          !SILC_PRIMARY_ROUTE(server)) {
        SILC_LOG_INFO(("Will not accept server connection because we do "
                       "not have primary router connection established"));
-       silc_server_disconnect_remote(server, sock, 
+       sock->protocol = NULL;
+       silc_server_disconnect_remote(server, sock,
                                      SILC_STATUS_ERR_PERM_DENIED,
                                      "We do not have connection to primary "
                                      "router established, try later");
@@ -1991,7 +2071,8 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
                                            router->backup_replace_ip, 0)) {
          SILC_LOG_INFO(("Will not accept connections because we do "
                         "not have backup router connection established"));
-         silc_server_disconnect_remote(server, sock, 
+         sock->protocol = NULL;
+         silc_server_disconnect_remote(server, sock,
                                        SILC_STATUS_ERR_PERM_DENIED,
                                        "We do not have connection to backup "
                                        "router established, try later");
@@ -2036,7 +2117,8 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
       if (!new_server) {
        SILC_LOG_ERROR(("Could not add new server to cache"));
        silc_free(sock->user_data);
-       silc_server_disconnect_remote(server, sock, 
+       sock->protocol = NULL;
+       silc_server_disconnect_remote(server, sock,
                                      SILC_STATUS_ERR_AUTH_FAILED, NULL);
        server->stat.auth_failures++;
        goto out;
@@ -2120,7 +2202,8 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
                        server->schedule);
 
  out:
-  silc_protocol_free(protocol);
+  if (sock->protocol == protocol)
+    silc_protocol_free(protocol);
   if (ctx->packet)
     silc_packet_context_free(ctx->packet);
   if (ctx->ske)
@@ -2156,7 +2239,7 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
 
   if (type == SILC_TASK_WRITE) {
     /* Do not send data to disconnected connection */
-    if (SILC_IS_DISCONNECTED(sock)) {
+    if (SILC_IS_DISCONNECTING(sock) || SILC_IS_DISCONNECTED(sock)) {
       SILC_LOG_DEBUG(("Disconnected socket connection, cannot send"));
       return;
     }
@@ -2187,9 +2270,9 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
                       sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
                       "Router")));
 
-      SILC_SET_DISCONNECTING(sock);
       if (sock->user_data)
        silc_server_free_sock_user_data(server, sock, NULL);
+      SILC_SET_DISCONNECTING(sock);
       silc_server_close_connection(server, sock);
     }
     return;
@@ -2209,9 +2292,9 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
                       sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
                       "Router"), strerror(errno)));
 
-      SILC_SET_DISCONNECTING(sock);
       if (sock->user_data)
        silc_server_free_sock_user_data(server, sock, NULL);
+      SILC_SET_DISCONNECTING(sock);
       silc_server_close_connection(server, sock);
     }
     return;
@@ -2231,10 +2314,18 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
     }
 
     SILC_LOG_DEBUG(("Premature EOF from connection %d", sock->sock));
-    SILC_SET_DISCONNECTING(sock);
 
     if (sock->user_data) {
       char tmp[128];
+
+      /* If backup disconnected then mark that resuming willl not be allowed */
+      if (server->server_type == SILC_ROUTER && !server->backup_router &&
+         sock->type == SILC_SOCKET_TYPE_SERVER && sock->user_data) {
+       SilcServerEntry server_entry = sock->user_data;
+       if (server_entry->server_type == SILC_BACKUP_ROUTER)
+         server->backup_closed = TRUE;
+      }
+
       if (silc_socket_get_error(sock, tmp, sizeof(tmp) - 1))
        silc_server_free_sock_user_data(server, sock, tmp);
       else
@@ -2244,6 +2335,7 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
       silc_server_create_connections(server);
     }
 
+    SILC_SET_DISCONNECTING(sock);
     silc_server_close_connection(server, sock);
     return;
   }
@@ -2269,7 +2361,7 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
   local_is_router = (server->server_type == SILC_ROUTER);
 
   /* If socket connection is our primary, we are backup and we are doing
-     backup resuming, we won't process the packet as being a router 
+     backup resuming, we won't process the packet as being a router
      (affects channel message decryption). */
   if (server->backup_router && SILC_SERVER_IS_BACKUP(sock) &&
       SILC_PRIMARY_ROUTE(server) == sock)
@@ -2281,15 +2373,15 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
 
   /* If processing failed the connection is closed. */
   if (!ret) {
-    /* On packet processing errors we may close our primary router 
+    /* On packet processing errors we may close our primary router
        connection but won't become primary router if we are the backup
        since this is local error condition. */
     if (SILC_PRIMARY_ROUTE(server) == sock && server->backup_router)
       server->backup_noswitch = TRUE;
 
-    SILC_SET_DISCONNECTING(sock);
     if (sock->user_data)
       silc_server_free_sock_user_data(server, sock, NULL);
+    SILC_SET_DISCONNECTING(sock);
     silc_server_close_connection(server, sock);
   }
 }
@@ -2314,7 +2406,7 @@ SILC_TASK_CALLBACK(silc_server_packet_parse_real)
     ret = silc_packet_parse_special(packet, idata ? idata->receive_key : NULL);
 
   /* If entry is disabled ignore what we got. */
-  if (idata && idata->status & SILC_IDLIST_STATUS_DISABLED && 
+  if (idata && idata->status & SILC_IDLIST_STATUS_DISABLED &&
       ret != SILC_PACKET_HEARTBEAT && ret != SILC_PACKET_RESUME_ROUTER &&
       ret != SILC_PACKET_REKEY && ret != SILC_PACKET_REKEY_DONE) {
     SILC_LOG_DEBUG(("Connection is disabled"));
@@ -2402,11 +2494,9 @@ bool silc_server_packet_parse(SilcPacketParserContext *parser_context,
      process all packets synchronously, since there might be packets in
      queue that we are not able to decrypt without first processing the
      packets before them. */
-  if ((parser_context->packet->type == SILC_PACKET_REKEY ||
-       parser_context->packet->type == SILC_PACKET_REKEY_DONE) ||
-      (sock->protocol && sock->protocol->protocol &&
-       (sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_KEY_EXCHANGE ||
-       sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY))) {
+  if (sock->protocol && sock->protocol->protocol &&
+      (sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_KEY_EXCHANGE ||
+       sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY)) {
     silc_server_packet_parse_real(server->schedule, server, 0, sock->sock,
                                  parser_context);
 
@@ -2426,15 +2516,15 @@ bool silc_server_packet_parse(SilcPacketParserContext *parser_context,
                                  silc_server_packet_parse, server);
 
     if (!ret) {
-      /* On packet processing errors we may close our primary router 
+      /* On packet processing errors we may close our primary router
          connection but won't become primary router if we are the backup
          since this is local error condition. */
       if (SILC_PRIMARY_ROUTE(server) == sock && server->backup_router)
        server->backup_noswitch = TRUE;
 
-      SILC_SET_DISCONNECTING(sock);
       if (sock->user_data)
        silc_server_free_sock_user_data(server, sock, NULL);
+      SILC_SET_DISCONNECTING(sock);
       silc_server_close_connection(server, sock);
     }
 
@@ -2495,7 +2585,7 @@ void silc_server_packet_parse_type(SilcServer server,
        message = silc_memdup(packet->buffer->data + 1,
                              packet->buffer->len - 1);
 
-      SILC_LOG_INFO(("Disconnected by %s (%s): %s (%d) %s", 
+      SILC_LOG_INFO(("Disconnected by %s (%s): %s (%d) %s",
                     sock->ip, sock->hostname,
                     silc_get_status_message(status), status,
                     message ? message : ""));
@@ -2504,10 +2594,18 @@ void silc_server_packet_parse_type(SilcServer server,
       /* Do not switch to backup in case of error */
       server->backup_noswitch = (status == SILC_STATUS_OK ? FALSE : TRUE);
 
+      /* If backup disconnected then mark that resuming willl not be allowed */
+      if (server->server_type == SILC_ROUTER && !server->backup_router &&
+         sock->type == SILC_SOCKET_TYPE_SERVER && sock->user_data) {
+       SilcServerEntry server_entry = sock->user_data;
+       if (server_entry->server_type == SILC_BACKUP_ROUTER)
+         server->backup_closed = TRUE;
+      }
+
       /* Handle the disconnection from our end too */
-      SILC_SET_DISCONNECTING(sock);
       if (sock->user_data && SILC_IS_LOCAL(sock->user_data))
        silc_server_free_sock_user_data(server, sock, NULL);
+      SILC_SET_DISCONNECTING(sock);
       silc_server_close_connection(server, sock);
       server->backup_noswitch = FALSE;
     }
@@ -2533,9 +2631,46 @@ void silc_server_packet_parse_type(SilcServer server,
      */
     if (packet->flags & SILC_PACKET_FLAG_LIST)
       break;
+
+    /* Check for failure START_USE from backup router */
+    if (server->server_type == SILC_SERVER &&
+       server->backup_primary && packet->buffer->len == 4) {
+      SilcUInt32 type;
+      SILC_GET32_MSB(type, packet->buffer->data);
+      if (type == SILC_SERVER_BACKUP_START_USE) {
+       /* Attempt to reconnect to primary */
+       SILC_LOG_DEBUG(("Received failed START_USE from backup %s", sock->ip));
+
+       /* Default action is to disconnect from backup and reconnect to
+          primary.  Since this failure can happen during switching to
+          backup (backup might have not noticed the primary going down yet),
+          we will wait a while and keep sending START_USE to backup.
+          Only after that we'll give up. */
+       if (server->router == sock->user_data &&
+           (time(0) - server->router_connect) < 30) {
+         SILC_LOG_DEBUG(("Resending START_USE to backup router"));
+         silc_server_backup_send_start_use(server, sock, FALSE);
+         break;
+       }
+
+       /* If backup is our primary, disconnect now. */
+       if (server->router == sock->user_data) {
+         if (sock->user_data)
+           silc_server_free_sock_user_data(server, sock, NULL);
+         SILC_SET_DISCONNECTING(sock);
+         silc_server_close_connection(server, sock);
+       }
+
+       /* Reconnect */
+       silc_server_create_connections(server);
+      }
+    }
+
+    /* Execute protocol */
     if (sock->protocol) {
       sock->protocol->state = SILC_PROTOCOL_STATE_FAILURE;
       silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
+      break;
     }
     break;
 
@@ -2648,7 +2783,12 @@ void silc_server_packet_parse_type(SilcServer server,
       silc_protocol_execute(sock->protocol, server->schedule, 0, 100000);
     } else {
       SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
-                     "protocol active, packet dropped."));
+                     "protocol active (%s:%d [%s]).", sock->hostname,
+                     sock->port,
+                     (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
+                      sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
+                      sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
+                      "Router")));
     }
     break;
 
@@ -2691,7 +2831,12 @@ void silc_server_packet_parse_type(SilcServer server,
       }
     } else {
       SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
-                     "protocol active, packet dropped."));
+                     "protocol active (%s:%d [%s]).", sock->hostname,
+                     sock->port,
+                     (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
+                      sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
+                      sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
+                      "Router")));
     }
     break;
 
@@ -2734,7 +2879,12 @@ void silc_server_packet_parse_type(SilcServer server,
       }
     } else {
       SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
-                     "protocol active, packet dropped."));
+                     "protocol active (%s:%d [%s]).", sock->hostname,
+                     sock->port,
+                     (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
+                      sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
+                      sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
+                      "Router")));
     }
     break;
 
@@ -2771,7 +2921,12 @@ void silc_server_packet_parse_type(SilcServer server,
       silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
     } else {
       SILC_LOG_ERROR(("Received Connection Auth packet but no authentication "
-                     "protocol active, packet dropped."));
+                     "protocol active (%s:%d [%s]).", sock->hostname,
+                     sock->port,
+                     (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
+                      sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
+                      sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
+                      "Router")));
     }
     break;
 
@@ -2870,7 +3025,12 @@ void silc_server_packet_parse_type(SilcServer server,
       silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
     } else {
       SILC_LOG_ERROR(("Received Re-key done packet but no re-key "
-                     "protocol active, packet dropped."));
+                     "protocol active (%s:%d [%s]).", sock->hostname,
+                     sock->port,
+                     (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
+                      sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
+                      sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
+                      "Router")));
     }
     break;
 
@@ -2923,7 +3083,20 @@ void silc_server_create_connection(SilcServer server,
 
 SILC_TASK_CALLBACK(silc_server_close_connection_final)
 {
-  silc_socket_free(context);
+  SilcServer server = app_context;
+  SilcSocketConnection sock = context;
+
+  SILC_LOG_DEBUG(("Deleting socket %p", sock));
+
+  /* Close the actual connection */
+  silc_net_close_connection(sock->sock);
+  server->sockets[sock->sock] = NULL;
+
+  /* We won't listen for this connection anymore */
+  silc_schedule_task_del_by_fd(server->schedule, sock->sock);
+  silc_schedule_unset_listen_fd(server->schedule, sock->sock);
+
+  silc_socket_free(sock);
 }
 
 /* Closes connection to socket connection */
@@ -2933,62 +3106,49 @@ void silc_server_close_connection(SilcServer server,
 {
   char tmp[128];
 
-  if (!server->sockets[sock->sock] && SILC_IS_DISCONNECTED(sock)) {
-    silc_schedule_unset_listen_fd(server->schedule, sock->sock);
+  if (SILC_IS_DISCONNECTED(sock)) {
     silc_schedule_task_del_by_fd(server->schedule, sock->sock);
-    silc_net_close_connection(sock->sock);
     silc_schedule_task_add(server->schedule, sock->sock,
                           silc_server_close_connection_final,
                           (void *)sock, 0, 1, SILC_TASK_TIMEOUT,
                           SILC_TASK_PRI_NORMAL);
+    server->sockets[sock->sock] = NULL;
+    return;
+  }
+
+  /* If any protocol is active cancel its execution. It will call
+     the final callback which will finalize the disconnection. */
+  if (sock->protocol && sock->protocol->protocol &&
+      sock->protocol->protocol->type != SILC_PROTOCOL_SERVER_BACKUP) {
+    SILC_LOG_DEBUG(("Cancelling protocol, calling final callback"));
+    silc_protocol_cancel(sock->protocol, server->schedule);
+    sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
+    silc_protocol_execute_final(sock->protocol, server->schedule);
+    sock->protocol = NULL;
     return;
   }
 
   memset(tmp, 0, sizeof(tmp));
   silc_socket_get_error(sock, tmp, sizeof(tmp));
   SILC_LOG_INFO(("Closing connection %s:%d [%s] %s", sock->hostname,
-                  sock->port,
-                  (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
-                   sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
-                   sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
-                   "Router"), tmp[0] ? tmp : ""));
-
-  /* Unregister all tasks */
-  silc_schedule_task_del_by_fd(server->schedule, sock->sock);
-
-  server->sockets[sock->sock] = NULL;
-
-  /* If sock->user_data is NULL then we'll check for active protocols
-     here since the silc_server_free_sock_user_data has not been called
-     for this connection. */
-  if (!sock->user_data) {
-    /* If any protocol is active cancel its execution. It will call
-       the final callback which will finalize the disconnection. */
-    if (sock->protocol && sock->protocol->protocol &&
-       sock->protocol->protocol->type != SILC_PROTOCOL_SERVER_BACKUP) {
-      SILC_LOG_DEBUG(("Cancelling protocol, calling final callback"));
-      silc_protocol_cancel(sock->protocol, server->schedule);
-      sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
-      silc_protocol_execute_final(sock->protocol, server->schedule);
-      sock->protocol = NULL;
-      return;
-    }
-  }
-
-  /* Close the actual connection */
-  silc_net_close_connection(sock->sock);
-
-  /* We won't listen for this connection anymore */
-  silc_schedule_unset_listen_fd(server->schedule, sock->sock);
+                sock->port,
+                (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
+                 sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
+                 sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
+                 "Router"), tmp[0] ? tmp : ""));
 
+  SILC_SET_DISCONNECTED(sock);
   silc_schedule_task_add(server->schedule, sock->sock,
                         silc_server_close_connection_final,
                         (void *)sock, 0, 1, SILC_TASK_TIMEOUT,
                         SILC_TASK_PRI_NORMAL);
+  server->sockets[sock->sock] = NULL;
 }
 
 /* Sends disconnect message to remote connection and disconnects the
-   connection. */
+   connection.  NOTE: If this is called from protocol callback
+   then sock->protocol must be set NULL before calling this, since
+   this routine dispatches protocol callbacks too. */
 
 void silc_server_disconnect_remote(SilcServer server,
                                   SilcSocketConnection sock,
@@ -3003,7 +3163,8 @@ void silc_server_disconnect_remote(SilcServer server,
   if (!sock)
     return;
 
-  if (SILC_IS_DISCONNECTED(sock)) {
+  if (SILC_IS_DISCONNECTING(sock)) {
+    SILC_SET_DISCONNECTED(sock);
     silc_server_close_connection(server, sock);
     return;
   }
@@ -3042,7 +3203,7 @@ void silc_server_disconnect_remote(SilcServer server,
   silc_server_packet_queue_purge(server, sock);
 
   /* Mark the connection to be disconnected */
-  SILC_SET_DISCONNECTED(sock);
+  SILC_SET_DISCONNECTING(sock);
   silc_server_close_connection(server, sock);
 }
 
@@ -3132,6 +3293,17 @@ void silc_server_free_sock_user_data(SilcServer server,
                                     SilcSocketConnection sock,
                                     const char *signoff_message)
 {
+
+  /* If any protocol is active cancel its execution */
+  if (sock->protocol && sock->protocol->protocol &&
+      sock->protocol->protocol->type != SILC_PROTOCOL_SERVER_BACKUP) {
+    SILC_LOG_DEBUG(("Cancelling protocol, calling final callback"));
+    silc_protocol_cancel(sock->protocol, server->schedule);
+    sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
+    silc_protocol_execute_final(sock->protocol, server->schedule);
+    sock->protocol = NULL;
+  }
+
   switch (sock->type) {
   case SILC_SOCKET_TYPE_CLIENT:
     {
@@ -3164,7 +3336,8 @@ void silc_server_free_sock_user_data(SilcServer server,
       if (server->router == user_data) {
        /* Check whether we have a backup router connection */
        if (!backup_router || backup_router == user_data) {
-         silc_server_create_connections(server);
+         if (!server->no_reconnect)
+           silc_server_create_connections(server);
          server->id_entry->router = NULL;
          server->router = NULL;
          server->standalone = TRUE;
@@ -3178,17 +3351,23 @@ void silc_server_free_sock_user_data(SilcServer server,
            server->router = backup_router;
            server->router_connect = time(0);
            server->backup_primary = TRUE;
+           backup_router->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
+
+           /* Send START_USE to backup router to indicate we have switched */
+           silc_server_backup_send_start_use(server,
+                                             backup_router->connection,
+                                             FALSE);
          } else {
            SILC_LOG_INFO(("We are now new primary router in this cell"));
            server->id_entry->router = NULL;
            server->router = NULL;
            server->standalone = TRUE;
-
-           /* We stop here to take a breath */
-           sleep(2);
          }
 
-         if (server->server_type == SILC_BACKUP_ROUTER) {
+         /* We stop here to take a breath */
+         sleep(2);
+
+         if (server->backup_router) {
            server->server_type = SILC_ROUTER;
 
            /* We'll need to constantly try to reconnect to the primary
@@ -3212,7 +3391,8 @@ void silc_server_free_sock_user_data(SilcServer server,
       } else if (server->server_type == SILC_SERVER &&
                 sock->type == SILC_SOCKET_TYPE_ROUTER) {
        /* Reconnect to the router (backup) */
-       silc_server_create_connections(server);
+       if (!server->no_reconnect)
+         silc_server_create_connections(server);
       }
 
       if (user_data->server_name)
@@ -3330,16 +3510,6 @@ void silc_server_free_sock_user_data(SilcServer server,
     }
   }
 
-  /* If any protocol is active cancel its execution */
-  if (sock->protocol && sock->protocol->protocol &&
-      sock->protocol->protocol->type != SILC_PROTOCOL_SERVER_BACKUP) {
-    SILC_LOG_DEBUG(("Cancelling protocol, calling final callback"));
-    silc_protocol_cancel(sock->protocol, server->schedule);
-    sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
-    silc_protocol_execute_final(sock->protocol, server->schedule);
-    sock->protocol = NULL;
-  }
-
   sock->user_data = NULL;
 }
 
@@ -3363,11 +3533,12 @@ void silc_server_remove_from_channels(SilcServer server,
   if (!client)
     return;
 
-  SILC_LOG_DEBUG(("Removing client from joined channels"));
-
   if (notify && !client->id)
     notify = FALSE;
 
+  SILC_LOG_DEBUG(("Removing client %s from joined channels",
+                 notify ? silc_id_render(client->id, SILC_ID_CLIENT) : ""));
+
   if (notify) {
     clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
     if (!clidp)
@@ -3416,7 +3587,7 @@ void silc_server_remove_from_channels(SilcServer server,
        !silc_server_channel_has_local(channel)) {
       /* Notify about leaving client if this channel has global users. */
       if (notify && channel->global_users)
-       silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
+       silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
                                           SILC_NOTIFY_TYPE_SIGNOFF,
                                           signoff_message ? 2 : 1,
                                           clidp->data, clidp->len,
@@ -3430,7 +3601,7 @@ void silc_server_remove_from_channels(SilcServer server,
 
     /* Send notify to channel about client leaving SILC and channel too */
     if (notify)
-      silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
+      silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
                                         SILC_NOTIFY_TYPE_SIGNOFF,
                                         signoff_message ? 2 : 1,
                                         clidp->data, clidp->len,
@@ -3490,7 +3661,7 @@ bool silc_server_remove_from_one_channel(SilcServer server,
   SilcBuffer clidp;
 
   SILC_LOG_DEBUG(("Removing %s from channel %s",
-                 silc_id_render(client->id, SILC_ID_CLIENT), 
+                 silc_id_render(client->id, SILC_ID_CLIENT),
                  channel->channel_name));
 
   /* Get the entry to the channel, if this client is not on the channel
@@ -3538,7 +3709,7 @@ bool silc_server_remove_from_one_channel(SilcServer server,
       !silc_server_channel_has_local(channel)) {
     /* Notify about leaving client if this channel has global users. */
     if (notify && channel->global_users)
-      silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
+      silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
                                         SILC_NOTIFY_TYPE_LEAVE, 1,
                                         clidp->data, clidp->len);
 
@@ -3550,7 +3721,7 @@ bool silc_server_remove_from_one_channel(SilcServer server,
 
   /* Send notify to channel about client leaving the channel */
   if (notify)
-    silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
+    silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
                                       SILC_NOTIFY_TYPE_LEAVE, 1,
                                       clidp->data, clidp->len);
 
@@ -3588,8 +3759,8 @@ SILC_TASK_CALLBACK(silc_server_timeout_remote)
     return;
   }
 
-  silc_server_disconnect_remote(server, sock, 
-                               protocol == 
+  silc_server_disconnect_remote(server, sock,
+                               protocol ==
                                SILC_PROTOCOL_SERVER_CONNECTION_AUTH ?
                                SILC_STATUS_ERR_AUTH_FAILED :
                                SILC_STATUS_ERR_KEY_EXCHANGE_FAILED,
@@ -4017,7 +4188,7 @@ void silc_server_perform_heartbeat(SilcSocketConnection sock,
 {
   SilcServer server = hb_context;
 
-  SILC_LOG_DEBUG(("Sending heartbeat to %s:%d (%s)", sock->hostname, 
+  SILC_LOG_DEBUG(("Sending heartbeat to %s:%d (%s)", sock->hostname,
                 sock->port, sock->ip));
 
   /* Send the heartbeat */
@@ -4259,6 +4430,66 @@ void silc_server_announce_get_channel_topic(SilcServer server,
   }
 }
 
+/* Returns channel's invite and ban lists */
+
+void silc_server_announce_get_inviteban(SilcServer server,
+                                       SilcChannelEntry channel,
+                                       SilcBuffer *invite,
+                                       SilcBuffer *ban)
+{
+  SilcBuffer list, idp, idp2, tmp2;
+  SilcUInt32 type;
+  SilcHashTableList htl;
+  const unsigned char a[1] = { 0x03 };
+
+  idp = silc_id_payload_encode((void *)channel->id, SILC_ID_CHANNEL);
+
+  /* Encode invite list */
+  if (channel->invite_list && silc_hash_table_count(channel->invite_list)) {
+    list = silc_buffer_alloc_size(2);
+    type = silc_hash_table_count(channel->invite_list);
+    SILC_PUT16_MSB(type, list->data);
+    silc_hash_table_list(channel->invite_list, &htl);
+    while (silc_hash_table_get(&htl, (void **)&type, (void **)&tmp2))
+      list = silc_argument_payload_encode_one(list, tmp2->data, tmp2->len,
+                                              type);
+    silc_hash_table_list_reset(&htl);
+
+    idp2 = silc_id_payload_encode(server->id, SILC_ID_SERVER);
+    *invite =
+      silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_INVITE, 5,
+                                        idp->data, idp->len,
+                                        channel->channel_name,
+                                        strlen(channel->channel_name),
+                                        idp2->data, idp2->len,
+                                        a, 1,
+                                        list->data, list->len);
+    silc_buffer_free(idp2);
+    silc_buffer_free(list);
+  }
+
+  /* Encode ban list */
+  if (channel->ban_list && silc_hash_table_count(channel->ban_list)) {
+    list = silc_buffer_alloc_size(2);
+    type = silc_hash_table_count(channel->ban_list);
+    SILC_PUT16_MSB(type, list->data);
+    silc_hash_table_list(channel->ban_list, &htl);
+    while (silc_hash_table_get(&htl, (void **)&type, (void **)&tmp2))
+      list = silc_argument_payload_encode_one(list, tmp2->data, tmp2->len,
+                                              type);
+    silc_hash_table_list_reset(&htl);
+
+    *ban =
+      silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_BAN, 3,
+                                        idp->data, idp->len,
+                                        a, 1,
+                                        list->data, list->len);
+    silc_buffer_free(list);
+  }
+
+  silc_buffer_free(idp);
+}
+
 /* Returns assembled packets for channel users of the `channel'. */
 
 void silc_server_announce_get_channel_users(SilcServer server,
@@ -4270,7 +4501,7 @@ void silc_server_announce_get_channel_users(SilcServer server,
   SilcChannelClientEntry chl;
   SilcHashTableList htl;
   SilcBuffer chidp, clidp, csidp;
-  SilcBuffer tmp, fkey = NULL;
+  SilcBuffer tmp, fkey = NULL, chpklist;
   int len;
   unsigned char mode[4];
   char *hmac;
@@ -4279,15 +4510,16 @@ void silc_server_announce_get_channel_users(SilcServer server,
 
   chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
   csidp = silc_id_payload_encode(server->id, SILC_ID_SERVER);
+  chpklist = silc_server_get_channel_pk_list(server, channel, TRUE, FALSE);
 
   /* CMODE notify */
   SILC_PUT32_MSB(channel->mode, mode);
   hmac = channel->hmac ? (char *)silc_hmac_get_name(channel->hmac) : NULL;
   if (channel->founder_key)
     fkey = silc_pkcs_public_key_payload_encode(channel->founder_key);
-  tmp = 
+  tmp =
     silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_CMODE_CHANGE,
-                                      6, csidp->data, csidp->len,
+                                      7, csidp->data, csidp->len,
                                       mode, sizeof(mode),
                                       NULL, 0,
                                       hmac, hmac ? strlen(hmac) : 0,
@@ -4295,7 +4527,9 @@ void silc_server_announce_get_channel_users(SilcServer server,
                                       channel->passphrase ?
                                       strlen(channel->passphrase) : 0,
                                       fkey ? fkey->data : NULL,
-                                      fkey ? fkey->len : 0);
+                                      fkey ? fkey->len : 0,
+                                      chpklist ? chpklist->data : NULL,
+                                      chpklist ? chpklist->len : 0);
   len = tmp->len;
   *channel_modes =
     silc_buffer_realloc(*channel_modes,
@@ -4375,6 +4609,8 @@ void silc_server_announce_get_channels(SilcServer server,
                                       SilcBuffer **channel_users_modes,
                                       SilcUInt32 *channel_users_modes_c,
                                       SilcBuffer **channel_topics,
+                                      SilcBuffer **channel_invites,
+                                      SilcBuffer **channel_bans,
                                       SilcChannelID ***channel_ids,
                                       unsigned long creation_time)
 {
@@ -4442,7 +4678,7 @@ void silc_server_announce_get_channels(SilcServer server,
                                      sizeof(**channel_ids) * (i + 1));
          (*channel_ids)[i] = NULL;
          silc_server_announce_get_channel_users(server, channel,
-                                                &(*channel_modes)[i], 
+                                                &(*channel_modes)[i],
                                                 channel_users,
                                                 &(*channel_users_modes)[i]);
          (*channel_ids)[i] = channel->id;
@@ -4453,8 +4689,19 @@ void silc_server_announce_get_channels(SilcServer server,
          (*channel_topics)[i] = NULL;
          silc_server_announce_get_channel_topic(server, channel,
                                                 &(*channel_topics)[i]);
-         (*channel_users_modes_c)++;
 
+         /* Channel's invite and ban list */
+         *channel_invites = silc_realloc(*channel_invites,
+                                         sizeof(**channel_invites) * (i + 1));
+         (*channel_invites)[i] = NULL;
+         *channel_bans = silc_realloc(*channel_bans,
+                                      sizeof(**channel_bans) * (i + 1));
+         (*channel_bans)[i] = NULL;
+         silc_server_announce_get_inviteban(server, channel,
+                                            &(*channel_invites)[i],
+                                            &(*channel_bans)[i]);
+
+         (*channel_users_modes_c)++;
          silc_free(cid);
 
          i++;
@@ -4483,6 +4730,8 @@ void silc_server_announce_channels(SilcServer server,
   SilcBuffer channels = NULL, *channel_modes = NULL, channel_users = NULL;
   SilcBuffer *channel_users_modes = NULL;
   SilcBuffer *channel_topics = NULL;
+  SilcBuffer *channel_invites = NULL;
+  SilcBuffer *channel_bans = NULL;
   SilcUInt32 channel_users_modes_c = 0;
   SilcChannelID **channel_ids = NULL;
 
@@ -4495,6 +4744,8 @@ void silc_server_announce_channels(SilcServer server,
                                    &channel_users_modes,
                                    &channel_users_modes_c,
                                    &channel_topics,
+                                   &channel_invites,
+                                   &channel_bans,
                                    &channel_ids, creation_time);
 
   /* Get channels and channel users in global list */
@@ -4505,6 +4756,8 @@ void silc_server_announce_channels(SilcServer server,
                                      &channel_users_modes,
                                      &channel_users_modes_c,
                                      &channel_topics,
+                                     &channel_invites,
+                                     &channel_bans,
                                      &channel_ids, creation_time);
 
   if (channels) {
@@ -4601,6 +4854,52 @@ void silc_server_announce_channels(SilcServer server,
     silc_free(channel_topics);
   }
 
+  if (channel_invites) {
+    int i;
+
+    for (i = 0; i < channel_users_modes_c; i++) {
+      if (!channel_invites[i])
+       continue;
+
+      silc_buffer_push(channel_invites[i],
+                      channel_invites[i]->data -
+                      channel_invites[i]->head);
+      SILC_LOG_HEXDUMP(("channel invite list"), channel_invites[i]->data,
+                      channel_invites[i]->len);
+      silc_server_packet_send_dest(server, remote,
+                                  SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+                                  channel_ids[i], SILC_ID_CHANNEL,
+                                  channel_invites[i]->data,
+                                  channel_invites[i]->len,
+                                  FALSE);
+      silc_buffer_free(channel_invites[i]);
+    }
+    silc_free(channel_invites);
+  }
+
+  if (channel_bans) {
+    int i;
+
+    for (i = 0; i < channel_users_modes_c; i++) {
+      if (!channel_bans[i])
+       continue;
+
+      silc_buffer_push(channel_bans[i],
+                      channel_bans[i]->data -
+                      channel_bans[i]->head);
+      SILC_LOG_HEXDUMP(("channel ban list"), channel_bans[i]->data,
+                      channel_bans[i]->len);
+      silc_server_packet_send_dest(server, remote,
+                                  SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+                                  channel_ids[i], SILC_ID_CHANNEL,
+                                  channel_bans[i]->data,
+                                  channel_bans[i]->len,
+                                  FALSE);
+      silc_buffer_free(channel_bans[i]);
+    }
+    silc_free(channel_bans);
+  }
+
   silc_free(channel_ids);
 }
 
@@ -4780,18 +5079,18 @@ void silc_server_save_user_channels(SilcServer server,
   if (!channels || !channels_user_modes ||
       !(client->data.status & SILC_IDLIST_STATUS_REGISTERED))
     goto out;
-  
+
   ch = silc_channel_payload_parse_list(channels->data, channels->len);
   if (ch && silc_get_mode_list(channels_user_modes, silc_dlist_count(ch),
                               &chumodes)) {
-    ht = silc_hash_table_alloc(0, silc_hash_ptr, NULL, NULL, 
+    ht = silc_hash_table_alloc(0, silc_hash_ptr, NULL, NULL,
                               NULL, NULL, NULL, TRUE);
     silc_dlist_start(ch);
     while ((entry = silc_dlist_get(ch)) != SILC_LIST_END) {
       /* Check if we have this channel, and add it if we don't have it.
         Also add the client on the channel unless it is there already. */
       channel_id = silc_channel_get_id_parse(entry);
-      channel = silc_idlist_find_channel_by_id(server->local_list, 
+      channel = silc_idlist_find_channel_by_id(server->local_list,
                                               channel_id, NULL);
       if (!channel)
        channel = silc_idlist_find_channel_by_id(server->global_list,
@@ -4802,7 +5101,7 @@ void silc_server_save_user_channels(SilcServer server,
          i++;
          continue;
        }
-       
+
        /* We don't have that channel anywhere, add it. */
        name = silc_channel_get_name(entry, NULL);
        channel = silc_idlist_add_channel(server->global_list, strdup(name), 0,
@@ -5023,6 +5322,42 @@ SilcBuffer silc_server_get_client_channel_list(SilcServer server,
   return buffer;
 }
 
+/* Timeout callback for unsuccessful rekey.  The rekey did not go through
+   for some reason. */
+
+SILC_TASK_CALLBACK(silc_server_rekey_timeout)
+{
+  SilcServerRekeyInternalContext *ctx = context;
+  SilcServer server = app_context;
+  SilcSocketConnection sock = ctx->sock;
+
+  SILC_LOG_DEBUG(("Timeout occurred in rekey protocol with %s:%d [%s]",
+                 sock->hostname, sock->port,
+                 (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
+                  sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
+                  sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
+                  "Router")));
+
+  SILC_LOG_WARNING(("Timeout occurred in rekey protocol with %s:%d [%s]",
+                   sock->hostname, sock->port,
+                   (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
+                    sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
+                    sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
+                    "Router")));
+
+  if (sock->protocol) {
+    silc_protocol_cancel(sock->protocol, server->schedule);
+    silc_protocol_free(sock->protocol);
+    sock->protocol = NULL;
+  }
+  if (ctx->packet)
+    silc_packet_context_free(ctx->packet);
+  if (ctx->ske)
+    silc_ske_free(ctx->ske);
+  silc_socket_free(sock);
+  silc_free(ctx);
+}
+
 /* A timeout callback for the re-key. We will be the initiator of the
    re-key protocol. */
 
@@ -5034,11 +5369,41 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_callback)
   SilcProtocol protocol;
   SilcServerRekeyInternalContext *proto_ctx;
 
+  if (!idata)
+    return;
+
+  /* Do not execute rekey with disabled connections, as it would not
+     go through anyway. */
+  if (idata->status & SILC_IDLIST_STATUS_DISABLED)
+    return;
+
+  /* If rekey protocol is active already wait for it to finish */
+  if (sock->protocol && sock->protocol->protocol &&
+      sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY)
+    return;
+
+  /* If any other protocol is active do not start this protocol yet. */
+  if (sock->protocol) {
+    SILC_LOG_DEBUG(("Waiting for other protocol to finish before rekeying"));
+    silc_schedule_task_add(server->schedule, sock->sock,
+                          silc_server_rekey_callback,
+                          sock, 60, 0, SILC_TASK_TIMEOUT,
+                          SILC_TASK_PRI_NORMAL);
+    return;
+  }
+
+  SILC_LOG_DEBUG(("Executing rekey protocol with %s:%d [%s]",
+                 sock->hostname, sock->port,
+                 (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
+                  sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
+                  sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
+                  "Router")));
+
   /* Allocate internal protocol context. This is sent as context
      to the protocol. */
   proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
   proto_ctx->server = (void *)server;
-  proto_ctx->sock = sock;
+  proto_ctx->sock = silc_socket_dup(sock);
   proto_ctx->responder = FALSE;
   proto_ctx->pfs = idata->rekey->pfs;
 
@@ -5048,16 +5413,17 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_callback)
                      &protocol, proto_ctx, silc_server_rekey_final);
   sock->protocol = protocol;
 
+  /* Register timeout callback in case the rekey does not go through. */
+  proto_ctx->timeout_task =
+    silc_schedule_task_add(server->schedule, sock->sock,
+                          silc_server_rekey_timeout,
+                          proto_ctx,
+                          server->config->key_exchange_timeout, 0,
+                          SILC_TASK_TIMEOUT,
+                          SILC_TASK_PRI_LOW);
+
   /* Run the protocol */
   silc_protocol_execute(protocol, server->schedule, 0, 0);
-
-  SILC_LOG_DEBUG(("Rekey protocol completed"));
-
-  /* Re-register re-key timeout */
-  silc_schedule_task_add(server->schedule, sock->sock,
-                        silc_server_rekey_callback,
-                        context, idata->rekey->timeout, 0,
-                        SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
 }
 
 /* The final callback for the REKEY protocol. This will actually take the
@@ -5070,8 +5436,10 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_final)
     (SilcServerRekeyInternalContext *)protocol->context;
   SilcServer server = (SilcServer)ctx->server;
   SilcSocketConnection sock = ctx->sock;
+  SilcIDListData idata = (SilcIDListData)sock->user_data;
 
-  SILC_LOG_DEBUG(("Start"));
+  if (ctx->timeout_task)
+    silc_schedule_task_del(server->schedule, ctx->timeout_task);
 
   if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
       protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
@@ -5085,22 +5453,35 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_final)
       silc_packet_context_free(ctx->packet);
     if (ctx->ske)
       silc_ske_free(ctx->ske);
+    silc_socket_free(sock);
     silc_free(ctx);
+    silc_server_disconnect_remote(server, sock,
+                                 SILC_STATUS_ERR_KEY_EXCHANGE_FAILED, NULL);
 
     /* Reconnect */
-    SILC_SET_DISCONNECTING(sock);
-    server->backup_noswitch = TRUE;
-    if (sock->user_data)
-      silc_server_free_sock_user_data(server, sock, NULL);
-    silc_server_close_connection(server, sock);
-    silc_server_create_connections(server);
+    if (sock->type != SILC_SOCKET_TYPE_CLIENT)
+      silc_server_create_connections(server);
     return;
   }
 
+  SILC_LOG_DEBUG(("Rekey protocol completed with %s:%d [%s]",
+                 sock->hostname, sock->port,
+                 (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
+                  sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
+                  sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
+                  "Router")));
+
   /* Purge the outgoing data queue to assure that all rekey packets really
      go to the network before we quit the protocol. */
   silc_server_packet_queue_purge(server, sock);
 
+  /* Re-register re-key timeout */
+  if (ctx->responder == FALSE)
+    silc_schedule_task_add(server->schedule, sock->sock,
+                          silc_server_rekey_callback,
+                          sock, idata->rekey->timeout, 0,
+                          SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+
   /* Cleanup */
   silc_protocol_free(protocol);
   sock->protocol = NULL;
@@ -5108,6 +5489,7 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_final)
     silc_packet_context_free(ctx->packet);
   if (ctx->ske)
     silc_ske_free(ctx->ske);
+  silc_socket_free(sock);
   silc_free(ctx);
 }
 
@@ -5119,11 +5501,10 @@ SILC_TASK_CALLBACK(silc_server_get_stats)
   SilcServer server = (SilcServer)context;
   SilcBuffer idp, packet;
 
-  SILC_LOG_DEBUG(("Retrieving stats from router"));
-
   if (!server->standalone) {
+    SILC_LOG_DEBUG(("Retrieving stats from router"));
     idp = silc_id_payload_encode(server->router->id, SILC_ID_SERVER);
-    packet = silc_command_payload_encode_va(SILC_COMMAND_STATS, 
+    packet = silc_command_payload_encode_va(SILC_COMMAND_STATS,
                                            ++server->cmd_ident, 1,
                                            1, idp->data, idp->len);
     silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
index 1204b2449f59feb6bf3406b17db736bb5130ff97..8cdf3b0352f35603cc4f4520f8a4d7f5b80628d4 100644 (file)
@@ -209,6 +209,8 @@ void silc_server_announce_get_channels(SilcServer server,
                                       SilcBuffer **channel_users_modes,
                                       SilcUInt32 *channel_users_modes_c,
                                       SilcBuffer **channel_topics,
+                                      SilcBuffer **channel_invites,
+                                      SilcBuffer **channel_bans,
                                       SilcChannelID ***channel_ids,
                                       unsigned long creation_time);
 void silc_server_announce_servers(SilcServer server, bool global,
index 757f5177a17d0e812a64f01521870d0cc3ddf256..dce3c9be2d41ff4300f769d0920ab902bf3758dd 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  server_backup.c 
+  server_backup.c
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2001 - 2002 Pekka Riikonen
+  Copyright (C) 2001 - 2003 Pekka Riikonen
 
   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
@@ -26,6 +26,9 @@ static void silc_server_backup_connect_primary(SilcServer server,
                                               SilcServerEntry server_entry,
                                               void *context);
 
+
+/************************** Types and Definitions ***************************/
+
 /* Backup router */
 typedef struct {
   SilcServerEntry server;
@@ -60,14 +63,19 @@ typedef struct {
 typedef struct {
   SilcServer server;
   SilcSocketConnection sock;
-  bool responder;
   SilcUInt8 type;
   SilcUInt8 session;
   SilcServerBackupProtocolSession *sessions;
   SilcUInt32 sessions_count;
   long start;
+  unsigned int responder        : 1;
+  unsigned int received_failure : 1;
+  unsigned int timeout          : 1;
 } *SilcServerBackupProtocolContext;
 
+
+/********************* Backup Configuration Routines ************************/
+
 /* Adds the `backup_server' to be one of our backup router. This can be
    called multiple times to set multiple backup routers. The `ip' and `port'
    is the IP and port that the `backup_router' will replace if the `ip'
@@ -88,6 +96,12 @@ void silc_server_backup_add(SilcServer server, SilcServerEntry backup_server,
       return;
   }
 
+  /* See if already added */
+  for (i = 0; i < server->backup->servers_count; i++) {
+    if (server->backup->servers[i].server == backup_server)
+      return;
+  }
+
   SILC_LOG_DEBUG(("Backup router %s will replace %s",
                  ((SilcSocketConnection)backup_server->connection)->ip,
                  ip, port));
@@ -119,10 +133,10 @@ void silc_server_backup_add(SilcServer server, SilcServerEntry backup_server,
   server->backup->servers_count++;
 }
 
-/* Returns backup router for IP and port in `replacing' or NULL if there
+/* Returns backup router for IP and port in `server_id' or NULL if there
    does not exist backup router. */
 
-SilcServerEntry silc_server_backup_get(SilcServer server, 
+SilcServerEntry silc_server_backup_get(SilcServer server,
                                       SilcServerID *server_id)
 {
   int i;
@@ -193,7 +207,7 @@ void silc_server_backup_free(SilcServer server)
    a later time we can check whether it has been replaced by an backup
    router. */
 
-void silc_server_backup_replaced_add(SilcServer server, 
+void silc_server_backup_replaced_add(SilcServer server,
                                     SilcServerID *server_id,
                                     SilcServerEntry server_entry)
 {
@@ -203,7 +217,7 @@ void silc_server_backup_replaced_add(SilcServer server,
   if (!server->backup)
     server->backup = silc_calloc(1, sizeof(*server->backup));
   if (!server->backup->replaced) {
-    server->backup->replaced = 
+    server->backup->replaced =
       silc_calloc(1, sizeof(*server->backup->replaced));
     server->backup->replaced_count = 1;
   }
@@ -284,12 +298,12 @@ void silc_server_backup_replaced_del(SilcServer server,
   }
 }
 
-/* Broadcast the received packet indicated by `packet' to all of our backup 
-   routers. All router wide information is passed using broadcast packets. 
+/* Broadcast the received packet indicated by `packet' to all of our backup
+   routers. All router wide information is passed using broadcast packets.
    That is why all backup routers need to get this data too. It is expected
    that the caller already knows that the `packet' is broadcast packet. */
 
-void silc_server_backup_broadcast(SilcServer server, 
+void silc_server_backup_broadcast(SilcServer server,
                                  SilcSocketConnection sender,
                                  SilcPacketContext *packet)
 {
@@ -311,7 +325,7 @@ void silc_server_backup_broadcast(SilcServer server,
   for (i = 0; i < server->backup->servers_count; i++) {
     backup = server->backup->servers[i].server;
 
-    if (!backup || backup->connection == sender || 
+    if (!backup || backup->connection == sender ||
        server->backup->servers[i].local == FALSE)
       continue;
     if (server->backup->servers[i].server == server->id_entry)
@@ -326,7 +340,7 @@ void silc_server_backup_broadcast(SilcServer server,
       return;
     }
     silc_buffer_put((SilcBuffer)&p, buffer->data, buffer->len);
-    silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++, 
+    silc_packet_encrypt(idata->send_key, idata->hmac_send, idata->psn_send++,
                        (SilcBuffer)&p, p.len);
 
     SILC_LOG_HEXDUMP(("Broadcasted packet, len %d", p.len), p.data, p.len);
@@ -382,7 +396,7 @@ void silc_server_backup_send(SilcServer server,
     SILC_LOG_DEBUG(("Sending %s packet to backup router %s (%s)",
                    silc_get_packet_name(type), sock->hostname, sock->ip));
 
-    silc_server_packet_send(server, backup->connection, type, flags, 
+    silc_server_packet_send(server, backup->connection, type, flags,
                            data, data_len, force_send);
   }
 }
@@ -424,41 +438,181 @@ void silc_server_backup_send_dest(SilcServer server,
     SILC_LOG_DEBUG(("Sending %s packet to backup router %s (%s)",
                    silc_get_packet_name(type), sock->hostname, sock->ip));
 
-    silc_server_packet_send_dest(server, backup->connection, type, flags, 
-                                dst_id, dst_id_type, data, data_len, 
+    silc_server_packet_send_dest(server, backup->connection, type, flags,
+                                dst_id, dst_id_type, data, data_len,
                                 force_send);
   }
 }
 
+/* Send the START_USE indication to remote connection.  If `failure' is
+   TRUE then this sends SILC_PACKET_FAILURE.  Otherwise it sends
+   SILC_PACKET_RESUME_ROUTER. */
+
+void silc_server_backup_send_start_use(SilcServer server,
+                                      SilcSocketConnection sock,
+                                      bool failure)
+{
+  unsigned char data[4];
+
+  SILC_LOG_DEBUG(("Sending START_USE (%s) to %s",
+                 failure ? "failure" : "success", sock->ip));
+
+  if (failure) {
+    SILC_PUT32_MSB(SILC_SERVER_BACKUP_START_USE, data);
+    silc_server_packet_send(server, sock, SILC_PACKET_FAILURE, 0,
+                           data, 4, FALSE);
+  } else {
+    data[0] = SILC_SERVER_BACKUP_START_USE;
+    data[1] = 0;
+    silc_server_packet_send(server, sock,
+                           SILC_PACKET_RESUME_ROUTER, 0,
+                           data, 2, FALSE);
+  }
+}
+
+/* Send the REPLACED indication to remote router.  This is send by the
+   primary router (remote router) of the primary router that came back
+   online.  This is not sent by backup router or any other server. */
+
+void silc_server_backup_send_replaced(SilcServer server,
+                                     SilcSocketConnection sock)
+{
+  unsigned char data[4];
+
+  SILC_LOG_DEBUG(("Sending REPLACED (%s) to %s", sock->ip));
+
+  data[0] = SILC_SERVER_BACKUP_REPLACED;
+  data[1] = 0;
+  silc_server_packet_send(server, sock,
+                         SILC_PACKET_RESUME_ROUTER, 0,
+                         data, 2, FALSE);
+}
+
+
+/************************ Backup Resuming Protocol **************************/
+
+/* Timeout callback for protocol */
+
 SILC_TASK_CALLBACK(silc_server_backup_timeout)
 {
   SilcProtocol protocol = context;
+  SilcServerBackupProtocolContext ctx = protocol->context;
   SilcServer server = app_context;
 
   SILC_LOG_INFO(("Timeout occurred during backup resuming protocol"));
+  ctx->timeout = TRUE;
   silc_protocol_cancel(protocol, server->schedule);
   protocol->state = SILC_PROTOCOL_STATE_ERROR;
   silc_protocol_execute_final(protocol, server->schedule);
 }
 
+/* Callback to start the protocol as responder */
+
+SILC_TASK_CALLBACK(silc_server_backup_responder_start)
+{
+  SilcServerBackupProtocolContext proto_ctx = context;
+  SilcSocketConnection sock = proto_ctx->sock;
+  SilcServer server = app_context;
+
+  /* If other protocol is executing at the same time, start with timeout. */
+  if (sock->protocol) {
+    SILC_LOG_DEBUG(("Other protocol is executing, wait for it to finish"));
+    silc_schedule_task_add(server->schedule, sock->sock,
+                          silc_server_backup_responder_start,
+                          proto_ctx, 2, 0,
+                          SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+    return;
+  }
+
+  /* Run the backup resuming protocol */
+  silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
+                     &sock->protocol, proto_ctx,
+                     silc_server_protocol_backup_done);
+  silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
+  silc_schedule_task_add(server->schedule, sock->sock,
+                        silc_server_backup_timeout,
+                        sock->protocol, 30, 0, SILC_TASK_TIMEOUT,
+                        SILC_TASK_PRI_NORMAL);
+}
+
+/* Callback to send START_USE to backup to check whether using backup
+   is ok. */
+
+SILC_TASK_CALLBACK(silc_server_backup_check_status)
+{
+  SilcSocketConnection sock = context;
+  SilcServer server = app_context;
+
+  /* Check whether we are still using backup */
+  if (!server->backup_primary)
+    return;
+
+  silc_server_backup_send_start_use(server, sock, FALSE);
+  silc_socket_free(sock);      /* unref */
+}
+
+typedef struct {
+  SilcServer server;
+  SilcSocketConnection sock;
+  SilcPacketContext *packet;
+} *SilcServerBackupPing;
+
+/* PING command reply callback */
+
+void silc_server_backup_ping_reply(void *context, void *reply)
+{
+  SilcServerBackupPing pc = context;
+  SilcServerCommandReplyContext cmdr = reply;
+
+  if (cmdr && !silc_command_get_status(cmdr->payload, NULL, NULL)) {
+    /* Timeout error occurred, the primary is really down. */
+    SilcSocketConnection primary = SILC_PRIMARY_ROUTE(pc->server);
+
+    SILC_LOG_DEBUG(("PING timeout, primary is down"));
+
+    if (primary) {
+      if (primary->user_data)
+       silc_server_free_sock_user_data(pc->server, primary, NULL);
+      SILC_SET_DISCONNECTING(primary);
+      silc_server_close_connection(pc->server, primary);
+    }
+
+    /* Reprocess the RESUME_ROUTER packet */
+    silc_server_backup_resume_router(pc->server, pc->sock, pc->packet);
+  } else {
+    /* The primary is not down, refuse to serve the server as primary */
+    SILC_LOG_DEBUG(("PING received, primary is up"));
+    silc_server_backup_send_start_use(pc->server, pc->sock, TRUE);
+  }
+
+  silc_socket_free(pc->sock);
+  silc_packet_context_free(pc->packet);
+  silc_free(pc);
+}
+
 /* Processes incoming RESUME_ROUTER packet. This can give the packet
    for processing to the protocol handler or allocate new protocol if
    start command is received. */
 
-void silc_server_backup_resume_router(SilcServer server, 
-                                     SilcSocketConnection sock, 
+void silc_server_backup_resume_router(SilcServer server,
+                                     SilcSocketConnection sock,
                                      SilcPacketContext *packet)
 {
   SilcUInt8 type, session;
   SilcServerBackupProtocolContext ctx;
+  SilcIDListData idata;
   int i, ret;
 
+  SILC_LOG_DEBUG(("Received RESUME_ROUTER packet"));
+
   if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
       sock->type == SILC_SOCKET_TYPE_UNKNOWN) {
     SILC_LOG_DEBUG(("Bad packet received"));
     return;
   }
 
+  idata = (SilcIDListData)sock->user_data;
+
   ret = silc_buffer_unformat(packet->buffer,
                             SILC_STR_UI_CHAR(&type),
                             SILC_STR_UI_CHAR(&session),
@@ -467,81 +621,83 @@ void silc_server_backup_resume_router(SilcServer server,
     SILC_LOG_ERROR(("Malformed resume router packet received"));
     return;
   }
-  
-  /* Activate the protocol for this socket if necessary */
-  if ((type == SILC_SERVER_BACKUP_RESUMED || 
-      type == SILC_SERVER_BACKUP_RESUMED_GLOBAL) &&
-      sock->type == SILC_SOCKET_TYPE_ROUTER && !sock->protocol && 
-      ((SilcIDListData)sock->user_data)->status & 
-      SILC_IDLIST_STATUS_DISABLED) {
-    SilcServerEntry backup_router;
 
-    if (silc_server_backup_replaced_get(server, 
-                                       ((SilcServerEntry)sock->
-                                        user_data)->id, 
-                                       &backup_router)) {
-      SilcSocketConnection bsock = 
-       (SilcSocketConnection)backup_router->connection;
-      if (bsock->protocol && bsock->protocol->protocol &&
-         bsock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP) {
-       sock->protocol = bsock->protocol;
-       ctx = sock->protocol->context;
-       ctx->sock = sock;
-      }
+  /* Check whether this packet is used to tell us that server will start
+     using us as primary router. */
+  if (type == SILC_SERVER_BACKUP_START_USE) {
+    SilcBuffer idp;
+    SilcServerBackupPing pc;
+
+    /* If we are normal server then backup router has sent us back
+       this reply and we use the backup as primary router now. */
+    if (server->server_type == SILC_SERVER) {
+      /* Nothing to do here actually, since we have switched already. */
+      SILC_LOG_DEBUG(("Received successful START_USE from backup router"));
+      return;
     }
-  }
 
-  /* If the backup resuming protocol is active then process the packet
-     in the protocol. */
-  if (sock->protocol && sock->protocol->protocol &&
-      sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP) {
-    ctx = sock->protocol->context;
-    ctx->type = type;
+    /* Backup router following. */
 
-    if (type != SILC_SERVER_BACKUP_RESUMED &&
-       type != SILC_SERVER_BACKUP_RESUMED_GLOBAL) {
-      for (i = 0; i < ctx->sessions_count; i++) {
-       if (session == ctx->sessions[i].session) {
-         ctx->session = session;
-         silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
-         return;
-       }
-      }
-    } else {
-      silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
+    /* If we are marked as router then the primary is down and we send
+       success START_USE back to the server. */
+    if (server->server_type == SILC_ROUTER) {
+      SILC_LOG_DEBUG(("Sending success START_USE back to %s", sock->ip));
+      silc_server_backup_send_start_use(server, sock, FALSE);
       return;
     }
 
-    SILC_LOG_ERROR(("Bad resume router packet RESUMED %d", type));
-    return;
-  }
-
-  /* We don't have protocol active. If we are router and the packet is 
-     coming from our primary router then lets check whether it means we've
-     been replaced by an backup router in my cell. This is usually received
-     immediately after we've connected to our primary router. */
+    /* We have just lost primary, send success START_USE back */
+    if (server->standalone) {
+      SILC_LOG_DEBUG(("We are stanalone, sending success START_USE back to %s",
+                     sock->ip));
+      silc_server_backup_send_start_use(server, sock, FALSE);
+      return;
+    }
 
-  if (sock->type == SILC_SOCKET_TYPE_ROUTER &&
-      sock && SILC_PRIMARY_ROUTE(server) == sock &&
-      type == SILC_SERVER_BACKUP_REPLACED) {
-    /* We have been replaced by an backup router in our cell. We must
-       mark our primary router connection disabled since we are not allowed
-       to use it at this moment. */
-    SilcIDListData idata = (SilcIDListData)sock->user_data;
-    SILC_LOG_INFO(("We are replaced by an backup router in this cell, will "
-                  "wait until backup resuming protocol is executed"));
-    idata->status |= SILC_IDLIST_STATUS_DISABLED;
+    /* We are backup router. This server claims that our primary is down.
+       We will check this ourselves by sending PING command to the primary. */
+    SILC_LOG_DEBUG(("Sending PING to detect status of primary router"));
+    idp = silc_id_payload_encode(server->router->id, SILC_ID_SERVER);
+    silc_server_send_command(server, SILC_PRIMARY_ROUTE(server),
+                            SILC_COMMAND_PING, ++server->cmd_ident, 1,
+                            1, idp->data, idp->len);
+    silc_buffer_free(idp);
+
+    /* Reprocess this packet after received reply from router */
+    pc = silc_calloc(1, sizeof(*pc));
+    pc->server = server;
+    pc->sock = silc_socket_dup(sock);
+    pc->packet = silc_packet_context_dup(packet);
+    silc_server_command_pending_timed(server, SILC_COMMAND_PING,
+                                     server->cmd_ident,
+                                     silc_server_backup_ping_reply, pc, 15);
     return;
   }
 
-  if (type == SILC_SERVER_BACKUP_START ||
-      type == SILC_SERVER_BACKUP_START_GLOBAL) {
-    /* We have received a start for resuming protocol. */
+
+  /* Start the resuming protocol if requested. */
+  if (type == SILC_SERVER_BACKUP_START) {
+    /* We have received a start for resuming protocol.  We are either
+       primary router that came back online or normal server. */
     SilcServerBackupProtocolContext proto_ctx;
 
+    /* If backup had closed the connection earlier we won't allow resuming
+       since we (primary router) have never gone away. */
+    if (server->server_type == SILC_ROUTER && !server->backup_router &&
+       server->backup_closed) {
+      unsigned char data[4];
+      SILC_LOG_DEBUG(("Backup resuming not allowed since we are still "
+                     "primary router"));
+      SILC_PUT32_MSB(SILC_SERVER_BACKUP_START, data);
+      silc_server_packet_send(server, sock, SILC_PACKET_FAILURE, 0,
+                             data, 4, FALSE);
+      server->backup_closed = FALSE;
+      return;
+    }
+
     proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
     proto_ctx->server = server;
-    proto_ctx->sock = sock;
+    proto_ctx->sock = silc_socket_dup(sock);
     proto_ctx->responder = TRUE;
     proto_ctx->type = type;
     proto_ctx->session = session;
@@ -550,15 +706,75 @@ void silc_server_backup_resume_router(SilcServer server,
     SILC_LOG_DEBUG(("Starting backup resuming protocol as responder"));
     SILC_LOG_INFO(("Starting backup resuming protocol"));
 
-    /* Run the backup resuming protocol */
-    silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
-                       &sock->protocol, proto_ctx, 
-                       silc_server_protocol_backup_done);
-    silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
+    /* Start protocol immediately */
     silc_schedule_task_add(server->schedule, sock->sock,
-                          silc_server_backup_timeout,
-                          sock->protocol, 30, 0, SILC_TASK_TIMEOUT,
-                          SILC_TASK_PRI_NORMAL);
+                          silc_server_backup_responder_start,
+                          proto_ctx, 0, 1,
+                          SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+    return;
+  }
+
+
+  /* If we are router and the packet is coming from our primary router
+     then it means we have been replaced by an backup router in our cell. */
+  if (type == SILC_SERVER_BACKUP_REPLACED &&
+      server->server_type == SILC_ROUTER &&
+      sock->type == SILC_SOCKET_TYPE_ROUTER &&
+      SILC_PRIMARY_ROUTE(server) == sock) {
+    /* We have been replaced by an backup router in our cell. We must
+       mark our primary router connection disabled since we are not allowed
+       to use it at this moment. */
+    SILC_LOG_INFO(("We are replaced by an backup router in this cell, will "
+                  "wait until backup resuming protocol is executed"));
+    idata->status |= SILC_IDLIST_STATUS_DISABLED;
+    return;
+  }
+
+
+  /* Activate the shared protocol context for this socket connection
+     if necessary */
+  if (type == SILC_SERVER_BACKUP_RESUMED &&
+      sock->type == SILC_SOCKET_TYPE_ROUTER && !sock->protocol &&
+      idata->status & SILC_IDLIST_STATUS_DISABLED) {
+    SilcServerEntry backup_router;
+
+    if (silc_server_backup_replaced_get(server, ((SilcServerEntry)idata)->id,
+                                       &backup_router)) {
+      SilcSocketConnection bsock =
+       (SilcSocketConnection)backup_router->connection;
+      if (bsock->protocol && bsock->protocol->protocol &&
+         bsock->protocol->protocol->type == SILC_PROTOCOL_SERVER_BACKUP) {
+       sock->protocol = bsock->protocol;
+       ctx = sock->protocol->context;
+       if (ctx->sock)
+         silc_socket_free(ctx->sock); /* unref */
+       ctx->sock = silc_socket_dup(sock);
+      }
+    }
+  }
+
+
+  /* Call the resuming protocol if the protocol is active. */
+  if (SILC_SERVER_IS_BACKUP(sock)) {
+    ctx = sock->protocol->context;
+    ctx->type = type;
+
+    for (i = 0; i < ctx->sessions_count; i++) {
+      if (session == ctx->sessions[i].session) {
+       ctx->session = session;
+       silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
+       return;
+      }
+    }
+
+    /* If RESUMED received the session ID is zero, execute the protocol. */
+    if (type == SILC_SERVER_BACKUP_RESUMED) {
+      silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
+      return;
+    }
+
+    SILC_LOG_ERROR(("Unknown backup resuming session %d", session));
+    return;
   }
 }
 
@@ -580,9 +796,17 @@ SILC_TASK_CALLBACK(silc_server_backup_connect_to_router)
   sock = silc_net_create_connection(server_ip, sconn->remote_port,
                                    sconn->remote_host);
   if (sock < 0) {
+    if (server->server_type == SILC_SERVER) {
+      sconn->retry_count++;
+      if (sconn->retry_count > 3) {
+       silc_free(sconn->remote_host);
+       silc_free(sconn);
+       return;
+      }
+    }
     silc_schedule_task_add(server->schedule, 0,
                           silc_server_backup_connect_to_router,
-                          context, 5, 0, SILC_TASK_TIMEOUT, 
+                          context, 10, 0, SILC_TASK_TIMEOUT,
                           SILC_TASK_PRI_NORMAL);
     return;
   }
@@ -610,7 +834,8 @@ void silc_server_backup_reconnect(SilcServer server,
   sconn->callback = callback;
   sconn->callback_context = context;
   sconn->no_reconnect = TRUE;
-  silc_schedule_task_add(server->schedule, 0, 
+  sconn->retry_count = 0;
+  silc_schedule_task_add(server->schedule, 0,
                         silc_server_backup_connect_to_router,
                         sconn, 1, 0, SILC_TASK_TIMEOUT,
                         SILC_TASK_PRI_NORMAL);
@@ -621,17 +846,28 @@ void silc_server_backup_reconnect(SilcServer server,
 
 SILC_TASK_CALLBACK(silc_server_backup_connected_later)
 {
-  SilcServerBackupProtocolContext proto_ctx = 
+  SilcServerBackupProtocolContext proto_ctx =
     (SilcServerBackupProtocolContext)context;
   SilcServer server = proto_ctx->server;
   SilcSocketConnection sock = proto_ctx->sock;
 
+  /* If running other protocol already run this one a bit later. */
+  if (sock->protocol) {
+    SILC_LOG_DEBUG(("Other protocol is running, wait for it to finish"));
+    silc_schedule_task_add(server->schedule, 0,
+                          silc_server_backup_connected_later,
+                          proto_ctx, 10, 0,
+                          SILC_TASK_TIMEOUT,
+                          SILC_TASK_PRI_NORMAL);
+    return;
+  }
+
   SILC_LOG_DEBUG(("Starting backup resuming protocol as initiator"));
   SILC_LOG_INFO(("Starting backup resuming protocol"));
 
   /* Run the backup resuming protocol */
   silc_protocol_alloc(SILC_PROTOCOL_SERVER_BACKUP,
-                     &sock->protocol, proto_ctx, 
+                     &sock->protocol, proto_ctx,
                      silc_server_protocol_backup_done);
   silc_protocol_execute(sock->protocol, server->schedule, 0, 0);
 
@@ -656,18 +892,21 @@ void silc_server_backup_connected(SilcServer server,
     /* Try again */
     SilcServerConfigRouter *primary;
     primary = silc_server_config_get_primary_router(server);
-    if (primary)
-      silc_server_backup_reconnect(server,
-                                  primary->host, primary->port,
-                                  silc_server_backup_connected,
-                                  context);
+    if (primary) {
+      if (!silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_ROUTER,
+                                          primary->host, primary->port))
+       silc_server_backup_reconnect(server,
+                                    primary->host, primary->port,
+                                    silc_server_backup_connected,
+                                    context);
+    }
     return;
   }
 
   sock = (SilcSocketConnection)server_entry->connection;
   proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
   proto_ctx->server = server;
-  proto_ctx->sock = sock;
+  proto_ctx->sock = silc_socket_dup(sock);
   proto_ctx->responder = FALSE;
   proto_ctx->type = SILC_SERVER_BACKUP_START;
   proto_ctx->start = time(0);
@@ -693,20 +932,36 @@ static void silc_server_backup_connect_primary(SilcServer server,
   SilcServerBackupProtocolContext ctx;
   SilcSocketConnection sock;
   SilcIDListData idata;
-  SilcBuffer buffer;
+  unsigned char data[2];
+
+  if (SILC_IS_DISCONNECTING(backup_router) ||
+      SILC_IS_DISCONNECTED(backup_router)) {
+    silc_socket_free(backup_router);
+    return;
+  }
 
   if (!server_entry) {
     /* Try again */
     SilcServerConfigRouter *primary;
     primary = silc_server_config_get_primary_router(server);
     if (primary)
-      silc_server_backup_reconnect(server,
-                                  primary->host, primary->port,
-                                  silc_server_backup_connect_primary,
-                                  context);
+      if (!silc_server_find_socket_by_host(server, SILC_SOCKET_TYPE_ROUTER,
+                                          primary->host, primary->port))
+       silc_server_backup_reconnect(server,
+                                    primary->host, primary->port,
+                                    silc_server_backup_connect_primary,
+                                    context);
     return;
   }
 
+  /* Unref */
+  silc_socket_free(backup_router);
+
+  if (!backup_router->protocol)
+    return;
+  if (!server_entry->connection)
+    return;
+
   ctx = (SilcServerBackupProtocolContext)backup_router->protocol->context;
   sock = (SilcSocketConnection)server_entry->connection;
   idata = (SilcIDListData)server_entry;
@@ -716,16 +971,10 @@ static void silc_server_backup_connect_primary(SilcServer server,
                ctx->session));
 
   /* Send the CONNECTED packet back to the backup router. */
-  buffer = silc_buffer_alloc(2);
-  silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
-  silc_buffer_format(buffer,
-                    SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_CONNECTED),
-                    SILC_STR_UI_CHAR(ctx->session),
-                    SILC_STR_END);
-  silc_server_packet_send(server, backup_router, 
-                         SILC_PACKET_RESUME_ROUTER, 0, 
-                         buffer->data, buffer->len, FALSE);
-  silc_buffer_free(buffer);
+  data[0] = SILC_SERVER_BACKUP_CONNECTED;
+  data[1] = ctx->session;
+  silc_server_packet_send(server, backup_router,
+                         SILC_PACKET_RESUME_ROUTER, 0, data, 2, FALSE);
 
   /* The primary connection is disabled until it sends the RESUMED packet
      to us. */
@@ -733,38 +982,41 @@ static void silc_server_backup_connect_primary(SilcServer server,
 
   /* Move this protocol context from this backup router connection to
      the primary router connection since it will send the subsequent
-     packets in this protocol. We don't talk with backup router 
+     packets in this protocol. We don't talk with backup router
      anymore. */
   sock->protocol = backup_router->protocol;
-  ctx->sock = (SilcSocketConnection)server_entry->connection;
+  if (ctx->sock)
+    silc_socket_free(ctx->sock); /* unref */
+  ctx->sock = silc_socket_dup(server_entry->connection);
   backup_router->protocol = NULL;
 }
 
+/* Timeout callback used by the backup router to send the ENDING packet
+   to primary router to indicate that it can now resume as being primary
+   router. All CONNECTED packets has been received when we reach this. */
+
 SILC_TASK_CALLBACK(silc_server_backup_send_resumed)
 {
   SilcProtocol protocol = (SilcProtocol)context;
   SilcServerBackupProtocolContext ctx = protocol->context;
   SilcServer server = ctx->server;
-  SilcBuffer packet;
+  unsigned char data[2];
   int i;
 
+  SILC_LOG_DEBUG(("Start"));
+
   for (i = 0; i < ctx->sessions_count; i++)
     if (ctx->sessions[i].server_entry == ctx->sock->user_data)
       ctx->session = ctx->sessions[i].session;
-  
+
   /* We've received all the CONNECTED packets and now we'll send the
      ENDING packet to the new primary router. */
-  packet = silc_buffer_alloc(2);
-  silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
-  silc_buffer_format(packet,
-                    SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_ENDING),
-                    SILC_STR_UI_CHAR(ctx->session),
-                    SILC_STR_END);
-  silc_server_packet_send(server, ctx->sock, 
-                         SILC_PACKET_RESUME_ROUTER, 0, 
-                         packet->data, packet->len, FALSE);
-  silc_buffer_free(packet);
-  
+  data[0] = SILC_SERVER_BACKUP_ENDING;
+  data[1] = ctx->session;
+  silc_server_packet_send(server, ctx->sock, SILC_PACKET_RESUME_ROUTER, 0,
+                         data, sizeof(data), FALSE);
+
+  /* The protocol will go to END state. */
   protocol->state = SILC_PROTOCOL_STATE_END;
 }
 
@@ -776,10 +1028,9 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
   SilcProtocol protocol = (SilcProtocol)context;
   SilcServerBackupProtocolContext ctx = protocol->context;
   SilcServer server = ctx->server;
-  SilcBuffer packet;
-  SilcIDCacheList list;
-  SilcIDCacheEntry id_cache;
   SilcServerEntry server_entry;
+  SilcSocketConnection sock = NULL;
+  unsigned char data[2];
   int i;
 
   if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
@@ -788,126 +1039,63 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
   switch(protocol->state) {
   case SILC_PROTOCOL_STATE_START:
     if (ctx->responder == FALSE) {
-      /* Initiator of the protocol. We are backup router */
-
-      packet = silc_buffer_alloc(2);
-      silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
-
-      /* Send the START packet to primary router and normal servers. */
-      if (silc_idcache_get_all(server->local_list->servers, &list)) {
-       if (silc_idcache_list_first(list, &id_cache)) {
-         while (id_cache) {
-           server_entry = (SilcServerEntry)id_cache->context;
-           if (!server_entry || (server_entry == server->id_entry) || 
-               !server_entry->connection || !server_entry->data.send_key ||
-               (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)) {
-             if (!silc_idcache_list_next(list, &id_cache))
-               break;
-             else
-               continue;
-           }
-
-           ctx->sessions = silc_realloc(ctx->sessions,
-                                        sizeof(*ctx->sessions) *
-                                        (ctx->sessions_count + 1));
-           ctx->sessions[ctx->sessions_count].session = ctx->sessions_count;
-           ctx->sessions[ctx->sessions_count].connected = FALSE;
-           ctx->sessions[ctx->sessions_count].server_entry = server_entry;
-
-           SILC_LOG_DEBUG(("Sending START to %s (session %d)",
-                           server_entry->server_name, ctx->sessions_count));
-           SILC_LOG_INFO(("Expecting CONNECTED from %s (session %d)",
-                           server_entry->server_name, ctx->sessions_count));
-
-           /* This connection is performing this protocol too now */
-           ((SilcSocketConnection)server_entry->connection)->protocol =
-             protocol;
-
-           if (server_entry->server_type == SILC_ROUTER)
-             packet->data[0] = SILC_SERVER_BACKUP_START;
-           else
-             packet->data[0] = SILC_SERVER_BACKUP_START_GLOBAL;
-           packet->data[1] = ctx->sessions_count;
-           silc_server_packet_send(server, server_entry->connection,
-                                   SILC_PACKET_RESUME_ROUTER, 0, 
-                                   packet->data, packet->len, FALSE);
-           ctx->sessions_count++;
-
-           if (!silc_idcache_list_next(list, &id_cache))
-             break;
-         }
-       }
-
-       silc_idcache_list_free(list);
+      /*
+       * Initiator (backup router)
+       */
+
+      /* Send the START packet to primary router and normal servers. The
+        packet will indicate to the primary router that it has been replaced
+        by us.  For normal servers it means that we will be resigning as
+        being primary router shortly. */
+      for (i = 0; i < server->config->param.connections_max; i++) {
+       sock = server->sockets[i];
+       if (!sock || !sock->user_data ||
+           sock->user_data == server->id_entry ||
+           (sock->type != SILC_SOCKET_TYPE_ROUTER &&
+            sock->type != SILC_SOCKET_TYPE_SERVER))
+         continue;
+
+       server_entry = sock->user_data;
+       if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
+         continue;
+
+       ctx->sessions = silc_realloc(ctx->sessions,
+                                    sizeof(*ctx->sessions) *
+                                    (ctx->sessions_count + 1));
+       ctx->sessions[ctx->sessions_count].session = ctx->sessions_count;
+       ctx->sessions[ctx->sessions_count].connected = FALSE;
+       ctx->sessions[ctx->sessions_count].server_entry = server_entry;
+
+       SILC_LOG_DEBUG(("Sending START to %s (session %d)",
+                       server_entry->server_name, ctx->sessions_count));
+       SILC_LOG_INFO(("Expecting CONNECTED from %s (session %d)",
+                      server_entry->server_name, ctx->sessions_count));
+
+       /* This connection is performing this protocol too now */
+       sock->protocol = protocol;
+
+       data[0] = SILC_SERVER_BACKUP_START;
+       data[1] = ctx->sessions_count;
+       silc_server_packet_send(server, sock, SILC_PACKET_RESUME_ROUTER, 0,
+                               data, sizeof(data), FALSE);
+       ctx->sessions_count++;
       }
 
-      if (silc_idcache_get_all(server->global_list->servers, &list)) {
-       if (silc_idcache_list_first(list, &id_cache)) {
-         while (id_cache) {
-           server_entry = (SilcServerEntry)id_cache->context;
-           if (!server_entry || (server_entry == server->id_entry) || 
-               !server_entry->connection || !server_entry->data.send_key ||
-               (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)) {
-             if (!silc_idcache_list_next(list, &id_cache))
-               break;
-             else
-               continue;
-           }
-
-           ctx->sessions = silc_realloc(ctx->sessions,
-                                        sizeof(*ctx->sessions) *
-                                        (ctx->sessions_count + 1));
-           ctx->sessions[ctx->sessions_count].session = ctx->sessions_count;
-           ctx->sessions[ctx->sessions_count].connected = FALSE;
-           ctx->sessions[ctx->sessions_count].server_entry = server_entry;
-
-           SILC_LOG_DEBUG(("Sending START to %s (session %d)", 
-                           server_entry->server_name, ctx->sessions_count));
-           SILC_LOG_INFO(("Expecting CONNECTED from %s (session %d)",
-                           server_entry->server_name, ctx->sessions_count));
-
-           /* This connection is performing this protocol too now */
-           ((SilcSocketConnection)server_entry->connection)->protocol =
-             protocol;
-
-           if (server_entry->server_type == SILC_ROUTER)
-             packet->data[0] = SILC_SERVER_BACKUP_START;
-           else
-             packet->data[0] = SILC_SERVER_BACKUP_START_GLOBAL;
-           packet->data[1] = ctx->sessions_count;
-           silc_server_packet_send(server, server_entry->connection,
-                                   SILC_PACKET_RESUME_ROUTER, 0, 
-                                   packet->data, packet->len, FALSE);
-           ctx->sessions_count++;
-
-           if (!silc_idcache_list_next(list, &id_cache))
-             break;
-         }
-       }
-
-       silc_idcache_list_free(list);
-      }
-
-      silc_buffer_free(packet);
-
-      /* If we are not standalone and our primary is not the one we've
-        talking to now, then announce our information to it since we
-        haven't done that yet.  Standalone backup router announces
-        these during connecting to the primary. */
-      if (!server->standalone && SILC_PRIMARY_ROUTE(server) != ctx->sock) {
-       silc_server_announce_servers(server, TRUE, 0, ctx->sock);
-       silc_server_announce_clients(server, 0, ctx->sock);
-       silc_server_announce_channels(server, 0, ctx->sock);
-      }
+      /* Announce data to the new primary to be. */
+      silc_server_announce_servers(server, TRUE, 0, ctx->sock);
+      silc_server_announce_clients(server, 0, ctx->sock);
+      silc_server_announce_channels(server, 0, ctx->sock);
 
       protocol->state++;
+
     } else {
-      /* Responder of the protocol. */
+      /*
+       * Responder (all servers and routers)
+       */
       SilcServerConfigRouter *primary;
 
-      /* We should have received START or START_GLOBAL packet */
-      if (ctx->type != SILC_SERVER_BACKUP_START &&
-         ctx->type != SILC_SERVER_BACKUP_START_GLOBAL) {
+      /* We should have received START packet */
+      if (ctx->type != SILC_SERVER_BACKUP_START) {
        SILC_LOG_ERROR(("Bad resume router packet START %d", ctx->type));
        break;
       }
@@ -929,7 +1117,7 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
        silc_server_backup_reconnect(server,
                                     primary->host, primary->port,
                                     silc_server_backup_connect_primary,
-                                    ctx->sock);
+                                    silc_socket_dup(ctx->sock));
       } else {
        /* Nowhere to connect just return the CONNECTED packet */
        SILC_LOG_DEBUG(("Received START (session %d), send CONNECTED back",
@@ -938,36 +1126,35 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
                      ctx->session));
 
        /* Send the CONNECTED packet back to the backup router. */
-       packet = silc_buffer_alloc(2);
-       silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
-       silc_buffer_format(packet,
-                          SILC_STR_UI_CHAR(SILC_SERVER_BACKUP_CONNECTED),
-                          SILC_STR_UI_CHAR(ctx->session),
-                          SILC_STR_END);
-       silc_server_packet_send(server, ctx->sock, 
-                               SILC_PACKET_RESUME_ROUTER, 0, 
-                               packet->data, packet->len, FALSE);
-       silc_buffer_free(packet);
+       data[0] = SILC_SERVER_BACKUP_CONNECTED;
+       data[1] = ctx->session;
+       silc_server_packet_send(server, ctx->sock,
+                               SILC_PACKET_RESUME_ROUTER, 0,
+                               data, sizeof(data), FALSE);
       }
 
-      if (server->server_type == SILC_ROUTER &&
-         (!server->router || 
-          server->router->data.status & SILC_IDLIST_STATUS_DISABLED))
-       protocol->state++;
-      else
-       protocol->state = SILC_PROTOCOL_STATE_END;
-
+      /* Add this resuming session */
       ctx->sessions = silc_realloc(ctx->sessions,
                                   sizeof(*ctx->sessions) *
                                   (ctx->sessions_count + 1));
       ctx->sessions[ctx->sessions_count].session = ctx->session;
       ctx->sessions_count++;
+
+      /* Normal server goes directly to the END state. */
+      if (server->server_type == SILC_ROUTER &&
+         (!server->router ||
+          server->router->data.status & SILC_IDLIST_STATUS_DISABLED))
+       protocol->state++;
+      else
+       protocol->state = SILC_PROTOCOL_STATE_END;
     }
     break;
 
   case 2:
     if (ctx->responder == FALSE) {
-      /* Initiator */
+      /*
+       * Initiator (backup router)
+       */
 
       /* We should have received CONNECTED packet */
       if (ctx->type != SILC_SERVER_BACKUP_CONNECTED) {
@@ -986,6 +1173,7 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
        }
       }
 
+      /* See if all returned CONNECTED, if not, then continue waiting. */
       for (i = 0; i < ctx->sessions_count; i++) {
        if (!ctx->sessions[i].connected)
          return;
@@ -995,14 +1183,18 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
                     "continuing"));
       SILC_LOG_DEBUG(("Sending ENDING packet to primary router"));
 
-      /* Send with a timeout */
-      silc_schedule_task_add(server->schedule, 0, 
+      /* The ENDING is sent with timeout, and then we continue to the
+        END state in the protocol. */
+      silc_schedule_task_add(server->schedule, 0,
                             silc_server_backup_send_resumed,
                             protocol, 1, 0, SILC_TASK_TIMEOUT,
                             SILC_TASK_PRI_NORMAL);
       return;
+
     } else {
-      /* Responder */
+      /*
+       * Responder (primary router)
+       */
 
       /* We should have been received ENDING packet */
       if (ctx->type != SILC_SERVER_BACKUP_ENDING) {
@@ -1012,114 +1204,55 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
 
       SILC_LOG_DEBUG(("Received ENDING packet, we are going to resume now"));
 
-      /* This state is received by the primary router but also servers
-        and perhaps other routers so check that if we are the primary
-        router of the cell then start sending RESUMED packets.  If we
-        are normal server or one of those other routers then procede
-        to next state. */
-      if (server->router &&
-         !(server->router->data.status & SILC_IDLIST_STATUS_DISABLED) &&
-         silc_server_config_is_primary_route(server)) {
-       /* We'll wait for RESUMED packet */
-       protocol->state = SILC_PROTOCOL_STATE_END;
-       break;
-      }
-
       /* Switch announced informations to our primary router of using the
         backup router. */
       silc_server_local_servers_toggle_enabled(server, TRUE);
-      silc_server_update_servers_by_server(server, ctx->sock->user_data, 
+      silc_server_update_servers_by_server(server, ctx->sock->user_data,
                                           server->router);
       silc_server_update_clients_by_server(server, ctx->sock->user_data,
                                           server->router, TRUE);
-      if (server->server_type == SILC_SERVER)
-       silc_server_update_channels_by_server(server, ctx->sock->user_data, 
-                                             server->router);
-
-      packet = silc_buffer_alloc(2);
-      silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
-
-      /* We are the primary router, start sending RESUMED packets. */
-      if (silc_idcache_get_all(server->local_list->servers, &list)) {
-       if (silc_idcache_list_first(list, &id_cache)) {
-         while (id_cache) {
-           server_entry = (SilcServerEntry)id_cache->context;
-           if (!server_entry || (server_entry == server->id_entry) || 
-               !server_entry->connection || !server_entry->data.send_key) {
-             if (!silc_idcache_list_next(list, &id_cache))
-               break;
-             else
-               continue;
-           }
-
-           SILC_LOG_DEBUG(("Sending RESUMED to %s",
-                           server_entry->server_name));
-           SILC_LOG_INFO(("Sending RESUMED to %s",
-                          server_entry->server_name));
-
-           server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
-
-           /* This connection is performing this protocol too now */
-           ((SilcSocketConnection)server_entry->connection)->protocol =
-             protocol;
-
-           if (server_entry->server_type == SILC_ROUTER)
-             packet->data[0] = SILC_SERVER_BACKUP_RESUMED;
-           else
-             packet->data[0] = SILC_SERVER_BACKUP_RESUMED_GLOBAL;
-           silc_server_packet_send(server, server_entry->connection,
-                                   SILC_PACKET_RESUME_ROUTER, 0, 
-                                   packet->data, packet->len, FALSE);
 
-           if (!silc_idcache_list_next(list, &id_cache))
-             break;
-         }
-       }
-
-       silc_idcache_list_free(list);
+      /* We as primary router now must send RESUMED packets to all servers
+        and routers so that they know we are back.   For backup router we
+        send the packet last so that we give the backup as much time as
+        possible to deal with message routing at this critical moment. */
+      for (i = 0; i < server->config->param.connections_max; i++) {
+       sock = server->sockets[i];
+       if (!sock || !sock->user_data ||
+           sock->user_data == server->id_entry ||
+           (sock->type != SILC_SOCKET_TYPE_ROUTER &&
+            sock->type != SILC_SOCKET_TYPE_SERVER))
+         continue;
+
+       /* Send to backup last */
+       if (sock == ctx->sock)
+         continue;
+
+      send_to_backup:
+       server_entry = sock->user_data;
+       server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
+
+       SILC_LOG_DEBUG(("Sending RESUMED to %s", server_entry->server_name));
+       SILC_LOG_INFO(("Sending RESUMED to %s", server_entry->server_name));
+
+       /* This connection is performing this protocol too now */
+       sock->protocol = protocol;
+
+       data[0] = SILC_SERVER_BACKUP_RESUMED;
+       data[1] = 0;
+       silc_server_packet_send(server, sock, SILC_PACKET_RESUME_ROUTER, 0,
+                               data, sizeof(data), FALSE);
+       silc_server_packet_queue_purge(server, sock);
       }
 
-      if (silc_idcache_get_all(server->global_list->servers, &list)) {
-       if (silc_idcache_list_first(list, &id_cache)) {
-         while (id_cache) {
-           server_entry = (SilcServerEntry)id_cache->context;
-           if (!server_entry || (server_entry == server->id_entry) || 
-               !server_entry->connection || !server_entry->data.send_key) {
-             if (!silc_idcache_list_next(list, &id_cache))
-               break;
-             else
-               continue;
-           }
-
-           SILC_LOG_DEBUG(("Sending RESUMED to %s",
-                           server_entry->server_name));
-           SILC_LOG_INFO(("Sending RESUMED to %s",
-                          server_entry->server_name));
-
-           server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
-
-           /* This connection is performing this protocol too now */
-           ((SilcSocketConnection)server_entry->connection)->protocol =
-             protocol;
-
-           if (server_entry->server_type == SILC_ROUTER)
-             packet->data[0] = SILC_SERVER_BACKUP_RESUMED;
-           else
-             packet->data[0] = SILC_SERVER_BACKUP_RESUMED_GLOBAL;
-           silc_server_packet_send(server, server_entry->connection,
-                                   SILC_PACKET_RESUME_ROUTER, 0, 
-                                   packet->data, packet->len, FALSE);
-
-           if (!silc_idcache_list_next(list, &id_cache))
-             break;
-         }
-       }
-
-       silc_idcache_list_free(list);
+      /* Now send the same packet to backup */
+      if (sock != ctx->sock) {
+       sleep(1);
+       sock = ctx->sock;
+       goto send_to_backup;
       }
 
-      silc_buffer_free(packet);
-
+      /* We are now resumed and are back as primary router in the cell. */
       SILC_LOG_INFO(("We are now the primary router of our cell again"));
       server->wait_backup = FALSE;
 
@@ -1133,24 +1266,27 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
 
   case SILC_PROTOCOL_STATE_END:
     {
+      /*
+       * Responder (backup router, servers, and remote router)
+       */
       SilcServerEntry router, backup_router;
 
-      /* We should have been received RESUMED packet from our primary
-        router. */
-      if (ctx->type != SILC_SERVER_BACKUP_RESUMED &&
-         ctx->type != SILC_SERVER_BACKUP_RESUMED_GLOBAL) {
+      /* We should have been received RESUMED from our primary router. */
+      if (ctx->type != SILC_SERVER_BACKUP_RESUMED) {
        SILC_LOG_ERROR(("Bad resume router packet RESUMED %d", ctx->type));
        break;
       }
 
       SILC_LOG_INFO(("Received RESUMED from new primary router"));
 
+      /* If we are the backup router, mark that we are no longer primary
+        but are back to backup router status. */
       if (server->backup_router)
        server->server_type = SILC_BACKUP_ROUTER;
 
       /* We have now new primary router. All traffic goes there from now on. */
-      router = (SilcServerEntry)ctx->sock->user_data;
-      if (silc_server_backup_replaced_get(server, router->id, 
+      router = ctx->sock->user_data;
+      if (silc_server_backup_replaced_get(server, router->id,
                                          &backup_router)) {
 
        if (backup_router == server->router) {
@@ -1165,27 +1301,19 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
                         router->server_name));
        }
        server->backup_primary = FALSE;
+       sock = router->connection;
 
-       /* Update the client entries of the backup router to the new 
+       /* Update the client entries of the backup router to the new
           router */
        silc_server_local_servers_toggle_enabled(server, FALSE);
        router->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
        silc_server_update_servers_by_server(server, backup_router, router);
-       silc_server_update_clients_by_server(server, NULL, router, FALSE);
+       silc_server_update_clients_by_server(
+                                  server, NULL, router,
+                                  server->server_type == SILC_BACKUP_ROUTER);
        if (server->server_type == SILC_SERVER)
          silc_server_update_channels_by_server(server, backup_router, router);
        silc_server_backup_replaced_del(server, backup_router);
-
-       /* Announce all of our information to the router. */
-       if (server->server_type == SILC_ROUTER)
-         silc_server_announce_servers(server, FALSE, ctx->start,
-                                      router->connection);
-
-       /* Announce our clients and channels to the router */
-       silc_server_announce_clients(server, ctx->start,
-                                    router->connection);
-       silc_server_announce_channels(server, ctx->start,
-                                     router->connection);
       }
 
       /* Send notify about primary router going down to local operators */
@@ -1214,6 +1342,7 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
   case SILC_PROTOCOL_STATE_FAILURE:
     /* Protocol has ended, call the final callback */
     SILC_LOG_ERROR(("Error during backup resume: received Failure"));
+    ctx->received_failure = TRUE;
     if (protocol->final_callback)
       silc_protocol_execute_final(protocol, server->schedule);
     else
@@ -1225,6 +1354,8 @@ SILC_TASK_CALLBACK_GLOBAL(silc_server_protocol_backup)
   }
 }
 
+/* Final resuming protocol completion callback */
+
 SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
 {
   SilcProtocol protocol = (SilcProtocol)context;
@@ -1232,106 +1363,145 @@ SILC_TASK_CALLBACK(silc_server_protocol_backup_done)
   SilcServer server = ctx->server;
   SilcServerEntry server_entry;
   SilcSocketConnection sock;
-  SilcIDCacheList list;
-  SilcIDCacheEntry id_cache;
+  bool error;
+  int i;
 
   silc_schedule_task_del_by_context(server->schedule, protocol);
 
-  if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
-      protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
+  error = (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
+          protocol->state == SILC_PROTOCOL_STATE_FAILURE);
+
+  if (error) {
     SILC_LOG_ERROR(("Error occurred during backup router resuming protcool"));
+    if (server->server_type == SILC_SERVER)
+      silc_schedule_task_del_by_callback(server->schedule,
+                                        silc_server_backup_connect_to_router);
   }
 
   if (server->server_shutdown)
     return;
 
   /* Remove this protocol from all server entries that has it */
-  if (silc_idcache_get_all(server->local_list->servers, &list)) {
-    if (silc_idcache_list_first(list, &id_cache)) {
-      while (id_cache) {
-       server_entry = (SilcServerEntry)id_cache->context;
-       sock = (SilcSocketConnection)server_entry->connection;
-
-       if (sock->protocol == protocol) {
-         sock->protocol = NULL;
-
-         /* Backup closes connection and reconnects if error occurred */
-         if (SILC_PRIMARY_ROUTE(server) == sock && server->backup_router) {
-           if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
-               protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
-             server->backup_noswitch = TRUE;
-             server->server_type = SILC_BACKUP_ROUTER;
-             if (ctx->sock == sock)
-               ctx->sock = NULL;
-
-             if (sock->user_data)
-               silc_server_free_sock_user_data(server, sock, NULL);
-             silc_server_close_connection(server, sock);
-             silc_server_create_connections(server);
-
-             if (!silc_idcache_list_next(list, &id_cache))
-               break;
-             continue;
-           }
+  for (i = 0; i < server->config->param.connections_max; i++) {
+    sock = server->sockets[i];
+    if (!sock || !sock->user_data ||
+       (sock->type != SILC_SOCKET_TYPE_ROUTER &&
+        sock->type != SILC_SOCKET_TYPE_SERVER))
+      continue;
+
+    server_entry = sock->user_data;
+
+    /* The SilcProtocol context was shared between all connections, clear
+       it from all connections. */
+    if (sock->protocol == protocol) {
+      silc_server_packet_queue_purge(server, sock);
+      sock->protocol = NULL;
+
+      if (error) {
+
+       if (server->server_type == SILC_SERVER &&
+           server_entry->server_type == SILC_ROUTER)
+         continue;
+
+       /* Backup router */
+       if (SILC_PRIMARY_ROUTE(server) == sock && server->backup_router) {
+         if (ctx->sock == sock) {
+           silc_socket_free(sock); /* unref */
+           ctx->sock = NULL;
          }
 
-         if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
+         if (!ctx->received_failure) {
+           /* Protocol error, probably timeout. Just restart the protocol. */
+           SilcServerBackupProtocolContext proto_ctx;
+
+           /* Restart the protocol. */
+           proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+           proto_ctx->server = server;
+           proto_ctx->sock = silc_socket_dup(sock);
+           proto_ctx->responder = FALSE;
+           proto_ctx->type = SILC_SERVER_BACKUP_START;
+           proto_ctx->start = time(0);
+
+           /* Start through scheduler */
+           silc_schedule_task_add(server->schedule, 0,
+                                  silc_server_backup_connected_later,
+                                  proto_ctx, 2, 0,
+                                  SILC_TASK_TIMEOUT,
+                                  SILC_TASK_PRI_NORMAL);
+         } else {
+           /* If failure was received, switch back to normal backup router.
+              For some reason primary wouldn't accept that we were supposed
+              to perfom resuming protocol. */
+           server->server_type = SILC_BACKUP_ROUTER;
+           silc_server_local_servers_toggle_enabled(server, FALSE);
            server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
+           silc_server_update_servers_by_server(server, server->id_entry,
+                                                sock->user_data);
+           silc_server_update_clients_by_server(server, NULL,
+                                                sock->user_data, TRUE);
+
+           /* Announce our clients and channels to the router */
+           silc_server_announce_clients(server, 0, sock);
+           silc_server_announce_channels(server, 0, sock);
+         }
+
+         continue;
        }
-       
-       if (!silc_idcache_list_next(list, &id_cache))
-         break;
       }
+
+      server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
     }
-    silc_idcache_list_free(list);
   }
 
-  if (silc_idcache_get_all(server->global_list->servers, &list)) {
-    if (silc_idcache_list_first(list, &id_cache)) {
-      while (id_cache) {
-       server_entry = (SilcServerEntry)id_cache->context;
-       sock = (SilcSocketConnection)server_entry->connection;
-
-       if (sock->protocol == protocol) {
-         sock->protocol = NULL;
-
-         /* Backup closes connection and reconnects if error occurred */
-         if (SILC_PRIMARY_ROUTE(server) == sock && server->backup_router) {
-           if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
-               protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
-             server->backup_noswitch = TRUE;
-             server->server_type = SILC_BACKUP_ROUTER;
-             if (ctx->sock == sock)
-               ctx->sock = NULL;
-
-             if (sock->user_data)
-               silc_server_free_sock_user_data(server, sock, NULL);
-             silc_server_close_connection(server, sock);
-             silc_server_create_connections(server);
-
-             if (!silc_idcache_list_next(list, &id_cache))
-               break;
-             continue;
-           }
-         }
+  if (!error) {
+    SILC_LOG_INFO(("Backup resuming protocol ended successfully"));
 
-         if (server_entry->data.status & SILC_IDLIST_STATUS_DISABLED)
-           server_entry->data.status &= ~SILC_IDLIST_STATUS_DISABLED;
-       }
-       
-       if (!silc_idcache_list_next(list, &id_cache))
-         break;
+    if (ctx->type == SILC_SERVER_BACKUP_RESUMED && server->router) {
+      /* Announce all of our information to the router. */
+      if (server->server_type == SILC_ROUTER)
+       silc_server_announce_servers(server, FALSE, 0,
+                                    server->router->connection);
+
+      /* Announce our clients and channels to the router */
+      silc_server_announce_clients(server, 0, server->router->connection);
+      silc_server_announce_channels(server, 0, server->router->connection);
+    }
+  } else {
+    /* Error */
+
+    if (server->server_type == SILC_SERVER) {
+      /* If we are still using backup router Send confirmation to backup
+        that using it is still ok and continue sending traffic there.
+        The backup will reply with error if it's not ok. */
+      if (server->router && server->backup_primary) {
+       /* Send START_USE just in case using backup wouldn't be ok. */
+       silc_server_backup_send_start_use(server, server->router->connection,
+                                         FALSE);
+
+       /* Check couple of times same START_USE just in case. */
+       silc_schedule_task_add(server->schedule, 0,
+                              silc_server_backup_check_status,
+                              silc_socket_dup(server->router->connection),
+                              5, 1, SILC_TASK_TIMEOUT,
+                              SILC_TASK_PRI_NORMAL);
+       silc_schedule_task_add(server->schedule, 0,
+                              silc_server_backup_check_status,
+                              silc_socket_dup(server->router->connection),
+                              20, 1, SILC_TASK_TIMEOUT,
+                              SILC_TASK_PRI_NORMAL);
+       silc_schedule_task_add(server->schedule, 0,
+                              silc_server_backup_check_status,
+                              silc_socket_dup(server->router->connection),
+                              60, 1, SILC_TASK_TIMEOUT,
+                              SILC_TASK_PRI_NORMAL);
       }
     }
-    silc_idcache_list_free(list);
   }
 
-  if (protocol->state != SILC_PROTOCOL_STATE_ERROR &&
-      protocol->state != SILC_PROTOCOL_STATE_FAILURE)
-    SILC_LOG_INFO(("Backup resuming protocol ended successfully"));
-
   if (ctx->sock && ctx->sock->protocol)
     ctx->sock->protocol = NULL;
+  if (ctx->sock)
+    silc_socket_free(ctx->sock); /* unref */
   silc_protocol_free(protocol);
   silc_free(ctx->sessions);
   silc_free(ctx);
index 2ca105b3a9ce47b4dd1429dadd709148bef2aa13..e6ea92259bbe7328aa45f2cc796a2c9ea3512182 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  server_backup.h 
+  server_backup.h
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2001 - 2002 Pekka Riikonen
+  Copyright (C) 2001 - 2003 Pekka Riikonen
 
   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
 #define SERVER_BACKUP_H
 
 /* Backup resuming protocol types */
-#define SILC_SERVER_BACKUP_START            1
-#define SILC_SERVER_BACKUP_START_GLOBAL     2
-#define SILC_SERVER_BACKUP_CONNECTED        3
-#define SILC_SERVER_BACKUP_ENDING           4
-#define SILC_SERVER_BACKUP_RESUMED          5
-#define SILC_SERVER_BACKUP_RESUMED_GLOBAL   6
-#define SILC_SERVER_BACKUP_REPLACED         20
+#define SILC_SERVER_BACKUP_START          1   /* Start protocol */
+#define SILC_SERVER_BACKUP_CONNECTED      2   /* Connected to primary */
+#define SILC_SERVER_BACKUP_ENDING         3   /* Giving up as primary */
+#define SILC_SERVER_BACKUP_RESUMED        4   /* Primary is back online */
+#define SILC_SERVER_BACKUP_REPLACED       20  /* Primary has been replaced */
+#define SILC_SERVER_BACKUP_START_USE      21  /* Start use backup as primary */
 
 /* Adds the `backup_server' to be one of our backup router. This can be
    called multiple times to set multiple backup routers. The `replacing' is
@@ -37,9 +36,9 @@
 void silc_server_backup_add(SilcServer server, SilcServerEntry backup_server,
                            const char *ip, int port, bool local);
 
-/* Returns backup router for IP and port in `replacing' or NULL if there
+/* Returns backup router for IP and port in `server_id' or NULL if there
    does not exist backup router. */
-SilcServerEntry silc_server_backup_get(SilcServer server, 
+SilcServerEntry silc_server_backup_get(SilcServer server,
                                       SilcServerID *server_id);
 
 /* Deletes the backup server `server_entry'. */
@@ -54,7 +53,7 @@ void silc_server_backup_free(SilcServer server);
    by backup router indicated by the `server'. If the router connects at
    a later time we can check whether it has been replaced by an backup
    router. */
-void silc_server_backup_replaced_add(SilcServer server, 
+void silc_server_backup_replaced_add(SilcServer server,
                                     SilcServerID *server_id,
                                     SilcServerEntry server_entry);
 
@@ -70,11 +69,11 @@ bool silc_server_backup_replaced_get(SilcServer server,
 void silc_server_backup_replaced_del(SilcServer server,
                                     SilcServerEntry server_entry);
 
-/* Broadcast the received packet indicated by `packet' to all of our backup 
-   routers. All router wide information is passed using broadcast packets. 
+/* Broadcast the received packet indicated by `packet' to all of our backup
+   routers. All router wide information is passed using broadcast packets.
    That is why all backup routers need to get this data too. It is expected
    that the caller already knows that the `packet' is broadcast packet. */
-void silc_server_backup_broadcast(SilcServer server, 
+void silc_server_backup_broadcast(SilcServer server,
                                  SilcSocketConnection sender,
                                  SilcPacketContext *packet);
 
@@ -111,11 +110,24 @@ void silc_server_backup_send_dest(SilcServer server,
                                  bool force_send,
                                  bool local);
 
+/* Send the START_USE indication to remote connection.  If `failure' is
+   TRUE then this sends SILC_PACKET_FAILURE.  Otherwise it sends
+   SILC_PACKET_RESUME_ROUTER. */
+void silc_server_backup_send_start_use(SilcServer server,
+                                      SilcSocketConnection sock,
+                                      bool failure);
+
+/* Send the REPLACED indication to remote router.  This is send by the
+   primary router (remote router) of the primary router that came back
+   online.  This is not sent by backup router or any other server. */
+void silc_server_backup_send_replaced(SilcServer server,
+                                     SilcSocketConnection sock);
+
 /* Processes incoming RESUME_ROUTER packet. This can give the packet
    for processing to the protocol handler or allocate new protocol if
    start command is received. */
-void silc_server_backup_resume_router(SilcServer server, 
-                                     SilcSocketConnection sock, 
+void silc_server_backup_resume_router(SilcServer server,
+                                     SilcSocketConnection sock,
                                      SilcPacketContext *packet);
 
 /* Constantly tries to reconnect to a primary router indicated by the
index 0f4e14b43c4c35ff945f093ceea53413eb749732..7cf42a8ed8964553455acac8f70a10e81438c231 100644 (file)
@@ -4,13 +4,13 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2002 Pekka Riikonen
+  Copyright (C) 1997 - 2003 Pekka Riikonen
 
   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
@@ -85,11 +85,15 @@ struct SilcServerStruct {
   unsigned int backup_router  : 1;   /* Set if this is backup router */
   unsigned int backup_primary : 1;   /* Set if we've switched our primary
                                        router to a backup router. */
-  unsigned int backup_noswitch: 1;   /* Set if we've won't switch to 
+  unsigned int backup_noswitch: 1;   /* Set if we've won't switch to
                                        become primary (we are backup) */
+  unsigned int backup_closed  : 1;   /* Set if backup closed connection.
+                                       Do not allow resuming in this case. */
   unsigned int wait_backup    : 1;   /* Set if we are waiting for backup
                                        router to connect to us. */
   unsigned int server_shutdown: 1;   /* Set when shutting down */
+  unsigned int no_reconnect   : 1;   /* If set, server won't reconnect to
+                                       router after disconnection. */
 
   SilcServerEntry router;           /* Pointer to the primary router */
   unsigned long router_connect;             /* Time when router was connected */
@@ -162,14 +166,14 @@ typedef struct {
   (!server->standalone && server->router ? server->router->connection : NULL)
 
 /* Return TRUE if a packet must be broadcasted (router broadcasts) */
-#define SILC_BROADCAST(server) (server->server_type == SILC_ROUTER) 
+#define SILC_BROADCAST(server) (server->server_type == SILC_ROUTER)
 
 /* Return TRUE if entry is locally connected or local to us */
 #define SILC_IS_LOCAL(entry) \
   (((SilcIDListData)entry)->status & SILC_IDLIST_STATUS_LOCAL)
 
 /* Registers generic task for file descriptor for reading from network and
-   writing to network. As being generic task the actual task is allocated 
+   writing to network. As being generic task the actual task is allocated
    only once and after that the same task applies to all registered fd's. */
 #define SILC_REGISTER_CONNECTION_FOR_IO(fd)            \
 do {                                                   \
@@ -184,7 +188,7 @@ do {                                                        \
 do {                                                                   \
   silc_schedule_set_listen_fd((s), (fd), SILC_TASK_READ, FALSE);       \
 } while(0)
-     
+
 #define SILC_SET_CONNECTION_FOR_OUTPUT(s, fd)                               \
 do {                                                                        \
   silc_schedule_set_listen_fd((s), (fd), (SILC_TASK_READ | SILC_TASK_WRITE), \
index 6475c57301b06b7dcde972704472061994bf0c7a..3414c650c517afce54047277d32eab873454dfa7 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  server_query.c 
+  server_query.c
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2002 Pekka Riikonen
+  Copyright (C) 2002 - 2003 Pekka Riikonen
 
   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
@@ -163,7 +163,7 @@ void silc_server_query_send_error(SilcServer server,
 
   /* Send the command reply with error */
   silc_server_send_command_reply(server, query->cmd->sock,
-                                query->querycmd, error, 0, 
+                                query->querycmd, error, 0,
                                 silc_command_get_ident(query->cmd->payload),
                                 argc, data_type, data, data_len);
   va_end(va);
@@ -292,7 +292,7 @@ void silc_server_query_send_router(SilcServer server, SilcServerQuery query)
   old_ident = silc_command_get_ident(query->cmd->payload);
   silc_command_set_ident(query->cmd->payload, ++server->cmd_ident);
   tmpbuf = silc_command_payload_encode_payload(query->cmd->payload);
-  silc_server_packet_send(server, 
+  silc_server_packet_send(server,
                          SILC_PRIMARY_ROUTE(server),
                          SILC_PACKET_COMMAND, 0,
                          tmpbuf->data, tmpbuf->len, TRUE);
@@ -329,7 +329,7 @@ void silc_server_query_send_router_reply(void *context, void *reply)
                           silc_command_get_ident(query->cmd->payload));
     buffer = silc_command_payload_encode_payload(cmdr->payload);
     silc_server_packet_send(server, query->cmd->sock,
-                           SILC_PACKET_COMMAND_REPLY, 0, 
+                           SILC_PACKET_COMMAND_REPLY, 0,
                            buffer->data, buffer->len, FALSE);
     silc_buffer_free(buffer);
     silc_server_query_free(query);
@@ -591,20 +591,20 @@ void silc_server_query_process(SilcServer server, SilcServerQuery query,
 
   if (query->nickname) {
     /* Get all clients matching nickname from local list */
-    if (!silc_idlist_get_clients_by_hash(server->local_list, 
+    if (!silc_idlist_get_clients_by_hash(server->local_list,
                                         query->nickname, server->md5hash,
                                         &clients, &clients_count))
-      silc_idlist_get_clients_by_nickname(server->local_list, 
+      silc_idlist_get_clients_by_nickname(server->local_list,
                                          query->nickname,
                                          query->nick_server,
                                          &clients, &clients_count);
 
     /* Check global list as well */
     if (check_global) {
-      if (!silc_idlist_get_clients_by_hash(server->global_list, 
+      if (!silc_idlist_get_clients_by_hash(server->global_list,
                                           query->nickname, server->md5hash,
                                           &clients, &clients_count))
-       silc_idlist_get_clients_by_nickname(server->global_list, 
+       silc_idlist_get_clients_by_nickname(server->global_list,
                                            query->nickname,
                                            query->nick_server,
                                            &clients, &clients_count);
@@ -718,6 +718,10 @@ void silc_server_query_process(SilcServer server, SilcServerQuery query,
     }
   }
 
+  SILC_LOG_DEBUG(("Querying %d clients", clients_count));
+  SILC_LOG_DEBUG(("Querying %d servers", servers_count));
+  SILC_LOG_DEBUG(("Querying %d channels", channels_count));
+
   /* If nothing was found, then just send the errors */
   if (!clients && !channels && !servers) {
     silc_server_query_send_reply(server, query, NULL, 0, NULL, 0, NULL, 0);
@@ -965,7 +969,7 @@ void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
       if (!r) {
        /* Allocate new temp query list context */
        query->querylist = silc_realloc(query->querylist,
-                                       sizeof(*query->querylist) * 
+                                       sizeof(*query->querylist) *
                                        (query->querylist_count + 1));
        r = &query->querylist[query->querylist_count];
        query->querylist_count++;
@@ -1132,6 +1136,10 @@ void silc_server_query_send_reply(SilcServer server,
   bool sent_reply = FALSE;
 
   SILC_LOG_DEBUG(("Sending reply to query"));
+  SILC_LOG_DEBUG(("Sending %d clients", clients_count));
+  SILC_LOG_DEBUG(("Sending %d servers", servers_count));
+  SILC_LOG_DEBUG(("Sending %d channels", channels_count));
+  SILC_LOG_DEBUG(("Sending %d errors", query->errors_count));
 
   status = SILC_STATUS_OK;
 
@@ -1195,7 +1203,7 @@ void silc_server_query_send_reply(SilcServer server,
 
       if (k >= 1)
        status = SILC_STATUS_LIST_ITEM;
-      if (valid_count > 1 && k == valid_count - 1 
+      if (valid_count > 1 && k == valid_count - 1
          && !servers_count && !channels_count && !query->errors_count)
        status = SILC_STATUS_LIST_END;
       if (query->reply_count && k - 1 == query->reply_count)
@@ -1226,9 +1234,9 @@ void silc_server_query_send_reply(SilcServer server,
                       server->server_name, len);
        }
       }
-      
+
       switch (query->querycmd) {
-       
+
       case SILC_COMMAND_WHOIS:
        {
          unsigned char idle[4], mode[4];
@@ -1248,11 +1256,11 @@ void silc_server_query_send_reply(SilcServer server,
 
          if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
            channels =
-             silc_server_get_client_channel_list(server, entry, FALSE, 
+             silc_server_get_client_channel_list(server, entry, FALSE,
                                                  FALSE, &umode_list);
          else
            channels =
-             silc_server_get_client_channel_list(server, entry, TRUE, 
+             silc_server_get_client_channel_list(server, entry, TRUE,
                                                  TRUE, &umode_list);
 
          if (memcmp(entry->data.fingerprint, fempty, sizeof(fempty)))
@@ -1284,7 +1292,7 @@ void silc_server_query_send_reply(SilcServer server,
                                         2, idp->data, idp->len,
                                         3, nh, strlen(nh),
                                         4, uh, strlen(uh),
-                                        5, entry->userinfo, 
+                                        5, entry->userinfo,
                                         strlen(entry->userinfo),
                                         6, channels ? channels->data : NULL,
                                         channels ? channels->len : 0,
@@ -1353,8 +1361,8 @@ void silc_server_query_send_reply(SilcServer server,
                                       2, idp->data, idp->len,
                                       3, nh, strlen(nh),
                                       4, uh, strlen(uh),
-                                      5, entry->userinfo, 
-                                      entry->userinfo ? 
+                                      5, entry->userinfo,
+                                      entry->userinfo ?
                                       strlen(entry->userinfo) : 0);
        sent_reply = TRUE;
        break;
@@ -1387,15 +1395,18 @@ void silc_server_query_send_reply(SilcServer server,
     k = 0;
     for (i = 0; i < servers_count; i++) {
       entry = servers[i];
-      
+
       if (k >= 1)
        status = SILC_STATUS_LIST_ITEM;
+      if (servers_count == 1 && status != SILC_STATUS_OK && !channels_count &&
+         !query->errors_count)
+       status = SILC_STATUS_LIST_END;
       if (servers_count > 1 && k == servers_count - 1 && !channels_count &&
          !query->errors_count)
        status = SILC_STATUS_LIST_END;
       if (query->reply_count && k - 1 == query->reply_count)
        status = SILC_STATUS_LIST_END;
-      
+
       SILC_LOG_DEBUG(("%s: server %s",
                      (status == SILC_STATUS_OK ?         "   OK" :
                       status == SILC_STATUS_LIST_START ? "START" :
@@ -1408,13 +1419,13 @@ void silc_server_query_send_reply(SilcServer server,
       idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
       silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
                                     status, 0, ident, 2,
-                                    2, idp->data, idp->len, 
-                                    3, entry->server_name, 
-                                    entry->server_name ? 
+                                    2, idp->data, idp->len,
+                                    3, entry->server_name,
+                                    entry->server_name ?
                                     strlen(entry->server_name) : 0);
       silc_buffer_free(idp);
       sent_reply = TRUE;
-      
+
       if (status == SILC_STATUS_LIST_END)
        break;
       k++;
@@ -1431,15 +1442,18 @@ void silc_server_query_send_reply(SilcServer server,
     k = 0;
     for (i = 0; i < channels_count; i++) {
       entry = channels[i];
-      
+
       if (k >= 1)
        status = SILC_STATUS_LIST_ITEM;
+      if (channels_count == 1 && status != SILC_STATUS_OK &&
+         !query->errors_count)
+       status = SILC_STATUS_LIST_END;
       if (channels_count > 1 && k == channels_count - 1 &&
          !query->errors_count)
        status = SILC_STATUS_LIST_END;
       if (query->reply_count && k - 1 == query->reply_count)
        status = SILC_STATUS_LIST_END;
-      
+
       SILC_LOG_DEBUG(("%s: channel %s",
                      (status == SILC_STATUS_OK ?         "   OK" :
                       status == SILC_STATUS_LIST_START ? "START" :
@@ -1452,13 +1466,13 @@ void silc_server_query_send_reply(SilcServer server,
       idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
       silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
                                     status, 0, ident, 2,
-                                    2, idp->data, idp->len, 
-                                    3, entry->channel_name, 
-                                    entry->channel_name ? 
+                                    2, idp->data, idp->len,
+                                    3, entry->channel_name,
+                                    entry->channel_name ?
                                     strlen(entry->channel_name) : 0);
       silc_buffer_free(idp);
       sent_reply = TRUE;
-      
+
       if (status == SILC_STATUS_LIST_END)
        break;
       k++;
@@ -1502,6 +1516,8 @@ void silc_server_query_send_reply(SilcServer server,
 
       if (k >= 1)
        status = SILC_STATUS_LIST_ITEM;
+      if (query->errors_count == 1 && status != SILC_STATUS_OK)
+       status = SILC_STATUS_LIST_END;
       if (query->errors_count > 1 && k == query->errors_count - 1)
        status = SILC_STATUS_LIST_END;
       if (query->reply_count && k - 1 == query->reply_count)
@@ -1512,7 +1528,7 @@ void silc_server_query_send_reply(SilcServer server,
                       status == SILC_STATUS_LIST_START ? "START" :
                       status == SILC_STATUS_LIST_ITEM  ? " ITEM" :
                       status == SILC_STATUS_LIST_END  ?  "  END" :
-                      "      : "), 
+                      "      : "),
                      silc_get_status_message(query->errors[i].error),
                      query->errors[i].error));
 
@@ -1596,7 +1612,7 @@ SilcBuffer silc_server_query_reply_attrs(SilcServer server,
     case SILC_ATTRIBUTE_STATUS_FREETEXT:
       /* Put STATUS_FREETEXT.  We just tell in the message that we are
         replying on behalf of the client. */
-      tmp = 
+      tmp =
        "This information was provided by the server on behalf of the user";
       buffer = silc_attribute_payload_encode(buffer, attribute,
                                             SILC_ATTRIBUTE_FLAG_VALID,
@@ -1645,7 +1661,7 @@ SilcBuffer silc_server_query_reply_attrs(SilcServer server,
       if (attribute == SILC_ATTRIBUTE_SERVER_PUBLIC_KEY ||
          attribute == SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE)
        break;
-      
+
       /* For other attributes we cannot reply so mark it invalid */
       buffer = silc_attribute_payload_encode(buffer, attribute,
                                             SILC_ATTRIBUTE_FLAG_INVALID,
index 839599d2cfde0b1f166e504c4c4c5d3014319a6e..2cc4907804fabca8ebffc23fe4fb2b43de50d6aa 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  server_util.c 
+  server_util.c
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2002 Pekka Riikonen
+  Copyright (C) 1997 - 2003 Pekka Riikonen
 
   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
@@ -42,7 +42,7 @@ silc_server_remove_clients_channels(SilcServer server,
   if (!client)
     return;
 
-  SILC_LOG_DEBUG(("Remove client %s from all channels",   
+  SILC_LOG_DEBUG(("Remove client %s from all channels",
                 client->nickname ? client->nickname :
                  (unsigned char *)""));
 
@@ -72,7 +72,7 @@ silc_server_remove_clients_channels(SilcServer server,
 
     /* If there is no global users on the channel anymore mark the channel
        as local channel. Do not check if the removed client is local client. */
-    if (server->server_type != SILC_ROUTER && channel->global_users && 
+    if (server->server_type != SILC_ROUTER && channel->global_users &&
        chl->client->router && !silc_server_channel_has_global(channel))
       channel->global_users = FALSE;
 
@@ -113,7 +113,7 @@ silc_server_remove_clients_channels(SilcServer server,
     }
     silc_hash_table_list_reset(&htl2);
 
-    /* Add the channel to the the channels list to regenerate the 
+    /* Add the channel to the the channels list to regenerate the
        channel key */
     if (!silc_hash_table_find(channels, channel, NULL, NULL))
       silc_hash_table_add(channels, channel, channel);
@@ -123,7 +123,7 @@ silc_server_remove_clients_channels(SilcServer server,
 
 /* This function removes all client entries that are originated from
    `router' and are owned by `entry'.  `router' and `entry' can be same
-   too.  If `server_signoff' is TRUE then SERVER_SIGNOFF notify is 
+   too.  If `server_signoff' is TRUE then SERVER_SIGNOFF notify is
    distributed to our local clients. */
 
 bool silc_server_remove_clients_by_server(SilcServer server,
@@ -230,7 +230,7 @@ bool silc_server_remove_clients_by_server(SilcServer server,
     }
     silc_idcache_list_free(list);
   }
-  
+
   if (silc_idcache_get_all(server->global_list->clients, &list)) {
 
     if (silc_idcache_list_first(list, &id_cache)) {
@@ -328,7 +328,7 @@ bool silc_server_remove_clients_by_server(SilcServer server,
        is to be removed for those servers that would like to use that list. */
     args = silc_argument_payload_encode(argc, argv, argv_lens,
                                        argv_types);
-    not = silc_notify_payload_encode_args(SILC_NOTIFY_TYPE_SERVER_SIGNOFF, 
+    not = silc_notify_payload_encode_args(SILC_NOTIFY_TYPE_SERVER_SIGNOFF,
                                          argc, args);
     silc_server_packet_send_clients(server, clients,
                                    SILC_PACKET_NOTIFY, 0, FALSE,
@@ -363,8 +363,8 @@ bool silc_server_remove_clients_by_server(SilcServer server,
     if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY || !channel->channel_key)
       continue;
 
-    silc_server_send_channel_key(server, NULL, channel, 
-                                server->server_type == SILC_ROUTER ? 
+    silc_server_send_channel_key(server, NULL, channel,
+                                server->server_type == SILC_ROUTER ?
                                 FALSE : !server->standalone);
   }
   silc_hash_table_list_reset(&htl);
@@ -386,6 +386,8 @@ silc_server_update_clients_by_real_server(SilcServer server,
   SilcIDCacheList list;
   bool tolocal = (to == server->id_entry);
 
+  SILC_LOG_DEBUG(("Start"));
+
   if (!silc_idcache_get_all(server->local_list->servers, &list))
     return NULL;
 
@@ -394,7 +396,7 @@ silc_server_update_clients_by_real_server(SilcServer server,
       server_entry = (SilcServerEntry)id_cache->context;
       if (server_entry != from &&
          (tolocal || server_entry != server->id_entry) &&
-         SILC_ID_COMPARE(server_entry->id, client->id, 
+         SILC_ID_COMPARE(server_entry->id, client->id,
                          client->id->ip.data_len)) {
        SILC_LOG_DEBUG(("Found (local) %s",
                        silc_id_render(server_entry->id, SILC_ID_SERVER)));
@@ -412,6 +414,7 @@ silc_server_update_clients_by_real_server(SilcServer server,
          }
          server_entry = server_entry->router;
        } else {
+         SILC_LOG_DEBUG(("Server locally connected"));
          /* If the client is not marked as local then move it to local list
             since the server is local. */
          if (server_entry->server_type != SILC_BACKUP_ROUTER && !local) {
@@ -420,6 +423,16 @@ silc_server_update_clients_by_real_server(SilcServer server,
                             client_cache->id, client_cache->context,
                             client_cache->expire, NULL);
            silc_idcache_del_by_context(server->global_list->clients, client);
+
+         } else if (server->server_type == SILC_BACKUP_ROUTER && local) {
+           /* If we are backup router and this client is on local list, we
+              must move it to global list, as it is not currently local to
+              us (we are not primary). */
+           SILC_LOG_DEBUG(("Moving client to global list"));
+           silc_idcache_add(server->global_list->clients, client_cache->name,
+                            client_cache->id, client_cache->context,
+                            client_cache->expire, NULL);
+           silc_idcache_del_by_context(server->local_list->clients, client);
          }
        }
 
@@ -442,7 +455,7 @@ silc_server_update_clients_by_real_server(SilcServer server,
       server_entry = (SilcServerEntry)id_cache->context;
       if (server_entry != from && server_entry != server->id_entry &&
          (tolocal || server_entry != server->id_entry) &&
-         SILC_ID_COMPARE(server_entry->id, client->id, 
+         SILC_ID_COMPARE(server_entry->id, client->id,
                          client->id->ip.data_len)) {
        SILC_LOG_DEBUG(("Found (global) %s",
                        silc_id_render(server_entry->id, SILC_ID_SERVER)));
@@ -459,6 +472,7 @@ silc_server_update_clients_by_real_server(SilcServer server,
          }
          server_entry = server_entry->router;
        } else {
+         SILC_LOG_DEBUG(("Server locally connected"));
          /* If the client is marked as local then move it to global list
             since the server is global. */
          if (server_entry->server_type != SILC_BACKUP_ROUTER && local) {
@@ -490,7 +504,7 @@ silc_server_update_clients_by_real_server(SilcServer server,
    to, when we've acting as backup router. If it is FALSE the `to' will
    be the new source. */
 
-void silc_server_update_clients_by_server(SilcServer server, 
+void silc_server_update_clients_by_server(SilcServer server,
                                          SilcServerEntry from,
                                          SilcServerEntry to,
                                          bool resolve_real_server)
@@ -500,6 +514,16 @@ void silc_server_update_clients_by_server(SilcServer server,
   SilcClientEntry client = NULL;
   bool local;
 
+  if (from && from->id) {
+    SILC_LOG_DEBUG(("Changing from server %s",
+                   silc_id_render(from->id, SILC_ID_SERVER)));
+  }
+  if (to && to->id) {
+    SILC_LOG_DEBUG(("Changing to server %s",
+                   silc_id_render(to->id, SILC_ID_SERVER)));
+  }
+
+  SILC_LOG_DEBUG(("global list"));
   local = FALSE;
   if (silc_idcache_get_all(server->global_list->clients, &list)) {
     if (silc_idcache_list_first(list, &id_cache)) {
@@ -516,16 +540,16 @@ void silc_server_update_clients_by_server(SilcServer server,
            continue;
        }
 
-       SILC_LOG_DEBUG(("Client %s", 
+       SILC_LOG_DEBUG(("Client %s",
                        silc_id_render(client->id, SILC_ID_CLIENT)));
        if (client->router)
-         SILC_LOG_DEBUG(("Client->router %s", 
+         SILC_LOG_DEBUG(("Client->router %s",
                          silc_id_render(client->router->id, SILC_ID_SERVER)));
 
        if (from) {
          if (client->router == from) {
            if (resolve_real_server) {
-             client->router = 
+             client->router =
                silc_server_update_clients_by_real_server(server, from, to,
                                                          client, local,
                                                          id_cache);
@@ -541,11 +565,18 @@ void silc_server_update_clients_by_server(SilcServer server,
          }
        } else {
          /* All are changed */
+         if (resolve_real_server)
+           /* Call this so that the entry is moved to correct list if
+              needed.  No resolving by real server is actually done. */
+           silc_server_update_clients_by_real_server(server, NULL, to,
+                                                     client, local,
+                                                     id_cache);
+
          client->router = to;
        }
 
        if (client->router)
-         SILC_LOG_DEBUG(("Client changed to %s", 
+         SILC_LOG_DEBUG(("Client changed to %s",
                          silc_id_render(client->router->id, SILC_ID_SERVER)));
 
        if (!silc_idcache_list_next(list, &id_cache))
@@ -555,6 +586,7 @@ void silc_server_update_clients_by_server(SilcServer server,
     silc_idcache_list_free(list);
   }
 
+  SILC_LOG_DEBUG(("local list"));
   local = TRUE;
   if (silc_idcache_get_all(server->local_list->clients, &list)) {
     if (silc_idcache_list_first(list, &id_cache)) {
@@ -571,16 +603,16 @@ void silc_server_update_clients_by_server(SilcServer server,
            continue;
        }
 
-       SILC_LOG_DEBUG(("Client %s", 
+       SILC_LOG_DEBUG(("Client %s",
                        silc_id_render(client->id, SILC_ID_CLIENT)));
        if (client->router)
-         SILC_LOG_DEBUG(("Client->router %s", 
+         SILC_LOG_DEBUG(("Client->router %s",
                          silc_id_render(client->router->id, SILC_ID_SERVER)));
 
        if (from) {
          if (client->router == from) {
            if (resolve_real_server) {
-             client->router = 
+             client->router =
                silc_server_update_clients_by_real_server(server, from, to,
                                                          client, local,
                                                          id_cache);
@@ -592,11 +624,18 @@ void silc_server_update_clients_by_server(SilcServer server,
          }
        } else {
          /* All are changed */
+         if (resolve_real_server)
+           /* Call this so that the entry is moved to correct list if
+              needed.  No resolving by real server is actually done. */
+           silc_server_update_clients_by_real_server(server, NULL, to,
+                                                     client, local,
+                                                     id_cache);
+
          client->router = to;
        }
 
        if (client->router)
-         SILC_LOG_DEBUG(("Client changed to %s", 
+         SILC_LOG_DEBUG(("Client changed to %s",
                          silc_id_render(client->router->id, SILC_ID_SERVER)));
 
        if (!silc_idcache_list_next(list, &id_cache))
@@ -610,7 +649,7 @@ void silc_server_update_clients_by_server(SilcServer server,
 /* Updates servers that are from `from' to be originated from `to'.  This
    will also update the server's connection to `to's connection. */
 
-void silc_server_update_servers_by_server(SilcServer server, 
+void silc_server_update_servers_by_server(SilcServer server,
                                          SilcServerEntry from,
                                          SilcServerEntry to)
 {
@@ -650,9 +689,18 @@ void silc_server_update_servers_by_server(SilcServer server,
             whether this server is in our cell, but not connected to
             us (in which case we must remove it). */
 
-         if (server_entry->router == from) {
+         if (from) {
+           if (server_entry->router == from) {
+             SILC_LOG_DEBUG(("Updating server (local) %s",
+                             server_entry->server_name ?
+                             server_entry->server_name : ""));
+             server_entry->router = to;
+             server_entry->connection = to->connection;
+           }
+         } else {
+           /* Update all */
            SILC_LOG_DEBUG(("Updating server (local) %s",
-                           server_entry->server_name ? 
+                           server_entry->server_name ?
                            server_entry->server_name : ""));
            server_entry->router = to;
            server_entry->connection = to->connection;
@@ -696,9 +744,18 @@ void silc_server_update_servers_by_server(SilcServer server,
             whether this server is in our cell, but not connected to
             us (in which case we must remove it). */
 
-         if (server_entry->router == from) {
+         if (from) {
+           if (server_entry->router == from) {
+             SILC_LOG_DEBUG(("Updating server (global) %s",
+                             server_entry->server_name ?
+                             server_entry->server_name : ""));
+             server_entry->router = to;
+             server_entry->connection = to->connection;
+           }
+         } else {
+           /* Update all */
            SILC_LOG_DEBUG(("Updating server (global) %s",
-                           server_entry->server_name ? 
+                           server_entry->server_name ?
                            server_entry->server_name : ""));
            server_entry->router = to;
            server_entry->connection = to->connection;
@@ -846,7 +903,7 @@ void silc_server_remove_servers_by_server(SilcServer server,
 
 /* Removes channels that are from `from. */
 
-void silc_server_remove_channels_by_server(SilcServer server, 
+void silc_server_remove_channels_by_server(SilcServer server,
                                           SilcServerEntry from)
 {
   SilcIDCacheList list = NULL;
@@ -871,7 +928,7 @@ void silc_server_remove_channels_by_server(SilcServer server,
 
 /* Updates channels that are from `from' to be originated from `to'.  */
 
-void silc_server_update_channels_by_server(SilcServer server, 
+void silc_server_update_channels_by_server(SilcServer server,
                                           SilcServerEntry from,
                                           SilcServerEntry to)
 {
@@ -885,8 +942,13 @@ void silc_server_update_channels_by_server(SilcServer server,
     if (silc_idcache_list_first(list, &id_cache)) {
       while (id_cache) {
        channel = (SilcChannelEntry)id_cache->context;
-       if (channel->router == from)
+       if (from) {
+         if (channel->router == from)
+           channel->router = to;
+       } else {
+         /* Update all */
          channel->router = to;
+       }
        if (!silc_idcache_list_next(list, &id_cache))
          break;
       }
@@ -995,9 +1057,9 @@ bool silc_server_channel_delete(SilcServer server,
   return TRUE;
 }
 
-/* Returns TRUE if the given client is on the channel.  FALSE if not. 
+/* Returns TRUE if the given client is on the channel.  FALSE if not.
    This works because we assure that the user list on the channel is
-   always in up to date thus we can only check the channel list from 
+   always in up to date thus we can only check the channel list from
    `client' which is faster than checking the user list from `channel'. */
 
 bool silc_server_client_on_channel(SilcClientEntry client,
@@ -1007,7 +1069,7 @@ bool silc_server_client_on_channel(SilcClientEntry client,
   if (!client || !channel)
     return FALSE;
 
-  return silc_hash_table_find(client->channels, channel, NULL, 
+  return silc_hash_table_find(client->channels, channel, NULL,
                              (void **)chl);
 }
 
@@ -1017,6 +1079,27 @@ bool silc_server_name_bad_chars(const char *name, SilcUInt32 name_len)
 {
   int i;
 
+  for (i = 0; i < name_len; i++) {
+    if (!isascii(name[i]))
+      return TRUE;
+    if (name[i] <= 32) return TRUE;
+    if (name[i] == ' ') return TRUE;
+    if (name[i] == '*') return TRUE;
+    if (name[i] == '?') return TRUE;
+    if (name[i] == ',') return TRUE;
+    if (name[i] == '@') return TRUE;
+    if (name[i] == '!') return TRUE;
+  }
+
+  return FALSE;
+}
+
+/* Same as silc_server_name_bad_chars but check for channel names. */
+
+bool silc_server_name_bad_chchars(const char *name, SilcUInt32 name_len)
+{
+  int i;
+
   for (i = 0; i < name_len; i++) {
     if (!isascii(name[i]))
       return TRUE;
@@ -1072,7 +1155,7 @@ SilcUInt32 silc_server_num_sockets_by_ip(SilcServer server, const char *ip,
    by `ip' or `hostname', `port', and `type'.  Returns 0 if socket connections
    does not exist. If `ip' is provided then `hostname' is ignored. */
 
-SilcUInt32 silc_server_num_sockets_by_remote(SilcServer server, 
+SilcUInt32 silc_server_num_sockets_by_remote(SilcServer server,
                                             const char *ip,
                                             const char *hostname,
                                             SilcUInt16 port,
@@ -1095,12 +1178,12 @@ SilcUInt32 silc_server_num_sockets_by_remote(SilcServer server,
   return count;
 }
 
-/* Finds locally cached public key by the public key received in the SKE. 
+/* Finds locally cached public key by the public key received in the SKE.
    If we have it locally cached then we trust it and will use it in the
    authentication protocol.  Returns the locally cached public key or NULL
    if we do not find the public key.  */
 
-SilcPublicKey silc_server_find_public_key(SilcServer server, 
+SilcPublicKey silc_server_find_public_key(SilcServer server,
                                          SilcHashTable local_public_keys,
                                          SilcPublicKey remote_public_key)
 {
@@ -1110,7 +1193,7 @@ SilcPublicKey silc_server_find_public_key(SilcServer server,
                  silc_hash_table_count(local_public_keys)));
 
   if (!silc_hash_table_find_ext(local_public_keys, remote_public_key,
-                               (void **)&cached_key, NULL, 
+                               (void **)&cached_key, NULL,
                                silc_hash_public_key, NULL,
                                silc_hash_public_key_compare, NULL)) {
     SILC_LOG_ERROR(("Public key not found"));
@@ -1138,8 +1221,10 @@ SilcPublicKey silc_server_get_public_key(SilcServer server,
   assert(silc_hash_table_count(local_public_keys) < 2);
 
   silc_hash_table_list(local_public_keys, &htl);
-  if (!silc_hash_table_get(&htl, NULL, (void **)&cached_key))
+  if (!silc_hash_table_get(&htl, NULL, (void **)&cached_key)) {
+    silc_hash_table_list_reset(&htl);
     return NULL;
+  }
   silc_hash_table_list_reset(&htl);
 
   return cached_key;
@@ -1149,7 +1234,7 @@ SilcPublicKey silc_server_get_public_key(SilcServer server,
    checks for example whether there is too much connections for this host,
    and required version for the host etc. */
 
-bool silc_server_connection_allowed(SilcServer server, 
+bool silc_server_connection_allowed(SilcServer server,
                                    SilcSocketConnection sock,
                                    SilcSocketType type,
                                    SilcServerConfigConnParams *global,
@@ -1170,18 +1255,18 @@ bool silc_server_connection_allowed(SilcServer server,
 
   /* Check version */
 
-  l_protocol_version = 
-    silc_version_to_num(params && params->version_protocol ? 
-                       params->version_protocol : 
+  l_protocol_version =
+    silc_version_to_num(params && params->version_protocol ?
+                       params->version_protocol :
                        global->version_protocol);
-  l_software_version = 
-    silc_version_to_num(params && params->version_software ? 
-                       params->version_software : 
+  l_software_version =
+    silc_version_to_num(params && params->version_software ?
+                       params->version_software :
                        global->version_software);
-  l_vendor_version = (params && params->version_software_vendor ? 
-                     params->version_software_vendor : 
+  l_vendor_version = (params && params->version_software_vendor ?
+                     params->version_software_vendor :
                      global->version_software_vendor);
-  
+
   if (ske && silc_ske_parse_version(ske, &r_protocol_version, NULL,
                                    &r_software_version, NULL,
                                    &r_vendor_version)) {
@@ -1192,7 +1277,8 @@ bool silc_server_connection_allowed(SilcServer server,
        r_protocol_version < l_protocol_version) {
       SILC_LOG_INFO(("Connection %s (%s) is too old version",
                     sock->hostname, sock->ip));
-      silc_server_disconnect_remote(server, sock, 
+      sock->protocol = NULL;
+      silc_server_disconnect_remote(server, sock,
                                    SILC_STATUS_ERR_BAD_VERSION,
                                    "You support too old protocol version");
       return FALSE;
@@ -1203,18 +1289,20 @@ bool silc_server_connection_allowed(SilcServer server,
        r_software_version < l_software_version) {
       SILC_LOG_INFO(("Connection %s (%s) is too old version",
                     sock->hostname, sock->ip));
-      silc_server_disconnect_remote(server, sock, 
+      sock->protocol = NULL;
+      silc_server_disconnect_remote(server, sock,
                                    SILC_STATUS_ERR_BAD_VERSION,
                                    "You support too old software version");
       return FALSE;
     }
 
     /* Regex match vendor version */
-    if (l_vendor_version && r_vendor_version && 
+    if (l_vendor_version && r_vendor_version &&
        !silc_string_match(l_vendor_version, r_vendor_version)) {
       SILC_LOG_INFO(("Connection %s (%s) is unsupported version",
                     sock->hostname, sock->ip));
-      silc_server_disconnect_remote(server, sock, 
+      sock->protocol = NULL;
+      silc_server_disconnect_remote(server, sock,
                                    SILC_STATUS_ERR_BAD_VERSION,
                                    "Your software is not supported");
       return FALSE;
@@ -1232,7 +1320,8 @@ bool silc_server_connection_allowed(SilcServer server,
   if (max_hosts && conn_number >= max_hosts) {
     SILC_LOG_INFO(("Server is full, closing %s (%s) connection",
                   sock->hostname, sock->ip));
-    silc_server_disconnect_remote(server, sock, 
+    sock->protocol = NULL;
+    silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_RESOURCE_LIMIT,
                                  "Server is full, try again later");
     return FALSE;
@@ -1241,7 +1330,8 @@ bool silc_server_connection_allowed(SilcServer server,
   if (num_sockets >= max_per_host) {
     SILC_LOG_INFO(("Too many connections from %s (%s), closing connection",
                   sock->hostname, sock->ip));
-    silc_server_disconnect_remote(server, sock, 
+    sock->protocol = NULL;
+    silc_server_disconnect_remote(server, sock,
                                  SILC_STATUS_ERR_RESOURCE_LIMIT,
                                  "Too many connections from your host");
     return FALSE;
@@ -1286,7 +1376,7 @@ bool silc_server_check_cmode_rights(SilcServer server,
        return FALSE;
     }
   }
-  
+
   if (mode & SILC_CHANNEL_MODE_PASSPHRASE) {
     if (!(channel->mode & SILC_CHANNEL_MODE_PASSPHRASE)) {
       if (is_op && !is_fo)
@@ -1310,7 +1400,7 @@ bool silc_server_check_cmode_rights(SilcServer server,
        return FALSE;
     }
   }
-  
+
   if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
     if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)) {
       if (is_op && !is_fo)
@@ -1322,7 +1412,7 @@ bool silc_server_check_cmode_rights(SilcServer server,
        return FALSE;
     }
   }
-  
+
   if (mode & SILC_CHANNEL_MODE_SILENCE_USERS) {
     if (!(channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS)) {
       if (is_op && !is_fo)
@@ -1334,7 +1424,7 @@ bool silc_server_check_cmode_rights(SilcServer server,
        return FALSE;
     }
   }
-  
+
   if (mode & SILC_CHANNEL_MODE_SILENCE_OPERS) {
     if (!(channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS)) {
       if (is_op && !is_fo)
@@ -1346,7 +1436,19 @@ bool silc_server_check_cmode_rights(SilcServer server,
        return FALSE;
     }
   }
-  
+
+  if (mode & SILC_CHANNEL_MODE_CHANNEL_AUTH) {
+    if (!(channel->mode & SILC_CHANNEL_MODE_CHANNEL_AUTH)) {
+      if (is_op && !is_fo)
+       return FALSE;
+    }
+  } else {
+    if (channel->mode & SILC_CHANNEL_MODE_CHANNEL_AUTH) {
+      if (is_op && !is_fo)
+       return FALSE;
+    }
+  }
+
   return TRUE;
 }
 
@@ -1410,14 +1512,14 @@ void silc_server_send_connect_notifys(SilcServer server,
     SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
                            ("There are %d clients, %d servers and %d "
                             "routers in SILC Network",
-                            server->stat.clients, server->stat.servers + 1,
+                            server->stat.clients, server->stat.servers,
                             server->stat.routers));
   } else {
     if (server->stat.clients && server->stat.servers + 1)
       SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
                              ("There are %d clients, %d servers and %d "
                               "routers in SILC Network",
-                              server->stat.clients, server->stat.servers + 1,
+                              server->stat.clients, server->stat.servers,
                               (server->standalone ? 0 :
                                !server->stat.routers ? 1 :
                                server->stat.routers)));
@@ -1427,12 +1529,12 @@ void silc_server_send_connect_notifys(SilcServer server,
     SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
                            ("There are %d clients on %d server in our cell",
                             server->stat.cell_clients,
-                            server->stat.cell_servers + 1));
+                            server->stat.cell_servers));
   if (server->server_type == SILC_ROUTER) {
     SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
                            ("I have %d clients, %d channels, %d servers and "
                             "%d routers",
-                            server->stat.my_clients, 
+                            server->stat.my_clients,
                             server->stat.my_channels,
                             server->stat.my_servers,
                             server->stat.my_routers));
@@ -1480,7 +1582,7 @@ void silc_server_kill_client(SilcServer server,
 {
   SilcBuffer killed, killer;
 
-  SILC_LOG_DEBUG(("Killing client %s", 
+  SILC_LOG_DEBUG(("Killing client %s",
                  silc_id_render(remote_client->id, SILC_ID_CLIENT)));
 
   /* Send the KILL notify packets. First send it to the channel, then
@@ -1493,7 +1595,7 @@ void silc_server_kill_client(SilcServer server,
   /* Send KILLED notify to the channels. It is not sent to the client
      as it will be sent differently destined directly to the client and not
      to the channel. */
-  silc_server_send_notify_on_channels(server, remote_client, 
+  silc_server_send_notify_on_channels(server, remote_client,
                                      remote_client, SILC_NOTIFY_TYPE_KILLED,
                                      3, killed->data, killed->len,
                                      comment, comment ? strlen(comment) : 0,
@@ -1506,15 +1608,15 @@ void silc_server_kill_client(SilcServer server,
 
   /* Send KILLED notify to the client directly */
   if (remote_client->connection || remote_client->router)
-    silc_server_send_notify_killed(server, remote_client->connection ? 
-                                  remote_client->connection : 
+    silc_server_send_notify_killed(server, remote_client->connection ?
+                                  remote_client->connection :
                                   remote_client->router->connection, FALSE,
-                                  remote_client->id, comment, 
+                                  remote_client->id, comment,
                                   killer_id, killer_id_type);
 
   /* Remove the client from all channels. This generates new keys to the
      channels as well. */
-  silc_server_remove_from_channels(server, NULL, remote_client, FALSE, 
+  silc_server_remove_from_channels(server, NULL, remote_client, FALSE,
                                   NULL, TRUE, TRUE);
 
   /* Remove the client entry, If it is locally connected then we will also
@@ -1543,7 +1645,7 @@ void silc_server_kill_client(SilcServer server,
     if (!silc_idlist_del_client(server->global_list, remote_client)) {
       /* Remove this client from watcher list if it is */
       silc_server_del_from_watcher_list(server, remote_client);
-      silc_idlist_del_client(server->local_list, remote_client);  
+      silc_idlist_del_client(server->local_list, remote_client);
     }
   }
 
@@ -1558,8 +1660,8 @@ typedef struct {
   const char *new_nick;
 } WatcherNotifyContext;
 
-static void 
-silc_server_check_watcher_list_foreach(void *key, void *context, 
+static void
+silc_server_check_watcher_list_foreach(void *key, void *context,
                                       void *user_context)
 {
   WatcherNotifyContext *notify = user_context;
@@ -1579,10 +1681,10 @@ silc_server_check_watcher_list_foreach(void *key, void *context,
                    silc_id_render(entry->id, SILC_ID_CLIENT)));
 
     /* Send the WATCH notify */
-    silc_server_send_notify_watch(notify->server, sock, entry, 
-                                 notify->client, 
+    silc_server_send_notify_watch(notify->server, sock, entry,
+                                 notify->client,
                                  notify->new_nick ? notify->new_nick :
-                                 (const char *)notify->client->nickname, 
+                                 (const char *)notify->client->nickname,
                                  notify->notify);
   }
 }
@@ -1684,7 +1786,7 @@ bool silc_server_force_cumode_change(SilcServer server,
   idp1 = silc_id_payload_encode(server->id, SILC_ID_SERVER);
   idp2 = silc_id_payload_encode(chl->client->id, SILC_ID_CLIENT);
   SILC_PUT32_MSB(forced_mode, cumode);
-  silc_server_send_notify_to_channel(server, sock, channel, FALSE,
+  silc_server_send_notify_to_channel(server, sock, channel, FALSE, TRUE,
                                     SILC_NOTIFY_TYPE_CUMODE_CHANGE,
                                     3, idp1->data, idp1->len,
                                     cumode, sizeof(cumode),
@@ -1725,7 +1827,7 @@ bool silc_server_inviteban_match(SilcServer server, SilcHashTable list,
   unsigned char *tmp = NULL;
   SilcUInt32 len = 0, t;
   SilcHashTableList htl;
-  SilcBuffer entry, idp = NULL;
+  SilcBuffer entry, idp = NULL, pkp = NULL;
   bool ret = FALSE;
 
   if (type < 1 || type > 3 || !check)
@@ -1737,9 +1839,11 @@ bool silc_server_inviteban_match(SilcServer server, SilcHashTable list,
       return FALSE;
   }
   if (type == 2) {
-    tmp = silc_pkcs_public_key_encode(check, &len);
-    if (!tmp)
+    pkp = silc_pkcs_public_key_payload_encode(check);
+    if (!pkp)
       return FALSE;
+    tmp = pkp->data;
+    len = pkp->len;
   }
   if (type == 3) {
     idp = silc_id_payload_encode(check, SILC_ID_CLIENT);
@@ -1766,9 +1870,10 @@ bool silc_server_inviteban_match(SilcServer server, SilcHashTable list,
   }
   silc_hash_table_list_reset(&htl);
 
-  if (!idp)
+  if (type == 1)
     silc_free(tmp);
   silc_buffer_free(idp);
+  silc_buffer_free(pkp);
   return ret;
 }
 
@@ -1783,10 +1888,10 @@ void silc_server_inviteban_process(SilcServer server, SilcHashTable list,
   SilcHashTableList htl;
 
   SILC_LOG_DEBUG(("Processing invite/ban for %s action",
-                 action == 0x00 ? "ADD" : "DEL"));
+                 action == 0x01 ? "DEL" : "ADD"));
 
   /* Add the information to invite list */
-  if (action == 0x00) {
+  if (action == 0x00 || action == 0x03) {
     /* Traverse all arguments and add to the hash table according to
        their type. */
     tmp = silc_argument_get_first_arg(args, &type, &len);
@@ -1794,15 +1899,61 @@ void silc_server_inviteban_process(SilcServer server, SilcHashTable list,
       if (type == 1) {
        /* Invite string.  Get the old invite string from hash table
           and append this at the end of the existing one. */
-       if (!silc_hash_table_find(list, (void *)1, NULL, (void **)&tmp2)) {
+       if (!silc_hash_table_find(list, (void *)1, NULL, (void *)&tmp2)) {
          tmp2 = silc_calloc(1, sizeof(*tmp2));
          silc_hash_table_add(list, (void *)1, tmp2);
        }
-       if (tmp[len - 1] == ',')
-         tmp[len - 1] = '\0';
-       if (len) {
-         silc_buffer_strformat(tmp2, tmp, SILC_STR_END);
-         silc_buffer_strformat(tmp2, ",", SILC_STR_END);
+
+       /* Check that the string is not part of invite string already */
+       if (action == 0x00) {
+         if (silc_string_match(tmp2->data, tmp))
+           break;
+
+         if (len) {
+           if (tmp[len - 1] == ',')
+             tmp[len - 1] = '\0';
+           silc_buffer_strformat(tmp2, tmp, SILC_STR_END);
+           silc_buffer_strformat(tmp2, ",", SILC_STR_END);
+         }
+       } else {
+         /* Announced list.  Check each entry in the list */
+         unsigned char e[256];
+         char *start, *end, *n, *rtmp;
+         int i, k;
+
+         rtmp = silc_memdup(tmp, len);
+         for (i = 0, k = 0; i < len; i++) {
+           if (tmp[i] != ',')
+             continue;
+
+           memset(e, 0, sizeof(e));
+           silc_strncat(e, sizeof(e), tmp + k, i - k);
+           if (!silc_string_match(tmp2->data, e)) {
+             k = i + 1;
+             continue;
+           }
+
+           /* Matches.  Delete it since we have it already */
+           start = strstr(rtmp, e);
+           if (start && strlen(start) >= (i - k)) {
+             end = start + (i - k);
+             n = silc_calloc(strlen(rtmp) - (i - k), sizeof(*n));
+             strncat(n, rtmp, start - rtmp);
+             if (strlen(end) > 1)
+               strncat(n, end + 1, ((rtmp + strlen(rtmp)) - end) - 1);
+             silc_free(rtmp);
+             rtmp = n;
+           }
+
+           k = i + 1;
+         }
+
+         /* Save the part that we didn't already have. */
+         if (strlen(rtmp) > 1) {
+           silc_buffer_strformat(tmp2, rtmp, SILC_STR_END);
+           silc_buffer_strformat(tmp2, ",", SILC_STR_END);
+         }
+         silc_free(rtmp);
        }
 
       } else if (type == 2) {
@@ -1873,7 +2024,8 @@ void silc_server_inviteban_process(SilcServer server, SilcHashTable list,
              end = start + len;
              n = silc_calloc(strlen(string) - len, sizeof(*n));
              strncat(n, string, start - string);
-             strncat(n, end + 1, ((string + strlen(string)) - end) - 1);
+             if (strlen(end) > 1)
+               strncat(n, end + 1, ((string + strlen(string)) - end) - 1);
              silc_free(tmp2->head);
              silc_buffer_set(tmp2, n, strlen(n));
            }
@@ -1930,3 +2082,244 @@ void silc_server_create_connections(SilcServer server)
                         silc_server_connect_to_router, server, 0, 1,
                         SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
 }
+
+static void
+silc_server_process_channel_pk_destruct(void *key, void *context,
+                                       void *user_context)
+{
+  silc_free(key);
+  silc_pkcs_public_key_free(context);
+}
+
+/* Processes a channel public key, either adds or removes it. */
+
+SilcStatus
+silc_server_process_channel_pk(SilcServer server,
+                              SilcChannelEntry channel,
+                              SilcUInt32 type, const unsigned char *pk,
+                              SilcUInt32 pk_len)
+{
+  unsigned char pkhash[20];
+  SilcPublicKey chpk;
+
+  SILC_LOG_DEBUG(("Processing channel public key"));
+
+  if (!pk || !pk_len)
+    return SILC_STATUS_ERR_NOT_ENOUGH_PARAMS;
+
+  /* Decode the public key */
+  if (!silc_pkcs_public_key_payload_decode((unsigned char *)pk, pk_len, &chpk))
+    return SILC_STATUS_ERR_UNSUPPORTED_PUBLIC_KEY;
+
+  /* Create channel public key list (hash table) if needed */
+  if (!channel->channel_pubkeys) {
+    channel->channel_pubkeys =
+      silc_hash_table_alloc(0, silc_hash_data, (void *)20,
+                           silc_hash_data_compare, (void *)20,
+                           silc_server_process_channel_pk_destruct, channel,
+                           TRUE);
+  }
+
+  /* Create SHA-1 digest of the public key data */
+  silc_hash_make(server->sha1hash, pk + 4, pk_len - 4, pkhash);
+
+  if (type == 0x00) {
+    /* Add new public key to channel public key list */
+    SILC_LOG_DEBUG(("Add new channel public key to channel %s",
+                   channel->channel_name));
+
+    /* Check for resource limit */
+    if (silc_hash_table_count(channel->channel_pubkeys) > 64) {
+      silc_pkcs_public_key_free(chpk);
+      return SILC_STATUS_ERR_RESOURCE_LIMIT;
+    }
+
+    /* Add if doesn't exist already */
+    if (!silc_hash_table_find(channel->channel_pubkeys, pkhash,
+                             NULL, NULL))
+      silc_hash_table_add(channel->channel_pubkeys, silc_memdup(pkhash, 20),
+                         chpk);
+  } else if (type == 0x01) {
+    /* Delete public key from channel public key list */
+    SILC_LOG_DEBUG(("Delete a channel public key from channel %s",
+                   channel->channel_name));
+    if (!silc_hash_table_del(channel->channel_pubkeys, pkhash))
+      silc_pkcs_public_key_free(chpk);
+  } else {
+    silc_pkcs_public_key_free(chpk);
+    return SILC_STATUS_ERR_NOT_ENOUGH_PARAMS;
+  }
+
+  return SILC_STATUS_OK;
+}
+
+/* Returns the channel public keys as Argument List payload. */
+
+SilcBuffer silc_server_get_channel_pk_list(SilcServer server,
+                                          SilcChannelEntry channel,
+                                          bool announce,
+                                          bool delete)
+{
+  SilcHashTableList htl;
+  SilcBuffer list, pkp;
+  SilcPublicKey pk;
+
+  SILC_LOG_DEBUG(("Encoding channel public keys list"));
+
+  if (!channel->channel_pubkeys ||
+      !silc_hash_table_count(channel->channel_pubkeys))
+    return NULL;
+
+  /* Encode the list */
+  list = silc_buffer_alloc_size(2);
+  silc_buffer_format(list,
+                    SILC_STR_UI_SHORT(silc_hash_table_count(
+                                      channel->channel_pubkeys)),
+                    SILC_STR_END);
+
+  silc_hash_table_list(channel->channel_pubkeys, &htl);
+  while (silc_hash_table_get(&htl, NULL, (void **)&pk)) {
+    pkp = silc_pkcs_public_key_payload_encode(pk);
+    list = silc_argument_payload_encode_one(list, pkp->data, pkp->len,
+                                           announce ? 0x03 :
+                                           delete ? 0x01 : 0x00);
+    silc_buffer_free(pkp);
+  }
+  silc_hash_table_list_reset(&htl);
+
+  return list;
+}
+
+/* Sets the channel public keys into channel from the list of public keys. */
+
+SilcStatus silc_server_set_channel_pk_list(SilcServer server,
+                                          SilcSocketConnection sender,
+                                          SilcChannelEntry channel,
+                                          const unsigned char *pklist,
+                                          SilcUInt32 pklist_len)
+{
+  SilcUInt16 argc;
+  SilcArgumentPayload args;
+  unsigned char *chpk;
+  SilcUInt32 chpklen, type;
+  SilcStatus ret = SILC_STATUS_OK;
+
+  SILC_LOG_DEBUG(("Setting channel public keys list"));
+
+  if (!pklist || pklist_len < 2)
+    return SILC_STATUS_ERR_NOT_ENOUGH_PARAMS;
+
+  /* Get the argument from the Argument List Payload */
+  SILC_GET16_MSB(argc, pklist);
+  args = silc_argument_payload_parse(pklist + 2, pklist_len - 2, argc);
+  if (!args)
+    return SILC_STATUS_ERR_NOT_ENOUGH_PARAMS;
+
+  /* Process the public keys one by one */
+  chpk = silc_argument_get_first_arg(args, &type, &chpklen);
+
+  /* If announcing keys and we have them set already, do not allow this */
+  if (chpk && type == 0x03 && channel->channel_pubkeys &&
+      server->server_type == SILC_ROUTER &&
+      sender != SILC_PRIMARY_ROUTE(server)) {
+    SILC_LOG_DEBUG(("Channel public key list set already, enforce our list"));
+    silc_argument_payload_free(args);
+    return SILC_STATUS_ERR_OPERATION_ALLOWED;
+  }
+
+  /* If we are normal server and receive announcement list and we already
+     have keys set, we replace the old list with the announced one. */
+  if (chpk && type == 0x03 && channel->channel_pubkeys &&
+      server->server_type != SILC_ROUTER) {
+    SilcBuffer sidp;
+    unsigned char mask[4];
+
+    SILC_LOG_DEBUG(("Router enforces its list, remove old list"));
+    silc_hash_table_free(channel->channel_pubkeys);
+    channel->channel_pubkeys = NULL;
+
+    /* Send notify that removes the old list */
+    sidp = silc_id_payload_encode(server->id, SILC_ID_SERVER);
+    SILC_PUT32_MSB((channel->mode & (~SILC_CHANNEL_MODE_CHANNEL_AUTH)), mask);
+    silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
+                                      SILC_NOTIFY_TYPE_CMODE_CHANGE, 7,
+                                      sidp->data, sidp->len,
+                                      mask, 4,
+                                      channel->cipher,
+                                      channel->cipher ?
+                                      strlen(channel->cipher) : 0,
+                                      channel->hmac_name,
+                                      channel->hmac_name ?
+                                      strlen(channel->hmac_name) : 0,
+                                      channel->passphrase,
+                                      channel->passphrase ?
+                                      strlen(channel->passphrase) : 0,
+                                      NULL, 0, NULL, 0);
+    silc_buffer_free(sidp);
+  }
+
+  while (chpk) {
+    if (type == 0x03)
+      type = 0x00;
+    ret = silc_server_process_channel_pk(server, channel, type,
+                                        chpk, chpklen);
+    if (ret != SILC_STATUS_OK)
+      break;
+    chpk = silc_argument_get_next_arg(args, &type, &chpklen);
+  }
+
+  silc_argument_payload_free(args);
+  return ret;
+}
+
+/* Verifies the Authentication Payload `auth' with one of the public keys
+   on the `channel' public key list. */
+
+bool silc_server_verify_channel_auth(SilcServer server,
+                                    SilcChannelEntry channel,
+                                    SilcClientID *client_id,
+                                    const unsigned char *auth,
+                                    SilcUInt32 auth_len)
+{
+  SilcAuthPayload ap;
+  SilcPublicKey chpk;
+  unsigned char *pkhash;
+  SilcUInt32 pkhash_len;
+  bool ret = FALSE;
+
+  SILC_LOG_DEBUG(("Verifying channel authentication"));
+
+  if (!auth || !auth_len || !channel->channel_pubkeys)
+    return FALSE;
+
+  /* Get the hash from the auth data which tells us what public key we
+     must use in verification. */
+
+  ap = silc_auth_payload_parse(auth, auth_len);
+  if (!ap)
+    return FALSE;
+
+  pkhash = silc_auth_get_public_data(ap, &pkhash_len);
+  if (pkhash_len < 128)
+    goto out;
+
+  /* Find the public key with the hash */
+  if (!silc_hash_table_find(channel->channel_pubkeys, pkhash,
+                           NULL, (void **)&chpk)) {
+    SILC_LOG_DEBUG(("Public key not found in channel public key list"));
+    goto out;
+  }
+
+  /* Verify the signature */
+  if (!silc_auth_verify(ap, SILC_AUTH_PUBLIC_KEY, (void *)chpk, 0,
+                       server->sha1hash, client_id, SILC_ID_CLIENT)) {
+    SILC_LOG_DEBUG(("Authentication failed"));
+    goto out;
+  }
+
+  ret = TRUE;
+
+ out:
+  silc_auth_payload_free(ap);
+  return ret;
+}
index 489abf8781633deda10323812360d2bf4b199866..413bdeb97284c108dec09cb9f6a5b5052b5cd88c 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  server_util.h 
+  server_util.h
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2002 Pekka Riikonen
+  Copyright (C) 1997 - 2003 Pekka Riikonen
 
   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
@@ -22,7 +22,7 @@
 
 /* This function removes all client entries that are originated from
    `router' and are owned by `entry'.  `router' and `entry' can be same
-   too.  If `server_signoff' is TRUE then SERVER_SIGNOFF notify is 
+   too.  If `server_signoff' is TRUE then SERVER_SIGNOFF notify is
    distributed to our local clients. */
 bool silc_server_remove_clients_by_server(SilcServer server,
                                          SilcServerEntry router,
@@ -34,8 +34,9 @@ bool silc_server_remove_clients_by_server(SilcServer server,
    attempt to figure out which clients really are originated from the
    `from' and which are originated from a server that we have connection
    to, when we've acting as backup router. If it is FALSE the `to' will
-   be the new source. */
-void silc_server_update_clients_by_server(SilcServer server, 
+   be the new source.  If `from' is NULL then all clients (except locally
+   connected) are updated `to'. */
+void silc_server_update_clients_by_server(SilcServer server,
                                          SilcServerEntry from,
                                          SilcServerEntry to,
                                          bool resolve_real_server);
@@ -62,11 +63,11 @@ void silc_server_remove_servers_by_server(SilcServer server,
                                          bool remove_clients);
 
 /* Removes channels that are from `from. */
-void silc_server_remove_channels_by_server(SilcServer server, 
+void silc_server_remove_channels_by_server(SilcServer server,
                                           SilcServerEntry from);
 
 /* Updates channels that are from `from' to be originated from `to'.  */
-void silc_server_update_channels_by_server(SilcServer server, 
+void silc_server_update_channels_by_server(SilcServer server,
                                           SilcServerEntry from,
                                           SilcServerEntry to);
 
@@ -85,9 +86,9 @@ bool silc_server_channel_has_local(SilcChannelEntry channel);
 bool silc_server_channel_delete(SilcServer server,
                                SilcChannelEntry channel);
 
-/* Returns TRUE if the given client is on the channel.  FALSE if not. 
+/* Returns TRUE if the given client is on the channel.  FALSE if not.
    This works because we assure that the user list on the channel is
-   always in up to date thus we can only check the channel list from 
+   always in up to date thus we can only check the channel list from
    `client' which is faster than checking the user list from `channel'. */
 bool silc_server_client_on_channel(SilcClientEntry client,
                                   SilcChannelEntry channel,
@@ -95,6 +96,7 @@ bool silc_server_client_on_channel(SilcClientEntry client,
 
 /* Checks string for bad characters and returns TRUE if they are found. */
 bool silc_server_name_bad_chars(const char *name, SilcUInt32 name_len);
+bool silc_server_name_bad_chchars(const char *name, SilcUInt32 name_len);
 
 /* Modifies the `nick' if it includes bad characters and returns new
    allocated nickname that does not include bad characters. */
@@ -108,17 +110,17 @@ SilcUInt32 silc_server_num_sockets_by_ip(SilcServer server, const char *ip,
 /* Find number of sockets by IP address indicated by remote host, indicated
    by `ip' or `hostname', `port', and `type'.  Returns 0 if socket connections
    does not exist. If `ip' is provided then `hostname' is ignored. */
-SilcUInt32 silc_server_num_sockets_by_remote(SilcServer server, 
+SilcUInt32 silc_server_num_sockets_by_remote(SilcServer server,
                                             const char *ip,
                                             const char *hostname,
                                             SilcUInt16 port,
                                             SilcSocketType type);
 
-/* Finds locally cached public key by the public key received in the SKE. 
+/* Finds locally cached public key by the public key received in the SKE.
    If we have it locally cached then we trust it and will use it in the
    authentication protocol.  Returns the locally cached public key or NULL
    if we do not find the public key.  */
-SilcPublicKey silc_server_find_public_key(SilcServer server, 
+SilcPublicKey silc_server_find_public_key(SilcServer server,
                                          SilcHashTable local_public_keys,
                                          SilcPublicKey remote_public_key);
 
@@ -132,7 +134,7 @@ SilcPublicKey silc_server_get_public_key(SilcServer server,
 /* Check whether the connection `sock' is allowed to connect to us.  This
    checks for example whether there is too much connections for this host,
    and required version for the host etc. */
-bool silc_server_connection_allowed(SilcServer server, 
+bool silc_server_connection_allowed(SilcServer server,
                                    SilcSocketConnection sock,
                                    SilcSocketType type,
                                    SilcServerConfigConnParams *global,
@@ -207,7 +209,36 @@ void silc_server_inviteban_process(SilcServer server, SilcHashTable list,
 void silc_server_inviteban_destruct(void *key, void *context,
                                    void *user_context);
 
-/* Creates connections accoring to configuration. */
+/* Creates connections according to configuration. */
 void silc_server_create_connections(SilcServer server);
 
+
+/* Processes a channel public key, either adds or removes it. */
+SilcStatus
+silc_server_process_channel_pk(SilcServer server,
+                              SilcChannelEntry channel,
+                              SilcUInt32 type, const unsigned char *pk,
+                              SilcUInt32 pk_len);
+
+/* Returns the channel public keys as Argument List payload. */
+SilcBuffer silc_server_get_channel_pk_list(SilcServer server,
+                                          SilcChannelEntry channel,
+                                          bool announce,
+                                          bool delete);
+
+/* Sets the channel public keys into channel from the list of public keys. */
+SilcStatus silc_server_set_channel_pk_list(SilcServer server,
+                                          SilcSocketConnection sender,
+                                          SilcChannelEntry channel,
+                                          const unsigned char *pklist,
+                                          SilcUInt32 pklist_len);
+
+/* Verifies the Authentication Payload `auth' with one of the public keys
+   on the `channel' public key list. */
+bool silc_server_verify_channel_auth(SilcServer server,
+                                    SilcChannelEntry channel,
+                                    SilcClientID *client_id,
+                                    const unsigned char *auth,
+                                    SilcUInt32 auth_len);
+
 #endif /* SERVER_UTIL_H */
index 2121264101e7665917e15b7519a0166af7f7642a..8ff643c1e0f4fc126349a05cdba23d956d3ec844 100644 (file)
@@ -303,6 +303,10 @@ SILC_CONFIG_CALLBACK(fetch_generic)
   else if (!strcmp(name, "qos_limit_usec")) {
     config->param.qos_limit_usec = *(SilcUInt32 *)val;
   }
+  else if (!strcmp(name, "debug_string")) {
+    CONFIG_IS_DOUBLE(config->debug_string);
+    config->debug_string = (*(char *)val ? strdup((char *) val) : NULL);
+  }
   else
     return SILC_CONFIG_EINTERNAL;
 
@@ -460,7 +464,7 @@ SILC_CONFIG_CALLBACK(fetch_pkcs)
   SERVER_CONFIG_DEBUG(("Received PKCS type=%d name=\"%s\" (val=%x)",
                       type, name, context));
   if (type == SILC_CONFIG_ARG_BLOCK) {
-    /* check the temporary struct's fields */
+    /* Check the temporary struct's fields */
     if (!tmp) /* discard empty sub-blocks */
       return SILC_CONFIG_OK;
     if (!tmp->name) {
@@ -498,7 +502,7 @@ SILC_CONFIG_CALLBACK(fetch_serverinfo)
   SERVER_CONFIG_DEBUG(("Received SERVERINFO type=%d name=\"%s\" (val=%x)",
                       type, name, context));
 
-  /* if there isn't the main struct alloc it */
+  /* If there isn't the main struct alloc it */
   if (!server_info)
     config->server_info = server_info = (SilcServerConfigServerInfo *)
                silc_calloc(1, sizeof(*server_info));
@@ -594,7 +598,7 @@ SILC_CONFIG_CALLBACK(fetch_serverinfo)
     char *file_tmp = (char *) val;
     CONFIG_IS_DOUBLE(server_info->public_key);
 
-    /* try to load specified file, if fail stop config parsing */
+    /* Try to load specified file, if fail stop config parsing */
     if (!silc_pkcs_load_public_key(file_tmp, &server_info->public_key,
                                   SILC_PKCS_FILE_PEM))
       if (!silc_pkcs_load_public_key(file_tmp, &server_info->public_key,
@@ -604,10 +608,21 @@ SILC_CONFIG_CALLBACK(fetch_serverinfo)
       }
   }
   else if (!strcmp(name, "privatekey")) {
+    struct stat st;
     char *file_tmp = (char *) val;
     CONFIG_IS_DOUBLE(server_info->private_key);
 
-    /* try to load specified file, if fail stop config parsing */
+    /* Check the private key file permissions. */
+    if ((stat(file_tmp, &st)) != -1) {
+      if ((st.st_mode & 0777) != 0600) {
+       SILC_SERVER_LOG_ERROR(("Wrong permissions in private key "
+                             "file \"%s\".  The permissions must be "
+                             "0600.", file_tmp));
+        return SILC_CONFIG_ESILENT;
+      }
+    }
+
+    /* Try to load specified file, if fail stop config parsing */
     if (!silc_pkcs_load_private_key(file_tmp, &server_info->private_key,
                                    "", 0, SILC_PKCS_FILE_BIN))
       if (!silc_pkcs_load_private_key(file_tmp, &server_info->private_key,
@@ -621,7 +636,7 @@ SILC_CONFIG_CALLBACK(fetch_serverinfo)
   return SILC_CONFIG_OK;
 
  got_err:
-  /* here we need to check if tmp exists because this function handles
+  /* Here we need to check if tmp exists because this function handles
    * misc data (multiple fields and single-only fields) */
   if (tmp) {
     silc_free(tmp->server_ip);
@@ -973,6 +988,10 @@ SILC_CONFIG_CALLBACK(fetch_server)
     /* check the temporary struct's fields */
     if (!tmp) /* discard empty sub-blocks */
       return SILC_CONFIG_OK;
+    if (!tmp->host) {
+      got_errno = SILC_CONFIG_EMISSFIELDS;
+      goto got_err;
+    }
 
     /* the temporary struct is ok, append it to the list */
     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->servers);
@@ -1036,6 +1055,10 @@ SILC_CONFIG_CALLBACK(fetch_router)
   if (type == SILC_CONFIG_ARG_BLOCK) {
     if (!tmp) /* discard empty sub-blocks */
       return SILC_CONFIG_OK;
+    if (!tmp->host) {
+      got_errno = SILC_CONFIG_EMISSFIELDS;
+      goto got_err;
+    }
 
     SILC_SERVER_CONFIG_LIST_APPENDTMP(config->routers);
     config->tmp = NULL;
@@ -1146,6 +1169,7 @@ static const SilcConfigTable table_general[] = {
   { "qos_bytes_limit",         SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
   { "qos_limit_sec",           SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
   { "qos_limit_usec",          SILC_CONFIG_ARG_INT,    fetch_generic,  NULL },
+  { "debug_string",                    SILC_CONFIG_ARG_STR,    fetch_generic,  NULL },
   { 0, 0, 0, 0 }
 };
 
@@ -1518,6 +1542,7 @@ void silc_server_config_destroy(SilcServerConfig config)
 
   /* Destroy general config stuff */
   silc_free(config->module_path);
+  silc_free(config->debug_string);
   silc_free(config->param.version_protocol);
   silc_free(config->param.version_software);
   silc_free(config->param.version_software_vendor);
index 03cb63a0d89b57304e2508dd961e9216d55c0ecb..2104976ed3e87275c5c485ab67a941d792cd930f 100644 (file)
@@ -175,6 +175,7 @@ typedef struct {
   bool logging_timestamp;
   bool logging_quick;
   long logging_flushdelay;
+  char *debug_string;
 
   /* Other configuration sections */
   SilcServerConfigCipher *cipher;
index d7e276a6175e65325f9ba997766ca3bbdeb73666..9e2c2a16b0ee5b161d4ad675fd13d5f41f3933b4 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2002 Pekka Riikonen
+  Copyright (C) 1997 - 2003 Pekka Riikonen
 
   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
@@ -317,7 +317,7 @@ SILC_TASK_CALLBACK(dump_stats)
   fprintf(fdd, "  backup_noswitch        : %d\n", silcd->backup_noswitch);
   fprintf(fdd, "  wait_backup            : %d\n", silcd->wait_backup);
   if (silcd->router)
-    fprintf(fdd, "  primary router         : %s\n", 
+    fprintf(fdd, "  primary router         : %s\n",
       silcd->router->server_name ? silcd->router->server_name : "");
 
   /* Dump socket connections */
@@ -347,7 +347,7 @@ SILC_TASK_CALLBACK(dump_stats)
     int c;
 
     fprintf(fdd, "\nDumping databases\n");
-    
+
     if (silc_idcache_get_all(silcd->local_list->servers, &list)) {
       if (silc_idcache_list_first(list, &id_cache)) {
        fprintf(fdd, "\nServers in local-list:\n");
@@ -692,7 +692,7 @@ int main(int argc, char **argv)
   if (ret == FALSE)
     goto fail;
 
-  /* Register default crypto stuff since we are going to need them 
+  /* Register default crypto stuff since we are going to need them
      in the configuration file parsing phase */
   silc_cipher_register_default();
   silc_pkcs_register_default();
@@ -718,11 +718,21 @@ int main(int argc, char **argv)
   if (silc_server_init(silcd) == FALSE)
     goto fail;
 
-  /* Ignore SIGPIPE */
+  /* Ignore some signals */
   sa.sa_handler = SIG_IGN;
   sa.sa_flags = 0;
   sigemptyset(&sa.sa_mask);
-  sigaction(SIGPIPE, &sa, NULL);
+#if defined(SIGPIPE)
+  sigaction(SIGPIPE, &sa, NULL);      /* Ignore broken pipes */
+#endif /* SIGPIPE*/
+#if defined(SIGXFSZ)
+  sigaction(SIGXFSZ, &sa, NULL);      /* Ignore file limit exceeds */
+#endif /* SIGXFSZ */
+#if defined(SIGXCPU)
+  sigaction(SIGXCPU, &sa, NULL);      /* Ignore CPU time limit exceeds */
+#endif /* SIGXCPU */
+
+  /* Handle specificly some other signals. */
   sa.sa_handler = signal_handler;
   sigaction(SIGHUP, &sa, NULL);
   sigaction(SIGTERM, &sa, NULL);
index 8b0ac3347bfb4281815f44e2f2b233dc7e8d9527..4bb362c80a9c18ec25db05ff880927b44369a7a1 100644 (file)
@@ -79,13 +79,13 @@ AC_DEFINE(SILC_DIST_DEFINE)
 LIB_BASE_VERSION=1.0
 
 # libsilc versions
-LIBSILC_CURRENT=1
+LIBSILC_CURRENT=2
 LIBSILC_REVISION=0
-LIBSILC_AGE=1
+LIBSILC_AGE=0
 
 # libsilcclient versions
-LIBSILCCLIENT_CURRENT=1
-LIBSILCCLIENT_REVISION=1
+LIBSILCCLIENT_CURRENT=2
+LIBSILCCLIENT_REVISION=0
 LIBSILCCLIENT_AGE=0
 
 # Substitute the version numbers
@@ -361,6 +361,29 @@ else
   fi
 fi
 
+#
+# Workaround a bug in GCC 2.x which causes memory exhaustion
+# when compiling sha1 with optimizations on UltraSPARC.
+#
+FIX_SHA1='#'
+if test "$GCC" -a "$host_cpu" = "sparc64"; then
+  AC_MSG_CHECKING(whether to enable GCC 2.x workaround for SHA1)
+  AC_TRY_COMPILE(
+    [
+      #if defined(__sparc64__) && (__GNUC__ == 2)
+      #else
+      choke me
+      #endif
+    ],
+    [],
+    [
+      FIX_SHA1=''
+      AC_MSG_RESULT(yes)
+    ],
+      AC_MSG_RESULT(no)
+    )
+fi
+AC_SUBST(FIX_SHA1)
 
 ##
 ##  Installation
@@ -977,7 +1000,7 @@ fi
 #
 AC_MSG_CHECKING(whether to compile native WIN32 code)
 AC_ARG_WITH(win32,
-  [  --with-win32            compile native WIN32 code (-mno-cygwin)],
+  [  --with-win32            compile native WIN32 (MinGW) code (-mno-cygwin)],
   [
     AC_MSG_RESULT(yes)
     AC_DEFINE(SILC_WIN32)
@@ -1032,6 +1055,13 @@ AC_ARG_WITH(silcd,
     AC_MSG_RESULT(yes)
   ])
 
+# Irssi perl support
+#
+AC_ARG_WITH(perl,
+  [[  --with-perl[=yes|no|module]  Build with Perl support - also specifies
+                               if it should be built into main silc binary
+                               (static, default) or as a module]])
+
 libtoolfix=true
 AC_MSG_CHECKING(whether to do libtoolfix)
 AC_ARG_WITH(libtoolfix,
@@ -1118,7 +1148,6 @@ lib/silcsftp/Makefile
 lib/silcsftp/tests/Makefile
 doc/example_silcd.conf
 includes/silcincludes.h
-silcmap/Makefile
 )
 
 if test "x$silc_dist" = "xsilc-client" ||
index 6fc615506e43700d894840a5567bad01b4f7b374..edb11a70f8c0119aced30dc70260fb06996a9a73 100644 (file)
@@ -24,12 +24,12 @@ DIST_SUBDIRS = SILC_DISTRIBUTION_SUBDIRS
 makerfc = ../scripts/makerfc
 
 all:
-       touch draft-riikonen-silc-spec-06.txt
-       touch draft-riikonen-silc-pp-06.txt
-       touch draft-riikonen-silc-ke-auth-06.txt
-       touch draft-riikonen-silc-commands-04.txt
-       touch draft-riikonen-silc-flags-payloads-02.txt
-       touch draft-riikonen-presence-attrs-01.txt
+       touch draft-riikonen-silc-spec-08.txt
+       touch draft-riikonen-silc-pp-08.txt
+       touch draft-riikonen-silc-ke-auth-07.txt
+       touch draft-riikonen-silc-commands-06.txt
+       touch draft-riikonen-silc-flags-payloads-03.txt
+       touch draft-riikonen-presence-attrs-02.txt
 
 if SILC_DIST_TOOLKIT
 toolkit-ref-html:
@@ -56,35 +56,35 @@ toolkit-ref-pdf:
 
 dist-hook:
        $(SILC_TOP_SRCDIR)/scripts/manpages.pl
-       touch draft-riikonen-silc-spec-06.txt
-       touch draft-riikonen-silc-pp-06.txt
-       touch draft-riikonen-silc-ke-auth-06.txt
-       touch draft-riikonen-silc-commands-04.txt
-       touch draft-riikonen-silc-flags-payloads-02.txt
-       touch draft-riikonen-presence-attrs-01.txt
-       $(makerfc) draft-riikonen-silc-spec-06.nroff \
-               draft-riikonen-silc-spec-06.txt
-       $(makerfc) draft-riikonen-silc-pp-06.nroff \
-               draft-riikonen-silc-pp-06.txt
-       $(makerfc) draft-riikonen-silc-ke-auth-06.nroff \
-               draft-riikonen-silc-ke-auth-06.txt
-       $(makerfc) draft-riikonen-silc-commands-04.nroff \
-               draft-riikonen-silc-commands-04.txt
-       $(makerfc) draft-riikonen-silc-flags-payloads-02.nroff \
-               draft-riikonen-silc-flags-payloads-02.txt
-       $(makerfc) draft-riikonen-presence-attrs-01.nroff \
-               draft-riikonen-presence-attrs-01.txt
+       touch draft-riikonen-silc-spec-08.txt
+       touch draft-riikonen-silc-pp-08.txt
+       touch draft-riikonen-silc-ke-auth-07.txt
+       touch draft-riikonen-silc-commands-06.txt
+       touch draft-riikonen-silc-flags-payloads-03.txt
+       touch draft-riikonen-presence-attrs-02.txt
+       $(makerfc) draft-riikonen-silc-spec-08.nroff \
+               draft-riikonen-silc-spec-08.txt
+       $(makerfc) draft-riikonen-silc-pp-08.nroff \
+               draft-riikonen-silc-pp-08.txt
+       $(makerfc) draft-riikonen-silc-ke-auth-07.nroff \
+               draft-riikonen-silc-ke-auth-07.txt
+       $(makerfc) draft-riikonen-silc-commands-06.nroff \
+               draft-riikonen-silc-commands-06.txt
+       $(makerfc) draft-riikonen-silc-flags-payloads-03.nroff \
+               draft-riikonen-silc-flags-payloads-03.txt
+       $(makerfc) draft-riikonen-presence-attrs-02.nroff \
+               draft-riikonen-presence-attrs-02.txt
 
 else
 dist-hook:
        $(SILC_TOP_SRCDIR)/scripts/manpages.pl
        rm draft-riikonen*.txt
-       touch draft-riikonen-silc-spec-06.txt
-       touch draft-riikonen-silc-pp-06.txt
-       touch draft-riikonen-silc-ke-auth-06.txt
-       touch draft-riikonen-silc-commands-04.txt
-       touch draft-riikonen-silc-flags-payloads-02.txt
-       touch draft-riikonen-presence-attrs-01.txt
+       touch draft-riikonen-silc-spec-08.txt
+       touch draft-riikonen-silc-pp-08.txt
+       touch draft-riikonen-silc-ke-auth-07.txt
+       touch draft-riikonen-silc-commands-06.txt
+       touch draft-riikonen-silc-flags-payloads-04.txt
+       touch draft-riikonen-presence-attrs-02.txt
 endif
 
 if SILC_DIST_TOOLKIT
diff --git a/doc/draft-riikonen-presence-attrs-02.nroff b/doc/draft-riikonen-presence-attrs-02.nroff
new file mode 100644 (file)
index 0000000..3e90e16
--- /dev/null
@@ -0,0 +1,669 @@
+.pl 10.0i
+.po 0
+.ll 7.2i
+.lt 7.2i
+.nr LL 7.2i
+.nr LT 7.2i
+.ds LF Riikonen
+.ds RF FORMFEED[Page %]
+.ds CF
+.ds LH Internet Draft
+.ds RH 29 July 2003
+.ds CH
+.na
+.hy 0
+.in 0
+.nf
+Network Working Group                                        P. Riikonen
+Internet-Draft
+draft-riikonen-presence-attrs-02.txt                        29 July 2003
+Expires: 29 January 2004
+
+.in 3
+
+.ce 2
+User Online Presence and Information Attributes
+<draft-riikonen-presence-attrs-02.txt>
+
+.ti 0
+Status of this Memo
+
+This document is an Internet-Draft and is in full conformance with   
+all provisions of Section 10 of RFC 2026.  Internet-Drafts are   
+working documents of the Internet Engineering Task Force (IETF), its   
+areas, and its working groups.  Note that other groups may also   
+distribute working documents as Internet-Drafts.   
+
+Internet-Drafts are draft documents valid for a maximum of six months   
+and may be updated, replaced, or obsoleted by other documents at any   
+time.  It is inappropriate to use Internet-Drafts as reference   
+material or to cite them other than as "work in progress."   
+
+The list of current Internet-Drafts can be accessed at   
+http://www.ietf.org/ietf/1id-abstracts.txt   
+
+The list of Internet-Draft Shadow Directories can be accessed at   
+http://www.ietf.org/shadow.html   
+
+The distribution of this memo is unlimited.  
+
+
+.ti 0
+Abstract
+
+This document defines set of attributes that can represent the online
+user's presence in a network, and to provide general information about
+the user.  The purpose is to provide a generic mechanism to share
+online presence and status, and general information about the user
+to be used in several kind of network protocols and applications.
+These attributes could be used by for example chat and conferencing
+protocols (such as Instant Message protocols), network games, and
+other similar network protocols and applications that has online
+users in a network.
+
+
+
+
+
+
+
+.ti 0
+Table of Contents
+
+.nf
+1 Introduction ..................................................  2
+  1.1 Requirements Terminology ..................................  2
+2 Attributes Concept ............................................  3
+  2.1 Requesting Attributes .....................................  3
+  2.2 Replying Attributes .......................................  3
+  2.3 Attribute Data Types ......................................  4
+  2.4 Attribute Payload .........................................  4
+  2.5 Attributes ................................................  5
+3 Security Considerations .......................................  11
+4 References ....................................................  12
+5 Author's Address ..............................................  13
+6 Full Copyright Statement ......................................  13
+
+
+.ti 0
+1. Introduction
+
+This document defines set of attributes that can represent the online
+user's presence in a network, and to provide general information about
+the user.  The purpose is to provide a generic mechanism to share
+online presence and status, and general information about the user
+to be used in several kind of network protocols and applications.
+These attributes could be used by for example chat and conferencing
+protocols (such as Instant Message protocols), network games, and
+other similar network protocols and applications that has online
+users in a network.
+
+This document does not define these attributes to be used in any
+specific protocol, but assumes that they can be used generally in
+any kind of online network protocol.  Furthermore, the document
+pays attention to special needs of various protocols, such as
+mobile network protocols, which requires the attributes to be
+both robust and compact.  The attributes are also considered to be
+easily implementable and for this reason a clear and robust structure
+was chosen for the attributes.
+
+This document is strongly influenced by Wireless Village Initiative
+where similar attributes are defined, and credits for the ideas are
+due there.  However, they are defined only in the context of the
+Wireless Village, and the format of the attributes used is not
+suitable for general purpose usage.
+
+
+.ti 0
+1.1 Requirements Terminology
+
+The keywords MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, RECOMMENDED, 
+MAY, and OPTIONAL, when they appear in this document, are to be
+interpreted as described in [RFC2119].
+
+
+.ti 0
+2 Attributes Concept
+
+Many network protocols needs a way to transfer and retrieve status
+information about users in a network.  For example, many chat and
+conferencing protocols such as IRC, and all Instant Message (IM)
+protocols, such as ICQ has a way to retrieve presence and status
+information about the users in the network.  This could be added to
+several other kind of network protocols as well, and for this reason
+a defined mechanism to provide these informations is needed.
+
+The attributes are usually requested by an entity in the network
+from other entity, usually a user or end user's device in the network.
+The recipient then replies to each of the requested attributes and
+sends the reply to the requester.
+
+This document does not define the actual transport for requesting and
+providing the replies to the requests, since this is irrelevant.
+This document defines a payload for requesting, and providing the
+information, but how the payload is transported is not defined in
+this document.  In a client-server network model the user requesting
+attributes usually destine the request to a remote user and the
+server relays the attributes to the remote user.  It is also possible
+that the concept is not user-to-user, but the server replies to the
+requested attributes on behalf of the user.
+
+
+.ti 0
+2.1 Requesting Attributes
+
+When an entity requests attributes from a user in the network,
+it assembles a list of Attribute Payloads, and sets the requested
+attribute value into the payload.  Each requested attribute is a separate
+Attribute Payload and they MUST be appended one after the other.  The
+requester need to understand that the recipient may not understand all
+the requested attributes, and may not reply to all of the requested
+attributes.  The requester also need to understand that the recipient
+may reply with additional attributes that were not requested.
+
+
+.ti 0
+2.2 Replying Attributes
+
+When en entity receives the Attribute Payloads it parses them one after
+the other.  The entity can parse each of the Attribute Payload separately
+since it knows the length of the current attribute; next attribute
+begins after the current attribute ends.  The entity then checks the
+requested attribute and SHOULD reply either with valid value or with
+an indication that the attribute is unsupported or unknown.  It is
+also possible to reply with additional attributes that were not
+requested.
+
+When replying to the requested attributes the entity assembles a list
+of Attribute Payloads, each including the attribute type and the
+actual attribute data.
+
+
+.ti 0
+2.3 Attribute Data Types
+
+This section defines basic data types that can appear in the attributes
+in this document.
+
+All integer values are stored in the MSB first order.  The size of the
+integer is provided separately with the attribute.  Integer is
+represented as "integer" in this documentation.
+
+Strings are always UTF-8 [RFC2279] encoded, and include 2 bytes length
+field indicating the length of the string.  Hence, when "string" value
+appears in this documentation it is encoded as:
+
+.in 6
+Length       Type       Value
+2 bytes      integer    Length of String field
+variable     UTF-8      String
+.in 3
+
+If string is not present then the length field includes zero (0)
+value.
+
+Boolean value is represented as "boolean" and its size is 1 byte.
+Value 0x00 indicates false value and value 0x01 indicates true value.
+
+
+.ti 0
+2.4 Attribute Payload
+
+The Attribute Payload is used to request an attribute, and to reply
+to the requested attribute.  One payload includes one attribute.
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|   Attribute   |   Attr Flags  |        Attribute Length       |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                        Attribute Data                         ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 1:  Attribute Payload
+
+
+.in 6
+o Attribute (1 byte) - Indicates the attribute included in this
+  Attribute Payload.
+
+o Attribute Flags (1 byte) - Indicates the flags associated
+  with this attribute.  The following flags are defined:
+
+    0x01        ATTRIBUTE_FLAG_INVALID
+
+      The attribute value in Attribute Data is invalid, or
+      unknown.  This may be set to indicate that a requested
+      attribute is not available, its value is unknown, or
+      sender does not understand it.
+
+    0x02        ATTRIBUTE_FLAG_VALID
+
+      The attribute value is included in the Attribute Data.
+
+  When sending this payload to request attributes this value
+  MUST be set to zero (0) value.  When sending a reply to the
+  request this field MUST NOT include a zero (0) value.
+
+o Attribute Length (2 bytes) - Indicates the length of the
+  Attribute Data field, not including any other field.
+
+o Attribute Data (variable length) - The Attribute Data.
+  The contents of this field is attribute specific, defined
+  subsequently.
+.in 3
+
+
+.ti 0
+2.5 Attributes
+
+The following values can appear in the Attribute field in the
+Attribute Payload to indicate the content of the attribute.  The
+format of the attribute data is represented as length, type and
+value.  Example:
+
+.in 6
+Length       Type       Value
+2 bytes      integer    Some integer value
+variable     string     Some string
+1 byte       boolean    Boolean value
+.in 3
+
+When sending multiple Attribute Payloads it is possible to include
+multiple same attributes in the packet.
+
+
+.in 6
+0    ATTRIBUTE_NONE
+
+     This attribute is reserved and it is never sent.
+
+
+1    ATTRIBUTE_USER_INFO
+
+     This attribute includes general information about the user, their
+     name and contact information.  The content of this attribute is
+     a VCard version 3.0 as defined in RFC 2426 [RFC2426] and RFC 2425
+     [RFC2425].  Note that some of the information that VCard provides
+     can be also provided in the means of providing other attributes.
+     The rationale for this is that the VCard does not provide all the
+     information, or with the required precision that may be desired in
+     some applications.  It is therefore RECOMMENDED that this attribute
+     would be used to provide only basic and constant user information,
+     such as name and contact information, but not online status 
+     information.
+
+     Length       Type       Value
+     variable     VCard      Basic user information
+
+
+2    ATTRIBUTE_SERVICE
+
+     This attribute indicates a service in the Internet that the user
+     is currently using or has logged in.  It also shows when the user
+     started using the service, and how long user has been idle in the
+     service.  The value of this attribute is as follows:
+
+     Length       Type       Value
+     4 bytes      integer    Service Port (IANA specified)
+     variable     string     Service Address
+     1 byte       boolean    Online status.  If this is set to
+                             0x01 (true) it means the user is online
+                             in the service.  Set to 0x00 (false) when
+                             out of reach.
+     variable     string     Signon date and time, UTC date, format as
+                             in ISO 8601
+     4 bytes      integer    Idle time
+
+
+3    ATTRIBUTE_STATUS_MOOD
+
+     This attribute indicates the mood of the user.  It can indicate
+     whether the user is eager to participate in the network.  The
+     value of this attribute is as follows:
+
+     Length       Type       Value
+     4 bytes      integer    Mood mask (values ORed together)
+
+     The following mood values are defined:
+
+     0x00000000   MOOD_NORMAL       No specific mood, normal mood
+     0x00000001   MOOD_HAPPY        The user feels happy
+     0x00000002   MOOD_SAD          The user feels sad
+     0x00000004   MOOD_ANGRY        The user feels angry
+     0x00000008   MOOD_JEALOUS      The user feels jealous
+     0x00000010   MOOD_ASHAMED      The user feels ashamed
+     0x00000020   MOOD_INVINCIBLE   The user feels invincible
+     0x00000040   MOOD_INLOVE       The user feels being in love
+     0x00000080   MOOD_SLEEPY       The user feels sleepy
+     0x00000100   MOOD_BORED        The user feels bored
+     0x00000200   MOOD_EXCITED      The user feels excited
+     0x00000400   MOOD_ANXIOUS      The user feels anxious
+
+
+4    ATTRIBUTE_STATUS_FREETEXT
+
+     This attribute includes the user's online status free text.  It
+     can provide personal status as a text message.  The contents of
+     this attribute is a UTF-8 encoded free text string.
+
+     Length       Type       Value
+     variable     string     Free text status string
+
+
+5    ATTRIBUTE_STATUS_MESSAGE
+
+     This attribute includes the user's online status message.  It
+     could provide for example a multi media message showing the status
+     of the user.  The contents of this attribute is a MIME object,
+     which can be used to provide for example video, audio, image or
+     other similar status message.  It could also provide a reference
+     to the message, for example an URL address.
+
+     Length       Type       Value
+     variable     MIME       Status message as MIME object
+
+
+6    ATTRIBUTE_PREFERRED_LANGUAGE
+
+     This attribute indicates the preferred language to be used when
+     communicating.  The encoding of this attribute is as follows:
+
+     Length       Type       Value
+     variable     string     ISO 639-2/T three letter code
+
+
+7    ATTRIBUTE_PREFERRED_CONTACT
+
+     This attribute indicates the preferred contact methods.  It can
+     indicate the method the user prefers when contacting.  The value
+     of this attribute is as follows:
+
+     Length       Type       Value
+     4 bytes      integer    Contact mask (values ORed together)
+
+     The following contact methods are defined:
+
+     0x00000000   CONTACT_NONE     No specific preferred contact method
+     0x00000001   CONTACT_EMAIL    Email is preferred
+     0x00000002   CONTACT_CALL     Phone call is preferred
+     0x00000004   CONTACT_PAGE     Paging is preferred
+     0x00000008   CONTACT_SMS      SMS is preferred
+     0x00000010   CONTACT_MMS      MMS is preferred
+     0x00000020   CONTACT_CHAT     Chatting is preferred
+     0x00000040   CONTACT_VIDEO    Video conferencing is preferred
+
+
+8    ATTRIBUTE_TIMEZONE
+
+     This attribute can be used to provide the current local time for
+     the user.  The contents of this attribute is a UTF-8 encoded
+     string and the format of the string is UTC time zone defined
+     in the ISO 8601.
+
+     Length       Type       Value
+     variable     string     UTC date, format as in ISO 8601
+
+     Note that ATTRIBUTE_USER_INFO may also provide this information.
+     However it is RECOMMENDED that this attribute is used when
+     current time zone information is provided.
+
+
+9    ATTRIBUTE_GEOLOCATION
+
+     This attribute can be used to provide measured global location of
+     the user.  How this information is gathered is out of scope of
+     this document.  The attribute can provide latitude and longitude
+     lateral positions, but also a vertical position.  A parameter
+     describing the accuracy of the information can also be provided.
+
+     Length       Type       Value
+     variable     string     Longitude (ex. 31 17 14.321W)
+     variable     string     Latitude (ex. 12 11 21.2N)
+     variable     string     Altitude
+     variable     string     Accuracy in meters
+
+     Note that ATTRIBUTE_USER_INFO may also provide this information,
+     however it does not have the vertical position, or the accuracy
+     parameter.  It is RECOMMENDED that this attribute is used when
+     providing current global position information.
+
+
+10   ATTRIBUTE_DEVICE_INFO
+
+     This attribute includes information about the user's device.
+     The encoding of this attribute is as follows:
+
+     Length       Type       Value
+     4 bytes      integer    Device type
+     variable     string     Name of the device manufacturer
+     variable     string     Device version
+     variable     string     Device model
+     variable     string     Device language (ISO 639-2/T)
+
+     The following Device types are defined:
+
+     0    DEVICE_COMPUTER        Device is a computer
+     1    DEVICE_MOBILE_PHONE    Device is a mobile phone
+     2    DEVICE_PDA             Device is a PDA
+     3    DEVICE_TERMINAL        Device is a terminal
+
+
+11   ATTRIBUTE_EXTENSION
+
+     This attribute indicates that the attribute value is vendor,
+     application or service specific attribute extension.  This field
+     MUST include a MIME object, which is the extension value.  This
+     document does not specify any explicit MIME objects for this
+     attribute.
+
+     Length       Type       Value
+     variable     MIME       Attribute extension as MIME object
+
+
+12   ATTRIBUTE_USER_PUBLIC_KEY
+
+     This attribute includes the user's public key or certificate.
+     As the public key and certificate format depends on which sort
+     of algorithm or certificate encoding user is using we need to
+     define a mechanism to differentiate the public key types from
+     each other.  This document specifies the most common public keys
+     and certificates.  This attribute can be used to deliver the
+     user's public key, and it MUST be present if also the
+     ATTRIBUTE_USER_DIGITAL_SIGNATURE is present.  Note that the
+     recipient of this attribute SHOULD verify the public key from
+     a third party, for example from Certification Authority.  If
+     there are more than one ATTRIBUTE_USER_PUBLIC_KEY attributes set
+     and ATTRIBUTE_USER_DIGITAL_SIGNATURE is also set, the digital
+     signature SHOULD be verifiable with the first set public key.
+
+     Length       Type       Value
+     variable     string     Public key/certificate type
+     variable     data       Public key/certificate data
+
+     The following public key/certificate types are defined:
+
+     ssh-rsa           SSH RSA public key [SSH-TRANS]
+     ssh-dss           SSH DSS public key [SSH-TRANS]
+     silc-rsa          SILC RSA public key [SILC1]
+     silc-dss          SILC DSS public key [SILC1]
+     pgp-sign-rsa      OpenPGP RSA certificate [RFC2440]
+     pgp-sign-dss      OpenPGP DSS certificate [RFC2440]
+     x509v3-sign-rsa   X.509 Version 3 RSA certificate [RFC2459]
+     x509v3-sign-dss   X.509 Version 3 DSS certificate [RFC2459]
+
+     Most of these public key/certificate types are equivalent to
+     the types specified for SSH protocol [SSH-TRANS] and are expected
+     to be officially assigned by IANA.
+
+     The encoding of the public key/certificate data in the attribute
+     is done in the manner defined in their respective definitions.
+
+     Note that these public keys are intended for signing.  Some
+     certificates may have a key usage restrictions and same key cannot
+     be used for both encryption and signing.  Therefore, the name
+     of the certificate type indicates if they are intended for 
+     signing only.
+
+
+13   ATTRIBUTE_SERVER_PUBLIC_KEY
+
+     This attribute includes a third party server or authority public
+     key or CA certificate and MUST be present if the attribute
+     ATTRIBUTE_SERVER_DIGITAL_SIGNATURE is also present.  The format
+     for this attribute is identical to the ATTRIBUTE_USER_PUBLIC_KEY 
+     attribute.  If there are more than one ATTRIBUTE_SERVER_PUBLIC_KEY
+     attributes set and ATTRIBUTE_SERVER_DIGITAL_SIGNATURE is also set,
+     the digital signature SHOULD be verifiable with the first set public
+     key.
+
+
+14   ATTRIBUTE_USER_DIGITAL_SIGNATURE
+
+     This attribute value includes digital signature of all Attribute
+     Payloads except this attribute.  This signature can be provided by
+     the user.  This attribute SHOULD be last attribute provided in the 
+     reply so that it is easier for the receiver to compute the signature 
+     data to be verified.  The format and encoding of this attribute
+     depends on the public key or certificate used to produce the
+     signature.  See the ATTRIBUTE_USER_PUBLIC_KEY for all public keys
+     and certificates that can be used to produce a signature.
+
+     Length       Type       Value
+     variable     data       Digital signature data
+
+     The encodings are as follows per public key/certificate type:
+
+     ssh-rsa and ssh-dss                   Defined in [SSH-TRANS]
+     silc-rsa and silc-dss                 Defined in [SILC1]
+     pgp-sign-rsa and pgp-sign-dss         Defined in [RFC2440]
+     x509v3-sign-rsa and x509v3-sign-dss   Defined in [PKCS7]
+
+     The procedure producing the signature and encoding it are done
+     in the manner defined in their respective definitions, see the
+     provided references.  Also the hash function used with the
+     signature procedure is defined by the public key/certificate type.
+
+
+15   ATTRIBUTE_SERVER_DIGITAL_SIGNATURE
+
+     This attribute value includes digital signature of all Attribute
+     Payloads except this attribute, but including the attribute
+     ATTRIBUTE_USER_DIGITAL_SIGNATURE.  This signature can be provided
+     by a third party server or an authority which has verified the
+     information provided by the user.  How it verifies this information
+     is out of scope of this document, however it may base its
+     information to a previous registration information and current
+     online status of the user in a service.  This attribute SHOULD be 
+     last when provided, so that it is easier for the receiver to
+     compute the signature data to be verified.  The format for this
+     attribute is identical to the ATTRIBUTE_USER_DIGITAL_SIGNATURE
+     attribute.
+.in 3
+
+
+.ti 0
+3 Security Considerations
+
+The use of these attributes dictates whether the attributes need to
+be secured or not.  However, as the attributes are considered to provide
+accurate status information about specific user, it is suggested that
+the attributes would be secured.  The attributes should be digitally
+signed whenever it is possible.  Attributes can also be encrypted
+if it is provided by the protocol using the attributes.  A third party,
+like a server in the network, could also verify the information and provide
+digital signature in case the information is accurate.
+
+Even though the attributes would be digitally signed by the sender of
+the attributes, the information contained in the attribute may still
+be incorrect.  The third party server should not apply digital signature
+unless it can verify every attribute.  The receiver of the attributes
+should also not trust that the information in fact is correct.
+
+However, it is possible that the context where these attributes are used
+the attributes are provided by a party that can provide the accurate
+information.  For example a server in the network could reply to the
+attributes on behalf of the actual user for some of the attributes.
+
+
+.ti 0
+4 References 
+
+[RFC2119]    Bradner, S., "Key Words for use in RFCs to Indicate
+             Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+[RFC2279]    Yergeau, F., "UTF-8, a transformation format of ISO
+             10646", RFC 2279, January 1998.
+
+[RFC2425]    Howes, T., et al, "A MIME Content-Type for Directory
+             Information", RFC 2425, September 1998.
+
+[RFC2426]    Dawson, F., et al, "vCard MIME Directory Profile",
+             RFC 2426, September 1998.
+
+[SILC1]      Riikonen, P., "Secure Internet Live Conferencing (SILC),
+             Protocol Specification", Internet Draft, May 2002.
+
+[RFC2440]    Callas, J., et al, "OpenPGP Message Format", RFC 2440,
+             November 1998.
+
+[RFC2459]    Housley, R., et al, "Internet X.509 Public Key 
+             Infrastructure, Certificate and CRL Profile", RFC 2459,
+             January 1999.
+
+[SSH-TRANS]  Ylonen, T., et al, "SSH Transport Layer Protocol", 
+             Internet Draft.
+
+[PKCS7]      Kalinski, B., "PKCS #7: Cryptographic Message Syntax,
+             Version 1.5", RFC 2315, March 1998.
+
+
+
+
+.ti 0
+5 Author's Address
+
+Pekka Riikonen
+Snellmaninkatu 34 A 15
+70100 Kuopio
+Finland
+
+EMail: priikone@iki.fi
+
+
+.ti 0
+6 Full Copyright Statement
+
+Copyright (C) The Internet Society (2003). All Rights Reserved.
+
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
diff --git a/doc/draft-riikonen-silc-commands-05.nroff b/doc/draft-riikonen-silc-commands-05.nroff
new file mode 100644 (file)
index 0000000..c132151
--- /dev/null
@@ -0,0 +1,2598 @@
+.pl 10.0i
+.po 0
+.ll 7.2i
+.lt 7.2i
+.nr LL 7.2i
+.nr LT 7.2i
+.ds LF Riikonen
+.ds RF FORMFEED[Page %]
+.ds CF
+.ds LH Internet Draft
+.ds RH 27 June 2003
+.ds CH
+.na
+.hy 0
+.in 0
+.nf
+Network Working Group                                        P. Riikonen
+Internet-Draft
+draft-riikonen-silc-commands-05.txt                         27 June 2003
+Expires: 27 December 2003
+
+.in 3
+
+.ce 2
+SILC Commands
+<draft-riikonen-silc-commands-05.txt>
+
+.ti 0
+Status of this Memo
+
+This document is an Internet-Draft and is in full conformance with
+all provisions of Section 10 of RFC 2026.  Internet-Drafts are
+working documents of the Internet Engineering Task Force (IETF), its
+areas, and its working groups.  Note that other groups may also
+distribute working documents as Internet-Drafts.
+
+Internet-Drafts are draft documents valid for a maximum of six months
+and may be updated, replaced, or obsoleted by other documents at any
+time.  It is inappropriate to use Internet-Drafts as reference
+material or to cite them other than as "work in progress."
+
+The list of current Internet-Drafts can be accessed at
+http://www.ietf.org/ietf/1id-abstracts.txt
+
+The list of Internet-Draft Shadow Directories can be accessed at
+http://www.ietf.org/shadow.html
+
+The distribution of this memo is unlimited.
+
+
+.ti 0
+Abstract
+
+This memo describes the commands used in the Secure Internet Live
+Conferencing (SILC) protocol, specified in the Secure Internet Live
+Conferencing, Protocol Specification [SILC1].  The SILC Commands are
+very important part of the SILC protocol.  Usually the commands are used
+by SILC clients to manage the SILC session, but also SILC servers may
+use the commands.  This memo specifies detailed command messages and
+command reply messages.
+
+
+
+
+
+
+
+
+.ti 0
+Table of Contents
+
+.nf
+1 Introduction ..................................................  2
+  1.1 Requirements Terminology ..................................  2
+2 SILC Commands .................................................  2
+  2.1 SILC Commands Syntax ......................................  4
+  2.2 SILC Command Argument Idioms ..............................  4
+  2.3 SILC Commands List ........................................  5
+  2.4 SILC Command Status Payload ............................... 42
+3 SILC Status Types ............................................. 43
+4 Security Considerations ....................................... 50
+5 References .................................................... 50
+6 Author's Address .............................................. 51
+Appendix A ...................................................... 51
+Full Copyright Statement ........................................ 53
+
+
+.ti 0
+1. Introduction
+
+This document describes the commands used in the Secure Internet Live
+Conferencing (SILC) protocol, specified in the Secure Internet Live
+Conferencing, Protocol Specification [SILC1].  This document specifies
+detailed command messages and command reply messages.
+
+Commands are very important part on SILC network especially for client
+which uses commands to operate on the SILC network.  Commands are used
+to set nickname, join to channel, change modes and many other things.
+
+See the [SILC1] for the requirements and the restrictions for the usage
+of the SILC commands.  The [SILC2] defines the command packet type and
+the Command Payload which is actually used to deliver the commands and
+command reply messages.
+
+
+.ti 0
+1.1 Requirements Terminology
+
+The keywords MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, RECOMMENDED,
+MAY, and OPTIONAL, when they appear in this document, are to be
+interpreted as described in [RFC2119].
+
+
+.ti 0
+2 SILC Commands
+
+.ti 0
+2.1 SILC Commands Syntax
+
+This section briefly describes the syntax of the command notions
+in this document.  Every field in command is separated from each
+other by whitespaces (` ') indicating that each field is independent
+argument and each argument MUST have own Command Argument Payload.
+The number of maximum arguments are defined with each command
+separately.  The Command Argument Payload is described in [SILC2].
+
+Every command defines specific number for each argument.  Currently,
+they are defined in ascending order; first argument has number one
+(1), second has number two (2) and so on.  This number is set into the
+Argument Type field in the Command Argument Payload.  This makes it
+possible to send the arguments in free order as the number MUST be
+used to identify the type of the argument.  This makes is it also
+possible to have multiple optional arguments in commands and in
+command replies.  The number of argument is marked in parentheses
+before the actual argument.
+
+
+
+.in 6
+Example:  Arguments:  (1) <nickname> (2) <username@host>
+.in 3
+
+
+Every command replies with Status Payload.  This payload tells the
+sender of the command whether the command was completed successfully or
+whether there was an error.  If error occurred the payload includes the
+error type.  In the next section the Status Payload is not described
+as it is common to all commands and has been described here.  Commands
+MAY reply with other arguments as well.  These arguments are command
+specific and are described in the next section.
+
+Example command:
+.in 6
+
+EXAMPLE_COMMAND
+
+.in 8
+Max Arguments:  3
+    Arguments:  (1) <nickname>[@<server>]  (2) <message>
+                (3) [<count>]
+
+The command has maximum of 3 arguments.  However, only first
+and second arguments are mandatory.
+
+First argument <nickname> is mandatory but may have optional
+<nickname@server> format as well.  Second argument is mandatory
+<message> argument.  Third argument is optional <count> argument.
+
+The numbers in parentheses are the argument specific numbers
+that specify the type of the argument in Command Argument Payload.
+The receiver always knows that, say, argument number two (2) is
+<message> argument, regardless of the ordering of the arguments in
+the Command Payload.
+
+Reply messages to the command:
+
+Max Arguments:  4
+    Arguments:  (1) <Status Payload>  (2) [<channel list>]
+                (3) <idle time>       (4) [<away message>]
+
+This command may reply with maximum of 4 arguments.  However,
+only the first and third arguments are mandatory.  The numbers
+in the parentheses have the same meaning as in the upper
+command sending specification.
+
+Every command reply with <Status Payload>, it is mandatory
+argument for all command replies and for this reason it is not
+described in the command reply descriptions.
+
+
+
+Status messages:
+
+    SILC_STATUS_OK
+    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+    SILC_STATUS_ERR_NO_SUCH_NICK
+
+Every command reply also defines set of status message that it
+may return inside the <Status Payload>.  All status messages
+are defined in the section 2.3 SILC Command Status Payload
+The status messages defined with the command are recommendations.
+It is possible to return other status messages not listed with
+the command reply definition.
+.in 3
+
+
+.ti 0
+2.2 SILC Command Argument Idioms
+
+All commands that has an ID as argument (for example <Client ID>) are
+actually ID Payloads, defined in [SILC2] that includes the type of the
+ID, length of the ID and the actual ID data.  This way variable length
+ID's can be sent as arguments.
+
+All passphrases that may be sent in commands as arguments MUST be
+UTF-8 [RFC2279] encoded.
+
+All public keys and certificates that are sent as arguments are actually
+Public Key Payloads [SILC2].  This way it is possible to send different
+kind of public keys and certificate types as arguments.
+
+
+
+
+.ti 0
+2.3 SILC Commands List
+
+This section lists all SILC commands, however, it is expected that a
+implementation and especially client implementation has many more
+commands that has only local affect.  These commands are official
+SILC commands that has both client and server sides and cannot be
+characterized as local commands.
+
+List of all defined commands in SILC follows.
+
+.in 0
+   0    SILC_COMMAND_NONE
+
+        None.  This is reserved command and MUST NOT be sent.
+
+
+   1    SILC_COMMAND_WHOIS
+
+        Max Arguments:  256
+            Arguments:  (1) [<nickname>[@<server>]]   (2) [<count>]
+                        (3) [<Requested Attributes>]  (4) [<Client ID>]
+                        (n) [...]
+
+        Whois command is used to query various information about specific
+        user.  The user may be requested by their nickname and server name.
+        The query may find multiple matching users as there are no unique
+        nicknames in the SILC.  The <count> option may be given to narrow
+        down the number of accepted results.  If this is not defined there
+        are no limit of accepted results.  The query may also be narrowed
+        down by defining the server name of the nickname.  The <count> is
+        32 bit MSB first order integer.
+
+        It is also possible to search the user by Client ID.  If the
+        <Client ID> is provided server MUST use it as the search value
+        instead of the <nickname>.  One of the arguments MUST be given.
+        It is also possible to define multiple Client ID's to search
+        multiple users sending only one WHOIS command.  In this case the
+        Client ID's are appended as normal arguments.
+
+        To prevent miss-use of this command wildcards in the nickname
+        or in the server name are not permitted.  It is not allowed
+        to request all users on some server.  The WHOIS requests MUST
+        be based on explicit nickname request.
+
+        The WHOIS request MUST be always sent to the router by server
+        so that all users are searched.  However, the server still MUST
+        search its locally connected clients.  The router MUST send
+        this command to the server which owns the requested client, if
+        the router is unable to provide all mandatory information about
+        the client.  That server MUST reply to the command.  Server MUST
+        NOT send whois replies to the client until it has received the
+        reply from its router.
+
+        The <Requested Attributes> is defined in [ATTRS] and can be used
+        to request various information about the client.  See Appendix A
+        for definition of using these attributes in SILC.
+
+        Reply messages to the command:
+
+        Max Arguments:  11
+            Arguments:  (1) <Status Payload>       (2) <Client ID>
+                        (3) <nickname>[@<server>]  (4) <username@host>
+                        (5) <real name>            (6) [<Channel Payload
+                                                         list>]
+                        (7) [<user mode>]          (8) [<idle time>]
+                        (9) [<fingerprint>]        (10) <channel user
+                                                         mode list>
+                        (11) [<Attributes>]
+
+
+        This command may reply with several command reply messages to
+        form a list of results.  In this case the status payload will
+        include STATUS_LIST_START status in the first reply and
+        STATUS_LIST_END in the last reply to indicate the end of the
+        list.  If there are only one reply the status is set to normal
+        STATUS_OK.  If multiple Client IDs was requested then each found
+        and unfound client MUST cause successful or error reply,
+        respectively.
+
+        The command replies include the Client ID of the nickname,
+        nickname and server name, user name and host name and user's real
+        name.  Client should process these replies only after the last
+        reply has been received with the STATUS_LIST_END status.  If the
+        <count> option were defined in the query there will be only
+        <count> many replies from the server.
+
+        The server returns the list of channels if the client has
+        joined channels.  In this case the list is list of Channel
+        Payloads.  The Mode Mask in the Channel Payload is the channel's
+        mode.  The list is encoded by adding the Channel Payloads one
+        after the other.  Private and secret channels MUST NOT be sent,
+        except if the sender of this command is on those channels, or
+        the sender is server.  The <channel user mode list> MUST also
+        be sent if client is joined channels.  This list includes 32 bit
+        MSB first order values one after the other and each indicate
+        the user's mode on a channel.  The order of these values MUST
+        be same as the channel order in the <Channel Payload list>.
+
+        The server also returns client's user mode, idle time, and the
+        fingerprint of the client's public key.  The <fingerprint> is the
+        binary hash digest of the public key.  The fingerprint MUST NOT
+        be sent if the server has not verified the proof of possession of
+        the corresponding private key.  Server can do this during the
+        SILC Key Exchange protocol.  The <fingerprint> is SHA1 digest.
+
+        The <Attributes> is the reply to the <Requested Attributes>.
+        See the Appendix A for more information.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_LIST_START
+            SILC_STATUS_LIST_END
+            SILC_STATUS_ERR_NO_SUCH_NICK
+            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+            SILC_STATUS_ERR_WILDCARDS
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+
+
+   2    SILC_COMMAND_WHOWAS
+
+        Max Arguments:  2
+            Arguments:  (1) <nickname>[@<server>]  (2) [<count>]
+
+        Whowas.  This command is used to query history information about
+        specific user.  The user may be requested by their nickname and
+        server name.  The query may find multiple matching users as there
+        are no unique nicknames in the SILC.  The <count> option may be
+        given to narrow down the number of accepted results.  If this
+        is not defined there are no limit of accepted results.  The query
+        may also be narrowed down by defining the server name of the
+        nickname.  The <count> is 32 bit MSB first order integer.
+
+        To prevent miss-use of this command wildcards in the nickname
+        or in the server name are not permitted.  The WHOWAS requests MUST
+        be based on specific nickname request.
+
+        The WHOWAS request MUST be always sent to the router by server
+        so that all users are searched.  However, the server still must
+        search its locally connected clients.
+
+        Reply messages to the command:
+
+        Max Arguments:  5
+            Arguments:  (1) <Status Payload>        (2) <Client ID>
+                        (3) <nickname>[@<server>]   (4) <username@host>
+                        (5) [<real name>]
+
+        This command may reply with several command reply messages to form
+        a list of results.  In this case the status payload will include
+        STATUS_LIST_START status in the first reply and STATUS_LIST_END in
+        the last reply to indicate the end of the list.  If there are only
+        one reply the status is set to normal STATUS_OK.
+
+        The command replies with nickname and user name and host name.
+        Every server MUST keep history for some period of time of its
+        locally connected clients.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_LIST_START
+            SILC_STATUS_LIST_END
+            SILC_STATUS_ERR_NO_SUCH_NICK
+            SILC_STATUS_ERR_WILDCARDS
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+
+
+   3    SILC_COMMAND_IDENTIFY
+
+        Max Arguments:  256
+            Arguments:  (1) [<nickname>[@<server>]]  (2) [<server name>]
+                        (3) [<channel name>]         (4) [<count>]
+                        (5) [<ID Payload>]           (n) [...]
+
+        Identify command is used to query information about an entity by
+        the entity's name or ID.  This command can be used to query
+        information about clients, servers and channels.
+
+        The query may find multiple matching entities.  The <count> option
+        may be given to narrow down the number of accepted results.  If
+        this is not defined there are no limit of accepted results.  The
+        <count> is 32 bit MSB first order integer.
+
+        It is also possible to search the entity by its ID.  If the
+        <ID Payload> is provided server must use it as the search value
+        instead of the entity's name.  One of the arguments MUST be given.
+        It is also possible to define multiple ID Payloads to search
+        multiple entities sending only one IDENTIFY command.  In this case
+        the ID Payloads are appended as normal arguments.  The type of the
+        entity is defined by the type of the ID Payload.
+
+        To prevent miss-use of this command wildcards in the names are
+        not permitted.  It is not allowed to request for example all users
+        on server.
+
+        Implementations may not want to give interface access to this
+        command as it is hardly a command that would be used by an end
+        user.  However, it must be implemented as it is most likely used
+        with private message sending.
+
+        The IDENTIFY command MUST be always sent to the router by server
+        so that all users are searched.  However, server MUST still search
+        its locally connected clients.
+
+        Reply messages to the command:
+
+        Max Arguments:  4
+            Arguments:  (1) <Status Payload>   (2) <ID Payload>
+                        (3) [<entity's name>]  (4) [<info>]
+
+        This command may reply with several command reply messages to form
+        a list of results.  In this case the status payload will include
+        STATUS_LIST_START status in the first reply and STATUS_LIST_END in
+        the last reply to indicate the end of the list.  If there are only
+        one reply the status is set to normal STATUS_OK.  If multiple Client
+        IDs was requested then each found and unfound client must cause
+        successful or error reply, respectively.
+
+        When querying clients the <entity's name> must include the client's
+        nickname in the following format: nickname[@server].  The
+        <info> must include the client's username and host in the following
+        format: username@host.
+
+        When querying servers the <entity's name> must include the server's
+        full name.  The <info> may be omitted.
+
+        When querying channels the <entity's name> must include the
+        channel's name.  The <info> may be omitted.
+
+        If the <count> option were defined in the query there will be only
+        <count> many replies from the server.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_LIST_START
+            SILC_STATUS_LIST_END
+            SILC_STATUS_ERR_NO_SUCH_NICK
+            SILC_STATUS_ERR_NO_SUCH_SERVER
+            SILC_STATUS_ERR_NO_SUCH_CHANNEL
+            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+            SILC_STATUS_ERR_NO_SUCH_SERVER_ID
+            SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+            SILC_STATUS_ERR_WILDCARDS
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+
+
+   4    SILC_COMMAND_NICK
+
+        Max Arguments:  1
+            Arguments:  (1) <nickname>
+
+        Set/change nickname.  This command is used to set nickname for
+        user.  Nickname MUST NOT include any whitespaces (` '),
+        non-printable characters, commas (`,'), '@', '!' or any wildcard
+        characters.
+
+        When nickname is changed new Client ID is generated.  Server MUST
+        distribute SILC_NOTIFY_TYPE_NICK_CHANGE to local clients on the
+        channels (if any) the client is joined on.  Then it MUST send
+        SILC_NOTIFY_TYPE_NICK_CHANGE notify to its primary route to
+        notify about nickname and Client ID change.
+
+        Reply messages to the command:
+
+        Max Arguments:  3
+            Arguments:  (1) <Status Payload>  (2) <New ID Payload>
+                        (3) <nickname>
+
+        This command replies always with <New ID Payload> that is
+        generated by the server every time user changes their nickname.
+        Client receiving this payload MUST start using the received
+        Client ID as its current valid Client ID.  The New ID Payload
+        is described in [SILC2].  The <nickname> is the user's new
+        nickname.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_WILDCARDS
+            SILC_STATUS_ERR_NICKNAME_IN_USE
+            SILC_STATUS_ERR_BAD_NICKNAME
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+
+
+   5    SILC_COMMAND_LIST
+
+        Max Arguments:  1
+            Arguments:  (1) [<Channel ID>]
+
+        The list command is used to list channels and their topics on the
+        current server.  If the <Channel ID> parameter is used, only the
+        status of that channel is displayed.  Secret channels are not
+        listed at all.  Private channels are listed with status indicating
+        that the channel is private.  Router MAY reply with all channels
+        it knows about.
+
+        Reply messages to the command:
+
+        Max Arguments:  5
+            Arguments:  (1) <Status Payload>  (2) <Channel ID>
+                        (3) <channel>         (4) [<topic>]
+                        (5) [<user count>]
+
+        This command may reply with several command reply messages to form
+        a list of results.  In this case the status payload will include
+        STATUS_LIST_START status in the first reply and STATUS_LIST_END in
+        the last reply to indicate the end of the list.  If there are only
+        one reply the status is set to normal STATUS_OK.
+
+        This command replies with Channel ID, name and the topic of the
+        channel.  If the channel is private channel the <topic> SHOULD
+        include the "*private*" string.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_LIST_START
+            SILC_STATUS_LIST_END
+            SILC_STATUS_ERR_WILDCARDS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+            SILC_STATUS_ERR_NO_CHANNEL_ID
+            SILC_STATUS_ERR_NO_SUCH_SERVER
+
+
+   6    SILC_COMMAND_TOPIC
+
+        Max Arguments:  2
+            Arguments:  (1) <Channel ID>  (2) [<topic>]
+
+        This command is used to change or view the topic of a channel.
+        The topic for channel <Channel ID> is returned if there is no
+        <topic> given.  If the <topic> parameter is present, the topic
+        for that channel will be changed, if the channel modes permit
+        this action.
+
+        After setting the topic the server MUST send the notify type
+        SILC_NOTIFY_TYPE_TOPIC_SET to its primary router and then to
+        the channel which topic was changed.
+
+        Reply messages to the command:
+
+        Max Arguments:  2
+            Arguments:  (1) <Status Payload>  (2) <Channel ID>
+                        (3) [<topic>]
+
+        The command may reply with the topic of the channel if it is
+        set.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_ON_CHANNEL
+            SILC_STATUS_ERR_WILDCARDS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_NO_SUCH_CHANNEL
+            SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+            SILC_STATUS_ERR_NO_CHANNEL_ID
+            SILC_STATUS_ERR_BAD_CHANNEL_ID
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NO_CHANNEL_PRIV
+
+
+   7    SILC_COMMAND_INVITE
+
+        Max Arguments:  4
+            Arguments:  (1) <Channel ID>       (2) [<Client ID>]
+                        (3) [<add | del>]      (4) [<invite list>]
+
+        This command can be used to invite other clients to join to a
+        channel, and to manage the channel's invite list.  The <Client
+        ID> argument is the target client's ID that is being invited.
+        The <Channel ID> is the Channel ID of the requested channel.
+        The sender of this command MUST be on the channel.  The server
+        MUST also send the notify type SILC_NOTIFY_TYPE_INVITE to its
+        primary router and then to the client indicated by the <Client
+        ID>.
+
+        The <add | del> is an argument of size of 1 byte where 0x00 means
+        adding a client to invite list, and 0x01 means deleting a client
+        from invite list.  The <invite list>, if present, indicates
+        the information to be added to or removed from the invite list.
+        It may include a string for matching clients, public key of a
+        client or Client ID of a client.  The <invite list> is an
+        Argument List Payload.
+
+        The following Argument Types has been defined for invite list
+        Argument Payloads:
+
+          0x01 - Argument is an invite string of following format:
+
+            [<nickname>[@<server>]!][<username>]@[<hostname or IP/MASK>]
+
+            The <hostname> may also be in format of IP/MASK to indicate
+            a network, for example 10.2.1.0/255.255.0.0.
+
+          0x02 - Argument is the public key of a client
+          0x03 - Argument is the Client ID of a client
+
+        If unknown type value is received or there is invalid amount of
+        Argument Payloads present in the list, the command MUST be
+        discarded.  When argument that is to be deleted from the invite
+        list does not exist in the list the argument is ignored.
+
+        When adding to or removing from the invite list the server MUST
+        send the notify type SILC_NOTIFY_TYPE_INVITE to its primary router.
+        The client which executes this command MUST have at least channel
+        operator privileges to be able to add to or remove from the invite
+        list.  The wildcards MAY be used with this command.  When this
+        command is used to invite explicit client with <Client ID> the
+        ID MUST be added to the invite list by the server.
+
+        When this command is given with only <Channel ID> argument then
+        the command merely returns the invite list of the channel.   This
+        command MUST fail if the requested channel does not exist, the
+        requested <Client ID> is already on the channel or if the channel
+        is invite only channel and the caller of this command does not
+        have at least channel operator privileges on the channel.
+
+        Reply messages to the command:
+
+        Max Arguments:  3
+            Arguments:  (1) <Status Payload>  (2) <Channel ID>
+                        (3) [<invite list>]
+
+       This command replies with the invite list of the channel if it
+       exists.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+            SILC_STATUS_ERR_NO_CLIENT_ID
+            SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+            SILC_STATUS_ERR_NO_CHANNEL_ID
+            SILC_STATUS_ERR_NOT_ON_CHANNEL
+            SILC_STATUS_ERR_USER_ON_CHANNEL
+            SILC_STATUS_ERR_NO_CHANNEL_PRIV
+            SILC_STATUS_ERR_RESOURCE_LIMIT
+
+
+   8    SILC_COMMAND_QUIT
+
+        Max Arguments:  1
+            Arguments:  (1) [<quit message>]
+
+        This command is used by client to end SILC session.  The server
+        must close the connection to a client which sends this command.
+        if <quit message> is given it will be sent to other clients on
+        channel if the client is on channel when quitting.
+
+        Reply messages to the command:
+
+        This command does not reply anything.
+
+
+    9   SILC_COMMAND_KILL
+
+        Max Arguments:  3
+            Arguments:  (1) <Client ID>          (2) [<comment>]
+                        (3) [<auth payload>]
+
+        This command can be used by SILC operators to remove a client from
+        SILC network.  It also can be used by a normal client to remove
+        its own client from network by providing correct authentication
+        data.
+
+        Router operator killing a client:
+
+        The removing has temporary effects and client may reconnect to
+        SILC network.  The <Client ID> is the client to be removed from SILC.
+        The <comment> argument may be provided to give to the removed client
+        some information why it was removed from the network.  The killer
+        MUST have SILC operator privileges.
+
+        When killing a client the router MUST first send notify type
+        SILC_NOTIFY_TYPE_KILLED to all channels the client has joined.
+        The packet MUST NOT be sent to the killed client on the channels.
+        Then, the router MUST send the same notify type to its primary
+        router.  Finally, the router MUST send the same notify type
+        destined directly to the client which was killed.  The killed
+        client MUST also be removed from the invite lists of joined
+        channels if it is explicitly added in the invite lists.
+
+        Normal client killing by authentication:
+
+        When normal client executes this command the <Client ID> is the
+        destination client to be removed from the network.  The client
+        MUST provide the <auth payload> which includes a digital signature
+        that MUST be verified with the public key of the client indicated
+        by <Client ID>.  The <Client ID> MUST be local client to the server.
+        If the signature verification is successful the server sends
+        SILC_NOTIFY_TYPE_SIGNOFF to network and to the destination client.
+        The SILC_NOTIFY_TYPE_KILLED MUST NOT be used in this case.  If the
+        verification fails the destination client remains in network.
+        The hash function used in <auth payload> computing is SHA1.
+
+        Reply messages to the command:
+
+        Max Arguments:  1
+            Arguments:  (1) <Status Payload>
+
+        This command replies only with Status Payload.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_WILDCARDS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+            SILC_STATUS_ERR_NO_CLIENT_ID
+            SILC_STATUS_ERR_NO_ROUTER_PRIV
+
+
+   10   SILC_COMMAND_INFO
+
+        Max Arguments:  2
+            Arguments:  (1) [<server>]  (2) [<Server ID>]
+
+        This command is used to fetch various information about a server.
+        If <server> argument is specified the command MUST be sent to
+        the requested server.
+
+        If the <Server ID> is specified the server information if fetched
+        by the provided Server ID.  One of the arguments MUST always be
+        present.
+
+        Reply messages to the command:
+
+        Max Arguments:  4
+            Arguments:  (1) <Status Payload>  (2) <Server ID>
+                        (3) <server name>     (4) <string>
+
+        This command replies with the Server ID of the server and a
+        string which tells the information about the server.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_WILDCARDS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NO_SUCH_SERVER
+            SILC_STATUS_ERR_NO_SUCH_SERVER_ID
+            SILC_STATUS_ERR_NO_SERVER_ID
+
+
+   11   SILC_COMMAND_STATS
+
+        Max Arguments:  1
+            Arguments:  (1) <Server ID>
+
+        This command is used to fetch various statistical information
+        from the server indicated by <Server ID>, which is the ID of
+        server where sender is connected to.  Server receiving this
+        command MAY also send this further to its router for fetching
+        other cell and network wide statistics to accompany the reply.
+
+        Reply messages to the command:
+
+        Max Arguments:  3
+            Arguments:  (1) <Status Payload>          (2) <Server ID>
+                        (3) [<statistics structure>]
+
+        This command replies with the Server ID of the server and
+        optional statistics structure which includes 32 bit MSB first
+        ordered integer values to represent various statistical
+        information.  The structure is as follows:
+
+          starttime      - time when server was started
+          uptime         - uptime of the server
+          my clients     - number of locally connected clients
+          my channels    - number of locally created channels
+          my server ops  - number of local server operators
+          my router ops  - number of local router operators
+          cell clients   - number of clients in local cell
+          cell channels  - number of channels in local cell
+          cell servers   - number of servers in local cell
+          clients        - number of client in SILC network
+          channels       - number of channels in SILC network
+          servers        - number of servers in SILC network
+          routers        - number of routers in SILC network
+          server ops     - number of server operators in SILC network
+          router ops     - number of router operators in SILC network
+
+        If some value is unknown it is set to zero (0) value.  The
+        "starttime" is the start time of the server, and is seconds
+        since Epoch (POSIX.1).  The "uptime" is time difference of
+        current time and "starttime" in the server, and is seconds
+        in value.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NO_SUCH_SERVER_ID
+            SILC_STATUS_ERR_NO_SUCH_SERVER
+            SILC_STATUS_ERR_NO_SERVER_ID
+
+
+   12   SILC_COMMAND_PING
+
+        Max Arguments:  1
+            Arguments:  (1) <Server ID>
+
+        This command is used by client and server to test the communication
+        channel to its server if one suspects that the communication is not
+        working correctly.  The <Server ID> is the ID of the server the
+        sender is connected to.
+
+        Reply messages to the command:
+
+        Max Arguments:  1
+            Arguments:  (1) <Status Payload>
+
+        This command replies only with Status Payload.  Server returns
+        SILC_STATUS_OK in Status Payload if pinging was successful.
+
+
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NO_SERVER_ID
+            SILC_STATUS_ERR_NO_SUCH_SERVER
+            SILC_STATUS_ERR_NOT_REGISTERED
+
+
+   13   SILC_COMMAND_OPER
+
+        Max Arguments:  2
+            Arguments:  (1) <username>  (2) <authentication payload>
+
+        This command is used by normal client to obtain server operator
+        privileges on some server or router.  Note that router operator
+        has router privileges that supersedes the server operator
+        privileges and this does not obtain those privileges.  Client
+        MUST use SILCOPER command to obtain router level privileges.
+
+        The <username> is the username set in the server configurations
+        as operator.  The <authentication payload> is the data that the
+        client is authenticated against.  It may be passphrase prompted
+        for user on client's screen or it may be public key authentication
+        based on digital signatures.  The public key used to verify the
+        signature should be locally saved in the server, and server should
+        not use public key received during the SKE to verify this signature.
+
+        After changing the mode the server MUST send the notify type
+        SILC_NOTIFY_TYPE_UMODE_CHANGE to its primary router.
+
+        Reply messages to the command:
+
+        Max Arguments:  1
+            Arguments:  (1) <Status Payload>
+
+        This command replies only with Status Payload.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_AUTH_FAILED
+
+
+   14   SILC_COMMAND_JOIN
+
+        Max Arguments:  7
+            Arguments:  (1) <channel>         (2) <Client ID>
+                        (3) [<passphrase>]    (4) [<cipher>]
+                        (5) [<hmac>]          (6) [<founder auth>]
+                        (7) [<channel auth>]
+
+        Join to channel/create new channel.  This command is used to
+        join to a channel.  If the channel does not exist the channel is
+        created.  If server is normal server this command MUST be sent
+        to router which will create the channel.  The channel MAY be
+        protected with passphrase.  If this is the case the passphrase
+        MUST be sent along the join command.
+
+        The name of the <channel> MUST NOT include any spaces (` '),
+        non-printable characters, commas (`,') or any wildcard characters.
+
+        The second argument <Client ID> is the Client ID of the client
+        which is joining to the client.  When client sends this command
+        to the server the <Client ID> MUST be the client's own ID.
+
+        Cipher to be used to secure the traffic on the channel MAY be
+        requested by sending the name of the requested <cipher>.  This
+        is used only if the channel does not exist and is created.  If
+        the channel already exists the cipher set previously for the
+        channel will be used to secure the traffic.  The computed MACs
+        of the channel message are produced by the default HMAC or by
+        the <hmac> provided for the command.
+
+        The <founder auth> is Authentication Payload providing the
+        authentication for gaining founder privileges on the channel
+        when joining the channel.  The client may provide this if it
+        knows that it is the founder of the channel and that the
+        SILC_CMODE_FOUNDER_AUTH mode is set on the channel.  The server
+        MUST verify whether the client is able to gain the founder
+        privileges the same way as the client had given the
+        SILC_COMMAND_CUMODE command to gain founder privileges.  The
+        client is still able to join the channel even if the founder
+        privileges could not be gained.  The hash function used with
+        the <founder payload> MUST be sha1.
+
+        If the <channel auth> is present and the channel mode
+        SILC_CMODE_CHANNEL_AUTH is set the server MUST verify the
+        <channel auth> with channel public key(s).  If public key that
+        can verify <channel auth> does not exist on the channel public
+        key list the client MUST NOT be allowed to join the channel.
+        Because more than one public key may be set on channel the
+        <channel auth> Authentication Payload's Public Data field
+        MUST include an indication of the public key to be used.  The
+        first 20 bytes of the Public Data field MUST be SHA-1 digest of
+        the public key that must be used in verification.  Rest of the
+        Public Data field are set as defined in [SILC1].  This way server
+        can determine from the digest whether that public key exist on the
+        channel and then use that key in verification.  The hash function
+        used with <channel auth> MUST be sha1.
+
+        The server MUST check whether the user is allowed to join to
+        the requested channel.  Various modes set to the channel affect
+        the ability of the user to join the channel.  These conditions
+        are:
+
+            o  The user MUST be invited to the channel if the channel
+               is invite-only channel.
+
+            o  The Client ID/nickname/username/host name/public key
+               MUST NOT match any active bans.
+
+            o  The correct passphrase MUST be provided if passphrase
+               is set to the channel, and/or digital signature verification
+               with channel public key MUST be successful if public keys
+               has been set to the channel.
+
+            o  The user count limit, if set, MUST NOT be reached.
+
+        If the client provided correct <founder auth> payload it can
+        override these conditions, except the condition for the passphrase.
+        The correct passphrase MUST be provided even if <founder auth>
+        payload is provided.
+
+        Reply messages to the command:
+
+        Max Arguments:  15
+            Arguments:  (1) <Status Payload>        (2) <channel>
+                        (3) <Channel ID>            (4) <Client ID>
+                        (5) <channel mode mask>     (6) <created>
+                        (7) [<Channel Key Payload>] (8) [<ban list>]
+                        (9) [<invite list>]         (10) [<topic>]
+                        (11) [<hmac>]               (12) <list count>
+                        (13) <Client ID list>       (14) <client mode list>
+                        (15) [<founder pubkey>]
+
+        This command replies with the channel name requested by the
+        client, channel ID of the channel and topic of the channel
+        if it exists.  The <Client ID> is the Client ID which was joined
+        to the channel.  It also replies with the channel mode mask
+        which tells all the modes set on the channel.  If the channel
+        is created the mode mask is zero (0) and <created> is 0x01.
+        If ban mask and/or invite list is set they are sent as well.
+
+        The <list count>, <Client ID list> and <client mode list> are
+        the clients currently on the channel and their modes on the
+        channel.  The <Client ID list> is formed by adding the ID Payloads
+        one after the other.  The <client mode list> is formed by adding
+        32 bit MSB first order values one after the other.  The <founder
+        pubkey> is the public key (or certificate) of the channel founder.
+
+        Client receives the channel key in the reply message as well
+        inside <Channel Key Payload>.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_WILDCARDS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_BAD_PASSWORD
+            SILC_STATUS_ERR_CHANNEL_IS_FULL
+            SILC_STATUS_ERR_NOT_INVITED
+            SILC_STATUS_ERR_BANNED_FROM_CHANNEL
+            SILC_STATUS_ERR_BAD_CHANNEL
+            SILC_STATUS_ERR_USER_ON_CHANNEL
+
+
+   15   SILC_COMMAND_MOTD
+
+        Max Arguments:  1
+            Arguments:  (1) <server>
+
+        This command is used to query the Message of the Day of the server.
+
+        Reply messages to the command:
+
+        Max Arguments:  3
+            Arguments:  (1) <Status Payload>  (2) <Server ID>
+                        (3) [<motd>]
+
+        This command replies with the motd message if it exists.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NO_SUCH_SERVER
+
+
+   16   SILC_COMMAND_UMODE
+
+        Max Arguments:  2
+            Arguments:  (1) <Client ID>  (2) [<client mode mask>]
+
+        This command is used by client to set/unset modes for itself.
+        However, there are some modes that the client MUST NOT set itself,
+        but they will be set by server.  However, client MAY unset any
+        mode.  Modes may be masked together ORing them thus having
+        several modes set.  Client MUST keep its client mode mask
+        locally so that the mode setting/unsetting would work without
+        problems.  Client may change only its own modes.
+
+        After changing the mode server MUST send the notify type
+        SILC_NOTIFY_TYPE_UMODE_CHANGE to its primary router.
+
+        The following client modes are defined:
+
+           0x00000000    SILC_UMODE_NONE
+
+              No specific mode for client.  This is the initial
+              setting when new client is created.  The client is
+              normal client and is present in the network.
+
+
+           0x00000001    SILC_UMODE_SERVER_OPERATOR
+
+              Marks the user as server operator.  Client MUST NOT
+              set this mode itself.  Server sets this mode to the
+              client when client attains the server operator
+              privileges by SILC_COMMAND_OPER command.  Client
+              MAY unset the mode itself.
+
+
+           0x00000002    SILC_UMODE_ROUTER_OPERATOR
+
+              Marks the user as router (SILC) operator.  Client
+              MUST NOT set this mode itself.  Router sets this mode
+              to the client when client attains the router operator
+              privileges by SILC_COMMAND_SILCOPER command.  Client
+              MAY unset the mode itself.
+
+
+           0x00000004    SILC_UMODE_GONE
+
+              Marks that the user is not currently present in the
+              SILC Network.  Client MAY set and unset this mode.
+
+
+           0x00000008    SILC_UMODE_INDISPOSED
+
+              Marks that the user is currently indisposed and may
+              not be able to receive any messages, and that user may
+              not be present in the network.  Client MAY set and
+              unset this mode.
+
+
+           0x00000010    SILC_UMODE_BUSY
+
+              Marks that the user is currently busy and may not
+              want to receive any messages, and that user may not
+              be present in the network.  Client MAY set and unset
+              this mode.
+
+
+           0x00000020    SILC_UMODE_PAGE
+
+              User is not currently present or is unable to receive
+              messages, and prefers to be paged in some mechanism
+              if the user needs to be reached.  Client MAY set and
+              unset this mode.
+
+
+           0x00000040    SILC_UMODE_HYPER
+
+              Marks that the user is hyper active and is eager to
+              receive and send messages.   Client MAY set and unset
+              this mode.
+
+
+           0x00000080    SILC_UMODE_ROBOT
+
+              Marks that the client is actually a robot program.
+              Client MAY set and unset this mode.
+
+
+           0x00000100    SILC_UMODE_ANONYMOUS
+
+              Marks that the client is anonymous client.  Server
+              that specifically is designed for anonymous services
+              can set and unset this mode.  Client MUST NOT set or
+              unset this mode itself.  A client with this mode set
+              would have the username and the hostname information
+              scrambled by the server which set this mode.
+
+
+           0x00000200    SILC_UMODE_BLOCK_PRIVMSG
+
+              Marks that the client wishes to block private
+              messages sent to the client, unless the Private
+              Message Key flag is set in the SILC packet header.
+              If this mode is set server MUST NOT deliver private
+              messages to the client without the Private Message
+              Key flag being set.  The Private Message Key flag set
+              indicates that the private message is protected with
+              a key shared between the sender and the recipient.
+
+              A separate service could provide additional filtering
+              features for accepting private messages from certain
+              sender.  However, this document does not specify such
+              service.
+
+              The client MAY set and unset this mode.
+
+
+           0x00000400    SILC_UMODE_DETACHED
+
+              Marks that the client is detached from the SILC network.
+              This means that the actual network connection to the
+              client is lost but the client entry is still valid.  The
+              detached client can be resumed at a later time.  This
+              mode MUST NOT be set by client.  It can only be set when
+              client has issued command SILC_COMMAND_DETACH.  The server
+              sets this mode.  This mode cannot be unset with this
+              command.  It is unset when the client is resuming back to
+              the network and SILC_PACKET_RESUME_CLIENT packet is
+              received.
+
+              This flag MUST NOT be used to determine whether a packet
+              can be sent to the client or not.  Only the server that
+              had the original client connection can make the decision
+              by knowing that the network connection is not active.
+              In this case the default case is to discard the packet.
+
+
+           0x00000800    SILC_UMODE_REJECT_WATCHING
+
+              Marks that the client rejects that it could be watched
+              by someone else.  If this mode is set notifications about
+              this client is not send, even if someone is watching the
+              same nickname this client has.  Client MAY set and unset
+              this mode.  Any changes for this client MUST NOT be
+              notified to any watcher when this mode is set.
+
+              A separate service could provide additional filtering
+              features for rejecting and accepting the watching from
+              certain users.  However, this document does not specify
+              such service.
+
+
+           0x00001000    SILC_UMODE_BLOCK_INVITE
+
+              Marks that the client wishes to block incoming invite
+              notifications.  Client MAY set and unset this mode.
+              When set server does not deliver invite notifications
+              to the client.  Note that this mode may make it harder
+              to join invite-only channels.
+
+        If the <client mode mask> was not provided this command merely
+        returns the mode mask to the client.
+
+
+        Reply messages to the command:
+
+        Max Arguments:  2
+            Arguments:  (1) <Status Payload>  (2) <client mode mask>
+
+        This command replies with the changed client mode mask that
+        the client MUST to keep locally.
+
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+            SILC_STATUS_ERR_BAD_CLIENT_ID
+            SILC_STATUS_ERR_NOT_YOU
+            SILC_STATUS_ERR_PERM_DENIED
+            SILC_STATUS_ERR_UNKNOWN_MODE
+            SILC_STATUS_ERR_NO_CLIENT_ID
+
+
+   17   SILC_COMMAND_CMODE
+
+        Max Arguments:  10
+            Arguments:  (1) <Channel ID>      (2) [<channel mode mask>]
+                        (3) [<user limit>]    (4) [<passphrase>]
+                        (5) [<cipher>]        (6) [<hmac>]
+                        (7) [<auth payload>]  (8) [<founder pubkey>]
+                        (9) [<add | del>]     (10) [<channel pubkey>]
+
+        This command is used by client to set or change channel flags on
+        a channel.  Channel has several modes that set various properties
+        of a channel.  Modes may be masked together by ORing them thus
+        having several modes set.  The <Channel ID> is the ID of the
+        target channel.  The client changing channel mode MUST be on
+        the same channel and posses sufficient privileges to be able to
+        change the mode.
+
+        When the mode is changed SILC_NOTIFY_TYPE_CMODE_CHANGE notify
+        type MUST be distributed to the channel.
+
+        The following channel modes are defined:
+
+           0x00000000    SILC_CMODE_NONE
+
+              No specific mode on channel.  This is the default when
+              channel is created.  This means that channel is just plain
+              normal channel.
+
+
+           0x00000001    SILC_CMODE_PRIVATE
+
+              Channel is private channel.  Private channels are shown
+              in the channel list listed with SILC_COMMAND_LIST command
+              with indication that the channel is private.  Also,
+              client on private channel will no be detected to be on
+              the channel as the channel is not shown in the client's
+              currently joined channel list.  Channel founder and
+              channel operator MAY set/unset this mode.
+
+
+           0x00000002    SILC_CMODE_SECRET
+
+              Channel is secret channel.  Secret channels are not shown
+              in the list listed with SILC_COMMAND_LIST command.  Secret
+              channels can be considered to be invisible channels.
+              Channel founder and channel operator MAY set/unset this
+              mode.
+
+
+           0x00000004    SILC_CMODE_PRIVKEY
+
+              Channel uses private channel key to protect the traffic
+              on the channel.  When this mode is set the client will be
+              responsible to set the key it wants to use to encrypt and
+              decrypt the traffic on channel.  Server generated channel
+              keys are not used at all.  This mode provides additional
+              security as clients on channel may agree to use private
+              channel key that even servers do not know.  Naturally,
+              this requires that every client on the channel knows
+              the key before hand (it is considered to be pre-shared-
+              key).  The key material SHOULD be processed as stated
+              in the [SILC3] in the section Processing the Key Material.
+
+              As it is local setting it is possible to have several
+              private channel keys on one channel.  In this case several
+              clients can talk on same channel but only those clients
+              that share the key with the message sender will be able
+              to hear the talking.  Client SHOULD NOT display those
+              message for the end user that it is not able to decrypt
+              when this mode is set.
+
+              Only channel founder MAY set/unset this mode.  If this
+              mode is unset the server will distribute new channel
+              key to all clients on the channel which will be used
+              thereafter.
+
+
+           0x00000008    SILC_CMODE_INVITE
+
+              Channel is invite only channel.  Client may join to this
+              channel only if it is invited to the channel.  Channel
+              founder and channel operator MAY set/unset this mode.
+
+
+           0x00000010    SILC_CMODE_TOPIC
+
+              The topic of the channel may only be set by client that
+              is channel founder or channel operator.  Normal clients
+              on channel will not be able to set topic when this mode
+              is set.  Channel founder and channel operator MAY set/
+              unset this mode.
+
+
+           0x00000020    SILC_CMODE_ULIMIT
+
+              User limit has been set to the channel.  New clients
+              may not join to the channel when the limit set is
+              reached.  Channel founder and channel operator MAY set/
+              unset the limit.  The <user limit> argument is the
+              number of limited users.
+
+
+           0x00000040    SILC_CMODE_PASSPHRASE
+
+              Passphrase has been set to the channel.  Client may
+              join to the channel only if it is able to provide the
+              correct passphrase.  Setting passphrases to channel
+              is entirely safe as all commands are protected in the
+              SILC network.  Only channel founder MAY set/unset
+              the passphrase.  The <passphrase> argument is the
+              set passphrase.
+
+
+           0x00000080    SILC_CMODE_CIPHER
+
+              Sets specific cipher to be used to protect channel
+              traffic.  The <cipher> argument is the requested cipher.
+              When set or unset the server must re-generate new
+              channel key.  Only channel founder MAY set the cipher of
+              the channel.  When unset the new key is generated using
+              default cipher for the channel.
+
+
+           0x00000100    SILC_CMODE_HMAC
+
+              Sets specific hmac to be used to compute the MACs of the
+              channel message.  The <hmac> argument is the requested hmac.
+              Only channel founder may set the hmac of the channel.
+
+
+           0x00000200    SILC_CMODE_FOUNDER_AUTH
+
+              Channel founder may set this mode to be able to regain
+              channel founder rights even if the client leaves the
+              channel.  The <auth payload> is the Authentication Payload
+              consisting of the public key authentication method and the
+              digital signature for that method.  The passphrase or NONE
+              authentication methods MUST NOT be accepted.
+
+              The server does not save <auth payload> but MUST verify it.
+              The public key used to verify the payload is the <founder
+              pubkey> if present, or the public key of the client sending
+              this command.  If <founder pubkey> is present also that
+              public key MUST be saved as founder's public key.  This
+              mode may be set only if the <auth payload> was verified
+              successfully.  The hash function used with the <auth
+              payload> MUST be sha1.
+
+              The public key of the founder is sent in the
+              SILC_NOTIFY_TYPE_CMODE_CHANGE notify type so that other
+              routers and servers in the network may save the public key.
+              This way the founder can reclaim the founder rights back
+              to the channel from any server in the network.  The founder
+              rights can be regained by the SILC_CUMODE_FOUNDER channel
+              user mode, or during joining procedure with the command
+              SILC_COMMAND_JOIN.
+
+              If this mode is already set but the <founder pubkey> is
+              different the new key will replace the old founder key and
+              the new key is distributed in the network with the
+              SILC_NOTIFY_TYPE_CMODE_CHANGE notify.  Only the original
+              founder may set this mode multiple times and the client
+              MUST have SILC_CUMODE_FOUNDER mode on the channel.
+
+              When this channel mode is set the channel also becomes
+              permanent.  If all clients leave the channel while this
+              mode is set the channel MUST NOT be destroyed.  The founder
+              can reclaim the founder mode back on these empty channels
+              at any time.  Implementations MAY limit the number of how
+              many channels a user can own and how long they remain
+              persistent.
+
+
+           0x00000400    SILC_CMODE_SILENCE_USERS
+
+              Channel founder may set this mode to silence normal users
+              on the channel.  Users with operator privileges are not
+              affected by this mode.  Messages sent by normal users
+              are dropped by servers when this mode is set.  This mode
+              can be used to moderate the channel.  Only channel founder
+              may set/unset this mode.
+
+
+           0x00000800    SILC_CMODE_SILENCE_OPERS
+
+              Channel founder may set this mode to silence operators
+              on the channel.  When used with SILC_CMODE_SILENCE_USERS
+              mode this can be used to set the channel in state where only
+              the founder of the channel may send messages to the channel.
+              Messages sent by operators are dropped by servers when this
+              mode is set.  Only channel founder may set/unset this mode.
+
+
+           0x00001000    SILC_CMODE_CHANNEL_AUTH
+
+              When this mode is set the channel has one or more public keys
+              or certificates set, and ability to join the channel requires
+              a client to provide digital signature that can be successfully
+              verified with one of the channel public keys.  This mode is
+              equivalent to the SILC_MODE_PASSPHRASE except that digital
+              signatures are used to gain access to the channel.  Both
+              modes MAY be set at the same time.  Channel founder may set
+              and unset this mode.
+
+              To add one public key to channel this mode is set and the
+              <add | del> argument includes 0x00 value, and the <channel
+              pubkey> is the public key.  To remove one public key from
+              channel public key list the <add | del> includes 0x01 value
+              and <channel pubkey> is the public key to be removed.  To
+              remove all public keys at once this mode is unset.  An
+              implementation MAY limit the number of public keys that can
+              be set on the channel.  This mode MUST NOT be set if <channel
+              pubkey> is not present when the mode is set for the first
+              time.
+
+
+        To make the mode system work, client MUST keep the channel mode
+        mask locally so that the mode setting and unsetting would work
+        without problems.  The client receives the initial channel mode
+        mask when it joins to the channel.  When the mode changes on
+        channel the server MUST distribute the changed channel mode mask
+        to all clients on the channel by sending the notify type
+        SILC_NOTIFY_TYPE_CMODE_CHANGE.  The notify type MUST also be sent
+        to the server's primary router.  If the <channel mode mask> was
+        not provided this command merely returns the mode mask to the
+        client.
+
+        Reply messages to the command:
+
+        Max Arguments:  5
+            Arguments:  (1) <Status Payload>    (2) <Channel ID>
+                        (3) <channel mode mask> (4) [<founder pubkey>]
+                        (5) [<channel pubkeys>]
+
+        This command replies with the changed channel mode mask that
+        client MUST keep locally.  It may also return the channel
+        founder's public key if it is set.  It may also return list of
+        channel public keys.  The <channel pubkeys> is Argument List
+        Payload and each argument includes one public key.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ON_CHANNEL
+            SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+            SILC_STATUS_ERR_BAD_CHANNEL_ID
+            SILC_STATUS_ERR_NO_CHANNEL_ID
+            SILC_STATUS_ERR_NO_CHANNEL_PRIV
+            SILC_STATUS_ERR_NO_CHANNEL_FOPRIV
+            SILC_STATUS_ERR_UNKNOWN_MODE
+            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+            SILC_STATUS_ERR_AUTH_FAILED
+
+
+   18   SILC_COMMAND_CUMODE
+
+        Max Arguments:  4
+            Arguments:  (1) <Channel ID>    (2) <mode mask>
+                        (3) <Client ID>     (4) [<auth payload>]
+
+        This command is used by client to change channel user modes on
+        channel.  Users on channel may have some special modes and this
+        command is used by channel operators to set or change these modes.
+        The <Channel ID> is the ID of the target channel.  The <mode mask>
+        is OR'ed mask of modes.  The <Client ID> is the target client.
+        The client changing channel user modes MUST be on the same channel
+        as the target client and posses sufficient privileges to be able to
+        change the mode.
+
+        When the mode is changed SILC_NOTIFY_TYPE_CUMODE_CHANGE notify
+        type is distributed to the channel.
+
+        The following channel modes are defined:
+
+           0x00000000    SILC_CUMODE_NONE
+
+              No specific mode.  This is the normal situation for client.
+              Also, this is the mode set when removing all modes from
+              the target client.
+
+
+           0x00000001    SILC_CUMODE_FOUNDER
+
+              The client is channel founder of the channel.  Usually this
+              mode is set only by the server when the channel was created.
+              However, if the SILC_CMODE_FOUNDER_AUTH channel mode has
+              been set, the client can claim channel founder privileges
+              by providing the <auth payload> that the server will use
+              to authenticate the client.  The public key that server will
+              use to verify the <auth payload> MUST be the same public key
+              that was saved when the SILC_CMODE_FOUNDER_AUTH channel
+              mode was set.  The client MAY remove this mode at any time.
+
+
+           0x00000002    SILC_CUMODE_OPERATOR
+
+              Sets channel operator privileges on the channel for a
+              client on the channel.  Channel founder and channel operator
+              MAY set/unset this mode.  The client MAY remove this mode
+              at any time.
+
+
+           0x00000004    SILC_CUMODE_BLOCK_MESSAGES
+
+              Marks that the client wishes not to receive any channel
+              messages sent for the channel.  Client MAY set and unset
+              this mode to itself.  Client MUST NOT set it to anyone else.
+              When this mode is set server MUST NOT deliver channel
+              messages to this client.  Other packets such as channel
+              key packets are still sent to the client.
+
+              A separate service could provide additional filtering
+              features for accepting channel messages from certain
+              sender.  However, this document does not specify such
+              service.
+
+
+           0x00000008    SILC_CUMODE_BLOCK_MESSAGES_USERS
+
+              Marks that the client wishes not to receive any channel
+              messages sent from normal users.  Only messages sent by
+              channel founder or channel operator is accepted.  Client
+              MAY set and unset this mode to itself.  Client MUST NOT
+              set it to anyone else.  When this mode is set server MUST
+              NOT deliver channel messages that are sent by normal users
+              to this client.
+
+              A separate service could provide additional filtering
+              features for accepting channel messages from certain
+              sender.  However, this document does not specify such
+              service.
+
+
+           0x00000010    SILC_CUMODE_BLOCK_MESSAGES_ROBOTS
+
+              Marks that the client wishes not to receive any channel
+              messages sent from robots.  Messages sent by users with
+              the SILC_UMODE_ROBOT user mode set are not delivered.
+              Client MAY set and unset this mode to itself.  Client MUST
+              NOT set it to anyone else.  When this mode is set server
+              MUST NOT deliver channel messages that are sent by robots
+              to this client.
+
+
+           0x00000020    SILC_CUMODE_QUIET
+
+              Marks that the client cannot talk on the channel.  This
+              mode can be set by channel operator or channel founder to
+              some other user that is not operator or founder.  The
+              target client MUST NOT unset this mode.  When this mode
+              is set the server MUST drop messages sent by this client
+              to the channel.
+
+
+        Reply messages to the command:
+
+        Max Arguments:  4
+            Arguments:  (1) <Status Payload>  (2) <channel user mode mask>
+                        (3) <Channel ID>      (4) <Client ID>
+
+        This command replies with the changed channel user mode mask that
+        client MUST keep locally. The <Channel ID> is the specified
+        channel.  The <Client ID> is the target client.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ON_CHANNEL
+            SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+            SILC_STATUS_ERR_BAD_CHANNEL_ID
+            SILC_STATUS_ERR_NO_CHANNEL_ID
+            SILC_STATUS_ERR_NO_CHANNEL_PRIV
+            SILC_STATUS_ERR_NO_CHANNEL_FOPRIV
+            SILC_STATUS_ERR_UNKNOWN_MODE
+            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+            SILC_STATUS_ERR_AUTH_FAILED
+
+
+   19   SILC_COMMAND_KICK
+
+        Max Arguments:  3
+            Arguments:  (1) <Channel ID>      (2) <Client ID>
+                        (3) [<comment>]
+
+        This command is used by channel operators to remove a client from
+        channel.  The <channel> argument is the channel the client to be
+        removed is on currently.  Note that the "kicker" must be on the same
+        channel.  If <comment> is provided it will be sent to the removed
+        client.
+
+        After kicking the client the server MUST send the notify type
+        SILC_NOTIFY_TYPE_KICKED to the channel and to its primary router.
+        The client is removed from the channel after sending this notify.
+        The kicked client MUST be removed from the invite list of the
+        channel if it is explicitly added in the list.  The channel key
+        MUST also be re-generated after kicking, unless the
+        SILC_CMODE_PRIVKEY mode is set.
+
+        Reply messages to the command:
+
+        Max Arguments:  1
+            Arguments:  (1) <Status Payload>
+
+        This command replies only with Status Payload.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NO_SUCH_CHANNEL
+            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+            SILC_STATUS_ERR_NO_CHANNEL_PRIV
+            SILC_STATUS_ERR_NO_CLIENT_ID
+
+
+
+   20   SILC_COMMAND_BAN
+
+        Max Arguments:  3
+            Arguments:  (1) <Channel ID>         (2) [<add | del>]
+                        (3) [<ban list>]
+
+        This command is used to manage the ban list of the channel
+        indicated by the <Channel ID>.  A client that is banned from
+        channel is no longer able to join the channel.  The client which
+        is executing this command MUST have at least channel operator
+        privileges on the channel.
+
+        The <add | del> is an argument of size of 1 byte where 0x00 means
+        adding a client to ban list, and 0x01 means deleting a client
+        from ban list.  The <ban list>, if present, indicates the
+        information to be added to or removed from the ban list.  It
+        may include a string for matching clients, public key of a
+        client or Client ID of a client.  The <ban list> is an Argument
+        List Payload.
+
+        The following Argument Types has been defined for ban list
+        Argument Payloads:
+
+          0x01 - Argument is an ban string of following format:
+
+            [<nickname>[@<server>]!][<username>]@[<hostname or IP/MASK>]
+
+            The <hostname> may also be in format of IP/MASK to indicate
+            a network.
+
+          0x02 - Argument is the public key of a client
+          0x03 - Argument is the Client ID of a client
+
+        If unknown type value is received or there is invalid amount of
+        Argument Payloads present in the list, the command MUST be
+        discarded.  When argument that is to be deleted from the ban
+        list does not exist in the list the argument is ignored.
+
+        The server MUST send the notify type SILC_NOTIFY_TYPE_BAN to its
+        primary router after adding to or removing from the ban list.
+        The wildcards MAY be used with this command.  If this command
+        is executed without the ban arguments the command merely replies
+        with the current ban list.
+
+        Reply messages to the command:
+
+        Max Arguments:  3
+            Arguments:  (1) <Status Payload>  (2) <Channel ID>
+                        (3) [<ban list>]
+
+        This command replies with the <Channel ID> of the channel and
+        the current <ban list> of the channel if it exists.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+            SILC_STATUS_ERR_NO_CHANNEL_ID
+            SILC_STATUS_ERR_NOT_ON_CHANNEL
+            SILC_STATUS_ERR_NO_CHANNEL_PRIV
+            SILC_STATUS_ERR_RESOURCE_LIMIT
+
+
+
+
+   21   SILC_COMMAND_DETACH
+
+        Max Arguments:  0
+            Arguments:
+
+        This command is used to detach from the network.  Client can
+        send this command to its server to indicate that it will be
+        detached.  By detaching the client remains in the network but
+        the actual network connection to the server is closed.  The
+        client may then later resume the old session back.
+
+        When this command is received the server MUST check that the
+        client is locally connected client, and set the user mode
+        SILC_UMODE_DETACHED flag.  The SILC_NOTIFY_TYPE_UMODE_CHANGE
+        MUST be also sent to routers.  The server then sends command
+        reply to this command and closes the network connection.
+        The server MUST NOT remove the client from its lists, or send
+        any signoff notifications for this client.  See the [SILC1]
+        for detailed information about detaching.
+
+        Reply messages to the command:
+
+        Max Arguments:  1
+            Arguments:  (1) <Status Payload>
+
+        This command replies only with the status indication.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_REGISTERED
+
+
+
+   22   SILC_COMMAND_WATCH
+
+        Max Arguments:  3
+            Arguments:  (1) <Client ID>       (2) [<add nickname>]
+                        (3) [<del nickname>]
+
+        This command is used to set up a watch for <add nickname>
+        nickname.  When a user in the network appears with the
+        nickname, or signoffs the network or user's mode is changed
+        the client which set up the watch will be notified about
+        this change.  This can be used to watch for certain nicknames
+        in the network and receive notifications when for example a
+        friend appears in the network or leaves the network.
+
+        The <del nickname> is a nickname that has been previously
+        added to watch list and is now removed from it.  Notifications
+        for that nickname will not be delivered anymore.
+
+        The <Client ID> is the Client ID of the sender of this command.
+
+        The nickname set to watch MUST NOT include any wildcards.
+        Note also that a nickname may match several users since
+        nicknames are not unique.  Implementations MAY set limits
+        for how many nicknames client can watch.
+
+        When normal server receives this command from client it
+        MUST send it to its router.  Router will process the command
+        and actually keeps the watch list.
+
+        Reply messages to the command:
+
+        Max Arguments:  1
+            Arguments:  (1) <Status Payload>
+
+        This command replies only with the status indication.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_BAD_NICKNAME
+            SILC_STATUS_ERR_WILDCARDS
+            SILC_STATUS_ERR_RESOURCE_LIMIT
+            SILC_STATUS_ERR_NO_SUCH_NICK
+            SILC_STATUS_ERR_NICKNAME_IN_USE
+
+
+   23   SILC_COMMAND_SILCOPER
+
+        Max Arguments:  2
+            Arguments:  (1) <username>  (2) <authentication payload>
+
+        This command is used by normal client to obtain router operator
+        privileges (also known as SILC operator) on the router.  Note
+        that router operator has privileges that supersedes the server
+        operator privileges.
+
+        The <username> is the username set in the server configurations
+        as operator.  The <authentication payload> is the data that the
+        client is authenticated against.  It may be passphrase prompted
+        for user on client's screen or it may be public key or certificate
+        authentication data (data signed with private key).  The public
+        key that router will use to verify the signature found in the
+        payload should be verified.  It is recommended that the public
+        key is saved locally in the router and router would not use
+        any public keys received during the SKE.
+
+        Difference between router operator and server operator is that
+        router operator is able to handle cell level properties while
+        server operator (even on router server) is able to handle only
+        local properties, such as, local connections and normal server
+        administration.  The router operator is also able to use the
+        SILC_COMMAND_KILL command.
+
+        After changing the mode server MUST send the notify type
+        SILC_NOTIFY_TYPE_UMODE_CHANGE to its primary router.
+
+        Reply messages to the command:
+
+        Max Arguments:  1
+            Arguments:  (1) <Status Payload>
+
+        This command replies only with Status Payload.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_AUTH_FAILED
+
+
+
+
+   24   SILC_COMMAND_LEAVE
+
+        Max Arguments:  1
+            Arguments:  (1) <Channel ID>
+
+        This command is used by client to leave a channel the client is
+        joined to.
+
+        When leaving channel the server MUST send the notify type
+        SILC_NOTIFY_TYPE_LEAVE to its primary router and to the channel.
+        The channel key MUST also be re-generated when leaving the channel
+        and distribute it to all clients still currently on the channel.
+        The key MUST NOT be re-generated if the SILC_CMODE_PRIVKEY mode
+        is set.
+
+        Reply messages to the command:
+
+        Max Arguments:  2
+            Arguments:  (1) <Status Payload>  (2) <Channel ID>
+
+        The <Channel ID> is the ID of left channel.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+            SILC_STATUS_ERR_BAD_CHANNEL_ID
+            SILC_STATUS_ERR_NO_CHANNEL_ID
+
+
+   25   SILC_COMMAND_USERS
+
+        Max Arguments:  2
+            Arguments:  (1) [<Channel ID>]  (2) [<channel name>]
+
+        This command is used to list user names currently on the requested
+        channel; either the argument <Channel ID> or the <channel name>.
+        One of these arguments must be present.  The server MUST resolve
+        the joined clients and reply with a lists of users on the channel
+        and with list of user modes on the channel.
+
+        If the requested channel is a private or secret channel, this
+        command MUST NOT send the list of users, except if the sender is
+        on the channel, or the sender is a server.  Otherwise, error is
+        returned to the sender.
+
+        Reply messages to the command:
+
+        Max Arguments:  5
+            Arguments:  (1) <Status Payload>  (2) <Channel ID>
+                        (3) <list count>      (4) <Client ID list>
+                        (5) <client mode list>
+
+        This command replies with the Channel ID of the requested channel
+        Client ID list of the users on the channel and list of their modes.
+        The Client ID list has Client ID's of all users in the list.  The
+        <Client ID list> is formed by adding Client ID's one after another.
+        The <client mode list> is formed by adding client's user modes on
+        the channel one after another (4 bytes (32 bits) each).  The <list
+        count> of length of 4 bytes (32 bits), tells the number of entries
+        in the lists.  Both lists MUST have equal number of entries.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+            SILC_STATUS_ERR_BAD_CHANNEL_ID
+            SILC_STATUS_ERR_NO_CHANNEL_ID
+            SILC_STATUS_ERR_NOT_ON_CHANNEL
+
+
+   26   SILC_COMMAND_GETKEY
+
+        Max Arguments:  1
+            Arguments:  (1) <ID Payload>
+
+        This command is used to fetch the public key of the client or
+        server indicated by the <ID Payload>.  The public key is fetched
+        from the server where to the client is connected.
+
+        Reply messages to the command:
+
+        Max Arguments:  3
+            Arguments:  (1) <Status Payload>      (2) <ID Payload>
+                        (3) [<Public Key Payload>]
+
+        This command replies with the client's or server's ID and with
+        the <Public Key Payload>.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+            SILC_STATUS_ERR_NO_SUCH_SERVER_ID
+
+
+   27   SILC_COMMAND_SERVICE
+
+        Max Arguments:  256
+            Arguments:  (1) [<service name>]    (2) [<auth payload>]
+                        (n) [...]
+
+        This command is used to negotiate a service agreement with a
+        remote server.  If this command is given without arguments it
+        MAY return the service list, if it is publicly available.  The
+        <service name> is a service specific identifier, and the
+        <auth payload> MAY be used to authenticate the requester to the
+        remote service.  The authentication to a service may be based
+        on previous agreement with the requester and the service
+        provider.  The command MAY also take additional service
+        specific arguments.
+
+        This document does not specify any services.  How the services
+        are configured and put available in a server is also out of
+        scope of this document.
+
+        This command MAY be used by client to start using some service
+        in a server, but it also MAY be used by server to negotiate
+        to start using a service in some other server or router.
+
+        After the negotiation is done both of the parties need to know
+        from the service identifier how the service can be used.  The
+        service can be considered to be a protocol which both of the
+        parties need to support.
+
+        Reply messages to the command:
+
+        Max Arguments:  256
+            Arguments:  (1) <Status Payload>      (2) [<service list>]
+                        (3) [<service name>]      (n) [...]
+
+
+        This command MAY reply with the <service list> when command is
+        given without arguments, and the list is a comma separated list
+        of service identifiers.  The <service name> is the service that
+        the sender requested and this is provided when the server has
+        accepted the sender to use the <service name>.  The command
+        reply MAY also have additional service specific arguments.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NO_SUCH_SERVICE
+            SILC_STATUS_ERR_AUTH_FAILED
+            SILC_STATUS_ERR_PERM_DENIED
+
+
+
+   28 - 199
+
+        Currently undefined commands.
+
+
+   200 - 254
+
+        These commands are reserved for private use and will not be defined
+        in this document.
+
+
+   255  SILC_COMMAND_MAX
+
+        Reserved command.  This must not be sent.
+.in 3
+
+
+.ti 0
+2.4 SILC Command Status Payload
+
+Command Status Payload is sent in command reply messages to indicate
+the status of the command.  The payload is one of argument in the
+command thus this is the data area in Command Argument Payload described
+in [SILC2].  The payload is only 2 bytes in length.  The following
+diagram represents the Command Status Payload (fields are always in
+MSB first order).
+
+
+.in 21
+.nf
+                     1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|     Status    |     Error     |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 6:  SILC Command Status Payload
+
+
+.in 6
+o Status (1 byte) - Indicates the status message type,
+  error, start of list, entry of list or end of list.
+
+o Error (1 byte) - Indicates the error if the Status
+  field is some list status, which means there are list
+  of errors.
+.in 3
+
+The values in Status and Error fields are set according
+the following rules:
+
+.in 6
+o If there is single reply and error has not occurred
+  then Status field includes value SILC_STATUS_OK, and
+  the Error field MUST be ignored (and set to zero
+  value).
+
+o If there is single error, then Status field includes
+  one of the error values, and the Error field MUST be
+  ignored (and set to zero value).
+
+o If there will be multiple successful command replies
+  then Status field includes SILC_STATUS_LIST_START,
+  SILC_STATUS_LIST_ITEM or SILC_STATUS_LIST_END value,
+  and Error field is set to SILC_STATUS_OK.
+
+o If there are multiple error replies then Status field
+  includes SILC_STATUS_LIST_START, SILC_STATUS_LIST_ITEM
+  or SILC_STATUS_LIST_END value, and the Error field
+  includes the error value.
+.in 3
+
+This way it is possible to send single successful or
+single error reply, but also multiple successful and
+multiple error replies.  Note that it is possible to
+send both list of successful replies and list of error
+replies at the same time, however in this case the
+list of error replies MUST be sent after the successful
+replies.  This way the recipient may ignore the multiple
+errors if it wishes to do so.  Also note that in this
+case the successful and error replies belong to the
+same list.
+
+All Status messages are described in the next section.
+
+
+.ti 0
+3 SILC Status Types
+
+Status messages are returned in SILC protocol in command reply
+packet and in notify packet.  The SILC_PACKET_COMMAND_REPLY is
+the command reply packet and status types are sent inside the
+Status Payload as one of command reply argument, as defined in
+previous sections.  For SILC_PACKET_NOTIFY packet they can be sent
+as defined in [SILC2] for SILC_NOTIFY_TYPE_ERROR type.  The same
+types defined in this section are used in both cases.
+
+When returning status messages in the command reply message they
+indicate whether the command was executed without errors.  If error
+occurred the status indicates which error occurred.
+
+When sending status messages in SILC_NOTIFY_TYPE_ERROR notify type
+they always send some error status.  Usually they are sent to
+indicate that error occurred while processing some SILC packet.
+Please see the [SILC1] and [SILC2] for more information sending
+status types in SILC_NOTIFY_TYPE_ERROR notify.
+
+The Status Types are only numeric values and the receiver must
+convert the numeric values into human readable messages if this
+is desired in the application.
+
+List of all defined status types:
+
+.in 0
+   Generic status messages:
+
+   0    SILC_STATUS_OK
+
+        Ok status.  Everything went Ok.  The status payload maybe
+        safely ignored in this case.
+
+   1    SILC_STATUS_LIST_START
+
+        Start of the list.  There will be several command replies and
+        this reply is the start of the list.
+
+   2    SILC_STATUS_LIST_ITEM
+
+        Item in the list.  This is one of the item in the list but not the
+        first or last one.
+
+   3    SILC_STATUS_LIST_END
+
+        End of the list.  There were several command replies and this
+        reply is the last of the list.  There won't be other replies
+        belonging to this list after this one.
+
+   4 - 9
+
+        Currently undefined and has been reserved for the future.
+
+
+   Error status message:
+
+
+
+   10   SILC_STATUS_ERR_NO_SUCH_NICK
+
+        "No such nickname".  Requested nickname does not exist.
+
+   11   SILC_STATUS_ERR_NO_SUCH_CHANNEL
+
+        "No such channel".  Requested channel name does not exist.
+
+   12   SILC_STATUS_ERR_NO_SUCH_SERVER
+
+        "No such server".  Requested server name does not exist.
+
+   13   SILC_STATUS_ERR_INCOMPLETE_INFORMATION
+
+        "Incomplete registration information".  Information remote
+        sent was incomplete.
+
+   14   SILC_STATUS_ERR_NO_RECIPIENT
+
+        "No recipient given".  Command required recipient which was
+        not provided.
+
+   15   SILC_STATUS_ERR_UNKNOWN_COMMAND
+
+        "Unknown command".  Command sent to server is unknown by the
+        server.
+
+   16   SILC_STATUS_ERR_WILDCARDS
+
+        "Wildcards cannot be used".  Wildcards were provided but they
+        weren't permitted.
+
+   17   SILC_STATUS_ERR_NO_CLIENT_ID
+
+        "No Client ID given".  Client ID were expected as command
+        parameter but were not found.
+
+   18   SILC_STATUS_ERR_NO_CHANNEL_ID
+
+        "No Channel ID given".  Channel ID were expected as command
+        parameter but were not found.
+
+   19   SILC_STATUS_ERR_NO_SERVER_ID
+
+        "No Serve ID given".  Server ID were expected as command
+        parameter but were not found.
+
+   20   SILC_STATUS_ERR_BAD_CLIENT_ID
+
+        "Bad Client ID".  Client ID provided were erroneous.
+
+   21   SILC_STATUS_ERR_BAD_CHANNEL_ID
+
+        "Bad Channel ID".  Channel ID provided were erroneous.
+
+   22   SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+
+        "No such Client ID".  Client ID provided does not exist.
+        The unknown Client ID MUST be provided as next argument
+        in the reply.
+
+   23   SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+
+        "No such Channel ID".  Channel ID provided does not exist.
+        The unknown Channel ID MUST be provided as next argument
+        in the reply.
+
+   24   SILC_STATUS_ERR_NICKNAME_IN_USE
+
+        "Nickname already exists".  Nickname created could not be
+        registered because number of same nicknames were already set to
+        maximum.  This is not expected to happen in real life but is
+        possible to occur.
+
+   25   SILC_STATUS_ERR_NOT_ON_CHANNEL
+
+        "You are not on that channel".  The command were specified for
+        channel user is not currently on.
+
+   26   SILC_STATUS_ERR_USER_NOT_ON_CHANNEL
+
+        "They are not on channel".  The requested target client is not
+        on requested channel.
+
+   27   SILC_STATUS_ERR_USER_ON_CHANNEL
+
+        "User already on channel".  User were invited on channel they
+        already are on.
+
+   28   SILC_STATUS_ERR_NOT_REGISTERED
+
+        "You have not registered".  User executed command that requires
+        the client to be registered on the server before it may be
+        executed.
+
+   29   SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+
+        "Not enough parameters".  Command requires more parameters
+        than provided.
+
+   30   SILC_STATUS_ERR_TOO_MANY_PARAMS
+
+        "Too many parameters".  Too many parameters were provided
+        for the command.
+
+   31   SILC_STATUS_ERR_PERM_DENIED
+
+        "Permission denied".  Generic permission denied error status
+        to indicate disallowed access.
+
+   32   SILC_STATUS_ERR_BANNED_FROM_SERVER
+
+        "You are banned from this server".  The client tried to register
+        on server that has explicitly denied this host to connect.
+
+   33   SILC_STATUS_ERR_BAD_PASSWORD
+
+        "Cannot join channel. Incorrect password".  Password provided for
+        channel were not accepted.
+
+   34   SILC_STATUS_ERR_CHANNEL_IS_FULL
+
+        "Cannot join channel. Channel is full".  The channel is full
+        and client cannot be joined to it.
+
+   35   SILC_STATUS_ERR_NOT_INVITED
+
+        "Cannot join channel. You have not been invited".  The channel
+        is invite only channel and client has not been invited.
+
+   36   SILC_STATUS_ERR_BANNED_FROM_CHANNEL
+
+        "Cannot join channel. You have been banned".  The client has
+        been banned from the channel.
+
+   37   SILC_STATUS_ERR_UNKNOWN_MODE
+
+        "Unknown mode".  Mode provided by the client were unknown to
+        the server.
+
+   38   SILC_STATUS_ERR_NOT_YOU
+
+        "Cannot change mode for other users".  User tried to change
+        someone else's mode.
+
+   39   SILC_STATUS_ERR_NO_CHANNEL_PRIV
+
+        "Permission denied. You are not channel operator".  Command may
+        be executed only by channel operator.
+
+   40   SILC_STATUS_ERR_NO_CHANNEL_FOPRIV
+
+        "Permission denied. You are not channel founder".  Command may
+        be executed only by channel operator.
+
+   41   SILC_STATUS_ERR_NO_SERVER_PRIV
+
+        "Permission denied. You are not server operator".  Command may
+        be executed only by server operator.
+
+   42   SILC_STATUS_ERR_NO_ROUTER_PRIV
+
+        "Permission denied. You are not SILC operator".  Command may be
+        executed only by router (SILC) operator.
+
+   43   SILC_STATUS_ERR_BAD_NICKNAME
+
+        "Bad nickname".  Nickname requested contained illegal characters
+        or were malformed.
+
+   44   SILC_STATUS_ERR_BAD_CHANNEL
+
+        "Bad channel name".  Channel requested contained illegal characters
+        or were malformed.
+
+   45   SILC_STATUS_ERR_AUTH_FAILED
+
+        "Authentication failed".  The authentication data sent as
+        argument were wrong and thus authentication failed.
+
+   46   SILC_STATUS_ERR_UNKOWN_ALGORITHM
+
+        "The algorithm was not supported."  The server does not support the
+        requested algorithm.
+
+   47   SILC_STATUS_ERR_NO_SUCH_SERVER_ID
+
+        "No such Server ID".  Server ID provided does not exist.
+        The unknown Server ID MUST be provided as next argument
+        in the reply.
+
+   48   SILC_STATUS_ERR_RESOURCE_LIMIT
+
+        "No more resources available".  This can mean that server cannot
+        or will not accept something due to resource limitations.
+
+   49   SILC_STATUS_ERR_NO_SUCH_SERVICE
+
+        "Service does not exist".  Requested service identifier is
+        unknown.
+
+   50   SILC_STATUS_ERR_NOT_AUTHENTICATED
+
+        "You have not been authenticated".  Remote connection is not
+        authenticated even though it is supposed to be.
+
+   51   SILC_STATUS_ERR_BAD_SERVER_ID
+
+        "Server ID is not valid".  Provided server ID is not valid.
+
+   52   SILC_STATUS_ERR_KEY_EXCHANGE_FAILED
+
+        "Key exchange failed".  Key Exchange protocol failed.
+
+   53   SILC_STATUS_ERR_BAD_VERSION
+
+        "Bad version".  Protocol or software version mismatch.
+
+   54   SILC_STATUS_ERR_TIMEDOUT
+
+        "Operation timed out".  Operation or service request timed
+        out, and thus was not processed.
+
+   55   SILC_STATUS_ERR_UNSUPPORTED_PUBLIC_KEY
+
+        "Unsupported public key type".  The public key or certificate
+        type is not supported in this implementation.
+
+   56   SILC_STATUS_ERR_OPERATION_ALLOWED
+
+        "Operation is not allowed".  A operation, for example a command,
+        is not allowed or it's execution is not allowed.
+
+.in 3
+
+
+
+.ti 0
+4 Security Considerations
+
+Security is central to the design of this protocol, and these security
+considerations permeate the specification.  Common security considerations
+such as keeping private keys truly private and using adequate lengths for
+symmetric and asymmetric keys must be followed in order to maintain the
+security of this protocol.
+
+
+.ti 0
+5 References
+
+[SILC1]      Riikonen, P., "Secure Internet Live Conferencing (SILC),
+             Protocol Specification", Internet Draft, May 2002.
+
+[SILC2]      Riikonen, P., "SILC Packet Protocol", Internet Draft,
+             May 2002.
+
+[SILC3]      Riikonen, P., "SILC Key Exchange and Authentication
+             Protocols", Internet Draft, May 2002.
+
+[IRC]        Oikarinen, J., and Reed D., "Internet Relay Chat Protocol",
+             RFC 1459, May 1993.
+
+[IRC-ARCH]   Kalt, C., "Internet Relay Chat: Architecture", RFC 2810,
+             April 2000.
+
+[IRC-CHAN]   Kalt, C., "Internet Relay Chat: Channel Management", RFC
+             2811, April 2000.
+
+[IRC-CLIENT] Kalt, C., "Internet Relay Chat: Client Protocol", RFC
+             2812, April 2000.
+
+[IRC-SERVER] Kalt, C., "Internet Relay Chat: Server Protocol", RFC
+             2813, April 2000.
+
+[SSH-TRANS]  Ylonen, T., et al, "SSH Transport Layer Protocol",
+             Internet Draft.
+
+[PGP]        Callas, J., et al, "OpenPGP Message Format", RFC 2440,
+             November 1998.
+
+[SPKI]       Ellison C., et al, "SPKI Certificate Theory", RFC 2693,
+             September 1999.
+
+[PKIX-Part1] Housley, R., et al, "Internet X.509 Public Key
+             Infrastructure, Certificate and CRL Profile", RFC 2459,
+             January 1999.
+
+[Schneier]   Schneier, B., "Applied Cryptography Second Edition",
+             John Wiley & Sons, New York, NY, 1996.
+
+[Menezes]    Menezes, A., et al, "Handbook of Applied Cryptography",
+             CRC Press 1997.
+
+[OAKLEY]     Orman, H., "The OAKLEY Key Determination Protocol",
+             RFC 2412, November 1998.
+
+[ISAKMP]     Maughan D., et al, "Internet Security Association and
+             Key Management Protocol (ISAKMP)", RFC 2408, November
+             1998.
+
+[IKE]        Harkins D., and Carrel D., "The Internet Key Exchange
+             (IKE)", RFC 2409, November 1998.
+
+[HMAC]       Krawczyk, H., "HMAC: Keyed-Hashing for Message
+             Authentication", RFC 2104, February 1997.
+
+[PKCS1]      Kalinski, B., and Staddon, J., "PKCS #1 RSA Cryptography
+             Specifications, Version 2.0", RFC 2437, October 1998.
+
+[RFC2119]    Bradner, S., "Key Words for use in RFCs to Indicate
+             Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+[RFC2279]    Yergeau, F., "UTF-8, a transformation format of ISO
+             10646", RFC 2279, January 1998.
+
+[ATTRS]      Riikonen, P., "User Online Presence and Information
+             Attributes", Internet Draft, May 2002.
+
+
+.ti 0
+6 Author's Address
+
+.nf
+Pekka Riikonen
+Snellmaninkatu 34 A 15
+70100 Kuopio
+Finland
+
+EMail: priikone@iki.fi
+
+
+.ti 0
+Appendix A
+
+This appendix defines the usage of the <Requested Attributes> argument in
+the SILC_COMMAND_WHOIS command.  The attributes are defined in [ATTRS],
+and may be used to request additional information about the user.  Since
+the information that may be requested using the attributes is something
+that server cannot deliver to the sender, it is possible to send the WHOIS
+command directly to the destination client whom will then provide the
+requested attributes.  This requires the servers to relay the WHOIS
+command to the client, and it requires capability for handling the WHOIS
+command in the client end.
+
+The <Requested Attributes> MAY include several attributes that are
+requested.  The format and encoding of the <Requested Attributes> is as
+defined in [ATTRS].  When <Requested Attributes> argument is set the
+server MAY process the attributes to see whether it can narrow down
+the WHOIS search, for example when searching with a nickname.  The
+normal servers MUST process the WHOIS command as normal WHOIS command,
+that is to send the command directly to the router.  The router MAY
+process the attributes, but it MUST send the command to the server
+that owns the requested client.
+
+The server that owns the client and receives the command MUST check
+whether the client is detached from the network.  If it is detached,
+that is the user mode has the SILC_UMODE_DETACHED mode set, it SHOULD
+process the attributes and provide as many of the requested attributes
+as possible and then send reply back to the sender.  If the client is
+active in the network it MUST send the command to the client for
+processing.
+
+The client receiving WHOIS command SHOULD check whether the
+<Requested Attributes> argument is set.  If it is not set then the
+WHOIS command SHOULD be discarded.  The client processes the requested
+attributes and SHOULD reply to each of the requested attribute with
+either valid value, or with an indication that the requested attribute
+is not known or supported.  This is to be done as defined in [ATTRS].
+The client always MUST send a reply to the command when some attributes
+were requested.  The client MAY also add additional attributes to the
+reply even if they were not requested.  The client MAY also digitally
+sign the attributes with ATTRIBUTE_USER_DIGITAL_SIGNATURE as defined
+in [ATTRS].  Then the client sends the reply back to the sender of
+the command.  The command reply that client assembles does not need
+to include any other argument but the <Status Payload> (1), and the
+<Attributes> (11).  The server receiving reply from client MUST allow
+this sort of command reply for WHOIS command.
+
+The information received from the client MAY be cached in the
+server's end.  The caching may be desired for example if the client
+can be detached from the network.  This way the server is then able
+to provide at least partial information for a requester.  The
+server MAY also process the command reply and verify whether the
+attributes provided in the reply are actually valid.  If it can do
+this, and verify that they indeed are valid values it MAY append
+a digital signature at the end of the attributes with the
+ATTRIBUTE_SERVER_DIGITAL_SIGNATURE as defined in [ATTRS].  The
+server then MUST provide valid WHOIS command reply to the sender
+of the command.   Other servers and routers that receive the command
+reply en route to the original sender MAY also cache the information.
+
+The client which receives the command reply to the WHOIS command
+SHOULD verify the ATTRIBUTE_USER_DIGITAL_SIGNATURE and the
+ATTRIBUTE_SERVER_DIGITAL_SIGNATURE if they are provided.
+
+
+.ti 0
+Full Copyright Statement
+
+Copyright (C) The Internet Society (2003). All Rights Reserved.
+
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/doc/draft-riikonen-silc-commands-06.nroff b/doc/draft-riikonen-silc-commands-06.nroff
new file mode 100644 (file)
index 0000000..84e9197
--- /dev/null
@@ -0,0 +1,2632 @@
+.pl 10.0i
+.po 0
+.ll 7.2i
+.lt 7.2i
+.nr LL 7.2i
+.nr LT 7.2i
+.ds LF Riikonen
+.ds RF FORMFEED[Page %]
+.ds CF
+.ds LH Internet Draft
+.ds RH 12 August 2003
+.ds CH
+.na
+.hy 0
+.in 0
+.nf
+Network Working Group                                        P. Riikonen
+Internet-Draft
+draft-riikonen-silc-commands-06.txt                       12 August 2003
+Expires: 12 February 2004
+
+.in 3
+
+.ce 2
+SILC Commands
+<draft-riikonen-silc-commands-06.txt>
+
+.ti 0
+Status of this Memo
+
+This document is an Internet-Draft and is in full conformance with
+all provisions of Section 10 of RFC 2026.  Internet-Drafts are
+working documents of the Internet Engineering Task Force (IETF), its
+areas, and its working groups.  Note that other groups may also
+distribute working documents as Internet-Drafts.
+
+Internet-Drafts are draft documents valid for a maximum of six months
+and may be updated, replaced, or obsoleted by other documents at any
+time.  It is inappropriate to use Internet-Drafts as reference
+material or to cite them other than as "work in progress."
+
+The list of current Internet-Drafts can be accessed at
+http://www.ietf.org/ietf/1id-abstracts.txt
+
+The list of Internet-Draft Shadow Directories can be accessed at
+http://www.ietf.org/shadow.html
+
+The distribution of this memo is unlimited.
+
+
+.ti 0
+Abstract
+
+This memo describes the commands used in the Secure Internet Live
+Conferencing (SILC) protocol, specified in the Secure Internet Live
+Conferencing, Protocol Specification [SILC1].  The SILC Commands are
+very important part of the SILC protocol.  Usually the commands are used
+by SILC clients to manage the SILC session, but also SILC servers may
+use the commands.  This memo specifies detailed command messages and
+command reply messages.
+
+
+
+
+
+
+
+
+.ti 0
+Table of Contents
+
+.nf
+1 Introduction ..................................................  2
+  1.1 Requirements Terminology ..................................  2
+2 SILC Commands .................................................  2
+  2.1 SILC Commands Syntax ......................................  4
+  2.2 SILC Command Argument Idioms ..............................  4
+  2.3 SILC Commands List ........................................  5
+  2.4 SILC Command Status Payload ............................... 42
+3 SILC Status Types ............................................. 43
+4 Security Considerations ....................................... 50
+5 References .................................................... 50
+6 Author's Address .............................................. 51
+Appendix A ...................................................... 51
+Full Copyright Statement ........................................ 53
+
+
+.ti 0
+1. Introduction
+
+This document describes the commands used in the Secure Internet Live
+Conferencing (SILC) protocol, specified in the Secure Internet Live
+Conferencing, Protocol Specification [SILC1].  This document specifies
+detailed command messages and command reply messages.
+
+Commands are very important part on SILC network especially for client
+which uses commands to operate on the SILC network.  Commands are used
+to set nickname, join to channel, change modes and many other things.
+
+See the [SILC1] for the requirements and the restrictions for the usage
+of the SILC commands.  The [SILC2] defines the command packet type and
+the Command Payload which is actually used to deliver the commands and
+command reply messages.
+
+
+.ti 0
+1.1 Requirements Terminology
+
+The keywords MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, RECOMMENDED,
+MAY, and OPTIONAL, when they appear in this document, are to be
+interpreted as described in [RFC2119].
+
+
+.ti 0
+2 SILC Commands
+
+.ti 0
+2.1 SILC Commands Syntax
+
+This section briefly describes the syntax of the command notions
+in this document.  Every field in command is separated from each
+other by whitespaces (` ') indicating that each field is independent
+argument and each argument MUST have own Command Argument Payload.
+The number of maximum arguments are defined with each command
+separately.  The Command Argument Payload is described in [SILC2].
+
+Every command defines specific number for each argument.  Currently,
+they are defined in ascending order; first argument has number one
+(1), second has number two (2) and so on.  This number is set into the
+Argument Type field in the Command Argument Payload.  This makes it
+possible to send the arguments in free order as the number MUST be
+used to identify the type of the argument.  This makes is it also
+possible to have multiple optional arguments in commands and in
+command replies.  The number of argument is marked in parentheses
+before the actual argument.
+
+
+
+.in 6
+Example:  Arguments:  (1) <nickname> (2) <username@host>
+.in 3
+
+
+Every command replies with Status Payload.  This payload tells the
+sender of the command whether the command was completed successfully or
+whether there was an error.  If error occurred the payload includes the
+error type.  In the next section the Status Payload is not described
+as it is common to all commands and has been described here.  Commands
+MAY reply with other arguments as well.  These arguments are command
+specific and are described in the next section.
+
+Example command:
+.in 6
+
+EXAMPLE_COMMAND
+
+.in 8
+Max Arguments:  3
+    Arguments:  (1) <nickname>[@<server>]  (2) <message>
+                (3) [<count>]
+
+The command has maximum of 3 arguments.  However, only first
+and second arguments are mandatory.
+
+First argument <nickname> is mandatory but may have optional
+<nickname@server> format as well.  Second argument is mandatory
+<message> argument.  Third argument is optional <count> argument.
+
+The numbers in parentheses are the argument specific numbers
+that specify the type of the argument in Command Argument Payload.
+The receiver always knows that, say, argument number two (2) is
+<message> argument, regardless of the ordering of the arguments in
+the Command Payload.
+
+Reply messages to the command:
+
+Max Arguments:  4
+    Arguments:  (1) <Status Payload>  (2) [<channel list>]
+                (3) <idle time>       (4) [<away message>]
+
+This command may reply with maximum of 4 arguments.  However,
+only the first and third arguments are mandatory.  The numbers
+in the parentheses have the same meaning as in the upper
+command sending specification.
+
+Every command reply with <Status Payload>, it is mandatory
+argument for all command replies and for this reason it is not
+described in the command reply descriptions.
+
+
+
+Status messages:
+
+    SILC_STATUS_OK
+    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+    SILC_STATUS_ERR_NO_SUCH_NICK
+
+Every command reply also defines set of status message that it
+may return inside the <Status Payload>.  All status messages
+are defined in the section 2.3 SILC Command Status Payload
+The status messages defined with the command are recommendations.
+It is possible to return other status messages not listed with
+the command reply definition.
+.in 3
+
+
+.ti 0
+2.2 SILC Command Argument Idioms
+
+All commands that has an ID as argument (for example <Client ID>) are
+actually ID Payloads, defined in [SILC2] that includes the type of the
+ID, length of the ID and the actual ID data.  This way variable length
+ID's can be sent as arguments.
+
+All passphrases that may be sent in commands as arguments MUST be
+UTF-8 [RFC2279] encoded.  All strings, with exeption of nicknames and
+channel names [SILC1], are UTF-8 encoded.  This includes strings like
+algorithm names, quit, kick and kill messages, service identifiers and
+others.
+
+All public keys and certificates that are sent as arguments are actually
+Public Key Payloads [SILC2].  This way it is possible to send different
+kind of public keys and certificate types as arguments.
+
+
+
+
+.ti 0
+2.3 SILC Commands List
+
+This section lists all SILC commands, however, it is expected that a
+implementation and especially client implementation has many more
+commands that has only local affect.  These commands are official
+SILC commands that has both client and server sides and cannot be
+characterized as local commands.
+
+List of all defined commands in SILC follows.
+
+.in 0
+   0    SILC_COMMAND_NONE
+
+        None.  This is reserved command and MUST NOT be sent.
+
+
+   1    SILC_COMMAND_WHOIS
+
+        Max Arguments:  256
+            Arguments:  (1) [<nickname>[@<server>]]   (2) [<count>]
+                        (3) [<Requested Attributes>]  (4) [<Client ID>]
+                        (n) [...]
+
+        Whois command is used to query various information about specific
+        user.  The user may be requested by their nickname and server name.
+        The query may find multiple matching users as there are no unique
+        nicknames in the SILC.  The <count> option may be given to narrow
+        down the number of accepted results.  If this is not defined there
+        are no limit of accepted results.  The query may also be narrowed
+        down by defining the server name of the nickname.  The <count> is
+        32 bit MSB first order integer.
+
+        It is also possible to search the user by Client ID.  If the
+        <Client ID> is provided server MUST use it as the search value
+        instead of the <nickname>.  One of the arguments MUST be given.
+        It is also possible to define multiple Client ID's to search
+        multiple users sending only one WHOIS command.  In this case the
+        Client ID's are appended as normal arguments.
+
+        To prevent miss-use of this command wildcards in the nickname
+        or in the server name are not permitted.  It is not allowed
+        to request all users on some server.  The WHOIS requests MUST
+        be based on explicit nickname request.
+
+        The WHOIS request MUST be always sent to the router by server
+        so that all users are searched.  However, the server still MUST
+        search its locally connected clients.  The router MUST send
+        this command to the server which owns the requested client, if
+        the router is unable to provide all mandatory information about
+        the client.  That server MUST reply to the command.  Server MUST
+        NOT send whois replies to the client until it has received the
+        reply from its router.
+
+        The <Requested Attributes> is defined in [ATTRS] and can be used
+        to request various information about the client.  See Appendix A
+        for definition of using these attributes in SILC.
+
+        Reply messages to the command:
+
+        Max Arguments:  11
+            Arguments:  (1) <Status Payload>       (2) <Client ID>
+                        (3) <nickname>[@<server>]  (4) <username@host>
+                        (5) <real name>            (6) [<Channel Payload
+                                                         list>]
+                        (7) [<user mode>]          (8) [<idle time>]
+                        (9) [<fingerprint>]        (10) <channel user
+                                                         mode list>
+                        (11) [<Attributes>]
+
+
+        This command may reply with several command reply messages to
+        form a list of results.  In this case the status payload will
+        include STATUS_LIST_START status in the first reply and
+        STATUS_LIST_END in the last reply to indicate the end of the
+        list.  If there are only one reply the status is set to normal
+        STATUS_OK.  If multiple Client IDs was requested then each found
+        and unfound client MUST cause successful or error reply,
+        respectively.
+
+        The command replies include the Client ID of the nickname,
+        nickname and server name, user name and host name and user's real
+        name.  Client should process these replies only after the last
+        reply has been received with the STATUS_LIST_END status.  If the
+        <count> option were defined in the query there will be only
+        <count> many replies from the server.
+
+        The server returns the list of channels if the client has
+        joined channels.  In this case the list is list of Channel
+        Payloads.  The Mode Mask in the Channel Payload is the channel's
+        mode.  The list is encoded by adding the Channel Payloads one
+        after the other.  Private and secret channels MUST NOT be sent,
+        except if the sender of this command is on those channels, or
+        the sender is server.  The <channel user mode list> MUST also
+        be sent if client is joined channels.  This list includes 32 bit
+        MSB first order values one after the other and each indicate
+        the user's mode on a channel.  The order of these values MUST
+        be same as the channel order in the <Channel Payload list>.
+
+        The server also returns client's user mode, idle time, and the
+        fingerprint of the client's public key.  The <fingerprint> is the
+        binary hash digest of the public key.  The fingerprint MUST NOT
+        be sent if the server has not verified the proof of possession of
+        the corresponding private key.  Server can do this during the
+        SILC Key Exchange protocol.  The <fingerprint> is SHA1 digest.
+
+        The <Attributes> is the reply to the <Requested Attributes>.
+        See the Appendix A for more information.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_LIST_START
+            SILC_STATUS_LIST_END
+            SILC_STATUS_ERR_NO_SUCH_NICK
+            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+            SILC_STATUS_ERR_WILDCARDS
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+
+
+   2    SILC_COMMAND_WHOWAS
+
+        Max Arguments:  2
+            Arguments:  (1) <nickname>[@<server>]  (2) [<count>]
+
+        Whowas.  This command is used to query history information about
+        specific user.  The user may be requested by their nickname and
+        server name.  The query may find multiple matching users as there
+        are no unique nicknames in the SILC.  The <count> option may be
+        given to narrow down the number of accepted results.  If this
+        is not defined there are no limit of accepted results.  The query
+        may also be narrowed down by defining the server name of the
+        nickname.  The <count> is 32 bit MSB first order integer.
+
+        To prevent miss-use of this command wildcards in the nickname
+        or in the server name are not permitted.  The WHOWAS requests MUST
+        be based on specific nickname request.
+
+        The WHOWAS request MUST be always sent to the router by server
+        so that all users are searched.  However, the server still must
+        search its locally connected clients.
+
+        Reply messages to the command:
+
+        Max Arguments:  5
+            Arguments:  (1) <Status Payload>        (2) <Client ID>
+                        (3) <nickname>[@<server>]   (4) <username@host>
+                        (5) [<real name>]
+
+        This command may reply with several command reply messages to form
+        a list of results.  In this case the status payload will include
+        STATUS_LIST_START status in the first reply and STATUS_LIST_END in
+        the last reply to indicate the end of the list.  If there are only
+        one reply the status is set to normal STATUS_OK.
+
+        The command replies with nickname and user name and host name.
+        Every server MUST keep history for some period of time of its
+        locally connected clients.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_LIST_START
+            SILC_STATUS_LIST_END
+            SILC_STATUS_ERR_NO_SUCH_NICK
+            SILC_STATUS_ERR_WILDCARDS
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+
+
+   3    SILC_COMMAND_IDENTIFY
+
+        Max Arguments:  256
+            Arguments:  (1) [<nickname>[@<server>]]  (2) [<server name>]
+                        (3) [<channel name>]         (4) [<count>]
+                        (5) [<ID Payload>]           (n) [...]
+
+        Identify command is used to query information about an entity by
+        the entity's name or ID.  This command can be used to query
+        information about clients, servers and channels.
+
+        The query may find multiple matching entities.  The <count> option
+        may be given to narrow down the number of accepted results.  If
+        this is not defined there are no limit of accepted results.  The
+        <count> is 32 bit MSB first order integer.
+
+        It is also possible to search the entity by its ID.  If the
+        <ID Payload> is provided server must use it as the search value
+        instead of the entity's name.  One of the arguments MUST be given.
+        It is also possible to define multiple ID Payloads to search
+        multiple entities sending only one IDENTIFY command.  In this case
+        the ID Payloads are appended as normal arguments.  The type of the
+        entity is defined by the type of the ID Payload.
+
+        To prevent miss-use of this command wildcards in the names are
+        not permitted.  It is not allowed to request for example all users
+        on server.
+
+        Implementations may not want to give interface access to this
+        command as it is hardly a command that would be used by an end
+        user.  However, it must be implemented as it is most likely used
+        with private message sending.
+
+        The IDENTIFY command MUST be always sent to the router by server
+        so that all users are searched.  However, server MUST still search
+        its locally connected clients.
+
+        Reply messages to the command:
+
+        Max Arguments:  4
+            Arguments:  (1) <Status Payload>   (2) <ID Payload>
+                        (3) [<entity's name>]  (4) [<info>]
+
+        This command may reply with several command reply messages to form
+        a list of results.  In this case the status payload will include
+        STATUS_LIST_START status in the first reply and STATUS_LIST_END in
+        the last reply to indicate the end of the list.  If there are only
+        one reply the status is set to normal STATUS_OK.  If multiple Client
+        IDs was requested then each found and unfound client must cause
+        successful or error reply, respectively.
+
+        When querying clients the <entity's name> must include the client's
+        nickname in the following format: nickname[@server].  The
+        <info> must include the client's username and host in the following
+        format: username@host.
+
+        When querying servers the <entity's name> must include the server's
+        full name.  The <info> may be omitted.
+
+        When querying channels the <entity's name> must include the
+        channel's name.  The <info> may be omitted.
+
+        If the <count> option were defined in the query there will be only
+        <count> many replies from the server.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_LIST_START
+            SILC_STATUS_LIST_END
+            SILC_STATUS_ERR_NO_SUCH_NICK
+            SILC_STATUS_ERR_NO_SUCH_SERVER
+            SILC_STATUS_ERR_NO_SUCH_CHANNEL
+            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+            SILC_STATUS_ERR_NO_SUCH_SERVER_ID
+            SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+            SILC_STATUS_ERR_WILDCARDS
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+
+
+   4    SILC_COMMAND_NICK
+
+        Max Arguments:  1
+            Arguments:  (1) <nickname>
+
+        Set/change nickname.  This command is used to set nickname for
+        user.  Nickname MUST NOT include any whitespaces (` '),
+        non-printable characters, commas (`,'), '@', '!' or any wildcard
+        characters.
+
+        When nickname is changed new Client ID is generated.  Server MUST
+        distribute SILC_NOTIFY_TYPE_NICK_CHANGE to local clients on the
+        channels (if any) the client is joined on.  Then it MUST send
+        SILC_NOTIFY_TYPE_NICK_CHANGE notify to its primary route to
+        notify about nickname and Client ID change.
+
+        Reply messages to the command:
+
+        Max Arguments:  3
+            Arguments:  (1) <Status Payload>  (2) <New ID Payload>
+                        (3) <nickname>
+
+        This command replies always with <New ID Payload> that is
+        generated by the server every time user changes their nickname.
+        Client receiving this payload MUST start using the received
+        Client ID as its current valid Client ID.  The New ID Payload
+        is described in [SILC2].  The <nickname> is the user's new
+        nickname.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_WILDCARDS
+            SILC_STATUS_ERR_NICKNAME_IN_USE
+            SILC_STATUS_ERR_BAD_NICKNAME
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+
+
+   5    SILC_COMMAND_LIST
+
+        Max Arguments:  1
+            Arguments:  (1) [<Channel ID>]
+
+        The list command is used to list channels and their topics on the
+        current server.  If the <Channel ID> parameter is used, only the
+        status of that channel is displayed.  Secret channels are not
+        listed at all.  Private channels are listed with status indicating
+        that the channel is private.  Router MAY reply with all channels
+        it knows about.
+
+        Reply messages to the command:
+
+        Max Arguments:  5
+            Arguments:  (1) <Status Payload>  (2) <Channel ID>
+                        (3) <channel>         (4) [<topic>]
+                        (5) [<user count>]
+
+        This command may reply with several command reply messages to form
+        a list of results.  In this case the status payload will include
+        STATUS_LIST_START status in the first reply and STATUS_LIST_END in
+        the last reply to indicate the end of the list.  If there are only
+        one reply the status is set to normal STATUS_OK.
+
+        This command replies with Channel ID, name and the topic of the
+        channel.  If the channel is private channel the <topic> SHOULD
+        include the "*private*" string.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_LIST_START
+            SILC_STATUS_LIST_END
+            SILC_STATUS_ERR_WILDCARDS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+            SILC_STATUS_ERR_NO_CHANNEL_ID
+            SILC_STATUS_ERR_NO_SUCH_SERVER
+
+
+   6    SILC_COMMAND_TOPIC
+
+        Max Arguments:  2
+            Arguments:  (1) <Channel ID>  (2) [<topic>]
+
+        This command is used to change or view the topic of a channel.
+        The topic for channel <Channel ID> is returned if there is no
+        <topic> given.  If the <topic> parameter is present, the topic
+        for that channel will be changed, if the channel modes permit
+        this action.
+
+        After setting the topic the server MUST send the notify type
+        SILC_NOTIFY_TYPE_TOPIC_SET to its primary router and then to
+        the channel which topic was changed.
+
+        Reply messages to the command:
+
+        Max Arguments:  2
+            Arguments:  (1) <Status Payload>  (2) <Channel ID>
+                        (3) [<topic>]
+
+        The command may reply with the topic of the channel if it is
+        set.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_ON_CHANNEL
+            SILC_STATUS_ERR_WILDCARDS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_NO_SUCH_CHANNEL
+            SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+            SILC_STATUS_ERR_NO_CHANNEL_ID
+            SILC_STATUS_ERR_BAD_CHANNEL_ID
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NO_CHANNEL_PRIV
+
+
+   7    SILC_COMMAND_INVITE
+
+        Max Arguments:  4
+            Arguments:  (1) <Channel ID>       (2) [<Client ID>]
+                        (3) [<add | del>]      (4) [<invite list>]
+
+        This command can be used to invite other clients to join to a
+        channel, and to manage the channel's invite list.  The <Client
+        ID> argument is the target client's ID that is being invited.
+        The <Channel ID> is the Channel ID of the requested channel.
+        The sender of this command MUST be on the channel.  The server
+        MUST also send the notify type SILC_NOTIFY_TYPE_INVITE to its
+        primary router and then to the client indicated by the <Client
+        ID>.
+
+        The <add | del> is an argument of size of 1 byte where 0x00 means
+        adding a client to invite list, and 0x01 means deleting a client
+        from invite list.  The <invite list>, if present, indicates
+        the information to be added to or removed from the invite list.
+        It may include a string for matching clients, public key of a
+        client (Public Key Payload) or Client ID of a client.  The
+        <invite list> is an Argument List Payload.
+
+        The following Argument Types has been defined for invite list
+        Argument Payloads:
+
+          0x01 - Argument is an invite string of following format:
+
+            [<nickname>[@<server>]!][<username>]@[<hostname or IP/MASK>]
+
+            The <hostname> may also be in format of IP/MASK to indicate
+            a network, for example 10.2.1.0/255.255.0.0.
+
+          0x02 - Argument is the public key of a client
+          0x03 - Argument is the Client ID of a client
+
+        If unknown type value is received or there is invalid amount of
+        Argument Payloads present in the list, the command MUST be
+        discarded.  When argument that is to be deleted from the invite
+        list does not exist in the list the argument is ignored.
+
+        When adding to or removing from the invite list the server MUST
+        send the notify type SILC_NOTIFY_TYPE_INVITE to its primary router.
+        When the SILC_CHANNEL_MODE_INVITE is set the client which executes
+        this command MUST have at least channel operator privileges to be
+        able to add to or remove from the invite list.  If this channel
+        mode is not set the list manipulation is allowed for all clients.
+        Wildcards MAY be used with this command.  When this command is
+        used to invite explicit client with <Client ID> the ID MUST be
+        added to the invite list by the server.
+
+        When this command is given with only <Channel ID> argument then
+        the command merely returns the invite list of the channel.   This
+        command MUST fail if the requested channel does not exist, the
+        requested <Client ID> is already on the channel or if the channel
+        is invite only channel and the caller of this command does not
+        have at least channel operator privileges on the channel.
+
+        Reply messages to the command:
+
+        Max Arguments:  3
+            Arguments:  (1) <Status Payload>  (2) <Channel ID>
+                        (3) [<invite list>]
+
+       This command replies with the invite list of the channel if it
+       exists.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+            SILC_STATUS_ERR_NO_CLIENT_ID
+            SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+            SILC_STATUS_ERR_NO_CHANNEL_ID
+            SILC_STATUS_ERR_NOT_ON_CHANNEL
+            SILC_STATUS_ERR_USER_ON_CHANNEL
+            SILC_STATUS_ERR_NO_CHANNEL_PRIV
+            SILC_STATUS_ERR_RESOURCE_LIMIT
+
+
+   8    SILC_COMMAND_QUIT
+
+        Max Arguments:  1
+            Arguments:  (1) [<quit message>]
+
+        This command is used by client to end SILC session.  The server
+        must close the connection to a client which sends this command.
+        if <quit message> is given it will be sent to other clients on
+        channel if the client is on channel when quitting.
+
+        Reply messages to the command:
+
+        This command does not reply anything.
+
+
+    9   SILC_COMMAND_KILL
+
+        Max Arguments:  3
+            Arguments:  (1) <Client ID>          (2) [<comment>]
+                        (3) [<auth payload>]
+
+        This command can be used by SILC operators to remove a client from
+        SILC network.  It also can be used by a normal client to remove
+        its own client from network by providing correct authentication
+        data.
+
+        Router operator killing a client:
+
+        The removing has temporary effects and client may reconnect to
+        SILC network.  The <Client ID> is the client to be removed from SILC.
+        The <comment> argument may be provided to give to the removed client
+        some information why it was removed from the network.  The killer
+        MUST have SILC operator privileges.
+
+        When killing a client the router MUST first send notify type
+        SILC_NOTIFY_TYPE_KILLED to all channels the client has joined.
+        The packet MUST NOT be sent to the killed client on the channels.
+        Then, the router MUST send the same notify type to its primary
+        router.  Finally, the router MUST send the same notify type
+        destined directly to the client which was killed.  The killed
+        client MUST also be removed from the invite lists of joined
+        channels if it is explicitly added in the invite lists.
+
+        Normal client killing by authentication:
+
+        When normal client executes this command the <Client ID> is the
+        destination client to be removed from the network.  The client
+        MUST provide the <auth payload> which includes a digital signature
+        that MUST be verified with the public key of the client indicated
+        by <Client ID>.  The <Client ID> MUST be local client to the server.
+        If the signature verification is successful the server sends
+        SILC_NOTIFY_TYPE_SIGNOFF to network and to the destination client.
+        The SILC_NOTIFY_TYPE_KILLED MUST NOT be used in this case.  If the
+        verification fails the destination client remains in network.
+        The hash function used in <auth payload> computing is SHA1.
+
+        Reply messages to the command:
+
+        Max Arguments:  2
+            Arguments:  (1) <Status Payload>  (2) <Client ID>
+
+        This command returns with the requested Client ID.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_WILDCARDS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+            SILC_STATUS_ERR_NO_CLIENT_ID
+            SILC_STATUS_ERR_NO_ROUTER_PRIV
+
+
+   10   SILC_COMMAND_INFO
+
+        Max Arguments:  2
+            Arguments:  (1) [<server>]  (2) [<Server ID>]
+
+        This command is used to fetch various information about a server.
+        If <server> argument is specified the command MUST be sent to
+        the requested server.
+
+        If the <Server ID> is specified the server information if fetched
+        by the provided Server ID.  One of the arguments MUST always be
+        present.
+
+        Reply messages to the command:
+
+        Max Arguments:  4
+            Arguments:  (1) <Status Payload>  (2) <Server ID>
+                        (3) <server name>     (4) <string>
+
+        This command replies with the Server ID of the server and a
+        string which tells the information about the server.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_WILDCARDS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NO_SUCH_SERVER
+            SILC_STATUS_ERR_NO_SUCH_SERVER_ID
+            SILC_STATUS_ERR_NO_SERVER_ID
+
+
+   11   SILC_COMMAND_STATS
+
+        Max Arguments:  1
+            Arguments:  (1) <Server ID>
+
+        This command is used to fetch various statistical information
+        from the server indicated by <Server ID>, which is the ID of
+        server where sender is connected to.  Server receiving this
+        command MAY also send this further to its router for fetching
+        other cell and network wide statistics to accompany the reply.
+
+        Reply messages to the command:
+
+        Max Arguments:  3
+            Arguments:  (1) <Status Payload>          (2) <Server ID>
+                        (3) [<statistics structure>]
+
+        This command replies with the Server ID of the server and
+        optional statistics structure which includes 32 bit MSB first
+        ordered integer values to represent various statistical
+        information.  The structure is as follows:
+
+          starttime      - time when server was started
+          uptime         - uptime of the server
+          my clients     - number of locally connected clients
+          my channels    - number of locally created channels
+          my server ops  - number of local server operators
+          my router ops  - number of local router operators
+          cell clients   - number of clients in local cell
+          cell channels  - number of channels in local cell
+          cell servers   - number of servers in local cell
+          clients        - number of client in SILC network
+          channels       - number of channels in SILC network
+          servers        - number of servers in SILC network
+          routers        - number of routers in SILC network
+          server ops     - number of server operators in SILC network
+          router ops     - number of router operators in SILC network
+
+        If some value is unknown it is set to zero (0) value.  The
+        "starttime" is the start time of the server, and is seconds
+        since Epoch (POSIX.1).  The "uptime" is time difference of
+        current time and "starttime" in the server, and is seconds
+        in value.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NO_SUCH_SERVER_ID
+            SILC_STATUS_ERR_NO_SUCH_SERVER
+            SILC_STATUS_ERR_NO_SERVER_ID
+
+
+   12   SILC_COMMAND_PING
+
+        Max Arguments:  1
+            Arguments:  (1) <Server ID>
+
+        This command is used by client and server to test the communication
+        channel to its server if one suspects that the communication is not
+        working correctly.  The <Server ID> is the ID of the server the
+        sender is connected to.
+
+        Reply messages to the command:
+
+        Max Arguments:  1
+            Arguments:  (1) <Status Payload>
+
+        This command replies only with Status Payload.  Server returns
+        SILC_STATUS_OK in Status Payload if pinging was successful.
+
+
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NO_SERVER_ID
+            SILC_STATUS_ERR_NO_SUCH_SERVER
+            SILC_STATUS_ERR_NOT_REGISTERED
+
+
+   13   SILC_COMMAND_OPER
+
+        Max Arguments:  2
+            Arguments:  (1) <username>  (2) <authentication payload>
+
+        This command is used by normal client to obtain server operator
+        privileges on some server or router.  Note that router operator
+        has router privileges that supersedes the server operator
+        privileges and this does not obtain those privileges.  Client
+        MUST use SILCOPER command to obtain router level privileges.
+
+        The <username> is the username set in the server configurations
+        as operator.  The <authentication payload> is the data that the
+        client is authenticated against.  It may be passphrase prompted
+        for user on client's screen or it may be public key authentication
+        based on digital signatures.  The public key used to verify the
+        signature should be locally saved in the server, and server should
+        not use public key received during the SKE to verify this signature.
+
+        After changing the mode the server MUST send the notify type
+        SILC_NOTIFY_TYPE_UMODE_CHANGE to its primary router.
+
+        Reply messages to the command:
+
+        Max Arguments:  1
+            Arguments:  (1) <Status Payload>
+
+        This command replies only with Status Payload.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_AUTH_FAILED
+
+
+   14   SILC_COMMAND_JOIN
+
+        Max Arguments:  7
+            Arguments:  (1) <channel>         (2) <Client ID>
+                        (3) [<passphrase>]    (4) [<cipher>]
+                        (5) [<hmac>]          (6) [<founder auth>]
+                        (7) [<channel auth>]
+
+        Join to channel/create new channel.  This command is used to
+        join to a channel.  If the channel does not exist the channel is
+        created.  If server is normal server this command MUST be sent
+        to router which will create the channel.  The channel MAY be
+        protected with passphrase.  If this is the case the passphrase
+        MUST be sent along the join command.
+
+        The name of the <channel> MUST NOT include any spaces (` '),
+        non-printable characters, commas (`,') or any wildcard characters.
+
+        The second argument <Client ID> is the Client ID of the client
+        which is joining to the client.  When client sends this command
+        to the server the <Client ID> MUST be the client's own ID.
+
+        Cipher to be used to secure the traffic on the channel MAY be
+        requested by sending the name of the requested <cipher>.  This
+        is used only if the channel does not exist and is created.  If
+        the channel already exists the cipher set previously for the
+        channel will be used to secure the traffic.  The computed MACs
+        of the channel message are produced by the default HMAC or by
+        the <hmac> provided for the command.
+
+        The <founder auth> is Authentication Payload providing the
+        authentication for gaining founder privileges on the channel
+        when joining the channel.  The client may provide this if it
+        knows that it is the founder of the channel and that the
+        SILC_CMODE_FOUNDER_AUTH mode is set on the channel.  The server
+        MUST verify whether the client is able to gain the founder
+        privileges the same way as the client had given the
+        SILC_COMMAND_CUMODE command to gain founder privileges.  The
+        client is still able to join the channel even if the founder
+        privileges could not be gained.  The hash function used with
+        the <founder payload> MUST be sha1.
+
+        If the <channel auth> is present and the channel mode
+        SILC_CMODE_CHANNEL_AUTH is set the server MUST verify the
+        <channel auth> with channel public key(s).  If public key that
+        can verify <channel auth> does not exist on the channel public
+        key list the client MUST NOT be allowed to join the channel.
+        Because more than one public key may be set on channel the
+        <channel auth> Authentication Payload's Public Data field
+        MUST include an indication of the public key to be used.  The
+        first 20 bytes of the Public Data field MUST be SHA-1 digest of
+        the public key that must be used in verification.  Rest of the
+        Public Data field are set as defined in [SILC1].  This way server
+        can determine from the digest whether that public key exist on the
+        channel and then use that key in verification.  The hash function
+        used with <channel auth> MUST be sha1.
+
+        The server MUST check whether the user is allowed to join to
+        the requested channel.  Various modes set to the channel affect
+        the ability of the user to join the channel.  These conditions
+        are:
+
+            o  The user MUST be invited to the channel if the channel
+               is invite-only channel.
+
+            o  The Client ID/nickname/username/host name/public key
+               MUST NOT match any active bans.
+
+            o  The correct passphrase MUST be provided if passphrase
+               is set to the channel, and/or digital signature verification
+               with channel public key MUST be successful if public keys
+               has been set to the channel.
+
+            o  The user count limit, if set, MUST NOT be reached.
+
+        If the client provided correct <founder auth> payload it can
+        override these conditions, except the condition for the passphrase.
+        The correct passphrase MUST be provided even if <founder auth>
+        payload is provided.
+
+        Reply messages to the command:
+
+        Max Arguments:  16
+            Arguments:  (1) <Status Payload>        (2) <channel>
+                        (3) <Channel ID>            (4) <Client ID>
+                        (5) <channel mode mask>     (6) <created>
+                        (7) [<Channel Key Payload>] (8) [<ban list>]
+                        (9) [<invite list>]         (10) [<topic>]
+                        (11) [<hmac>]               (12) <list count>
+                        (13) <Client ID list>       (14) <client mode list>
+                        (15) [<founder pubkey>]     (16) [<channel pubkeys>]
+
+        This command replies with the channel name requested by the
+        client, channel ID of the channel and topic of the channel
+        if it exists.  The <Client ID> is the Client ID which was joined
+        to the channel.  It also replies with the channel mode mask
+        which tells all the modes set on the channel.  If the channel
+        is created the mode mask is zero (0) and <created> is 0x01.
+        If ban mask and/or invite list is set they are sent as well.
+
+        The <list count>, <Client ID list> and <client mode list> are
+        the clients currently on the channel and their modes on the
+        channel.  The <Client ID list> is formed by adding the ID Payloads
+        one after the other.  The <client mode list> is formed by adding
+        32 bit MSB first order values one after the other.  The <founder
+        pubkey> is the public key (or certificate) of the channel founder.
+        The <channel pubkeys> is Argument List Payload containing the
+        channel public keys that has been set for the channel.
+
+        Client receives the channel key in the reply message as well
+        inside <Channel Key Payload>.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_WILDCARDS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_BAD_PASSWORD
+            SILC_STATUS_ERR_CHANNEL_IS_FULL
+            SILC_STATUS_ERR_NOT_INVITED
+            SILC_STATUS_ERR_BANNED_FROM_CHANNEL
+            SILC_STATUS_ERR_BAD_CHANNEL
+            SILC_STATUS_ERR_USER_ON_CHANNEL
+
+
+   15   SILC_COMMAND_MOTD
+
+        Max Arguments:  1
+            Arguments:  (1) <server>
+
+        This command is used to query the Message of the Day of the server.
+
+        Reply messages to the command:
+
+        Max Arguments:  3
+            Arguments:  (1) <Status Payload>  (2) <Server ID>
+                        (3) [<motd>]
+
+        This command replies with the motd message if it exists.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NO_SUCH_SERVER
+
+
+   16   SILC_COMMAND_UMODE
+
+        Max Arguments:  2
+            Arguments:  (1) <Client ID>  (2) [<client mode mask>]
+
+        This command is used by client to set/unset modes for itself.
+        However, there are some modes that the client MUST NOT set itself,
+        but they will be set by server.  However, client MAY unset any
+        mode.  Modes may be masked together ORing them thus having
+        several modes set.  Client MUST keep its client mode mask
+        locally so that the mode setting/unsetting would work without
+        problems.  Client may change only its own modes.
+
+        After changing the mode server MUST send the notify type
+        SILC_NOTIFY_TYPE_UMODE_CHANGE to its primary router.
+
+        The following client modes are defined:
+
+           0x00000000    SILC_UMODE_NONE
+
+              No specific mode for client.  This is the initial
+              setting when new client is created.  The client is
+              normal client and is present in the network.
+
+
+           0x00000001    SILC_UMODE_SERVER_OPERATOR
+
+              Marks the user as server operator.  Client MUST NOT
+              set this mode itself.  Server sets this mode to the
+              client when client attains the server operator
+              privileges by SILC_COMMAND_OPER command.  Client
+              MAY unset the mode itself.
+
+
+           0x00000002    SILC_UMODE_ROUTER_OPERATOR
+
+              Marks the user as router (SILC) operator.  Client
+              MUST NOT set this mode itself.  Router sets this mode
+              to the client when client attains the router operator
+              privileges by SILC_COMMAND_SILCOPER command.  Client
+              MAY unset the mode itself.
+
+
+           0x00000004    SILC_UMODE_GONE
+
+              Marks that the user is not currently present in the
+              SILC Network.  Client MAY set and unset this mode.
+
+
+           0x00000008    SILC_UMODE_INDISPOSED
+
+              Marks that the user is currently indisposed and may
+              not be able to receive any messages, and that user may
+              not be present in the network.  Client MAY set and
+              unset this mode.
+
+
+           0x00000010    SILC_UMODE_BUSY
+
+              Marks that the user is currently busy and may not
+              want to receive any messages, and that user may not
+              be present in the network.  Client MAY set and unset
+              this mode.
+
+
+           0x00000020    SILC_UMODE_PAGE
+
+              User is not currently present or is unable to receive
+              messages, and prefers to be paged in some mechanism
+              if the user needs to be reached.  Client MAY set and
+              unset this mode.
+
+
+           0x00000040    SILC_UMODE_HYPER
+
+              Marks that the user is hyper active and is eager to
+              receive and send messages.   Client MAY set and unset
+              this mode.
+
+
+           0x00000080    SILC_UMODE_ROBOT
+
+              Marks that the client is actually a robot program.
+              Client MAY set and unset this mode.
+
+
+           0x00000100    SILC_UMODE_ANONYMOUS
+
+              Marks that the client is anonymous client.  Server
+              that specifically is designed for anonymous services
+              can set and unset this mode.  Client MUST NOT set or
+              unset this mode itself.  A client with this mode set
+              would have the username and the hostname information
+              scrambled by the server which set this mode.
+
+
+           0x00000200    SILC_UMODE_BLOCK_PRIVMSG
+
+              Marks that the client wishes to block private
+              messages sent to the client, unless the Private
+              Message Key flag is set in the SILC packet header.
+              If this mode is set server MUST NOT deliver private
+              messages to the client without the Private Message
+              Key flag being set.  The Private Message Key flag set
+              indicates that the private message is protected with
+              a key shared between the sender and the recipient.
+
+              A separate service could provide additional filtering
+              features for accepting private messages from certain
+              sender.  However, this document does not specify such
+              service.
+
+              The client MAY set and unset this mode.
+
+
+           0x00000400    SILC_UMODE_DETACHED
+
+              Marks that the client is detached from the SILC network.
+              This means that the actual network connection to the
+              client is lost but the client entry is still valid.  The
+              detached client can be resumed at a later time.  This
+              mode MUST NOT be set by client.  It can only be set when
+              client has issued command SILC_COMMAND_DETACH.  The server
+              sets this mode.  This mode cannot be unset with this
+              command.  It is unset when the client is resuming back to
+              the network and SILC_PACKET_RESUME_CLIENT packet is
+              received.
+
+              This flag MUST NOT be used to determine whether a packet
+              can be sent to the client or not.  Only the server that
+              had the original client connection can make the decision
+              by knowing that the network connection is not active.
+              In this case the default case is to discard the packet.
+
+
+           0x00000800    SILC_UMODE_REJECT_WATCHING
+
+              Marks that the client rejects that it could be watched
+              by someone else.  If this mode is set notifications about
+              this client is not send, even if someone is watching the
+              same nickname this client has.  Client MAY set and unset
+              this mode.  Any changes for this client MUST NOT be
+              notified to any watcher when this mode is set.
+
+              A separate service could provide additional filtering
+              features for rejecting and accepting the watching from
+              certain users.  However, this document does not specify
+              such service.
+
+
+           0x00001000    SILC_UMODE_BLOCK_INVITE
+
+              Marks that the client wishes to block incoming invite
+              notifications.  Client MAY set and unset this mode.
+              When set server does not deliver invite notifications
+              to the client.  Note that this mode may make it harder
+              to join invite-only channels.
+
+        If the <client mode mask> was not provided this command merely
+        returns the mode mask to the client.
+
+
+        Reply messages to the command:
+
+        Max Arguments:  2
+            Arguments:  (1) <Status Payload>  (2) <client mode mask>
+
+        This command replies with the changed client mode mask that
+        the client MUST to keep locally.
+
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+            SILC_STATUS_ERR_BAD_CLIENT_ID
+            SILC_STATUS_ERR_NOT_YOU
+            SILC_STATUS_ERR_PERM_DENIED
+            SILC_STATUS_ERR_UNKNOWN_MODE
+            SILC_STATUS_ERR_NO_CLIENT_ID
+
+
+   17   SILC_COMMAND_CMODE
+
+        Max Arguments:  9
+            Arguments:  (1) <Channel ID>      (2) [<channel mode mask>]
+                        (3) [<user limit>]    (4) [<passphrase>]
+                        (5) [<cipher>]        (6) [<hmac>]
+                        (7) [<auth payload>]  (8) [<founder pubkey>]
+                        (9) [<channel pubkey>]
+
+        This command is used by client to set or change channel flags on
+        a channel.  Channel has several modes that set various properties
+        of a channel.  Modes may be masked together by ORing them thus
+        having several modes set.  The <Channel ID> is the ID of the
+        target channel.  The client changing channel mode MUST be on
+        the same channel and posses sufficient privileges to be able to
+        change the mode.
+
+        When the mode is changed SILC_NOTIFY_TYPE_CMODE_CHANGE notify
+        type MUST be distributed to the channel.
+
+        The following channel modes are defined:
+
+           0x00000000    SILC_CMODE_NONE
+
+              No specific mode on channel.  This is the default when
+              channel is created.  This means that channel is just plain
+              normal channel.
+
+
+           0x00000001    SILC_CMODE_PRIVATE
+
+              Channel is private channel.  Private channels are shown
+              in the channel list listed with SILC_COMMAND_LIST command
+              with indication that the channel is private.  Also,
+              client on private channel will no be detected to be on
+              the channel as the channel is not shown in the client's
+              currently joined channel list.  Channel founder and
+              channel operator MAY set/unset this mode.
+
+
+           0x00000002    SILC_CMODE_SECRET
+
+              Channel is secret channel.  Secret channels are not shown
+              in the list listed with SILC_COMMAND_LIST command.  Secret
+              channels can be considered to be invisible channels.
+              Channel founder and channel operator MAY set/unset this
+              mode.
+
+
+           0x00000004    SILC_CMODE_PRIVKEY
+
+              Channel uses private channel key to protect the traffic
+              on the channel.  When this mode is set the client will be
+              responsible to set the key it wants to use to encrypt and
+              decrypt the traffic on channel.  Server generated channel
+              keys are not used at all.  This mode provides additional
+              security as clients on channel may agree to use private
+              channel key that even servers do not know.  Naturally,
+              this requires that every client on the channel knows
+              the key before hand (it is considered to be pre-shared-
+              key).  The key material SHOULD be processed as stated
+              in the [SILC3] in the section Processing the Key Material.
+
+              As it is local setting it is possible to have several
+              private channel keys on one channel.  In this case several
+              clients can talk on same channel but only those clients
+              that share the key with the message sender will be able
+              to hear the talking.  Client SHOULD NOT display those
+              message for the end user that it is not able to decrypt
+              when this mode is set.
+
+              Only channel founder MAY set/unset this mode.  If this
+              mode is unset the server will distribute new channel
+              key to all clients on the channel which will be used
+              thereafter.
+
+
+           0x00000008    SILC_CMODE_INVITE
+
+              Channel is invite only channel.  Client may join to this
+              channel only if it is invited to the channel.  Channel
+              founder and channel operator MAY set/unset this mode.
+
+
+           0x00000010    SILC_CMODE_TOPIC
+
+              The topic of the channel may only be set by client that
+              is channel founder or channel operator.  Normal clients
+              on channel will not be able to set topic when this mode
+              is set.  Channel founder and channel operator MAY set/
+              unset this mode.
+
+
+           0x00000020    SILC_CMODE_ULIMIT
+
+              User limit has been set to the channel.  New clients
+              may not join to the channel when the limit set is
+              reached.  Channel founder and channel operator MAY set/
+              unset the limit.  The <user limit> argument is the
+              number of limited users.
+
+
+           0x00000040    SILC_CMODE_PASSPHRASE
+
+              Passphrase has been set to the channel.  Client may
+              join to the channel only if it is able to provide the
+              correct passphrase.  Setting passphrases to channel
+              is entirely safe as all commands are protected in the
+              SILC network.  Only channel founder MAY set/unset
+              the passphrase.  The <passphrase> argument is the
+              set passphrase.
+
+
+           0x00000080    SILC_CMODE_CIPHER
+
+              Sets specific cipher to be used to protect channel
+              traffic.  The <cipher> argument is the requested cipher.
+              When set or unset the server must re-generate new
+              channel key.  Only channel founder MAY set the cipher of
+              the channel.  When unset the new key is generated using
+              default cipher for the channel.
+
+
+           0x00000100    SILC_CMODE_HMAC
+
+              Sets specific hmac to be used to compute the MACs of the
+              channel message.  The <hmac> argument is the requested hmac.
+              Only channel founder may set the hmac of the channel.
+
+
+           0x00000200    SILC_CMODE_FOUNDER_AUTH
+
+              Channel founder may set this mode to be able to regain
+              channel founder rights even if the client leaves the
+              channel.  The <auth payload> is the Authentication Payload
+              consisting of the public key authentication method and the
+              digital signature for that method.  The passphrase or NONE
+              authentication methods MUST NOT be accepted.
+
+              The server does not save <auth payload> but MUST verify it.
+              The public key used to verify the payload is the <founder
+              pubkey> if present, or the public key of the client sending
+              this command.  If <founder pubkey> is present also that
+              public key MUST be saved as founder's public key.  This
+              mode may be set only if the <auth payload> was verified
+              successfully.  The hash function used with the <auth
+              payload> MUST be sha1.
+
+              The public key of the founder is sent in the
+              SILC_NOTIFY_TYPE_CMODE_CHANGE notify type so that other
+              routers and servers in the network may save the public key.
+              This way the founder can reclaim the founder rights back
+              to the channel from any server in the network.  The founder
+              rights can be regained by the SILC_CUMODE_FOUNDER channel
+              user mode, or during joining procedure with the command
+              SILC_COMMAND_JOIN.
+
+              If this mode is already set but the <founder pubkey> is
+              different the new key will replace the old founder key and
+              the new key is distributed in the network with the
+              SILC_NOTIFY_TYPE_CMODE_CHANGE notify.  Only the original
+              founder may set this mode multiple times and the client
+              MUST have SILC_CUMODE_FOUNDER mode on the channel.
+
+              When this channel mode is set the channel also becomes
+              permanent.  If all clients leave the channel while this
+              mode is set the channel MUST NOT be destroyed.  The founder
+              can reclaim the founder mode back on these empty channels
+              at any time.  Implementations MAY limit the number of how
+              many channels a user can own and how long they remain
+              persistent.
+
+
+           0x00000400    SILC_CMODE_SILENCE_USERS
+
+              Channel founder may set this mode to silence normal users
+              on the channel.  Users with operator privileges are not
+              affected by this mode.  Messages sent by normal users
+              are dropped by servers when this mode is set.  This mode
+              can be used to moderate the channel.  Only channel founder
+              may set/unset this mode.
+
+
+           0x00000800    SILC_CMODE_SILENCE_OPERS
+
+              Channel founder may set this mode to silence operators
+              on the channel.  When used with SILC_CMODE_SILENCE_USERS
+              mode this can be used to set the channel in state where only
+              the founder of the channel may send messages to the channel.
+              Messages sent by operators are dropped by servers when this
+              mode is set.  Only channel founder may set/unset this mode.
+
+
+           0x00001000    SILC_CMODE_CHANNEL_AUTH
+
+              When this mode is set the channel has one or more public keys
+              or certificates set, and ability to join the channel requires
+              a client to provide digital signature that can be successfully
+              verified with one of the channel public keys.  This mode is
+              equivalent to the SILC_MODE_PASSPHRASE except that digital
+              signatures are used to gain access to the channel.  Both
+              modes MAY be set at the same time.  Channel founder may set
+              and unset this mode.
+
+              The <channel pubkey> argument is an Argument List Payload
+              where each argument is Public Key Payload including public
+              key to be added or removed from the channel public key list.
+              To add a public key to channel this mode is set and the
+              argument type is 0x00, and the argument is the public key.
+              To remove a public key from channel public key list the
+              argument type is 0x01, and the argument is the public key
+              to be removed from the list.  To remove all public keys at
+              once this mode is unset.  An implementation MAY limit the
+              number of public keys that can be set for the channel.
+              This mode MUST NOT be set if <channel pubkey> is not present
+              when the mode is set for the first time.  Implementation MAY
+              add and remove multiple public keys at the same time by
+              including multiple arguments to the <channel pubkey>
+              Argument List Payload.
+
+
+        To make the mode system work, client MUST keep the channel mode
+        mask locally so that the mode setting and unsetting would work
+        without problems.  The client receives the initial channel mode
+        mask when it joins to the channel.  When the mode changes on
+        channel the server MUST distribute the changed channel mode mask
+        to all clients on the channel by sending the notify type
+        SILC_NOTIFY_TYPE_CMODE_CHANGE.  The notify type MUST also be sent
+        to the server's primary router.  If the <channel mode mask> was
+        not provided this command returns the mode mask, founder key
+        and channel public key list to the client.
+
+        Reply messages to the command:
+
+        Max Arguments:  5
+            Arguments:  (1) <Status Payload>    (2) <Channel ID>
+                        (3) <channel mode mask> (4) [<founder pubkey>]
+                        (5) [<channel pubkeys>]
+
+        This command replies with the changed channel mode mask that
+        client MUST keep locally.  It may also return the channel
+        founder's public key if it is set.  It may also return list of
+        channel public keys when the list was altered.  The <channel
+        pubkeys> is Argument List Payload and each argument includes
+        one public key.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ON_CHANNEL
+            SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+            SILC_STATUS_ERR_BAD_CHANNEL_ID
+            SILC_STATUS_ERR_NO_CHANNEL_ID
+            SILC_STATUS_ERR_NO_CHANNEL_PRIV
+            SILC_STATUS_ERR_NO_CHANNEL_FOPRIV
+            SILC_STATUS_ERR_UNKNOWN_MODE
+            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+            SILC_STATUS_ERR_AUTH_FAILED
+
+
+   18   SILC_COMMAND_CUMODE
+
+        Max Arguments:  4
+            Arguments:  (1) <Channel ID>    (2) <mode mask>
+                        (3) <Client ID>     (4) [<auth payload>]
+
+        This command is used by client to change channel user modes on
+        channel.  Users on channel may have some special modes and this
+        command is used by channel operators to set or change these modes.
+        The <Channel ID> is the ID of the target channel.  The <mode mask>
+        is OR'ed mask of modes.  The <Client ID> is the target client.
+        The client changing channel user modes MUST be on the same channel
+        as the target client and posses sufficient privileges to be able to
+        change the mode.
+
+        When the mode is changed SILC_NOTIFY_TYPE_CUMODE_CHANGE notify
+        type is distributed to the channel.
+
+        The following channel modes are defined:
+
+           0x00000000    SILC_CUMODE_NONE
+
+              No specific mode.  This is the normal situation for client.
+              Also, this is the mode set when removing all modes from
+              the target client.
+
+
+           0x00000001    SILC_CUMODE_FOUNDER
+
+              The client is channel founder of the channel.  Usually this
+              mode is set only by the server when the channel was created.
+              However, if the SILC_CMODE_FOUNDER_AUTH channel mode has
+              been set, the client can claim channel founder privileges
+              by providing the <auth payload> that the server will use
+              to authenticate the client.  The public key that server will
+              use to verify the <auth payload> MUST be the same public key
+              that was saved when the SILC_CMODE_FOUNDER_AUTH channel
+              mode was set.  The client MAY remove this mode at any time.
+
+
+           0x00000002    SILC_CUMODE_OPERATOR
+
+              Sets channel operator privileges on the channel for a
+              client on the channel.  Channel founder and channel operator
+              MAY set/unset this mode.  The client MAY remove this mode
+              at any time.
+
+
+           0x00000004    SILC_CUMODE_BLOCK_MESSAGES
+
+              Marks that the client wishes not to receive any channel
+              messages sent for the channel.  Client MAY set and unset
+              this mode to itself.  Client MUST NOT set it to anyone else.
+              When this mode is set server MUST NOT deliver channel
+              messages to this client.  Other packets such as channel
+              key packets are still sent to the client.
+
+              A separate service could provide additional filtering
+              features for accepting channel messages from certain
+              sender.  However, this document does not specify such
+              service.
+
+
+           0x00000008    SILC_CUMODE_BLOCK_MESSAGES_USERS
+
+              Marks that the client wishes not to receive any channel
+              messages sent from normal users.  Only messages sent by
+              channel founder or channel operator is accepted.  Client
+              MAY set and unset this mode to itself.  Client MUST NOT
+              set it to anyone else.  When this mode is set server MUST
+              NOT deliver channel messages that are sent by normal users
+              to this client.
+
+              A separate service could provide additional filtering
+              features for accepting channel messages from certain
+              sender.  However, this document does not specify such
+              service.
+
+
+           0x00000010    SILC_CUMODE_BLOCK_MESSAGES_ROBOTS
+
+              Marks that the client wishes not to receive any channel
+              messages sent from robots.  Messages sent by users with
+              the SILC_UMODE_ROBOT user mode set are not delivered.
+              Client MAY set and unset this mode to itself.  Client MUST
+              NOT set it to anyone else.  When this mode is set server
+              MUST NOT deliver channel messages that are sent by robots
+              to this client.
+
+
+           0x00000020    SILC_CUMODE_QUIET
+
+              Marks that the client cannot talk on the channel.  This
+              mode can be set by channel operator or channel founder to
+              some other user that is not operator or founder.  The
+              target client MUST NOT unset this mode.  When this mode
+              is set the server MUST drop messages sent by this client
+              to the channel.
+
+
+        Reply messages to the command:
+
+        Max Arguments:  4
+            Arguments:  (1) <Status Payload>  (2) <channel user mode mask>
+                        (3) <Channel ID>      (4) <Client ID>
+
+        This command replies with the changed channel user mode mask that
+        client MUST keep locally. The <Channel ID> is the specified
+        channel.  The <Client ID> is the target client.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ON_CHANNEL
+            SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+            SILC_STATUS_ERR_BAD_CHANNEL_ID
+            SILC_STATUS_ERR_NO_CHANNEL_ID
+            SILC_STATUS_ERR_NO_CHANNEL_PRIV
+            SILC_STATUS_ERR_NO_CHANNEL_FOPRIV
+            SILC_STATUS_ERR_UNKNOWN_MODE
+            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+            SILC_STATUS_ERR_AUTH_FAILED
+
+
+   19   SILC_COMMAND_KICK
+
+        Max Arguments:  3
+            Arguments:  (1) <Channel ID>      (2) <Client ID>
+                        (3) [<comment>]
+
+        This command is used by channel operators to remove a client from
+        channel.  The <channel> argument is the channel the client to be
+        removed is on currently.  Note that the "kicker" must be on the same
+        channel.  If <comment> is provided it will be sent to the removed
+        client.
+
+        After kicking the client the server MUST send the notify type
+        SILC_NOTIFY_TYPE_KICKED to the channel and to its primary router.
+        The client is removed from the channel after sending this notify.
+        The kicked client MUST be removed from the invite list of the
+        channel if it is explicitly added in the list.  The channel key
+        MUST also be re-generated after kicking, unless the
+        SILC_CMODE_PRIVKEY mode is set.
+
+        Reply messages to the command:
+
+        Max Arguments:  3
+            Arguments:  (1) <Status Payload>  (2) <Channel ID>
+                        (3) <Client ID>
+
+        This command returns the Channel ID and Client ID that was kicked
+        from the channel.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NO_SUCH_CHANNEL
+            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+            SILC_STATUS_ERR_NO_CHANNEL_PRIV
+            SILC_STATUS_ERR_NO_CLIENT_ID
+
+
+
+   20   SILC_COMMAND_BAN
+
+        Max Arguments:  3
+            Arguments:  (1) <Channel ID>         (2) [<add | del>]
+                        (3) [<ban list>]
+
+        This command is used to manage the ban list of the channel
+        indicated by the <Channel ID>.  A client that is banned from
+        channel is no longer able to join the channel.  The client which
+        is executing this command MUST have at least channel operator
+        privileges on the channel.
+
+        The <add | del> is an argument of size of 1 byte where 0x00 means
+        adding a client to ban list, and 0x01 means deleting a client
+        from ban list.  The <ban list>, if present, indicates the
+        information to be added to or removed from the ban list.  It
+        may include a string for matching clients, public key of a
+        client (Public Key Payload) or Client ID of a client.  The
+        <ban list> is an Argument List Payload.
+
+        The following Argument Types has been defined for ban list
+        Argument Payloads:
+
+          0x01 - Argument is an ban string of following format:
+
+            [<nickname>[@<server>]!][<username>]@[<hostname or IP/MASK>]
+
+            The <hostname> may also be in format of IP/MASK to indicate
+            a network.
+
+          0x02 - Argument is the public key of a client
+          0x03 - Argument is the Client ID of a client
+
+        If unknown type value is received or there is invalid amount of
+        Argument Payloads present in the list, the command MUST be
+        discarded.  When argument that is to be deleted from the ban
+        list does not exist in the list the argument is ignored.
+
+        The server MUST send the notify type SILC_NOTIFY_TYPE_BAN to its
+        primary router after adding to or removing from the ban list.
+        The wildcards MAY be used with this command.  If this command
+        is executed without the ban arguments the command merely replies
+        with the current ban list.
+
+        Reply messages to the command:
+
+        Max Arguments:  3
+            Arguments:  (1) <Status Payload>  (2) <Channel ID>
+                        (3) [<ban list>]
+
+        This command replies with the <Channel ID> of the channel and
+        the current <ban list> of the channel if it exists.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+            SILC_STATUS_ERR_NO_CHANNEL_ID
+            SILC_STATUS_ERR_NOT_ON_CHANNEL
+            SILC_STATUS_ERR_NO_CHANNEL_PRIV
+            SILC_STATUS_ERR_RESOURCE_LIMIT
+
+
+
+
+   21   SILC_COMMAND_DETACH
+
+        Max Arguments:  0
+            Arguments:
+
+        This command is used to detach from the network.  Client can
+        send this command to its server to indicate that it will be
+        detached.  By detaching the client remains in the network but
+        the actual network connection to the server is closed.  The
+        client may then later resume the old session back.
+
+        When this command is received the server MUST check that the
+        client is locally connected client, and set the user mode
+        SILC_UMODE_DETACHED flag.  The SILC_NOTIFY_TYPE_UMODE_CHANGE
+        MUST be also sent to routers.  The server then sends command
+        reply to this command and closes the network connection.
+        The server MUST NOT remove the client from its lists, or send
+        any signoff notifications for this client.  See the [SILC1]
+        for detailed information about detaching.
+
+        Reply messages to the command:
+
+        Max Arguments:  1
+            Arguments:  (1) <Status Payload>
+
+        This command replies only with the status indication.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_REGISTERED
+
+
+
+   22   SILC_COMMAND_WATCH
+
+        Max Arguments:  3
+            Arguments:  (1) <Client ID>       (2) [<add nickname>]
+                        (3) [<del nickname>]
+
+        This command is used to set up a watch for <add nickname>
+        nickname.  When a user in the network appears with the
+        nickname, or signoffs the network or user's mode is changed
+        the client which set up the watch will be notified about
+        this change.  This can be used to watch for certain nicknames
+        in the network and receive notifications when for example a
+        friend appears in the network or leaves the network.
+
+        The <del nickname> is a nickname that has been previously
+        added to watch list and is now removed from it.  Notifications
+        for that nickname will not be delivered anymore.
+
+        The <Client ID> is the Client ID of the sender of this command.
+
+        The nickname set to watch MUST NOT include any wildcards.
+        Note also that a nickname may match several users since
+        nicknames are not unique.  Implementations MAY set limits
+        for how many nicknames client can watch.
+
+        When normal server receives this command from client it
+        MUST send it to its router.  Router will process the command
+        and actually keeps the watch list.
+
+        Reply messages to the command:
+
+        Max Arguments:  1
+            Arguments:  (1) <Status Payload>
+
+        This command replies only with the status indication.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_BAD_NICKNAME
+            SILC_STATUS_ERR_WILDCARDS
+            SILC_STATUS_ERR_RESOURCE_LIMIT
+            SILC_STATUS_ERR_NO_SUCH_NICK
+            SILC_STATUS_ERR_NICKNAME_IN_USE
+
+
+   23   SILC_COMMAND_SILCOPER
+
+        Max Arguments:  2
+            Arguments:  (1) <username>  (2) <authentication payload>
+
+        This command is used by normal client to obtain router operator
+        privileges (also known as SILC operator) on the router.  Note
+        that router operator has privileges that supersedes the server
+        operator privileges.
+
+        The <username> is the username set in the server configurations
+        as operator.  The <authentication payload> is the data that the
+        client is authenticated against.  It may be passphrase prompted
+        for user on client's screen or it may be public key or certificate
+        authentication data (data signed with private key).  The public
+        key that router will use to verify the signature found in the
+        payload should be verified.  It is recommended that the public
+        key is saved locally in the router and router would not use
+        any public keys received during the SKE.
+
+        Difference between router operator and server operator is that
+        router operator is able to handle cell level properties while
+        server operator (even on router server) is able to handle only
+        local properties, such as, local connections and normal server
+        administration.  The router operator is also able to use the
+        SILC_COMMAND_KILL command.
+
+        After changing the mode server MUST send the notify type
+        SILC_NOTIFY_TYPE_UMODE_CHANGE to its primary router.
+
+        Reply messages to the command:
+
+        Max Arguments:  1
+            Arguments:  (1) <Status Payload>
+
+        This command replies only with Status Payload.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_AUTH_FAILED
+
+
+
+
+   24   SILC_COMMAND_LEAVE
+
+        Max Arguments:  1
+            Arguments:  (1) <Channel ID>
+
+        This command is used by client to leave a channel the client is
+        joined to.
+
+        When leaving channel the server MUST send the notify type
+        SILC_NOTIFY_TYPE_LEAVE to its primary router and to the channel.
+        The channel key MUST also be re-generated when leaving the channel
+        and distribute it to all clients still currently on the channel.
+        The key MUST NOT be re-generated if the SILC_CMODE_PRIVKEY mode
+        is set.
+
+        Reply messages to the command:
+
+        Max Arguments:  2
+            Arguments:  (1) <Status Payload>  (2) <Channel ID>
+
+        The <Channel ID> is the ID of left channel.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+            SILC_STATUS_ERR_BAD_CHANNEL_ID
+            SILC_STATUS_ERR_NO_CHANNEL_ID
+
+
+   25   SILC_COMMAND_USERS
+
+        Max Arguments:  2
+            Arguments:  (1) [<Channel ID>]  (2) [<channel name>]
+
+        This command is used to list user names currently on the requested
+        channel; either the argument <Channel ID> or the <channel name>.
+        One of these arguments must be present.  The server MUST resolve
+        the joined clients and reply with a lists of users on the channel
+        and with list of user modes on the channel.
+
+        If the requested channel is a private or secret channel, this
+        command MUST NOT send the list of users, except if the sender is
+        on the channel, or the sender is a server.  Otherwise, error is
+        returned to the sender.
+
+        Reply messages to the command:
+
+        Max Arguments:  5
+            Arguments:  (1) <Status Payload>  (2) <Channel ID>
+                        (3) <list count>      (4) <Client ID list>
+                        (5) <client mode list>
+
+        This command replies with the Channel ID of the requested channel
+        Client ID list of the users on the channel and list of their modes.
+        The Client ID list has Client ID's of all users in the list.  The
+        <Client ID list> is formed by adding Client ID's one after another.
+        The <client mode list> is formed by adding client's user modes on
+        the channel one after another (4 bytes (32 bits) each).  The <list
+        count> of length of 4 bytes (32 bits), tells the number of entries
+        in the lists.  Both lists MUST have equal number of entries.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+            SILC_STATUS_ERR_BAD_CHANNEL_ID
+            SILC_STATUS_ERR_NO_CHANNEL_ID
+            SILC_STATUS_ERR_NOT_ON_CHANNEL
+
+
+   26   SILC_COMMAND_GETKEY
+
+        Max Arguments:  1
+            Arguments:  (1) <ID Payload>
+
+        This command is used to fetch the public key of the client or
+        server indicated by the <ID Payload>.  The public key is fetched
+        from the server where to the client is connected.
+
+        Reply messages to the command:
+
+        Max Arguments:  3
+            Arguments:  (1) <Status Payload>      (2) <ID Payload>
+                        (3) [<Public Key Payload>]
+
+        This command replies with the client's or server's ID and with
+        the <Public Key Payload>.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+            SILC_STATUS_ERR_NO_SUCH_SERVER_ID
+
+
+   27   SILC_COMMAND_SERVICE
+
+        Max Arguments:  256
+            Arguments:  (1) [<service name>]    (2) [<auth payload>]
+                        (n) [...]
+
+        This command is used to negotiate a service agreement with a
+        remote server.  If this command is given without arguments it
+        MAY return the service list, if it is publicly available.  The
+        <service name> is a service specific identifier, and the
+        <auth payload> MAY be used to authenticate the requester to the
+        remote service.  The authentication to a service may be based
+        on previous agreement with the requester and the service
+        provider.  The command MAY also take additional service
+        specific arguments.  The <service name> is UTF-8 string.
+
+        This document does not specify any services.  How the services
+        are configured and put available in a server is also out of
+        scope of this document.
+
+        This command MAY be used by client to start using some service
+        in a server, but it also MAY be used by server to negotiate
+        to start using a service in some other server or router.
+
+        After the negotiation is done both of the parties need to know
+        from the service identifier how the service can be used.  The
+        service can be considered to be a protocol which both of the
+        parties need to support.
+
+        Reply messages to the command:
+
+        Max Arguments:  256
+            Arguments:  (1) <Status Payload>      (2) [<service list>]
+                        (3) [<service name>]      (n) [...]
+
+
+        This command MAY reply with the <service list> when command is
+        given without arguments, and the list is a comma separated list
+        of service identifiers.  The <service name> is the service that
+        the sender requested and this is provided when the server has
+        accepted the sender to use the <service name>.  The command
+        reply MAY also have additional service specific arguments.
+
+        Status messages:
+
+            SILC_STATUS_OK
+            SILC_STATUS_ERR_NOT_REGISTERED
+            SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+            SILC_STATUS_ERR_TOO_MANY_PARAMS
+            SILC_STATUS_ERR_NO_SUCH_SERVICE
+            SILC_STATUS_ERR_AUTH_FAILED
+            SILC_STATUS_ERR_PERM_DENIED
+
+
+
+   28 - 199
+
+        Currently undefined commands.
+
+
+   200 - 254
+
+        These commands are reserved for private use and will not be defined
+        in this document.
+
+
+   255  SILC_COMMAND_MAX
+
+        Reserved command.  This must not be sent.
+.in 3
+
+
+.ti 0
+2.4 SILC Command Status Payload
+
+Command Status Payload is sent in command reply messages to indicate
+the status of the command.  The payload is one of argument in the
+command thus this is the data area in Command Argument Payload described
+in [SILC2].  The payload is only 2 bytes in length.  The following
+diagram represents the Command Status Payload (fields are always in
+MSB first order).
+
+
+.in 21
+.nf
+                     1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|     Status    |     Error     |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 6:  SILC Command Status Payload
+
+
+.in 6
+o Status (1 byte) - Indicates the status message type,
+  error, start of list, entry of list or end of list.
+
+o Error (1 byte) - Indicates the error if the Status
+  field is some list status, which means there are list
+  of errors.
+.in 3
+
+The values in Status and Error fields are set according
+the following rules:
+
+.in 6
+o If there is single reply and error has not occurred
+  then Status field includes value SILC_STATUS_OK, and
+  the Error field MUST be ignored (and set to zero
+  value).
+
+o If there is single error, then Status field includes
+  one of the error values, and the Error field MUST be
+  ignored (and set to zero value).
+
+o If there will be multiple successful command replies
+  then Status field includes SILC_STATUS_LIST_START,
+  SILC_STATUS_LIST_ITEM or SILC_STATUS_LIST_END value,
+  and Error field is set to SILC_STATUS_OK.
+
+o If there are multiple error replies then Status field
+  includes SILC_STATUS_LIST_START, SILC_STATUS_LIST_ITEM
+  or SILC_STATUS_LIST_END value, and the Error field
+  includes the error value.
+.in 3
+
+This way it is possible to send single successful or
+single error reply, but also multiple successful and
+multiple error replies.  Note that it is possible to
+send both list of successful replies and list of error
+replies at the same time, however in this case the
+list of error replies MUST be sent after the successful
+replies.  This way the recipient may ignore the multiple
+errors if it wishes to do so.  Also note that in this
+case the successful and error replies belong to the
+same list.
+
+All Status messages are described in the next section.
+
+
+.ti 0
+3 SILC Status Types
+
+Status messages are returned in SILC protocol in command reply
+packet and in notify packet.  The SILC_PACKET_COMMAND_REPLY is
+the command reply packet and status types are sent inside the
+Status Payload as one of command reply argument, as defined in
+previous sections.  For SILC_PACKET_NOTIFY packet they can be sent
+as defined in [SILC2] for SILC_NOTIFY_TYPE_ERROR type.  The same
+types defined in this section are used in both cases.
+
+When returning status messages in the command reply message they
+indicate whether the command was executed without errors.  If error
+occurred the status indicates which error occurred.  If error
+occurred the arguments to the command replies are dictated by the
+error type.  If arguments are to be sent, they are defined below
+with the error status types.
+
+When sending status messages in SILC_NOTIFY_TYPE_ERROR notify type
+they always send some error status.  Usually they are sent to
+indicate that error occurred while processing some SILC packet.
+Please see the [SILC1] and [SILC2] for more information sending
+status types in SILC_NOTIFY_TYPE_ERROR notify.
+
+The Status Types are only numeric values and the receiver must
+convert the numeric values into human readable messages if this
+is desired in the application.
+
+List of all defined status types:
+
+.in 0
+   Generic status messages:
+
+   0    SILC_STATUS_OK
+
+        Ok status.  Everything went Ok.  The status payload maybe
+        safely ignored in this case.
+
+   1    SILC_STATUS_LIST_START
+
+        Start of the list.  There will be several command replies and
+        this reply is the start of the list.
+
+   2    SILC_STATUS_LIST_ITEM
+
+        Item in the list.  This is one of the item in the list but not the
+        first or last one.
+
+   3    SILC_STATUS_LIST_END
+
+        End of the list.  There were several command replies and this
+        reply is the last of the list.  There won't be other replies
+        belonging to this list after this one.
+
+   4 - 9
+
+        Currently undefined and has been reserved for the future.
+
+
+   Error status message:
+
+
+
+   10   SILC_STATUS_ERR_NO_SUCH_NICK
+
+        "No such nickname".  Requested nickname does not exist.
+         The next argument MUST be the requested nickname.
+
+   11   SILC_STATUS_ERR_NO_SUCH_CHANNEL
+
+        "No such channel".  Requested channel name does not exist.
+         The next argument MUST be the requested channel name.
+
+   12   SILC_STATUS_ERR_NO_SUCH_SERVER
+
+        "No such server".  Requested server name does not exist.
+         The next argument MUST be the requested server name.
+
+   13   SILC_STATUS_ERR_INCOMPLETE_INFORMATION
+
+        "Incomplete registration information".  Information remote
+        sent was incomplete.
+
+   14   SILC_STATUS_ERR_NO_RECIPIENT
+
+        "No recipient given".  Command required recipient which was
+        not provided.
+
+   15   SILC_STATUS_ERR_UNKNOWN_COMMAND
+
+        "Unknown command".  Command sent to server is unknown by the
+        server.
+
+   16   SILC_STATUS_ERR_WILDCARDS
+
+        "Wildcards cannot be used".  Wildcards were provided but they
+        weren't permitted.
+
+   17   SILC_STATUS_ERR_NO_CLIENT_ID
+
+        "No Client ID given".  Client ID were expected as command
+        parameter but were not found.
+
+   18   SILC_STATUS_ERR_NO_CHANNEL_ID
+
+        "No Channel ID given".  Channel ID were expected as command
+        parameter but were not found.
+
+   19   SILC_STATUS_ERR_NO_SERVER_ID
+
+        "No Serve ID given".  Server ID were expected as command
+        parameter but were not found.
+
+   20   SILC_STATUS_ERR_BAD_CLIENT_ID
+
+        "Bad Client ID".  Client ID provided were erroneous.
+         The next argument MUST be the provided ID.
+
+   21   SILC_STATUS_ERR_BAD_CHANNEL_ID
+
+        "Bad Channel ID".  Channel ID provided were erroneous.
+         The next argument MUST be the provided ID.
+
+   22   SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+
+        "No such Client ID".  Client ID provided does not exist.
+        The unknown Client ID MUST be provided as next argument
+        in the reply.
+
+   23   SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+
+        "No such Channel ID".  Channel ID provided does not exist.
+        The unknown Channel ID MUST be provided as next argument
+        in the reply.
+
+   24   SILC_STATUS_ERR_NICKNAME_IN_USE
+
+        "Nickname already exists".  Nickname created could not be
+        registered because number of same nicknames were already set to
+        maximum.  This is not expected to happen in real life but is
+        possible to occur.
+
+   25   SILC_STATUS_ERR_NOT_ON_CHANNEL
+
+        "You are not on that channel".  The command were specified for
+        channel user is not currently on.  The next argument MUST be the
+        Channel ID.
+
+   26   SILC_STATUS_ERR_USER_NOT_ON_CHANNEL
+
+        "They are not on channel".  The requested target client is not
+        on requested channel.  The next two arguments, in this order,
+        MUST be the requested Client ID and Channel ID.
+
+   27   SILC_STATUS_ERR_USER_ON_CHANNEL
+
+        "User already on channel".  User were invited on channel they
+        already are on.  The next two arguments, in this order, MUST be
+        the  requested Client ID and Channel ID.
+
+   28   SILC_STATUS_ERR_NOT_REGISTERED
+
+        "You have not registered".  User executed command that requires
+        the client to be registered on the server before it may be
+        executed.
+
+   29   SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+
+        "Not enough parameters".  Command requires more parameters
+        than provided.
+
+   30   SILC_STATUS_ERR_TOO_MANY_PARAMS
+
+        "Too many parameters".  Too many parameters were provided
+        for the command.
+
+   31   SILC_STATUS_ERR_PERM_DENIED
+
+        "Permission denied".  Generic permission denied error status
+        to indicate disallowed access.
+
+   32   SILC_STATUS_ERR_BANNED_FROM_SERVER
+
+        "You are banned from this server".  The client tried to register
+        on server that has explicitly denied this host to connect.
+
+   33   SILC_STATUS_ERR_BAD_PASSWORD
+
+        "Cannot join channel. Incorrect password".  Password provided for
+        channel were not accepted.  The next argument MUST be the
+        Channel ID.
+
+   34   SILC_STATUS_ERR_CHANNEL_IS_FULL
+
+        "Cannot join channel. Channel is full".  The channel is full
+        and client cannot be joined to it.  The next argument MUST be
+        the Channel ID.
+
+   35   SILC_STATUS_ERR_NOT_INVITED
+
+        "Cannot join channel. You have not been invited".  The channel
+        is invite only channel and client has not been invited.  The next
+        argument MUST be the Channel ID.
+
+   36   SILC_STATUS_ERR_BANNED_FROM_CHANNEL
+
+        "Cannot join channel. You have been banned".  The client has
+        been banned from the channel.  The next argument MUST be the
+        Channel ID.
+
+   37   SILC_STATUS_ERR_UNKNOWN_MODE
+
+        "Unknown mode".  Mode provided by the client were unknown to
+        the server.
+
+   38   SILC_STATUS_ERR_NOT_YOU
+
+        "Cannot change mode for other users".  User tried to change
+        someone else's mode.
+
+   39   SILC_STATUS_ERR_NO_CHANNEL_PRIV
+
+        "Permission denied. You are not channel operator".  Command may
+        be executed only by channel operator.  The next argument MUST be
+        the Channel ID.
+
+   40   SILC_STATUS_ERR_NO_CHANNEL_FOPRIV
+
+        "Permission denied. You are not channel founder".  Command may
+        be executed only by channel operator.  The next argument MUST be
+        the Channel ID.
+
+   41   SILC_STATUS_ERR_NO_SERVER_PRIV
+
+        "Permission denied. You are not server operator".  Command may
+        be executed only by server operator.
+
+   42   SILC_STATUS_ERR_NO_ROUTER_PRIV
+
+        "Permission denied. You are not SILC operator".  Command may be
+        executed only by router (SILC) operator.
+
+   43   SILC_STATUS_ERR_BAD_NICKNAME
+
+        "Bad nickname".  Nickname requested contained illegal characters
+        or were malformed.
+
+   44   SILC_STATUS_ERR_BAD_CHANNEL
+
+        "Bad channel name".  Channel requested contained illegal characters
+        or were malformed.
+
+   45   SILC_STATUS_ERR_AUTH_FAILED
+
+        "Authentication failed".  The authentication data sent as
+        argument were wrong and thus authentication failed.
+
+   46   SILC_STATUS_ERR_UNKOWN_ALGORITHM
+
+        "The algorithm was not supported."  The server does not support the
+        requested algorithm.  The next argument MUST be the algorithm name
+        string.
+
+   47   SILC_STATUS_ERR_NO_SUCH_SERVER_ID
+
+        "No such Server ID".  Server ID provided does not exist.
+        The unknown Server ID MUST be provided as next argument
+        in the reply.
+
+   48   SILC_STATUS_ERR_RESOURCE_LIMIT
+
+        "No more resources available".  This can mean that server cannot
+        or will not accept something due to resource limitations.
+
+   49   SILC_STATUS_ERR_NO_SUCH_SERVICE
+
+        "Service does not exist".  Requested service identifier is
+        unknown.  The next argument MUST be the service identifier.
+
+   50   SILC_STATUS_ERR_NOT_AUTHENTICATED
+
+        "You have not been authenticated".  Remote connection is not
+        authenticated even though it is supposed to be.
+
+   51   SILC_STATUS_ERR_BAD_SERVER_ID
+
+        "Server ID is not valid".  Provided server ID is not valid.
+        The next argument MUST be the provided ID.
+
+   52   SILC_STATUS_ERR_KEY_EXCHANGE_FAILED
+
+        "Key exchange failed".  Key Exchange protocol failed.
+
+   53   SILC_STATUS_ERR_BAD_VERSION
+
+        "Bad version".  Protocol or software version mismatch.
+
+   54   SILC_STATUS_ERR_TIMEDOUT
+
+        "Operation timed out".  Operation or service request timed
+        out, and thus was not processed.
+
+   55   SILC_STATUS_ERR_UNSUPPORTED_PUBLIC_KEY
+
+        "Unsupported public key type".  The public key or certificate
+        type is not supported in this implementation.
+
+   56   SILC_STATUS_ERR_OPERATION_ALLOWED
+
+        "Operation is not allowed".  A operation, for example a command,
+        is not allowed or it's execution is not allowed.
+
+.in 3
+
+
+
+.ti 0
+4 Security Considerations
+
+Security is central to the design of this protocol, and these security
+considerations permeate the specification.  Common security considerations
+such as keeping private keys truly private and using adequate lengths for
+symmetric and asymmetric keys must be followed in order to maintain the
+security of this protocol.
+
+
+.ti 0
+5 References
+
+[SILC1]      Riikonen, P., "Secure Internet Live Conferencing (SILC),
+             Protocol Specification", Internet Draft, May 2002.
+
+[SILC2]      Riikonen, P., "SILC Packet Protocol", Internet Draft,
+             May 2002.
+
+[SILC3]      Riikonen, P., "SILC Key Exchange and Authentication
+             Protocols", Internet Draft, May 2002.
+
+[IRC]        Oikarinen, J., and Reed D., "Internet Relay Chat Protocol",
+             RFC 1459, May 1993.
+
+[IRC-ARCH]   Kalt, C., "Internet Relay Chat: Architecture", RFC 2810,
+             April 2000.
+
+[IRC-CHAN]   Kalt, C., "Internet Relay Chat: Channel Management", RFC
+             2811, April 2000.
+
+[IRC-CLIENT] Kalt, C., "Internet Relay Chat: Client Protocol", RFC
+             2812, April 2000.
+
+[IRC-SERVER] Kalt, C., "Internet Relay Chat: Server Protocol", RFC
+             2813, April 2000.
+
+[SSH-TRANS]  Ylonen, T., et al, "SSH Transport Layer Protocol",
+             Internet Draft.
+
+[PGP]        Callas, J., et al, "OpenPGP Message Format", RFC 2440,
+             November 1998.
+
+[SPKI]       Ellison C., et al, "SPKI Certificate Theory", RFC 2693,
+             September 1999.
+
+[PKIX-Part1] Housley, R., et al, "Internet X.509 Public Key
+             Infrastructure, Certificate and CRL Profile", RFC 2459,
+             January 1999.
+
+[Schneier]   Schneier, B., "Applied Cryptography Second Edition",
+             John Wiley & Sons, New York, NY, 1996.
+
+[Menezes]    Menezes, A., et al, "Handbook of Applied Cryptography",
+             CRC Press 1997.
+
+[OAKLEY]     Orman, H., "The OAKLEY Key Determination Protocol",
+             RFC 2412, November 1998.
+
+[ISAKMP]     Maughan D., et al, "Internet Security Association and
+             Key Management Protocol (ISAKMP)", RFC 2408, November
+             1998.
+
+[IKE]        Harkins D., and Carrel D., "The Internet Key Exchange
+             (IKE)", RFC 2409, November 1998.
+
+[HMAC]       Krawczyk, H., "HMAC: Keyed-Hashing for Message
+             Authentication", RFC 2104, February 1997.
+
+[PKCS1]      Kalinski, B., and Staddon, J., "PKCS #1 RSA Cryptography
+             Specifications, Version 2.0", RFC 2437, October 1998.
+
+[RFC2119]    Bradner, S., "Key Words for use in RFCs to Indicate
+             Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+[RFC2279]    Yergeau, F., "UTF-8, a transformation format of ISO
+             10646", RFC 2279, January 1998.
+
+[ATTRS]      Riikonen, P., "User Online Presence and Information
+             Attributes", Internet Draft, May 2002.
+
+
+.ti 0
+6 Author's Address
+
+.nf
+Pekka Riikonen
+Snellmaninkatu 34 A 15
+70100 Kuopio
+Finland
+
+EMail: priikone@iki.fi
+
+
+.ti 0
+Appendix A
+
+This appendix defines the usage of the <Requested Attributes> argument in
+the SILC_COMMAND_WHOIS command.  The attributes are defined in [ATTRS],
+and may be used to request additional information about the user.  Since
+the information that may be requested using the attributes is something
+that server cannot deliver to the sender, it is possible to send the WHOIS
+command directly to the destination client whom will then provide the
+requested attributes.  This requires the servers to relay the WHOIS
+command to the client, and it requires capability for handling the WHOIS
+command in the client end.
+
+The <Requested Attributes> MAY include several attributes that are
+requested.  The format and encoding of the <Requested Attributes> is as
+defined in [ATTRS].  When <Requested Attributes> argument is set the
+server MAY process the attributes to see whether it can narrow down
+the WHOIS search, for example when searching with a nickname.  The
+normal servers MUST process the WHOIS command as normal WHOIS command,
+that is to send the command directly to the router.  The router MAY
+process the attributes, but it MUST send the command to the server
+that owns the requested client.
+
+The server that owns the client and receives the command MUST check
+whether the client is detached from the network.  If it is detached,
+that is the user mode has the SILC_UMODE_DETACHED mode set, it SHOULD
+process the attributes and provide as many of the requested attributes
+as possible and then send reply back to the sender.  If the client is
+active in the network it MUST send the command to the client for
+processing.
+
+The client receiving WHOIS command SHOULD check whether the
+<Requested Attributes> argument is set.  If it is not set then the
+WHOIS command SHOULD be discarded.  The client processes the requested
+attributes and SHOULD reply to each of the requested attribute with
+either valid value, or with an indication that the requested attribute
+is not known or supported.  This is to be done as defined in [ATTRS].
+The client always MUST send a reply to the command when some attributes
+were requested.  The client MAY also add additional attributes to the
+reply even if they were not requested.  The client MAY also digitally
+sign the attributes with ATTRIBUTE_USER_DIGITAL_SIGNATURE as defined
+in [ATTRS].  Then the client sends the reply back to the sender of
+the command.  The command reply that client assembles does not need
+to include any other argument but the <Status Payload> (1), and the
+<Attributes> (11).  The server receiving reply from client MUST allow
+this sort of command reply for WHOIS command.
+
+The information received from the client MAY be cached in the
+server's end.  The caching may be desired for example if the client
+can be detached from the network.  This way the server is then able
+to provide at least partial information for a requester.  The
+server MAY also process the command reply and verify whether the
+attributes provided in the reply are actually valid.  If it can do
+this, and verify that they indeed are valid values it MAY append
+a digital signature at the end of the attributes with the
+ATTRIBUTE_SERVER_DIGITAL_SIGNATURE as defined in [ATTRS].  The
+server then MUST provide valid WHOIS command reply to the sender
+of the command.   Other servers and routers that receive the command
+reply en route to the original sender MAY also cache the information.
+
+The client which receives the command reply to the WHOIS command
+SHOULD verify the ATTRIBUTE_USER_DIGITAL_SIGNATURE and the
+ATTRIBUTE_SERVER_DIGITAL_SIGNATURE if they are provided.
+
+
+.ti 0
+Full Copyright Statement
+
+Copyright (C) The Internet Society (2003). All Rights Reserved.
+
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/doc/draft-riikonen-silc-flags-payloads-03.nroff b/doc/draft-riikonen-silc-flags-payloads-03.nroff
new file mode 100644 (file)
index 0000000..a17fb04
--- /dev/null
@@ -0,0 +1,456 @@
+.pl 10.0i
+.po 0
+.ll 7.2i
+.lt 7.2i
+.nr LL 7.2i
+.nr LT 7.2i
+.ds LF Riikonen
+.ds RF FORMFEED[Page %]
+.ds CF
+.ds LH Internet Draft
+.ds RH 17 June 2003
+.ds CH
+.na
+.hy 0
+.in 0
+.nf
+Network Working Group                                        P. Riikonen
+Internet-Draft
+draft-riikonen-flags-payloads-03.txt                        17 June 2003
+Expires: 17 December 2003
+
+.in 3
+
+.ce 2
+SILC Message Flag Payloads
+<draft-riikonen-flags-payloads-03.txt>
+
+.ti 0
+Status of this Memo
+
+This document is an Internet-Draft and is in full conformance with
+all provisions of Section 10 of RFC 2026.  Internet-Drafts are
+working documents of the Internet Engineering Task Force (IETF), its
+areas, and its working groups.  Note that other groups may also
+distribute working documents as Internet-Drafts.
+
+Internet-Drafts are draft documents valid for a maximum of six months
+and may be updated, replaced, or obsoleted by other documents at any
+time.  It is inappropriate to use Internet-Drafts as reference
+material or to cite them other than as "work in progress."
+
+The list of current Internet-Drafts can be accessed at
+http://www.ietf.org/ietf/1id-abstracts.txt
+
+The list of Internet-Draft Shadow Directories can be accessed at
+http://www.ietf.org/shadow.html
+
+The distribution of this memo is unlimited.
+
+
+.ti 0
+Abstract
+
+This memo describes the data payloads associated with the SILC Message
+Flags, as defined in the SILC Packet Protocol specification [SILC2].  The
+purpose of the Message Flags is to augment the function of the Message
+Payload used to send both private and channel messages, by allowing the
+sender to tell the receiver what type of data the payload includes, and
+how the data should be processed.  Some of the Message Flags may define
+additional payloads to be associated with the flag, and this memo
+describes these payloads.
+
+
+
+
+
+
+
+
+.ti 0
+Table of Contents
+
+.nf
+1 Introduction ..................................................  2
+  1.1 Requirements Terminology ..................................  2
+2 SILC Message Flags ............................................  2
+3 SILC Message Flag Payloads ....................................  3
+  3.1 SILC_MESSAGE_FLAG_REQUEST .................................  3
+  3.2 SILC_MESSAGE_FLAG_REPLY ...................................  3
+  3.3 SILC_MESSAGE_FLAG_SIGNED ..................................  4
+  3.4 SILC_MESSAGE_FLAG_DATA ....................................  6
+4 Security Considerations .......................................  7
+5 References ....................................................  8
+6 Author's Address ..............................................  8
+7 Full Copyright Statement ......................................  9
+
+
+.ti 0
+1. Introduction
+
+The Secure Internet Live Conferencing [SILC1] supports sending binary
+messages between users in the network.  To make the data sending, and
+processing at the receiver's end as simple as possible the SILC defines
+Message Flags to the Message Payload [SILC2] that is used to send private
+and channel messages, which can help the receiver to decide how the data
+is encoded, and how it should be interpreted.  Some of the Message Flags
+may define additional payloads to be associated with the flag, but the
+[SILC2] does not define them.  This memo defines the payloads for those
+Message Flags that was marked to include additional payloads in [SILC2].
+
+By defining the payloads for the Message Flags the Message Payload
+can be augmented to support any kind of data, which can be easily
+interpreted at the receiver end.  For example, it would be possible to
+send audio stream, video stream, image files and HTML pages as messages,
+and the receiver can either choose to ignore the message or to process
+it, or to perhaps pass the message to some application for processing.
+Without specific payloads for Message Flags it is almost impossible for
+the receiver to interpret binary data from the payload.
+
+
+.ti 0
+1.1 Requirements Terminology
+
+The keywords MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, RECOMMENDED,
+MAY, and OPTIONAL, when they appear in this document, are to be
+interpreted as described in [RFC2119].
+
+
+.ti 0
+2 SILC Message Flags
+
+The Message Flags was added to the SILC protocol for the reason that SILC
+provides sending binary data as messages between users, and entities in
+the network, and interpreting pure binary data is almost impossible.
+With the flags the purpose, the reason, and the way the message is
+supposed to be interpreted can be told to the recipient.  Other
+conferencing protocols which are usually ASCII based protocols do not have
+such problems since they do not generally support sending of binary data
+at all, or require encoding of the data before it can be sent over the
+network.
+
+The Message Payload in SILC can have flags that can augment the function
+of the payload.  The flags can tell for example that the message is a
+request, or a reply to an earlier received request.  They can tell that
+the message is some action that the sender is performing, or they can tell
+that the message is an auto reply, or that it is explicitly digitally
+signed by the sender.
+
+The problem of Message Flags is that the space for flags mask is only 16
+bits, so there is a limited number of flags available.  For this reason
+having a flag that defines a generic way of sending any kind of data as
+a message, and can be easily interpreted at the receiver's end is important.
+For this reason the flag SILC_MESSAGE_FLAG_DATA was added to the protocol
+which can represent any data.  This memo describe how this flag is used
+and how the associated payload is constructed and processed.  This memo
+also describes payloads for all the other flags that can have associated
+payloads.
+
+
+.ti 0
+3 SILC Message Flag Payloads
+
+The [SILC2] defines the flags which may have associated payloads.  This
+section will list these flags and define the payloads.
+
+
+.ti 0
+3.1 SILC_MESSAGE_FLAG_REQUEST
+
+Currently this flag can be used in the context of application specific,
+service specific or vendor specific requests, and the data payload type is
+dependent of this context.  Therefore, payload is not defined for this
+flag in this memo.  This flag may also be masked with some other flag in
+the message payload, including with some other flag that defines
+additional payload.
+
+
+.ti 0
+3.2 SILC_MESSAGE_FLAG_REPLY
+
+Currently this flag can be used in the context of application specific,
+service specific or vendor specific replies, and the data payload type is
+dependent of this context.  Therefore, payload is not defined for this
+flag in this memo.  This flag may also be masked with some other flag in
+the message payload, including with some other flag that defines
+additional payload.
+
+
+.ti 0
+3.3 SILC_MESSAGE_FLAG_SIGNED
+
+This flag is used to tell the recipient that the sent message is
+digitally signed by the sender, and that the recipient should verify
+the signature to verify the true authenticity of the received message.
+All message payloads in SILC provides message authentication code (MAC)
+which can be used to verify that the sender produced and sent the message.
+Even so, signing messages digitally can be used to verify the authenticity
+of the message when recipient trusts the sender and to provide
+non-repudiation.
+
+This flag defines a payload which is used to deliver the actual message,
+sender's public key and the digital signature.  The payload for
+SILC_MESSAGE_FLAG_SIGNED is as follows:
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                   Start of Message Payload                    ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                      Public Key Payload                       ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|     Signature Data Length     |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                        Signature Data                         ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                       Initial Vector *                        ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                              MAC *                            ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 1:  SILC_MESSAGE_FLAG_SIGNED Payload
+
+
+.in 6
+o Start of Message Payload (variable length) - This is the
+  start of the Message Payload without the IV and MAC fields,
+  since those fields are appended at the end of this payload.
+
+o Public Key Payload (variable length) - This includes the
+  Public Key Payload [SILC2] which can be used to deliver the
+  sender's public key (or certificate).  It also indicates the
+  type of the public key (or certificate) which the recipient
+  use to identify how the signature must be verified.  This
+  payload must always be present but it is not required to
+  include the public key data.  The Public Key Type field in
+  the Public Key Payload MUST be set to the correct type of
+  the key, even if the actual public key data is not included.
+
+o Signature Data Length (2 bytes) - Indicates the length of
+  the Signature Data field not including any other field.
+
+o Signature Data (variable length) - Includes the actual
+  signature data.  The signature computation and encoding
+  is key type specific.  See [SILC3] for all key types, and
+  their respective references for how to compute and encode
+  the signature.
+
+o Initial Vector (variable length) - the IV of the Message
+  Payload as defined in [SILC2].  This field is not encrypted.
+
+o MAC (variable length) - the MAC of the Message Payload as
+  defined in [SILC2].  The MAC is computed after encryption
+  and after signature computation.  All data in the Message
+  Payload and this payload, including the IV field are
+  included in the MAC computation.  This field is not
+  encrypted.
+.in 3
+
+How the data is processed before it is signed is key type specific.
+The actual data that to be signed MUST be the plaintext message
+payload before encryption.  The data to be signed is concatenation
+of the Start of Message Payload field and the Public Key Payload,
+in that order.  Any other fields are not included for signature data.
+Before signing, the data is always processed, usually hashed.  The
+hash function to be used is defined in the key type specific
+definitions.  See the key type specific references in [SILC3].
+
+If the public key of the sender is included in the payload the
+recipient SHOULD verify it before accepting the public key.  Recipient
+SHOULD verify the signature before accepting and caching the public key.
+With certificates the certificate verification may be done before
+verifying the signature.  If the signature verification fails the
+message should still be displayed.  The end user should also be
+notified about the result of the signature verification.
+
+To make the packet size smaller implementations may not want to
+include the actual public key in all signed messages.  Sending the
+public key in the first message is usually sufficient.  Subsequent
+messages may include empty Public Key Payload with an indication of
+the public key type.
+
+Implementations that do not support this flag can still process the
+message payload in normal manner.  These implementations merely parse
+the decrypted payload in normal manner and ignore the extra data in
+the payload.  They can do this by extracting the MAC and the IV from
+the end of the data buffer and thus ignoring the data between start of
+the Message Payload and the Initial Vector field.
+
+This flag MAY be masked with any other Message Flag including those that
+define additional payloads.  As long as the defined payload resides in
+the data area of the message payload this flag may be masked with the
+other flags.
+
+
+.ti 0
+3.4 SILC_MESSAGE_FLAG_DATA
+
+This flag is used to represent any data as a message in the way that it
+can be easily interpreted by the recipient.  This flag is used to send
+MIME objects as messages from the sender to the receiver.  The MIME as
+defined in [RFC2045], [RFC2046], [RFC2047], [RFC2048] and [RFC2049] is
+well established protocol for sending different kind of data with many
+applications and protocols.  It support dozens of different media types
+and encodings, and for this reason is ideal for sending data in SILC
+message payloads as well.
+
+When the receiver has checked that the message payload includes the
+SILC_MESSAGE_FLAG_DATA flag, it may then start parsing the MIME header.
+It would also be possible to pass the message to some application which
+can already interpret MIME objects.  If the receiver does not support the
+media type received in the MIME header, it SHOULD be treated as
+"application/octet-stream".  The receiver MAY also ignore and discard
+messages that it does not support.
+
+The MIME header MUST be at the start of the data area of the Message
+Payload.  The MIME header received in the data area of the payload SHOULD
+have the MIME-Version field at first and then Content-Type field.  The
+MIME-Version field is not required to be present in each body part of
+multipart entity.  Additionally the header MAY also include any other
+MIME compliant headers.  The character encoding for the MIME Header
+strings inside the message payload is US-ASCII, as defined in [RFC2045].
+The actual MIME object may define additional character sets or encodings
+for the data it delivers.
+
+Hence, the MIME Header in the message payload may be as follows:
+
+.in 8
+.nf
+MIME-Version: 1.0\\r\\n
+Content-Type: discrete/composite\\r\\n
+Content-Transfer-Encoding: binary\\r\\n
+\\r\\n
+.in 3
+
+The Content-Transfer-Encoding field behaves as defined in [RFC2045] and
+defines the encoding of the data in the MIME object.  The preferred data
+encoding with SILC is "binary".  However, many MIME media types defines
+their preferred encoding and they may be used if binary encoding is not
+suitable.
+
+When sending large amounts of traffic or large files as MIME objects the
+limits of the SILC Packet needs to be taken into consideration.  The
+maximum length of SILC Packet is 2^16 bytes, and larger messages would
+need to be fragmented.  MIME provides way of fragmenting and reassembling
+messages, and it is to be done with SILC as defined in [RFC2046].  The
+MIME fragmentation is defined for gateway usage, but in case of SILC the
+sender (for example, a client) may also start sending fragmented MIME
+objects.
+
+This flag SHOULD NOT be masked with some other Message Flag that defines
+payloads for message data.  Generally this sort of setting would be
+impossible for the receiver to interpret.  However, flags that does not
+define any specific payloads MAY be masked with this flag as well.  For
+example, this flag could be masked also with SILC_MESSAGE_FLAG_REQUEST flag.
+It also can be masked with SILC_MESSAGE_FLAG_SIGNED flag since it does not
+define data specific payload.
+
+
+.ti 0
+4 Security Considerations
+
+In case of SILC_MESSAGE_FLAG_DATA the implementors should pay special
+attention to the security implications of any media type that can cause
+the remote execution of any actions in the receiver's environment.  The
+[RFC2046] and [RFC2048] discusses more MIME specific security
+considerations.  Even though SILC provides secured messages, in case of
+MIME which can be used to transfer files and documents which are stored in
+the receiver's local environment, securing separately the MIME object may
+be desired.  For example, augmenting the MIME support in SILC messages to
+support S/MIME may be desired in some implementations.
+
+
+
+
+.ti 0
+5 References
+
+[SILC1]      Riikonen, P., "Secure Internet Live Conferencing (SILC),
+             Protocol Specification", Internet Draft, June 2003.
+
+[SILC2]      Riikonen, P., "SILC Packet Protocol", Internet Draft,
+             June 2003.
+
+[SILC3]      Riikonen, P., "SILC Key Exchange and Authentication
+             Protocols", Internet Draft, June 2003.
+
+[RFC2045]    Freed, N., et al., "Multipurpose Internet Mail Extensions
+             (MIME) Part One: Format of Internet Message Bodies",
+             Standards Track, RFC 2045, November 1996.
+
+[RFC2046]    Freed, N., et al., "Multipurpose Internet Mail Extensions
+             (MIME) Part Two: Media Types", Standards Track, RFC 2045,
+             November 1996.
+
+[RFC2047]    Moore K., "MIME (Multipurpose Internet Mail Extensions)
+             Part Three: Message Header Extensions for Non-ASCII Text"
+             Standards Track, RFC 2047, November 1996.
+
+[RFC2048]    Freed, N., et al., "Multipurpose Internet Mail Extensions
+             (MIME) Part Four: Registration Procedures", Standards
+             Track, RFC 2048, November 1996.
+
+[RFC2049]    Freed, N., et al., "Multipurpose Internet Mail Extensions
+             (MIME) Part Five: Conformance Criteria and Examples",
+             Standards Track, RFC 2049, November 1996.
+
+[RFC2119]    Bradner, S., "Key Words for use in RFCs to Indicate
+             Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+
+
+.ti 0
+6 Author's Address
+
+Pekka Riikonen
+Snellmaninkatu 34 A 15
+70100 Kuopio
+Finland
+
+EMail: priikone@iki.fi
+
+
+
+
+.ti 0
+7 Full Copyright Statement
+
+Copyright (C) The Internet Society (2003). All Rights Reserved.
+
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/doc/draft-riikonen-silc-ke-auth-07.nroff b/doc/draft-riikonen-silc-ke-auth-07.nroff
new file mode 100644 (file)
index 0000000..1da5641
--- /dev/null
@@ -0,0 +1,1180 @@
+.pl 10.0i
+.po 0
+.ll 7.2i
+.lt 7.2i
+.nr LL 7.2i
+.nr LT 7.2i
+.ds LF Riikonen
+.ds RF FORMFEED[Page %]
+.ds CF
+.ds LH Internet-Draft
+.ds RH 17 June 2003
+.ds CH
+.na
+.hy 0
+.in 0
+.nf
+Network Working Group                                        P. Riikonen
+Internet-Draft
+draft-riikonen-silc-ke-auth-07.txt                          17 June 2003
+Expires: 17 December 2003
+
+.in 3
+
+.ce 2
+SILC Key Exchange and Authentication Protocols
+<draft-riikonen-silc-ke-auth-07.txt>
+
+.ti 0
+Status of this Memo
+
+This document is an Internet-Draft and is in full conformance with
+all provisions of Section 10 of RFC 2026.  Internet-Drafts are
+working documents of the Internet Engineering Task Force (IETF), its
+areas, and its working groups.  Note that other groups may also
+distribute working documents as Internet-Drafts.
+
+Internet-Drafts are draft documents valid for a maximum of six months
+and may be updated, replaced, or obsoleted by other documents at any
+time.  It is inappropriate to use Internet-Drafts as reference
+material or to cite them other than as "work in progress."
+
+The list of current Internet-Drafts can be accessed at
+http://www.ietf.org/ietf/1id-abstracts.txt
+
+The list of Internet-Draft Shadow Directories can be accessed at
+http://www.ietf.org/shadow.html
+
+The distribution of this memo is unlimited.
+
+
+.ti 0
+Abstract
+
+This memo describes two protocols used in the Secure Internet Live
+Conferencing (SILC) protocol, specified in the Secure Internet Live
+Conferencing, Protocol Specification [SILC1].  The SILC Key Exchange
+(SKE) protocol provides secure key exchange between two parties
+resulting into shared secret key material.  The protocol is based
+on Diffie-Hellman key exchange algorithm and its functionality is
+derived from several key exchange protocols.
+
+The second protocol, SILC Connection Authentication protocol provides
+user level authentication used when creating connections in SILC
+network.  The protocol is transparent to the authentication data
+which means that it can be used to authenticate the connection with, for
+example, passphrase (pre-shared secret) or public key (and certificate)
+based on digital signatures.
+
+
+
+.ti 0
+Table of Contents
+
+.nf
+1 Introduction ..................................................  2
+  1.1 Requirements Terminology ..................................  3
+2 SILC Key Exchange Protocol ....................................  3
+  2.1 Key Exchange Payloads .....................................  4
+      2.1.1 Key Exchange Start Payload ..........................  4
+      2.1.2 Key Exchange Payload ................................  8
+  2.2 Key Exchange Procedure .................................... 11
+  2.3 Processing the Key Material ............................... 12
+  2.4 SILC Key Exchange Groups .................................. 14
+      2.4.1 diffie-hellman-group1 ............................... 14
+      2.4.2 diffie-hellman-group2 ............................... 15
+      2.4.3 diffie-hellman-group3 ............................... 15
+  2.5 Key Exchange Status Types ................................. 16
+3 SILC Connection Authentication Protocol ....................... 17
+  3.1 Connection Auth Payload ................................... 18
+  3.2 Connection Authentication Types ........................... 19
+      3.2.1 Passphrase Authentication ........................... 19
+      3.2.2 Public Key Authentication ........................... 20
+  3.3 Connection Authentication Status Types .................... 21
+4 Security Considerations ....................................... 21
+5 References .................................................... 21
+6 Author's Address .............................................. 23
+7 Full Copyright Statement ...................................... 23
+
+
+.ti 0
+List of Figures
+
+.nf
+Figure 1:  Key Exchange Start Payload
+Figure 2:  Key Exchange Payload
+Figure 3:  Connection Auth Payload
+
+
+.ti 0
+1 Introduction
+
+This memo describes two protocols used in the Secure Internet Live
+Conferencing (SILC) protocol specified in the Secure Internet Live
+Conferencing, Protocol Specification [SILC1].  The SILC Key Exchange
+(SKE) protocol provides secure key exchange between two parties
+resulting into shared secret key material.  The protocol is based on
+Diffie-Hellman key exchange algorithm and its functionality is derived
+from several key exchange protocols, such as SSH2 Key Exchange protocol,
+Station-To-Station (STS) protocol and the OAKLEY Key Determination
+protocol [OAKLEY].
+
+The second protocol, SILC Connection Authentication protocol provides
+user level authentication used when creating connections in SILC
+network.  The protocol is transparent to the authentication data which
+means that it can be used to authenticate the connection with, for example,
+passphrase (pre-shared secret) or public key (and certificate) based
+on digital signatures.
+
+The basis of secure SILC session requires strong and secure key exchange
+protocol and authentication.  The authentication protocol is secured and
+no authentication data is ever sent in the network without encrypting
+and authenticating it first.  Thus, authentication protocol may be used
+only after the key exchange protocol has been successfully completed.
+
+This document constantly refers to other SILC protocol specifications
+that should be read to be able to fully understand the functionality
+and purpose of these protocols.  The most important references are
+the Secure Internet Live Conferencing, Protocol Specification [SILC1]
+and the SILC Packet Protocol [SILC2].
+
+The protocol is intended to be used with the SILC protocol thus it
+does not define own framework that could be used.  The framework is
+provided by the SILC protocol.
+
+
+.ti 0
+1.1 Requirements Terminology
+
+The keywords MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, RECOMMENDED,
+MAY, and OPTIONAL, when they appear in this document, are to be
+interpreted as described in [RFC2119].
+
+
+.ti 0
+2 SILC Key Exchange Protocol
+
+SILC Key Exchange Protocol (SKE) is used to exchange shared secret
+material used to secure the communication channel.  The protocol use
+Diffie-Hellman key exchange algorithm and its functionality is derived
+from several key exchange protocols, such as SSH2 Key Exchange protocol,
+Station-To-Station (STS) protocol and the OAKLEY Key Determination
+protocol [OAKLEY].  The protocol does not claim any conformance
+to any of these protocols, they were only used as a reference when
+designing this protocol.  The protocol can mutually authenticate the
+negotiating parties during the key exchange.
+
+The purpose of SILC Key Exchange protocol is to create session keys to
+be used in current SILC session.  The keys are valid only for some period
+of time (usually an hour) or at most until the session ends.  These keys
+are used to protect packets traveling between the two entities.
+Usually all traffic is secured with the key material derived from this
+protocol.
+
+The Diffie-Hellman implementation used in the SILC SHOULD be compliant
+to the PKCS #3.
+
+
+.ti 0
+2.1 Key Exchange Payloads
+
+During the key exchange procedure public data is sent between initiator
+and responder.  This data is later used in the key exchange procedure.
+There are several payloads used in the key exchange.  As for all SILC
+packets, SILC Packet Header, described in [SILC2], is at the start of
+all packets sent in during this protocol.  All the fields in the
+following payloads are in MSB (most significant byte first) order.
+Following descriptions of these payloads.
+
+
+.ti 0
+2.1.1 Key Exchange Start Payload
+
+The key exchange between two entities MUST be started by sending the
+SILC_PACKET_KEY_EXCHANGE packet containing Key Exchange Start Payload.
+Initiator sends the Key Exchange Start Payload to the responder filled
+with all security properties it supports.  The responder then checks
+whether it supports the security properties.
+
+It then sends a Key Exchange Start Payload to the initiator filled with
+security properties it selected from the original payload.  The payload
+sent by responder MUST include only one chosen property per list.  The
+character encoding for the security property values as defined in [SILC1]
+SHOULD be UTF-8 [RFC2279] in Key Exchange Start Payload.
+
+The Key Exchange Start Payload is used to tell connecting entities what
+security properties and algorithms should be used in the communication.
+The Key Exchange Start Payload is sent only once per session.  Even if
+the PFS (Perfect Forward Secrecy) flag is set the Key Exchange Start
+Payload is not re-sent.  When PFS is desired the Key Exchange Payloads
+are sent to negotiate new key material.  The procedure is equivalent to
+the very first negotiation except that the Key Exchange Start Payload
+is not sent.
+
+As this payload is used only with the very first key exchange the payload
+is never encrypted, as there are no keys to encrypt it with.
+
+A cookie is also sent in this payload.  A cookie is used to randomize the
+payload so that none of the key exchange parties can determine this
+payload before the key exchange procedure starts.  The cookie MUST be
+returned to the original sender unmodified by the responder.
+
+Following diagram represents the Key Exchange Start Payload.  The lists
+mentioned below are always comma (`,') separated and the list MUST NOT
+include white spaces (` ').
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|   RESERVED    |     Flags     |         Payload Length        |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
++                                                               +
+|                                                               |
++                            Cookie                             +
+|                                                               |
++                                                               +
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|     Version String Length     |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                         Version String                        ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|   Key Exchange Grp Length     |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                      Key Exchange Groups                      ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        PKCS Alg Length        |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                         PKCS Algorithms                       ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|     Encryption Alg Length     |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                      Encryption Algorithms                    ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Hash Alg Length         |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                         Hash Algorithms                       ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|         HMAC Length           |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                             HMACs                             ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|    Compression Alg Length     |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                     Compression Algorithms                    ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 1:  Key Exchange Start Payload
+
+
+.in 6
+o RESERVED (1 byte) - Reserved field.  Sender fills this with
+  zero (0) value.
+
+o Flags (1 byte) - Indicates flags to be used in the key
+  exchange.  Several flags can be set at once by ORing the
+  flags together.  The following flags are reserved for this
+  field:
+
+     No flags                 0x00
+
+       In this case the field is ignored.
+
+     IV Included              0x01
+
+       This flag is used to indicate that Initial Vector (IV)
+       in encryption will be included in the ciphertext
+       which the recipient must use in decryption.  The IV
+       MUST be set after the last ciphertext block.  With
+       this flag it is possible to use SILC protocol on
+       unreliable transport such as UDP/IP which may cause
+       packet reordering and packet losses.  By default,
+       this flag is not set and thus IV is not included
+       in the ciphertext.  Setting this flag increases the
+       ciphertext size by one ciphertext block.  Responder
+       MAY override this flag for the initiator.
+
+     PFS                      0x02
+
+       Perfect Forward Secrecy (PFS) to be used in the
+       key exchange protocol.  If not set, re-keying
+       is performed using the old key.  See the [SILC1]
+       for more information on this issue.  When PFS is
+       used, re-keying and creating new keys for any
+       particular purpose MUST cause new key exchange with
+       new Diffie-Hellman exponent values.  In this key
+       exchange only the Key Exchange Payload is sent and
+       the Key Exchange Start Payload MUST NOT be sent.
+       When doing PFS the Key Exchange Payloads are
+       encrypted with the old keys.
+
+     Mutual Authentication    0x04
+
+       Both of the parties will perform authentication
+       by providing signed data for the other party to
+       verify.  By default, only responder will provide
+       the signature data.  If this is set then the
+       initiator must also provide it.  Initiator MAY
+       set this but also responder MAY set this even if
+       initiator did not set it.
+
+     Rest of the flags are reserved for the future and
+     MUST NOT be set.
+
+o Payload Length (2 bytes) - Length of the entire Key Exchange
+  Start payload, not including any other field.
+
+o Cookie (16 bytes) - Cookie that randomize this payload so
+  that each of the party cannot determine the payload before
+  hand.  This field MUST be present.
+
+o Version String Length (2 bytes) - The length of the Version
+  String field, not including any other field.
+
+o Version String (variable length) - Indicates the version of
+  the sender of this payload.  Initiator sets this when sending
+  the payload and responder sets this when it replies by sending
+  this payload.  See [SILC1] for definition for the version
+  string format.  This field MUST be present and include valid
+  version string.
+
+o Key Exchange Grp Length (2 bytes) - The length of the
+  key exchange group list, not including any other field.
+
+o Key Exchange Group (variable length) - The list of
+  key exchange groups.  See the section 2.4 SILC Key Exchange
+  Groups for definitions of these groups.  This field MUST
+  be present.
+
+o PKCS Alg Length (2 bytes) - The length of the PKCS algorithms
+  list, not including any other field.
+
+o PKCS Algorithms (variable length) - The list of PKCS
+  algorithms.  This field MUST be present.
+
+o Encryption Alg Length (2 bytes) - The length of the encryption
+  algorithms list, not including any other field.
+
+o Encryption Algorithms (variable length) - The list of
+  encryption algorithms.  This field MUST be present.
+
+o Hash Alg Length (2 bytes) - The length of the Hash algorithm
+  list, not including any other field.
+
+o Hash Algorithms (variable length) - The list of Hash
+  algorithms.  The hash algorithms are mainly used in the
+  SKE protocol.  This field MUST be present.
+
+o HMAC Length (2 bytes) - The length of the HMAC list, not
+  including any other field.
+
+o HMACs (variable length) - The list of HMACs.  The HMAC's
+  are used to compute the Message Authentication Code (MAC)
+  of the SILC packets.  This field MUST be present.
+
+o Compression Alg Length (2 bytes) - The length of the
+  compression algorithms list, not including any other field.
+
+o Compression Algorithms (variable length) - The list of
+  compression algorithms.  This field MAY be omitted.
+.in 3
+
+
+.ti 0
+2.1.2 Key Exchange Payload
+
+Key Exchange payload is used to deliver the public key (or certificate),
+the computed Diffie-Hellman public value and possibly signature data
+from one party to the other.  When initiator is using this payload
+and the Mutual Authentication flag is not set then the initiator MUST
+NOT provide the signature data.  If the flag is set then the initiator
+MUST provide the signature data so that the responder can verify it.
+
+The Mutual Authentication flag is usually used when a separate
+authentication protocol will not be executed for the initiator of the
+protocol.  This is case for example when the SKE is performed between
+two SILC clients.  In normal case, where client is connecting to a
+server, or server is connecting to a router the Mutual Authentication
+flag MAY be omitted.  However, if the connection authentication protocol
+for the connecting entity is not based on digital signatures (it is
+based on pre-shared key) then the Mutual Authentication flag SHOULD be
+enabled.  This way the connecting entity has to provide proof of
+possession of the private key for the public key it will provide in
+this protocol.
+
+When performing re-key with PFS selected this is the only payload that
+is sent in the SKE protocol.  The Key Exchange Start Payload MUST NOT
+be sent at all.  However, this payload does not have all the fields
+present.  In the re-key with PFS the public key and a possible signature
+data SHOULD NOT be present.  If they are present they MUST be ignored.
+The only field that is present is the Public Data that is used to create
+the new key material.  In the re-key the Mutual Authentication flag, that
+may be set in the initial negotiation, MUST also be ignored.
+
+This payload is sent inside SILC_PACKET_KEY_EXCHANGE_1 and inside
+SILC_PACKET_KEY_EXCHANGE_2 packet types.  The initiator uses the
+SILC_PACKET_KEY_EXCHANGE_1 and the responder the latter.
+
+The following diagram represent the Key Exchange Payload.
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Public Key Length       |        Public Key Type        |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~            Public Key of the party (or certificate)           ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Public Data Length      |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                          Public Data                          ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Signature Length       |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                        Signature Data                         ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 2:  Key Exchange Payload
+
+
+.in 6
+o Public Key Length (2 bytes) - The length of the Public Key
+  (or certificate) field, not including any other field.
+
+o Public Key Type (2 bytes) - The public key (or certificate)
+  type.  This field indicates the type of the public key in
+  the packet.  Following types are defined:
+
+     1    SILC style public key (mandatory)
+     2    SSH2 style public key (optional)
+     3    X.509 Version 3 certificate (optional)
+     4    OpenPGP certificate (optional)
+     5    SPKI certificate (optional)
+
+  The only required type to support is type number 1.  See
+  [SILC1] for the SILC public key specification.  See
+  SSH2 public key specification in [SSH-TRANS].  See X.509v3
+  certificate specification in [PKIX-Part1].  See OpenPGP
+  certificate specification in [PGP].  See SPKI certificate
+  specification in [SPKI].  If this field includes zero (0)
+  or unsupported type number the protocol MUST be aborted
+  sending SILC_PACKET_FAILURE message and the connection SHOULD
+  be closed immediately.
+
+o Public Key (or certificate) (variable length) - The
+  public key or certificate of the party.  This public key
+  is used to verify the digital signature.  The public key
+  or certificate in this field is encoded in the manner as
+  defined in their respective definitions; see previous field.
+
+o Public Data Length (2 bytes) - The length of the Public Data
+  field, not including any other field.
+
+o Public Data (variable length) - The public data to be
+  sent to the receiver (computed Diffie-Hellman public values).
+  See section 2.2 Key Exchange Procedure for detailed description
+  how this field is computed.  This field is MP integer and is
+  encoded as defined in [SILC1].
+
+o Signature Length (2 bytes) - The length of the signature,
+  not including any other field.
+
+o Signature Data (variable length) - The signature signed
+  by the sender.  The receiver of this signature MUST
+  verify it.  The verification is done using the sender's
+  public key.  See section 2.2 Key Exchange Procedure for
+  detailed description how to produce the signature.  If
+  the Mutual Authentication flag is not set then initiator
+  MUST NOT provide this field and the Signature Length field
+  MUST be set to zero (0) value.  If the flag is set then
+  also the initiator MUST provide this field.  The responder
+  always MUST provide this field.  The encoding for signature
+  is defined in [SILC1].
+.in 3
+
+
+
+.ti 0
+2.2 Key Exchange Procedure
+
+The key exchange begins by sending SILC_PACKET_KEY_EXCHANGE packet with
+Key Exchange Start Payload to select the security properties to be used
+in the key exchange and later in the communication.
+
+After Key Exchange Start Payload has been processed by both of the
+parties the protocol proceeds as follows:
+
+
+Setup:  p is a large and public safe prime.  This is one of the
+        Diffie Hellman groups.  q is order of subgroup (largest
+        prime factor of p).  g is a generator and is defined
+        along with the Diffie Hellman group.
+
+    1.  Initiator generates a random number x, where 1 < x < q,
+        and computes e = g ^ x mod p.  The result e is then
+        encoded into Key Exchange Payload, with the public key
+        (or certificate) and sent to the responder.
+
+        If the Mutual Authentication flag is set then initiator
+        MUST also produce signature data SIGN_i which the responder
+        will verify.  The initiator MUST compute a hash value
+        HASH_i = hash(Initiator's Key Exchange Start Payload |
+        public key (or certificate) | e).  The '|' stands for
+        concatenation.  It then signs the HASH_i value with its
+        private key resulting a signature SIGN_i.
+
+    2.  Responder generates a random number y, where 1 < y < q,
+        and computes f = g ^ y mod p.  It then computes the
+        shared secret KEY = e ^ y mod p, and, a hash value
+        HASH = hash(Initiator's Key Exchange Start Payload |
+        public key (or certificate) | Initiator's public key
+        (or certificate) | e | f | KEY).  It then signs
+        the HASH value with its private key resulting a signature
+        SIGN.
+
+        It then encodes its public key (or certificate), f and
+        SIGN into Key Exchange Payload and sends it to the
+        initiator.
+
+        If the Mutual Authentication flag is set then the responder
+        SHOULD verify that the public key provided in the payload
+        is authentic, or if certificates are used it verifies the
+        certificate.  The responder MAY accept the public key without
+        verifying it, however, doing so may result to insecure key
+        exchange (accepting the public key without verifying may be
+        desirable for practical reasons on many environments.  For
+        long term use this is never desirable, in which case
+        certificates would be the preferred method to use).  It then
+        computes the HASH_i value the same way initiator did in the
+        phase 1.  It then verifies the signature SIGN_i from the
+        payload with the hash value HASH_i using the received public
+        key.
+
+    3.  Initiator verifies that the public key provided in
+        the payload is authentic, or if certificates are used
+        it verifies the certificate.  The initiator MAY accept
+        the public key without verifying it, however, doing
+        so may result to insecure key exchange (accepting the
+        public key without verifying may be desirable for
+        practical reasons on many environments.  For long term
+        use this is never desirable, in which case certificates
+        would be the preferred method to use).
+
+        Initiator then computes the shared secret KEY =
+        f ^ x mod p, and, a hash value HASH in the same way as
+        responder did in phase 2.  It then verifies the
+        signature SIGN from the payload with the hash value
+        HASH using the received public key.
+
+
+If any of these phases is to fail the SILC_PACKET_FAILURE MUST be sent
+to indicate that the key exchange protocol has failed, and the connection
+SHOULD be closed immediately.  Any other packets MUST NOT be sent or
+accepted during the key exchange except the SILC_PACKET_KEY_EXCHANGE_*,
+SILC_PACKET_FAILURE and SILC_PACKET_SUCCESS packets.
+
+The result of this protocol is a shared secret key material KEY and
+a hash value HASH.  The key material itself is not fit to be used as
+a key, it needs to be processed further to derive the actual keys to be
+used.  The key material is also used to produce other security parameters
+later used in the communication.  See section 2.3 Processing the Key
+Material for detailed description how to process the key material.
+
+If the Mutual Authentication flag was set the protocol produces also
+a hash value HASH_i.  This value, however, must be discarded.
+
+After the keys are processed the protocol is ended by sending the
+SILC_PACKET_SUCCESS packet.  Both entities send this packet to
+each other.  After this both parties MUST start using the new keys.
+
+
+.ti 0
+2.3 Processing the Key Material
+
+Key Exchange protocol produces secret shared key material KEY.  This
+key material is used to derive the actual keys used in the encryption
+of the communication channel.  The key material is also used to derive
+other security parameters used in the communication.  Key Exchange
+protocol produces a hash value HASH as well.
+
+The keys MUST be derived from the key material as follows:
+
+.in 6
+Sending Initial Vector (IV)     = hash(0x0 | KEY | HASH)
+Receiving Initial Vector (IV)   = hash(0x1 | KEY | HASH)
+Sending Encryption Key          = hash(0x2 | KEY | HASH)
+Receiving Encryption Key        = hash(0x3 | KEY | HASH)
+Sending HMAC Key                = hash(0x4 | KEY | HASH)
+Receiving HMAC Key              = hash(0x5 | KEY | HASH)
+.in 3
+
+
+The Initial Vector (IV) is used in the encryption when doing for
+example CBC mode.  As many bytes as needed are taken from the start of
+the hash output for IV.  Sending IV is for sending key and receiving IV
+is for receiving key.  For receiving party, the receiving IV is actually
+sender's sending IV, and, the sending IV is actually sender's receiving
+IV.  Initiator uses IV's as they are (sending IV for sending and
+receiving IV for receiving).
+
+The Encryption Keys are derived as well from the hash().  If the hash()
+output is too short for the encryption algorithm more key material MUST
+be produced in the following manner:
+
+.in 6
+K1 = hash(0x2 | KEY | HASH)
+K2 = hash(KEY | HASH | K1)
+K3 = hash(KEY | HASH | K1 | K2)  ...
+
+Sending Encryption Key = K1 | K2 | K3 ...
+
+
+K1 = hash(0x3 | KEY | HASH)
+K2 = hash(KEY | HASH | K1)
+K3 = hash(KEY | HASH | K1 | K2)  ...
+
+Receiving Encryption Key = K1 | K2 | K3 ...
+.in 3
+
+
+The key is distributed by hashing the previous hash with the original
+key material.  The final key is a concatenation of the hash values.
+For Receiving Encryption Key the procedure is equivalent.  Sending key
+is used only for encrypting data to be sent.  The receiving key is used
+only to decrypt received data.  For receiving party, the receive key is
+actually sender's sending key, and, the sending key is actually sender's
+receiving key.  Initiator uses generated keys as they are (sending key
+for sending and receiving key for receiving).
+
+The HMAC keys are used to create MAC values to packets in the
+communication channel.  As many bytes as needed are taken from the start
+of the hash output to generate the MAC keys.
+
+These procedures are performed by all parties of the key exchange
+protocol.  This MUST be done before the protocol has been ended by
+sending the SILC_PACKET_SUCCESS packet, to assure that parties can
+successfully process the key material.
+
+This same key processing procedure MAY be used in the SILC in some
+other circumstances as well.  Any changes to this procedure is defined
+separately when this procedure is needed.  See the [SILC1] and the
+[SILC2] for these circumstances.
+
+
+.ti 0
+2.4 SILC Key Exchange Groups
+
+The Following groups may be used in the SILC Key Exchange protocol.
+The first group diffie-hellman-group1 is REQUIRED, other groups MAY be
+negotiated to be used in the connection with Key Exchange Start Payload
+and SILC_PACKET_KEY_EXCHANGE packet.  However, the first group MUST be
+proposed in the Key Exchange Start Payload regardless of any other
+requested group (however, it does not have to be the first in the list).
+
+
+.ti 0
+2.4.1 diffie-hellman-group1
+
+The length of this group is 1024 bits.  This is REQUIRED group.
+The prime is 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 }.
+
+Its hexadecimal value is
+
+.in 6
+FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
+29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
+EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
+E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED
+EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE65381
+FFFFFFFF FFFFFFFF
+.in 3
+
+
+The generator used with this prime is g = 2.  The group order q is
+(p - 1) / 2.
+
+This group was taken from RFC 2412.
+
+
+.ti 0
+2.4.2 diffie-hellman-group2
+
+The length of this group is 1536 bits.  This is OPTIONAL group.
+The prime is 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 }.
+
+Its hexadecimal value is
+
+.in 6
+FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
+29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
+EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
+E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED
+EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D
+C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F
+83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D
+670C354E 4ABC9804 F1746C08 CA237327 FFFFFFFF FFFFFFFF
+.in 3
+
+The generator used with this prime is g = 2.  The group order q is
+(p - 1) / 2.
+
+This group was taken from RFC 3526.
+
+
+.ti 0
+2.4.3 diffie-hellman-group3
+
+The length of this group is 2048 bits.  This is OPTIONAL group.
+This prime is: 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 }.
+
+Its hexadecimal value is
+
+.in 6
+FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
+29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
+EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
+E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED
+EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D
+C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F
+83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D
+670C354E 4ABC9804 F1746C08 CA18217C 32905E46 2E36CE3B
+E39E772C 180E8603 9B2783A2 EC07A28F B5C55DF0 6F4C52C9
+DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510
+15728E5A 8AACAA68 FFFFFFFF FFFFFFFF
+.in 3
+
+The generator used with this prime is g = 2.  The group order q is
+(p - 1) / 2.
+
+This group was taken from RFC 3526.
+
+Additional larger groups are defined in RFC 3526 and may be used in SKE
+by defining name for them using the above name format.
+
+
+.ti 0
+2.5 Key Exchange Status Types
+
+This section defines all key exchange protocol status types that may
+be returned in the SILC_PACKET_SUCCESS or SILC_PACKET_FAILURE packets
+to indicate the status of the protocol.  Implementations may map the
+status types to human readable error message.  All types except the
+SILC_SKE_STATUS_OK type MUST be sent in SILC_PACKET_FAILURE packet.
+The length of status is 32 bits (4 bytes).  The following status types
+are defined:
+
+.in 6
+0   SILC_SKE_STATUS_OK
+
+    Protocol were executed successfully.
+
+
+1   SILC_SKE_STATUS_ERROR
+
+    Unknown error occurred.  No specific error type is defined.
+
+
+2   SILC_SKE_STATUS_BAD_PAYLOAD
+
+    Provided KE payload were malformed or included bad fields.
+
+
+3   SILC_SKE_STATUS_UNSUPPORTED_GROUP
+
+    None of the provided groups were supported.
+
+
+4   SILC_SKE_STATUS_UNSUPPORTED_CIPHER
+
+    None of the provided ciphers were supported.
+
+
+5   SILC_SKE_STATUS_UNSUPPORTED_PKCS
+
+    None of the provided public key algorithms were supported.
+
+
+6   SILC_SKE_STATUS_UNSUPPORTED_HASH_FUNCTION
+
+    None of the provided hash functions were supported.
+
+
+7   SILC_SKE_STATUS_UNSUPPORTED_HMAC
+
+    None of the provided HMACs were supported.
+
+
+8   SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY
+
+    Provided public key type is not supported.
+
+
+9   SILC_SKE_STATUS_INCORRECT_SIGNATURE
+
+    Provided signature was incorrect.
+
+
+10  SILC_SKE_STATUS_BAD_VERSION
+
+    Provided version string was not acceptable.
+
+
+11  SILC_SKE_STATUS_INVALID_COOKIE
+
+    The cookie in the Key Exchange Start Payload was malformed,
+    because responder modified the cookie.
+.in 3
+
+
+.ti 0
+3 SILC Connection Authentication Protocol
+
+Purpose of Connection Authentication protocol is to authenticate the
+connecting party with server.  Usually connecting party is client but
+server may connect to router server as well.  Its other purpose is to
+provide information for the server about which type of entity the
+connection is.  The type defines whether the connection is client,
+server or router connection.  Server use this information to create the
+ID for the connection.
+
+Server MUST verify the authentication data received and if it is to fail
+the authentication MUST be failed by sending SILC_PACKET_FAILURE packet.
+If authentication is successful the protocol is ended by server by sending
+SILC_PACKET_SUCCESS packet.
+
+The protocol is executed after the SILC Key Exchange protocol.  It MUST
+NOT be executed in any other time.  As it is performed after key exchange
+protocol all traffic in the connection authentication protocol is
+encrypted with the exchanged keys.
+
+The protocol MUST be started by the connecting party by sending the
+SILC_PACKET_CONNECTION_AUTH packet with Connection Auth Payload,
+described in the next section.  This payload MUST include the
+authentication data.  The authentication data is set according
+authentication method that MUST be known by both parties.  If connecting
+party does not know what is the mandatory authentication method it MAY
+request it from the server by sending SILC_PACKET_CONNECTION_AUTH_REQUEST
+packet.  This packet is not part of this protocol and is described in
+section Connection Auth Request Payload in [SILC2].  However, if
+connecting party already knows the mandatory authentication method
+sending the request is not necessary.
+
+See [SILC1] and section Connection Auth Request Payload in [SILC2] also
+for the list of different authentication methods.  Authentication method
+MAY also be NONE, in which case the server does not require
+authentication.  However, in this case the protocol still MUST be
+executed; the authentication data is empty indicating no authentication
+is required.
+
+If authentication method is passphrase the authentication data is
+plaintext passphrase.  As the payload is encrypted it is safe to have
+plaintext passphrase.  It is also provided as plaintext passphrase
+because the receiver may need to pass the entire passphrase into a
+passphrase verifier, and a message digest of the passphrase would
+prevent this.  See the section 3.2.1 Passphrase Authentication for
+more information.
+
+If authentication method is public key authentication the authentication
+data is a digital signature of the hash value of hash HASH and Key
+Exchange Start Payload, established by the SILC Key Exchange protocol.
+This signature MUST then be verified by the server.  See the section
+3.2.2 Public Key Authentication for more information.
+
+See the section 4 SILC Procedures in [SILC1] for more information about
+client creating connection to server, and server creating connection
+to router, and how to register the session in the SILC Network after
+successful Connection Authentication protocol.
+
+
+.ti 0
+3.1 Connection Auth Payload
+
+Client sends this payload to authenticate itself to the server.  Server
+connecting to another server also sends this payload.  Server receiving
+this payload MUST verify all the data in it and if something is to fail
+the authentication MUST be failed by sending SILC_PACKET_FAILURE packet.
+
+The payload may only be sent with SILC_PACKET_CONNECTION_AUTH packet.
+It MUST NOT be sent in any other packet type.  The following diagram
+represent the Connection Auth Payload.
+
+
+
+
+
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Payload Length         |        Connection Type        |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                     Authentication Data                       ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 3:  Connection Auth Payload
+
+
+.in 6
+o Payload Length (2 bytes) - Length of the entire Connection
+  Auth Payload.
+
+o Connection Type (2 bytes) - Indicates the type of the
+  connection.  See section Connection Auth Request Payload
+  in [SILC2] for the list of connection types.  This field MUST
+  include valid connection type or the packet MUST be discarded
+  and authentication MUST be failed.
+
+o Authentication Data (variable length) - The actual
+  authentication data.  Contents of this depends on the
+  authentication method known by both parties.  If no
+  authentication is required this field does not exist.
+.in 3
+
+
+.ti 0
+3.2 Connection Authentication Types
+
+SILC supports two authentication types to be used in the connection
+authentication protocol; passphrase authentication or public key
+authentication based on digital signatures.  The following sections
+defines the authentication methods.  See [SILC2] for defined numerical
+authentication method types.
+
+
+.ti 0
+3.2.1 Passphrase Authentication
+
+Passphrase authentication or pre-shared key based authentication is
+simply an authentication where the party that wants to authenticate
+itself to the other end sends the passphrase that is required by
+the other end, for example server.  The plaintext passphrase is put
+to the payload, that is then encrypted.  The plaintext passphrase
+MUST be in UTF-8 [RFC2279] encoding.  If the passphrase is in the
+sender's system in some other encoding it MUST be UTF-8 encoded
+before transmitted.  The receiver MAY change the encoding of the
+passphrase to its system's default character encoding before verifying
+the passphrase.
+
+If the passphrase matches with the one in the server's end the
+authentication is successful.  Otherwise SILC_PACKET_FAILURE MUST be
+sent to the sender and the protocol execution fails.
+
+This is REQUIRED authentication method to be supported by all SILC
+implementations.
+
+When password authentication is used it is RECOMMENDED that maximum
+amount of padding is applied to the SILC packet.  This way it is not
+possible to approximate the length of the password from the encrypted
+packet.
+
+
+
+.ti 0
+3.2.2 Public Key Authentication
+
+Public key authentication may be used if passphrase based authentication
+is not desired.  The public key authentication works by sending a
+digital signature as authentication data to the other end, say, server.
+The server MUST then verify the signature by the public key of the sender,
+which the server has received earlier in SKE protocol.
+
+The signature is computed using the private key of the sender by signing
+the HASH value provided by the SKE protocol previously, and the Key
+Exchange Start Payload from SKE protocol that was sent to the server.
+These are concatenated and hash function is used to compute a hash value
+which is then signed.
+
+  auth_hash = hash(HASH | Key Exchange Start Payload);
+  signature = sign(auth_hash);
+
+The hash() function used to compute the value is the hash function
+negotiated in the SKE protocol.  The server MUST verify the data, thus
+it must keep the HASH and the Key Exchange Start Payload saved during
+SKE and authentication protocols.  These values can be discarded after
+Connection Authentication protocol is completed.
+
+If the verified signature matches the sent signature, the authentication
+were successful and SILC_PACKET_SUCCESS is sent.  If it failed the
+protocol execution is stopped and SILC_PACKET_FAILURE is sent.
+
+This is REQUIRED authentication method to be supported by all SILC
+implementations.
+
+
+
+.ti 0
+3.3 Connection Authentication Status Types
+
+This section defines all connection authentication status types that
+may be returned in the SILC_PACKET_SUCCESS or SILC_PACKET_FAILURE packets
+to indicate the status of the protocol.  Implementations may map the
+status types to human readable error message.  All types except the
+SILC_AUTH_STATUS_OK type MUST be sent in SILC_PACKET_FAILURE packet.
+The length of status is 32 bits (4 bytes).  The following status types
+are defined:
+
+0   SILC_AUTH_OK
+
+    Protocol was executed successfully.
+
+
+1   SILC_AUTH_FAILED
+
+    Authentication failed.
+
+
+.ti 0
+4 Security Considerations
+
+Security is central to the design of this protocol, and these security
+considerations permeate the specification.  Common security considerations
+such as keeping private keys truly private and using adequate lengths for
+symmetric and asymmetric keys must be followed in order to maintain the
+security of this protocol.
+
+
+.ti 0
+5 References
+
+[SILC1]      Riikonen, P., "Secure Internet Live Conferencing (SILC),
+             Protocol Specification", Internet Draft, June 2003.
+
+[SILC2]      Riikonen, P., "SILC Packet Protocol", Internet Draft,
+             June 2003.
+
+[SILC4]      Riikonen, P., "SILC Commands", Internet Draft, June 2003.
+
+[IRC]        Oikarinen, J., and Reed D., "Internet Relay Chat Protocol",
+             RFC 1459, May 1993.
+
+[IRC-ARCH]   Kalt, C., "Internet Relay Chat: Architecture", RFC 2810,
+             April 2000.
+
+[IRC-CHAN]   Kalt, C., "Internet Relay Chat: Channel Management", RFC
+             2811, April 2000.
+
+[IRC-CLIENT] Kalt, C., "Internet Relay Chat: Client Protocol", RFC
+             2812, April 2000.
+
+[IRC-SERVER] Kalt, C., "Internet Relay Chat: Server Protocol", RFC
+             2813, April 2000.
+
+[SSH-TRANS]  Ylonen, T., et al, "SSH Transport Layer Protocol",
+             Internet Draft.
+
+[PGP]        Callas, J., et al, "OpenPGP Message Format", RFC 2440,
+             November 1998.
+
+[SPKI]       Ellison C., et al, "SPKI Certificate Theory", RFC 2693,
+             September 1999.
+
+[PKIX-Part1] Housley, R., et al, "Internet X.509 Public Key
+             Infrastructure, Certificate and CRL Profile", RFC 2459,
+             January 1999.
+
+[Schneier]   Schneier, B., "Applied Cryptography Second Edition",
+             John Wiley & Sons, New York, NY, 1996.
+
+[Menezes]    Menezes, A., et al, "Handbook of Applied Cryptography",
+             CRC Press 1997.
+
+[OAKLEY]     Orman, H., "The OAKLEY Key Determination Protocol",
+             RFC 2412, November 1998.
+
+[ISAKMP]     Maughan D., et al, "Internet Security Association and
+             Key Management Protocol (ISAKMP)", RFC 2408, November
+             1998.
+
+[IKE]        Harkins D., and Carrel D., "The Internet Key Exchange
+             (IKE)", RFC 2409, November 1998.
+
+[HMAC]       Krawczyk, H., "HMAC: Keyed-Hashing for Message
+             Authentication", RFC 2104, February 1997.
+
+[PKCS1]      Kalinski, B., and Staddon, J., "PKCS #1 RSA Cryptography
+             Specifications, Version 2.0", RFC 2437, October 1998.
+
+[RFC2119]    Bradner, S., "Key Words for use in RFCs to Indicate
+             Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+[RFC2279]    Yergeau, F., "UTF-8, a transformation format of ISO
+             10646", RFC 2279, January 1998.
+
+
+.ti 0
+6 Author's Address
+
+.nf
+Pekka Riikonen
+Snellmaninkatu 34 A 15
+70100 Kuopio
+Finland
+
+EMail: priikone@iki.fi
+
+
+.ti 0
+7 Full Copyright Statement
+
+Copyright (C) The Internet Society (2003). All Rights Reserved.
+
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/doc/draft-riikonen-silc-pp-07.nroff b/doc/draft-riikonen-silc-pp-07.nroff
new file mode 100644 (file)
index 0000000..3792722
--- /dev/null
@@ -0,0 +1,3017 @@
+.pl 10.0i
+.po 0
+.ll 7.2i
+.lt 7.2i
+.nr LL 7.2i
+.nr LT 7.2i
+.ds LF Riikonen
+.ds RF FORMFEED[Page %]
+.ds CF
+.ds LH Internet Draft
+.ds RH 28 July 2003
+.ds CH
+.na
+.hy 0
+.in 0
+.nf
+Network Working Group                                        P. Riikonen
+Internet-Draft
+draft-riikonen-silc-pp-07.txt                               28 July 2003
+Expires: 28 January 2004
+
+.in 3
+
+.ce 2
+SILC Packet Protocol
+<draft-riikonen-silc-pp-07.txt>
+
+.ti 0
+Status of this Memo
+
+This document is an Internet-Draft and is in full conformance with
+all provisions of Section 10 of RFC 2026.  Internet-Drafts are
+working documents of the Internet Engineering Task Force (IETF), its
+areas, and its working groups.  Note that other groups may also
+distribute working documents as Internet-Drafts.
+
+Internet-Drafts are draft documents valid for a maximum of six months
+and may be updated, replaced, or obsoleted by other documents at any
+time.  It is inappropriate to use Internet-Drafts as reference
+material or to cite them other than as "work in progress."
+
+The list of current Internet-Drafts can be accessed at
+http://www.ietf.org/ietf/1id-abstracts.txt
+
+The list of Internet-Draft Shadow Directories can be accessed at
+http://www.ietf.org/shadow.html
+
+The distribution of this memo is unlimited.
+
+
+.ti 0
+Abstract
+
+This memo describes a Packet Protocol used in the Secure Internet Live
+Conferencing (SILC) protocol, specified in the Secure Internet Live
+Conferencing, Protocol Specification [SILC1].  This protocol describes
+the packet types and packet payloads which defines the contents of the
+packets.  The protocol provides secure binary packet protocol that
+assures that the contents of the packets are secured and authenticated.
+
+
+
+
+
+
+
+
+
+.ti 0
+Table of Contents
+
+.nf
+1 Introduction ..................................................  3
+  1.1 Requirements Terminology ..................................  4
+2 SILC Packet Protocol ..........................................  4
+  2.1 SILC Packet ...............................................  4
+  2.2 SILC Packet Header ........................................  5
+  2.3 SILC Packet Types .........................................  7
+      2.3.1 SILC Packet Payloads ................................ 15
+      2.3.2 Generic payloads .................................... 15
+            2.3.2.1 ID Payload .................................. 15
+            2.3.2.2 Argument Payload ............................ 16
+            2.3.2.3 Argument List Payload ....................... 17
+            2.3.2.4 Channel Payload ............................. 18
+            2.3.2.5 Public Key Payload .......................... 19
+            2.3.2.6 Message Payload ............................. 19
+      2.3.3 Disconnect Payload .................................. 23
+      2.3.4 Success Payload ..................................... 23
+      2.3.5 Failure Payload ..................................... 24
+      2.3.6 Reject Payload ...................................... 24
+      2.3.7 Notify Payload ...................................... 25
+      2.3.8 Error Payload ....................................... 34
+      2.3.9 Channel Message Payload ............................. 34
+      2.3.10 Channel Key Payload ................................ 35
+      2.3.11 Private Message Payload ............................ 37
+      2.3.12 Private Message Key Payload ........................ 37
+      2.3.13 Command Payload .................................... 39
+      2.3.14 Command Reply Payload .............................. 40
+      2.3.15 Connection Auth Request Payload .................... 40
+      2.3.16 New ID Payload ..................................... 41
+      2.3.17 New Client Payload ................................. 42
+      2.3.18 New Server Payload ................................. 43
+      2.3.19 New Channel Payload ................................ 44
+      2.3.20 Key Agreement Payload .............................. 45
+      2.3.21 Resume Router Payload .............................. 46
+      2.3.22 File Transfer Payload .............................. 46
+      2.3.23 Resume Client Payload .............................. 48
+  2.4 SILC ID Types ............................................. 49
+  2.5 Packet Encryption And Decryption .......................... 49
+      2.5.1 Normal Packet Encryption And Decryption ............. 50
+      2.5.2 Channel Message Encryption And Decryption ........... 50
+      2.5.3 Private Message Encryption And Decryption ........... 51
+  2.6 Packet MAC Generation ..................................... 52
+  2.7 Packet Padding Generation ................................. 52
+  2.8 Packet Compression ........................................ 53
+  2.9 Packet Sending ............................................ 53
+  2.10 Packet Reception ......................................... 54
+  2.11 Packet Routing ........................................... 54
+  2.12 Packet Broadcasting ...................................... 55
+3 Security Considerations ....................................... 56
+4 References .................................................... 56
+5 Author's Address .............................................. 58
+6 Full Copyright Statement ...................................... 58
+
+.ti 0
+List of Figures
+
+.nf
+Figure 1:   Typical SILC Packet
+Figure 2:   SILC Packet Header
+Figure 3:   ID Payload
+Figure 4:   Argument Payload
+Figure 5:   Argument List Payload
+Figure 6:   Channel Payload
+Figure 7:   Public Key Payload
+Figure 8:   Message Payload
+Figure 9:   Disconnect Payload
+Figure 10:  Success Payload
+Figure 11:  Failure Payload
+Figure 12:  Reject Payload
+Figure 13:  Notify Payload
+Figure 14:  Error Payload
+Figure 15:  Channel Key Payload
+Figure 16:  Private Message Key Payload
+Figure 17:  Command Payload
+Figure 18:  Connection Auth Request Payload
+Figure 19:  New Client Payload
+Figure 20:  New Server Payload
+Figure 21:  Key Agreement Payload
+Figure 22:  Resume Router Payload
+Figure 23:  File Transfer Payload
+Figure 24:  Resume Client Payload
+
+
+.ti 0
+1. Introduction
+
+This document describes a Packet Protocol used in the Secure Internet
+Live Conferencing (SILC) protocol specified in the Secure Internet Live
+Conferencing, Protocol Specification [SILC1].  This protocol describes
+the packet types and packet payloads which defines the contents of the
+packets.  The protocol provides secure binary packet protocol that
+assures that the contents of the packets are secured and authenticated.
+The packet protocol is designed to be compact to avoid unnecessary
+overhead as much as possible.  This makes the SILC suitable also in
+environment of low bandwidth requirements such as mobile networks.  All
+packet payloads can also be compressed to further reduce the size of
+the packets.
+
+All packets in SILC network are always encrypted and their integrity
+is assured by computed MACs.  The protocol defines several packet types
+and packet payloads.  Each packet type usually has a specific packet
+payload that actually defines the contents of the packet.  Each packet
+also includes a default SILC Packet Header that provides sufficient
+information about the origin and the destination of the packet.
+
+
+.ti 0
+1.1 Requirements Terminology
+
+The keywords MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, RECOMMENDED,
+MAY, and OPTIONAL, when they appear in this document, are to be
+interpreted as described in [RFC2119].
+
+
+.ti 0
+2 SILC Packet Protocol
+
+.ti 0
+2.1 SILC Packet
+
+SILC packets deliver messages from sender to receiver securely by
+encrypting important fields of the packet.  The packet consists of
+default SILC Packet Header, Padding, Packet Payload data, and, packet
+MAC.
+
+The following diagram illustrates typical SILC packet.
+
+.in 5
+.nf
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+|   n bytes   | 1 - n bytes |      n bytes       |  n bytes
+| SILC Header |   Padding   |    Data Payload    |    MAC
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+.in 3
+
+.ce
+Figure 1:  Typical SILC Packet
+
+
+SILC Header is always the first part of the packet and its purpose
+is to provide information about the packet.  It provides for example
+the packet type, origin of the packet and the destination of the packet.
+The header is variable in length.  See the following section for
+description of SILC Packet header.  Packets without SILC header or
+with malformed SILC header MUST be dropped.
+
+Padding follows the packet header.  The purpose of the padding is to
+make the packet multiple by eight (8) or by the block size of the
+cipher used in the encryption, which ever is larger.  The maximum
+length of padding is currently 128 bytes.  The padding is always
+encrypted.  The padding is applied always, even if the packet is
+not encrypted.  See the section 2.7 Padding Generation for more
+detailed information.
+
+Data payload area follows padding and it is the actual data of the
+packet.  The packet data is the packet payloads defined in this
+protocol.  The data payload area is always encrypted.
+
+The last part of SILC packet is the packet MAC that assures the
+integrity of the packet.  See the section 2.6 Packet MAC Generation
+for more information.  If compression is used the compression is
+always applied before encryption.
+
+All fields in all packet payloads are always in MSB (most significant
+byte first) order.
+
+
+.ti 0
+2.2 SILC Packet Header
+
+The SILC packet header is applied to all SILC packets and it is
+variable in length.  The purpose of SILC Packet header is to provide
+detailed information about the packet.  The receiver of the packet
+uses the packet header to parse the packet and gain other relevant
+parameters of the packet.
+
+The following diagram represents the SILC packet header.
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|         Payload Length        |     Flags     |  Packet Type  |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|   Pad Length  |    RESERVED   | Source ID Len |  Dest ID Len  |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|  Src ID Type  |                                               |
++-+-+-+-+-+-+-+-+                                               +
+|                                                               |
+~                           Source ID                           ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|  Dst ID Type  |                                               |
++-+-+-+-+-+-+-+-+                                               +
+|                                                               |
+~                         Destination ID                        ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 2:  SILC Packet Header
+
+.in 6
+o Payload Length (2 bytes) - Indicates the length of the
+  packet not including the padding of the packet.
+
+o Flags (1 byte) - Indicates flags to be used in packet
+  processing.  Several flags may be set by ORing the flags
+  together.
+
+  The following flags are reserved for this field:
+
+
+     No flags                  0x00
+
+       In this case the field is ignored.
+
+
+     Private Message Key       0x01
+
+       Indicates that the packet data MUST include private
+       message that is encrypted using private key set by
+       client.  Servers does not know this key and cannot
+       handle the packet, but passes it along.  See section
+       2.5.3 Private Message Encryption And Decryption for
+       more information.
+
+
+     List                      0x02
+
+       Indicates that the packet consists of list of
+       packet payloads indicated by the Packet Type field.
+       The payloads are added one after the other.  Note that
+       there are packet types that must not be used as
+       list.  Parsing of list packet is done by calculating
+       the length of each payload and parsing them one by
+       one.
+
+
+     Broadcast                 0x04
+
+       Marks the packet to be broadcasted.  Client and normal
+       server cannot send broadcast packets.  Only router server
+       may send broadcast packet.  The router receiving of packet
+       with this flag set MUST send (broadcast) the packet to
+       its primary route.  If router has several router connections
+       the packet may be sent only to the primary route.  See
+       section 2.12 Packet Broadcasting for description of
+       packet broadcasting.
+
+
+     Compressed                0x08
+
+       Marks that the payload of the packet is compressed.
+       The sender of the packet marks this flag when it
+       compresses the payload, and any server or router
+       en route to the recipient MUST NOT unset this flag.
+       See section 2.8 Packet Compression for description of
+       packet compressing.
+
+.in 3
+
+o Packet Type (1 byte) - Indicates the type of the packet.
+  Receiver uses this field to parse the packet.  See section
+  2.3 SILC Packets for list of defined packet types.
+
+o Pad Length (1 byte) - Indicates the length of the padding
+  applied after the SILC Packet header.  Maximum length for
+  padding is 128 bytes.
+
+o RESERVED (1 byte) - Reserved field and must include a
+  zero (0) value.
+
+o Source ID Length (1 byte) - Indicates the length of the
+  Source ID field in the header, not including this or any
+  other fields.
+
+o Destination ID Length (1 byte) - Indicates the length of the
+  Destination ID field in the header, not including this or
+  any other fields.
+
+o Src ID Type (1 byte) - Indicates the type of ID in the
+  Source ID field.  See section 2.4 SILC ID Types for
+  defined ID types.
+
+o Source ID (variable length) - The actual source ID that
+  indicates which is the original sender of the packet.
+
+o Dst ID Type (1 byte) - Indicates the type of ID in the
+  Destination ID field.  See section 2.4 SILC ID Types for
+  defined ID types.
+
+o Destination ID (variable length) - The actual destination
+  ID that indicates which is the end receiver of the packet.
+
+
+
+.ti 0
+2.3 SILC Packet Types
+
+SILC packet types defines the contents of the packet and it is used by
+the receiver to parse the packet.  The packet type is 8 bits in length.
+The range for the packet types are from 0 - 255, where 0 is never sent and
+255 is currently reserved for future extensions and MUST NOT be defined to
+any other purpose.  Every SILC specification compliant implementation
+SHOULD support all the following packet types.
+
+The below list of the SILC Packet types includes reference to the packet
+payload as well.  Packet payloads are the actual packet data area.  Each
+packet type defines packet payload which usually may only be sent with
+the specific packet type.
+
+Most of the packets are packets that must be destined directly to entity
+that is connected to the sender.  It is not allowed, for example, for a
+router to send SILC_PACKET_DISCONNECT packet to client that is not
+directly connected to the router.  However, there are some special packet
+types that may be destined to some entity that the sender does not have
+direct connection with.  These packets are for example private message
+packets, channel message packets, command packets and some other packets
+that may be broadcasted in the SILC network.  If the packet is allowed to
+be sent to indirectly connected entity it is defined separately in the
+following packet description list.  Other packets MUST NOT be sent or
+accepted, if sent, to indirectly connected entities.
+
+Some packets MAY be sent as lists by adding the List flag to the Packet
+Header and constructing multiple packet payloads one after the other.
+When this is allowed it is separately defined in the following list.
+Other packets MUST NOT be sent as list and the List flag MUST NOT be set.
+
+
+List of SILC Packet types are defined as follows.
+
+.in 1
+     0    SILC_PACKET_NONE
+
+          This type is reserved and it is never sent.
+
+
+     1    SILC_PACKET_DISCONNECT
+
+          This packet is sent to disconnect the remote end.  Reason of
+          the disconnection is sent inside the packet payload.
+
+          Payload of the packet:  See section 2.3.3 Disconnect Payload
+
+
+     2    SILC_PACKET_SUCCESS
+
+          This packet is sent upon successful execution of a protocol.
+          The status of the success is sent in the packet payload.
+
+          Payload of the packet:  See section 2.3.4 Success Payload
+
+
+     3    SILC_PACKET_FAILURE
+
+          This packet is sent upon failure of a protocol.  The status
+          of the failure is sent in the packet payload.
+
+          Payload of the packet:  See section 2.3.5 Failure Payload
+
+
+     4    SILC_PACKET_REJECT
+
+          This packet MAY be sent upon rejection of a protocol.  The
+          status of the rejection is sent in the packet payload.
+
+          Payload of the packet:  See section 2.3.6 Reject Payload
+
+
+     5    SILC_PACKET_NOTIFY
+
+          This packet is used to send notify message.  The packet is
+          usually sent between server and client, but also between
+          server and router.  Client MUST NOT send this packet.  Server
+          MAY destine this packet to channel as well when the packet is
+          distributed to all clients on the channel.  This packet MAY
+          be sent as list.
+
+          Payload of the packet:  See section 2.3.7 Notify Payload.
+
+
+     6    SILC_PACKET_ERROR
+
+          This packet is sent when an error occurs.  Server MAY
+          send this packet.  Client MUST NOT send this packet.  The
+          client MAY entirely ignore the packet, however, server is
+          most likely to take action anyway.  This packet MAY be sent
+          to entity that is indirectly connected to the sender.
+
+          Payload of the packet:  See section 2.3.8 Error Payload.
+
+
+     7    SILC_PACKET_CHANNEL_MESSAGE
+
+          This packet is used to send messages to channels.  The packet
+          includes Channel ID of the channel and the actual message to
+          the channel.  Messages sent to the channel are always protected
+          by channel specific keys.  This packet MAY be sent to entity
+          that is indirectly connected to the sender.
+
+          Payload of the packet:  See section 2.3.9 Channel Message
+                                  Payload
+
+
+     8    SILC_PACKET_CHANNEL_KEY
+
+          This packet is used to distribute new key for particular
+          channel when server generates it.  Each channel has their own
+          independent keys that is used to protect the traffic on the
+          channel.  It is also possible to use channel private keys that
+          are not server generated.  In this case this packet is not used.
+          Client MUST NOT send this packet.  This packet MAY be sent to
+          entity that is indirectly connected to the sender.
+
+          Payload of the packet:  See section 2.3.10 Channel Key Payload
+
+
+     9    SILC_PACKET_PRIVATE_MESSAGE
+
+          This packet is used to send private messages from client
+          to another client.  By default, private messages are protected
+          by session keys established by normal key exchange protocol.
+          However, it is possible to use specific key to protect private
+          messages.  See [SILC1] for private message key generation.
+          This packet MAY be sent to entity that is indirectly connected
+          to the sender.
+
+          Payload of the packet:  See section 2.3.11 Private Message
+                                  Payload
+
+
+     10   SILC_PACKET_PRIVATE_MESSAGE_KEY
+
+          This packet can be used to agree about a key to be used to
+          protect private messages between two clients.  This packet
+          is sent inside the SILC network and protected with session
+          keys.  There are other means of agreeing to use private message
+          keys as well, than sending this packet which may not be
+          desirable on all situations.  See the [SILC1] for private
+          message key generation.
+
+          Payload of the packet:  See section 2.3.12 Private Message
+                                  Key Payload
+
+
+     11   SILC_PACKET_COMMAND
+
+          This packet is used to send commands from client to server.
+          Server MAY send this packet to other servers as well.  All
+          commands are listed in their own section SILC Command Types
+          in [SILC4].  The contents of this packet is command specific.
+          This packet MAY be sent to entity that is indirectly connected
+          to the sender.
+
+          Payload of the packet:  See section 2.3.13 Command Payload
+
+
+     12   SILC_PACKET_COMMAND_REPLY
+
+          This packet is sent as reply to the SILC_PACKET_COMMAND packet.
+          The contents of this packet is command specific.  This packet
+          MAY be sent to entity that is indirectly connected to the
+          sender.  This packet MAY be sent as list.
+
+          Payload of the packet:  See section 2.3.14 Command Reply
+                                  Payload and section 2.3.13 Command
+                                  Payload
+
+
+
+     13   SILC_PACKET_KEY_EXCHANGE
+
+          This packet is used to start SILC Key Exchange Protocol,
+          described in detail in [SILC3].
+
+          Payload of the packet:  Payload of this packet is described
+                                  in the section SILC Key Exchange
+                                  Protocol and its sub sections in
+                                  [SILC3].
+
+
+     14   SILC_PACKET_KEY_EXCHANGE_1
+
+          This packet is used as part of the SILC Key Exchange Protocol.
+
+          Payload of the packet:  Payload of this packet is described
+                                  in the section SILC Key Exchange
+                                  Protocol and its sub sections in
+                                  [SILC3].
+
+
+     15   SILC_PACKET_KEY_EXCHANGE_2
+
+          This packet is used as part of the SILC Key Exchange Protocol.
+
+          Payload of the packet:  Payload of this packet is described
+                                  in the section SILC Key Exchange
+                                  Protocol and its sub sections in
+                                  [SILC3].
+
+
+     16   SILC_PACKET_CONNECTION_AUTH_REQUEST
+
+          This packet is used to request an authentication method to
+          be used in the SILC Connection Authentication Protocol.  If
+          initiator of the protocol does not know the mandatory
+          authentication method this packet MAY be used to determine it.
+          The party receiving this payload SHOULD respond with the same
+          packet including the mandatory authentication method.
+
+          Payload of the packet:  See section 2.3.15 Connection Auth
+                                  Request Payload
+
+
+     17   SILC_PACKET_CONNECTION_AUTH
+
+          This packet is used to start and perform the SILC Connection
+          Authentication Protocol.  This protocol is used to authenticate
+          the connecting party.  The protocol is described in detail in
+          [SILC3].
+
+          Payload of the packet:  Payload of this packet is described
+                                  in the section SILC Authentication
+                                  Protocol and it sub sections in [SILC].
+
+
+     18   SILC_PACKET_NEW_ID
+
+          This packet is used to distribute new IDs from server to
+          router and from router to all other routers in SILC network.
+          This is used when for example new client is registered to
+          SILC network.  The newly created IDs of these operations are
+          distributed by this packet.  Only server may send this packet,
+          however, client MUST be able to receive this packet.  This
+          packet MAY be sent to entity that is indirectly connected
+          to the sender.  This packet MAY be sent as list.
+
+          Payload of the packet:  See section 2.3.16 New ID Payload
+
+
+     19   SILC_PACKET_NEW_CLIENT
+
+          This packet is used by client to register itself to the
+          SILC network.  This is sent after key exchange and
+          authentication protocols has been completed.  Client sends
+          various information about itself in this packet to the server.
+
+          Payload of the packet:  See section 2.3.17 New Client Payload
+
+
+     20   SILC_PACKET_NEW_SERVER
+
+          This packet is used by server to register itself to the
+          SILC network.  This is sent after key exchange and
+          authentication protocols has been completed.  Server sends
+          this to the router it connected to, or, if router was
+          connecting, to the connected router.  Server sends its
+          Server ID and other information in this packet.  The client
+          MUST NOT send or receive this packet.
+
+          Payload of the packet:  See section 2.3.18 New Server Payload
+
+
+     21   SILC_PACKET_NEW_CHANNEL
+
+          This packet is used to notify routers about newly created
+          channel.  Channels are always created by the router and it MUST
+          notify other routers about the created channel.  Router sends
+          this packet to its primary route.  Client MUST NOT send this
+          packet.  This packet MAY be sent to entity that is indirectly
+          connected to the sender.  This packet MAY be sent as list.
+
+          Payload of the packet:  See section 2.3.19 New Channel Payload
+
+
+     22   SILC_PACKET_REKEY
+
+          This packet is used to indicate that re-key must be performed
+          for session keys.  See section Session Key Regeneration in
+          [SILC1] for more information.  This packet does not have
+          a payload.
+
+
+     23   SILC_PACKET_REKEY_DONE
+
+          This packet is used to indicate that re-key is performed and
+          new keys must be used hereafter.  This packet does not have a
+          payload.
+
+
+     24   SILC_PACKET_HEARTBEAT
+
+          This packet is used by clients, servers and routers to keep the
+          connection alive.  It is RECOMMENDED that all servers implement
+          keepalive actions and perform it to both direction in a link.
+          This packet does not have a payload.
+
+
+     25   SILC_PACKET_KEY_AGREEMENT
+
+          This packet is used by clients to request key negotiation
+          between another client in the SILC network.  If the negotiation
+          is started it is performed using the SKE protocol.  The result of
+          the negotiation, the secret key material, can be used for
+          example as private message key.  The server and router MUST NOT
+          send this packet.
+
+          Payload of the packet:  See section 2.3.20 Key Agreement Payload
+
+
+     26   SILC_PACKET_RESUME_ROUTER
+
+          This packet is used during backup router protocol when the
+          original primary router of the cell comes back online and wishes
+          to resume the position as being the primary router of the cell.
+
+          Payload of the packet:  See section 2.3.21 Resume Router Payload
+
+
+     27   SILC_PACKET_FTP
+
+          This packet is used to perform an file transfer protocol in the
+          SILC session with some entity in the network.  The packet is
+          multi purpose.  The packet is used to tell other entity in the
+          network that the sender wishes to perform an file transfer
+          protocol.  The packet is also used to actually tunnel the
+          file transfer protocol stream.  The file transfer protocol
+          stream is always protected with the SILC binary packet protocol.
+
+          Payload of the packet:  See section 2.3.22 File Transfer Payload
+
+
+     28   SILC_PACKET_RESUME_CLIENT
+
+          This packet is used to resume a client back to the network
+          after it has been detached.  A client is able to detach from
+          the network but the client is still valid client in the network.
+          The client may then later resume its session back by sending
+          this packet to a server.  Routers also use this packet to notify
+          other routers in the network that the detached client has resumed.
+
+          Payload of the packet:  See section 2.3.23 Resume Client Payload
+
+
+     29 - 199
+
+          Currently undefined commands.
+
+
+     200 - 254
+
+          These packet types are reserved for private use and they will
+          not be defined by this document.
+
+
+     255  SILC_PACKET_MAX
+
+          This type is reserved for future extensions and currently it
+          MUST NOT be sent.
+.in 3
+
+
+.ti 0
+2.3.1 SILC Packet Payloads
+
+All payloads resides in the main data area of the SILC packet.  However
+all payloads MUST be at the start of the data area after the SILC
+packet header and padding.  All fields in the packet payload are always
+encrypted, as they reside in the data area of the packet which is
+always encrypted.  Most of the payloads may only be sent with specific
+packet type which is defined in the description of the payload.
+
+There are some other payloads in SILC as well.  However, they are not
+common in the sense that they could be sent at any time.  These payloads
+are not described in this section.  These are payloads such as SILC
+Key Exchange payloads and so on.  These are described in [SILC1],
+[SILC3] and [SILC4].
+
+
+.ti 0
+2.3.2 Generic payloads
+
+This section describes generic payloads that are not associated to any
+specific packet type.  They can be used for example inside some other
+packet payload.
+
+
+.ti 0
+2.3.2.1 ID Payload
+
+This payload can be used to send an ID.  ID's are variable in length
+thus this payload provides a way to send variable length ID.
+
+The following diagram represents the ID Payload.
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|             ID Type           |           ID Length           |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                           ID Data                             ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 3:  ID Payload
+
+
+.in 6
+o ID Type (2 bytes) - Indicates the type of the ID.  See
+  section 2.4 SILC ID Types for list of defined ID types.
+
+o ID Length (2 bytes) - Length of the ID Data area not
+  including the length of any other fields in the payload.
+
+o ID Data (variable length) - The actual ID data.  The encoding
+  of the ID data is defined in section 2.4 SILC ID Types.
+.in 3
+
+
+.ti 0
+2.3.2.2 Argument Payload
+
+Argument Payload is used to set arguments for any packet payload that
+need and support arguments, such as commands.  Number of arguments
+associated with a packet MUST be indicated by the packet payload which
+need the arguments.  Argument Payloads MUST always reside right after
+the packet payload needing the arguments.  Incorrect amount of argument
+payloads MUST cause rejection of the packet.
+
+The following diagram represents the Argument Payload.
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|         Payload Length        | Argument Type |               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+               +
+|                                                               |
+~                        Argument Data                          ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 4:  Argument Payload
+
+
+.in 6
+o Payload Length (2 bytes) - Length of the Argument Data
+  field not including the length of any other field in the
+  payload.
+
+o Argument Type (1 byte) - Indicates the type of the argument.
+  Every argument can have a specific type that are defined
+  by the packet payload needing the argument.  For example
+  every command specify a number for each argument that may be
+  associated with the command.  By using this number the receiver
+  of the packet knows what type of argument this is.  If there is
+  no specific argument type this field is set to zero (0) value.
+
+o Argument Data (variable length) - Argument data.
+.in 3
+
+
+.ti 0
+2.3.2.3 Argument List Payload
+
+Argument List Payload is a list of Argument Payloads appended one
+after the other.  The number of arguments is indicated in the
+payload.
+
+The following diagram represents the Argument List Payload.
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|         Argument Nums         |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                        Argument Payloads                      ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 5:  Argument List Payload
+
+
+.in 6
+o Argument Nums (2 bytes) - Indicates the number of Argument
+  Payloads.  If zero (0) value is found in this field no
+  arguments are present.
+
+o Argument Payloads (variable length) - The Argument Payloads
+  appended one after the other.  The payloads can be decoded
+  since the length of the payload is indicated in each of
+  the Argument Payload.
+.in 3
+
+
+
+
+.ti 0
+2.3.2.4 Channel Payload
+
+Generic Channel Payload may be used to send information about a channel,
+its name, the Channel ID and a mode.
+
+The following diagram represents the Channel Payload.
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|      Channel Name Length      |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                         Channel Name                          ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Channel ID Length       |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                          Channel ID                           ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                           Mode Mask                           |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 6:  New Channel Payload
+
+
+.in 6
+o Channel Name Length (2 bytes) - Length of the Channel Name
+  field.
+
+o Channel Name (variable length) - The name of the channel.
+
+o Channel ID Length (2 bytes) - Length of the Channel ID field.
+
+o Channel ID (variable length) - The encoded Channel ID.
+
+o Mode Mask (4 bytes) - A mode.  This can be the mode of the
+  channel but it can also be the mode of a client on the
+  channel.  The contents of this field is dependent of the
+  usage of this payload.  The usage is defined separately
+  when this payload is used.  This is a 32 bit MSB first value.
+.in 3
+
+
+
+
+
+
+.ti 0
+2.3.2.5 Public Key Payload
+
+Generic Public Key Payload may be used to send different type of
+public keys and certificates.
+
+The following diagram represents the Public Key Payload.
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Public Key Length       |        Public Key Type        |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                  Public Key (or certificate)                  ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 7:  Public Key Payload
+
+
+.in 6
+o Public Key Length (2 bytes) - The length of the Public Key
+  (or certificate) field, not including any other field.
+
+o Public Key Type (2 bytes) - The public key (or certificate)
+  type.  This field indicates the type of the public key in
+  the packet.  See the [SILC3] for defined public key types.
+
+o Public Key (or certificate) (variable length) - The
+  encoded public key or certificate data.
+.in 3
+
+
+.ti 0
+2.3.2.6 Message Payload
+
+Generic Message Payload can be used to send messages in SILC.  It
+is used to send channel messages and private messages.
+
+The following diagram represents the Message Payload.
+
+(*) indicates that the field is not encrypted.
+
+
+
+
+
+
+
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Message  Flags         |         Message Length        |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                         Message Data                          ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Padding Length         |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                            Padding                            ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                       Initial Vector *                        ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                              MAC *                            ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 8:  Message Payload
+
+
+.in 6
+o Message Flags (2 bytes) - Includes the Message Flags of the
+  message.  The flags can indicate a reason or a purpose for
+  the message.  The following Message Flags are defined:
+
+  0x0000  SILC_MESSAGE_FLAG_NONE
+
+          No specific flags set.
+
+  0x0001  SILC_MESSAGE_FLAG_AUTOREPLY
+
+          This message is an automatic reply to an earlier
+          received message.
+
+  0x0002  SILC_MESSAGE_FLAG_NOREPLY
+
+          There should not be reply messages to this
+          message.
+
+  0x0004  SILC_MESSAGE_FLAG_ACTION
+
+          The sender is performing an action and the message
+          is the indication of the action.
+
+  0x0008  SILC_MESSAGE_FLAG_NOTICE
+
+          The message is for example an informational notice
+          type message.
+
+  0x0010  SILC_MESSAGE_FLAG_REQUEST
+
+          This is a generic request flag to send request
+          messages.  A separate document should define any
+          payloads associated to this flag.
+
+  0x0020  SILC_MESSAGE_FLAG_SIGNED
+
+          This flag indicates that the message is signed
+          with sender's private key and thus can be verified
+          by the receiver using the sender's public key.  A
+          separate document should define the detailed procedure
+          of the signing process and any associated payloads
+          for this flag.
+
+  0x0040  SILC_MESSAGE_FLAG_REPLY
+
+          This is a generic reply flag to send a reply to
+          previously received request.  A separate document
+          should define any payloads associated to this flag.
+
+  0x0080  SILC_MESSAGE_FLAG_DATA
+
+          This is a generic data flag, indicating that the
+          message includes some data which can be interpreted
+          in a specific way.  Using this flag any kind of data
+          can be delivered inside message payload.  A separate
+          document should define how this flag is interpreted
+          and define any associated payloads.
+
+  0x0100  SILC_MESSAGE_FLAG_UTF8
+
+          This flag indicates that the message is UTF-8 encoded
+          textual message.  When sending text messages in SILC
+          this flag SHOULD be used.  When this flag is used the
+          text sent as message MUST be UTF-8 encoded.
+
+  0x0200 - 0x0800 RESERVED
+
+          Reserved for future flags.
+
+  0x1000 - 0x8000 PRIVATE RANGE
+
+          Private range for free use.
+
+o Message Length (2 bytes) - Indicates the length of the
+  Message Data field in the payload, not including any
+  other field.
+
+o Message Data (variable length) - The actual message data.
+
+o Padding Length (2 bytes) - Indicates the length of the
+  Padding field in the payload, not including any other
+  field.
+
+o Padding (variable length) - If this payload is used as
+  channel messages, the padding MUST be applied because
+  this payload is encrypted separately from other parts
+  of the packet.  If this payload is used as private
+  messages, the padding is present only when the payload
+  is encrypted with private message key.  If encrypted
+  with session keys this field MUST NOT be present and the
+  Padding Length field includes a zero (0) value.  The
+  padding SHOULD be random data.
+
+o Initial Vector (variable length) - This field MUST be
+  present when this payload is used as channel messages.
+  The IV SHOULD be random data for each channel message.
+
+  When encrypting private messages with session keys this
+  field MUST NOT be present.  For private messages this
+  field is present only when encrypting with a static
+  private message key (pre-shared key).  If randomly
+  generated key material is used this field MUST NOT be
+  present.  Also, If Key Agreement (SKE) was used to
+  negotiate fresh key material for private message key
+  this field MUST NOT be present.  See the section 4.6
+  in [SILC1] for more information about IVs when
+  encrypting private messages.
+
+  This field includes the initial vector used in message
+  encryption.  It need to be used in the packet decryption
+  as well.  Contents of this field depends on the encryption
+  algorithm and encryption mode.  This field is not encrypted,
+  is not included in padding calculation and its length
+  equals to cipher's block size.  This field is authenticated
+  by the message MAC.
+
+o MAC (variable length) - The MAC computed from the
+  Message Flags, Message Length, Message Data, Padding Length,
+  Padding and Initial Vector fields in that order.  The MAC
+  is computed after the payload is encrypted.  This is so
+  called Encrypt-Then-MAC order; first encrypt, then compute
+  MAC from ciphertext.  The MAC protects the integrity of
+  the Message Payload.  Also, when used as channel messages
+  it is possible to have multiple private channel keys set,
+  and receiver can use the MAC to verify which of the keys
+  must be used in decryption.  This field is not encrypted.
+  This field is authenticated by the SILC packet MAC.
+.in 3
+
+
+.ti 0
+2.3.3 Disconnect Payload
+
+Disconnect payload is sent upon disconnection.  Reason of the
+disconnection is sent to the disconnected party in the payload.
+
+The payload may only be sent with SILC_PACKET_DISCONNECT packet.  It
+MUST NOT be sent in any other packet type.  The following diagram
+represents the Disconnect Payload.
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|    Status     |                                               |
++-+-+-+-+-+-+-+-+                                               +
+|                                                               |
+~                      Disconnect Message                       ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 9:  Disconnect Payload
+
+.in 6
+o Status (1 byte) - Indicates the Status Type, defined in [SILC3]
+  for the reason of disconnection.
+
+o Disconnect Message (variable length) - Human readable UTF-8
+  encoded string indicating reason of the disconnection.  This
+  field MAY be omitted.
+.in 3
+
+
+.ti 0
+2.3.4 Success Payload
+
+Success payload is sent when some protocol execution is successfully
+completed.  The payload is simple; indication of the success is sent.
+This may be any data, including binary or human readable data, and
+it is protocol dependent.
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                      Success Indication                       ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 10:  Success Payload
+
+
+.in 6
+o Success Indication (variable length) - Indication of
+  the success.  This may be for example some flag that
+  indicates the protocol and the success status or human
+  readable success message.  The true length of this
+  payload is available by calculating it from the SILC
+  Packet Header.
+.in 3
+
+
+.ti 0
+2.3.5 Failure Payload
+
+This is opposite of Success Payload.  Indication of failure of
+some protocol is sent in the payload.
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                      Failure Indication                       ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 11:  Failure Payload
+
+
+.in 6
+o Failure Indication (variable length) - Indication of
+  the failure.  This may be for example some flag that
+  indicates the protocol and the failure status or human
+  readable failure message.  The true length of this
+  payload is available by calculating it from the SILC
+  Packet Header.
+.in 3
+
+
+.ti 0
+2.3.6 Reject Payload
+
+This payload is sent when some protocol is rejected to be executed.
+Other operations MAY send this as well that was rejected.  The
+indication of the rejection is sent in the payload.  The indication
+may be binary or human readable data and is protocol dependent.
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                       Reject Indication                       ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 12:  Reject Payload
+
+
+.in 6
+o Reject Indication (variable length) - Indication of
+  the rejection.  This maybe for example some flag that
+  indicates the protocol and the rejection status or human
+  readable rejection message.  The true length of this
+  payload is available by calculating it from the SILC
+  Packet Header.
+.in 3
+
+
+
+.ti 0
+2.3.7 Notify Payload
+
+Notify payload is used to send notify messages.  The payload is usually
+sent from server to client and from server to router.  It is also used
+by routers to notify other routers in the network.  This payload MAY also
+be sent to a channel.  Client MUST NOT send this payload.  When this
+packet is received by client it SHOULD process it.  Servers and routers
+MUST process notify packets.
+
+The payload may only be sent with SILC_PACKET_NOTIFY packet.  It MUST
+NOT be sent in any other packet type.  The following diagram represents
+the Notify Payload.
+
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|          Notify Type          |        Payload Length         |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Argument Nums |
++-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 13:  Notify Payload
+
+
+.in 6
+o Notify Type (2 bytes) - Indicates the type of the notify
+  message.
+
+o Payload Length (2 bytes) - Length of the entire Notify Payload
+  including any associated Argument Payloads.
+
+o Argument Nums (1 byte) - Indicates the number of Argument
+  Payloads associated to this payload.  Notify types may define
+  arguments to be sent along the notify message.
+.in 3
+
+The following list of currently defined notify types.  The format for
+notify arguments is same as in SILC commands described in [SILC4].
+Note that all IDs sent in arguments are sent inside ID Payload.  Also
+note that all passphrases that may be sent inside arguments MUST be
+UTF-8 [RFC2279] encoded.  Also note that all public keys or certificates
+sent inside arguments are actually Public Key Payloads.
+
+
+.in 6
+0     SILC_NOTIFY_TYPE_NONE
+
+      If no specific notify type apply for the notify message this type
+      MAY be used.
+
+      Max Arguments:  1
+          Arguments:  (1) <message>
+
+      The <message> is implementation specific free UTF-8 text string.
+      Receiver MAY ignore this message.
+
+
+1     SILC_NOTIFY_TYPE_INVITE
+
+      Sent when an client is invited to a channel.  This is also sent
+      when the invite list of the channel is changed.  This notify type
+      is sent between routers and if an client was invited, to the
+      client as well.  In this case the packet is destined to the
+      client.
+
+      Max Arguments:  5
+          Arguments:  (1) <Channel ID>          (2) <channel name>
+                      (3) [<sender Client ID>]  (4) [<add | del>]
+                      (5) [<invite list>]
+
+      The <Channel ID> is the channel.  The <channel name> is the name
+      of the channel and is provided because the client which receives
+      this notify packet may not have a way to resolve the name of the
+      channel from the <Channel ID>.  The <sender Client ID> is the
+      Client ID which invited the client to the channel.  The
+      <add | del> is an argument of size of 1 byte where 0x00 means
+      adding a client to invite list, and 0x01 means deleting a client
+      from invite list.  The <invite list>, if present, indicates the
+      information to be added to or removed from the invite list.
+      The <invite list> format is defined in [SILC4] with
+      SILC_COMMAND_INVITE command.  When this notify is destined to
+      a client the <add | del> and <invite list> MUST NOT be sent.
+
+
+2     SILC_NOTIFY_TYPE_JOIN
+
+      Sent when client has joined to a channel.  The server MUST
+      distribute this type to the local clients on the channel and then
+      send it to its primary router.  Note that, when router is joining
+      the client on behalf of normal server then router MUST send this
+      notify type locally and globally.  The router or server receiving
+      the packet distributes this type to the local clients on the
+      channel and broadcast it to the network.  This notify is sent
+      also to the client that joined the channel.
+
+      Max Arguments:  2
+          Arguments:  (1) [<Client ID>]       (2) <Channel ID>
+
+      The <Client ID> is the client that joined to the channel
+      indicated by the <Channel ID>.
+
+
+3     SILC_NOTIFY_TYPE_LEAVE
+
+      Sent when client has left a channel.  The server must distribute
+      this type to the local clients on the channel and then send it
+      to its primary router.  The router or server receiving the
+      packet distributes this type to the local clients on the channel
+      and broadcast it to the network.  This notify MUST NOT be sent to
+      the leaving client.
+
+      Max Arguments:  1
+          Arguments:  (1) <Client ID>
+
+      The <Client ID> is the client which left the channel.
+
+
+4     SILC_NOTIFY_TYPE_SIGNOFF
+
+      Sent when client signoff from SILC network.  The server MUST
+      distribute this type to the local clients on the channel and
+      then send it to its primary router.  The router or server
+      receiving the packet distributes this type to the local clients
+      on the channel and broadcast it to the network.  This notify
+      MUST NOT be sent to the quitting client.
+
+      Max Arguments:  2
+          Arguments:  (1) <Client ID>  (2) <message>
+
+      The <Client ID> is the client which left SILC network.  The
+      <message> is free text string indicating the reason of the
+      signoff.
+
+
+5     SILC_NOTIFY_TYPE_TOPIC_SET
+
+      Sent when topic is set/changed on a channel.  This type may be
+      sent only to the clients which are joined on the channel which
+      topic was just set or changed.  The packet is destined to the
+      channel.
+
+      Max Arguments:  2
+          Arguments:  (1) <ID Payload>  (2) <topic>
+
+      The <ID Payload> is the ID of the entity who set the topic.
+      It usually is Client ID but it can be Server ID and Channel ID
+      as well.
+
+
+6     SILC_NOTIFY_TYPE_NICK_CHANGE
+
+      Sent when client changes nick on a channel.  The server MUST
+      distribute this type only to the local clients on the channel
+      and then send it to its primary router.  The router or server
+      receiving the packet distributes this type to the local clients
+      on the channel and broadcast it to the network.  This packet is
+      destined directly to the sent entity.  This MUST be sent to those
+      clients that are joined on same channels as the client that
+      changed the nickname.  This notify MUST NOT be sent multiple
+      times to the same recipient.  This notify MUST be sent also to
+      the client that changed the nickname.
+
+      Max Arguments:  3
+          Arguments:  (1) <Old Client ID>  (2) <New Client ID>
+                      (3) <nickname>
+
+      The <Old Client ID> is the old ID of the client which changed
+      the nickname.  The <New Client ID> is the new ID generated by
+      the change of the nickname.  The <nickname> is the new nickname.
+      Note that it is possible to send this notify even if the
+      nickname has not changed, but client ID was changed.
+
+
+7     SILC_NOTIFY_TYPE_CMODE_CHANGE
+
+      Sent when channel mode has changed.  This type MUST be sent only
+      to the clients which are joined on the channel which mode was
+      changed.  This packet is destined to the channel.
+
+      Max Arguments:  8
+          Arguments:  (1) <ID Payload>    (2) <mode mask>
+                      (3) [<cipher>]      (4) <[hmac>]
+                      (5) [<passphrase>]  (6) [<founder public key>]
+                      (7) [<add | del>]   (8) [<channel public key>]
+
+      The <ID Payload> is the ID (usually Client ID but it can be
+      Server ID as well when the router is enforcing channel mode
+      change) of the entity which changed the mode.  The <mode mask>
+      is the new mode mask of the channel.  The client can safely
+      ignore the <cipher> argument since the SILC_PACKET_CHANNEL_KEY
+      packet will force the new channel key change anyway.  The <hmac>
+      argument is important since the client is responsible of setting
+      the new HMAC and the hmac key into use.  The <passphrase> is
+      the passphrase of the channel, if it was now set.  The <founder
+      public key> argument is sent when the founder mode on the
+      channel was set.  All routers and servers that receive the packet
+      MUST save the founder's public key so that the founder can
+      reclaim the channel founder rights back for the channel on any
+      server in the network.
+
+      The <add | del> and <channel public key> is used to add or
+      remove channel public key from the channel.  To add one public
+      key to channel the SILC_CMODE_CHANNEL_AUTH mode is set and the
+      <add | del> argument includes 0x00 value, and the <channel
+      public key> is the public key.  To remove one public key from
+      channel public key list the <add | del> includes 0x01 value and
+      <channel pubkey> is the public key to be removed.  If the
+      SILC_CMODE_CHANNEL_AUTH mode is unset (and was set earlier)
+      all public keys are removed at once.
+
+
+8     SILC_NOTIFY_TYPE_CUMODE_CHANGE
+
+      Sent when user mode on channel has changed.  This type MUST be
+      sent only to the clients which are joined on the channel where
+      the target client is on.  This packet is destined to the channel.
+
+      Max Arguments:  4
+          Arguments:  (1) <ID Payload>        (2) <mode mask>
+                      (3) <Target Client ID>  (4) [<founder pubkey>]
+
+      The <ID Payload> is the ID (usually Client ID but it can be
+      Server ID as well when the router is enforcing user's mode
+      change) of the entity which changed the mode.  The <mode mask>
+      is the new mode mask of the channel.  The <Target Client ID>
+      is the client which mode was changed.  The <founder pubkey>
+      is the public key of the channel founder and may be sent only
+      when first time setting the channel founder mode using the
+      SILC_COMMAND_CUMODE command, and when sending this notify.
+
+
+9     SILC_NOTIFY_TYPE_MOTD
+
+      Sent when Message of the Day (motd) is sent to a client.
+
+      Max Arguments:  1
+          Arguments:  (1) <motd>
+
+      The <motd> is the Message of the Day.  This notify MAY be
+      ignored.
+
+
+10    SILC_NOTIFY_TYPE_CHANNEL_CHANGE
+
+      Sent when channel's ID has changed for a reason or another.
+      This is sent by normal server to the client.  This can also be
+      sent by router to other server to force the Channel ID change.
+      The Channel ID MUST be changed to use the new one.  When sent
+      to clients, this type MUST be sent only to the clients which are
+      joined on the channel.  This packet is destined to the sent
+      entity.
+
+      Max Arguments:  2
+          Arguments:  (1) <Old Channel ID>  (2) <New Channel ID>
+
+      The <Old Channel ID> is the channel's old ID and the <New
+      Channel ID> is the new one that MUST replace the old one.
+      Server which receives this from router MUST re-announce the
+      channel to the router by sending SILC_PACKET_NEW_CHANNEL packet
+      with the new Channel ID.
+
+
+11    SILC_NOTIFY_TYPE_SERVER_SIGNOFF
+
+      Sent when server quits SILC network.  Those clients from this
+      server that are on channels must be removed from the channel.
+      This packet is destined to the sent entity.
+
+      Max Arguments:  256
+          Arguments:  (1) <Server ID>   (n) [<Client ID>]   [...]
+
+      The <Server ID> is the server's ID.  The rest of the arguments
+      are the Client IDs of the clients which are coming from this
+      server and are thus quitting the SILC network also.  If the
+      maximum number of arguments are reached another
+      SILC_NOTIFY_TYPE_SERVER_SIGNOFF notify packet MUST be sent.
+      When this notify packet is sent between routers the Client ID's
+      MAY be omitted.  Server receiving the Client ID's in the payload
+      may use them directly to remove the client.
+
+
+12    SILC_NOTIFY_TYPE_KICKED
+
+      Sent when a client has been kicked from a channel.  This MUST
+      also be sent to the client which was kicked from the channel.
+      The client which was kicked from the channel MUST be removed
+      from the channel.  The client MUST also be removed from channel's
+      invite list if it is explicitly added in the list.  This packet
+      is destined to the channel.  The router or server receiving the
+      packet distributes this type to the local clients on the channel
+      and broadcast it to the network.
+
+      Max Arguments:  3
+          Arguments:  (1) <Client ID>           (2) [<comment>]
+                      (3) <Kicker's Client ID>
+
+      The <Client ID> is the client which was kicked from the channel.
+      The kicker may have set the <comment> to indicate the reason for
+      the kicking.  The <Kicker's Client ID> is the kicker.
+
+
+13    SILC_NOTIFY_TYPE_KILLED
+
+      Sent when a client has been killed from the network.  This MUST
+      also be sent to the client which was killed from the network.
+      This notify MUST be sent to those clients which are joined on
+      same channels as the killed client.  The client which was killed
+      MUST be removed from the network.  This packet is destined
+      directly to the sent entity.  The router or server receiving
+      the packet distributes this type to the local clients on the
+      channel and broadcast it to the network.  The client MUST also
+      be removed from joined channels invite list if it is explicitly
+      added in the lists.  This notify MUST NOT be sent multiple
+      times to same recipient.
+
+      Max Arguments:  3
+          Arguments:  (1) <Client ID>           (2) [<comment>]
+                      (3) <Killer's ID>
+
+      The <Client ID> is the client which was killed from the network.
+      The killer may have set the <comment> to indicate the reason for
+      the killing.  The <Killer's ID> is the killer, which may be
+      client but also router server.
+
+
+14    SILC_NOTIFY_TYPE_UMODE_CHANGE
+
+      Sent when user's mode in the SILC changes.  This type is sent
+      only between routers as broadcast packet.
+
+      Max Arguments:  2
+          Arguments:  (1) <Client ID>  (2) <mode mask>
+
+      The <Client ID> is the client which mode was changed.  The
+      <mode mask> is the new mode mask.
+
+
+15    SILC_NOTIFY_TYPE_BAN
+
+      Sent when the ban list of the channel is changed.  This type is
+      sent only between routers as broadcast packet.
+
+      Max Arguments:  3
+          Arguments:  (1) <Channel ID>         (2) [<add | del>]
+                      (3) [<ban list>]
+
+      The <Channel ID> is the channel which ban list was changed.
+      The <add | del> is an argument of size of 1 byte where 0x00 means
+      adding a client to ban list, and 0x01 means deleting a client
+      from ban list.  The <ban list> indicates the information to be
+      added to or removed from the ban list.  The <ban list> format
+      format is defined in [SILC4] with SILC_COMMAND_BAN command.
+
+
+16    SILC_NOTIFY_TYPE_ERROR
+
+      Sent when an error occurs during processing some SILC procedure.
+      This is not used when error occurs during command processing, see
+      [SILC4] for more information about commands and command replies.
+      This type is sent directly to the sender of the packet whose
+      packet caused the error.  See [SILC1] for definition when this
+      type can be sent.
+
+      Max Arguments:  256
+          Arguments:  (1) <Status Type>        (n) [...]
+
+      The <Status Type> is the error type defined in [SILC4].  Note
+      that same types are also used with command replies to indicate
+      the status of a command.  Both commands and this notify type
+      share same status types.  Rest of the arguments are status type
+      dependent and are specified with those status types that can be
+      sent currently inside this notify type in [SILC4].  The <Status
+      Type> is size of 1 byte.
+
+
+17    SILC_NOTIFY_TYPE_WATCH
+
+      Sent to indicate change in a watched user.  Client can set
+      nicknames to be watched with SILC_COMMAND_WATCH command, and
+      receive notifications when they login to network, signoff from
+      the network or their user mode is changed.  This notify type
+      is used to deliver these notifications.  The notify type is
+      sent directly to the watching client.
+
+      Max Arguments:  4
+          Arguments:  (1) <Client ID>        (2) [<nickname>]
+                      (3) <user mode>        (4) [<Notify Type>]
+
+      The <Client ID> is the user's Client ID which is being watched,
+      and the <nickname> is its nickname.  If the client just
+      changed the nickname, then <nickname> is the new nickname, but
+      the <Client ID> is the old client ID.  The <user mode> is the
+      user's current user mode.  The <Notify Type> can be same as the
+      Notify Payload's Notify Type, and is 16 bit MSB first order
+      value.  If provided it may indicate the notify that occurred
+      for the client.  If client logged in to the network the
+      <Notify Type> MUST NOT be present.
+.in 3
+
+Notify types starting from 16384 are reserved for private notify
+message types.
+
+Router server which receives SILC_NOTIFY_TYPE_SIGNOFF,
+SILC_NOTIFY_TYPE_SERVER_SIGNOFF, SILC_NOTIFY_TYPE_KILLED,
+SILC_NOTIFY_TYPE_NICK_CHANGE and SILC_NOTIFY_TYPE_UMODE_CHANGE
+MUST check whether someone in the local cell is watching the nickname
+the client has, and send the SILC_NOTIFY_TYPE_WATCH notify to the
+watcher, unless the watched client in case has the user mode
+SILC_UMODE_REJECT_WATCHING set.  If the watcher client and the client
+that was watched is same the notify SHOULD NOT be sent.
+
+
+
+
+
+.ti 0
+2.3.8 Error Payload
+
+Error payload is sent upon error in protocol.  Error may occur in
+various conditions when server sends this packet.  Client MUST NOT
+send this payload but MUST be able to accept it.  However, client
+MAY ignore the contents of the packet as server is going to take
+action on the error anyway.  However, it is recommended that the
+client takes error packet seriously.
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                         Error Message                         ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 14:  Error Payload
+
+
+.in 6
+o Error Message (variable length) - Human readable error
+  message as UTF-8 string.
+.in 3
+
+
+.ti 0
+2.3.9 Channel Message Payload
+
+Channel Message Payload is used to send message to channels, a group
+of users.  These messages can only be sent if client has joined to
+some channel.  Even though this packet is very common in SILC it
+is still special packet.  Some special handling on sending and
+reception of channel message is required.
+
+Padding MUST be applied into this payload since the payload is
+encrypted separately from other parts of the packet with the
+channel specific key.  Hence the requirement of the padding.
+The packet MUST be made multiple by eight (8) or by the block
+size of the cipher, which ever is larger.
+
+The SILC header in this packet is encrypted with the session key
+of the next receiver of the packet.  Nothing else is encrypted
+with that key.  Thus, the actual packet and padding to be
+encrypted with the session key is SILC Header plus padding to it.
+
+Receiver of the the channel message packet is able to determine
+the channel the message is destined to by checking the destination
+ID from the SILC Packet header which tells the destination channel.
+The original sender of the packet is also determined by checking
+the source ID from the header which tells the client which sent
+the message.
+
+This packet use generic Message Payload as Channel Message Payload.
+See section 2.3.2.5 for generic Message Payload.
+
+
+.ti 0
+2.3.10 Channel Key Payload
+
+All traffic in channels are protected by channel specific keys.
+Channel Key Payload is used to distribute channel keys to all
+clients on the particular channel.  Channel keys are sent when
+the channel is created, when new user joins to the channel and
+whenever a user has left a channel.  Server creates the new
+channel key and distributes it to the clients by encrypting this
+payload with the session key shared between the server and
+the client.  After that, client MUST start using the key received
+in this payload to protect the traffic on the channel.
+
+The client which is joining to the channel receives its key in the
+SILC_COMMAND_JOIN command reply message thus it is not necessary to
+send this payload to the entity which sent the SILC_COMMAND_JOIN
+command.
+
+Channel keys are cell specific thus every router in the cell have
+to create a channel key and distribute it if any client in the
+cell has joined to a channel.  Channel traffic between cell's
+are not encrypted using channel keys, they are encrypted using
+normal session keys between two routers.  Inside a cell, all
+channel traffic is encrypted with the specified channel key.
+Channel key SHOULD expire periodically, say, in one hour, in
+which case new channel key is created and distributed.
+
+Note that, this packet is not used if SILC_CMODE_PRIVKEY mode is set
+on channel.  This means that channel uses channel private keys which
+are not server generated.  For this reason server cannot send this
+packet as it does not know the key.
+
+The payload may only be sent with SILC_PACKET_CHANNEL_KEY packet.
+It MUST NOT be sent in any other packet type.  The following diagram
+represents the Channel Key Payload.
+
+
+
+
+
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Channel ID Length       |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                          Channel ID                           ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|      Cipher Name Length       |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                         Cipher Name                           ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|      Channel Key Length       |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                         Channel Key                           ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 15:  Channel Key Payload
+
+
+
+.in 6
+o Channel ID Length (2 bytes) - Indicates the length of the
+  Channel ID field in the payload, not including any other
+  field.
+
+o Channel ID (variable length) - The Channel ID of the
+  channel.
+
+o Cipher Name Length (2 bytes) - Indicates the length of the
+  Cipher name field in the payload, not including any other
+  field.
+
+o Cipher Name (variable length) - Name of the cipher used
+  in the protection of channel traffic.  This name is
+  initially decided by the creator of the channel but it
+  may change during the life time of the channel as well.
+
+o Channel Key Length (2 bytes) - Indicates the length of the
+  Channel Key field in the payload, not including any other
+  field.
+
+o Channel Key (variable length) - The actual channel key
+  material.
+.in 3
+
+
+.ti 0
+2.3.11 Private Message Payload
+
+Private Message Payload is used to send private message between
+two clients.  The messages are sent only to the specified user
+and no other user inside SILC network is able to see the message.
+
+The message can be protected by the session key established by the
+SILC Key Exchange Protocol.  However, it is also possible to agree
+to use a private key to protect just the private messages.  It is
+for example possible to perform Key Agreement between two clients.
+See section 2.3.20 Key Agreement Payload how to perform key
+agreement.  See also section 2.3.12 Private Message Key Payload
+for another way of using private keys with private messages.  See
+[SILC1] section 4.6 for detailed description for private message
+key generation procedure.
+
+If normal session key is used to protect the message, every server
+between the sender client and the receiving client MUST decrypt the
+packet and always re-encrypt it with the session key of the next
+receiver of the packet.  See section Client To Client in [SILC1].
+
+When the private message key is used, and the Private Message Key
+flag was set in the SILC Packet header no server or router en route
+is able to decrypt or re-encrypt the packet.  In this case only the
+SILC Packet header is processed by the servers and routers en route.
+Section Client To Client in [SILC1] gives example of this scheme.
+
+This packet use generic Message Payload as Private Message Payload.
+See section 2.3.2.5 for generic Message Payload.
+
+
+.ti 0
+2.3.12 Private Message Key Payload
+
+This payload is OPTIONAL and can be used to send private message
+key between two clients in the network.  The packet is secured with
+normal session keys.  By default private messages are encrypted
+with session keys, and with this payload it is possible to set
+private key for private message encryption between two clients.
+
+The receiver of this payload SHOULD verify for example from user
+whether user want to receive private message key.  Note that there
+are other, more secure ways of exchanging private message keys in
+the SILC network.  Instead of sending this payload it is possible to
+negotiate the private message key with SKE protocol using the Key
+Agreement payload directly peer to peer, see section 2.3.20.
+
+This payload may only be sent by client to another client.  Server
+MUST NOT send this payload.  After sending this payload the sender of
+private messages must set the Private Message Key flag into SILC Packet
+Header.
+
+The payload may only be sent with SILC_PACKET_PRIVATE_MESSAGE_KEY
+packet.  It MUST NOT be sent in any other packet type.  The following
+diagram represents the Private Message Key Payload.
+
+
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|  Private Message Key Length   |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                      Private Message Key                      ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|      Cipher Name Length       |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                          Cipher Name                          ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       HMAC Name Length        |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                           HMAC Name                           ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 16:  Private Message Key Payload
+
+
+
+.in 6
+o Private Message Key Length (2 bytes) - Indicates the length
+  of the Private Message Key field in the payload, not including
+  any other field.
+
+o Private Message Key (variable length) - The actual private
+  message key material.
+
+o Cipher Name Length (2 bytes) - Indicates the length of the
+  Cipher Name field in the payload, not including any other
+  field.
+
+o Cipher Name (variable length) - Name of the cipher to use
+  in the private message encryption.  If this field does not
+  exist then the default cipher of the SILC protocol is used.
+  See the [SILC1] for defined ciphers.
+
+o HMAC Name Length (2 bytes) - Indicates the length of the
+  HMAC Name field in the payload, not including any other
+  field.
+
+o HMAC Name (variable length) - Name of the HMAC to use
+  in the private message MAC computation.  If this field does
+  not exist then the default HMAC of the SILC protocol is used.
+  See the [SILC1] for defined HMACs.
+.in 3
+
+
+.ti 0
+2.3.13 Command Payload
+
+Command Payload is used to send SILC commands from client to server.
+Also server MAY send commands to other servers.  The following diagram
+represents the Command Payload.
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|         Payload Length        | SILC Command  | Arguments Num |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Command Identifier      |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 17:  Command Payload
+
+
+.in 6
+o Payload Length (2 bytes) - Length of the entire command
+  payload including any command argument payloads associated
+  with this payload.
+
+o SILC Command (1 byte) - Indicates the SILC command.  This MUST
+  be set to non-zero value.  If zero (0) value is found in this
+  field the packet MUST be discarded.
+
+o Arguments Num (1 byte) - Indicates the number of arguments
+  associated with the command.  If there are no arguments this
+  field is set to zero (0).  The arguments MUST follow the
+  Command Payload.  See section 2.3.2.2 for definition of the
+  Argument Payload.
+
+o Command Identifier (2 bytes) - Identifies this command at the
+  sender's end.  The entity which replies to this command MUST
+  set the value found from this field into the Command Payload
+  used to send the reply to the sender.  This way the sender
+  can identify which command reply belongs to which originally
+  sent command.  What this field includes is implementation
+  issue but it is RECOMMENDED that wrapping counter value is
+  used in the field.
+.in 3
+
+See [SILC4] for detailed description of different SILC commands,
+their arguments and their reply messages.
+
+
+.ti 0
+2.3.14 Command Reply Payload
+
+Command Reply Payload is used to send replies to the commands.  The
+Command Reply Payload is identical to the Command Payload thus see
+the 2.3.13 section for the payload specification.
+
+The entity which sends the reply packet MUST set the Command Identifier
+field in the reply packet's Command Payload to the value it received
+in the original command packet.
+
+See SILC Commands in [SILC4] for detailed description of different
+SILC commands, their arguments and their reply messages.
+
+
+.ti 0
+2.3.15 Connection Auth Request Payload
+
+Client MAY send this payload to server to request the authentication
+method that must be used in authentication protocol.  If client knows
+this information beforehand this payload is not necessary to be sent.
+Server performing authentication with another server MAY also send
+this payload to request the authentication method.  If the connecting
+server already knows this information this payload is not necessary
+to be sent.
+
+Server receiving this request SHOULD reply with same payload sending
+the mandatory authentication method.  Algorithms that may be required
+to be used by the authentication method are the ones already
+established by the SILC Key Exchange protocol.  See section Key
+Exchange Start Payload in [SILC3] for detailed information.
+
+The payload may only be sent with SILC_PACKET_CONNECTION_AUTH_REQUEST
+packet.  It MUST NOT be sent in any other packet type.  The following
+diagram represents the Connection Auth Request Payload.
+
+
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Connection Type        |     Authentication Method     |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 18:  Connection Auth Request Payload
+
+
+.in 6
+o Connection Type (2 bytes) - Indicates the type of the
+  connection.  The following connection types are defined:
+
+
+     1    Client connection
+     2    Server connection
+     3    Router connection
+
+  If any other type is found in this field the packet MUST be
+  discarded and the authentication MUST be failed.
+
+o Authentication Method (2 bytes) - Indicates the authentication
+  method to be used in the authentication protocol.  The following
+  authentication methods are defined:
+
+     0    NONE        (mandatory)
+     1    password    (mandatory)
+     2    public key  (mandatory)
+
+  If any other type is found in this field the packet MUST be
+  discarded and the authentication MUST be failed.  If this
+  payload is sent as request to receive the mandatory
+  authentication method this field MUST be set to zero (0),
+  indicating that receiver should send the mandatory
+  authentication method.  The receiver sending this payload
+  to the requesting party, MAY also set this field to zero (0)
+  to indicate that authentication is not required.  In this
+  case authentication protocol still MUST be started but
+  server is most likely to respond with SILC_PACKET_SUCCESS
+  immediately.
+.in 3
+
+
+.ti 0
+2.3.16 New ID Payload
+
+New ID Payload is a multipurpose payload.  It is used to send newly
+created ID's from clients and servers.  When client connects to server
+and registers itself to the server by sending SILC_PACKET_NEW_CLIENT
+packet, server replies with this packet by sending the created ID for
+the client.  Server always creates the ID for the client.
+
+This payload is also used when server tells its router that new client
+has registered to the SILC network.  In this case the server sends
+the Client ID of the client to the router.  Similarly when router
+distributes information to other routers about the client in the SILC
+network this payload is used.
+
+Also, when server connects to router, router use this payload to inform
+other routers about new server in the SILC network.  However, every
+server (or router) creates their own ID's thus the ID distributed by
+this payload is not created by the distributor in this case.  Servers
+create their own ID's.  Server registers itself to the network by
+sending SILC_PACKET_NEW_SERVER to the router it connected to.  The case
+is same when router connects to another router.
+
+This payload MUST NOT be used to send information about new channels.
+New channels are always distributed by sending the dedicated
+SILC_PACKET_NEW_CHANNEL packet.  Client MUST NOT send this payload.
+Both client and server (and router) MAY receive this payload.
+
+The packet use generic ID Payload as New ID Payload.  See section
+2.3.2.1 for generic ID Payload.
+
+
+.ti 0
+2.3.17 New Client Payload
+
+When client is connected to the server, keys has been exchanged and
+connection has been authenticated, client MUST register itself to the
+server.  Client's first packet after key exchange and authentication
+protocols MUST be SILC_PACKET_NEW_CLIENT.  This payload tells server all
+the relevant information about the connected user.  Server creates a new
+client ID for the client when received this payload and sends it to the
+client in New ID Payload.
+
+This payload sends username and real name of the user on the remote host
+which is connected to the SILC server with SILC client.  The server
+creates the client ID according the information sent in this payload.
+The nickname of the user becomes the nickname sent in this payload.
+
+The payload may only be sent with SILC_PACKET_NEW_CLIENT packet.  It
+MUST NOT be sent in any other packet type.  The following diagram
+represents the New Client Payload.
+
+
+
+
+
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Username Length        |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                           Username                            ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Real Name Length        |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                           Real Name                           ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 19:  New Client Payload
+
+
+.in 6
+o Username Length (2 bytes) - Length of the Username field.
+
+o Username (variable length) - The username of the user on
+  the host where connecting to the SILC server.
+
+o Real Name Length (2 bytes) - Length of the Real Name field.
+
+o Real Name (variable length) - The real name of the user
+  on the host where connecting to the SILC server.
+.in 3
+
+
+.ti 0
+2.3.18 New Server Payload
+
+This payload is sent by server when it has completed successfully both
+key exchange and connection authentication protocols.  The server
+MUST register itself to the SILC Network by sending this payload.
+The first packet after these key exchange and authentication protocols
+is SILC_PACKET_NEW_SERVER packet.  The payload includes the Server ID
+of the server that it has created by itself.  It also includes a
+name of the server that is associated to the Server ID.
+
+The payload may only be sent with SILC_PACKET_NEW_SERVER packet.  It
+MUST NOT be sent in any other packet type.  The following diagram
+represents the New Server Payload.
+
+
+
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Server ID Length        |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                        Server ID Data                         ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|     Server Name Length        |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                          Server Name                          ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 20:  New Server Payload
+
+
+.in 6
+o Server ID Length (2 bytes) - Length of the Server ID Data
+  field.
+
+o Server ID Data (variable length) - The encoded Server ID
+  data.
+
+o Server Name Length (2 bytes) - Length of the server name
+  field.
+
+o Server Name (variable length) - The server name string.
+.in 3
+
+
+.ti 0
+2.3.19 New Channel Payload
+
+Information about newly created channel is broadcasted to all routers
+in the SILC network by sending this packet payload.  Channels are
+created by router of the cell.  Server never creates channels unless
+it is a standalone server and it does not have router connection,
+in this case server acts as router.  Normal server send JOIN command
+to the router (after it has received JOIN command from client) which
+then processes the command and creates the channel.  Client MUST NOT
+send this packet.  Server MAY send this packet to a router when it is
+announcing its existing channels to the router after it has connected
+to the router.
+
+The packet use generic Channel Payload as New Channel Payload.  See
+section 2.3.2.3 for generic Channel Payload.  The Mode Mask field in the
+Channel Payload is the mode of the channel.
+
+
+.ti 0
+2.3.20 Key Agreement Payload
+
+This payload is used by clients to request key negotiation between
+another client in the SILC Network.  The key agreement protocol used
+is the SKE protocol.  The result of the protocol, the secret key
+material, can be used for example as private message key between the
+two clients.  This significantly adds security as the clients agree
+about the key without any server interaction.  The protocol is executed
+peer to peer.  The server and router MUST NOT send this payload.
+
+The sender MAY tell the receiver of this payload the hostname and the
+port where the SKE protocol is running in the sender's end.  The
+receiver MAY then initiate the SKE negotiation with the sender.  The
+sender MAY also optionally not to include the hostname and the port
+of its SKE protocol.  In this case the receiver MAY reply to the
+request by sending the same payload filled with the receiver's hostname
+and the port where the SKE protocol is running.  The sender MAY then
+initiate the SKE negotiation with the receiver.
+
+This payload may be sent with SILC_PACKET_KEY_AGREEMENT and
+SILC_PACKET_FTP packet types.  It MUST NOT be sent in any other packet
+types.  The following diagram represents the Key Agreement Payload.
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Hostname Length        |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                           Hostname                            ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                             Port                              |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 21:  Key Agreement Payload
+
+
+.in 6
+o Hostname Length (2 bytes) - Indicates the length of the
+  Hostname field.
+
+o Hostname (variable length) - The hostname or IP address where
+  the SKE protocol is running.  The sender MAY fill this field
+  when sending the payload.  If the receiver sends this payload
+  as reply to the request it MUST fill this field.
+
+o Port (4 bytes) - The port where the SKE protocol is bound.
+  The sender MAY fill this field when sending the payload.  If
+  the receiver sends this payload as reply to the request it
+  MUST fill this field.  This is a 32 bit MSB first order value.
+.in 3
+
+
+After the key material has been received from the SKE protocol it is
+processed as the [SILC3] describes.  If the key material is used as
+channel private key then the Sending Encryption Key, as defined in
+[SILC3] is used as the channel private key.  Other key material must
+be discarded.  The [SILC1] in section 4.6 defines the way to use the
+key material if it is intended to be used as private message keys.
+Any other use for the key material is undefined.
+
+
+.ti 0
+2.3.21 Resume Router Payload
+
+See the [SILC1] for Resume Router protocol where this payload is
+used.  The payload may only be sent with SILC_PACKET_RESUME_ROUTER
+packet.  It MUST NOT be sent in any other packet type.  The following
+diagram represents the Resume Router Payload.
+
+
+.in 21
+.nf
+                     1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|      Type     |  Session ID   |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 22:  Resume Router Payload
+
+
+.in 6
+o Type (1 byte) - Indicates the type of the backup resume
+  protocol packet.  The type values are defined in [SILC1].
+
+o Session ID (1 bytes) - Indicates the session ID for the
+  backup resume protocol.  The sender of the packet sets this
+  value and the receiver MUST set the same value in subsequent
+  reply packet.
+.in 3
+
+
+.ti 0
+2.3.22 File Transfer Payload
+
+File Transfer Payload is used to perform file transfer protocol between
+two entities in the network.  The actual file transfer protocol is always
+encapsulated inside the SILC Packet.  The actual data stream is also sent
+peer to peer outside SILC network.
+
+When an entity, usually a client wishes to perform file transfer protocol
+with another client in the network, they perform Key Agreement protocol
+as described in the section 2.3.20 Key Agreement Payload and in [SILC3],
+inside File Transfer Payload.  After the Key Agreement protocol has been
+performed the subsequent packets in the data stream will be protected
+using the new key material.  The actual file transfer protocol is also
+initialized in this stage.  All file transfer protocol packets are always
+encapsulated in the File Transfer Payload and protected with the
+negotiated key material.
+
+The payload may only be sent with SILC_PACKET_FTP packet.  It MUST NOT
+be sent in any other packet type.  The following diagram represents the
+File Transfer Payload.
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|     Type      |                                               |
++-+-+-+-+-+-+-+-+                                               +
+|                                                               |
+~                             Data                              ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 23:  File Transfer Payload
+
+
+.in 6
+o Type (1 byte) - Indicates the type of the file transfer
+  protocol.  The following file transfer protocols has been
+  defined:
+
+    1    Secure File Transfer Protocol (SFTP)  (mandatory)
+
+  If zero (0) value or any unsupported file transfer protocol
+  type is found in this field the packet MUST be discarded.
+  The currently mandatory file transfer protocol is SFTP.
+  The SFTP protocol is defined in [SFTP].
+
+o Data (variable length) - Arbitrary file transfer data.  The
+  contents and encoding of this field is dependent of the usage
+  of this payload and the type of the file transfer protocol.
+  When this payload is used to perform the Key Agreement
+  protocol, this field include the Key Agreement Payload,
+  as defined in the section 2.3.20 Key Agreement Payload.
+  When this payload is used to send the actual file transfer
+  protocol data, the encoding is defined in the corresponding
+  file transfer protocol.
+.in 3
+
+
+.ti 0
+2.3.23 Resume Client Payload
+
+This payload is used by client to resume its detached session in the
+SILC Network.  A client is able to detach itself from the network by
+sending SILC_COMMAND_DETACH command to its server.  The network
+connection to the client is lost but the client remains as valid
+client in the network.  The client is able to resume the session back
+by sending this packet and including the old Client ID, and an
+Authentication Payload [SILC1] which the server use to verify with
+the detached client's public key.  This also implies that the
+mandatory authentication method is public key authentication.
+
+Server or router that receives this from the client also sends this,
+without the Authentication Payload, to routers in the network so that
+they know the detached client has resumed.  Refer to the [SILC1] for
+detailed description how the detaching and resuming procedure is
+performed.
+
+The payload may only be sent with SILC_PACKET_RESUME CLIENT packet.  It
+MUST NOT be sent in any other packet type.  The following diagram
+represents the Resume Client Payload.
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Client ID Length        |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                           Client ID                           ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                     Authentication Payload                    ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 24:  Resume Client Payload
+
+
+.in 6
+o Client ID Length (1 byte) - The length of the Client ID
+  field not including any other field.
+
+o Client ID (variable length) - The detached client's Client
+  ID.  The client that sends this payload must know the Client
+  ID.
+
+o Authentication Payload (variable length) - The authentication
+  payload that the server will verify with the detached client's
+  public key.  If the server doesn't know the public key, it must
+  retrieve it for example with SILC_COMMAND_GETKEY command.
+.in 3
+
+
+
+.ti 0
+2.4 SILC ID Types
+
+ID's are used in the SILC network to associate different entities.
+The following ID's has been defined to be used in the SILC network.
+
+.in 6
+0    No ID
+
+     This is used when other ID type is available at the time.
+
+1    Server ID
+
+     Server ID to associate servers.  See the format of
+     this ID in [SILC1].
+
+2    Client ID
+
+     Client ID to associate clients.  See the format of
+     this ID in [SILC1].
+
+3    Channel ID
+
+     Channel ID to associate channels.  See the format of
+     this ID in [SILC1].
+.in 3
+
+When encoding different IDs into the ID Payload, all fields are always
+in MSB first order.  The IP address, port, and/or the random number
+are encoded in the MSB first order.
+
+
+.ti 0
+2.5 Packet Encryption And Decryption
+
+SILC packets are encrypted almost entirely.  Only the MAC at the end
+of the packet is never encrypted.  The SILC Packet header is the first
+part of a packet to be encrypted and it is always encrypted with the
+key of the next receiver of the packet.  The data payload area of the
+packet is always entirely encrypted and it is usually encrypted with
+the next receiver's key.  However, there are some special packet types
+and packet payloads that require special encryption process.  These
+special cases are described in the next sections.  First is described
+the normal packet encryption process.
+
+
+
+.ti 0
+2.5.1 Normal Packet Encryption And Decryption
+
+Normal SILC packets are encrypted with the session key of the next
+receiver of the packet.  The entire SILC Packet header and the packet
+data payload is is encrypted with the same key.  Padding of the packet
+is also encrypted always with the session key, also in special cases.
+Computed MAC of the packet MUST NOT be encrypted.
+
+Decryption process in these cases are straightforward.  The receiver
+of the packet MUST first decrypt the SILC Packet header, or some parts
+of it, usually first 16 bytes of it.  Then the receiver checks the
+packet type from the decrypted part of the header and can determine
+how the rest of the packet must be decrypted.  If the packet type is
+any of the special cases described in the following sections the packet
+decryption is special.  If the packet type is not among those special
+packet types rest of the packet can be decrypted with the same key.
+At this point the receiver is also able to determine the length of the
+packet.
+
+With out a doubt, this sort of decryption processing causes some
+overhead to packet decryption, but never the less, is required.
+
+The MAC of the packet is also verified at this point.  The MAC is
+computed from the ciphertext of the packet so it can be verified
+at this stage.  The length of the packet need to be known to be able
+to verify the MAC from the ciphertext so the first 16 bytes need to
+be decrypted to determine the packet length.  However, the MAC MUST
+be verified from the entire ciphertext.
+
+
+.ti 0
+2.5.2 Channel Message Encryption And Decryption
+
+Channel Messages (Channel Message Payload) are always encrypted with
+the channel specific key.  However, the SILC Packet header is not
+encrypted with that key.  As in normal case, the header is encrypted
+with the key of the next receiver of the packet.  Note that, in this
+case the encrypted data area is not touched at all; it MUST NOT be
+re-encrypted with the session key.
+
+Receiver of a channel message, who ever that is, is REQUIRED to decrypt
+the SILC Packet header to be able to recognize the packet to be as
+channel message.  This is same procedure as for normal SILC packets.
+As the receiver founds the packet to be channel message, rest of the
+packet processing is special.  Rest of the SILC Packet header is
+decrypted with the same session key along with the padding of the
+packet.  After that the packet is protected with the channel specific
+key and thus can be decrypted only if the receiver is the client on
+the channel.  See section 2.7 Packet Padding Generation for more
+information about padding on special packets.
+
+If the receiver of the channel message is router which is routing the
+message to another router then it MUST decrypt the Channel Message
+payload too.  Between routers (that is, between cells) channel messages
+are protected with session keys shared between the routers.  This
+causes another special packet processing for channel messages.  If
+the channel message is received from another router then the entire
+packet, including Channel Message payload, MUST be encrypted with the
+session key shared between the routers.  In this case the packet
+decryption process is as with normal SILC packets.  Hence, if the
+router is sending channel message to another router the Channel
+Message payload MUST have been decrypted and MUST be re-encrypted
+with the session key shared between the another router.  In this
+case the packet encryption is as with any normal SILC packet.
+
+It must be noted that this is only when the channel messages are sent
+from router to another router.  In all other cases the channel
+message encryption and decryption is as described before.  This
+different processing of channel messages with router to router
+connection is because channel keys are cell specific.  All cells have
+their own channel keys thus the channel message traveling from one
+cell to another MUST be protected as it would be any normal SILC
+packet.
+
+If the SILC_CMODE_PRIVKEY channel mode has been set for the channel
+then the router cannot decrypt the packet as it does not know the
+private key.  In this case the entire packet MUST be encrypted with
+the session key and sent to the router.  The router receiving the
+packet MUST check the channel mode and decrypt the packet accordingly.
+
+
+.ti 0
+2.5.3 Private Message Encryption And Decryption
+
+By default, private message in SILC are protected by session keys.
+In this case the private message encryption and decryption process is
+equivalent to normal packet encryption and decryption.
+
+However, private messages MAY be protected with private message key
+which causes the packet to be special packet.  The procedure in this
+case is very much alike to channel packets.  The actual private message
+is encrypted with the private message key and other parts of the
+packet is encrypted with the session key.  See 2.7 Packet Padding
+Generation for more information about padding on special packets.
+
+The difference from channel message processing is that server or router
+en route never decrypts the actual private message, as it does not
+have the key to do that.  Thus, when sending packets between router
+the processing is same as in any other case as well; the packet's header
+and padding is protected by the session key and the data area is not
+touched and is not re-encrypted.
+
+The true receiver of the private message is able to decrypt the private
+message as it shares the key with the sender of the message.
+
+
+.ti 0
+2.6 Packet MAC Generation
+
+Data integrity of a packet is protected by including a message
+authentication code (MAC) at the end of the packet.  The MAC is computed
+from shared secret MAC key, that is established by the SILC Key Exchange
+protocol, from packet sequence number, and from the encrypted packet
+data.  The MAC is always computed after packet is encrypted.  This is
+so called Encrypt-Then-MAC order; packet is first encrypted, then MAC
+is computed from the encrypted data.
+
+The MAC is computed from entire packet.  Every bit of data in the packet,
+including SILC Packet Header is used in the MAC computing.  This way
+the entire packet becomes authenticated.
+
+Hence, packet's MAC generation is as follows:
+
+  mac = MAC(key, sequence number | Encrypted SILC packet)
+
+The MAC key is negotiated during the SKE protocol.  The sequence number
+is a 32 bit MSB first value starting from zero for first packet and
+increasing for subsequent packets, finally wrapping after 2^32 packets.
+The value is never reset, not even after rekey has been performed.
+However, rekey MUST be performed before the sequence number wraps
+and repeats from zero.  Note that the sequence number is incremented only
+when MAC is computed for a packet.  If packet is not encrypted and MAC is
+not computed then the sequence number is not incremented.  Hence, the
+sequence number is zero for the very first encrypted packet.
+
+See [SILC1] for defined and allowed MAC algorithms.
+
+
+.ti 0
+2.7 Packet Padding Generation
+
+Padding is needed in the packet because the packet is encrypted.  It
+always MUST be multiple by eight (8) or multiple by the block size
+of the cipher, which ever is larger.  The padding is always encrypted.
+
+For normal packets the padding is added after the SILC Packet Header
+and between the Data Payload area.  The padding for normal packets
+may be calculated as follows:
+
+.in 6
+padding_length = 16 - (packet_length mod block_size)
+if (padding_length < 8)
+  padding_length += block_size
+.in 3
+
+The `block_size' is the block size of the cipher.  The maximum padding
+length is 128 bytes, and minimum is 8 bytes.  For example, packets that
+include a passphrase or a password for authentication purposes SHOULD
+pad the packet up to the maximum padding length.  The maximum padding
+is calculated as follows:
+
+.in 6
+padding_length = 128 - (packet_length mod block_size)
+.in 3
+
+For special packets the padding calculation is different as special
+packets may be encrypted differently.  In these cases the encrypted
+data area MUST already be multiple by the block size thus in this case
+the padding is calculated only for SILC Packet Header, not for any
+other area of the packet.  The same algorithm works in this case as
+well, except that the `packet length' is now the SILC Packet Header
+length.
+
+The padding MUST be random data, preferably, generated by
+cryptographically strong random number generator for each packet
+separately.
+
+
+.ti 0
+2.8 Packet Compression
+
+SILC Packets MAY be compressed.  In this case the data payload area
+is compressed and all other areas of the packet MUST remain as they
+are.  After compression is performed for the data area, the length
+field of Packet Header MUST be set to the compressed length of the
+data.
+
+The compression MUST always be applied before encryption.  When
+the packet is received and decrypted the data area MUST be decompressed.
+Note that the true sender of the packet MUST apply the compression and
+the true receiver of the packet MUST apply the decompression.  Any
+server or router en route SHOULD NOT decompress the packet.
+
+
+.ti 0
+2.9 Packet Sending
+
+The sender of the packet MUST assemble the SILC Packet Header with
+correct values.  It MUST set the Source ID of the header as its own
+ID, unless it is forwarding the packet.  It MUST also set the Destination
+ID of the header to the true destination.  If the destination is client
+it will be Client ID, if it is server it will be Server ID and if it is
+channel it will be Channel ID.
+
+If the sender wants to compress the packet it MUST apply the
+compression now.  Sender MUST also compute the padding as described
+in above sections.  Then sender MUST encrypt the packet as has been
+described in above sections according whether the packet is normal
+packet or special packet.  Then sender MUST compute the MAC of the
+packet.  The computed MAC MUST NOT be encrypted.
+
+
+.ti 0
+2.10 Packet Reception
+
+On packet reception the receiver MUST check that all fields in the
+SILC Packet Header are valid.  It MUST check the flags of the
+header and act accordingly.  It MUST also check the MAC of the packet
+and if it is to be failed the packet MUST be discarded.  Also if the
+header of the packet includes any bad fields the packet MUST be
+discarded.
+
+See above sections on the decryption process of the received packet.
+
+The receiver MUST also check that the ID's in the header are valid
+ID's.  Unsupported ID types or malformed ID's MUST cause packet
+rejection.  The padding on the reception is always ignored.
+
+The receiver MUST also check the packet type and start parsing the
+packet according to the type.  However, note the above sections on
+special packet types and their parsing.
+
+
+.ti 0
+2.11 Packet Routing
+
+Routers are the primary entities in the SILC network that takes care
+of packet routing.  However, normal servers routes packets as well, for
+example, when they are routing channel message to the local clients.
+Routing is quite simple as every packet tells the true origin and the
+true destination of the packet.
+
+It is still RECOMMENDED for routers that has several routing connections
+to create route cache for those destinations that has faster route than
+the router's primary route.  This information is available for the router
+when other router connects to the router.  The connecting party then
+sends all of its locally connected clients, servers and channels.  These
+informations helps to create the route cache.  Also, when new channels
+are created to a cell its information is broadcasted to all routers
+in the network.  Channel ID's are based on router's ID thus it is easy
+to create route cache based on these informations.  If faster route for
+destination does not exist in router's route cache the packet MUST be
+routed to the primary route (default route).
+
+However, there are some issues when routing channel messages to group
+of users.  Routers are responsible of routing the channel message to
+other routers, local servers and local clients as well.  Routers MUST
+send the channel message to only one router in the network, preferably
+to the shortest route to reach the channel users.  The message can be
+routed into either upstream or downstream.  After the message is sent
+to a router in the network it MUST NOT be sent to any other router in
+either same route or other route.  The message MUST NOT be routed to
+the router it came from.
+
+When routing for example private messages they should be routed to the
+shortest route always to reach the destination client as fast as possible.
+
+For server which receives a packet to be routed to its locally connected
+client the server MUST check whether the particular packet type is
+allowed to be routed to the client.  Not all packets may be sent by
+some odd entity to client that is indirectly connected to the sender.
+See section 2.3 SILC Packet Types and paragraph about indirectly connected
+entities and sending packets to them.  The section mentions the packets
+that may be sent to indirectly connected entities.  It is clear that
+server cannot send, for example, disconnect packet to client that is not
+directly connected to the server.
+
+Routers form a ring in the SILC network.  However, routers may have other
+direct connections to other routers in the network too.  This can cause
+interesting routing problems in the network.  Since the network is a ring,
+the packets usually should be routed into clock-wise direction, or if it
+cannot be used then always counter clock-wise (primary route) direction.
+Problems may arise when a faster direct route exists and router is routing
+a channel message.  Currently channel messages must be routed either
+in upstream or downstream, they cannot be routed to other direct routes.
+The SILC protocol should have a shortest path discovery protocol, and some
+existing routing protocol, that can handle a ring network with other
+direct routes inside the ring (so called hybrid ring-mesh topology),
+MAY be defined to be used with the SILC protocol.  Additional
+specifications MAY be written on the subject to permeate this
+specification.
+
+
+.ti 0
+2.12 Packet Broadcasting
+
+SILC packets MAY be broadcasted in SILC network.  However, only router
+server may send or receive broadcast packets.  Client and normal server
+MUST NOT send broadcast packets and they MUST ignore broadcast packets
+if they receive them.  Broadcast packets are sent by setting Broadcast
+flag to the SILC packet header.
+
+Broadcasting packets means that the packet is sent to all routers in
+the SILC network, except to the router that sent the packet.  The router
+receiving broadcast packet MUST send the packet to its primary route.
+The fact that SILC routers may have several router connections can
+cause problems, such as race conditions inside the SILC network, if
+care is not taken when broadcasting packets.  Router MUST NOT send
+the broadcast packet to any other route except to its primary route.
+
+If the primary route of the router is the original sender of the packet
+the packet MUST NOT be sent to the primary route.  This may happen
+if router has several router connections and some other router uses
+the router as its primary route.
+
+Routers use broadcast packets to broadcast for example information
+about newly registered clients, servers, channels etc. so that all the
+routers may keep these informations up to date.
+
+
+.ti 0
+3 Security Considerations
+
+Security is central to the design of this protocol, and these security
+considerations permeate the specification.  Common security considerations
+such as keeping private keys truly private and using adequate lengths for
+symmetric and asymmetric keys must be followed in order to maintain the
+security of this protocol.
+
+
+.ti 0
+4 References
+
+[SILC1]      Riikonen, P., "Secure Internet Live Conferencing (SILC),
+             Protocol Specification", Internet Draft, May 2002.
+
+[SILC3]      Riikonen, P., "SILC Key Exchange and Authentication
+             Protocols", Internet Draft, May 2002.
+
+[SILC4]      Riikonen, P., "SILC Commands", Internet Draft, May 2002.
+
+[IRC]        Oikarinen, J., and Reed D., "Internet Relay Chat Protocol",
+             RFC 1459, May 1993.
+
+[IRC-ARCH]   Kalt, C., "Internet Relay Chat: Architecture", RFC 2810,
+             April 2000.
+
+[IRC-CHAN]   Kalt, C., "Internet Relay Chat: Channel Management", RFC
+             2811, April 2000.
+
+[IRC-CLIENT] Kalt, C., "Internet Relay Chat: Client Protocol", RFC
+             2812, April 2000.
+
+[IRC-SERVER] Kalt, C., "Internet Relay Chat: Server Protocol", RFC
+             2813, April 2000.
+
+[SSH-TRANS]  Ylonen, T., et al, "SSH Transport Layer Protocol",
+             Internet Draft.
+
+[PGP]        Callas, J., et al, "OpenPGP Message Format", RFC 2440,
+             November 1998.
+
+[SPKI]       Ellison C., et al, "SPKI Certificate Theory", RFC 2693,
+             September 1999.
+
+[PKIX-Part1] Housley, R., et al, "Internet X.509 Public Key
+             Infrastructure, Certificate and CRL Profile", RFC 2459,
+             January 1999.
+
+[Schneier]   Schneier, B., "Applied Cryptography Second Edition",
+             John Wiley & Sons, New York, NY, 1996.
+
+[Menezes]    Menezes, A., et al, "Handbook of Applied Cryptography",
+             CRC Press 1997.
+
+[OAKLEY]     Orman, H., "The OAKLEY Key Determination Protocol",
+             RFC 2412, November 1998.
+
+[ISAKMP]     Maughan D., et al, "Internet Security Association and
+             Key Management Protocol (ISAKMP)", RFC 2408, November
+             1998.
+
+[IKE]        Harkins D., and Carrel D., "The Internet Key Exchange
+             (IKE)", RFC 2409, November 1998.
+
+[HMAC]       Krawczyk, H., "HMAC: Keyed-Hashing for Message
+             Authentication", RFC 2104, February 1997.
+
+[PKCS1]      Kalinski, B., and Staddon, J., "PKCS #1 RSA Cryptography
+             Specifications, Version 2.0", RFC 2437, October 1998.
+
+[RFC2119]    Bradner, S., "Key Words for use in RFCs to Indicate
+             Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+[SFTP]       Ylonen T., and Lehtinen S., "Secure Shell File Transfer
+             Protocol", Internet Draft, March 2001.
+
+[RFC2279]    Yergeau, F., "UTF-8, a transformation format of ISO
+             10646", RFC 2279, January 1998.
+
+
+.ti 0
+5 Author's Address
+
+.nf
+Pekka Riikonen
+Snellmaninkatu 34 A 15
+70100 Kuopio
+Finland
+
+EMail: priikone@iki.fi
+
+
+.ti 0
+6 Full Copyright Statement
+
+Copyright (C) The Internet Society (2003). All Rights Reserved.
+
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/doc/draft-riikonen-silc-pp-08.nroff b/doc/draft-riikonen-silc-pp-08.nroff
new file mode 100644 (file)
index 0000000..ab7998c
--- /dev/null
@@ -0,0 +1,3041 @@
+.pl 10.0i
+.po 0
+.ll 7.2i
+.lt 7.2i
+.nr LL 7.2i
+.nr LT 7.2i
+.ds LF Riikonen
+.ds RF FORMFEED[Page %]
+.ds CF
+.ds LH Internet Draft
+.ds RH 11 August 2003
+.ds CH
+.na
+.hy 0
+.in 0
+.nf
+Network Working Group                                        P. Riikonen
+Internet-Draft
+draft-riikonen-silc-pp-08.txt                             11 August 2003
+Expires: 11 February 2004
+
+.in 3
+
+.ce 2
+SILC Packet Protocol
+<draft-riikonen-silc-pp-08.txt>
+
+.ti 0
+Status of this Memo
+
+This document is an Internet-Draft and is in full conformance with
+all provisions of Section 10 of RFC 2026.  Internet-Drafts are
+working documents of the Internet Engineering Task Force (IETF), its
+areas, and its working groups.  Note that other groups may also
+distribute working documents as Internet-Drafts.
+
+Internet-Drafts are draft documents valid for a maximum of six months
+and may be updated, replaced, or obsoleted by other documents at any
+time.  It is inappropriate to use Internet-Drafts as reference
+material or to cite them other than as "work in progress."
+
+The list of current Internet-Drafts can be accessed at
+http://www.ietf.org/ietf/1id-abstracts.txt
+
+The list of Internet-Draft Shadow Directories can be accessed at
+http://www.ietf.org/shadow.html
+
+The distribution of this memo is unlimited.
+
+
+.ti 0
+Abstract
+
+This memo describes a Packet Protocol used in the Secure Internet Live
+Conferencing (SILC) protocol, specified in the Secure Internet Live
+Conferencing, Protocol Specification [SILC1].  This protocol describes
+the packet types and packet payloads which defines the contents of the
+packets.  The protocol provides secure binary packet protocol that
+assures that the contents of the packets are secured and authenticated.
+
+
+
+
+
+
+
+
+
+.ti 0
+Table of Contents
+
+.nf
+1 Introduction ..................................................  3
+  1.1 Requirements Terminology ..................................  4
+2 SILC Packet Protocol ..........................................  4
+  2.1 SILC Packet ...............................................  4
+  2.2 SILC Packet Header ........................................  5
+  2.3 SILC Packet Types .........................................  7
+      2.3.1 SILC Packet Payloads ................................ 15
+      2.3.2 Generic payloads .................................... 15
+            2.3.2.1 ID Payload .................................. 15
+            2.3.2.2 Argument Payload ............................ 16
+            2.3.2.3 Argument List Payload ....................... 17
+            2.3.2.4 Channel Payload ............................. 18
+            2.3.2.5 Public Key Payload .......................... 19
+            2.3.2.6 Message Payload ............................. 19
+      2.3.3 Disconnect Payload .................................. 23
+      2.3.4 Success Payload ..................................... 23
+      2.3.5 Failure Payload ..................................... 24
+      2.3.6 Reject Payload ...................................... 24
+      2.3.7 Notify Payload ...................................... 25
+      2.3.8 Error Payload ....................................... 34
+      2.3.9 Channel Message Payload ............................. 34
+      2.3.10 Channel Key Payload ................................ 35
+      2.3.11 Private Message Payload ............................ 37
+      2.3.12 Private Message Key Payload ........................ 37
+      2.3.13 Command Payload .................................... 39
+      2.3.14 Command Reply Payload .............................. 40
+      2.3.15 Connection Auth Request Payload .................... 40
+      2.3.16 New ID Payload ..................................... 41
+      2.3.17 New Client Payload ................................. 42
+      2.3.18 New Server Payload ................................. 43
+      2.3.19 New Channel Payload ................................ 44
+      2.3.20 Key Agreement Payload .............................. 45
+      2.3.21 Resume Router Payload .............................. 46
+      2.3.22 File Transfer Payload .............................. 46
+      2.3.23 Resume Client Payload .............................. 48
+  2.4 SILC ID Types ............................................. 49
+  2.5 Packet Encryption And Decryption .......................... 49
+      2.5.1 Normal Packet Encryption And Decryption ............. 50
+      2.5.2 Channel Message Encryption And Decryption ........... 50
+      2.5.3 Private Message Encryption And Decryption ........... 51
+  2.6 Packet MAC Generation ..................................... 52
+  2.7 Packet Padding Generation ................................. 52
+  2.8 Packet Compression ........................................ 53
+  2.9 Packet Sending ............................................ 53
+  2.10 Packet Reception ......................................... 54
+  2.11 Packet Routing ........................................... 54
+  2.12 Packet Broadcasting ...................................... 55
+3 Security Considerations ....................................... 56
+4 References .................................................... 56
+5 Author's Address .............................................. 58
+6 Full Copyright Statement ...................................... 58
+
+.ti 0
+List of Figures
+
+.nf
+Figure 1:   Typical SILC Packet
+Figure 2:   SILC Packet Header
+Figure 3:   ID Payload
+Figure 4:   Argument Payload
+Figure 5:   Argument List Payload
+Figure 6:   Channel Payload
+Figure 7:   Public Key Payload
+Figure 8:   Message Payload
+Figure 9:   Disconnect Payload
+Figure 10:  Success Payload
+Figure 11:  Failure Payload
+Figure 12:  Reject Payload
+Figure 13:  Notify Payload
+Figure 14:  Error Payload
+Figure 15:  Channel Key Payload
+Figure 16:  Private Message Key Payload
+Figure 17:  Command Payload
+Figure 18:  Connection Auth Request Payload
+Figure 19:  New Client Payload
+Figure 20:  New Server Payload
+Figure 21:  Key Agreement Payload
+Figure 22:  Resume Router Payload
+Figure 23:  File Transfer Payload
+Figure 24:  Resume Client Payload
+
+
+.ti 0
+1. Introduction
+
+This document describes a Packet Protocol used in the Secure Internet
+Live Conferencing (SILC) protocol specified in the Secure Internet Live
+Conferencing, Protocol Specification [SILC1].  This protocol describes
+the packet types and packet payloads which defines the contents of the
+packets.  The protocol provides secure binary packet protocol that
+assures that the contents of the packets are secured and authenticated.
+The packet protocol is designed to be compact to avoid unnecessary
+overhead as much as possible.  This makes the SILC suitable also in
+environment of low bandwidth requirements such as mobile networks.  All
+packet payloads can also be compressed to further reduce the size of
+the packets.
+
+All packets in SILC network are always encrypted and their integrity
+is assured by computed MACs.  The protocol defines several packet types
+and packet payloads.  Each packet type usually has a specific packet
+payload that actually defines the contents of the packet.  Each packet
+also includes a default SILC Packet Header that provides sufficient
+information about the origin and the destination of the packet.
+
+
+.ti 0
+1.1 Requirements Terminology
+
+The keywords MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, RECOMMENDED,
+MAY, and OPTIONAL, when they appear in this document, are to be
+interpreted as described in [RFC2119].
+
+
+.ti 0
+2 SILC Packet Protocol
+
+.ti 0
+2.1 SILC Packet
+
+SILC packets deliver messages from sender to receiver securely by
+encrypting important fields of the packet.  The packet consists of
+default SILC Packet Header, Padding, Packet Payload data, and, packet
+MAC.
+
+The following diagram illustrates typical SILC packet.
+
+.in 5
+.nf
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+|   n bytes   | 1 - n bytes |      n bytes       |  n bytes
+| SILC Header |   Padding   |    Data Payload    |    MAC
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+.in 3
+
+.ce
+Figure 1:  Typical SILC Packet
+
+
+SILC Header is always the first part of the packet and its purpose
+is to provide information about the packet.  It provides for example
+the packet type, origin of the packet and the destination of the packet.
+The header is variable in length.  See the following section for
+description of SILC Packet header.  Packets without SILC header or
+with malformed SILC header MUST be dropped.
+
+Padding follows the packet header.  The purpose of the padding is to
+make the packet multiple by eight (8) or by the block size of the
+cipher used in the encryption, which ever is larger.  The maximum
+length of padding is currently 128 bytes.  The padding is always
+encrypted.  The padding is applied always, even if the packet is
+not encrypted.  See the section 2.7 Padding Generation for more
+detailed information.
+
+Data payload area follows padding and it is the actual data of the
+packet.  The packet data is the packet payloads defined in this
+protocol.  The data payload area is always encrypted.
+
+The last part of SILC packet is the packet MAC that assures the
+integrity of the packet.  See the section 2.6 Packet MAC Generation
+for more information.  If compression is used the compression is
+always applied before encryption.
+
+All fields in all packet payloads are always in MSB (most significant
+byte first) order.
+
+
+.ti 0
+2.2 SILC Packet Header
+
+The SILC packet header is applied to all SILC packets and it is
+variable in length.  The purpose of SILC Packet header is to provide
+detailed information about the packet.  The receiver of the packet
+uses the packet header to parse the packet and gain other relevant
+parameters of the packet.
+
+The following diagram represents the SILC packet header.
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|         Payload Length        |     Flags     |  Packet Type  |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|   Pad Length  |    RESERVED   | Source ID Len |  Dest ID Len  |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|  Src ID Type  |                                               |
++-+-+-+-+-+-+-+-+                                               +
+|                                                               |
+~                           Source ID                           ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|  Dst ID Type  |                                               |
++-+-+-+-+-+-+-+-+                                               +
+|                                                               |
+~                         Destination ID                        ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 2:  SILC Packet Header
+
+.in 6
+o Payload Length (2 bytes) - Indicates the length of the
+  packet not including the padding of the packet.
+
+o Flags (1 byte) - Indicates flags to be used in packet
+  processing.  Several flags may be set by ORing the flags
+  together.
+
+  The following flags are reserved for this field:
+
+
+     No flags                  0x00
+
+       In this case the field is ignored.
+
+
+     Private Message Key       0x01
+
+       Indicates that the packet data MUST include private
+       message that is encrypted using private key set by
+       client.  Servers does not know this key and cannot
+       handle the packet, but passes it along.  See section
+       2.5.3 Private Message Encryption And Decryption for
+       more information.
+
+
+     List                      0x02
+
+       Indicates that the packet consists of list of
+       packet payloads indicated by the Packet Type field.
+       The payloads are added one after the other.  Note that
+       there are packet types that must not be used as
+       list.  Parsing of list packet is done by calculating
+       the length of each payload and parsing them one by
+       one.
+
+
+     Broadcast                 0x04
+
+       Marks the packet to be broadcasted.  Client and normal
+       server cannot send broadcast packets.  Only router server
+       may send broadcast packet.  The router receiving of packet
+       with this flag set MUST send (broadcast) the packet to
+       its primary route.  If router has several router connections
+       the packet may be sent only to the primary route.  See
+       section 2.12 Packet Broadcasting for description of
+       packet broadcasting.
+
+
+     Compressed                0x08
+
+       Marks that the payload of the packet is compressed.
+       The sender of the packet marks this flag when it
+       compresses the payload, and any server or router
+       en route to the recipient MUST NOT unset this flag.
+       See section 2.8 Packet Compression for description of
+       packet compressing.
+
+.in 3
+
+o Packet Type (1 byte) - Indicates the type of the packet.
+  Receiver uses this field to parse the packet.  See section
+  2.3 SILC Packets for list of defined packet types.
+
+o Pad Length (1 byte) - Indicates the length of the padding
+  applied after the SILC Packet header.  Maximum length for
+  padding is 128 bytes.
+
+o RESERVED (1 byte) - Reserved field and must include a
+  zero (0) value.
+
+o Source ID Length (1 byte) - Indicates the length of the
+  Source ID field in the header, not including this or any
+  other fields.
+
+o Destination ID Length (1 byte) - Indicates the length of the
+  Destination ID field in the header, not including this or
+  any other fields.
+
+o Src ID Type (1 byte) - Indicates the type of ID in the
+  Source ID field.  See section 2.4 SILC ID Types for
+  defined ID types.
+
+o Source ID (variable length) - The actual source ID that
+  indicates which is the original sender of the packet.
+
+o Dst ID Type (1 byte) - Indicates the type of ID in the
+  Destination ID field.  See section 2.4 SILC ID Types for
+  defined ID types.
+
+o Destination ID (variable length) - The actual destination
+  ID that indicates which is the end receiver of the packet.
+
+
+
+.ti 0
+2.3 SILC Packet Types
+
+SILC packet types defines the contents of the packet and it is used by
+the receiver to parse the packet.  The packet type is 8 bits in length.
+The range for the packet types are from 0 - 255, where 0 is never sent and
+255 is currently reserved for future extensions and MUST NOT be defined to
+any other purpose.  Every SILC specification compliant implementation
+SHOULD support all the following packet types.
+
+The below list of the SILC Packet types includes reference to the packet
+payload as well.  Packet payloads are the actual packet data area.  Each
+packet type defines packet payload which usually may only be sent with
+the specific packet type.
+
+Most of the packets are packets that must be destined directly to entity
+that is connected to the sender.  It is not allowed, for example, for a
+router to send SILC_PACKET_DISCONNECT packet to client that is not
+directly connected to the router.  However, there are some special packet
+types that may be destined to some entity that the sender does not have
+direct connection with.  These packets are for example private message
+packets, channel message packets, command packets and some other packets
+that may be broadcasted in the SILC network.  The following packet
+desription list will define it separately if a packet is allowed to be
+sent to indirectly connected entity.  Other packets MUST NOT be sent or
+accepted, if sent, to indirectly connected entities.
+
+Some packets MAY be sent as lists by adding the List flag to the Packet
+Header and constructing multiple packet payloads one after the other.
+When this is allowed it is separately defined in the following list.
+Other packets MUST NOT be sent as list and the List flag MUST NOT be set.
+
+
+List of SILC Packet types are defined as follows.
+
+.in 1
+     0    SILC_PACKET_NONE
+
+          This type is reserved and it is never sent.
+
+
+     1    SILC_PACKET_DISCONNECT
+
+          This packet is sent to disconnect the remote end.  Reason of
+          the disconnection is sent inside the packet payload.
+
+          Payload of the packet:  See section 2.3.3 Disconnect Payload
+
+
+     2    SILC_PACKET_SUCCESS
+
+          This packet is sent upon successful execution of a protocol.
+          The status of the success is sent in the packet payload.
+
+          Payload of the packet:  See section 2.3.4 Success Payload
+
+
+     3    SILC_PACKET_FAILURE
+
+          This packet is sent upon failure of a protocol.  The status
+          of the failure is sent in the packet payload.
+
+          Payload of the packet:  See section 2.3.5 Failure Payload
+
+
+     4    SILC_PACKET_REJECT
+
+          This packet MAY be sent upon rejection of a protocol.  The
+          status of the rejection is sent in the packet payload.
+
+          Payload of the packet:  See section 2.3.6 Reject Payload
+
+
+     5    SILC_PACKET_NOTIFY
+
+          This packet is used to send notify message.  The packet is
+          usually sent between server and client, but also between
+          server and router.  Client MUST NOT send this packet.  Server
+          MAY destine this packet to channel as well when the packet is
+          distributed to all clients on the channel.  This packet MAY
+          be sent as list.
+
+          Payload of the packet:  See section 2.3.7 Notify Payload.
+
+
+     6    SILC_PACKET_ERROR
+
+          This packet is sent when an error occurs.  Server MAY
+          send this packet.  Client MUST NOT send this packet.  The
+          client MAY entirely ignore the packet, however, server is
+          most likely to take action anyway.  This packet MAY be sent
+          to entity that is indirectly connected to the sender.
+
+          Payload of the packet:  See section 2.3.8 Error Payload.
+
+
+     7    SILC_PACKET_CHANNEL_MESSAGE
+
+          This packet is used to send messages to channels.  The packet
+          includes Channel ID of the channel and the actual message to
+          the channel.  Messages sent to the channel are always protected
+          by channel specific keys.  This packet MAY be sent to entity
+          that is indirectly connected to the sender.
+
+          Payload of the packet:  See section 2.3.9 Channel Message
+                                  Payload
+
+
+     8    SILC_PACKET_CHANNEL_KEY
+
+          This packet is used to distribute new key for particular
+          channel when server generates it.  Each channel has their own
+          independent keys that is used to protect the traffic on the
+          channel.  It is also possible to use channel private keys that
+          are not server generated.  In this case this packet is not used.
+          Client MUST NOT send this packet.  This packet MAY be sent to
+          entity that is indirectly connected to the sender.
+
+          Payload of the packet:  See section 2.3.10 Channel Key Payload
+
+
+     9    SILC_PACKET_PRIVATE_MESSAGE
+
+          This packet is used to send private messages from client
+          to another client.  By default, private messages are protected
+          by session keys established by normal key exchange protocol.
+          However, it is possible to use specific key to protect private
+          messages.  See [SILC1] for private message key generation.
+          This packet MAY be sent to entity that is indirectly connected
+          to the sender.
+
+          Payload of the packet:  See section 2.3.11 Private Message
+                                  Payload
+
+
+     10   SILC_PACKET_PRIVATE_MESSAGE_KEY
+
+          This packet can be used to agree about a key to be used to
+          protect private messages between two clients.  This packet
+          is sent inside the SILC network and protected with session
+          keys.  There are other means of agreeing to use private message
+          keys as well, than sending this packet which may not be
+          desirable on all situations.  See the [SILC1] for private
+          message key generation.  This packet MAY be sent to entity
+          that is indirectly connected to the sender.
+
+          Payload of the packet:  See section 2.3.12 Private Message
+                                  Key Payload
+
+
+     11   SILC_PACKET_COMMAND
+
+          This packet is used to send commands from client to server.
+          Server MAY send this packet to other servers as well.  All
+          commands are listed in their own section SILC Command Types
+          in [SILC4].  The contents of this packet is command specific.
+          This packet MAY be sent to entity that is indirectly connected
+          to the sender.
+
+          Payload of the packet:  See section 2.3.13 Command Payload
+
+
+     12   SILC_PACKET_COMMAND_REPLY
+
+          This packet is sent as reply to the SILC_PACKET_COMMAND packet.
+          The contents of this packet is command specific.  This packet
+          MAY be sent to entity that is indirectly connected to the
+          sender.  This packet MAY be sent as list.
+
+          Payload of the packet:  See section 2.3.14 Command Reply
+                                  Payload and section 2.3.13 Command
+                                  Payload
+
+
+
+     13   SILC_PACKET_KEY_EXCHANGE
+
+          This packet is used to start SILC Key Exchange Protocol,
+          described in detail in [SILC3].
+
+          Payload of the packet:  Payload of this packet is described
+                                  in the section SILC Key Exchange
+                                  Protocol and its sub sections in
+                                  [SILC3].
+
+
+     14   SILC_PACKET_KEY_EXCHANGE_1
+
+          This packet is used as part of the SILC Key Exchange Protocol.
+
+          Payload of the packet:  Payload of this packet is described
+                                  in the section SILC Key Exchange
+                                  Protocol and its sub sections in
+                                  [SILC3].
+
+
+     15   SILC_PACKET_KEY_EXCHANGE_2
+
+          This packet is used as part of the SILC Key Exchange Protocol.
+
+          Payload of the packet:  Payload of this packet is described
+                                  in the section SILC Key Exchange
+                                  Protocol and its sub sections in
+                                  [SILC3].
+
+
+     16   SILC_PACKET_CONNECTION_AUTH_REQUEST
+
+          This packet is used to request an authentication method to
+          be used in the SILC Connection Authentication Protocol.  If
+          initiator of the protocol does not know the mandatory
+          authentication method this packet MAY be used to determine it.
+          The party receiving this payload SHOULD respond with the same
+          packet including the mandatory authentication method.
+
+          Payload of the packet:  See section 2.3.15 Connection Auth
+                                  Request Payload
+
+
+     17   SILC_PACKET_CONNECTION_AUTH
+
+          This packet is used to start and perform the SILC Connection
+          Authentication Protocol.  This protocol is used to authenticate
+          the connecting party.  The protocol is described in detail in
+          [SILC3].
+
+          Payload of the packet:  Payload of this packet is described
+                                  in the section SILC Authentication
+                                  Protocol and it sub sections in [SILC].
+
+
+     18   SILC_PACKET_NEW_ID
+
+          This packet is used to distribute new IDs from server to
+          router and from router to all other routers in SILC network.
+          This is used when for example new client is registered to
+          SILC network.  The newly created IDs of these operations are
+          distributed by this packet.  Only server may send this packet,
+          however, client MUST be able to receive this packet.  This
+          packet MAY be sent to entity that is indirectly connected
+          to the sender.  This packet MAY be sent as list.
+
+          Payload of the packet:  See section 2.3.16 New ID Payload
+
+
+     19   SILC_PACKET_NEW_CLIENT
+
+          This packet is used by client to register itself to the
+          SILC network.  This is sent after key exchange and
+          authentication protocols has been completed.  Client sends
+          various information about itself in this packet to the server.
+
+          Payload of the packet:  See section 2.3.17 New Client Payload
+
+
+     20   SILC_PACKET_NEW_SERVER
+
+          This packet is used by server to register itself to the
+          SILC network.  This is sent after key exchange and
+          authentication protocols has been completed.  Server sends
+          this to the router it connected to, or, if router was
+          connecting, to the connected router.  Server sends its
+          Server ID and other information in this packet.  The client
+          MUST NOT send or receive this packet.
+
+          Payload of the packet:  See section 2.3.18 New Server Payload
+
+
+     21   SILC_PACKET_NEW_CHANNEL
+
+          This packet is used to notify routers about newly created
+          channel.  Channels are always created by the router and it MUST
+          notify other routers about the created channel.  Router sends
+          this packet to its primary route.  Client MUST NOT send this
+          packet.  This packet MAY be sent to entity that is indirectly
+          connected to the sender.  This packet MAY be sent as list.
+
+          Payload of the packet:  See section 2.3.19 New Channel Payload
+
+
+     22   SILC_PACKET_REKEY
+
+          This packet is used to indicate that re-key must be performed
+          for session keys.  See section Session Key Regeneration in
+          [SILC1] for more information.  This packet does not have
+          a payload.
+
+
+     23   SILC_PACKET_REKEY_DONE
+
+          This packet is used to indicate that re-key is performed and
+          new keys must be used hereafter.  This packet does not have a
+          payload.
+
+
+     24   SILC_PACKET_HEARTBEAT
+
+          This packet is used by clients, servers and routers to keep the
+          connection alive.  It is RECOMMENDED that all servers implement
+          keepalive actions and perform it to both direction in a link.
+          This packet does not have a payload.
+
+
+     25   SILC_PACKET_KEY_AGREEMENT
+
+          This packet is used by clients to request key negotiation
+          between another client in the SILC network.  If the negotiation
+          is started it is performed using the SKE protocol.  The result of
+          the negotiation, the secret key material, can be used for
+          example as private message key.  The server and router MUST NOT
+          send this packet.
+
+          Payload of the packet:  See section 2.3.20 Key Agreement Payload
+
+
+     26   SILC_PACKET_RESUME_ROUTER
+
+          This packet is used during backup router protocol when the
+          original primary router of the cell comes back online and wishes
+          to resume the position as being the primary router of the cell.
+
+          Payload of the packet:  See section 2.3.21 Resume Router Payload
+
+
+     27   SILC_PACKET_FTP
+
+          This packet is used to perform an file transfer protocol in the
+          SILC session with some entity in the network.  The packet is
+          multi purpose.  The packet is used to tell other entity in the
+          network that the sender wishes to perform an file transfer
+          protocol.  The packet is also used to actually tunnel the
+          file transfer protocol stream.  The file transfer protocol
+          stream is always protected with the SILC binary packet protocol.
+
+          Payload of the packet:  See section 2.3.22 File Transfer Payload
+
+
+     28   SILC_PACKET_RESUME_CLIENT
+
+          This packet is used to resume a client back to the network
+          after it has been detached.  A client is able to detach from
+          the network but the client is still valid client in the network.
+          The client may then later resume its session back by sending
+          this packet to a server.  Routers also use this packet to notify
+          other routers in the network that the detached client has resumed.
+
+          Payload of the packet:  See section 2.3.23 Resume Client Payload
+
+
+     29 - 199
+
+          Currently undefined commands.
+
+
+     200 - 254
+
+          These packet types are reserved for private use and they will
+          not be defined by this document.
+
+
+     255  SILC_PACKET_MAX
+
+          This type is reserved for future extensions and currently it
+          MUST NOT be sent.
+.in 3
+
+
+.ti 0
+2.3.1 SILC Packet Payloads
+
+All payloads resides in the main data area of the SILC packet.  However
+all payloads MUST be at the start of the data area after the SILC
+packet header and padding.  All fields in the packet payload are always
+encrypted, as they reside in the data area of the packet which is
+always encrypted.  Most of the payloads may only be sent with specific
+packet type which is defined in the description of the payload.
+
+There are some other payloads in SILC as well.  However, they are not
+common in the sense that they could be sent at any time.  These payloads
+are not described in this section.  These are payloads such as SILC
+Key Exchange payloads and so on.  These are described in [SILC1],
+[SILC3] and [SILC4].
+
+
+.ti 0
+2.3.2 Generic payloads
+
+This section describes generic payloads that are not associated to any
+specific packet type.  They can be used for example inside some other
+packet payload.
+
+
+.ti 0
+2.3.2.1 ID Payload
+
+This payload can be used to send an ID.  ID's are variable in length
+thus this payload provides a way to send variable length ID.
+
+The following diagram represents the ID Payload.
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|             ID Type           |           ID Length           |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                           ID Data                             ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 3:  ID Payload
+
+
+.in 6
+o ID Type (2 bytes) - Indicates the type of the ID.  See
+  section 2.4 SILC ID Types for list of defined ID types.
+
+o ID Length (2 bytes) - Length of the ID Data area not
+  including the length of any other fields in the payload.
+
+o ID Data (variable length) - The actual ID data.  The encoding
+  of the ID data is defined in section 2.4 SILC ID Types.
+.in 3
+
+
+.ti 0
+2.3.2.2 Argument Payload
+
+Argument Payload is used to set arguments for any packet payload that
+need and support arguments, such as commands.  Number of arguments
+associated with a packet MUST be indicated by the packet payload which
+need the arguments.  Argument Payloads MUST always reside right after
+the packet payload needing the arguments.  Incorrect amount of argument
+payloads MUST cause rejection of the packet.
+
+The following diagram represents the Argument Payload.
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|          Data Length          | Argument Type |               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+               +
+|                                                               |
+~                        Argument Data                          ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 4:  Argument Payload
+
+
+.in 6
+o Data Length (2 bytes) - Length of the Argument Data field
+  not including the length of any other field in the payload.
+
+o Argument Type (1 byte) - Indicates the type of the argument.
+  Every argument can have a specific type that are defined
+  by the packet payload needing the argument.  For example
+  every command specify a number for each argument that may be
+  associated with the command.  By using this number the receiver
+  of the packet knows what type of argument this is.  If there is
+  no specific argument type this field is set to zero (0) value.
+
+o Argument Data (variable length) - Argument data.
+.in 3
+
+
+.ti 0
+2.3.2.3 Argument List Payload
+
+Argument List Payload is a list of Argument Payloads appended one
+after the other.  The number of arguments is indicated in the
+payload.
+
+The following diagram represents the Argument List Payload.
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|         Argument Nums         |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                        Argument Payloads                      ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 5:  Argument List Payload
+
+
+.in 6
+o Argument Nums (2 bytes) - Indicates the number of Argument
+  Payloads.  If zero (0) value is found in this field no
+  arguments are present.
+
+o Argument Payloads (variable length) - The Argument Payloads
+  appended one after the other.  The payloads can be decoded
+  since the length of the payload is indicated in each of
+  the Argument Payload.
+.in 3
+
+
+
+
+.ti 0
+2.3.2.4 Channel Payload
+
+Generic Channel Payload may be used to send information about a channel,
+its name, the Channel ID and a mode.
+
+The following diagram represents the Channel Payload.
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|      Channel Name Length      |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                         Channel Name                          ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Channel ID Length       |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                          Channel ID                           ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                           Mode Mask                           |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 6:  New Channel Payload
+
+
+.in 6
+o Channel Name Length (2 bytes) - Length of the Channel Name
+  field.
+
+o Channel Name (variable length) - The name of the channel.
+
+o Channel ID Length (2 bytes) - Length of the Channel ID field.
+
+o Channel ID (variable length) - The encoded Channel ID.
+
+o Mode Mask (4 bytes) - A mode.  This can be the mode of the
+  channel but it can also be the mode of a client on the
+  channel.  The contents of this field is dependent of the
+  usage of this payload.  The usage is defined separately
+  when this payload is used.  This is a 32 bit MSB first value.
+.in 3
+
+
+
+
+
+
+.ti 0
+2.3.2.5 Public Key Payload
+
+Generic Public Key Payload may be used to send different type of
+public keys and certificates.
+
+The following diagram represents the Public Key Payload.
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Public Key Length       |        Public Key Type        |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                  Public Key (or certificate)                  ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 7:  Public Key Payload
+
+
+.in 6
+o Public Key Length (2 bytes) - The length of the Public Key
+  (or certificate) field, not including any other field.
+
+o Public Key Type (2 bytes) - The public key (or certificate)
+  type.  This field indicates the type of the public key in
+  the packet.  See the [SILC3] for defined public key types.
+
+o Public Key (or certificate) (variable length) - The
+  encoded public key or certificate data.
+.in 3
+
+
+.ti 0
+2.3.2.6 Message Payload
+
+Generic Message Payload can be used to send messages in SILC.  It
+is used to send channel messages and private messages.
+
+The following diagram represents the Message Payload.
+
+(*) indicates that the field is not encrypted.
+
+
+
+
+
+
+
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Message  Flags         |         Message Length        |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                         Message Data                          ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Padding Length         |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                            Padding                            ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                       Initial Vector *                        ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                              MAC *                            ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 8:  Message Payload
+
+
+.in 6
+o Message Flags (2 bytes) - Includes the Message Flags of the
+  message.  The flags can indicate a reason or a purpose for
+  the message.  The following Message Flags are defined:
+
+  0x0000  SILC_MESSAGE_FLAG_NONE
+
+          No specific flags set.
+
+  0x0001  SILC_MESSAGE_FLAG_AUTOREPLY
+
+          This message is an automatic reply to an earlier
+          received message.
+
+  0x0002  SILC_MESSAGE_FLAG_NOREPLY
+
+          There should not be reply messages to this
+          message.
+
+  0x0004  SILC_MESSAGE_FLAG_ACTION
+
+          The sender is performing an action and the message
+          is the indication of the action.
+
+  0x0008  SILC_MESSAGE_FLAG_NOTICE
+
+          The message is for example an informational notice
+          type message.
+
+  0x0010  SILC_MESSAGE_FLAG_REQUEST
+
+          This is a generic request flag to send request
+          messages.  A separate document should define any
+          payloads associated to this flag.
+
+  0x0020  SILC_MESSAGE_FLAG_SIGNED
+
+          This flag indicates that the message is signed
+          with sender's private key and thus can be verified
+          by the receiver using the sender's public key.  A
+          separate document should define the detailed procedure
+          of the signing process and any associated payloads
+          for this flag.
+
+  0x0040  SILC_MESSAGE_FLAG_REPLY
+
+          This is a generic reply flag to send a reply to
+          previously received request.  A separate document
+          should define any payloads associated to this flag.
+
+  0x0080  SILC_MESSAGE_FLAG_DATA
+
+          This is a generic data flag, indicating that the
+          message includes some data which can be interpreted
+          in a specific way.  Using this flag any kind of data
+          can be delivered inside message payload.  A separate
+          document should define how this flag is interpreted
+          and define any associated payloads.
+
+  0x0100  SILC_MESSAGE_FLAG_UTF8
+
+          This flag indicates that the message is UTF-8 encoded
+          textual message.  When sending text messages in SILC
+          this flag SHOULD be used.  When this flag is used the
+          text sent as message MUST be UTF-8 encoded.
+
+  0x0200 - 0x0800 RESERVED
+
+          Reserved for future flags.
+
+  0x1000 - 0x8000 PRIVATE RANGE
+
+          Private range for free use.
+
+o Message Length (2 bytes) - Indicates the length of the
+  Message Data field in the payload, not including any
+  other field.
+
+o Message Data (variable length) - The actual message data.
+
+o Padding Length (2 bytes) - Indicates the length of the
+  Padding field in the payload, not including any other
+  field.
+
+o Padding (variable length) - If this payload is used as
+  channel messages, the padding MUST be applied because
+  this payload is encrypted separately from other parts
+  of the packet.  If this payload is used as private
+  messages, the padding is present only when the payload
+  is encrypted with private message key.  If encrypted
+  with session keys this field MUST NOT be present and the
+  Padding Length field includes a zero (0) value.  The
+  padding SHOULD be random data.
+
+o Initial Vector (variable length) - This field MUST be
+  present when this payload is used as channel messages.
+  The IV SHOULD be random data for each channel message.
+
+  When encrypting private messages with session keys this
+  field MUST NOT be present.  For private messages this
+  field is present only when encrypting with a static
+  private message key (pre-shared key).  If randomly
+  generated key material is used this field MUST NOT be
+  present.  Also, If Key Agreement (SKE) was used to
+  negotiate fresh key material for private message key
+  this field MUST NOT be present.  See the section 4.6
+  in [SILC1] for more information about IVs when
+  encrypting private messages.
+
+  This field includes the initial vector used in message
+  encryption.  It need to be used in the packet decryption
+  as well.  Contents of this field depends on the encryption
+  algorithm and encryption mode.  This field is not encrypted,
+  is not included in padding calculation and its length
+  equals to cipher's block size.  This field is authenticated
+  by the message MAC.
+
+o MAC (variable length) - The MAC computed from the
+  Message Flags, Message Length, Message Data, Padding Length,
+  Padding and Initial Vector fields in that order.  The MAC
+  is computed after the payload is encrypted.  This is so
+  called Encrypt-Then-MAC order; first encrypt, then compute
+  MAC from ciphertext.  The MAC protects the integrity of
+  the Message Payload.  Also, when used as channel messages
+  it is possible to have multiple private channel keys set,
+  and receiver can use the MAC to verify which of the keys
+  must be used in decryption.  This field is not present
+  when encrypting private messages with session key.  This
+  field is not encrypted. This field is authenticated by
+  the SILC packet MAC.
+.in 3
+
+
+.ti 0
+2.3.3 Disconnect Payload
+
+Disconnect payload is sent upon disconnection.  Reason of the
+disconnection is sent to the disconnected party in the payload.
+
+The payload may only be sent with SILC_PACKET_DISCONNECT packet.  It
+MUST NOT be sent in any other packet type.  The following diagram
+represents the Disconnect Payload.
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|    Status     |                                               |
++-+-+-+-+-+-+-+-+                                               +
+|                                                               |
+~                      Disconnect Message                       ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 9:  Disconnect Payload
+
+.in 6
+o Status (1 byte) - Indicates the Status Type, defined in [SILC3]
+  for the reason of disconnection.
+
+o Disconnect Message (variable length) - Human readable UTF-8
+  encoded string indicating reason of the disconnection.  This
+  field MAY be omitted.
+.in 3
+
+
+.ti 0
+2.3.4 Success Payload
+
+Success payload is sent when some protocol execution is successfully
+completed.  The payload is simple; indication of the success is sent.
+This may be any data, including binary or human readable data, and
+it is protocol dependent.
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                      Success Indication                       ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 10:  Success Payload
+
+
+.in 6
+o Success Indication (variable length) - Indication of
+  the success.  This may be for example some flag that
+  indicates the protocol and the success status or human
+  readable success message.  The true length of this
+  payload is available by calculating it from the SILC
+  Packet Header.
+.in 3
+
+
+.ti 0
+2.3.5 Failure Payload
+
+This is opposite of Success Payload.  Indication of failure of
+some protocol is sent in the payload.
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                      Failure Indication                       ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 11:  Failure Payload
+
+
+.in 6
+o Failure Indication (variable length) - Indication of
+  the failure.  This may be for example some flag that
+  indicates the protocol and the failure status or human
+  readable failure message.  The true length of this
+  payload is available by calculating it from the SILC
+  Packet Header.
+.in 3
+
+
+.ti 0
+2.3.6 Reject Payload
+
+This payload is sent when some protocol is rejected to be executed.
+Other operations MAY send this as well that was rejected.  The
+indication of the rejection is sent in the payload.  The indication
+may be binary or human readable data and is protocol dependent.
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                       Reject Indication                       ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 12:  Reject Payload
+
+
+.in 6
+o Reject Indication (variable length) - Indication of
+  the rejection.  This maybe for example some flag that
+  indicates the protocol and the rejection status or human
+  readable rejection message.  The true length of this
+  payload is available by calculating it from the SILC
+  Packet Header.
+.in 3
+
+
+
+.ti 0
+2.3.7 Notify Payload
+
+Notify payload is used to send notify messages.  The payload is usually
+sent from server to client and from server to router.  It is also used
+by routers to notify other routers in the network.  This payload MAY also
+be sent to a channel.  Client MUST NOT send this payload.  When this
+packet is received by client it SHOULD process it.  Servers and routers
+MUST process notify packets.
+
+The payload may only be sent with SILC_PACKET_NOTIFY packet.  It MUST
+NOT be sent in any other packet type.  The following diagram represents
+the Notify Payload.
+
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|          Notify Type          |        Payload Length         |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Argument Nums |
++-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 13:  Notify Payload
+
+
+.in 6
+o Notify Type (2 bytes) - Indicates the type of the notify
+  message.
+
+o Payload Length (2 bytes) - Length of the entire Notify Payload
+  including any associated Argument Payloads.
+
+o Argument Nums (1 byte) - Indicates the number of Argument
+  Payloads associated to this payload.  Notify types may define
+  arguments to be sent along the notify message.
+.in 3
+
+The following list of currently defined notify types.  The format for
+notify arguments is same as in SILC commands described in [SILC4].
+Note that all IDs sent in arguments are sent inside ID Payload.  Also
+note that all passphrases that may be sent inside arguments MUST be
+UTF-8 [RFC2279] encoded.  Also note that all public keys or certificates
+sent inside arguments are actually Public Key Payloads.
+
+
+.in 6
+0     SILC_NOTIFY_TYPE_NONE
+
+      If no specific notify type apply for the notify message this type
+      MAY be used.
+
+      Max Arguments:  1
+          Arguments:  (1) <message>
+
+      The <message> is implementation specific free UTF-8 text string.
+      Receiver MAY ignore this message.
+
+
+1     SILC_NOTIFY_TYPE_INVITE
+
+      Sent when an client is invited to a channel.  This is also sent
+      when the invite list of the channel is changed.  This notify type
+      is sent to local servers on the channel, but MUST NOT be sent
+      to clients on the channel.  Router MUST broadcast this to its
+      primary router and to local servers on the channel.  When a client
+      was directly invited to the channel this is also sent to that 
+      client.  In this case the packet is destined to the client.
+
+      Max Arguments:  5
+          Arguments:  (1) <Channel ID>          (2) <channel name>
+                      (3) [<sender Client ID>]  (4) [<add | del>]
+                      (5) [<invite list>]
+
+      The <Channel ID> is the channel.  The <channel name> is the name
+      of the channel and is provided because the client which receives
+      this notify packet may not have a way to resolve the name of the
+      channel from the <Channel ID>.  The <sender Client ID> is the
+      Client ID which invited the client to the channel.  The
+      <add | del> is an argument of size of 1 byte where 0x00 means
+      adding a client to invite list, and 0x01 means deleting a client
+      from invite list.  The <invite list>, if present, indicates the
+      information to be added to or removed from the invite list.
+      The <invite list> format is defined in [SILC4] with
+      SILC_COMMAND_INVITE command.  When this notify is destined to
+      a client the <add | del> and <invite list> MUST NOT be sent.
+      When <add | del> is used  to announce information during server 
+      connecting phase the argument type MUST be 0x03.  See section
+      4.2.1 in [SILC1] for more information.
+
+
+2     SILC_NOTIFY_TYPE_JOIN
+
+      Sent when client has joined to a channel.  The server MUST
+      distribute this type to the local clients on the channel and then
+      send it to its primary router.  Note that, when router is joining
+      the client on behalf of normal server then router MUST send this
+      notify type locally and globally.  The router or server receiving
+      the packet distributes this type to the local clients on the
+      channel and broadcast it to the network.  This notify is sent
+      also to the client that joined the channel.
+
+      Max Arguments:  2
+          Arguments:  (1) [<Client ID>]       (2) <Channel ID>
+
+      The <Client ID> is the client that joined to the channel
+      indicated by the <Channel ID>.
+
+
+3     SILC_NOTIFY_TYPE_LEAVE
+
+      Sent when client has left a channel.  The server must distribute
+      this type to the local clients on the channel and then send it
+      to its primary router.  The router or server receiving the
+      packet distributes this type to the local clients on the channel
+      and broadcast it to the network.  This notify MUST NOT be sent to
+      the leaving client.
+
+      Max Arguments:  1
+          Arguments:  (1) <Client ID>
+
+      The <Client ID> is the client which left the channel.
+
+
+4     SILC_NOTIFY_TYPE_SIGNOFF
+
+      Sent when client signoff from SILC network.  The server MUST
+      distribute this type to the local clients on the channel and
+      then send it to its primary router.  The router or server
+      receiving the packet distributes this type to the local clients
+      on the channel and broadcast it to the network.  This notify
+      MUST NOT be sent to the quitting client.
+
+      Max Arguments:  2
+          Arguments:  (1) <Client ID>  (2) <message>
+
+      The <Client ID> is the client which left SILC network.  The
+      <message> is free text string indicating the reason of the
+      signoff.
+
+
+5     SILC_NOTIFY_TYPE_TOPIC_SET
+
+      Sent when topic is set/changed on a channel.  This type may be
+      sent only to the clients which are joined on the channel which
+      topic was just set or changed.  The packet is destined to the
+      channel.
+
+      Max Arguments:  2
+          Arguments:  (1) <ID Payload>  (2) <topic>
+
+      The <ID Payload> is the ID of the entity who set the topic.
+      It usually is Client ID but it can be Server ID and Channel ID
+      as well.
+
+
+6     SILC_NOTIFY_TYPE_NICK_CHANGE
+
+      Sent when client changes nick on a channel.  The server MUST
+      distribute this type only to the local clients on the channel
+      and then send it to its primary router.  The router or server
+      receiving the packet distributes this type to the local clients
+      on the channel and broadcast it to the network.  This packet is
+      destined directly to the sent entity.  This MUST be sent to those
+      clients that are joined on same channels as the client that
+      changed the nickname.  This notify MUST NOT be sent multiple
+      times to the same recipient.  This notify MUST be sent also to
+      the client that changed the nickname.
+
+      Max Arguments:  3
+          Arguments:  (1) <Old Client ID>  (2) <New Client ID>
+                      (3) <nickname>
+
+      The <Old Client ID> is the old ID of the client which changed
+      the nickname.  The <New Client ID> is the new ID generated by
+      the change of the nickname.  The <nickname> is the new nickname.
+      Note that it is possible to send this notify even if the
+      nickname has not changed, but client ID was changed.
+
+
+7     SILC_NOTIFY_TYPE_CMODE_CHANGE
+
+      Sent when channel mode has changed.  This type MUST be sent only
+      to the clients which are joined on the channel which mode was
+      changed.  This packet is destined to the channel.
+
+      Max Arguments:  7
+          Arguments:  (1) <ID Payload>      (2) <mode mask>
+                      (3) [<cipher>]        (4) <[hmac>]
+                      (5) [<passphrase>]    (6) [<founder public key>]
+                      (7) [<channel pubkey>]
+
+      The <ID Payload> is the ID (usually Client ID but it can be
+      Server ID as well when the router is enforcing channel mode
+      change) of the entity which changed the mode.  The <mode mask>
+      is the new mode mask of the channel.  The client can safely
+      ignore the <cipher> argument since the SILC_PACKET_CHANNEL_KEY
+      packet will force the new channel key change anyway.  The <hmac>
+      argument is important since the client is responsible of setting
+      the new HMAC and the hmac key into use.  The <passphrase> is
+      the passphrase of the channel, if it was now set.  The <founder
+      public key> argument is sent when the founder mode on the
+      channel was set.  All routers and servers that receive the packet
+      MUST save the founder's public key so that the founder can
+      reclaim the channel founder rights back for the channel on any
+      server in the network.
+
+      The <channel pubkey> is an Argument List Payload and it is used
+      to add and/or remove channel public keys from the channel.  Also,
+      when announcing channel information between servers and routers
+      during connecting phase this argument includes the list of channel
+      public keys.  To add a public key to channel public key list the
+      SILC_CMODE_CHANNEL_AUTH mode is set and the argument type is 0x00,
+      and the argument is the public key.  To remove a public key from
+      the channel public key list the argument type is 0x01, and the
+      argument is the public key to be removed.  If the mode
+      SILC_CMODE_CHANNEL_AUTH is unset (and was set earlier) all public
+      keys are removed at once.  Implementation MAY add and remove
+      multiple public keys at the same time by including multiple
+      arguments to the <channel pubkey> Argument List Payload where each
+      argument is one Public Key Payload.  When <channel pubkey> is used
+      to announce information during server connecting phase the
+      argument type MUST be 0x03.  See section 4.2.1 in [SILC1] for
+      more information.
+
+
+8     SILC_NOTIFY_TYPE_CUMODE_CHANGE
+
+      Sent when user mode on channel has changed.  This type MUST be
+      sent only to the clients which are joined on the channel where
+      the target client is on.  This packet is destined to the channel.
+
+      Max Arguments:  4
+          Arguments:  (1) <ID Payload>        (2) <mode mask>
+                      (3) <Target Client ID>  (4) [<founder pubkey>]
+
+      The <ID Payload> is the ID (usually Client ID but it can be
+      Server ID as well when the router is enforcing user's mode
+      change) of the entity which changed the mode.  The <mode mask>
+      is the new mode mask of the channel.  The <Target Client ID>
+      is the client which mode was changed.  The <founder pubkey>
+      is the public key of the channel founder and may be sent only
+      when first time setting the channel founder mode using the
+      SILC_COMMAND_CUMODE command, and when sending this notify.
+
+
+9     SILC_NOTIFY_TYPE_MOTD
+
+      Sent when Message of the Day (motd) is sent to a client.
+
+      Max Arguments:  1
+          Arguments:  (1) <motd>
+
+      The <motd> is the Message of the Day.  This notify MAY be
+      ignored.
+
+
+10    SILC_NOTIFY_TYPE_CHANNEL_CHANGE
+
+      Sent when channel's ID has changed for a reason or another.
+      This is sent by normal server to the client.  This can also be
+      sent by router to other server to force the Channel ID change.
+      The Channel ID MUST be changed to use the new one.  When sent
+      to clients, this type MUST be sent only to the clients which are
+      joined on the channel.  This packet is destined to the sent
+      entity.
+
+      Max Arguments:  2
+          Arguments:  (1) <Old Channel ID>  (2) <New Channel ID>
+
+      The <Old Channel ID> is the channel's old ID and the <New
+      Channel ID> is the new one that MUST replace the old one.
+      Server which receives this from router MUST re-announce the
+      channel to the router by sending SILC_PACKET_NEW_CHANNEL packet
+      with the new Channel ID.
+
+
+11    SILC_NOTIFY_TYPE_SERVER_SIGNOFF
+
+      Sent when server quits SILC network.  Those clients from this
+      server that are on channels must be removed from the channel.
+      This packet is destined to the sent entity.
+
+      Max Arguments:  256
+          Arguments:  (1) <Server ID>   (n) [<Client ID>]   [...]
+
+      The <Server ID> is the server's ID.  The rest of the arguments
+      are the Client IDs of the clients which are coming from this
+      server and are thus quitting the SILC network also.  If the
+      maximum number of arguments are reached another
+      SILC_NOTIFY_TYPE_SERVER_SIGNOFF notify packet MUST be sent.
+      When this notify packet is sent between routers the Client ID's
+      MAY be omitted.  Server receiving the Client ID's in the payload
+      may use them directly to remove the client.
+
+
+12    SILC_NOTIFY_TYPE_KICKED
+
+      Sent when a client has been kicked from a channel.  This MUST
+      also be sent to the client which was kicked from the channel.
+      The client which was kicked from the channel MUST be removed
+      from the channel.  The client MUST also be removed from channel's
+      invite list if it is explicitly added in the list.  This packet
+      is destined to the channel.  The router or server receiving the
+      packet distributes this type to the local clients on the channel
+      and broadcast it to the network.
+
+      Max Arguments:  3
+          Arguments:  (1) <Client ID>           (2) [<comment>]
+                      (3) <Kicker's Client ID>
+
+      The <Client ID> is the client which was kicked from the channel.
+      The kicker may have set the <comment> to indicate the reason for
+      the kicking.  The <Kicker's Client ID> is the kicker.
+
+
+13    SILC_NOTIFY_TYPE_KILLED
+
+      Sent when a client has been killed from the network.  This MUST
+      also be sent to the client which was killed from the network.
+      This notify MUST be sent to those clients which are joined on
+      same channels as the killed client.  The client which was killed
+      MUST be removed from the network.  This packet is destined
+      directly to the sent entity.  The router or server receiving
+      the packet distributes this type to the local clients on the
+      channel and broadcast it to the network.  The client MUST also
+      be removed from joined channels invite list if it is explicitly
+      added in the lists.  This notify MUST NOT be sent multiple
+      times to same recipient.
+
+      Max Arguments:  3
+          Arguments:  (1) <Client ID>           (2) [<comment>]
+                      (3) <Killer's ID>
+
+      The <Client ID> is the client which was killed from the network.
+      The killer may have set the <comment> to indicate the reason for
+      the killing.  The <Killer's ID> is the killer, which may be
+      client but also router server.
+
+
+14    SILC_NOTIFY_TYPE_UMODE_CHANGE
+
+      Sent when user's mode in the SILC changes.  This type is sent
+      only between routers as broadcast packet.
+
+      Max Arguments:  2
+          Arguments:  (1) <Client ID>  (2) <mode mask>
+
+      The <Client ID> is the client which mode was changed.  The
+      <mode mask> is the new mode mask.
+
+
+15    SILC_NOTIFY_TYPE_BAN
+
+      Sent when the ban list of the channel is changed.  This notify
+      type is sent to local servers on the channel, but MUST NOT be
+      sent to clients on the channel.  Router MUST broadcast this to
+      its primary router and to local servers on the channel.
+
+      Max Arguments:  3
+          Arguments:  (1) <Channel ID>         (2) [<add | del>]
+                      (3) [<ban list>]
+
+      The <Channel ID> is the channel which ban list was changed.
+      The <add | del> is an argument of size of 1 byte where 0x00 means
+      adding a client to ban list, and 0x01 means deleting a client
+      from ban list.  The <ban list> indicates the information to be
+      added to or removed from the ban list.  The <ban list> format
+      format is defined in [SILC4] with SILC_COMMAND_BAN command.
+      When <add | del> is used  to announce information during server 
+      connecting phase the argument type MUST be 0x03.  See section
+      4.2.1 in [SILC1] for more information.
+
+
+16    SILC_NOTIFY_TYPE_ERROR
+
+      Sent when an error occurs during processing some SILC procedure.
+      This is not used when error occurs during command processing, see
+      [SILC4] for more information about commands and command replies.
+      This type is sent directly to the sender of the packet whose
+      packet caused the error.  See [SILC1] for definition when this
+      type can be sent.
+
+      Max Arguments:  256
+          Arguments:  (1) <Status Type>        (n) [...]
+
+      The <Status Type> is the error type defined in [SILC4].  Note
+      that same types are also used with command replies to indicate
+      the status of a command.  Both commands and this notify type
+      share same status types.  Rest of the arguments are status type
+      dependent and are specified with those status types that can be
+      sent currently inside this notify type in [SILC4].  The <Status
+      Type> is size of 1 byte.
+
+
+17    SILC_NOTIFY_TYPE_WATCH
+
+      Sent to indicate change in a watched user.  Client can set
+      nicknames to be watched with SILC_COMMAND_WATCH command, and
+      receive notifications when they login to network, signoff from
+      the network or their user mode is changed.  This notify type
+      is used to deliver these notifications.  The notify type is
+      sent directly to the watching client.
+
+      Max Arguments:  4
+          Arguments:  (1) <Client ID>        (2) [<nickname>]
+                      (3) <user mode>        (4) [<Notify Type>]
+
+      The <Client ID> is the user's Client ID which is being watched,
+      and the <nickname> is its nickname.  If the client just
+      changed the nickname, then <nickname> is the new nickname, but
+      the <Client ID> is the old client ID.  The <user mode> is the
+      user's current user mode.  The <Notify Type> can be same as the
+      Notify Payload's Notify Type, and is 16 bit MSB first order
+      value.  If provided it may indicate the notify that occurred
+      for the client.  If client logged in to the network the
+      <Notify Type> MUST NOT be present.
+.in 3
+
+Notify types starting from 16384 are reserved for private notify
+message types.
+
+Router server which receives SILC_NOTIFY_TYPE_SIGNOFF,
+SILC_NOTIFY_TYPE_SERVER_SIGNOFF, SILC_NOTIFY_TYPE_KILLED,
+SILC_NOTIFY_TYPE_NICK_CHANGE and SILC_NOTIFY_TYPE_UMODE_CHANGE
+MUST check whether someone in the local cell is watching the nickname
+the client has, and send the SILC_NOTIFY_TYPE_WATCH notify to the
+watcher, unless the watched client in case has the user mode
+SILC_UMODE_REJECT_WATCHING set.  If the watcher client and the client
+that was watched is same the notify SHOULD NOT be sent.
+
+
+
+
+
+.ti 0
+2.3.8 Error Payload
+
+Error payload is sent upon error in protocol.  Error may occur in
+various conditions when server sends this packet.  Client MUST NOT
+send this payload but MUST be able to accept it.  However, client
+MAY ignore the contents of the packet as server is going to take
+action on the error anyway.  However, it is recommended that the
+client takes error packet seriously.
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                         Error Message                         ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 14:  Error Payload
+
+
+.in 6
+o Error Message (variable length) - Human readable error
+  message as UTF-8 string.
+.in 3
+
+
+.ti 0
+2.3.9 Channel Message Payload
+
+Channel Message Payload is used to send message to channels, a group
+of users.  These messages can only be sent if client has joined to
+some channel.  Even though this packet is very common in SILC it
+is still special packet.  Some special handling on sending and
+reception of channel message is required.
+
+Padding MUST be applied into this payload since the payload is
+encrypted separately from other parts of the packet with the
+channel specific key.  Hence the requirement of the padding.
+The packet MUST be made multiple by eight (8) or by the block
+size of the cipher, which ever is larger.
+
+The SILC header in this packet is encrypted with the session key
+of the next receiver of the packet.  Nothing else is encrypted
+with that key.  Thus, the actual packet and padding to be
+encrypted with the session key is SILC Header plus padding to it.
+
+Receiver of the the channel message packet is able to determine
+the channel the message is destined to by checking the Destination
+ID from the SILC Packet header which tells the destination channel.
+The original sender of the packet is also determined by checking
+the source ID from the header which tells the client which sent
+the message.  The Destination ID MUST be Channel ID in the SILC
+Packet header.
+
+This packet use generic Message Payload as Channel Message Payload.
+See section 2.3.2.6 for generic Message Payload.
+
+
+.ti 0
+2.3.10 Channel Key Payload
+
+All traffic in channels are protected by channel specific keys.
+Channel Key Payload is used to distribute channel keys to all
+clients on the particular channel.  Channel keys are sent when
+the channel is created, when new user joins to the channel and
+whenever a user has left a channel.  Server creates the new
+channel key and distributes it to the clients by encrypting this
+payload with the session key shared between the server and
+the client.  After that, client MUST start using the key received
+in this payload to protect the traffic on the channel.
+
+The client which is joining to the channel receives its key in the
+SILC_COMMAND_JOIN command reply message thus it is not necessary to
+send this payload to the entity which sent the SILC_COMMAND_JOIN
+command.
+
+Channel keys are cell specific thus every router in the cell have
+to create a channel key and distribute it if any client in the
+cell has joined to a channel.  Channel traffic between cell's
+are not encrypted using channel keys, they are encrypted using
+normal session keys between two routers.  Inside a cell, all
+channel traffic is encrypted with the specified channel key.
+Channel key SHOULD expire periodically, say, in one hour, in
+which case new channel key is created and distributed.
+
+Note that, this packet is not used if SILC_CMODE_PRIVKEY mode is set
+on channel.  This means that channel uses channel private keys which
+are not server generated.  For this reason server cannot send this
+packet as it does not know the key.
+
+The payload may only be sent with SILC_PACKET_CHANNEL_KEY packet.
+It MUST NOT be sent in any other packet type.  The following diagram
+represents the Channel Key Payload.
+
+
+
+
+
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Channel ID Length       |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                          Channel ID                           ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|      Cipher Name Length       |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                         Cipher Name                           ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|      Channel Key Length       |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                         Channel Key                           ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 15:  Channel Key Payload
+
+
+
+.in 6
+o Channel ID Length (2 bytes) - Indicates the length of the
+  Channel ID field in the payload, not including any other
+  field.
+
+o Channel ID (variable length) - The Channel ID of the
+  channel.
+
+o Cipher Name Length (2 bytes) - Indicates the length of the
+  Cipher name field in the payload, not including any other
+  field.
+
+o Cipher Name (variable length) - Name of the cipher used
+  in the protection of channel traffic.  This name is
+  initially decided by the creator of the channel but it
+  may change during the life time of the channel as well.
+
+o Channel Key Length (2 bytes) - Indicates the length of the
+  Channel Key field in the payload, not including any other
+  field.
+
+o Channel Key (variable length) - The actual channel key
+  material.
+.in 3
+
+
+.ti 0
+2.3.11 Private Message Payload
+
+Private Message Payload is used to send private message between
+two clients.  The messages are sent only to the specified user
+and no other user inside SILC network is able to see the message.
+
+The message can be protected by the session key established by the
+SILC Key Exchange Protocol.  However, it is also possible to agree
+to use a private key to protect just the private messages.  It is
+for example possible to perform Key Agreement between two clients.
+See section 2.3.20 Key Agreement Payload how to perform key
+agreement.  See also section 2.3.12 Private Message Key Payload
+for another way of using private keys with private messages.  See
+[SILC1] section 4.6 for detailed description for private message
+key generation procedure.
+
+If normal session key is used to protect the message, every server
+between the sender client and the receiving client MUST decrypt the
+packet and always re-encrypt it with the session key of the next
+receiver of the packet.  See section Client To Client in [SILC1].
+
+When the private message key is used, and the Private Message Key
+flag was set in the SILC Packet header no server or router en route
+is able to decrypt or re-encrypt the packet.  In this case only the
+SILC Packet header is processed by the servers and routers en route.
+Section Client To Client in [SILC1] gives example of this scheme.
+
+This packet use generic Message Payload as Private Message Payload.
+See section 2.3.2.6 for generic Message Payload.
+
+
+.ti 0
+2.3.12 Private Message Key Payload
+
+This payload is OPTIONAL and can be used to send private message
+key between two clients in the network.  The packet is secured with
+normal session keys.  By default private messages are encrypted
+with session keys, and with this payload it is possible to set
+private key for private message encryption between two clients.
+
+The receiver of this payload SHOULD verify for example from user
+whether user want to receive private message key.  Note that there
+are other, more secure ways of exchanging private message keys in
+the SILC network.  Instead of sending this payload it is possible to
+negotiate the private message key with SKE protocol using the Key
+Agreement payload directly peer to peer, see section 2.3.20.
+
+This payload may only be sent by client to another client.  Server
+MUST NOT send this payload.  After sending this payload the sender of
+private messages must set the Private Message Key flag into SILC Packet
+Header.
+
+The payload may only be sent with SILC_PACKET_PRIVATE_MESSAGE_KEY
+packet.  It MUST NOT be sent in any other packet type.  The following
+diagram represents the Private Message Key Payload.
+
+
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|  Private Message Key Length   |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                      Private Message Key                      ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|      Cipher Name Length       |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                          Cipher Name                          ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       HMAC Name Length        |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                           HMAC Name                           ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 16:  Private Message Key Payload
+
+
+
+.in 6
+o Private Message Key Length (2 bytes) - Indicates the length
+  of the Private Message Key field in the payload, not including
+  any other field.
+
+o Private Message Key (variable length) - The actual private
+  message key material.
+
+o Cipher Name Length (2 bytes) - Indicates the length of the
+  Cipher Name field in the payload, not including any other
+  field.
+
+o Cipher Name (variable length) - Name of the cipher to use
+  in the private message encryption.  If this field does not
+  exist then the default cipher of the SILC protocol is used.
+  See the [SILC1] for defined ciphers.
+
+o HMAC Name Length (2 bytes) - Indicates the length of the
+  HMAC Name field in the payload, not including any other
+  field.
+
+o HMAC Name (variable length) - Name of the HMAC to use
+  in the private message MAC computation.  If this field does
+  not exist then the default HMAC of the SILC protocol is used.
+  See the [SILC1] for defined HMACs.
+.in 3
+
+
+.ti 0
+2.3.13 Command Payload
+
+Command Payload is used to send SILC commands from client to server.
+Also server MAY send commands to other servers.  The following diagram
+represents the Command Payload.
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|         Payload Length        | SILC Command  | Arguments Num |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Command Identifier      |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 17:  Command Payload
+
+
+.in 6
+o Payload Length (2 bytes) - Length of the entire command
+  payload including any command argument payloads associated
+  with this payload.
+
+o SILC Command (1 byte) - Indicates the SILC command.  This MUST
+  be set to non-zero value.  If zero (0) value is found in this
+  field the packet MUST be discarded.
+
+o Arguments Num (1 byte) - Indicates the number of arguments
+  associated with the command.  If there are no arguments this
+  field is set to zero (0).  The arguments MUST follow the
+  Command Payload.  See section 2.3.2.2 for definition of the
+  Argument Payload.
+
+o Command Identifier (2 bytes) - Identifies this command at the
+  sender's end.  The entity which replies to this command MUST
+  set the value found from this field into the Command Payload
+  used to send the reply to the sender.  This way the sender
+  can identify which command reply belongs to which originally
+  sent command.  What this field includes is implementation
+  issue but it is RECOMMENDED that wrapping counter value is
+  used in the field.
+.in 3
+
+See [SILC4] for detailed description of different SILC commands,
+their arguments and their reply messages.
+
+
+.ti 0
+2.3.14 Command Reply Payload
+
+Command Reply Payload is used to send replies to the commands.  The
+Command Reply Payload is identical to the Command Payload thus see
+the 2.3.13 section for the payload specification.
+
+The entity which sends the reply packet MUST set the Command Identifier
+field in the reply packet's Command Payload to the value it received
+in the original command packet.
+
+See SILC Commands in [SILC4] for detailed description of different
+SILC commands, their arguments and their reply messages.
+
+
+.ti 0
+2.3.15 Connection Auth Request Payload
+
+Client MAY send this payload to server to request the authentication
+method that must be used in authentication protocol.  If client knows
+this information beforehand this payload is not necessary to be sent.
+Server performing authentication with another server MAY also send
+this payload to request the authentication method.  If the connecting
+server already knows this information this payload is not necessary
+to be sent.
+
+Server receiving this request SHOULD reply with same payload sending
+the mandatory authentication method.  Algorithms that may be required
+to be used by the authentication method are the ones already
+established by the SILC Key Exchange protocol.  See section Key
+Exchange Start Payload in [SILC3] for detailed information.
+
+The payload may only be sent with SILC_PACKET_CONNECTION_AUTH_REQUEST
+packet.  It MUST NOT be sent in any other packet type.  The following
+diagram represents the Connection Auth Request Payload.
+
+
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Connection Type        |     Authentication Method     |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 18:  Connection Auth Request Payload
+
+
+.in 6
+o Connection Type (2 bytes) - Indicates the type of the
+  connection.  The following connection types are defined:
+
+
+     1    Client connection
+     2    Server connection
+     3    Router connection
+
+  If any other type is found in this field the packet MUST be
+  discarded and the authentication MUST be failed.
+
+o Authentication Method (2 bytes) - Indicates the authentication
+  method to be used in the authentication protocol.  The following
+  authentication methods are defined:
+
+     0    NONE        (mandatory)
+     1    password    (mandatory)
+     2    public key  (mandatory)
+
+  If any other type is found in this field the packet MUST be
+  discarded and the authentication MUST be failed.  If this
+  payload is sent as request to receive the mandatory
+  authentication method this field MUST be set to zero (0),
+  indicating that receiver should send the mandatory
+  authentication method.  The receiver sending this payload
+  to the requesting party, MAY also set this field to zero (0)
+  to indicate that authentication is not required.  In this
+  case authentication protocol still MUST be started but
+  server is most likely to respond with SILC_PACKET_SUCCESS
+  immediately.
+.in 3
+
+
+.ti 0
+2.3.16 New ID Payload
+
+New ID Payload is a multipurpose payload.  It is used to send newly
+created ID's from clients and servers.  When client connects to server
+and registers itself to the server by sending SILC_PACKET_NEW_CLIENT
+packet, server replies with this packet by sending the created ID for
+the client.  Server always creates the ID for the client.
+
+This payload is also used when server tells its router that new client
+has registered to the SILC network.  In this case the server sends
+the Client ID of the client to the router.  Similarly when router
+distributes information to other routers about the client in the SILC
+network this payload is used.
+
+Also, when server connects to router, router use this payload to inform
+other routers about new server in the SILC network.  However, every
+server (or router) creates their own ID's thus the ID distributed by
+this payload is not created by the distributor in this case.  Servers
+create their own ID's.  Server registers itself to the network by
+sending SILC_PACKET_NEW_SERVER to the router it connected to.  The case
+is same when router connects to another router.
+
+This payload MUST NOT be used to send information about new channels.
+New channels are always distributed by sending the dedicated
+SILC_PACKET_NEW_CHANNEL packet.  Client MUST NOT send this payload.
+Both client and server (and router) MAY receive this payload.
+
+The packet use generic ID Payload as New ID Payload.  See section
+2.3.2.1 for generic ID Payload.
+
+
+.ti 0
+2.3.17 New Client Payload
+
+When client is connected to the server, keys has been exchanged and
+connection has been authenticated, client MUST register itself to the
+server.  Client's first packet after key exchange and authentication
+protocols MUST be SILC_PACKET_NEW_CLIENT.  This payload tells server all
+the relevant information about the connected user.  Server creates a new
+client ID for the client when received this payload and sends it to the
+client in New ID Payload.
+
+This payload sends username and real name of the user on the remote host
+which is connected to the SILC server with SILC client.  The server
+creates the client ID according the information sent in this payload.
+The nickname of the user becomes the nickname sent in this payload.
+
+The payload may only be sent with SILC_PACKET_NEW_CLIENT packet.  It
+MUST NOT be sent in any other packet type.  The following diagram
+represents the New Client Payload.
+
+
+
+
+
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Username Length        |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                           Username                            ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Real Name Length        |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                           Real Name                           ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 19:  New Client Payload
+
+
+.in 6
+o Username Length (2 bytes) - Length of the Username field.
+
+o Username (variable length) - The username of the user on
+  the host where connecting to the SILC server.
+
+o Real Name Length (2 bytes) - Length of the Real Name field.
+
+o Real Name (variable length) - The real name of the user
+  on the host where connecting to the SILC server.
+.in 3
+
+
+.ti 0
+2.3.18 New Server Payload
+
+This payload is sent by server when it has completed successfully both
+key exchange and connection authentication protocols.  The server
+MUST register itself to the SILC Network by sending this payload.
+The first packet after these key exchange and authentication protocols
+is SILC_PACKET_NEW_SERVER packet.  The payload includes the Server ID
+of the server that it has created by itself.  It also includes a
+name of the server that is associated to the Server ID.
+
+The payload may only be sent with SILC_PACKET_NEW_SERVER packet.  It
+MUST NOT be sent in any other packet type.  The following diagram
+represents the New Server Payload.
+
+
+
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Server ID Length        |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                        Server ID Data                         ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|     Server Name Length        |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                          Server Name                          ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 20:  New Server Payload
+
+
+.in 6
+o Server ID Length (2 bytes) - Length of the Server ID Data
+  field.
+
+o Server ID Data (variable length) - The encoded Server ID
+  data.
+
+o Server Name Length (2 bytes) - Length of the server name
+  field.
+
+o Server Name (variable length) - The server name string.
+.in 3
+
+
+.ti 0
+2.3.19 New Channel Payload
+
+Information about newly created channel is broadcasted to all routers
+in the SILC network by sending this packet payload.  Channels are
+created by router of the cell.  Server never creates channels unless
+it is a standalone server and it does not have router connection,
+in this case server acts as router.  Normal server send JOIN command
+to the router (after it has received JOIN command from client) which
+then processes the command and creates the channel.  Client MUST NOT
+send this packet.  Server MAY send this packet to a router when it is
+announcing its existing channels to the router after it has connected
+to the router.
+
+The packet use generic Channel Payload as New Channel Payload.  See
+section 2.3.2.3 for generic Channel Payload.  The Mode Mask field in the
+Channel Payload is the mode of the channel.
+
+
+.ti 0
+2.3.20 Key Agreement Payload
+
+This payload is used by clients to request key negotiation between
+another client in the SILC Network.  The key agreement protocol used
+is the SKE protocol.  The result of the protocol, the secret key
+material, can be used for example as private message key between the
+two clients.  This significantly adds security as the clients agree
+about the key without any server interaction.  The protocol is executed
+peer to peer.  The server and router MUST NOT send this payload.
+
+The sender MAY tell the receiver of this payload the hostname and the
+port where the SKE protocol is running in the sender's end.  The
+receiver MAY then initiate the SKE negotiation with the sender.  The
+sender MAY also optionally not to include the hostname and the port
+of its SKE protocol.  In this case the receiver MAY reply to the
+request by sending the same payload filled with the receiver's hostname
+and the port where the SKE protocol is running.  The sender MAY then
+initiate the SKE negotiation with the receiver.
+
+This payload may be sent with SILC_PACKET_KEY_AGREEMENT and
+SILC_PACKET_FTP packet types.  It MUST NOT be sent in any other packet
+types.  The following diagram represents the Key Agreement Payload.
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Hostname Length        |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                           Hostname                            ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                             Port                              |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 21:  Key Agreement Payload
+
+
+.in 6
+o Hostname Length (2 bytes) - Indicates the length of the
+  Hostname field.
+
+o Hostname (variable length) - The hostname or IP address where
+  the SKE protocol is running.  The sender MAY fill this field
+  when sending the payload.  If the receiver sends this payload
+  as reply to the request it MUST fill this field.
+
+o Port (4 bytes) - The port where the SKE protocol is bound.
+  The sender MAY fill this field when sending the payload.  If
+  the receiver sends this payload as reply to the request it
+  MUST fill this field.  This is a 32 bit MSB first order value.
+.in 3
+
+
+After the key material has been received from the SKE protocol it is
+processed as the [SILC3] describes.  If the key material is used as
+channel private key then the Sending Encryption Key, as defined in
+[SILC3] is used as the channel private key.  Other key material must
+be discarded.  The [SILC1] in section 4.6 defines the way to use the
+key material if it is intended to be used as private message keys.
+Any other use for the key material is undefined.
+
+
+.ti 0
+2.3.21 Resume Router Payload
+
+See the [SILC1] for Resume Router protocol where this payload is
+used.  The payload may only be sent with SILC_PACKET_RESUME_ROUTER
+packet.  It MUST NOT be sent in any other packet type.  The following
+diagram represents the Resume Router Payload.
+
+
+.in 21
+.nf
+                     1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|      Type     |  Session ID   |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 22:  Resume Router Payload
+
+
+.in 6
+o Type (1 byte) - Indicates the type of the backup resume
+  protocol packet.  The type values are defined in [SILC1].
+
+o Session ID (1 bytes) - Indicates the session ID for the
+  backup resume protocol.  The sender of the packet sets this
+  value and the receiver MUST set the same value in subsequent
+  reply packet.
+.in 3
+
+
+.ti 0
+2.3.22 File Transfer Payload
+
+File Transfer Payload is used to perform file transfer protocol between
+two entities in the network.  The actual file transfer protocol is always
+encapsulated inside the SILC Packet.  The actual data stream is also sent
+peer to peer outside SILC network.
+
+When an entity, usually a client wishes to perform file transfer protocol
+with another client in the network, they perform Key Agreement protocol
+as described in the section 2.3.20 Key Agreement Payload and in [SILC3],
+inside File Transfer Payload.  After the Key Agreement protocol has been
+performed the subsequent packets in the data stream will be protected
+using the new key material.  The actual file transfer protocol is also
+initialized in this stage.  All file transfer protocol packets are always
+encapsulated in the File Transfer Payload and protected with the
+negotiated key material.
+
+The payload may only be sent with SILC_PACKET_FTP packet.  It MUST NOT
+be sent in any other packet type.  The following diagram represents the
+File Transfer Payload.
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|     Type      |                                               |
++-+-+-+-+-+-+-+-+                                               +
+|                                                               |
+~                             Data                              ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 23:  File Transfer Payload
+
+
+.in 6
+o Type (1 byte) - Indicates the type of the file transfer
+  protocol.  The following file transfer protocols has been
+  defined:
+
+    1    Secure File Transfer Protocol (SFTP)  (mandatory)
+
+  If zero (0) value or any unsupported file transfer protocol
+  type is found in this field the packet MUST be discarded.
+  The currently mandatory file transfer protocol is SFTP.
+  The SFTP protocol is defined in [SFTP].
+
+o Data (variable length) - Arbitrary file transfer data.  The
+  contents and encoding of this field is dependent of the usage
+  of this payload and the type of the file transfer protocol.
+  When this payload is used to perform the Key Agreement
+  protocol, this field include the Key Agreement Payload,
+  as defined in the section 2.3.20 Key Agreement Payload.
+  When this payload is used to send the actual file transfer
+  protocol data, the encoding is defined in the corresponding
+  file transfer protocol.
+.in 3
+
+
+.ti 0
+2.3.23 Resume Client Payload
+
+This payload is used by client to resume its detached session in the
+SILC Network.  A client is able to detach itself from the network by
+sending SILC_COMMAND_DETACH command to its server.  The network
+connection to the client is lost but the client remains as valid
+client in the network.  The client is able to resume the session back
+by sending this packet and including the old Client ID, and an
+Authentication Payload [SILC1] which the server use to verify with
+the detached client's public key.  This also implies that the
+mandatory authentication method is public key authentication.
+
+Server or router that receives this from the client also sends this,
+without the Authentication Payload, to routers in the network so that
+they know the detached client has resumed.  Refer to the [SILC1] for
+detailed description how the detaching and resuming procedure is
+performed.
+
+The payload may only be sent with SILC_PACKET_RESUME CLIENT packet.  It
+MUST NOT be sent in any other packet type.  The following diagram
+represents the Resume Client Payload.
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Client ID Length        |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                           Client ID                           ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                     Authentication Payload                    ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 24:  Resume Client Payload
+
+
+.in 6
+o Client ID Length (1 byte) - The length of the Client ID
+  field not including any other field.
+
+o Client ID (variable length) - The detached client's Client
+  ID.  The client that sends this payload must know the Client
+  ID.
+
+o Authentication Payload (variable length) - The authentication
+  payload that the server will verify with the detached client's
+  public key.  If the server doesn't know the public key, it must
+  retrieve it for example with SILC_COMMAND_GETKEY command.
+.in 3
+
+
+
+.ti 0
+2.4 SILC ID Types
+
+ID's are used in the SILC network to associate different entities.
+The following ID's has been defined to be used in the SILC network.
+
+.in 6
+0    No ID
+
+     This is used when other ID type is available at the time.
+
+1    Server ID
+
+     Server ID to associate servers.  See the format of
+     this ID in [SILC1].
+
+2    Client ID
+
+     Client ID to associate clients.  See the format of
+     this ID in [SILC1].
+
+3    Channel ID
+
+     Channel ID to associate channels.  See the format of
+     this ID in [SILC1].
+.in 3
+
+When encoding different IDs into the ID Payload, all fields are always
+in MSB first order.  The IP address, port, and/or the random number
+are encoded in the MSB first order.
+
+
+.ti 0
+2.5 Packet Encryption And Decryption
+
+SILC packets are encrypted almost entirely.  Only the MAC at the end
+of the packet is never encrypted.  The SILC Packet header is the first
+part of a packet to be encrypted and it is always encrypted with the
+key of the next receiver of the packet.  The data payload area of the
+packet is always entirely encrypted and it is usually encrypted with
+the next receiver's key.  However, there are some special packet types
+and packet payloads that require special encryption process.  These
+special cases are described in the next sections.  First is described
+the normal packet encryption process.
+
+
+
+.ti 0
+2.5.1 Normal Packet Encryption And Decryption
+
+Normal SILC packets are encrypted with the session key of the next
+receiver of the packet.  The entire SILC Packet header and the packet
+data payload is is encrypted with the same key.  Padding of the packet
+is also encrypted always with the session key, also in special cases.
+Computed MAC of the packet MUST NOT be encrypted.
+
+Decryption process in these cases are straightforward.  The receiver
+of the packet MUST first decrypt the SILC Packet header, or some parts
+of it, usually first 16 bytes of it.  Then the receiver checks the
+packet type from the decrypted part of the header and can determine
+how the rest of the packet must be decrypted.  If the packet type is
+any of the special cases described in the following sections the packet
+decryption is special.  If the packet type is not among those special
+packet types rest of the packet can be decrypted with the same key.
+At this point the receiver is also able to determine the length of the
+packet.
+
+With out a doubt, this sort of decryption processing causes some
+overhead to packet decryption, but never the less, is required.
+
+The MAC of the packet is also verified at this point.  The MAC is
+computed from the ciphertext of the packet so it can be verified
+at this stage.  The length of the packet need to be known to be able
+to verify the MAC from the ciphertext so the first 16 bytes need to
+be decrypted to determine the packet length.  However, the MAC MUST
+be verified from the entire ciphertext.
+
+
+.ti 0
+2.5.2 Channel Message Encryption And Decryption
+
+Channel Messages (Channel Message Payload) are always encrypted with
+the channel specific key.  However, the SILC Packet header is not
+encrypted with that key.  As in normal case, the header is encrypted
+with the key of the next receiver of the packet.  Note that, in this
+case the encrypted data area is not touched at all; it MUST NOT be
+re-encrypted with the session key.
+
+Receiver of a channel message, who ever that is, is REQUIRED to decrypt
+the SILC Packet header to be able to recognize the packet to be as
+channel message.  This is same procedure as for normal SILC packets.
+As the receiver founds the packet to be channel message, rest of the
+packet processing is special.  Rest of the SILC Packet header is
+decrypted with the same session key along with the padding of the
+packet.  After that the packet is protected with the channel specific
+key and thus can be decrypted only if the receiver is the client on
+the channel.  See section 2.7 Packet Padding Generation for more
+information about padding on special packets.
+
+If the receiver of the channel message is router which is routing the
+message to another router then it MUST decrypt the Channel Message
+payload too.  Between routers (that is, between cells) channel messages
+are protected with session keys shared between the routers.  This
+causes another special packet processing for channel messages.  If
+the channel message is received from another router then the entire
+packet, including Channel Message payload, MUST be encrypted with the
+session key shared between the routers.  In this case the packet
+decryption process is as with normal SILC packets.  Hence, if the
+router is sending channel message to another router the Channel
+Message payload MUST have been decrypted and MUST be re-encrypted
+with the session key shared between the another router.  In this
+case the packet encryption is as with any normal SILC packet.
+
+It must be noted that this is only when the channel messages are sent
+from router to another router.  In all other cases the channel
+message encryption and decryption is as described before.  This
+different processing of channel messages with router to router
+connection is because channel keys are cell specific.  All cells have
+their own channel keys thus the channel message traveling from one
+cell to another MUST be protected as it would be any normal SILC
+packet.
+
+If the SILC_CMODE_PRIVKEY channel mode has been set for the channel
+then the router cannot decrypt the packet as it does not know the
+private key.  In this case the entire packet MUST be encrypted with
+the session key and sent to the router.  The router receiving the
+packet MUST check the channel mode and decrypt the packet accordingly.
+
+
+.ti 0
+2.5.3 Private Message Encryption And Decryption
+
+By default, private message in SILC are protected by session keys.
+In this case the private message encryption and decryption process is
+equivalent to normal packet encryption and decryption.
+
+However, private messages MAY be protected with private message key
+which causes the packet to be special packet.  The procedure in this
+case is very much alike to channel packets.  The actual private message
+is encrypted with the private message key and other parts of the
+packet is encrypted with the session key.  See 2.7 Packet Padding
+Generation for more information about padding on special packets.
+
+The difference from channel message processing is that server or router
+en route never decrypts the actual private message, as it does not
+have the key to do that.  Thus, when sending packets between router
+the processing is same as in any other case as well; the packet's header
+and padding is protected by the session key and the data area is not
+touched and is not re-encrypted.
+
+The true receiver of the private message is able to decrypt the private
+message as it shares the key with the sender of the message.
+
+
+.ti 0
+2.6 Packet MAC Generation
+
+Data integrity of a packet is protected by including a message
+authentication code (MAC) at the end of the packet.  The MAC is computed
+from shared secret MAC key, that is established by the SILC Key Exchange
+protocol, from packet sequence number, and from the encrypted packet
+data.  The MAC is always computed after packet is encrypted.  This is
+so called Encrypt-Then-MAC order; packet is first encrypted, then MAC
+is computed from the encrypted data.
+
+The MAC is computed from entire packet.  Every bit of data in the packet,
+including SILC Packet Header is used in the MAC computing.  This way
+the entire packet becomes authenticated.
+
+Hence, packet's MAC generation is as follows:
+
+  mac = MAC(key, sequence number | Encrypted SILC packet)
+
+The MAC key is negotiated during the SKE protocol.  The sequence number
+is a 32 bit MSB first value starting from zero for first packet and
+increasing for subsequent packets, finally wrapping after 2^32 packets.
+The value is never reset, not even after rekey has been performed.
+However, rekey MUST be performed before the sequence number wraps
+and repeats from zero.  Note that the sequence number is incremented only
+when MAC is computed for a packet.  If packet is not encrypted and MAC is
+not computed then the sequence number is not incremented.  Hence, the
+sequence number is zero for the very first encrypted packet.
+
+See [SILC1] for defined and allowed MAC algorithms.
+
+
+.ti 0
+2.7 Packet Padding Generation
+
+Padding is needed in the packet because the packet is encrypted.  It
+always MUST be multiple by eight (8) or multiple by the block size
+of the cipher, which ever is larger.  The padding is always encrypted.
+
+For normal packets the padding is added after the SILC Packet Header
+and between the Data Payload area.  The padding for normal packets
+may be calculated as follows:
+
+.in 6
+padding_length = 16 - (packet_length mod block_size)
+if (padding_length < 8)
+  padding_length += block_size
+.in 3
+
+The `block_size' is the block size of the cipher.  The maximum padding
+length is 128 bytes, and minimum is 8 bytes.  For example, packets that
+include a passphrase or a password for authentication purposes SHOULD
+pad the packet up to the maximum padding length.  The maximum padding
+is calculated as follows:
+
+.in 6
+padding_length = 128 - (packet_length mod block_size)
+.in 3
+
+For special packets the padding calculation is different as special
+packets may be encrypted differently.  In these cases the encrypted
+data area MUST already be multiple by the block size thus in this case
+the padding is calculated only for SILC Packet Header, not for any
+other area of the packet.  The same algorithm works in this case as
+well, except that the `packet length' is now the SILC Packet Header
+length.
+
+The padding MUST be random data, preferably, generated by
+cryptographically strong random number generator for each packet
+separately.
+
+
+.ti 0
+2.8 Packet Compression
+
+SILC Packets MAY be compressed.  In this case the data payload area
+is compressed and all other areas of the packet MUST remain as they
+are.  After compression is performed for the data area, the length
+field of Packet Header MUST be set to the compressed length of the
+data.
+
+The compression MUST always be applied before encryption.  When
+the packet is received and decrypted the data area MUST be decompressed.
+Note that the true sender of the packet MUST apply the compression and
+the true receiver of the packet MUST apply the decompression.  Any
+server or router en route SHOULD NOT decompress the packet.
+
+
+.ti 0
+2.9 Packet Sending
+
+The sender of the packet MUST assemble the SILC Packet Header with
+correct values.  It MUST set the Source ID of the header as its own
+ID, unless it is forwarding the packet.  It MUST also set the Destination
+ID of the header to the true destination.  If the destination is client
+it will be Client ID, if it is server it will be Server ID and if it is
+channel it will be Channel ID.
+
+If the sender wants to compress the packet it MUST apply the
+compression now.  Sender MUST also compute the padding as described
+in above sections.  Then sender MUST encrypt the packet as has been
+described in above sections according whether the packet is normal
+packet or special packet.  Then sender MUST compute the MAC of the
+packet.  The computed MAC MUST NOT be encrypted.
+
+
+.ti 0
+2.10 Packet Reception
+
+On packet reception the receiver MUST check that all fields in the
+SILC Packet Header are valid.  It MUST check the flags of the
+header and act accordingly.  It MUST also check the MAC of the packet
+and if it is to be failed the packet MUST be discarded.  Also if the
+header of the packet includes any bad fields the packet MUST be
+discarded.
+
+See above sections on the decryption process of the received packet.
+
+The receiver MUST also check that the ID's in the header are valid
+ID's.  Unsupported ID types or malformed ID's MUST cause packet
+rejection.  The padding on the reception is always ignored.
+
+The receiver MUST also check the packet type and start parsing the
+packet according to the type.  However, note the above sections on
+special packet types and their parsing.
+
+
+.ti 0
+2.11 Packet Routing
+
+Routers are the primary entities in the SILC network that takes care
+of packet routing.  However, normal servers routes packets as well, for
+example, when they are routing channel message to the local clients.
+Routing is quite simple as every packet tells the true origin and the
+true destination of the packet.
+
+It is still RECOMMENDED for routers that has several routing connections
+to create route cache for those destinations that has faster route than
+the router's primary route.  This information is available for the router
+when other router connects to the router.  The connecting party then
+sends all of its locally connected clients, servers and channels.  These
+informations helps to create the route cache.  Also, when new channels
+are created to a cell its information is broadcasted to all routers
+in the network.  Channel ID's are based on router's ID thus it is easy
+to create route cache based on these informations.  If faster route for
+destination does not exist in router's route cache the packet MUST be
+routed to the primary route (default route).
+
+However, there are some issues when routing channel messages to group
+of users.  Routers are responsible of routing the channel message to
+other routers, local servers and local clients as well.  Routers MUST
+send the channel message to only one router in the network, preferably
+to the shortest route to reach the channel users.  The message can be
+routed into either upstream or downstream.  After the message is sent
+to a router in the network it MUST NOT be sent to any other router in
+either same route or other route.  The message MUST NOT be routed to
+the router it came from.
+
+When routing for example private messages they should be routed to the
+shortest route always to reach the destination client as fast as possible.
+
+For server which receives a packet to be routed to an entity that is
+indirectly connected to the sender, the server MUST check whether that
+particular packet type is allowed to be routed to that destination.  Not
+all packets may be sent by some odd entity to for example a local client,
+or to some remote server or router, that is indirectly connected to the
+sender.  See section 2.3 SILC Packet Types and paragraph about indirectly
+connected entities and sending packets to them.  That section defines the
+packets that may be sent to indirectly connected entities.  When a server
+or a router receives a packet that may be sent to indirectly connected
+entity and it is destined to other entity except that server, it MUST
+route it further either to shortest route or to the primary route to reach
+that destination.
+
+Routers form a ring in the SILC network.  However, routers may have other
+direct connections to other routers in the network too.  This can cause
+interesting routing problems in the network.  Since the network is a ring,
+the packets usually should be routed into clock-wise direction, or if it
+cannot be used then always counter clock-wise (primary route) direction.
+Problems may arise when a faster direct route exists and router is routing
+a channel message.  Currently channel messages must be routed either
+in upstream or downstream, they cannot be routed to other direct routes.
+The SILC protocol should have a shortest path discovery protocol, and some
+existing routing protocol, that can handle a ring network with other
+direct routes inside the ring (so called hybrid ring-mesh topology),
+MAY be defined to be used with the SILC protocol.  Additional
+specifications MAY be written on the subject to permeate this
+specification.
+
+
+.ti 0
+2.12 Packet Broadcasting
+
+SILC packets MAY be broadcasted in SILC network.  However, only router
+server may send or receive broadcast packets.  Client and normal server
+MUST NOT send broadcast packets and they MUST ignore broadcast packets
+if they receive them.  Broadcast packets are sent by setting Broadcast
+flag to the SILC packet header.
+
+Broadcasting packets means that the packet is sent to all routers in
+the SILC network, except to the router that sent the packet.  The router
+receiving broadcast packet MUST send the packet to its primary route.
+The fact that SILC routers may have several router connections can
+cause problems, such as race conditions inside the SILC network, if
+care is not taken when broadcasting packets.  Router MUST NOT send
+the broadcast packet to any other route except to its primary route.
+
+If the primary route of the router is the original sender of the packet
+the packet MUST NOT be sent to the primary route.  This may happen
+if router has several router connections and some other router uses
+the router as its primary route.
+
+Routers use broadcast packets to broadcast for example information
+about newly registered clients, servers, channels etc. so that all the
+routers may keep these informations up to date.
+
+
+.ti 0
+3 Security Considerations
+
+Security is central to the design of this protocol, and these security
+considerations permeate the specification.  Common security considerations
+such as keeping private keys truly private and using adequate lengths for
+symmetric and asymmetric keys must be followed in order to maintain the
+security of this protocol.
+
+
+.ti 0
+4 References
+
+[SILC1]      Riikonen, P., "Secure Internet Live Conferencing (SILC),
+             Protocol Specification", Internet Draft, May 2002.
+
+[SILC3]      Riikonen, P., "SILC Key Exchange and Authentication
+             Protocols", Internet Draft, May 2002.
+
+[SILC4]      Riikonen, P., "SILC Commands", Internet Draft, May 2002.
+
+[IRC]        Oikarinen, J., and Reed D., "Internet Relay Chat Protocol",
+             RFC 1459, May 1993.
+
+[IRC-ARCH]   Kalt, C., "Internet Relay Chat: Architecture", RFC 2810,
+             April 2000.
+
+[IRC-CHAN]   Kalt, C., "Internet Relay Chat: Channel Management", RFC
+             2811, April 2000.
+
+[IRC-CLIENT] Kalt, C., "Internet Relay Chat: Client Protocol", RFC
+             2812, April 2000.
+
+[IRC-SERVER] Kalt, C., "Internet Relay Chat: Server Protocol", RFC
+             2813, April 2000.
+
+[SSH-TRANS]  Ylonen, T., et al, "SSH Transport Layer Protocol",
+             Internet Draft.
+
+[PGP]        Callas, J., et al, "OpenPGP Message Format", RFC 2440,
+             November 1998.
+
+[SPKI]       Ellison C., et al, "SPKI Certificate Theory", RFC 2693,
+             September 1999.
+
+[PKIX-Part1] Housley, R., et al, "Internet X.509 Public Key
+             Infrastructure, Certificate and CRL Profile", RFC 2459,
+             January 1999.
+
+[Schneier]   Schneier, B., "Applied Cryptography Second Edition",
+             John Wiley & Sons, New York, NY, 1996.
+
+[Menezes]    Menezes, A., et al, "Handbook of Applied Cryptography",
+             CRC Press 1997.
+
+[OAKLEY]     Orman, H., "The OAKLEY Key Determination Protocol",
+             RFC 2412, November 1998.
+
+[ISAKMP]     Maughan D., et al, "Internet Security Association and
+             Key Management Protocol (ISAKMP)", RFC 2408, November
+             1998.
+
+[IKE]        Harkins D., and Carrel D., "The Internet Key Exchange
+             (IKE)", RFC 2409, November 1998.
+
+[HMAC]       Krawczyk, H., "HMAC: Keyed-Hashing for Message
+             Authentication", RFC 2104, February 1997.
+
+[PKCS1]      Kalinski, B., and Staddon, J., "PKCS #1 RSA Cryptography
+             Specifications, Version 2.0", RFC 2437, October 1998.
+
+[RFC2119]    Bradner, S., "Key Words for use in RFCs to Indicate
+             Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+[SFTP]       Ylonen T., and Lehtinen S., "Secure Shell File Transfer
+             Protocol", Internet Draft, March 2001.
+
+[RFC2279]    Yergeau, F., "UTF-8, a transformation format of ISO
+             10646", RFC 2279, January 1998.
+
+
+.ti 0
+5 Author's Address
+
+.nf
+Pekka Riikonen
+Snellmaninkatu 34 A 15
+70100 Kuopio
+Finland
+
+EMail: priikone@iki.fi
+
+
+.ti 0
+6 Full Copyright Statement
+
+Copyright (C) The Internet Society (2003). All Rights Reserved.
+
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
index 077cda32a0fee7f9fd1980145084896cff9eeb47..6dcbc302cdca1b116e3d7313a3e4df275453f35c 100644 (file)
@@ -8,7 +8,7 @@
 .ds RF FORMFEED[Page %]
 .ds CF
 .ds LH Internet Draft
-.ds RH XXX
+.ds RH 29 July 2003
 .ds CH
 .na
 .hy 0
@@ -16,8 +16,8 @@
 .nf
 Network Working Group                                        P. Riikonen
 Internet-Draft
-draft-riikonen-silc-spec-06.txt                         XXX
-Expires: XXX
+draft-riikonen-silc-spec-07.txt                             29 July 2003
+Expires: 29 January 2004
 
 .in 3
 
@@ -29,24 +29,24 @@ Protocol Specification
 .ti 0
 Status of this Memo
 
-This document is an Internet-Draft and is in full conformance with   
-all provisions of Section 10 of RFC 2026.  Internet-Drafts are   
-working documents of the Internet Engineering Task Force (IETF), its   
-areas, and its working groups.  Note that other groups may also   
-distribute working documents as Internet-Drafts.   
+This document is an Internet-Draft and is in full conformance with
+all provisions of Section 10 of RFC 2026.  Internet-Drafts are
+working documents of the Internet Engineering Task Force (IETF), its
+areas, and its working groups.  Note that other groups may also
+distribute working documents as Internet-Drafts.
 
-Internet-Drafts are draft documents valid for a maximum of six months   
-and may be updated, replaced, or obsoleted by other documents at any   
-time.  It is inappropriate to use Internet-Drafts as reference   
-material or to cite them other than as "work in progress."   
+Internet-Drafts are draft documents valid for a maximum of six months
+and may be updated, replaced, or obsoleted by other documents at any
+time.  It is inappropriate to use Internet-Drafts as reference
+material or to cite them other than as "work in progress."
 
-The list of current Internet-Drafts can be accessed at   
-http://www.ietf.org/ietf/1id-abstracts.txt   
+The list of current Internet-Drafts can be accessed at
+http://www.ietf.org/ietf/1id-abstracts.txt
 
-The list of Internet-Draft Shadow Directories can be accessed at   
-http://www.ietf.org/shadow.html   
+The list of Internet-Draft Shadow Directories can be accessed at
+http://www.ietf.org/shadow.html
 
-The distribution of this memo is unlimited.  
+The distribution of this memo is unlimited.
 
 
 .ti 0
@@ -54,10 +54,10 @@ Abstract
 
 This memo describes a Secure Internet Live Conferencing (SILC)
 protocol which provides secure conferencing services over insecure
-network channel.  SILC is IRC [IRC] like protocol, however, it is 
-not equivalent to IRC and does not support IRC.  Strong cryptographic
+network channel.  SILC provides advanced and feature rich conferencing
+services with security as main design principal.  Strong cryptographic
 methods are used to protect SILC packets inside the SILC network.
-Three other Internet Drafts relates very closely to this memo;
+Three other specifications relates very closely to this memo;
 SILC Packet Protocol [SILC2], SILC Key Exchange and Authentication
 Protocols [SILC3] and SILC Commands [SILC4].
 
@@ -75,64 +75,64 @@ Table of Contents
 2 SILC Concepts .................................................  4
   2.1 SILC Network Topology .....................................  4
   2.2 Communication Inside a Cell ...............................  6
-  2.3 Communication in the Network ..............................  6
+  2.3 Communication in the Network ..............................  7
   2.4 Channel Communication .....................................  7
   2.5 Router Connections ........................................  8
-3 SILC Specification ............................................  8
+3 SILC Specification ............................................  9
   3.1 Client ....................................................  9
       3.1.1 Client ID ...........................................  9
   3.2 Server .................................................... 10
-      3.2.1 Server's Local ID List .............................. 10
-      3.2.2 Server ID ........................................... 11
+      3.2.1 Server's Local ID List .............................. 11
+      3.2.2 Server ID ........................................... 12
       3.2.3 SILC Server Ports ................................... 12
-  3.3 Router .................................................... 12
+  3.3 Router .................................................... 13
       3.3.1 Router's Local ID List .............................. 13
-      3.3.2 Router's Global ID List ............................. 13
+      3.3.2 Router's Global ID List ............................. 14
       3.3.3 Router's Server ID .................................. 14
   3.4 Channels .................................................. 14
-      3.4.1 Channel ID .......................................... 15
+      3.4.1 Channel ID .......................................... 16
   3.5 Operators ................................................. 16
-  3.6 SILC Commands ............................................. 16
+  3.6 SILC Commands ............................................. 17
   3.7 SILC Packets .............................................. 17
   3.8 Packet Encryption ......................................... 17
       3.8.1 Determination of the Source and the Destination ..... 18
-      3.8.2 Client To Client .................................... 18
+      3.8.2 Client To Client .................................... 19
       3.8.3 Client To Channel ................................... 20
-      3.8.4 Server To Server .................................... 20
-  3.9 Key Exchange And Authentication ........................... 20
+      3.8.4 Server To Server .................................... 21
+  3.9 Key Exchange And Authentication ........................... 21
       3.9.1 Authentication Payload .............................. 21
   3.10 Algorithms ............................................... 23
       3.10.1 Ciphers ............................................ 23
              3.10.1.1 CBC Mode .................................. 24
              3.10.1.2 CTR Mode .................................. 24
-             3.10.1.3 Randomized CBC Mode ....................... 25
+             3.10.1.3 Randomized CBC Mode ....................... 26
       3.10.2 Public Key Algorithms .............................. 26
-      3.10.3 Hash Functions ..................................... 26
+             3.10.2.1 Multi-Precision Integers .................. 27
+      3.10.3 Hash Functions ..................................... 27
       3.10.4 MAC Algorithms ..................................... 27
-      3.10.5 Compression Algorithms ............................. 27
-  3.11 SILC Public Key .......................................... 28
-  3.12 SILC Version Detection ................................... 30
+      3.10.5 Compression Algorithms ............................. 28
+  3.11 SILC Public Key .......................................... 29
+  3.12 SILC Version Detection ................................... 31
   3.13 Backup Routers ........................................... 31
-      3.13.1 Switching to Backup Router ......................... 32
-      3.13.2 Resuming Primary Router ............................ 33
-      3.13.3 Discussion on Backup Router Scheme ................. 36
+      3.13.1 Switching to Backup Router ......................... 33
+      3.13.2 Resuming Primary Router ............................ 34
 4 SILC Procedures ............................................... 36
-  4.1 Creating Client Connection ................................ 36
+  4.1 Creating Client Connection ................................ 37
   4.2 Creating Server Connection ................................ 38
-      4.2.1 Announcing Clients, Channels and Servers ............ 38
-  4.3 Joining to a Channel ...................................... 39
+      4.2.1 Announcing Clients, Channels and Servers ............ 39
+  4.3 Joining to a Channel ...................................... 40
   4.4 Channel Key Generation .................................... 41
-  4.5 Private Message Sending and Reception ..................... 41
+  4.5 Private Message Sending and Reception ..................... 42
   4.6 Private Message Key Generation ............................ 42
   4.7 Channel Message Sending and Reception ..................... 43
-  4.8 Session Key Regeneration .................................. 43
+  4.8 Session Key Regeneration .................................. 44
   4.9 Command Sending and Reception ............................. 44
   4.10 Closing Connection ....................................... 45
-  4.11 Detaching and Resuming a Session ......................... 45
+  4.11 Detaching and Resuming a Session ......................... 46
 5 Security Considerations ....................................... 47
 6 References .................................................... 48
-7 Author's Address .............................................. 49
-
+7 Author's Address .............................................. 50
+8 Full Copyright Statement ...................................... 50
 
 .ti 0
 List of Figures
@@ -151,19 +151,23 @@ Figure 6:  Counter Block
 
 This document describes a Secure Internet Live Conferencing (SILC)
 protocol which provides secure conferencing services over insecure
-network channel.  SILC is IRC [IRC] like protocol, however, it is 
-not equivalent to IRC and does not support IRC.  Some of the SILC's
-features are not found in IRC but in traditional Instant Message (IM)
+network channel.  SILC can be used as a secure conferencing service
+that provides rich conferencing features.  Some of the SILC features
+are found in traditional chat protocols such as IRC [IRC] but many
+of the SILC features can also be found in Instant Message (IM) style
 protocols.  SILC combines features from both of these chat protocol
-styles, and SILC can be implemented as either IRC-like system or
-IM-like system.
+styles, and can be implemented as either IRC-like system or IM-like
+system.  Some of the more advanced and secure features of the
+protocol are new to all conferencing protocols.  SILC also supports
+multimedia messages and can also be implemented as a video and audio
+conferencing system.
 
 Strong cryptographic methods are used to protect SILC packets inside
-the SILC network.  Three other Internet Drafts relates very closely
+the SILC network.  Three other specifications relates very closely
 to this memo; SILC Packet Protocol [SILC2], SILC Key Exchange and
 Authentication Protocols [SILC3] and SILC Commands [SILC4].
 
-The protocol uses extensively packets as conferencing protocol 
+The protocol uses extensively packets as conferencing protocol
 requires message and command sending.  The SILC Packet Protocol is
 described in [SILC2] and should be read to fully comprehend this
 document and protocol.  [SILC2] also describes the packet encryption
@@ -173,11 +177,10 @@ This makes SILC also suitable in environment of low bandwidth
 requirements such as mobile networks.  All packet payloads in SILC
 can be also compressed.
 
-The security of SILC protocol, and for any security protocol for that
-matter, is based on strong and secure key exchange protocol.  The SILC
-Key Exchange protocol is described in [SILC3] along with connection
-authentication protocol and should be read to fully comprehend this
-document and protocol.
+The security of SILC protocol sessions are based on strong and secure
+key exchange protocol.  The SILC Key Exchange protocol is described
+in [SILC3] along with connection authentication protocol and should
+be read to fully comprehend this document and protocol.
 
 The SILC protocol has been developed to work on TCP/IP network
 protocol, although it could be made to work on other network protocols
@@ -189,7 +192,7 @@ be made in client-server model.
 .ti 0
 1.1 Requirements Terminology
 
-The keywords MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, RECOMMENDED, 
+The keywords MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, RECOMMENDED,
 MAY, and OPTIONAL, when they appear in this document, are to be
 interpreted as described in [RFC2119].
 
@@ -197,15 +200,15 @@ interpreted as described in [RFC2119].
 .ti 0
 2. SILC Concepts
 
-This section describes various SILC protocol concepts that forms the 
+This section describes various SILC protocol concepts that forms the
 actual protocol, and in the end, the actual SILC network.  The mission
-of the protocol is to deliver messages from clients to other clients 
-through routers and servers in secure manner.  The messages may also 
-be delivered from one client to many clients forming a group, also 
+of the protocol is to deliver messages from clients to other clients
+through routers and servers in secure manner.  The messages may also
+be delivered from one client to many clients forming a group, also
 known as a channel.
 
-This section does not focus to security issues.  Instead, basic network 
-concepts are introduced to make the topology of the SILC network 
+This section does not focus to security issues.  Instead, basic network
+concepts are introduced to make the topology of the SILC network
 clear.
 
 
@@ -213,22 +216,24 @@ clear.
 2.1 SILC Network Topology
 
 SILC network forms a ring as opposed to tree style network topology that
-conferencing protocols usually have.  The network has a cells which are 
-constructed from router and zero or more servers.  The servers are 
-connected to the router in a star like network topology.  Routers in the 
-network are connected to each other forming a ring.  The rationale for 
-this is to have servers that can perform specific kind of tasks what 
-other servers cannot perform.  This leads to two kinds of servers; normal 
-SILC servers and SILC routers.
-
-A difference between normal server and router server is that routers 
-knows everything about everything in the network.  They also do the 
-actual routing of the messages to the correct receiver.  Normal servers 
-knows only about local information and nothing about global information.
-This makes the network faster as there are less servers that needs to 
-keep global information up to date at all time.
-
-This, on the other hand, leads to kind of a cellular like network, where
+conferencing protocols usually have.  The network has a cells which are
+constructed from a router and zero or more servers.  The servers are
+connected to the router in a star like network topology.  Routers in the
+network are connected to each other forming a ring.  The rationale for
+this is to have servers that can perform specific kind of tasks what
+other servers cannot perform.  This leads to two kinds of servers; normal
+SILC servers and SILC router servers.
+
+A difference between normal server and router server is that routers
+knows all global information and keep the global network state up to date.
+They also do the actual routing of the messages to the correct receiver
+between other cells.  Normal servers knows only local information and
+receive global information only when it is needed.  They do not need to
+keep the global network state up to date.  This makes the network faster
+and scalable as there are less servers that needs to maintain global
+network state.
+
+This, on the other hand, leads into a cellular like network, where
 routers are in the center of the cell and servers are connected to the
 router.
 
@@ -263,29 +268,31 @@ A cell is formed when a server or servers connect to one router.  In
 SILC network normal server cannot directly connect to other normal
 server.  Normal server may only connect to SILC router which then
 routes the messages to the other servers in the cell.  Router servers
-on the other hand may connect to other routers to form the actual SILC 
-network, as seen in above figure.  However, router is also normal SILC 
-server; clients may connect to it the same way as to normal SILC 
-server.  Normal server also cannot have active connections to more 
-than one router.  Normal server cannot be connected to two different 
-cells.  Router servers, on the other hand, may have as many router to 
-router connections as needed.
+on the other hand may connect to other routers to form the actual SILC
+network, as seen in above figure.  However, router is also able to act
+as normal SILC server; clients may connect to it the same way as to
+normal SILC server.  Normal server also cannot have active connections
+to more than one router.  Normal server cannot be connected to two
+different cells.  Router servers, on the other hand, may have as many
+router to router connections as needed.  Other direct routes between
+other routers is also possible in addition of the mandatory ring
+connections.  This leads into a hybrid ring-mesh network topology.
 
 There are many issues in this network topology that needs to be careful
-about.  Issues like the size of the cells, the number of the routers in 
-the SILC network and the capacity requirements of the routers.  These
-issues should be discussed in the Internet Community and additional
-documents on the issue may be written.
+about.  Issues like routing, the size of the cells, the number of the
+routers in the SILC network and the capacity requirements of the
+routers.  These issues should be discussed in the Internet Community
+and additional documents on the issue may be written.
 
 
 .ti 0
 2.2 Communication Inside a Cell
 
-It is always guaranteed that inside a cell message is delivered to the 
+It is always guaranteed that inside a cell message is delivered to the
 recipient with at most two server hops.  A client which is connected to
-server in the cell and is talking on channel to other client connected 
-to other server in the same cell, will have its messages delivered from 
-its local server first to the router of the cell, and from the router 
+server in the cell and is talking on channel to other client connected
+to other server in the same cell, will have its messages delivered from
+its local server first to the router of the cell, and from the router
 to the other server in the cell.
 
 The following diagram represents this scenario:
@@ -313,8 +320,8 @@ Example:  Client 1. connected to Server 1. send message to
 
 
 If the client is connected directly to the router, as router is also normal
-SILC server, the messages inside the cell are always delivered only with 
-one server hop.  If clients communicating with each other are connected 
+SILC server, the messages inside the cell are always delivered only with
+one server hop.  If clients communicating with each other are connected
 to the same server, no router interaction is needed.  This is the optimal
 situation of message delivery in the SILC network.
 
@@ -322,9 +329,9 @@ situation of message delivery in the SILC network.
 .ti 0
 2.3 Communication in the Network
 
-If the message is destined to server that does not belong to local cell 
-the message is routed to the router server to which the destination 
-server belongs, if the local router is connected to destination router.
+If the message is destined to client that does not belong to local cell
+the message is routed to the router server to which the destination
+client belongs, if the local router is connected to destination router.
 If there is no direct connection to the destination router, the local
 router routes the message to its primary route.  The following diagram
 represents message sending between cells.
@@ -350,7 +357,7 @@ Figure 3:  Communication Between Cells
 Example:  Client 5. connected to Server 4. in Cell 1. sends message
           to Client 2. connected to Server 1. in Cell 2. travels
           from Server 4. to Router which routes the message to
-          Router in Cell 2, which then routes the message to 
+          Router in Cell 2, which then routes the message to
           Server 1.  All the other servers and routers in the
           network will not see the routed message.
 
@@ -360,7 +367,7 @@ when clients are connected directly to the routers and the messages
 are delivered from one router to the other.
 
 
-.ti 0 
+.ti 0
 2.4 Channel Communication
 
 Messages may be sent to group of clients as well.  Sending messages to
@@ -368,16 +375,15 @@ many clients works the same way as sending messages point to point, from
 message delivery point of view.  Security issues are another matter
 which are not discussed in this section.
 
-Router server handles the message routing to multiple recipients.  If 
-any recipient is not in the same cell as the sender the messages are 
+Router server handles the message routing to multiple recipients.  If
+any recipient is not in the same cell as the sender the messages are
 routed further.
 
-Server distributes the channel message to its local clients which are 
-joined to the channel.  Router also distributes the message to its 
+Server distributes the channel message to its local clients which are
+joined to the channel.  Router also distributes the message to its
 local clients on the channel.
 
 
-
 .ti 0
 2.5 Router Connections
 
@@ -421,7 +427,7 @@ primary routes.
 The issue of router connections are very important especially with SILC
 broadcast packets.  Usually all router wide information in the network is
 distributed by SILC broadcast packets.  This sort of ring network, with
-ability to have other direct routes in the network cause interesting
+ability to have other direct routes in the network can cause interesting
 routing problems.  The [SILC2] discusses the routing of packets in this
 sort of network in more detail.
 
@@ -437,39 +443,40 @@ specification and must be read.
 .ti 0
 3.1 Client
 
-A client is a piece of software connecting to SILC server.  SILC client 
-cannot be SILC server.  Purpose of clients is to provide the user 
+A client is a piece of software connecting to SILC server.  SILC client
+cannot be SILC server.  Purpose of clients is to provide the user
 interface of the SILC services for end user.  Clients are distinguished
 from other clients by unique Client ID.  Client ID is a 128 bit ID that
-is used in the communication in the SILC network.  The client ID is 
-based on the nickname selected by the user.  User uses logical nicknames
+is used in the communication in the SILC network.  The client ID is
+based on the user's IP address and nickname.  User use logical nicknames
 in communication which are then mapped to the corresponding Client ID.
-Client ID's are low level identifications and should not be seen by the
+Client IDs are low level identifications and should not be seen by the
 end user.
 
 Clients provide other information about the end user as well. Information
-such as the nickname of the user, username and the host name of the end 
-user and user's real name.  See section 3.2 Server for information of 
+such as the nickname of the user, username and the host name of the end
+user and user's real name.  See section 3.2 Server for information of
 the requirements of keeping this information.
 
 The nickname selected by the user is not unique in the SILC network.
-There can be 2^8 same nicknames for one IP address.  As for comparison to 
-IRC [IRC] where nicknames are unique this is a fundamental difference 
-between SILC and IRC.  This typically causes the server names or client's 
-host names to be used along with the nicknames on user interface to  
-identify specific users when sending messages.  This feature of SILC 
-makes IRC style nickname-wars obsolete as no one owns their nickname; 
-there can always be someone else with the same nickname.  The maximum 
-length of nickname is 128 bytes.
+There can be 2^8 same nicknames for one IP address.  As for comparison to
+IRC [IRC] where nicknames are unique this is a fundamental difference
+between SILC and IRC.  This typically causes the server names or client's
+host names to be used along with the nicknames on user interface to
+identify specific users when sending messages.  This feature of SILC
+makes IRC style nickname-wars obsolete as no one owns their nickname;
+there can always be someone else with the same nickname.  Also, any kind
+of nickname registering service becomes obsolete.  The maximum length of
+nickname is 128 bytes.
 
 
 .ti 0
 3.1.1 Client ID
 
 Client ID is used to identify users in the SILC network.  The Client ID
-is unique to the extent that there can be 2^128 different Client ID's,
-and ID's based on IPv6 addresses extends this to 2^224 different Client
-ID's.  Collisions are not expected to happen.  The Client ID is defined
+is unique to the extent that there can be 2^128 different Client IDs,
+and IDs based on IPv6 addresses extends this to 2^224 different Client
+IDs.  Collisions are not expected to happen.  The Client ID is defined
 as follows.
 
 .in 6
@@ -487,9 +494,9 @@ as follows.
 
 o Server ID IP address - Indicates the server where this
   client is coming from.  The IP address hence equals the
-  server IP address where to the client has connected.
+  server IP address where the client is connected.
 
-o Random number or counter - Random number to further 
+o Random number or counter - Random number to further
   randomize the Client ID.  Another choice is to use
   a counter starting from the zero (0).  This makes it
   possible to have 2^8 same nicknames from the same
@@ -503,16 +510,16 @@ o MD5 hash - MD5 hash value of the lowercase nickname is
 
 .in 3
 Collisions could occur when more than 2^8 clients using same nickname
-from the same server IP address is connected to the SILC network.  
-Server MUST be able to handle this situation by refusing to accept 
+from the same server IP address is connected to the SILC network.
+Server MUST be able to handle this situation by refusing to accept
 anymore of that nickname.
 
 Another possible collision may happen with the truncated hash value of
-the nickname.  It could be possible to have same truncated hash value for
-two different nicknames.  However, this is not expected to happen nor
-cause any problems if it would occur.  Nicknames are usually logical and
-it is unlikely to have two distinct logical nicknames produce same
-truncated hash value.
+the nickname.  It could be possible to have same truncated hash value
+for two different nicknames.  However, this is not expected to happen
+nor cause any serious problems if it would occur.  Nicknames are usually
+logical and it is unlikely to have two distinct logical nicknames
+produce same truncated hash value.
 
 
 .ti 0
@@ -537,15 +544,15 @@ cell's router except in situations where its cell's router is unavailable.
 
 Normal server keeps various information about the clients and their end
 users connected to it.  Every normal server MUST keep list of all locally
-connected clients, Client ID's, nicknames, usernames and host names and
+connected clients, Client IDs, nicknames, usernames and host names and
 user's real name.  Normal servers only keeps local information and it
 does not keep any global information.  Hence, normal servers knows only
 about their locally connected clients.  This makes servers efficient as
-they don't have to worry about global clients.  Server is also responsible
-of creating the Client ID's for their clients.
+they do not have to worry about global clients.  Server is also responsible
+of creating the Client IDs for their clients.
 
 Normal server also keeps information about locally created channels and
-their Channel ID's.
+their Channel IDs.
 
 Hence, local list for normal server includes:
 
@@ -571,19 +578,20 @@ client list        - All clients in server
 channel list       - All channels in server
    o Channel name
    o Channel ID
-   o Client ID's on channel
+   o Client IDs on channel
    o Client ID modes on channel
    o Channel key
 .in 3
 
 
+
 .ti 0
 3.2.2 Server ID
 
-Servers are distinguished from other servers by unique 64 bit Server ID 
+Servers are distinguished from other servers by unique 64 bit Server ID
 (for IPv4) or 160 bit Server ID (for IPv6).  The Server ID is used in
-the SILC to route messages to correct servers.  Server ID's also provide
-information for Client ID's, see section 3.1.1 Client ID.  Server ID is
+the SILC to route messages to correct servers.  Server IDs also provide
+information for Client IDs, see section 3.1.1 Client ID.  Server ID is
 defined as follows.
 
 .in 6
@@ -630,6 +638,7 @@ Server on network above privileged ports (>1023) SHOULD NOT be trusted
 as they could have been set up by untrusted party.
 
 
+
 .ti 0
 3.3 Router
 
@@ -639,11 +648,10 @@ is also a normal server thus clients may connect to it as it would be
 just normal SILC server.
 
 However, router servers has a lot of important tasks that normal servers
-do not have.  Router server knows everything about everything in the SILC.
+do not have.  Router server knows everything and keeps the global state.
 They know all clients currently on SILC, all servers and routers and all
 channels in SILC.  Routers are the only servers in SILC that care about
-global information and keeping them up to date at all time.  And, this
-is what they must do.
+global information and keeping them up to date at all time.
 
 
 .ti 0
@@ -674,7 +682,7 @@ client list        - All clients in the cell
 
 channel list       - All channels in the cell
    o Channel ID
-   o Client ID's on channel
+   o Client IDs on channel
    o Client ID modes on channel
    o Channel key
 .in 3
@@ -682,7 +690,8 @@ channel list       - All channels in the cell
 
 Note that locally connected clients and other information include all the
 same information as defined in section section 3.2.1 Server's Local ID
-List.
+List.  Router MAY also cache same detailed information for other clients
+if needed.
 
 
 .ti 0
@@ -690,15 +699,15 @@ List.
 
 Router server MUST also keep global list.  Normal servers do not have
 global list as they know only about local information.  Global list
-includes all the clients on SILC, their Client ID's, all created channels
-and their Channel ID's and all servers and routers on SILC and their
-Server ID's.  That is said, global list is for global information and the
+includes all the clients on SILC, their Client IDs, all created channels
+and their Channel IDs and all servers and routers on SILC and their
+Server IDs.  That is said, global list is for global information and the
 list must not include the local information already on the router's local
 list.
 
 Note that the global list does not include information like nicknames,
 usernames and host names or user's real names.  Router does not need to
-keep these informations as they are not needed by the router.  This 
+keep these informations as they are not needed by the router.  This
 information is available from the client's server which maybe queried
 when needed.
 
@@ -715,7 +724,7 @@ client list        - All clients in SILC
 
 channel list       - All channels in SILC
    o Channel ID
-   o Client ID's on channel
+   o Client IDs on channel
    o Client ID modes on channel
 .in 3
 
@@ -724,9 +733,9 @@ channel list       - All channels in SILC
 .ti 0
 3.3.3 Router's Server ID
 
-Router's Server ID's are equivalent to normal Server ID's.  As routers
-are normal servers as well same types of ID's applies for routers as well.
-Thus, see section 3.2.2 Server ID.
+Router's Server ID is equivalent to normal Server ID.  As routers are
+normal servers same types of IDs applies for routers as well.  See
+section 3.2.2 Server ID.
 
 
 .ti 0
@@ -736,7 +745,7 @@ A channel is a named group of one or more clients which will all receive
 messages addressed to that channel.  The channel is created when first
 client requests JOIN command to the channel, and the channel ceases to
 exist when the last client has left it.  When channel exists, any client
-can reference it using the name of the channel.  If the channel has
+can reference it using the Channel ID of the channel.  If the channel has
 a founder mode set and last client leaves the channel the channel does
 not cease to exist.  The founder mode can be used to make permanent
 channels in the network.  The founder of the channel can regain the
@@ -760,7 +769,7 @@ o Channel founder - When channel is created the joining client becomes
   privileges.  Basically, channel founder can fully operate the channel
   and all of its modes.  The privileges are limited only to the
   particular channel.  There can be only one channel founder per
-  channel. Channel founder supersedes channel operator's privileges.
+  channel.  Channel founder supersedes channel operator's privileges.
 
   Channel founder privileges cannot be removed by any other operator on
   channel.  When channel founder leaves the channel there is no channel
@@ -771,7 +780,7 @@ o Channel founder - When channel is created the joining client becomes
 
 o Channel operator - When client joins to channel that has not existed
   previously it will become automatically channel operator (and channel
-  founder discussed above).  Channel operator is able administrate the
+  founder discussed above).  Channel operator is able to administrate the
   channel, set some modes on channel, remove a badly behaving client
   from the channel and promote other clients to become channel
   operator.  The privileges are limited only to the particular channel.
@@ -783,6 +792,8 @@ o Channel operator - When client joins to channel that has not existed
 .in 3
 
 
+
+
 .ti 0
 3.4.1 Channel ID
 
@@ -798,25 +809,26 @@ follows.
 
 32 bit  Router's Server ID IP address (bits 1-32)
 16 bit  Router's Server ID port (bits 33-48)
-16 bit  Random number
+16 bit  Random number or counter
 
 160 bit Channel ID based on IPv6 addresses:
 
 128 bit  Router's Server ID IP address (bits 1-128)
  16 bit  Router's Server ID port (bits 129-144)
- 16 bit  Random number
+ 16 bit  Random number or counter
 
-o Router's Server ID IP address - Indicates the IP address of 
-  the router of the cell where this channel is created.  This is 
-  taken from the router's Server ID.  This way SILC router knows 
+o Router's Server ID IP address - Indicates the IP address of
+  the router of the cell where this channel is created.  This is
+  taken from the router's Server ID.  This way SILC router knows
   where this channel resides in the SILC network.
 
-o Router's Server ID port - Indicates the port of the channel on 
+o Router's Server ID port - Indicates the port of the channel on
   the server.  This is taken from the router's Server ID.
 
-o Random number - To further randomize the Channel ID.  This makes
-  sure that there are no collisions.  This also means that
-  in a cell there can be 2^16 channels.
+o Random number or counter - To further randomize the Channel ID.
+  Another choice is to use a counter starting from zero (0).
+  This makes sure that there are no collisions.  This also means
+  that in a cell there can be 2^16 different channels.
 .in 3
 
 
@@ -828,10 +840,10 @@ router.  Usually these people are SILC server and router administrators
 that take care of their own server and clients on them.  The purpose of
 operators is to administrate the SILC server or router.  However, even
 an operator with highest privileges is not able to enter invite-only
-channel, to gain access to the contents of a encrypted and authenticated
+channels, to gain access to the contents of encrypted and authenticated
 packets traveling in the SILC network or to gain channel operator
 privileges on public channels without being promoted.  They have the
-same privileges as everyone else except they are able to administrate
+same privileges as any normal user except they are able to administrate
 their server or router.
 
 
@@ -854,15 +866,15 @@ the command request but server is allowed to send command reply packet
 to client even if client has not requested the command.  Client MAY
 choose to ignore the command reply.
 
-It is expected that some of the commands may be miss-used by clients
+It is expected that some of the commands may be misused by clients
 resulting various problems on the server side.  Every implementation
 SHOULD assure that commands may not be executed more than once, say,
 in two (2) seconds.  However, to keep response rate up, allowing for
 example five (5) commands before limiting is allowed.  It is RECOMMENDED
-that commands such as SILC_COMMAND_NICK, SILC_COMMAND_JOIN, 
+that commands such as SILC_COMMAND_NICK, SILC_COMMAND_JOIN,
 SILC_COMMAND_LEAVE and SILC_COMMAND_KILL SHOULD be limited in all cases
 as they require heavy operations.  This should be sufficient to prevent
-the miss-use of commands.
+the misuse of commands.
 
 SILC commands are described in [SILC4].
 
@@ -874,7 +886,7 @@ Packets are naturally the most important part of the protocol and the
 packets are what actually makes the protocol.  Packets in SILC network
 are always encrypted using, usually the shared secret session key
 or some other key, for example, channel key, when encrypting channel
-messages.  It is not possible to send packet in SILC network without
+messages.  It is not possible to send packet in SILC network without
 encryption.  The SILC Packet Protocol is a wide protocol and is described
 in [SILC2].  This document does not define or describe details of
 SILC packets.
@@ -884,32 +896,32 @@ SILC packets.
 3.8 Packet Encryption
 
 All packets passed in SILC network MUST be encrypted.  This section
-defines how packets must be encrypted in the SILC network.  The detailed
-description of the actual encryption process of the packets are
-described in [SILC2].
+gives generic description of how packets must be encrypted in the SILC
+network.  The detailed description of the actual encryption process
+of the packets are described in [SILC2].
 
 Client and its server shares secret symmetric session key which is
-established by the SILC Key Exchange Protocol, described in [SILC3]. 
+established by the SILC Key Exchange Protocol, described in [SILC3].
 Every packet sent from client to server, with exception of packets for
 channels, are encrypted with this session key.
 
-Channels has a channel key that are shared by every client on the channel.
-However, the channel keys are cell specific thus one cell does not know
-the channel key of the other cell, even if that key is for same channel.
-Channel key is also known by the routers and all servers that has clients
-on the channel.  However, channels MAY have channel private keys that
-are entirely local setting for the client.  All clients on the channel
-MUST know the channel private key before hand to be able to talk on the
-channel.  In this case, no server or router know the key for channel.
+Channels have a channel key that are shared by every client on the channel.
+However, the channel keys are cell specific thus one cell does not know 
+the channel key of the other cell, even if that key is for same channel.  
+Channel key is also known by the routers and all servers that have clients 
+on the channel.  However, channels MAY have channel private keys that are 
+entirely local setting for the client.  All clients on the channel MUST 
+know the channel private key beforehand to be able to talk on the
+channel.  In this case, no server or router knows the key for the channel.
 
 Server shares secret symmetric session key with router which is
 established by the SILC Key Exchange Protocol.  Every packet passed from
 server to router, with exception of packets for channels, are encrypted
 with the shared session key.  Same way, router server shares secret
-symmetric key with its primary route.  However, every packet passed
+symmetric key with its primary router.  However, every packet passed
 from router to other router, including packets for channels, are
-encrypted with the shared session key.  Every router connection has
-their own session keys.
+encrypted with the shared session key.  Every router connection MUST
+have their own session keys.
 
 
 .ti 0
@@ -920,11 +932,11 @@ to be able to route the packets to correct receiver.  This information
 is available in the SILC Packet Header which is included in all packets
 sent in SILC network.  The SILC Packet Header is described in [SILC2].
 
-The header MUST be encrypted with the session key who is next receiver
-of the packet along the route.  The receiver of the packet, for example
-a router along the route, is able to determine the sender and the
+The header MUST be encrypted with the session key of whom is the next
+receiver of the packet along the route.  The receiver of the packet, for 
+example a router along the route, is able to determine the sender and the
 destination of the packet by decrypting the SILC Packet Header and
-checking the ID's attached to the header.  The ID's in the header will
+checking the IDs attached to the header.  The IDs in the header will
 tell to where the packet needs to be sent and where it is coming from.
 
 The header in the packet MUST NOT change during the routing of the
@@ -933,7 +945,9 @@ and the packet header and server or router between the sender and the
 receiver MUST NOT change the packet header.  Note however, that some
 packets such as commands may be resent by a server to serve the client's
 original command.  In this case the command packet sent by the server
-includes the server's IDs.
+includes the server's IDs as it is a different packet.  When server
+or router receives a packet it MUST verify that the Source ID is
+valid and correct ID for that sender.
 
 Note that the packet and the packet header may be encrypted with
 different keys.  For example, packets to channels are encrypted with
@@ -952,7 +966,7 @@ Example:  Private message from client to another client on different
           servers.  Clients do not share private message delivery
           keys; normal session keys are used.
 
-o Client 1. sends encrypted packet to its server.  The packet is
+o Client 1 sends encrypted packet to its server.  The packet is
   encrypted with the session key shared between client and its
   server.
 
@@ -962,7 +976,7 @@ o Server determines the destination of the packet and decrypts
   router.
 
 o Router determines the destination of the packet and decrypts
-  the packet.  Router encrypts the packet with session key 
+  the packet.  Router encrypts the packet with session key
   shared between the router and the destination server, and sends
   the packet to the server.
 
@@ -971,38 +985,41 @@ o Server determines the client to which the packet is destined
   session key shared between the server and the destination client,
   and sends the packet to the client.
 
-o Client 2. decrypts the packet.
+o Client 2 decrypts the packet.
 
 
 Example:  Private message from client to another client on different
-          servers.  Clients has established secret shared private
-          message delivery key with each other and that is used in 
+          servers.  Clients have established a secret shared private
+          message delivery key with each other and that is used in
           the message encryption.
 
-o Client 1. sends encrypted packet to its server.  The packet header
+o Client 1 sends encrypted packet to its server.  The packet header
   is encrypted with the session key shared between the client and
   server, and the private message is encrypted with the private
   message delivery key shared between clients.
 
-o Server determines the destination of the packet and sends the 
-  packet to the router.
+o Server determines the destination of the packet and sends the
+  packet to the router.  Header is encrypted with the session key.
 
 o Router determines the destination of the packet and sends the
-  packet to the server.
+  packet to the server.  Header is encrypted with the session key.
 
 o Server determines the client to which the packet is destined
-  to and sends the packet to the client.
+  to and sends the packet to the client.  Header is encrypted with
+  the session key.
 
-o Client 2. decrypts the packet with the secret shared key.
+o Client 2 decrypts the packet with the secret shared key.
 
 If clients share secret key with each other the private message
 delivery is much simpler since servers and routers between the
-clients do not need to decrypt and re-encrypt the packet.
-
-The process for clients on same server is much simpler as there are
-no need to send the packet to the router.  The process for clients 
-on different cells is same as above except that the packet is routed 
-outside the cell.  The router of the destination cell routes the 
+clients do not need to decrypt and re-encrypt the entire packet.
+The packet header however is always encrypted with session key and
+is decrypted and re-encrypted with the session key of next recipient.
+
+The process for clients on same server is much simpler as there is
+no need to send the packet to the router.  The process for clients
+on different cells is same as above except that the packet is routed
+outside the cell.  The router of the destination cell routes the
 packet to the destination same way as described above.
 
 
@@ -1014,8 +1031,10 @@ on the channel.
 
 Example:  Channel of four users; two on same server, other two on
           different cells.  Client sends message to the channel.
+          Packet header is encrypted with the session key, message
+          data is encrypted with channel key.
 
-o Client 1. encrypts the packet with channel key and sends the
+o Client 1 encrypts the packet with channel key and sends the
   packet to its server.
 
 o Server determines local clients on the channel and sends the
@@ -1028,7 +1047,7 @@ o Router determines local clients on the channel, if found
   router or fastest route.
 
 o (Other router(s) do the same thing and sends the packet to
-   the server(s))
+   the server(s).)
 
 o Server determines local clients on the channel and sends the
   packet to the client.
@@ -1050,19 +1069,19 @@ more in detail in [SILC2].
 3.9 Key Exchange And Authentication
 
 Key exchange is done always when for example client connects to server
-but also when server and router, and router and router connects to each
-other.  The purpose of key exchange protocol is to provide secure key
-material to be used in the communication.  The key material is used to
-derive various security parameters used to secure SILC packets.  The
+but also when server and router, and router and another router connect
+to each other.  The purpose of key exchange protocol is to provide secure
+key material to be used in the communication.  The key material is used
+to derive various security parameters used to secure SILC packets.  The
 SILC Key Exchange protocol is described in detail in [SILC3].
 
 Authentication is done after key exchange protocol has been successfully
 completed.  The purpose of authentication is to authenticate for example
-client connecting to the server.  However, clients may be accepted
+client connecting to the server.  However, clients MAY be accepted
 to connect to server without explicit authentication.  Servers are
-required to use authentication protocol when connecting.  The 
-authentication may be based on passphrase (pre-shared-secret) or public 
-key based on digital signatures.  All passphrases sent in SILC protocol 
+REQUIRED to use authentication protocol when connecting.  The
+authentication may be based on passphrase (pre-shared secret) or public
+key based on digital signatures.  All passphrases sent in SILC protocol
 MUST be UTF-8 [RFC2279] encoded. The connection authentication protocol
 is described in detail in [SILC3].
 
@@ -1070,11 +1089,11 @@ is described in detail in [SILC3].
 .ti 0
 3.9.1 Authentication Payload
 
-Authentication payload is used separately from the SKE and the Connection
-Authentication protocol.  It can be used during the session to authenticate
-with the remote.  For example, the client can authenticate itself to the
-server to become server operator.  In this case, Authentication Payload is
-used.
+Authentication Payload is used separately from the SKE and the Connection
+Authentication protocols.  It can be used during the session to
+authenticate with a remote.  For example, a client can authenticate
+itself to a server to become server operator.  In this case,
+Authentication Payload is used.
 
 The format of the Authentication Payload is as follows:
 
@@ -1098,7 +1117,7 @@ The format of the Authentication Payload is as follows:
 |                                                               |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 .in 3
+
 .ce
 Figure 5:  Authentication Payload
 
@@ -1108,7 +1127,7 @@ o Payload Length (2 bytes) - Length of the entire payload.
 
 o Authentication Method (2 bytes) - The method of the
   authentication.  The authentication methods are defined
-  in [SILC2] in the Connection Auth Request Payload.  The NONE 
+  in [SILC2] in the Connection Auth Request Payload.  The NONE
   authentication method SHOULD NOT be used.
 
 o Public Data Length (2 bytes) - Indicates the length of
@@ -1116,7 +1135,7 @@ o Public Data Length (2 bytes) - Indicates the length of
 
 o Public Data (variable length) - This is defined only if
   the authentication method is public key.  If it is any other
-  this field MAY include random data for padding purposes.
+  this field MAY include random data for padding purposes.
   However, in this case the field MUST be ignored by the
   receiver.
 
@@ -1126,22 +1145,22 @@ o Public Data (variable length) - This is defined only if
 
 o Authentication Data Length (2 bytes) - Indicates the
   length of the Authentication Data field.  If zero (0)
-  value is found in this field the payload MUST be 
+  value is found in this field the payload MUST be
   discarded.
 
-o Authentication Data (variable length) - Authentication 
+o Authentication Data (variable length) - Authentication
   method dependent authentication data.
 .in 3
 
 
-If the authentication method is password based, the Authentication
-Data field includes the plaintext UTF-8 encoded password.  It is safe
-to send plaintext password since the entire payload is encrypted.  In
+If the authentication method is passphrase-based, the Authentication
+Data field includes the plaintext UTF-8 encoded passphrase.  It is safe
+to send plaintext passphrase since the entire payload is encrypted.  In
 this case the Public Data Length is set to zero (0), but MAY also include
 random data for padding purposes.  It is also RECOMMENDED that maximum
-amount of padding is applied to SILC packet when using password based
+amount of padding is applied to SILC packet when using passphrase-based
 authentication.  This way it is not possible to approximate the length
-of the password from the encrypted packet.
+of the passphrase from the encrypted packet.
 
 If the authentication method is public key based (or certificate)
 the Authentication Data is computed as follows:
@@ -1161,8 +1180,8 @@ into the Public Data field as is.
 The receiver will compute the signature using the random data received
 in the payload, the ID associated to the connection and the public key
 (or certificate) received in the SKE protocol.  After computing the
-receiver MUST verify the signature.  In case of public key authentication
-also this payload is encrypted.
+receiver MUST verify the signature.  Also in case of public key
+authentication this payload is encrypted.
 
 
 .ti 0
@@ -1177,7 +1196,7 @@ key algorithm and MAC algorithms.
 3.10.1 Ciphers
 
 Cipher is the encryption algorithm that is used to protect the data
-in the SILC packets.  See [SILC2] of the actual encryption process and
+in the SILC packets.  See [SILC2] for the actual encryption process and
 definition of how it must be done.  SILC has a mandatory algorithm that
 must be supported in order to be compliant with this protocol.
 
@@ -1200,11 +1219,11 @@ mars-<len>-<mode>    MARS in <mode> mode, <len> bit key      (OPTIONAL)
 none                 No encryption                           (OPTIONAL)
 
 The <mode> is either "cbc", "ctr" or "rcbc".  Other encryption modes MAY
-be defined as to be used in SILC using the same format.  The <len> is
+be defined to be used in SILC using the same name format.  The <len> is
 either 256, 192 or 128 bit key length.  Also, additional ciphers MAY be
 defined to be used in SILC by using the same name format as above.
 
-Algorithm "none" does not perform any encryption process at all and 
+Algorithm "none" does not perform any encryption process at all and
 thus is not recommended to be used.  It is recommended that no client
 or server implementation would accept none algorithm except in special
 debugging mode.
@@ -1214,17 +1233,17 @@ debugging mode.
 3.10.1.1 CBC Mode
 
 The "cbc" encryption mode is CBC mode with inter-packet chaining.  This
-means that the Initial Vector (IV) for the next encryption block is
-the previous ciphertext block.  The very first IV MUST be random and is
-generated as described in [SILC3].
+means that the Initialization Vector (IV) for the next encryption block
+is the previous ciphertext block.  The very first IV MUST be random and
+is generated as described in [SILC3].
 
 
 .ti 0
 3.10.1.2 CTR Mode
 
-The "ctr" encryption mode is CTR mode.  The CTR mode in SILC is stateful
-in encryption and decryption.  Both sender and receiver maintain the
-counter for the CTR mode and thus can precompute the key stream for
+The "ctr" encryption mode is Counter Mode (CTR).  The CTR mode in SILC is 
+stateful in encryption and decryption.  Both sender and receiver maintain 
+the counter for the CTR mode and thus can precompute the key stream for
 encryption and decryption.  By default, CTR mode does not require
 plaintext padding, however implementations MAY apply padding to the
 packets.  If the last key block is larger than the last plaintext block
@@ -1238,8 +1257,8 @@ decryption operation is not needed since both encryption and decryption
 process is simple XOR with the plaintext block and the key stream block.
 
 The counter block is used to create the key for the CTR mode.  When
-SILC specifications refer to Initial Vector (IV) in general cases, in
-case of CTR mode it refers to the counter block.  The format of the
+SILC specifications refer to Initialization Vector (IV) in general cases, 
+in case of CTR mode it refers to the counter block.  The format of the
 128 bit counter block is as follows:
 
 .in 5
@@ -1290,7 +1309,7 @@ inappropriate.  For private messages, the Key Agreement could be
 performed to produce fresh key material.
 
 If the IV Included flag was negotiated in SKE, implementations SHOULD
-still use the same counter block format as defined above.  However, 
+still use the same counter block format as defined above.  However,
 implementations are RECOMMENDED to replace the Truncated HASH field
 with a 32 bit random value for each IV (counter block) per encrypted
 SILC packet.  Also note, that in this case the decryption process is
@@ -1309,17 +1328,19 @@ delivered to the recipient.  This mode increases the ciphertext size by
 one ciphertext block.  Note also that some data payloads in SILC are
 capable of delivering the IV to the recipient.  When explicitly
 encrypting these payloads with randomized CBC the IV MUST NOT be appended
-at the end of the ciphertext.  When encrypting these payloads with
-"cbc" mode they implicitly become randomized CBC since the IV is
-usually selected random and included in the ciphertext.  In these
-cases using either CBC or randomized CBC is actually equivalent.
+at the end of the ciphertext, but is placed at the specified location
+in the payload.  However, Message Payload for example has the IV at
+the location which is equivalent to placing it after the last ciphertext
+block.  When using CBC mode with such payloads it is actually equivalent
+to using randomized CBC since the IV is selected in random and included
+in the ciphertext.
 
 
 .ti 0
 3.10.2 Public Key Algorithms
 
 Public keys are used in SILC to authenticate entities in SILC network
-and to perform other tasks related to public key cryptography.  The 
+and to perform other tasks related to public key cryptography.  The
 public keys are also used in the SILC Key Exchange protocol [SILC3].
 
 The following public key algorithms are defined in SILC protocol:
@@ -1346,13 +1367,24 @@ represented as sign().  The signature computing procedure is dependent
 of the public key algorithm, and the public key or certificate encoding.
 When using SILC public key the signature is computed as described in
 previous paragraph for RSA and DSS keys.  If the hash function is not
-specified separately for signing process sha1 MUST be used.  When using
+specified separately for signing process SHA-1 MUST be used.  When using
 SSH2 public keys the signature is computed as described in [SSH-TRANS].
 When using X.509 version 3 certificates the signature is computed as
 described in [PKCS7].  When using OpenPGP certificates the signature is
 computed as described in [PGP].
 
 
+.ti 0
+3.10.2.1 Multi-Precision Integers
+
+Multi-Precision (MP) integers in SILC are encoded and decoded as defined
+in PKCS #1 [PKCS1].  MP integers are unsigned, encoded with desired octet
+length.  This means that if the octet length is more than the actual
+length of the integer one or more leading zero octets will appear at the
+start of the encoding.  The actual length of the integer is the bit size
+of the integer not counting any leading zero bits.
+
+
 .ti 0
 3.10.3 Hash Functions
 
@@ -1374,7 +1406,7 @@ md5              MD5, length = 16        (RECOMMENDED)
 
 Data integrity is protected by computing a message authentication code
 (MAC) of the packet data.  See [SILC2] for details how to compute the
-MAC.
+MAC for a packet.
 
 The following MAC algorithms are defined in SILC protocol:
 
@@ -1391,9 +1423,9 @@ authenticated when MAC is not computed.  It is recommended that no
 client or server would accept none MAC except in special debugging
 mode.
 
-The HMAC algorithm is described in [HMAC] and hash algorithms that
-are used as part of the HMACs are described in [Scheneir] and in
-[Menezes].
+The HMAC algorithm is described in [HMAC].  The hash algorithms used
+in HMACs, the SHA-1 is described in [RFC3174] and MD5 is described
+in [RFC1321].
 
 Additional MAC algorithms MAY be defined to be used in SILC.
 
@@ -1417,7 +1449,6 @@ zlib        GNU ZLIB (LZ77) compression  (OPTIONAL)
 Additional compression algorithms MAY be defined to be used in SILC.
 
 
-
 .ti 0
 3.11 SILC Public Key
 
@@ -1430,6 +1461,12 @@ and to perform other tasks related to public key cryptography.
 The format of the SILC Public Key is as follows:
 
 
+
+
+
+
+
+
 .in 5
 .nf
                      1                   2                   3
@@ -1461,7 +1498,7 @@ Figure 5:  SILC Public Key
 
 .in 6
 o Public Key Length (4 bytes) - Indicates the full length
-  of the public key, not including this field.
+  of the SILC Public Key, not including this field.
 
 o Algorithm Name Length (2 bytes) - Indicates the length
   of the Algorithm Length field, not including this field.
@@ -1494,8 +1531,10 @@ o Identifier (variable length) - Indicates the identifier
 
   At least user name (UN) and host name (HN) MUST be provided as
   identifier.  The fields are separated by commas (`,').  If
-  comma is in the identifier string it must be written as `\\,',
-  for example, `O=Company XYZ\\, Inc.'.
+  comma is in the identifier string it must be escaped as `\\,',
+  for example, `O=Company XYZ\\, Inc.'.  Other characters that
+  require escaping are listed in [RFC2253] and are to be escaped
+  as defined therein.
 
 o Public Data (variable length) - Includes the actual
   public data of the public key.
@@ -1529,13 +1568,13 @@ o Public Data (variable length) - Includes the actual
 .in 3
 
 All fields in the public key are in MSB (most significant byte first)
-order.  All strings in the public key are UTF-8 encoded.
+order.  All strings in the public key MUST be UTF-8 encoded.
 
-If an external protocol need to refer to SILC Public Key by name, the
-name "silc-rsa" and "silc-dss" for SILC Public Key based on RSA algorithm
+If an external protocol needs to refer to SILC Public Key by name, the
+names "silc-rsa" and "silc-dss" for SILC Public Key based on RSA algorithm
 and SILC Public Key based on DSS algorithm, respectively, are to be used.
-However, this SILC specification does not use these names directly, and 
-they are defined here for external protocols (protocols that may like 
+However, this SILC specification does not use these names directly, and
+they are defined here for external protocols (protocols that may like
 to use SILC Public Key).
 
 
@@ -1559,14 +1598,14 @@ software version = <major>[.<minor>[.<build or vendor string>]]
 .in 3
 
 Protocol version MUST provide both major and minor version.  Currently
-implementations MUST set the protocol version and accept at least the 
-protocol version as SILC-1.2-<software version>.  If new protocol version 
-causes incompatibilities with older version the <minor> version number 
-MUST be incremented.  The <major> is incremented if new protocol version 
+implementations MUST set the protocol version and accept at least the
+protocol version as SILC-1.2-<software version>.  If new protocol version
+causes incompatibilities with older version the <minor> version number
+MUST be incremented.  The <major> is incremented if new protocol version
 is fully incompatible.
 
 Software version MAY provide major, minor and build (vendor) version.
-The software version MAY be freely set and accepted.  The version string 
+The software version MAY be freely set and accepted.  The version string
 MUST consist of printable US-ASCII characters.
 
 Thus, the version strings could be, for example:
@@ -1582,13 +1621,13 @@ SILC-1.2-2.4.5 Vendor Limited
 .ti 0
 3.13 Backup Routers
 
-Backup routers may exist in the cell in addition of the primary router.
-However, they must not be active routers and act as routers in the cell.
+Backup routers may exist in the cell in addition to the primary router.
+However, they must not be active routers or act as routers in the cell.
 Only one router may be acting as primary router in the cell.  In the case
-of failure of the primary router may one of the backup routers become
-active.  The purpose of backup routers are in case of failure of the
-primary router to maintain working connections inside the cell and outside
-the cell and to avoid netsplits.
+of failure of the primary router one of the backup routers becomes active.
+The purpose of backup routers are in case of failure of the primary router
+to maintain working connections inside the cell and outside the cell and
+to avoid netsplits.
 
 Backup routers are normal servers in the cell that are prepared to take
 over the tasks of the primary router if needed.  They need to have at
@@ -1608,18 +1647,18 @@ able to take over the tasks of the primary router.  It is the primary
 router's responsibility to feed the data to the backup router.  If the
 backup router does not know all the data in the case of failure some
 connections may be lost.  The primary router of the cell must consider
-the backup router being actual router server when it feeds the data to
-it.
+the backup router being an actual router server when it feeds the data
+to it.
 
-In addition of having direct connection to the primary router of the
+In addition to having direct connection to the primary router of the
 cell, the backup router must also have connection to the same router
-the primary router of the cell is connected.  However, it must not be
-active router connection meaning that the backup router must not use
-that channel as its primary route and it must not notify the router
-about having connected servers, channels and clients behind it.  It
-merely connects to the router.  This sort of connection is later
-referred as being passive connection.  Some keepalive actions may be
-needed by the router to keep the connection alive.
+to which the primary router of the cell is connected.  However, it must 
+not be the active router connection meaning that the backup router must 
+not use that channel as its primary route and it must not notify the 
+router about having connected servers, channels and clients behind it.
+It merely connects to the router.  This sort of connection is later
+referred to as being a passive connection.  Some keepalive actions may
+be needed by the router to keep the connection alive.
 
 It is required that other normal servers have passive connections to
 the backup router(s) in the cell.  Some keepalive actions may be needed
@@ -1633,14 +1672,14 @@ to the cell's backup router.  It too is prepared to switch to use the
 backup router as its new primary router as soon as the original primary
 router becomes unresponsive.
 
-All of the parties of this protocol knows which one is the backup router
-of the cell from their local configuration.  Each of the entity must
+All of the parties of this protocol know which one is the backup router
+of the cell from their local configuration.  Each of the entities must
 be configured accordingly and care must be taken when configuring the
 backup routers, servers and other routers in the network.
 
 It must be noted that some of the channel messages and private messages
 may be lost during the switch to the backup router.  The announcements
-assures that the state of the network is not lost during the switch.
+assure that the state of the network is not lost during the switch.
 
 It is RECOMMENDED that there would be at least one backup router in
 the cell.  It is NOT RECOMMENDED to have all servers in the cell acting
@@ -1648,13 +1687,12 @@ as backup routers as it requires establishing several connections to
 several servers in the cell.  Large cells can easily have several
 backup routers in the cell.
 
-The order of the backup routers are decided at the configuration phase.
-All the parties of this protocol must be configured accordingly to 
-understand the order of the backup routers.  It is not required that
-the backup server is actually active server in the cell.  Backup router
-may be a spare server in the cell that does not accept normal client
+The order of the backup routers are decided at the local configuration
+phase.  All the parties of this protocol must be configured accordingly to
+understand the order of the backup routers.  It is not required that the
+backup server is actually an active server in the cell.  The backup router
+may be a redundant server in the cell that does not accept normal client
 connections at all.  It may be reserved purely for the backup purposes.
-These, however, are cell management issues.
 
 If also the first backup router is down as well and there is another
 backup router in the cell then it will start acting as the primary
@@ -1681,28 +1719,32 @@ database to understand that the route to the primary router will now go
 to the backup router.
 
 Servers connected to the backup router MUST send SILC_PACKET_RESUME_ROUTER
-packet with type number 21, to indicate that the server will start using
+packet with type value 21, to indicate that the server will start using
 the backup router as primary router.  The backup router MUST NOT allow
 this action if it detects that primary is still up and running.  If
-backup router knows that primary is up and running it MUST send type
-number 22 back to the server.  The server then MUST NOT use the backup
-as primary router, but must try to establish connection back to the
-primary router.  If the action is allowed type number 21 is sent back
-to the server from the backup router.
+backup router knows that primary is up and running it MUST send
+SILC_PACKET_FAILURE with type value 21 (4 bytes, MSB first order) back
+to the server.  The server then MUST NOT use the backup as primary
+router, but must try to establish connection back to the primary router.
+If the action is allowed type value 21 is sent back to the server from
+the backup router.  It is RECOMMENDED that implementations use the
+SILC_COMMAND_PING command to detect whether primary router is responsive.
 
 The servers connected to the backup router must then announce their
-clients, channels, channel users, channel user modes and channel modes
-to the backup router.  This is to assure that none of the important notify 
-packets were lost during the switch to the backup router.  The backup
-router must check which of these announced entities it already have
-and distribute the new ones to the primary route.
+clients, channels, channel users, channel user modes, channel modes,
+topics and other information to the backup router.  This is to assure
+that none of the important notify packets were lost during the switch
+to the backup router.  The backup router must check which of these
+announced entities it already has and distribute the new ones to the
+primary router.
 
 The backup router too must announce its servers, clients, channels
 and other information to the new primary router.  The primary router
-of the backup router too must announce its informations to the backup
+of the backup router too must announce its information to the backup
 router.  Both must process only the ones they do not know about.  If
-any of the announced modes does not match then they are enforced in
-normal manner defined later in this specification.
+any of the announced modes do not match then they are enforced in
+normal manner as defined in section 4.2.1 Announcing Clients, Channels
+and Servers.
 
 
 .ti 0
@@ -1720,7 +1762,7 @@ When the connection is established to the primary router the backup
 resuming protocol is executed.  The protocol is advanced as follows:
 
   1. Backup router sends SILC_PACKET_RESUME_ROUTER packet with type
-     value 1 the primary router that came back online.  The packet
+     value 1 to the primary router that came back online.  The packet
      will indicate the primary router has been replaced by the backup
      router.  After sending the packet the backup router will announce
      all of its channels, channel users, modes etc. to the primary
@@ -1729,144 +1771,112 @@ resuming protocol is executed.  The protocol is advanced as follows:
      If the primary knows that it has not been replaced (for example
      the backup itself disconnected from the primary router and thinks
      that it is now primary in the cell) the primary router send
-     SILC_PACKET_FAILURE with the type value 1 back to the backup
-     router.  If backup receives this it MUST NOT continue with the
-     backup resuming protocol.
+     SILC_PACKET_FAILURE with the type value 1 (4 bytes, MSB first
+     order) back to the backup router.  If backup receives this it
+     MUST NOT continue with the backup resuming protocol.
 
   2. Backup router sends SILC_PACKET_RESUME_ROUTER packet with type
-     value 2 to its current primary router to indicate that it will
+     value 1 to its current primary router to indicate that it will
      resign as being primary router.  Then, backup router sends the
      SILC_PACKET_RESUME_ROUTER packet with type value 1 to all
      connected servers to also indicate that it will resign as being
      primary router.
 
   3. Backup router also send SILC_PACKET_RESUME_ROUTER packet with
-     type value 2 to the router that is using the backup router
+     type value 1 to the router that is using the backup router
      currently as its primary router.
 
   4. Any server and router that receives the SILC_PACKET_RESUME_ROUTER
-     with type value 1 or 2 must reconnect immediately to the
-     primary router of the cell that came back online.  After they
-     have created the connection they MUST NOT use that connection
-     as active primary route but still route all packets to the
-     backup router.  After the connection is created they MUST send
-     SILC_PACKET_RESUME_ROUTER with type value 3 back to the
-     backup router.  The session ID value found in the first packet
-     MUST be set in this packet.
-
-  5. Backup router MUST wait for all packets with type value 3 before
+     with type value 1 must reconnect immediately to the primary
+     router of the cell that came back online.  After they have created
+     the connection they MUST NOT use that connection as active primary
+     route but still route all packets to the backup router.  After
+     the connection is created they MUST send SILC_PACKET_RESUME_ROUTER
+     with type value 2 back to the backup router.  The session ID value
+     found in the first packet MUST be set in this packet.
+
+  5. Backup router MUST wait for all packets with type value 2 before
      it continues with the protocol.  It knows from the session ID values
-     set in the packet when it have received all packets.  The session
-     value should be different in all packets it have sent earlier.
-     After the packets is received the backup router sends the
-     SILC_PACKET_RESUME_ROUTER packet with type value 4 to the
-     primary router that came back online.  This packet will indicate 
+     set in the packet when it has received all packets.  The session
+     value should be different in all packets it has sent earlier.
+     After the packets are received the backup router sends the
+     SILC_PACKET_RESUME_ROUTER packet with type value 3 to the
+     primary router that came back online.  This packet will indicate
      that the backup router is now ready to resign as being primary
      router.  The session ID value in this packet MUST be the same as
-     in first packet sent to the primary router.  During this time
+     in the first packet sent to the primary router.  During this time
      the backup router must still route all packets it is receiving
      from server connections.
 
-  6. The primary router receives the packet and send the
-     SILC_PACKET_RESUME_ROUTER with type value 5 to all connected servers
+  6. The primary router receives the packet and send the packet
+     SILC_PACKET_RESUME_ROUTER with type value 4 to all connected servers
      including the backup router.  It also sends the packet with type
-     value 6 to its primary router, and to the router that is using
+     value 4 to its primary router, and to the router that is using
      it as its primary router.  The Session ID value in this packet
      SHOULD be zero (0).
 
   7. Any server and router that receives the SILC_PACKET_RESUME_ROUTER
-     with type value 5 or 6 must switch their primary route to the
-     new primary router and remove the route for the backup router, since
-     it is not anymore the primary router of the cell.  They must also
+     packet with type value 4 must switch their primary route to the new
+     primary router and remove the route for the backup router, since
+     it is no longer the primary router of the cell.  They must also
      update their local database to understand that the clients are
      not originated from the backup router but from the locally connected
      servers.  After that they MUST announce their channels, channel
-     users, modes etc. to the primary router.  They must not use the
+     users, modes etc. to the primary router.  They MUST NOT use the
      backup router connection after this and the connection is considered
-     to be passive connection.  The implementations SHOULD be able
+     to be a passive connection.  The implementation SHOULD be able
      to disable the connection without closing the actual link.
 
-After this protocol is executed the backup router is now again normal
+After this protocol is executed the backup router is now again normal
 server in the cell that has the backup link to the primary router.  The
 primary router feeds the router specific data again to the backup router.
-All server connections in the backup router are considered passive
+All server connections to the backup router are considered passive
 connections.
 
 When the primary router of the cell comes back online and connects
-to its primary router, the remote primary router must send the 
-SILC_PACKET_RESUME_ROUTER with type value 20 indicating that the
+to its remote primary router, the remote primary router MUST send the
+SILC_PACKET_RESUME_ROUTER packet with type value 20 indicating that the
 connection is not allowed since the router has been replaced by an
-backup router.  The session ID value in this packet SHOULD be zero (0).
-When the router receives this packet it must not use the connection
-as active connection but to understand that it cannot act as primary
-router in the cell.  It must wait that the backup router connects to
-it, and the backup resuming protocol is executed.
+backup router in the cell.  The session ID value in this packet SHOULD be 
+zero (0).  When the primary router receives this packet it MUST NOT use 
+the connection as active connection but must understand that it cannot
+act as primary router in the cell, until the backup resuming protocol has
+been executed.
 
 The following type values has been defined for SILC_PACKET_RESUME_ROUTER
 packet:
 
   1    SILC_SERVER_BACKUP_START
-  2    SILC_SERVER_BACKUP_START_GLOBAL
-  3    SILC_SERVER_BACKUP_START_CONNECTED
-  4    SILC_SERVER_BACKUP_START_ENDING
-  5    SILC_SERVER_BACKUP_START_RESUMED
-  6    SILC_SERVER_BACKUP_START_RESUMED_GLOBAL
+  2    SILC_SERVER_BACKUP_START_CONNECTED
+  3    SILC_SERVER_BACKUP_START_ENDING
+  4    SILC_SERVER_BACKUP_START_RESUMED
   20   SILC_SERVER_BACKUP_START_REPLACED
   21   SILC_SERVER_BACKUP_START_USE
-  22   SILC_SERVER_BACKUP_START_USE_DENIED
 
-If any other value is found in the type field the packet must be 
+If any other value is found in the type field the packet MUST be
 discarded.  The SILC_PACKET_RESUME_ROUTER packet and its payload
 is defined in [SILC2].
 
 
-
-
-.ti 0
-3.13.3 Discussion on Backup Router Scheme
-
-It is clear that this backup router support is not able to handle all
-possible situations arising in unreliable network environment.  This
-scheme for example does not handle situation when the router actually
-does not go offline but the network link goes down temporarily.  It would
-require some intelligence to figure out when it is best time to switch
-to the backup router.  To make it even more complicated it is possible
-that the backup router may have not lost the network link to the primary
-router.
-
-Other possible situation is when the network link is lost temporarily
-between two primary routers in the SILC network.  Unless the routers
-notice the link going down they cannot perhaps find alternative routes.
-Worst situation is when the link goes down only for a short period of
-time, thus causing lag.  Should the routers or servers find alternative
-routes if they cannot get response from the router during the lag?
-When alternative routes are being found it must be careful not to
-mess up existing primary routes between routers in the network.
-
-It is suggested that the current backup router scheme is only temporary
-solution and existing backup router protocols are studied further.  It
-is also suggested that the backup router specification will be separated
-from this SILC specification Internet-Draft and additional specification
-is written on the subject.
-
-
 .ti 0
 4 SILC Procedures
 
-This section describes various SILC procedures such as how the 
+This section describes various SILC procedures such as how the
 connections are created and registered, how channels are created and
-so on.  The section describes the procedures only generally as details
-are described in [SILC2] and [SILC3].
+so on.  The references [SILC2], [SILC3] and [SILC4] permeate this 
+section's definitions.
+
+
 
 
 .ti 0
 4.1 Creating Client Connection
 
-This section describes the procedure when client connects to SILC server.
-When client connects to server the server MUST perform IP address lookup
-and reverse IP address lookup to assure that the origin host really is
-who it claims to be.  Client, host, connecting to server SHOULD have 
-both valid IP address and fully qualified domain name (FQDN).
+This section describes the procedure when a client connects to SILC
+server.  When client connects to server the server MUST perform IP
+address lookup and reverse IP address lookup to assure that the origin 
+host really is who it claims to be.  Client, a host, connecting to server 
+SHOULD have both valid IP address and fully qualified domain name (FQDN).
 
 After that the client and server performs SILC Key Exchange protocol
 which will provide the key material used later in the communication.
@@ -1877,11 +1887,11 @@ is described in [SILC3].
 Typical server implementation would keep a list of connections that it
 allows to connect to the server.  The implementation would check, for
 example, the connecting client's IP address from the connection list
-before the SILC Key Exchange protocol has been started.  Reason for
+before the SILC Key Exchange protocol has been started.  The reason for
 this is that if the host is not allowed to connect to the server there
 is no reason to perform the key exchange protocol.
 
-After successful key exchange protocol the client and server performs
+After successful key exchange protocol the client and server perform
 connection authentication protocol.  The purpose of the protocol is to
 authenticate the client connecting to the server.  Flexible
 implementation could also accept the client to connect to the server
@@ -1892,12 +1902,12 @@ MUST be terminated.  The connection authentication protocol is described
 in [SILC3].
 
 After successful key exchange and authentication protocol the client
-registers itself by sending SILC_PACKET_NEW_CLIENT packet to the
+MUST register itself by sending SILC_PACKET_NEW_CLIENT packet to the
 server.  This packet includes various information about the client
-that the server uses to create the client.  Server creates the client
-and sends SILC_PACKET_NEW_ID to the client which includes the created
-Client ID that the client MUST start using after that.  After that
-all SILC packets from the client MUST have the Client ID as the
+that the server uses to register the client.  Server registers the
+client and sends SILC_PACKET_NEW_ID to the client which includes the 
+created Client ID that the client MUST start using after that.  After
+that all SILC packets from the client MUST have the Client ID as the
 Source ID in the SILC Packet Header, described in [SILC2].
 
 Client MUST also get the server's Server ID that is to be used as
@@ -1909,22 +1919,22 @@ or to send SILC_COMMAND_INFO command and receive the Server ID as
 command reply.
 
 Server MAY choose not to use the information received in the
-SILC_PACKET_NEW_CLIENT packet.  For example, if public key or 
-certificate were used in the authentication, server MAY use those
-informations rather than what it received from client.  This is suitable
+SILC_PACKET_NEW_CLIENT packet.  For example, if public key or
+certificate were used in the authentication, server MAY use that
+information rather than what it received from client.  This is a suitable
 way to get the true information about client if it is available.
 
 The nickname of client is initially set to the username sent in the
-SILC_PACKET_NEW_CLIENT packet.  User should set the nickname to more
-suitable by sending SILC_COMMAND_NICK command.  However, this is not
-required as part of registration process.
+SILC_PACKET_NEW_CLIENT packet.  User may set the nickname to something
+more desirable by sending SILC_COMMAND_NICK command.  However, this is
+not required as part of registration process.
 
 Server MUST also distribute the information about newly registered
 client to its router (or if the server is router, to all routers in
 the SILC network).  More information about this in [SILC2].
 
 Router server MUST also check whether some client in the local cell
-is watching for the nickname this new client has, and send the 
+is watching for the nickname this new client has, and send the
 SILC_NOTIFY_TYPE_WATCH to the watcher.
 
 
@@ -1933,27 +1943,29 @@ SILC_NOTIFY_TYPE_WATCH to the watcher.
 
 This section describes the procedure when server connects to its
 router (or when router connects to other router, the cases are
-equivalent).  The procedure is very much alike when client connects
-to the server thus it is not repeated here.
+equivalent).  The procedure is very much alike to when a client
+connects to the server thus it is not repeated here.
 
 One difference is that server MUST perform connection authentication
 protocol with proper authentication.  A proper authentication is based
 on passphrase authentication or public key authentication based on
 digital signatures.
 
-After server and router has successfully performed the key exchange
-and connection authentication protocol, the server register itself
+After server and router have successfully performed the key exchange
+and connection authentication protocol, the server MUST register itself
 to the router by sending SILC_PACKET_NEW_SERVER packet.  This packet
 includes the server's Server ID that it has created by itself and
-other relevant information about the server.
+other relevant information about the server.  The router receiving the
+ID MUST verify that the IP address in the Server ID is same as the
+server's real IP address.
 
 After router has received the SILC_PACKET_NEW_SERVER packet it
 distributes the information about newly registered server to all routers
-in the SILC network.  More information about this in [SILC2].
+in the SILC network.  More information about this is in [SILC2].
 
-As client needed to resolve the destination ID this MUST be done by the
-server that connected to the router, as well.  The way to resolve it is
-to get the ID from previously received packet.  The server MAY also 
+As the client needed to resolve the destination ID this MUST be done by 
+the server that connected to the router, as well.  The way to resolve it 
+is to get the ID from previously received packet.  The server MAY also
 use SILC_COMMAND_INFO command to resolve the ID.  Server MUST also start
 using its own Server ID as Source ID in SILC Packet Header and the
 router's Server ID as Destination when communicating with the router.
@@ -1974,8 +1986,8 @@ Channels' mode and founder public key and other channel mode specific
 data is announced by sending SILC_NOTIFY_TYPE_CMODE_CHANGE notify list.
 Also, the channel users on the channels must be announced by compiling a
 list of Notify Payloads with the SILC_NOTIFY_TYPE_JOIN notify type into
-the SILC_PACKET_NOTIFY packet.  The users' modes on the channel must 
-also be announced by compiling list of Notify Payloads with the 
+the SILC_PACKET_NOTIFY packet.  The users' modes on the channel must
+also be announced by compiling list of Notify Payloads with the
 SILC_NOTIFY_TYPE_CUMODE_CHANGE notify type into the SILC_PACKET_NOTIFY
 packet.
 
@@ -1984,12 +1996,12 @@ ID Payloads into the SILC_PACKET_NEW_ID packet.
 
 Also, clients' modes (user modes in SILC) MUST be announced.  This is
 done by compiling a list of Notify Payloads with SILC_NOTIFY_UMODE_CHANGE
-notify type into the SILC_PACKET_NOTIFY packet.  Also, channel's topics
+notify type into the SILC_PACKET_NOTIFY packet.  Also, channels' topics
 MUST be announced by compiling a list of Notify Payloads with the
 SILC_NOTIFY_TOPIC_SET notify type into the SILC_PACKET_NOTIFY packet.
 
 The router which receives these lists MUST process them and broadcast
-the packets to its primary route.  When processing the announced channels
+the packets to its primary router.  When processing the announced channels
 and channel users the router MUST check whether a channel exists already
 with the same name.  If channel exists with the same name it MUST check
 whether the Channel ID is different.  If the Channel ID is different the
@@ -2003,10 +2015,10 @@ The router MUST also generate new channel key and distribute it to the
 channel.  The key MUST NOT be generated if the SILC_CMODE_PRIVKEY mode
 is set.
 
-If the channel has channel founder on the router the router MUST send
-the notify type SILC_NOTIFY_TYPE_CUMODE_CHANGE to the server to force
-the mode change for the channel founder on the server.  The channel 
-founder privileges MUST be removed.
+If the channel has channel founder already on the router, the router
+MUST send the notify type SILC_NOTIFY_TYPE_CUMODE_CHANGE to the server
+to force the mode change for the channel founder on the server.  The
+channel founder privileges MUST be removed.
 
 The router processing the channels MUST also compile a list of
 Notify Payloads with the SILC_NOTIFY_TYPE_JOIN notify type into the
@@ -2023,7 +2035,7 @@ Client joins to channel by sending command SILC_COMMAND_JOIN to the
 server.  If the receiver receiving join command is normal server the
 server MUST check its local list whether this channel already exists
 locally.  This would indicate that some client connected to the server
-has already joined to the channel.  If this is case the client is
+has already joined to the channel.  If this is the case, the client is
 joined to the channel, new channel key is created and information about
 newly joined channel is sent to the router.  The router is informed
 by sending SILC_NOTIFY_TYPE_JOIN notify type.  The notify type MUST
@@ -2040,13 +2052,13 @@ server MUST also save the channel key.
 
 If the receiver of the join command is router it MUST first check its
 local list whether anyone in the cell has already joined to the channel.
-If this is the case the client is joined to the channel and reply is
+If this is the case, the client is joined to the channel and reply is
 sent to the client.  If the command was sent by server the command reply
 is sent to the server which sent it.  Then the router MUST also create
 new channel key and distribute it to all clients on the channel and
-all servers that has clients on the channel.  Router MUST also send
+all servers that have clients on the channel.  Router MUST also send
 the SILC_NOTIFY_TYPE_JOIN notify type to local clients on the channel
-and to local servers that has clients on the channel.
+and to local servers that have clients on the channel.
 
 If the channel does not exist on the router's local list it MUST
 check the global list whether the channel exists at all.  If it does
@@ -2055,15 +2067,15 @@ the channel does not exist the channel is created and the client
 is joined to the channel.  The channel key is also created and
 distributed as previously described.  The client joining to the created
 channel is made automatically channel founder and both channel founder
-and channel operator privileges is set for the client.
+and channel operator privileges are set for the client.
 
 If the router created the channel in the process, information about the
-new channel MUST be broadcasted to all routers.  This is done by 
+new channel MUST be broadcast to all routers.  This is done by
 broadcasting SILC_PACKET_NEW_CHANNEL packet to the router's primary
 route.  When the router joins the client to the channel it MUST also
 send information about newly joined client to all routers in the SILC
 network.  This is done by broadcasting the SILC_NOTIFY_TYPE_JOIN notify
-type to the router's primary route. 
+type to the router's primary route.
 
 It is important to note that new channel key is created always when
 new client joins to channel, whether the channel has existed previously
@@ -2072,7 +2084,7 @@ any of the old traffic on the channel.  Client which receives the reply to
 the join command MUST start using the received Channel ID in the channel
 message communication thereafter.  Client also receives the key for the
 channel in the command reply.  Note that the channel key is never
-generated if the SILC_CMODE_PRIVKEY mode is set.
+generated or distributed if the SILC_CMODE_PRIVKEY mode is set.
 
 
 .ti 0
@@ -2092,12 +2104,21 @@ the key is created only on the cell where the client, which left the
 channel, exists.  While the server or router is creating the new channel
 key, no other client may join to the channel.  Messages that are sent
 while creating the new key are still processed with the old key.  After
-server has sent the SILC_PACKET_CHANNEL_KEY packet MUST client start
+server has sent the SILC_PACKET_CHANNEL_KEY packet client MUST start
 using the new key.  If server creates the new key the server MUST also
-send the new key to its router.  See [SILC2] on more information about
+send the new key to its router.  See [SILC2] for more information about
 how channel messages must be encrypted and decrypted when router is
 processing them.
 
+If the key changes very often due to joining traffic on the channel it
+is RECOMMENDED that client implementation would cache some of the old
+channel keys for short period of time so that it is able to decrypt all
+channel messages it receives.  It is possible that on a heavy traffic
+channel a message encrypted with channel key that was just changed
+is received by client after the new key was set into use.  This is
+possible because not all clients may receive the new key at the same
+time, and may still be sending messages encrypted with the old key.
+
 When client receives the SILC_PACKET_CHANNEL_KEY packet with the
 Channel Key Payload it MUST process the key data to create encryption
 and decryption key, and to create the HMAC key that is used to compute
@@ -2117,8 +2138,9 @@ Note that the server also MUST save the channel key.
 Private messages are sent point to point.  Client explicitly destine
 a private message to specific client that is delivered to only to that
 client.  No other client may receive the private message.  The receiver
-of the private message is destined in the SILC Packet Header as any
-other packet as well.
+of the private message is destined in the SILC Packet Header as in any
+other packet as well.  The Source ID in the SILC Packet Header MUST be
+the ID of the sender of the message.
 
 If the sender of a private message does not know the receiver's Client
 ID, it MUST resolve it from server.  There are two ways to resolve the
@@ -2148,17 +2170,17 @@ is used in the private message communication between those clients.
 The key sent inside the payload SHOULD be randomly generated.  This
 packet MUST NOT be used to send pre-shared keys.
 
-Other choice is to entirely use keys that are not sent through
+Another choice is to entirely use keys that are not sent through
 the SILC network at all.  This significantly adds security.  This key
-could be a pre-shared-key that is known by both of the clients.  Both
-agree about using the key and starts sending packets that indicate
+could be a pre-shared key that is known by both of the clients.  Both
+agree about using the key and start sending packets that indicate
 that the private message is secured using private message key.  In
 case of pre-shared keys (static keys) the IV used in encryption SHOULD
 be chosen randomly.
 
 It is also possible to negotiate fresh key material by performing
 Key Agreement.  The SILC_PACKET_KEY_AGREEMENT packet MAY be used to
-negotiate the fresh key material.  In this case the resulted key
+negotiate the fresh key material.  In this case the resulting key
 material is used to secure the private messages.  Also, the IV used
 in encryption is used as defined in [SILC3], unless otherwise stated
 by the encryption mode used.  By performing Key Agreement the clients
@@ -2177,14 +2199,16 @@ mandatory cipher and HMAC in private message encryption.
 .ti 0
 4.7 Channel Message Sending and Reception
 
-Channel messages are delivered to group of users.  The group forms a
+Channel messages are delivered to group of users.  The group forms a
 channel and all clients on the channel receives messages sent to the
-channel.
+channel.  The Source ID in the SILC Packet Header MUST be the ID
+of the sender of the message.
 
-Channel messages are destined to channel by specifying the Channel ID
+Channel messages are destined to channel by specifying the Channel ID
 as Destination ID in the SILC Packet Header.  The server MUST then
 distribute the message to all clients on the channel by sending the
-channel message destined explicitly to a client on the channel.
+channel message destined explicitly to a client on the channel.  However,
+the Destination ID MUST still remain as the Channel ID.
 
 If server receives a channel message packet which includes invalid
 destination Channel ID the server MUST send SILC_NOTIFY_TYPE_ERROR
@@ -2212,7 +2236,7 @@ will perform the SKE protocol.
 
 If PFS flag was set the resulted key material is processed as described
 in the section Processing the Key Material in [SILC3].  The difference
-with re-key in the processing is that the initial data for the hash 
+with re-key in the processing is that the initial data for the hash
 function is just the resulted key material and not the HASH as it
 is not computed at all with re-key.  Other than that, the key processing
 it equivalent to normal SKE negotiation.
@@ -2226,7 +2250,7 @@ the initial data for the hash function is the current sending encryption
 key and not the SKE's KEY and HASH values.  Other than that, the key
 processing is equivalent to normal SKE negotiation.
 
-After both parties has regenerated the session key, both MUST send
+After both parties have regenerated the session key, both MUST send
 SILC_PACKET_REKEY_DONE packet to each other.  These packets are still
 secured with the old key.  After these packets, the subsequent packets
 MUST be protected with the new key.
@@ -2237,37 +2261,35 @@ MUST be protected with the new key.
 
 Client usually sends the commands in the SILC network.  In this case
 the client simply sends the command packet to server and the server
-processes it and replies with command reply packet.  See the [SILC3]
+processes it and replies with command reply packet.  See the [SILC4]
 for detailed description of all commands.
 
-However, if the server is not able to process the command, it is sent 
-to the server's router.  This is case for example with commands such
-as, SILC_COMMAND_JOIN and SILC_COMMAND_WHOIS commands.  However, there
-are other commands as well.  For example, if client sends the WHOIS
+However, if the server is not able to process the command, it is sent to
+the server's router.  This is case for example with commands such as
+SILC_COMMAND_JOIN and SILC_COMMAND_WHOIS commands.  However, there are
+other commands as well [SILC4].  For example, if client sends the WHOIS
 command requesting specific information about some client the server must
-send the WHOIS command to router so that all clients in SILC network
-are searched.  The router, on the other hand, sends the WHOIS command
-further to receive the exact information about the requested client.
-The WHOIS command travels all the way to the server which owns the client
-and it replies with command reply packet.  Finally, the server which
-sent the command receives the command reply and it must be able to
-determine which client sent the original command.  The server then
-sends command reply to the client.  Implementations should have some
-kind of cache to handle, for example, WHOIS information.  Servers
-and routers along the route could all cache the information for faster
-referencing in the future.
+send the WHOIS command to router so that all clients in SILC network are
+searched.  The router, on the other hand, sends the WHOIS command further
+to receive the exact information about the requested client.  The WHOIS
+command travels all the way to the server which owns the client and it
+replies with command reply packet.  Finally, the server which sent the
+command receives the command reply and it must be able to determine which
+client sent the original command.  The server then sends command reply to
+the client.  Implementations should have some kind of cache to handle, for
+example, WHOIS information.  Servers and routers along the route could all
+cache the information for faster referencing in the future.
 
 The commands sent by server may be sent hop by hop until someone is able
 to process the command.  However, it is preferred to destine the command
 as precisely as it is possible.  In this case, other routers en route
 MUST route the command packet by checking the true sender and true
 destination of the packet.  However, servers and routers MUST NOT route
-command reply packets to clients coming from other server.  Client
+command reply packets to clients coming from other servers.  Client
 MUST NOT accept command reply packet originated from anyone else but
 from its own server.
 
 
-
 .ti 0
 4.10 Closing Connection
 
@@ -2280,15 +2302,17 @@ When remote server or router connection is closed the server or router
 MUST also remove all the clients that was behind the server or router
 from the SILC Network.  The server or router MUST also send the notify
 type SILC_NOTIFY_TYPE_SERVER_SIGNOFF to its primary router and to all
-local clients that are joined on the same channels with the remote 
+local clients that are joined on the same channels with the remote
 server's or router's clients.
 
 Router server MUST also check whether some client in the local cell
-is watching for the nickname this client has, and send the 
+is watching for the nickname this client has, and send the
 SILC_NOTIFY_TYPE_WATCH to the watcher, unless the client which left
 the network has the SILC_UMODE_REJECT_WATCHING user mode set.
 
 
+
+
 .ti 0
 4.11 Detaching and Resuming a Session
 
@@ -2301,7 +2325,7 @@ any server in the network.
 When client wishes to detach from the network it MUST send the
 SILC_COMMAND_DETACH command to its server.  The server then MUST set
 SILC_UMODE_DETACHED mode to the client and send SILC_NOTIFY_UMODE_CHANGE
-notify to its primary router, which will then MUST broadcast it further
+notify to its primary router, which then MUST broadcast it further
 to other routers in the network.  This user mode indicates that the
 client is detached from the network.  Implementations MUST NOT use
 the SILC_UMODE_DETACHED flag to determine whether a packet can be sent
@@ -2327,12 +2351,12 @@ completed the client MUST NOT send SILC_PACKET_NEW_CLIENT packet, but
 MUST send SILC_PACKET_RESUME_CLIENT packet.  This packet is used to
 perform the resuming procedure.  The packet MUST include the detached
 client's Client ID, which the client must know.  It also includes
-Authentication Payload which includes signature made with the client's
-private key.  The signature is computed as defined in the section
-3.9.1.  Thus, the authentication method MUST be based in public key
-authentication.
+Authentication Payload which includes signature computed with the
+client's private key.  The signature is computed as defined in the
+section 3.9.1.  Thus, the authentication method MUST be based in
+public key authentication.
 
-When server receives the SILC_PACKET_RESUME_CLIENT packet it MUST
+When server receive the SILC_PACKET_RESUME_CLIENT packet it MUST
 do the following:  Server checks that the Client ID is valid client
 and that it has the SILC_UMODE_DETACHED mode set.  Then it verifies
 the Authentication Payload with the detached client's public key.
@@ -2349,35 +2373,35 @@ server whom owned the detached client.
 
 The servers and routers that receives the SILC_PACKET_RESUME_CLIENT
 packet MUST know whether the packet already has been received for
-the client.  It is protocol error to attempt to resume the client
+the client.  It is protocol error to attempt to resume the client
 session from more than one server.  The implementations could set
 internal flag that indicates that the client is resumed.  If router
 receive SILC_PACKET_RESUME_CLIENT packet for client that is already
 resumed the client MUST be killed from the network.  This would
 indicate that the client is attempting to resume the session more
-than once which is protocol error.  In this case the router sends
+than once which is protocol error.  In this case the router sends
 SILC_NOTIFY_TYPE_KILLED to the client.  All routers that detect
 the same situation MUST also send the notify for the client.
 
 The servers and routers that receive the SILC_PACKET_RESUME_CLIENT
 must also understand that the client may not be found behind the
 same server that it originally came from.  They must update their
-caches according this.  The server that now owns the client session
+caches according to this.  The server that now owns the client session
 MUST check whether the Client ID of the resumed client is based
 on the server's Server ID.  If it is not it creates a new Client
 ID and send SILC_NOTIFY_TYPE_NICK_CHANGE to the network.  It MUST
-also send the channel keys of all channels that the client is
+also send the channel keys of all channels that the client has 
 joined to the client since it does not have them.  Whether the
 Client ID was changed or not the server MUST send SILC_PACKET_NEW_ID
-packet to the client.  Only after this the client is resumed back
+packet to the client.  Only after this is the client resumed back
 to the network and may start sending packets and messages.
 
-It is also possible that the server does not know about the channels
-that the client has joined.  In this case it join the client internally
-to the channels, generate new channel keys and distribute the keys
+It is also possible that the server did not know about the global
+channels before the client resumed.  In this case it joins the client
+to the channels, generates new channel keys and distributes the keys
 to the channels as described in section 4.4.
 
-It is implementation issue for how long servers keep detached client
+It is an implementation issue for how long servers keep detached client
 sessions.  It is RECOMMENDED that the detached sessions would be
 persistent as long as the server is running.
 
@@ -2391,12 +2415,12 @@ such as keeping private keys truly private and using adequate lengths for
 symmetric and asymmetric keys must be followed in order to maintain the
 security of this protocol.
 
-Special attention must also be paid on the servers and routers that are
+Special attention must also be paid to the servers and routers that are
 running the SILC service.  The SILC protocol's security depends greatly
 on the security and the integrity of the servers and administrators that
 are running the service.  It is recommended that some form of registration
-is required by the server and router administrator prior acceptance to
-the SILC Network.  Even though, the SILC protocol is secure in a network
+is required by the server and router administrator prior to acceptance to
+the SILC Network.  Even though the SILC protocol is secure in a network
 of mutual distrust between clients, servers, routers and administrators
 of the servers, the client should be able to trust the servers they are
 using if they wish to do so.
@@ -2405,25 +2429,25 @@ It however must be noted that if the client requires absolute security
 by not trusting any of the servers or routers in the SILC Network, it can
 be accomplished by negotiating private keys outside the SILC Network,
 either using SKE or some other key exchange protocol, or to use some
-other external means for distributing the keys.  This applies for all 
+other external means for distributing the keys.  This applies for all
 messages, private messages and channel messages.
 
-It is important to note that SILC, like any other security protocol is
-not full proof system; the SILC servers and routers could very well be
-compromised.  However, to provide acceptable level of security and
-usability for end user the protocol use many times session keys or other
-keys generated by the servers to secure the messages.  This is
-intentional design feature to allow ease of use for end user.  This way
+It is important to note that SILC, like any other security protocol, is
+not a foolproof system; the SILC servers and routers could very well be
+compromised.  However, to provide an acceptable level of security and
+usability for end users, the protocol uses many times session keys or 
+other keys generated by the servers to secure the messages.  This is an
+intentional design feature to allow ease of use for end users.  This way
 the network is still usable, and remains encrypted even if the external
 means of distributing the keys is not working.  The implementation,
-however, may like to not follow this design feature, and always negotiate
-the keys outside SILC network.  This is acceptable solution and many times
-recommended.  The implementation still must be able to work with the
-server generated keys.
+however, may like to not follow this design feature, and may always
+negotiate the keys outside SILC network.  This is an acceptable solution 
+and many times recommended.  The implementation still must be able to
+work with the server generated keys.
 
 If this is unacceptable for the client or end user, the private keys
 negotiated outside the SILC Network should always be used.  In the end
-it is always implementor's choice whether to negotiate private keys by
+it is the implementor's choice whether to negotiate private keys by 
 default or whether to use the keys generated by the servers.
 
 It is also recommended that router operators in the SILC Network would
@@ -2438,7 +2462,7 @@ should have a forum to discuss the cell management issues.
 [SILC2]      Riikonen, P., "SILC Packet Protocol", Internet Draft,
              May 2002.
 
-[SILC3]      Riikonen, P., "SILC Key Exchange and Authentication 
+[SILC3]      Riikonen, P., "SILC Key Exchange and Authentication
              Protocols", Internet Draft, May 2002.
 
 [SILC4]      Riikonen, P., "SILC Commands", Internet Draft, May 2002.
@@ -2458,7 +2482,7 @@ should have a forum to discuss the cell management issues.
 [IRC-SERVER] Kalt, C., "Internet Relay Chat: Server Protocol", RFC
              2813, April 2000.
 
-[SSH-TRANS]  Ylonen, T., et al, "SSH Transport Layer Protocol", 
+[SSH-TRANS]  Ylonen, T., et al, "SSH Transport Layer Protocol",
              Internet Draft.
 
 [PGP]        Callas, J., et al, "OpenPGP Message Format", RFC 2440,
@@ -2467,7 +2491,7 @@ should have a forum to discuss the cell management issues.
 [SPKI]       Ellison C., et al, "SPKI Certificate Theory", RFC 2693,
              September 1999.
 
-[PKIX-Part1] Housley, R., et al, "Internet X.509 Public Key 
+[PKIX-Part1] Housley, R., et al, "Internet X.509 Public Key
              Infrastructure, Certificate and CRL Profile", RFC 2459,
              January 1999.
 
@@ -2499,9 +2523,19 @@ should have a forum to discuss the cell management issues.
 [RFC2279]    Yergeau, F., "UTF-8, a transformation format of ISO
              10646", RFC 2279, January 1998.
 
+[RFC1321]    Rivest R., "The MD5 Message-Digest Algorithm", RFC 1321,
+             April 1992.
+
+[RFC3174]    Eastlake, F., et al., "US Secure Hash Algorithm 1 (SHA1)",
+             RFC 3174, September 2001.
+
 [PKCS7]      Kalinski, B., "PKCS #7: Cryptographic Message Syntax,
              Version 1.5", RFC 2315, March 1998.
 
+[RFC2253]    Wahl, M., et al., "Lightweight Directory Access Protocol
+             (v3): UTF-8 String Representation of Distinguished Names",
+             RFC 2253, December 1997.
+
 
 .ti 0
 7 Author's Address
@@ -2514,4 +2548,32 @@ Finland
 
 EMail: priikone@iki.fi
 
-This Internet-Draft expires XXX
+
+.ti 0
+8 Full Copyright Statement
+
+Copyright (C) The Internet Society (2003). All Rights Reserved.
+
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/doc/draft-riikonen-silc-spec-08.nroff b/doc/draft-riikonen-silc-spec-08.nroff
new file mode 100644 (file)
index 0000000..5aa308b
--- /dev/null
@@ -0,0 +1,2598 @@
+.pl 10.0i
+.po 0
+.ll 7.2i
+.lt 7.2i
+.nr LL 7.2i
+.nr LT 7.2i
+.ds LF Riikonen
+.ds RF FORMFEED[Page %]
+.ds CF
+.ds LH Internet Draft
+.ds RH 11 August 2003
+.ds CH
+.na
+.hy 0
+.in 0
+.nf
+Network Working Group                                        P. Riikonen
+Internet-Draft
+draft-riikonen-silc-spec-08.txt                           11 August 2003
+Expires: 11 February 2004
+
+.in 3
+
+.ce 3
+Secure Internet Live Conferencing (SILC),
+Protocol Specification
+<draft-riikonen-silc-spec-08.txt>
+
+.ti 0
+Status of this Memo
+
+This document is an Internet-Draft and is in full conformance with
+all provisions of Section 10 of RFC 2026.  Internet-Drafts are
+working documents of the Internet Engineering Task Force (IETF), its
+areas, and its working groups.  Note that other groups may also
+distribute working documents as Internet-Drafts.
+
+Internet-Drafts are draft documents valid for a maximum of six months
+and may be updated, replaced, or obsoleted by other documents at any
+time.  It is inappropriate to use Internet-Drafts as reference
+material or to cite them other than as "work in progress."
+
+The list of current Internet-Drafts can be accessed at
+http://www.ietf.org/ietf/1id-abstracts.txt
+
+The list of Internet-Draft Shadow Directories can be accessed at
+http://www.ietf.org/shadow.html
+
+The distribution of this memo is unlimited.
+
+
+.ti 0
+Abstract
+
+This memo describes a Secure Internet Live Conferencing (SILC)
+protocol which provides secure conferencing services over insecure
+network channel.  SILC provides advanced and feature rich conferencing
+services with security as main design principal.  Strong cryptographic
+methods are used to protect SILC packets inside the SILC network.
+Three other specifications relates very closely to this memo;
+SILC Packet Protocol [SILC2], SILC Key Exchange and Authentication
+Protocols [SILC3] and SILC Commands [SILC4].
+
+
+
+
+
+
+.ti 0
+Table of Contents
+
+.nf
+1 Introduction ..................................................  3
+  1.1 Requirements Terminology ..................................  4
+2 SILC Concepts .................................................  4
+  2.1 SILC Network Topology .....................................  4
+  2.2 Communication Inside a Cell ...............................  6
+  2.3 Communication in the Network ..............................  7
+  2.4 Channel Communication .....................................  7
+  2.5 Router Connections ........................................  8
+3 SILC Specification ............................................  9
+  3.1 Client ....................................................  9
+      3.1.1 Client ID ...........................................  9
+  3.2 Server .................................................... 10
+      3.2.1 Server's Local ID List .............................. 11
+      3.2.2 Server ID ........................................... 12
+      3.2.3 SILC Server Ports ................................... 12
+  3.3 Router .................................................... 13
+      3.3.1 Router's Local ID List .............................. 13
+      3.3.2 Router's Global ID List ............................. 14
+      3.3.3 Router's Server ID .................................. 14
+  3.4 Channels .................................................. 14
+      3.4.1 Channel ID .......................................... 16
+  3.5 Operators ................................................. 16
+  3.6 SILC Commands ............................................. 17
+  3.7 SILC Packets .............................................. 17
+  3.8 Packet Encryption ......................................... 17
+      3.8.1 Determination of the Source and the Destination ..... 18
+      3.8.2 Client To Client .................................... 19
+      3.8.3 Client To Channel ................................... 20
+      3.8.4 Server To Server .................................... 21
+  3.9 Key Exchange And Authentication ........................... 21
+      3.9.1 Authentication Payload .............................. 21
+  3.10 Algorithms ............................................... 23
+      3.10.1 Ciphers ............................................ 23
+             3.10.1.1 CBC Mode .................................. 24
+             3.10.1.2 CTR Mode .................................. 24
+             3.10.1.3 Randomized CBC Mode ....................... 26
+      3.10.2 Public Key Algorithms .............................. 26
+             3.10.2.1 Multi-Precision Integers .................. 27
+      3.10.3 Hash Functions ..................................... 27
+      3.10.4 MAC Algorithms ..................................... 27
+      3.10.5 Compression Algorithms ............................. 28
+  3.11 SILC Public Key .......................................... 29
+  3.12 SILC Version Detection ................................... 31
+  3.13 Backup Routers ........................................... 31
+      3.13.1 Switching to Backup Router ......................... 33
+      3.13.2 Resuming Primary Router ............................ 34
+4 SILC Procedures ............................................... 36
+  4.1 Creating Client Connection ................................ 37
+  4.2 Creating Server Connection ................................ 38
+      4.2.1 Announcing Clients, Channels and Servers ............ 39
+  4.3 Joining to a Channel ...................................... 40
+  4.4 Channel Key Generation .................................... 41
+  4.5 Private Message Sending and Reception ..................... 42
+  4.6 Private Message Key Generation ............................ 42
+  4.7 Channel Message Sending and Reception ..................... 43
+  4.8 Session Key Regeneration .................................. 44
+  4.9 Command Sending and Reception ............................. 44
+  4.10 Closing Connection ....................................... 45
+  4.11 Detaching and Resuming a Session ......................... 46
+5 Security Considerations ....................................... 47
+6 References .................................................... 48
+7 Author's Address .............................................. 50
+8 Full Copyright Statement ...................................... 50
+
+.ti 0
+List of Figures
+
+.nf
+Figure 1:  SILC Network Topology
+Figure 2:  Communication Inside cell
+Figure 3:  Communication Between Cells
+Figure 4:  Router Connections
+Figure 5:  SILC Public Key
+Figure 6:  Counter Block
+
+
+.ti 0
+1. Introduction
+
+This document describes a Secure Internet Live Conferencing (SILC)
+protocol which provides secure conferencing services over insecure
+network channel.  SILC can be used as a secure conferencing service
+that provides rich conferencing features.  Some of the SILC features
+are found in traditional chat protocols such as IRC [IRC] but many
+of the SILC features can also be found in Instant Message (IM) style
+protocols.  SILC combines features from both of these chat protocol
+styles, and can be implemented as either IRC-like system or IM-like
+system.  Some of the more advanced and secure features of the
+protocol are new to all conferencing protocols.  SILC also supports
+multimedia messages and can also be implemented as a video and audio
+conferencing system.
+
+Strong cryptographic methods are used to protect SILC packets inside
+the SILC network.  Three other specifications relates very closely
+to this memo; SILC Packet Protocol [SILC2], SILC Key Exchange and
+Authentication Protocols [SILC3] and SILC Commands [SILC4].
+
+The protocol uses extensively packets as conferencing protocol
+requires message and command sending.  The SILC Packet Protocol is
+described in [SILC2] and should be read to fully comprehend this
+document and protocol.  [SILC2] also describes the packet encryption
+and decryption in detail.  The SILC Packet Protocol provides secured
+and authenticated packets, and the protocol is designed to be compact.
+This makes SILC also suitable in environment of low bandwidth
+requirements such as mobile networks.  All packet payloads in SILC
+can be also compressed.
+
+The security of SILC protocol sessions are based on strong and secure
+key exchange protocol.  The SILC Key Exchange protocol is described
+in [SILC3] along with connection authentication protocol and should
+be read to fully comprehend this document and protocol.
+
+The SILC protocol has been developed to work on TCP/IP network
+protocol, although it could be made to work on other network protocols
+with only minor changes.  However, it is recommended that TCP/IP
+protocol is used under SILC protocol.  Typical implementation would
+be made in client-server model.
+
+
+.ti 0
+1.1 Requirements Terminology
+
+The keywords MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, RECOMMENDED,
+MAY, and OPTIONAL, when they appear in this document, are to be
+interpreted as described in [RFC2119].
+
+
+.ti 0
+2. SILC Concepts
+
+This section describes various SILC protocol concepts that forms the
+actual protocol, and in the end, the actual SILC network.  The mission
+of the protocol is to deliver messages from clients to other clients
+through routers and servers in secure manner.  The messages may also
+be delivered from one client to many clients forming a group, also
+known as a channel.
+
+This section does not focus to security issues.  Instead, basic network
+concepts are introduced to make the topology of the SILC network
+clear.
+
+
+.ti 0
+2.1 SILC Network Topology
+
+SILC network forms a ring as opposed to tree style network topology that
+conferencing protocols usually have.  The network has a cells which are
+constructed from a router and zero or more servers.  The servers are
+connected to the router in a star like network topology.  Routers in the
+network are connected to each other forming a ring.  The rationale for
+this is to have servers that can perform specific kind of tasks what
+other servers cannot perform.  This leads to two kinds of servers; normal
+SILC servers and SILC router servers.
+
+A difference between normal server and router server is that routers
+knows all global information and keep the global network state up to date.
+They also do the actual routing of the messages to the correct receiver
+between other cells.  Normal servers knows only local information and
+receive global information only when it is needed.  They do not need to
+keep the global network state up to date.  This makes the network faster
+and scalable as there are less servers that needs to maintain global
+network state.
+
+This, on the other hand, leads into a cellular like network, where
+routers are in the center of the cell and servers are connected to the
+router.
+
+The following diagram represents SILC network topology.
+
+.in 8
+.nf
+  ---- ---- ----         ---- ---- ----
+ | S8 | S5 | S4 |       | S7 | S5 | S6 |
+ ----- ---- -----       ----- ---- -----
+| S7 | S/R1 | S2 | --- | S8 | S/R2 | S4 |
+ ---- ------ ----       ---- ------ ----
+ | S6 | S3 | S1 |       | S1 | S3 | S2 |         ---- ----
+  ---- ---- ----         ---- ---- ----         | S3 | S1 |
+     Cell 1.   \\             Cell 2.  | \\____  ----- -----
+                |                     |        | S4 | S/R4 |
+    ---- ---- ----         ---- ---- ----       ---- ------
+   | S7 | S4 | S2 |       | S1 | S3 | S2 |      | S2 | S5 |
+   ----- ---- -----       ----- ---- -----       ---- ----
+  | S6 | S/R3 | S1 | --- | S4 | S/R5 | S5 | ____/ Cell 4.
+   ---- ------ ----       ---- ------ ----
+   | S8 | S5 | S3 |       | S6 | S7 | S8 |     ... etc ...
+    ---- ---- ----         ---- ---- ----
+       Cell 3.                Cell 5.
+.in 3
+
+.ce
+Figure 1:  SILC Network Topology
+
+
+A cell is formed when a server or servers connect to one router.  In
+SILC network normal server cannot directly connect to other normal
+server.  Normal server may only connect to SILC router which then
+routes the messages to the other servers in the cell.  Router servers
+on the other hand may connect to other routers to form the actual SILC
+network, as seen in above figure.  However, router is also able to act
+as normal SILC server; clients may connect to it the same way as to
+normal SILC server.  Normal server also cannot have active connections
+to more than one router.  Normal server cannot be connected to two
+different cells.  Router servers, on the other hand, may have as many
+router to router connections as needed.  Other direct routes between
+other routers is also possible in addition of the mandatory ring
+connections.  This leads into a hybrid ring-mesh network topology.
+
+There are many issues in this network topology that needs to be careful
+about.  Issues like routing, the size of the cells, the number of the
+routers in the SILC network and the capacity requirements of the
+routers.  These issues should be discussed in the Internet Community
+and additional documents on the issue may be written.
+
+
+.ti 0
+2.2 Communication Inside a Cell
+
+It is always guaranteed that inside a cell message is delivered to the
+recipient with at most two server hops.  A client which is connected to
+server in the cell and is talking on channel to other client connected
+to other server in the same cell, will have its messages delivered from
+its local server first to the router of the cell, and from the router
+to the other server in the cell.
+
+The following diagram represents this scenario:
+
+
+.in 25
+.nf
+1 --- S1     S4 --- 5
+         S/R
+ 2 -- S2     S3
+     /        |
+    4         3
+.in 3
+
+
+.ce
+Figure 2:  Communication Inside cell
+
+
+Example:  Client 1. connected to Server 1. send message to
+          Client 4. connected to Server 2. travels from Server 1.
+          first to Router which routes the message to Server 2.
+          which then sends it to the Client 4.  All the other
+          servers in the cell will not see the routed message.
+
+
+If the client is connected directly to the router, as router is also normal
+SILC server, the messages inside the cell are always delivered only with
+one server hop.  If clients communicating with each other are connected
+to the same server, no router interaction is needed.  This is the optimal
+situation of message delivery in the SILC network.
+
+
+.ti 0
+2.3 Communication in the Network
+
+If the message is destined to client that does not belong to local cell
+the message is routed to the router server to which the destination
+client belongs, if the local router is connected to destination router.
+If there is no direct connection to the destination router, the local
+router routes the message to its primary route.  The following diagram
+represents message sending between cells.
+
+
+
+.in 16
+.nf
+1 --- S1     S4 --- 5            S2 --- 1
+         S/R - - - - - - - - S/R
+ 2 -- S2     S3           S1
+     /        |             \\
+    4         3              2
+
+   Cell 1.               Cell 2.
+.in 3
+
+
+.ce
+Figure 3:  Communication Between Cells
+
+
+Example:  Client 5. connected to Server 4. in Cell 1. sends message
+          to Client 2. connected to Server 1. in Cell 2. travels
+          from Server 4. to Router which routes the message to
+          Router in Cell 2, which then routes the message to
+          Server 1.  All the other servers and routers in the
+          network will not see the routed message.
+
+
+The optimal case of message delivery from the client point of view is
+when clients are connected directly to the routers and the messages
+are delivered from one router to the other.
+
+
+.ti 0
+2.4 Channel Communication
+
+Messages may be sent to group of clients as well.  Sending messages to
+many clients works the same way as sending messages point to point, from
+message delivery point of view.  Security issues are another matter
+which are not discussed in this section.
+
+Router server handles the message routing to multiple recipients.  If
+any recipient is not in the same cell as the sender the messages are
+routed further.
+
+Server distributes the channel message to its local clients which are
+joined to the channel.  Router also distributes the message to its
+local clients on the channel.
+
+
+.ti 0
+2.5 Router Connections
+
+Router connections play very important role in making the SILC like
+network topology to work.  For example, sending broadcast packets in
+SILC network require special connections between routers; routers must
+be connected in a specific way.
+
+Every router has their primary route which is a connection to another
+router in the network.  Unless there is only two routers in the network
+must not routers use each other as their primary routes.  The router
+connections in the network must form a ring.
+
+Example with three routers in the network:
+
+
+.in 16
+.nf
+    S/R1 - < - < - < - < - < - < - S/R2
+     \\                               /
+      v                             ^
+       \\ - > -  > - S/R3 - > - > - /
+.in 3
+
+
+.ce
+Figure 4:  Router Connections
+
+
+Example:  Network with three routers.  Router 1. uses Router 2. as its
+          primary router.  Router 2. uses Router 3. as its primary router,
+          and Router 3. uses Router 1. as its primary router.  There may
+          be other direct connections between the routers but they must
+          not be used as primary routes.
+
+The above example is applicable to any amount of routers in the network
+except for two routers.  If there are only two routers in the network both
+routers must be able to handle situation where they use each other as their
+primary routes.
+
+The issue of router connections are very important especially with SILC
+broadcast packets.  Usually all router wide information in the network is
+distributed by SILC broadcast packets.  This sort of ring network, with
+ability to have other direct routes in the network can cause interesting
+routing problems.  The [SILC2] discusses the routing of packets in this
+sort of network in more detail.
+
+
+.ti 0
+3. SILC Specification
+
+This section describes the SILC protocol.  However, [SILC2] and
+[SILC3] describes other important protocols that are part of this SILC
+specification and must be read.
+
+
+.ti 0
+3.1 Client
+
+A client is a piece of software connecting to SILC server.  SILC client
+cannot be SILC server.  Purpose of clients is to provide the user
+interface of the SILC services for end user.  Clients are distinguished
+from other clients by unique Client ID.  Client ID is a 128 bit ID that
+is used in the communication in the SILC network.  The client ID is
+based on the user's IP address and nickname.  User use logical nicknames
+in communication which are then mapped to the corresponding Client ID.
+Client IDs are low level identifications and should not be seen by the
+end user.
+
+Clients provide other information about the end user as well. Information
+such as the nickname of the user, username and the host name of the end
+user and user's real name.  See section 3.2 Server for information of
+the requirements of keeping this information.
+
+The nickname selected by the user is not unique in the SILC network.
+There can be 2^8 same nicknames for one IP address.  As for comparison to
+IRC [IRC] where nicknames are unique this is a fundamental difference
+between SILC and IRC.  This typically causes the server names or client's
+host names to be used along with the nicknames on user interface to
+identify specific users when sending messages.  This feature of SILC
+makes IRC style nickname-wars obsolete as no one owns their nickname;
+there can always be someone else with the same nickname.  Also, any kind
+of nickname registering service becomes obsolete.  The maximum length of
+nickname is 128 bytes.
+
+
+.ti 0
+3.1.1 Client ID
+
+Client ID is used to identify users in the SILC network.  The Client ID
+is unique to the extent that there can be 2^128 different Client IDs,
+and IDs based on IPv6 addresses extends this to 2^224 different Client
+IDs.  Collisions are not expected to happen.  The Client ID is defined
+as follows.
+
+.in 6
+128 bit Client ID based on IPv4 addresses:
+
+32 bit  Server ID IP address (bits 1-32)
+ 8 bit  Random number or counter
+88 bit  Truncated MD5 hash value of the nickname
+
+224 bit Client ID based on IPv6 addresses:
+
+128 bit  Server ID IP address (bits 1-128)
+  8 bit  Random number or counter
+ 88 bit  Truncated MD5 hash value of the nickname
+
+o Server ID IP address - Indicates the server where this
+  client is coming from.  The IP address hence equals the
+  server IP address where the client is connected.
+
+o Random number or counter - Random number to further
+  randomize the Client ID.  Another choice is to use
+  a counter starting from the zero (0).  This makes it
+  possible to have 2^8 same nicknames from the same
+  server IP address.
+
+o MD5 hash - MD5 hash value of the lowercase nickname is
+  truncated taking 88 bits from the start of the hash value.
+  This hash value is used to search the user's Client ID
+  from the ID lists.  Note that the nickname MUST be in
+  lowercase format.
+
+.in 3
+Collisions could occur when more than 2^8 clients using same nickname
+from the same server IP address is connected to the SILC network.
+Server MUST be able to handle this situation by refusing to accept
+anymore of that nickname.
+
+Another possible collision may happen with the truncated hash value of
+the nickname.  It could be possible to have same truncated hash value
+for two different nicknames.  However, this is not expected to happen
+nor cause any serious problems if it would occur.  Nicknames are usually
+logical and it is unlikely to have two distinct logical nicknames
+produce same truncated hash value.
+
+
+.ti 0
+3.2 Server
+
+Servers are the most important parts of the SILC network.  They form the
+basis of the SILC, providing a point to which clients may connect to.
+There are two kinds of servers in SILC; normal servers and router servers.
+This section focus on the normal server and router server is described
+in the section 3.3 Router.
+
+Normal servers MUST NOT directly connect to other normal server.  Normal
+servers may only directly connect to router server.  If the message sent
+by the client is destined outside the local server it is always sent to
+the router server for further routing.  Server may only have one active
+connection to router on same port.  Normal server MUST NOT connect to other
+cell's router except in situations where its cell's router is unavailable.
+
+
+.ti 0
+3.2.1 Server's Local ID List
+
+Normal server keeps various information about the clients and their end
+users connected to it.  Every normal server MUST keep list of all locally
+connected clients, Client IDs, nicknames, usernames and host names and
+user's real name.  Normal servers only keeps local information and it
+does not keep any global information.  Hence, normal servers knows only
+about their locally connected clients.  This makes servers efficient as
+they do not have to worry about global clients.  Server is also responsible
+of creating the Client IDs for their clients.
+
+Normal server also keeps information about locally created channels and
+their Channel IDs.
+
+Hence, local list for normal server includes:
+
+.in 6
+server list        - Router connection
+   o Server name
+   o Server IP address
+   o Server ID
+   o Sending key
+   o Receiving key
+   o Public key
+
+client list        - All clients in server
+   o Nickname
+   o Username@host
+   o Real name
+   o Client ID
+   o Sending key
+   o Receiving key
+   o Public key
+
+
+channel list       - All channels in server
+   o Channel name
+   o Channel ID
+   o Client IDs on channel
+   o Client ID modes on channel
+   o Channel key
+.in 3
+
+
+
+.ti 0
+3.2.2 Server ID
+
+Servers are distinguished from other servers by unique 64 bit Server ID
+(for IPv4) or 160 bit Server ID (for IPv6).  The Server ID is used in
+the SILC to route messages to correct servers.  Server IDs also provide
+information for Client IDs, see section 3.1.1 Client ID.  Server ID is
+defined as follows.
+
+.in 6
+64 bit Server ID based on IPv4 addresses:
+
+32 bit  IP address of the server
+16 bit  Port
+16 bit  Random number
+
+160 bit Server ID based on IPv6 addresses:
+
+128 bit  IP address of the server
+ 16 bit  Port
+ 16 bit  Random number
+
+o IP address of the server - This is the real IP address of
+  the server.
+
+o Port - This is the port the server is bound to.
+
+o Random number - This is used to further randomize the Server ID.
+
+.in 3
+Collisions are not expected to happen in any conditions.  The Server ID
+is always created by the server itself and server is responsible of
+distributing it to the router.
+
+
+.ti 0
+3.2.3 SILC Server Ports
+
+The following ports has been assigned by IANA for the SILC protocol:
+
+.in 10
+silc            706/tcp    SILC
+silc            706/udp    SILC
+.in 3
+
+
+If there are needs to create new SILC networks in the future the port
+numbers must be officially assigned by the IANA.
+
+Server on network above privileged ports (>1023) SHOULD NOT be trusted
+as they could have been set up by untrusted party.
+
+
+
+.ti 0
+3.3 Router
+
+Router server in SILC network is responsible for keeping the cell together
+and routing messages to other servers and to other routers.  Router server
+is also a normal server thus clients may connect to it as it would be
+just normal SILC server.
+
+However, router servers has a lot of important tasks that normal servers
+do not have.  Router server knows everything and keeps the global state.
+They know all clients currently on SILC, all servers and routers and all
+channels in SILC.  Routers are the only servers in SILC that care about
+global information and keeping them up to date at all time.
+
+
+.ti 0
+3.3.1 Router's Local ID List
+
+Router server as well MUST keep local list of connected clients and
+locally created channels.  However, this list is extended to include all
+the informations of the entire cell, not just the server itself as for
+normal servers.
+
+However, on router this list is a lot smaller since routers do not need
+to keep information about user's nickname, username and host name and real
+name since these are not needed by the router.  The router keeps only
+information that it needs.
+
+Hence, local list for router includes:
+
+.in 6
+server list        - All servers in the cell
+   o Server name
+   o Server ID
+   o Router's Server ID
+   o Sending key
+   o Receiving key
+
+client list        - All clients in the cell
+   o Client ID
+
+channel list       - All channels in the cell
+   o Channel ID
+   o Client IDs on channel
+   o Client ID modes on channel
+   o Channel key
+.in 3
+
+
+Note that locally connected clients and other information include all the
+same information as defined in section section 3.2.1 Server's Local ID
+List.  Router MAY also cache same detailed information for other clients
+if needed.
+
+
+.ti 0
+3.3.2 Router's Global ID List
+
+Router server MUST also keep global list.  Normal servers do not have
+global list as they know only about local information.  Global list
+includes all the clients on SILC, their Client IDs, all created channels
+and their Channel IDs and all servers and routers on SILC and their
+Server IDs.  That is said, global list is for global information and the
+list must not include the local information already on the router's local
+list.
+
+Note that the global list does not include information like nicknames,
+usernames and host names or user's real names.  Router does not need to
+keep these informations as they are not needed by the router.  This
+information is available from the client's server which maybe queried
+when needed.
+
+Hence, global list includes:
+
+.in 6
+server list        - All servers in SILC
+   o Server name
+   o Server ID
+   o Router's Server ID
+
+client list        - All clients in SILC
+   o Client ID
+
+channel list       - All channels in SILC
+   o Channel ID
+   o Client IDs on channel
+   o Client ID modes on channel
+.in 3
+
+
+
+.ti 0
+3.3.3 Router's Server ID
+
+Router's Server ID is equivalent to normal Server ID.  As routers are
+normal servers same types of IDs applies for routers as well.  See
+section 3.2.2 Server ID.
+
+
+.ti 0
+3.4 Channels
+
+A channel is a named group of one or more clients which will all receive
+messages addressed to that channel.  The channel is created when first
+client requests JOIN command to the channel, and the channel ceases to
+exist when the last client has left it.  When channel exists, any client
+can reference it using the Channel ID of the channel.  If the channel has
+a founder mode set and last client leaves the channel the channel does
+not cease to exist.  The founder mode can be used to make permanent
+channels in the network.  The founder of the channel can regain the
+channel founder privileges on the channel later when he joins the
+channel.
+
+Channel names are unique although the real uniqueness comes from 64 bit
+Channel ID.  However, channel names are still unique and no two global
+channels with same name may exist.  The channel name is a string of
+maximum length of 256 bytes.  Channel names MUST NOT contain any
+whitespaces (`  '), any non-printable ASCII characters, commas (`,')
+and wildcard characters.
+
+Channels can have operators that can administrate the channel and
+operate all of its modes.  The following operators on channel exist on
+the SILC network.
+
+.in 6
+o Channel founder - When channel is created the joining client becomes
+  channel founder.  Channel founder is channel operator with some more
+  privileges.  Basically, channel founder can fully operate the channel
+  and all of its modes.  The privileges are limited only to the
+  particular channel.  There can be only one channel founder per
+  channel.  Channel founder supersedes channel operator's privileges.
+
+  Channel founder privileges cannot be removed by any other operator on
+  channel.  When channel founder leaves the channel there is no channel
+  founder on the channel.  However, it is possible to set a mode for
+  the channel which allows the original channel founder to regain the
+  founder privileges even after leaving the channel.  Channel founder
+  also cannot be removed by force from the channel.
+
+o Channel operator - When client joins to channel that has not existed
+  previously it will become automatically channel operator (and channel
+  founder discussed above).  Channel operator is able to administrate the
+  channel, set some modes on channel, remove a badly behaving client
+  from the channel and promote other clients to become channel
+  operator.  The privileges are limited only to the particular channel.
+
+  Normal channel user may be promoted (opped) to channel operator
+  gaining channel operator privileges.  Channel founder or other
+  channel operator may also demote (deop) channel operator to normal
+  channel user.
+.in 3
+
+
+
+
+.ti 0
+3.4.1 Channel ID
+
+Channels are distinguished from other channels by unique Channel ID.
+The Channel ID is a 64 bit ID (for IPv4) or 160 bit ID (for IPv6), and
+collisions are not expected to happen in any conditions.  Channel names
+are just for logical use of channels.  The Channel ID is created by the
+server where the channel is created.  The Channel ID is defined as
+follows.
+
+.in 6
+64 bit Channel ID based on IPv4 addresses:
+
+32 bit  Router's Server ID IP address (bits 1-32)
+16 bit  Router's Server ID port (bits 33-48)
+16 bit  Random number or counter
+
+160 bit Channel ID based on IPv6 addresses:
+
+128 bit  Router's Server ID IP address (bits 1-128)
+ 16 bit  Router's Server ID port (bits 129-144)
+ 16 bit  Random number or counter
+
+o Router's Server ID IP address - Indicates the IP address of
+  the router of the cell where this channel is created.  This is
+  taken from the router's Server ID.  This way SILC router knows
+  where this channel resides in the SILC network.
+
+o Router's Server ID port - Indicates the port of the channel on
+  the server.  This is taken from the router's Server ID.
+
+o Random number or counter - To further randomize the Channel ID.
+  Another choice is to use a counter starting from zero (0).
+  This makes sure that there are no collisions.  This also means
+  that in a cell there can be 2^16 different channels.
+.in 3
+
+
+.ti 0
+3.5 Operators
+
+Operators are normal users with extra privileges to their server or
+router.  Usually these people are SILC server and router administrators
+that take care of their own server and clients on them.  The purpose of
+operators is to administrate the SILC server or router.  However, even
+an operator with highest privileges is not able to enter invite-only
+channels, to gain access to the contents of encrypted and authenticated
+packets traveling in the SILC network or to gain channel operator
+privileges on public channels without being promoted.  They have the
+same privileges as any normal user except they are able to administrate
+their server or router.
+
+
+.ti 0
+3.6 SILC Commands
+
+Commands are very important part on SILC network especially for client
+which uses commands to operate on the SILC network.  Commands are used
+to set nickname, join to channel, change modes and many other things.
+
+Client usually sends the commands and server replies by sending a reply
+packet to the command.  Server MAY also send commands usually to serve
+the original client's request.  Usually server cannot send commands to
+clients, however there MAY be commands that allow the server to send
+commands to client.  By default servers MAY send commands only to other
+servers and routers.
+
+Note that the command reply is usually sent only after client has sent
+the command request but server is allowed to send command reply packet
+to client even if client has not requested the command.  Client MAY
+choose to ignore the command reply.
+
+It is expected that some of the commands may be misused by clients
+resulting various problems on the server side.  Every implementation
+SHOULD assure that commands may not be executed more than once, say,
+in two (2) seconds.  However, to keep response rate up, allowing for
+example five (5) commands before limiting is allowed.  It is RECOMMENDED
+that commands such as SILC_COMMAND_NICK, SILC_COMMAND_JOIN,
+SILC_COMMAND_LEAVE and SILC_COMMAND_KILL SHOULD be limited in all cases
+as they require heavy operations.  This should be sufficient to prevent
+the misuse of commands.
+
+SILC commands are described in [SILC4].
+
+
+.ti 0
+3.7 SILC Packets
+
+Packets are naturally the most important part of the protocol and the
+packets are what actually makes the protocol.  Packets in SILC network
+are always encrypted using, usually the shared secret session key
+or some other key, for example, channel key, when encrypting channel
+messages.  It is not possible to send a packet in SILC network without
+encryption.  The SILC Packet Protocol is a wide protocol and is described
+in [SILC2].  This document does not define or describe details of
+SILC packets.
+
+
+.ti 0
+3.8 Packet Encryption
+
+All packets passed in SILC network MUST be encrypted.  This section
+gives generic description of how packets must be encrypted in the SILC
+network.  The detailed description of the actual encryption process
+of the packets are described in [SILC2].
+
+Client and its server shares secret symmetric session key which is
+established by the SILC Key Exchange Protocol, described in [SILC3].
+Every packet sent from client to server, with exception of packets for
+channels, are encrypted with this session key.
+
+Channels have a channel key that are shared by every client on the channel.
+However, the channel keys are cell specific thus one cell does not know
+the channel key of the other cell, even if that key is for same channel.
+Channel key is also known by the routers and all servers that have clients
+on the channel.  However, channels MAY have channel private keys that are
+entirely local setting for the client.  All clients on the channel MUST
+know the channel private key beforehand to be able to talk on the
+channel.  In this case, no server or router knows the key for the channel.
+
+Server shares secret symmetric session key with router which is
+established by the SILC Key Exchange Protocol.  Every packet passed from
+server to router, with exception of packets for channels, are encrypted
+with the shared session key.  Same way, router server shares secret
+symmetric key with its primary router.  However, every packet passed
+from router to other router, including packets for channels, are
+encrypted with the shared session key.  Every router connection MUST
+have their own session keys.
+
+
+.ti 0
+3.8.1 Determination of the Source and the Destination
+
+The source and the destination of the packet needs to be determined
+to be able to route the packets to correct receiver.  This information
+is available in the SILC Packet Header which is included in all packets
+sent in SILC network.  The SILC Packet Header is described in [SILC2].
+
+The header MUST be encrypted with the session key of whom is the next
+receiver of the packet along the route.  The receiver of the packet, for
+example a router along the route, is able to determine the sender and the
+destination of the packet by decrypting the SILC Packet Header and
+checking the IDs attached to the header.  The IDs in the header will
+tell to where the packet needs to be sent and where it is coming from.
+
+The header in the packet MUST NOT change during the routing of the
+packet.  The original sender, for example client, assembles the packet
+and the packet header and server or router between the sender and the
+receiver MUST NOT change the packet header.  Note however, that some
+packets such as commands may be resent by a server to serve the client's
+original command.  In this case the command packet sent by the server
+includes the server's IDs as it is a different packet.  When server
+or router receives a packet it MUST verify that the Source ID is
+valid and correct ID for that sender.
+
+Note that the packet and the packet header may be encrypted with
+different keys.  For example, packets to channels are encrypted with
+the channel key, however, the header is encrypted with the session key
+as described above.  However, the header and the packet may be encrypted
+with same key.  This is the case, for example, with command packets.
+
+
+.ti 0
+3.8.2 Client To Client
+
+The process of message delivery and encryption from client to another
+client is as follows.
+
+Example:  Private message from client to another client on different
+          servers.  Clients do not share private message delivery
+          keys; normal session keys are used.
+
+o Client 1 sends encrypted packet to its server.  The packet is
+  encrypted with the session key shared between client and its
+  server.
+
+o Server determines the destination of the packet and decrypts
+  the packet.  Server encrypts the packet with session key shared
+  between the server and its router, and sends the packet to the
+  router.
+
+o Router determines the destination of the packet and decrypts
+  the packet.  Router encrypts the packet with session key
+  shared between the router and the destination server, and sends
+  the packet to the server.
+
+o Server determines the client to which the packet is destined
+  to and decrypts the packet.  Server encrypts the packet with
+  session key shared between the server and the destination client,
+  and sends the packet to the client.
+
+o Client 2 decrypts the packet.
+
+
+Example:  Private message from client to another client on different
+          servers.  Clients have established a secret shared private
+          message delivery key with each other and that is used in
+          the message encryption.
+
+o Client 1 sends encrypted packet to its server.  The packet header
+  is encrypted with the session key shared between the client and
+  server, and the private message is encrypted with the private
+  message delivery key shared between clients.
+
+o Server determines the destination of the packet and sends the
+  packet to the router.  Header is encrypted with the session key.
+
+o Router determines the destination of the packet and sends the
+  packet to the server.  Header is encrypted with the session key.
+
+o Server determines the client to which the packet is destined
+  to and sends the packet to the client.  Header is encrypted with
+  the session key.
+
+o Client 2 decrypts the packet with the secret shared key.
+
+If clients share secret key with each other the private message
+delivery is much simpler since servers and routers between the
+clients do not need to decrypt and re-encrypt the entire packet.
+The packet header however is always encrypted with session key and
+is decrypted and re-encrypted with the session key of next recipient.
+
+The process for clients on same server is much simpler as there is
+no need to send the packet to the router.  The process for clients
+on different cells is same as above except that the packet is routed
+outside the cell.  The router of the destination cell routes the
+packet to the destination same way as described above.
+
+
+.ti 0
+3.8.3 Client To Channel
+
+Process of message delivery from client on channel to all the clients
+on the channel.
+
+Example:  Channel of four users; two on same server, other two on
+          different cells.  Client sends message to the channel.
+          Packet header is encrypted with the session key, message
+          data is encrypted with channel key.
+
+o Client 1 encrypts the packet with channel key and sends the
+  packet to its server.
+
+o Server determines local clients on the channel and sends the
+  packet to the Client on the same server.  Server then sends
+  the packet to its router for further routing.
+
+o Router determines local clients on the channel, if found
+  sends packet to the local clients.  Router determines global
+  clients on the channel and sends the packet to its primary
+  router or fastest route.
+
+o (Other router(s) do the same thing and sends the packet to
+   the server(s).)
+
+o Server determines local clients on the channel and sends the
+  packet to the client.
+
+o All clients receiving the packet decrypts it.
+
+
+.ti 0
+3.8.4 Server To Server
+
+Server to server packet delivery and encryption is described in above
+examples. Router to router packet delivery is analogous to server to
+server.  However, some packets, such as channel packets, are processed
+differently.  These cases are described later in this document and
+more in detail in [SILC2].
+
+
+.ti 0
+3.9 Key Exchange And Authentication
+
+Key exchange is done always when for example client connects to server
+but also when server and router, and router and another router connect
+to each other.  The purpose of key exchange protocol is to provide secure
+key material to be used in the communication.  The key material is used
+to derive various security parameters used to secure SILC packets.  The
+SILC Key Exchange protocol is described in detail in [SILC3].
+
+Authentication is done after key exchange protocol has been successfully
+completed.  The purpose of authentication is to authenticate for example
+client connecting to the server.  However, clients MAY be accepted
+to connect to server without explicit authentication.  Servers are
+REQUIRED to use authentication protocol when connecting.  The
+authentication may be based on passphrase (pre-shared secret) or public
+key based on digital signatures.  All passphrases sent in SILC protocol
+MUST be UTF-8 [RFC2279] encoded. The connection authentication protocol
+is described in detail in [SILC3].
+
+
+.ti 0
+3.9.1 Authentication Payload
+
+Authentication Payload is used separately from the SKE and the Connection
+Authentication protocols.  It can be used during the session to
+authenticate with a remote.  For example, a client can authenticate
+itself to a server to become server operator.  In this case,
+Authentication Payload is used.
+
+The format of the Authentication Payload is as follows:
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Payload Length         |     Authentication Method     |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|      Public Data Length       |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                           Public Data                         ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|   Authentication Data Length  |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                       Authentication Data                     ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 5:  Authentication Payload
+
+
+.in 6
+o Payload Length (2 bytes) - Length of the entire payload.
+
+o Authentication Method (2 bytes) - The method of the
+  authentication.  The authentication methods are defined
+  in [SILC2] in the Connection Auth Request Payload.  The NONE
+  authentication method SHOULD NOT be used.
+
+o Public Data Length (2 bytes) - Indicates the length of
+  the Public Data field.
+
+o Public Data (variable length) - This is defined only if
+  the authentication method is public key.  If it is any other
+  this field MAY include random data for padding purposes.
+  However, in this case the field MUST be ignored by the
+  receiver.
+
+  When the authentication method is public key this includes
+  128 to 4096 bytes of non-zero random data that is used in
+  the signature process, described subsequently.
+
+o Authentication Data Length (2 bytes) - Indicates the
+  length of the Authentication Data field.  If zero (0)
+  value is found in this field the payload MUST be
+  discarded.
+
+o Authentication Data (variable length) - Authentication
+  method dependent authentication data.
+.in 3
+
+
+If the authentication method is passphrase-based, the Authentication
+Data field includes the plaintext UTF-8 encoded passphrase.  It is safe
+to send plaintext passphrase since the entire payload is encrypted.  In
+this case the Public Data Length is set to zero (0), but MAY also include
+random data for padding purposes.  It is also RECOMMENDED that maximum
+amount of padding is applied to SILC packet when using passphrase-based
+authentication.  This way it is not possible to approximate the length
+of the passphrase from the encrypted packet.
+
+If the authentication method is public key based (or certificate)
+the Authentication Data is computed as follows:
+
+  HASH = hash(random bytes | ID | public key (or certificate));
+  Authentication Data = sign(HASH);
+
+The hash() and the sign() are the hash function and the public key
+cryptography function selected in the SKE protocol, unless otherwise
+stated in the context where this payload is used.  The public key
+is SILC style public key unless certificates are used.  The ID is the
+entity's ID (Client or Server ID) which is authenticating itself.  The
+ID encoding is described in [SILC2].  The random bytes are non-zero
+random bytes of length between 128 and 4096 bytes, and will be included
+into the Public Data field as is.
+
+The receiver will compute the signature using the random data received
+in the payload, the ID associated to the connection and the public key
+(or certificate) received in the SKE protocol.  After computing the
+receiver MUST verify the signature.  Also in case of public key
+authentication this payload is encrypted.
+
+
+.ti 0
+3.10 Algorithms
+
+This section defines all the allowed algorithms that can be used in
+the SILC protocol.  This includes mandatory cipher, mandatory public
+key algorithm and MAC algorithms.
+
+
+.ti 0
+3.10.1 Ciphers
+
+Cipher is the encryption algorithm that is used to protect the data
+in the SILC packets.  See [SILC2] for the actual encryption process and
+definition of how it must be done.  SILC has a mandatory algorithm that
+must be supported in order to be compliant with this protocol.
+
+The following ciphers are defined in SILC protocol:
+
+aes-256-cbc          AES in CBC mode, 256 bit key            (REQUIRED)
+aes-256-ctr          AES in CTR mode, 256 bit key            (RECOMMENDED)
+aes-256-rcbc         AES in randomized CBC mode, 256 bit key (OPTIONAL)
+aes-192-<mode>       AES in <mode> mode, 192 bit key         (OPTIONAL)
+aes-128-<mode>       AES in <mode> mode, 128 bit key         (RECOMMENDED)
+twofish-256-<mode>   Twofish in <mode> mode, 256 bit key     (OPTIONAL)
+twofish-192-<mode>   Twofish in <mode> mode, 192 bit key     (OPTIONAL)
+twofish-128-<mode>   Twofish in <mode> mode, 128 bit key     (OPTIONAL)
+cast-256-<mode>      CAST-256 in <mode> mode, 256 bit key    (OPTIONAL)
+cast-192-<mode>      CAST-256 in <mode> mode, 192 bit key    (OPTIONAL)
+cast-128-<mode>      CAST-256 in <mode> mode, 128 bit key    (OPTIONAL)
+serpent-<len>-<mode> Serpent in <mode> mode, <len> bit key   (OPTIONAL)
+rc6-<len>-<mode>     RC6 in <mode> mode, <len> bit key       (OPTIONAL)
+mars-<len>-<mode>    MARS in <mode> mode, <len> bit key      (OPTIONAL)
+none                 No encryption                           (OPTIONAL)
+
+The <mode> is either "cbc", "ctr" or "rcbc".  Other encryption modes MAY
+be defined to be used in SILC using the same name format.  The <len> is
+either 256, 192 or 128 bit key length.  Also, additional ciphers MAY be
+defined to be used in SILC by using the same name format as above.
+
+Algorithm "none" does not perform any encryption process at all and
+thus is not recommended to be used.  It is recommended that no client
+or server implementation would accept none algorithm except in special
+debugging mode.
+
+
+.ti 0
+3.10.1.1 CBC Mode
+
+The "cbc" encryption mode is CBC mode with inter-packet chaining.  This
+means that the Initialization Vector (IV) for the next encryption block
+is the previous ciphertext block.  The very first IV MUST be random and
+is generated as described in [SILC3].
+
+
+.ti 0
+3.10.1.2 CTR Mode
+
+The "ctr" encryption mode is Counter Mode (CTR).  The CTR mode in SILC is
+stateful in encryption and decryption.  Both sender and receiver maintain
+the counter for the CTR mode and thus can precompute the key stream for
+encryption and decryption.  By default, CTR mode does not require
+plaintext padding, however implementations MAY apply padding to the
+packets.  If the last key block is larger than the last plaintext block
+the resulted value is truncated to the size of the plaintext block and
+the most significant bits are used.  When sending authentication data
+inside packets the maximum amount of padding SHOULD be applied with
+CTR mode as well.
+
+In CTR mode only the encryption operation of the cipher is used.  The
+decryption operation is not needed since both encryption and decryption
+process is simple XOR with the plaintext block and the key stream block.
+
+The counter block is used to create the key for the CTR mode.  When
+SILC specifications refer to Initialization Vector (IV) in general cases,
+in case of CTR mode it refers to the counter block.  The format of the
+128 bit counter block is as follows:
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                   Truncated HASH from SKE                     |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                Sending/Receiving IV from SKE                  |
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                        Block Counter                          |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 6:  Counter Block
+
+.in 6
+o Truncated HASH from SKE (4 bytes) - This value is the first 4
+  bytes from the HASH value that was computed as a result of SKE
+  protocol.  This acts as session identifier and each rekey MUST
+  produce a new HASH value.
+
+o Sending/Receiving IV from SKE (8 bytes) - This value is the
+  first 8 bytes from the Sending IV or Receiving IV generated in
+  the SKE protocol.  When this mode is used to encrypt sending
+  traffic the Sending IV is used, when used to decrypt receiving
+  traffic the Receiving IV is used.  This assures that two parties
+  of the protocol use different IV for sending traffic.  Each rekey
+  MUST produce a new value.
+
+o Block Counter (4 bytes) - This is the counter value for the
+  counter block and is MSB ordered number starting from one (1)
+  value for first block and incrementing for subsequent blocks.
+  The same value MUST NOT be used twice.  The rekey MUST be
+  performed before this counter value wraps.
+.in 3
+
+CTR mode MUST NOT be used with "none" MAC.  Implementations also MUST
+assure that the same counter block is not used to encrypt more than
+one block.  Also, the key material used with CTR mode MUST be fresh
+key material.  Static keys (pre-shared keys) MUST NOT be used with
+CTR mode.  For this reason using CTR mode to encrypt for example
+channel messages or private messages with a pre-shared key is
+inappropriate.  For private messages, the Key Agreement could be
+performed to produce fresh key material.
+
+If the IV Included flag was negotiated in SKE, or CTR mode is used to
+protect channel messages where the counter block will be included in the
+Message Payload, implementations SHOULD still use the same counter block
+format as defined above.  However, implementations are RECOMMENDED to
+replace the Truncated HASH field with a 32 bit random value for each IV
+(counter block) per encrypted SILC packet.  Also note, that in this case
+the decryption process is not stateful and receiver cannot precompute the
+key stream.
+
+
+.ti 0
+3.10.1.3 Randomized CBC Mode
+
+The "rcbc" encryption mode is CBC mode with randomized IV.  This means
+that each IV for each packet MUST be chosen randomly.  When encrypting
+more than one block the normal inter-packet chaining is used, but for
+the first block new random IV is selected in each packet.  In this mode
+the IV is appended at the end of the last ciphertext block and thus
+delivered to the recipient.  This mode increases the ciphertext size by
+one ciphertext block.  Note also that some data payloads in SILC are
+capable of delivering the IV to the recipient.  When explicitly
+encrypting these payloads with randomized CBC the IV MUST NOT be appended
+at the end of the ciphertext, but is placed at the specified location
+in the payload.  However, Message Payload for example has the IV at
+the location which is equivalent to placing it after the last ciphertext
+block.  When using CBC mode with such payloads it is actually equivalent
+to using randomized CBC since the IV is selected in random and included
+in the ciphertext.
+
+
+.ti 0
+3.10.2 Public Key Algorithms
+
+Public keys are used in SILC to authenticate entities in SILC network
+and to perform other tasks related to public key cryptography.  The
+public keys are also used in the SILC Key Exchange protocol [SILC3].
+
+The following public key algorithms are defined in SILC protocol:
+
+.in 6
+rsa        RSA  (REQUIRED)
+dss        DSS  (OPTIONAL)
+.in 3
+
+DSS is described in [Menezes].  The RSA MUST be implemented according
+PKCS #1 [PKCS1].  The mandatory PKCS #1 implementation in SILC MUST be
+compliant to either PKCS #1 version 1.5 or newer with the following
+notes: The signature encoding is always in same format as the encryption
+encoding regardless of the PKCS #1 version.  The signature with appendix
+(with hash algorithm OID in the data) MUST NOT be used in the SILC.  The
+rationale for this is that there is no binding between the PKCS #1 OIDs
+and the hash algorithms used in the SILC protocol.  Hence, the encoding
+is always in PKCS #1 version 1.5 format.
+
+Additional public key algorithms MAY be defined to be used in SILC.
+
+When signatures are computed in SILC the computing of the signature is
+represented as sign().  The signature computing procedure is dependent
+of the public key algorithm, and the public key or certificate encoding.
+When using SILC public key the signature is computed as described in
+previous paragraph for RSA and DSS keys.  If the hash function is not
+specified separately for signing process SHA-1 MUST be used.  When using
+SSH2 public keys the signature is computed as described in [SSH-TRANS].
+When using X.509 version 3 certificates the signature is computed as
+described in [PKCS7].  When using OpenPGP certificates the signature is
+computed as described in [PGP].
+
+
+.ti 0
+3.10.2.1 Multi-Precision Integers
+
+Multi-Precision (MP) integers in SILC are encoded and decoded as defined
+in PKCS #1 [PKCS1].  MP integers are unsigned, encoded with desired octet
+length.  This means that if the octet length is more than the actual
+length of the integer one or more leading zero octets will appear at the
+start of the encoding.  The actual length of the integer is the bit size
+of the integer not counting any leading zero bits.
+
+
+.ti 0
+3.10.3 Hash Functions
+
+Hash functions are used as part of MAC algorithms defined in the next
+section.  They are also used in the SILC Key Exchange protocol defined
+in the [SILC3].
+
+The following Hash algorithm are defined in SILC protocol:
+
+.in 6
+sha1             SHA-1, length = 20      (REQUIRED)
+md5              MD5, length = 16        (RECOMMENDED)
+.in 3
+
+
+
+.ti 0
+3.10.4 MAC Algorithms
+
+Data integrity is protected by computing a message authentication code
+(MAC) of the packet data.  See [SILC2] for details how to compute the
+MAC for a packet.
+
+The following MAC algorithms are defined in SILC protocol:
+
+.in 6
+hmac-sha1-96     HMAC-SHA1, length = 12 bytes  (REQUIRED)
+hmac-md5-96      HMAC-MD5, length = 12 bytes   (OPTIONAL)
+hmac-sha1        HMAC-SHA1, length = 20 bytes  (OPTIONAL)
+hmac-md5         HMAC-MD5, length = 16 bytes   (OPTIONAL)
+none             No MAC                        (OPTIONAL)
+.in 3
+
+The "none" MAC is not recommended to be used as the packet is not
+authenticated when MAC is not computed.  It is recommended that no
+client or server would accept none MAC except in special debugging
+mode.
+
+The HMAC algorithm is described in [HMAC].  The hash algorithms used
+in HMACs, the SHA-1 is described in [RFC3174] and MD5 is described
+in [RFC1321].
+
+Additional MAC algorithms MAY be defined to be used in SILC.
+
+
+.ti 0
+3.10.5 Compression Algorithms
+
+SILC protocol supports compression that may be applied to unencrypted
+data.  It is recommended to use compression on slow links as it may
+significantly speed up the data transmission.  By default, SILC does not
+use compression which is the mode that must be supported by all SILC
+implementations.
+
+The following compression algorithms are defined:
+
+.in 6
+none        No compression               (REQUIRED)
+zlib        GNU ZLIB (LZ77) compression  (OPTIONAL)
+.in 3
+
+Additional compression algorithms MAY be defined to be used in SILC.
+
+
+.ti 0
+3.11 SILC Public Key
+
+This section defines the type and format of the SILC public key.  All
+implementations MUST support this public key type.  See [SILC3] for
+other optional public key and certificate types allowed in the SILC
+protocol.  Public keys in SILC may be used to authenticate entities
+and to perform other tasks related to public key cryptography.
+
+The format of the SILC Public Key is as follows:
+
+
+
+
+
+
+
+
+.in 5
+.nf
+                     1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                        Public Key Length                      |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|     Algorithm Name Length     |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                         Algorithm Name                        ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Identifier Length       |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                           Identifier                          ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                           Public Data                         ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 5:  SILC Public Key
+
+
+.in 6
+o Public Key Length (4 bytes) - Indicates the full length
+  of the SILC Public Key, not including this field.
+
+o Algorithm Name Length (2 bytes) - Indicates the length
+  of the Algorithm Length field, not including this field.
+
+o Algorithm name (variable length) - Indicates the name
+  of the public key algorithm that the key is.  See the
+  section 3.10.2 Public Key Algorithms for defined names.
+
+o Identifier Length (2 bytes) - Indicates the length of
+  the Identifier field, not including this field.
+
+o Identifier (variable length) - Indicates the identifier
+  of the public key.  This data can be used to identify
+  the owner of the key.  The identifier is of the following
+  format:
+
+     UN   User name
+     HN   Host name or IP address
+     RN   Real name
+     E    EMail address
+     O    Organization
+     C    Country
+
+
+  Examples of an identifier:
+
+    `UN=priikone, HN=poseidon.pspt.fi, E=priikone@poseidon.pspt.fi'
+
+    `UN=sam, HN=dummy.fi, RN=Sammy Sam, O=Company XYZ, C=Finland'
+
+  At least user name (UN) and host name (HN) MUST be provided as
+  identifier.  The fields are separated by commas (`,').  If
+  comma is in the identifier string it must be escaped as `\\,',
+  for example, `O=Company XYZ\\, Inc.'.  Other characters that
+  require escaping are listed in [RFC2253] and are to be escaped
+  as defined therein.
+
+o Public Data (variable length) - Includes the actual
+  public data of the public key.
+
+  The format of this field for RSA algorithm is
+  as follows:
+
+     4 bytes            Length of e
+     variable length    e
+     4 bytes            Length of n
+     variable length    n
+
+
+  The format of this field for DSS algorithm is
+  as follows:
+
+     4 bytes            Length of p
+     variable length    p
+     4 bytes            Length of q
+     variable length    q
+     4 bytes            Length of g
+     variable length    g
+     4 bytes            Length of y
+     variable length    y
+
+  The variable length fields are multiple precession
+  integers encoded as strings in both examples.
+
+  Other algorithms must define their own type of this
+  field if they are used.
+.in 3
+
+All fields in the public key are in MSB (most significant byte first)
+order.  All strings in the public key MUST be UTF-8 encoded.
+
+If an external protocol needs to refer to SILC Public Key by name, the
+names "silc-rsa" and "silc-dss" for SILC Public Key based on RSA algorithm
+and SILC Public Key based on DSS algorithm, respectively, are to be used.
+However, this SILC specification does not use these names directly, and
+they are defined here for external protocols (protocols that may like
+to use SILC Public Key).
+
+
+.ti 0
+3.12 SILC Version Detection
+
+The version detection of both client and server is performed at the
+connection phase while executing the SILC Key Exchange protocol.  The
+version identifier is exchanged between initiator and responder.  The
+version identifier is of the following format:
+
+.in 6
+SILC-<protocol version>-<software version>
+.in 3
+
+The version strings are of the following format:
+
+.in 6
+protocol version = <major>.<minor>
+software version = <major>[.<minor>[.<build or vendor string>]]
+.in 3
+
+Protocol version MUST provide both major and minor version.  Currently
+implementations MUST set the protocol version and accept at least the
+protocol version as SILC-1.2-<software version>.  If new protocol version
+causes incompatibilities with older version the <minor> version number
+MUST be incremented.  The <major> is incremented if new protocol version
+is fully incompatible.
+
+Software version MAY provide major, minor and build (vendor) version.
+The software version MAY be freely set and accepted.  The version string
+MUST consist of printable US-ASCII characters.
+
+Thus, the version strings could be, for example:
+
+.in 6
+SILC-1.1-2.0.2
+SILC-1.0-1.2
+SILC-1.2-1.0.VendorXYZ
+SILC-1.2-2.4.5 Vendor Limited
+.in 3
+
+
+.ti 0
+3.13 Backup Routers
+
+Backup routers may exist in the cell in addition to the primary router.
+However, they must not be active routers or act as routers in the cell.
+Only one router may be acting as primary router in the cell.  In the case
+of failure of the primary router one of the backup routers becomes active.
+The purpose of backup routers are in case of failure of the primary router
+to maintain working connections inside the cell and outside the cell and
+to avoid netsplits.
+
+Backup routers are normal servers in the cell that are prepared to take
+over the tasks of the primary router if needed.  They need to have at
+least one direct and active connection to the primary router of the cell.
+This communication channel is used to send the router information to
+the backup router.  When the backup router connects to the primary router
+of the cell it MUST present itself as router server in the Connection
+Authentication protocol, even though it is normal server as long as the
+primary router is available.  Reason for this is that the configuration
+needed in the responder end requires usually router connection level
+configuration.  The responder, however must understand and treat the
+connection as normal server (except when feeding router level data to
+the backup router).
+
+Backup router must know everything that the primary router knows to be
+able to take over the tasks of the primary router.  It is the primary
+router's responsibility to feed the data to the backup router.  If the
+backup router does not know all the data in the case of failure some
+connections may be lost.  The primary router of the cell must consider
+the backup router being an actual router server when it feeds the data
+to it.
+
+In addition to having direct connection to the primary router of the
+cell, the backup router must also have connection to the same router
+to which the primary router of the cell is connected.  However, it must
+not be the active router connection meaning that the backup router must
+not use that channel as its primary route and it must not notify the
+router about having connected servers, channels and clients behind it.
+It merely connects to the router.  This sort of connection is later
+referred to as being a passive connection.  Some keepalive actions may
+be needed by the router to keep the connection alive.
+
+It is required that other normal servers have passive connections to
+the backup router(s) in the cell.  Some keepalive actions may be needed
+by the server to keep the connection alive.  After they notice the
+failure of the primary router they must start using the connection to
+the first backup router as their primary route.
+
+Also, if any other router in the network is using the cell's primary
+router as its own primary router, it must also have passive connection
+to the cell's backup router.  It too is prepared to switch to use the
+backup router as its new primary router as soon as the original primary
+router becomes unresponsive.
+
+All of the parties of this protocol know which one is the backup router
+of the cell from their local configuration.  Each of the entities must
+be configured accordingly and care must be taken when configuring the
+backup routers, servers and other routers in the network.
+
+It must be noted that some of the channel messages and private messages
+may be lost during the switch to the backup router.  The announcements
+assure that the state of the network is not lost during the switch.
+
+It is RECOMMENDED that there would be at least one backup router in
+the cell.  It is NOT RECOMMENDED to have all servers in the cell acting
+as backup routers as it requires establishing several connections to
+several servers in the cell.  Large cells can easily have several
+backup routers in the cell.
+
+The order of the backup routers are decided at the local configuration
+phase.  All the parties of this protocol must be configured accordingly to
+understand the order of the backup routers.  It is not required that the
+backup server is actually an active server in the cell.  The backup router
+may be a redundant server in the cell that does not accept normal client
+connections at all.  It may be reserved purely for the backup purposes.
+
+If also the first backup router is down as well and there is another
+backup router in the cell then it will start acting as the primary
+router as described above.
+
+
+.ti 0
+3.13.1 Switching to Backup Router
+
+When the primary router of the cell becomes unresponsive, for example
+by sending EOF to the connection, all the parties of this protocol MUST
+replace the old connection to the primary router with first configured
+backup router.  The backup router usually needs to do local modifications
+to its database in order to update all the information needed to maintain
+working routes.  The backup router must understand that clients that
+were originated from the primary router are now originated from some of
+the existing server connections and must update them accordingly.  It
+must also remove those clients that were owned by the primary router
+since those connections were lost when the primary router became
+unresponsive.
+
+All the other parties of the protocol must also update their local
+database to understand that the route to the primary router will now go
+to the backup router.
+
+Servers connected to the backup router MUST send SILC_PACKET_RESUME_ROUTER
+packet with type value 21, to indicate that the server will start using
+the backup router as primary router.  The backup router MUST NOT allow
+this action if it detects that primary is still up and running.  If
+backup router knows that primary is up and running it MUST send
+SILC_PACKET_FAILURE with type value 21 (4 bytes, MSB first order) back
+to the server.  The server then MUST NOT use the backup as primary
+router, but must try to establish connection back to the primary router.
+If the action is allowed type value 21 is sent back to the server from
+the backup router.  It is RECOMMENDED that implementations use the
+SILC_COMMAND_PING command to detect whether primary router is responsive.
+
+The servers connected to the backup router must then announce their
+clients, channels, channel users, channel user modes, channel modes,
+topics and other information to the backup router.  This is to assure
+that none of the important notify packets were lost during the switch
+to the backup router.  The backup router must check which of these
+announced entities it already has and distribute the new ones to the
+primary router.
+
+The backup router too must announce its servers, clients, channels
+and other information to the new primary router.  The primary router
+of the backup router too must announce its information to the backup
+router.  Both must process only the ones they do not know about.  If
+any of the announced modes do not match then they are enforced in
+normal manner as defined in section 4.2.1 Announcing Clients, Channels
+and Servers.
+
+
+.ti 0
+3.13.2 Resuming Primary Router
+
+Usually the primary router is unresponsive only a short period of time
+and it is intended that the original router of the cell will resume
+its position as primary router when it comes back online.  The backup
+router that is now acting as primary router of the cell must constantly
+try to connect to the original primary router of the cell.  It is
+RECOMMENDED that it would try to reconnect in 30 second intervals to
+the primary router.
+
+When the connection is established to the primary router the backup
+resuming protocol is executed.  The protocol is advanced as follows:
+
+  1. Backup router sends SILC_PACKET_RESUME_ROUTER packet with type
+     value 1 to the primary router that came back online.  The packet
+     will indicate the primary router has been replaced by the backup
+     router.  After sending the packet the backup router will announce
+     all of its channels, channel users, modes etc. to the primary
+     router.
+
+     If the primary knows that it has not been replaced (for example
+     the backup itself disconnected from the primary router and thinks
+     that it is now primary in the cell) the primary router send
+     SILC_PACKET_FAILURE with the type value 1 (4 bytes, MSB first
+     order) back to the backup router.  If backup receives this it
+     MUST NOT continue with the backup resuming protocol.
+
+  2. Backup router sends SILC_PACKET_RESUME_ROUTER packet with type
+     value 1 to its current primary router to indicate that it will
+     resign as being primary router.  Then, backup router sends the
+     SILC_PACKET_RESUME_ROUTER packet with type value 1 to all
+     connected servers to also indicate that it will resign as being
+     primary router.
+
+  3. Backup router also send SILC_PACKET_RESUME_ROUTER packet with
+     type value 1 to the router that is using the backup router
+     currently as its primary router.
+
+  4. Any server and router that receives the SILC_PACKET_RESUME_ROUTER
+     with type value 1 must reconnect immediately to the primary
+     router of the cell that came back online.  After they have created
+     the connection they MUST NOT use that connection as active primary
+     route but still route all packets to the backup router.  After
+     the connection is created they MUST send SILC_PACKET_RESUME_ROUTER
+     with type value 2 back to the backup router.  The session ID value
+     found in the first packet MUST be set in this packet.
+
+  5. Backup router MUST wait for all packets with type value 2 before
+     it continues with the protocol.  It knows from the session ID values
+     set in the packet when it has received all packets.  The session
+     value should be different in all packets it has sent earlier.
+     After the packets are received the backup router sends the
+     SILC_PACKET_RESUME_ROUTER packet with type value 3 to the
+     primary router that came back online.  This packet will indicate
+     that the backup router is now ready to resign as being primary
+     router.  The session ID value in this packet MUST be the same as
+     in the first packet sent to the primary router.  During this time
+     the backup router must still route all packets it is receiving
+     from server connections.
+
+  6. The primary router receives the packet and send the packet
+     SILC_PACKET_RESUME_ROUTER with type value 4 to all connected servers
+     including the backup router.  It also sends the packet with type
+     value 4 to its primary router, and to the router that is using
+     it as its primary router.  The Session ID value in these packets
+     SHOULD be zero (0).
+
+  7. Any server and router that receives the SILC_PACKET_RESUME_ROUTER
+     packet with type value 4 must switch their primary route to the new
+     primary router and remove the route for the backup router, since
+     it is no longer the primary router of the cell.  They must also
+     update their local database to understand that the clients are
+     not originated from the backup router but from the locally connected
+     servers.  After that they MUST announce their channels, channel
+     users, modes etc. to the primary router.  They MUST NOT use the
+     backup router connection after this and the connection is considered
+     to be a passive connection.  The implementation SHOULD be able
+     to disable the connection without closing the actual link.
+
+After this protocol is executed the backup router is now again a normal
+server in the cell that has the backup link to the primary router.  The
+primary router feeds the router specific data again to the backup router.
+All server connections to the backup router are considered passive
+connections.
+
+When the primary router of the cell comes back online and connects
+to its remote primary router, the remote primary router MUST send the
+SILC_PACKET_RESUME_ROUTER packet with type value 20 indicating that the
+connection is not allowed since the router has been replaced by an
+backup router in the cell.  The session ID value in this packet SHOULD be
+zero (0).  When the primary router receives this packet it MUST NOT use
+the connection as active connection but must understand that it cannot
+act as primary router in the cell, until the backup resuming protocol has
+been executed.
+
+The following type values has been defined for SILC_PACKET_RESUME_ROUTER
+packet:
+
+  1    SILC_SERVER_BACKUP_START
+  2    SILC_SERVER_BACKUP_START_CONNECTED
+  3    SILC_SERVER_BACKUP_START_ENDING
+  4    SILC_SERVER_BACKUP_START_RESUMED
+  20   SILC_SERVER_BACKUP_START_REPLACED
+  21   SILC_SERVER_BACKUP_START_USE
+
+If any other value is found in the type field the packet MUST be
+discarded.  The SILC_PACKET_RESUME_ROUTER packet and its payload
+is defined in [SILC2].
+
+
+.ti 0
+4 SILC Procedures
+
+This section describes various SILC procedures such as how the
+connections are created and registered, how channels are created and
+so on.  The references [SILC2], [SILC3] and [SILC4] permeate this
+section's definitions.
+
+
+
+
+.ti 0
+4.1 Creating Client Connection
+
+This section describes the procedure when a client connects to SILC
+server.  When client connects to server the server MUST perform IP
+address lookup and reverse IP address lookup to assure that the origin
+host really is who it claims to be.  Client, a host, connecting to server
+SHOULD have both valid IP address and fully qualified domain name (FQDN).
+
+After that the client and server performs SILC Key Exchange protocol
+which will provide the key material used later in the communication.
+The key exchange protocol MUST be completed successfully before the
+connection registration may continue.  The SILC Key Exchange protocol
+is described in [SILC3].
+
+Typical server implementation would keep a list of connections that it
+allows to connect to the server.  The implementation would check, for
+example, the connecting client's IP address from the connection list
+before the SILC Key Exchange protocol has been started.  The reason for
+this is that if the host is not allowed to connect to the server there
+is no reason to perform the key exchange protocol.
+
+After successful key exchange protocol the client and server perform
+connection authentication protocol.  The purpose of the protocol is to
+authenticate the client connecting to the server.  Flexible
+implementation could also accept the client to connect to the server
+without explicit authentication.  However, if authentication is
+desired for a specific client it may be based on passphrase or
+public key authentication.  If authentication fails the connection
+MUST be terminated.  The connection authentication protocol is described
+in [SILC3].
+
+After successful key exchange and authentication protocol the client
+MUST register itself by sending SILC_PACKET_NEW_CLIENT packet to the
+server.  This packet includes various information about the client
+that the server uses to register the client.  Server registers the
+client and sends SILC_PACKET_NEW_ID to the client which includes the
+created Client ID that the client MUST start using after that.  After
+that all SILC packets from the client MUST have the Client ID as the
+Source ID in the SILC Packet Header, described in [SILC2].
+
+Client MUST also get the server's Server ID that is to be used as
+Destination ID in the SILC Packet Header when communicating with
+the server (for example when sending commands to the server).  The
+ID may be resolved in two ways.  Client can take the ID from an
+previously received packet from server that MUST include the ID,
+or to send SILC_COMMAND_INFO command and receive the Server ID as
+command reply.
+
+Server MAY choose not to use the information received in the
+SILC_PACKET_NEW_CLIENT packet.  For example, if public key or
+certificate were used in the authentication, server MAY use that
+information rather than what it received from client.  This is a suitable
+way to get the true information about client if it is available.
+
+The nickname of client is initially set to the username sent in the
+SILC_PACKET_NEW_CLIENT packet.  User may set the nickname to something
+more desirable by sending SILC_COMMAND_NICK command.  However, this is
+not required as part of registration process.
+
+Server MUST also distribute the information about newly registered
+client to its router (or if the server is router, to all routers in
+the SILC network).  More information about this in [SILC2].
+
+Router server MUST also check whether some client in the local cell
+is watching for the nickname this new client has, and send the
+SILC_NOTIFY_TYPE_WATCH to the watcher.
+
+
+.ti 0
+4.2 Creating Server Connection
+
+This section describes the procedure when server connects to its
+router (or when router connects to other router, the cases are
+equivalent).  The procedure is very much alike to when a client
+connects to the server thus it is not repeated here.
+
+One difference is that server MUST perform connection authentication
+protocol with proper authentication.  A proper authentication is based
+on passphrase authentication or public key authentication based on
+digital signatures.
+
+After server and router have successfully performed the key exchange
+and connection authentication protocol, the server MUST register itself
+to the router by sending SILC_PACKET_NEW_SERVER packet.  This packet
+includes the server's Server ID that it has created by itself and
+other relevant information about the server.  The router receiving the
+ID MUST verify that the IP address in the Server ID is same as the
+server's real IP address.
+
+After router has received the SILC_PACKET_NEW_SERVER packet it
+distributes the information about newly registered server to all routers
+in the SILC network.  More information about this is in [SILC2].
+
+As the client needed to resolve the destination ID this MUST be done by
+the server that connected to the router, as well.  The way to resolve it
+is to get the ID from previously received packet.  The server MAY also
+use SILC_COMMAND_INFO command to resolve the ID.  Server MUST also start
+using its own Server ID as Source ID in SILC Packet Header and the
+router's Server ID as Destination when communicating with the router.
+
+
+.ti 0
+4.2.1 Announcing Clients, Channels and Servers
+
+After server or router has connected to the remote router, and it already
+has connected clients and channels it MUST announce them to the router.
+If the server is router server, also all the local servers in the cell
+MUST be announced.
+
+All clients are announced by compiling a list of ID Payloads into the
+SILC_PACKET_NEW_ID packet.  All channels are announced by compiling a
+list of Channel Payloads into the SILC_PACKET_NEW_CHANNEL packet.
+Channels' mode, founder public key, channel public keys, and other
+channel mode specific data is announced by sending the
+SILC_NOTIFY_TYPE_CMODE_CHANGE notify list.
+
+The channel public keys that are announced are compiled in Argument
+List Payload where the argument type is 0x03, and each argument is
+Public Key Payload containing one public key or certificate.
+
+Also, the channel users on the channels must be announced by compiling
+a list of Notify Payloads with the SILC_NOTIFY_TYPE_JOIN notify type
+into the SILC_PACKET_NOTIFY packet.  The users' modes on the channel
+must also be announced by compiling list of Notify Payloads with the
+SILC_NOTIFY_TYPE_CUMODE_CHANGE notify type into the SILC_PACKET_NOTIFY
+packet.
+
+The router MUST also announce the local servers by compiling list of
+ID Payloads into the SILC_PACKET_NEW_ID packet.
+
+Also, clients' modes (user modes in SILC) MUST be announced.  This is
+done by compiling a list of Notify Payloads with SILC_NOTIFY_UMODE_CHANGE
+notify type into the SILC_PACKET_NOTIFY packet.  Also, channels' topics
+MUST be announced by compiling a list of Notify Payloads with the
+SILC_NOTIFY_TOPIC_SET notify type into the SILC_PACKET_NOTIFY packet.
+Also, channel's invite and ban lists MUST be announced by compiling list
+of Notify Payloads with the SILC_NOTIFY_TYPE_INVITE and
+SILC_NOTIFY_TYPE_BAN notify types, respectively, into the 
+SILC_PACKET_NOTIFY packet.
+
+The router which receives these lists MUST process them and broadcast
+the packets to its primary router.  When processing the announced channels
+and channel users the router MUST check whether a channel exists already
+with the same name.  If channel exists with the same name it MUST check
+whether the Channel ID is different.  If the Channel ID is different the
+router MUST send the notify type SILC_NOTIFY_TYPE_CHANNEL_CHANGE to the
+server to force the channel ID change to the ID the router has.  If the
+mode of the channel is different the router MUST send the notify type
+SILC_NOTIFY_TYPE_CMODE_CHANGE to the server to force the mode change
+to the mode that the router has.
+
+The router MUST also generate new channel key and distribute it to the
+channel.  The key MUST NOT be generated if the SILC_CMODE_PRIVKEY mode
+is set.
+
+If the channel has a channel founder already on the router, the router
+MUST send the notify type SILC_NOTIFY_TYPE_CUMODE_CHANGE to the server
+to force the mode change for the channel founder on the server.  The
+channel founder privileges MUST be removed on the server.
+
+If the channel public keys are already set on the on router, the router
+MUST ignore the received channel public key list and send the notify
+type SILC_NOTIFY_TYPE_CUMODE_CHANGE to the server which includes the
+channel public key list that is on router.  The server MUST change the
+list to the one it receives from router.
+
+The router processing the channels MUST also compile a list of
+Notify Payloads with the SILC_NOTIFY_TYPE_JOIN notify type into the
+SILC_PACKET_NOTIFY and send the packet to the server.  This way the
+server (or router) will receive the clients on the channel that
+the router has.
+
+
+.ti 0
+4.3 Joining to a Channel
+
+This section describes the procedure when client joins to a channel.
+Client joins to channel by sending command SILC_COMMAND_JOIN to the
+server.  If the receiver receiving join command is normal server the
+server MUST check its local list whether this channel already exists
+locally.  This would indicate that some client connected to the server
+has already joined to the channel.  If this is the case, the client is
+joined to the channel, new channel key is created and information about
+newly joined channel is sent to the router.  The router is informed
+by sending SILC_NOTIFY_TYPE_JOIN notify type.  The notify type MUST
+also be sent to the local clients on the channel.  The new channel key
+is also sent to the router and to local clients on the channel.
+
+If the channel does not exist in the local list the client's command
+MUST be sent to the router which will then perform the actual joining
+procedure.  When server receives the reply to the command from the
+router it MUST be sent to the client which sent the command originally.
+Server will also receive the channel key from the server that it MUST
+send to the client which originally requested the join command.  The
+server MUST also save the channel key.
+
+If the receiver of the join command is router it MUST first check its
+local list whether anyone in the cell has already joined to the channel.
+If this is the case, the client is joined to the channel and reply is
+sent to the client.  If the command was sent by server the command reply
+is sent to the server which sent it.  Then the router MUST also create
+new channel key and distribute it to all clients on the channel and
+all servers that have clients on the channel.  Router MUST also send
+the SILC_NOTIFY_TYPE_JOIN notify type to local clients on the channel
+and to local servers that have clients on the channel.
+
+If the channel does not exist on the router's local list it MUST
+check the global list whether the channel exists at all.  If it does
+the client is joined to the channel as described previously.  If
+the channel does not exist the channel is created and the client
+is joined to the channel.  The channel key is also created and
+distributed as previously described.  The client joining to the created
+channel is made automatically channel founder and both channel founder
+and channel operator privileges are set for the client.
+
+If the router created the channel in the process, information about the
+new channel MUST be broadcast to all routers.  This is done by
+broadcasting SILC_PACKET_NEW_CHANNEL packet to the router's primary
+route.  When the router joins the client to the channel it MUST also
+send information about newly joined client to all routers in the SILC
+network.  This is done by broadcasting the SILC_NOTIFY_TYPE_JOIN notify
+type to the router's primary route.
+
+It is important to note that new channel key is created always when
+new client joins to channel, whether the channel has existed previously
+or not.  This way the new client on the channel is not able to decrypt
+any of the old traffic on the channel.  Client which receives the reply to
+the join command MUST start using the received Channel ID in the channel
+message communication thereafter.  Client also receives the key for the
+channel in the command reply.  Note that the channel key is never
+generated or distributed if the SILC_CMODE_PRIVKEY mode is set.
+
+
+.ti 0
+4.4 Channel Key Generation
+
+Channel keys are created by router which creates the channel by taking
+enough randomness from cryptographically strong random number generator.
+The key is generated always when channel is created, when new client
+joins a channel and after the key has expired.  Key could expire for
+example in an hour.
+
+The key MUST also be re-generated whenever some client leaves a channel.
+In this case the key is created from scratch by taking enough randomness
+from the random number generator.  After that the key is distributed to
+all clients on the channel.  However, channel keys are cell specific thus
+the key is created only on the cell where the client, which left the
+channel, exists.  While the server or router is creating the new channel
+key, no other client may join to the channel.  Messages that are sent
+while creating the new key are still processed with the old key.  After
+server has sent the SILC_PACKET_CHANNEL_KEY packet client MUST start
+using the new key.  If server creates the new key the server MUST also
+send the new key to its router.  See [SILC2] for more information about
+how channel messages must be encrypted and decrypted when router is
+processing them.
+
+If the key changes very often due to joining traffic on the channel it
+is RECOMMENDED that client implementation would cache some of the old
+channel keys for short period of time so that it is able to decrypt all
+channel messages it receives.  It is possible that on a heavy traffic
+channel a message encrypted with channel key that was just changed
+is received by client after the new key was set into use.  This is
+possible because not all clients may receive the new key at the same
+time, and may still be sending messages encrypted with the old key.
+
+When client receives the SILC_PACKET_CHANNEL_KEY packet with the
+Channel Key Payload it MUST process the key data to create encryption
+and decryption key, and to create the HMAC key that is used to compute
+the MACs of the channel messages.  The processing is as follows:
+
+  channel_key  = raw key data
+  HMAC key     = hash(raw key data)
+
+The raw key data is the key data received in the Channel Key Payload.
+The hash() function is the hash function used in the HMAC of the channel.
+Note that the server also MUST save the channel key.
+
+
+.ti 0
+4.5 Private Message Sending and Reception
+
+Private messages are sent point to point.  Client explicitly destine
+a private message to specific client that is delivered to only to that
+client.  No other client may receive the private message.  The receiver
+of the private message is destined in the SILC Packet Header as in any
+other packet as well.  The Source ID in the SILC Packet Header MUST be
+the ID of the sender of the message.
+
+If the sender of a private message does not know the receiver's Client
+ID, it MUST resolve it from server.  There are two ways to resolve the
+client ID from server; it is RECOMMENDED that client implementations
+send SILC_COMMAND_IDENTIFY command to receive the Client ID.  Client
+MAY also send SILC_COMMAND_WHOIS command to receive the Client ID.
+If the sender has received earlier a private message from the receiver
+it should have cached the Client ID from the SILC Packet Header.
+
+If server receives a private message packet which includes invalid
+destination Client ID the server MUST send SILC_NOTIFY_TYPE_ERROR
+notify to the client with error status indicating that such Client ID
+does not exist.
+
+See [SILC2] for description of private message encryption and decryption
+process.
+
+
+.ti 0
+4.6 Private Message Key Generation
+
+Private message MAY be protected with a key generated by the client.
+The key may be generated and sent to the other client by sending packet
+SILC_PACKET_PRIVATE_MESSAGE_KEY which travels through the network
+and is secured by session keys.  After that the private message key
+is used in the private message communication between those clients.
+The key sent inside the payload SHOULD be randomly generated.  This
+packet MUST NOT be used to send pre-shared keys.
+
+Another choice is to entirely use keys that are not sent through
+the SILC network at all.  This significantly adds security.  This key
+could be a pre-shared key that is known by both of the clients.  Both
+agree about using the key and start sending packets that indicate
+that the private message is secured using private message key.  In
+case of pre-shared keys (static keys) the IV used in encryption SHOULD
+be chosen randomly.
+
+It is also possible to negotiate fresh key material by performing
+Key Agreement.  The SILC_PACKET_KEY_AGREEMENT packet MAY be used to
+negotiate the fresh key material.  In this case the resulting key
+material is used to secure the private messages.  Also, the IV used
+in encryption is used as defined in [SILC3], unless otherwise stated
+by the encryption mode used.  By performing Key Agreement the clients
+may negotiate the cipher and HMAC to be used in the private message
+encryption and to negotiate additional security parameters.
+
+If the key is pre-shared key or other key material not generated by
+Key Agreement, then the key material SHOULD be processed as defined
+in [SILC3].  The hash function to be used SHOULD be SHA1.  In the
+processing, however, the HASH, as defined in [SILC3] MUST be ignored.
+After processing the key material it is employed as defined in [SILC3].
+In this case also, implementations SHOULD use the SILC protocol's
+mandatory cipher and HMAC in private message encryption.
+
+
+.ti 0
+4.7 Channel Message Sending and Reception
+
+Channel messages are delivered to a group of users.  The group forms a
+channel and all clients on the channel receives messages sent to the
+channel.  The Source ID in the SILC Packet Header MUST be the ID
+of the sender of the message.
+
+Channel messages are destined to a channel by specifying the Channel ID
+as Destination ID in the SILC Packet Header.  The server MUST then
+distribute the message to all clients, except to the original sender,
+on the channel by sending the channel message destined explicitly to a
+client on the channel.  However, the Destination ID MUST still remain
+as the Channel ID.
+
+If server receives a channel message packet which includes invalid
+destination Channel ID the server MUST send SILC_NOTIFY_TYPE_ERROR
+notify to the sender with error status indicating that such Channel ID
+does not exist.
+
+See the [SILC2] for description of channel message routing for router
+servers, and channel message encryption and decryption process.
+
+
+.ti 0
+4.8 Session Key Regeneration
+
+Session keys MUST be regenerated periodically, say, once in an hour.
+The re-key process is started by sending SILC_PACKET_REKEY packet to
+other end, to indicate that re-key must be performed.  The initiator
+of the connection SHOULD initiate the re-key.
+
+If perfect forward secrecy (PFS) flag was selected in the SILC Key
+Exchange protocol [SILC3] the re-key MUST cause new key exchange with
+SKE protocol.  In this case the protocol is secured with the old key
+and the protocol results to new key material.  See [SILC3] for more
+information.  After the SILC_PACKET_REKEY packet is sent the sender
+will perform the SKE protocol.
+
+If PFS flag was set the resulted key material is processed as described
+in the section Processing the Key Material in [SILC3].  The difference
+with re-key in the processing is that the initial data for the hash
+function is just the resulted key material and not the HASH as it
+is not computed at all with re-key.  Other than that, the key processing
+it equivalent to normal SKE negotiation.
+
+If PFS flag was not set, which is the default case, then re-key is done
+without executing SKE protocol.  In this case, the new key is created by
+providing the current sending encryption key to the SKE protocol's key
+processing function.  The process is described in the section Processing
+the Key Material in [SILC3].  The difference in the processing is that
+the initial data for the hash function is the current sending encryption
+key and not the SKE's KEY and HASH values.  Other than that, the key
+processing is equivalent to normal SKE negotiation.
+
+After both parties have regenerated the session key, both MUST send
+SILC_PACKET_REKEY_DONE packet to each other.  These packets are still
+secured with the old key.  After these packets, the subsequent packets
+MUST be protected with the new key.
+
+
+.ti 0
+4.9 Command Sending and Reception
+
+Client usually sends the commands in the SILC network.  In this case
+the client simply sends the command packet to server and the server
+processes it and replies with command reply packet.  See the [SILC4]
+for detailed description of all commands.
+
+However, if the server is not able to process the command, it is sent to
+the server's router.  This is case for example with commands such as
+SILC_COMMAND_JOIN and SILC_COMMAND_WHOIS commands.  However, there are
+other commands as well [SILC4].  For example, if client sends the WHOIS
+command requesting specific information about some client the server must
+send the WHOIS command to router so that all clients in SILC network are
+searched.  The router, on the other hand, sends the WHOIS command further
+to receive the exact information about the requested client.  The WHOIS
+command travels all the way to the server which owns the client and it
+replies with command reply packet.  Finally, the server which sent the
+command receives the command reply and it must be able to determine which
+client sent the original command.  The server then sends command reply to
+the client.  Implementations should have some kind of cache to handle, for
+example, WHOIS information.  Servers and routers along the route could all
+cache the information for faster referencing in the future.
+
+The commands sent by server may be sent hop by hop until someone is able
+to process the command.  However, it is preferred to destine the command
+as precisely as it is possible.  In this case, other routers en route
+MUST route the command packet by checking the true sender and true
+destination of the packet.  However, servers and routers MUST NOT route
+command reply packets to clients coming from other servers.  Client
+MUST NOT accept command reply packet originated from anyone else but
+from its own server.
+
+
+.ti 0
+4.10 Closing Connection
+
+When remote client connection is closed the server MUST send the notify
+type SILC_NOTIFY_TYPE_SIGNOFF to its primary router and to all channels
+the client was joined.  The server MUST also save the client's information
+for a period of time for history purposes.
+
+When remote server or router connection is closed the server or router
+MUST also remove all the clients that was behind the server or router
+from the SILC Network.  The server or router MUST also send the notify
+type SILC_NOTIFY_TYPE_SERVER_SIGNOFF to its primary router and to all
+local clients that are joined on the same channels with the remote
+server's or router's clients.
+
+Router server MUST also check whether some client in the local cell
+is watching for the nickname this client has, and send the
+SILC_NOTIFY_TYPE_WATCH to the watcher, unless the client which left
+the network has the SILC_UMODE_REJECT_WATCHING user mode set.
+
+
+
+
+.ti 0
+4.11 Detaching and Resuming a Session
+
+SILC protocol provides a possibility for a client to detach itself from
+the network without actually signing off from the network.  The client
+connection to the server is closed but the client remains as valid client
+in the network.  The client may then later resume its session back from
+any server in the network.
+
+When client wishes to detach from the network it MUST send the
+SILC_COMMAND_DETACH command to its server.  The server then MUST set
+SILC_UMODE_DETACHED mode to the client and send SILC_NOTIFY_UMODE_CHANGE
+notify to its primary router, which then MUST broadcast it further
+to other routers in the network.  This user mode indicates that the
+client is detached from the network.  Implementations MUST NOT use
+the SILC_UMODE_DETACHED flag to determine whether a packet can be sent
+to the client.  All packets MUST still be sent to the client even if
+client is detached from the network.  Only the server that originally
+had the active client connection is able to make the decision after it
+notices that the network connection is not active.  In this case the
+default case is to discard the packet.
+
+The SILC_UMODE_DETACHED flag cannot be set by client itself directly
+with SILC_COMMAND_UMODE command, but only implicitly by sending the
+SILC_COMMAND_DETACH command.  The flag also cannot be unset by the
+client, server or router with SILC_COMMAND_UMODE command, but only
+implicitly by sending and receiving the SILC_PACKET_RESUME_CLIENT
+packet.
+
+When the client wishes to resume its session in the SILC Network it
+connects to a server in the network, which MAY also be a different
+from the original server, and performs normal procedures regarding
+creating a connection as described in section 4.1.  After the SKE
+and the Connection Authentication protocols has been successfully
+completed the client MUST NOT send SILC_PACKET_NEW_CLIENT packet, but
+MUST send SILC_PACKET_RESUME_CLIENT packet.  This packet is used to
+perform the resuming procedure.  The packet MUST include the detached
+client's Client ID, which the client must know.  It also includes
+Authentication Payload which includes signature computed with the
+client's private key.  The signature is computed as defined in the
+section 3.9.1.  Thus, the authentication method MUST be based in
+public key authentication.
+
+When server receive the SILC_PACKET_RESUME_CLIENT packet it MUST
+do the following:  Server checks that the Client ID is valid client
+and that it has the SILC_UMODE_DETACHED mode set.  Then it verifies
+the Authentication Payload with the detached client's public key.
+If it does not have the public key it retrieves it by sending
+SILC_COMMAND_GETKEY command to the server that has the public key from
+the original client connection.  The server MUST NOT use the public
+key received in the SKE protocol for this connection.  If the
+signature is valid the server unsets the SILC_UMODE_DETACHED flag,
+and sends the SILC_PACKET_RESUME_CLIENT packet to its primary router.
+The routers MUST broadcast the packet and unset the SILC_UMODE_DETACHED
+flag when the packet is received.  If the server is router server it
+also MUST send the SILC_PACKET_RESUME_CLIENT packet to the original
+server whom owned the detached client.
+
+The servers and routers that receives the SILC_PACKET_RESUME_CLIENT
+packet MUST know whether the packet already has been received for
+the client.  It is a protocol error to attempt to resume the client
+session from more than one server.  The implementations could set
+internal flag that indicates that the client is resumed.  If router
+receive SILC_PACKET_RESUME_CLIENT packet for client that is already
+resumed the client MUST be killed from the network.  This would
+indicate that the client is attempting to resume the session more
+than once which is a protocol error.  In this case the router sends
+SILC_NOTIFY_TYPE_KILLED to the client.  All routers that detect
+the same situation MUST also send the notify for the client.
+
+The servers and routers that receive the SILC_PACKET_RESUME_CLIENT
+must also understand that the client may not be found behind the
+same server that it originally came from.  They must update their
+caches according to this.  The server that now owns the client session
+MUST check whether the Client ID of the resumed client is based
+on the server's Server ID.  If it is not it creates a new Client
+ID and send SILC_NOTIFY_TYPE_NICK_CHANGE to the network.  It MUST
+also send the channel keys of all channels that the client has
+joined to the client since it does not have them.  Whether the
+Client ID was changed or not the server MUST send SILC_PACKET_NEW_ID
+packet to the client.  Only after this is the client resumed back
+to the network and may start sending packets and messages.
+
+It is also possible that the server did not know about the global
+channels before the client resumed.  In this case it joins the client
+to the channels, generates new channel keys and distributes the keys
+to the channels as described in section 4.4.
+
+It is an implementation issue for how long servers keep detached client
+sessions.  It is RECOMMENDED that the detached sessions would be
+persistent as long as the server is running.
+
+
+.ti 0
+5 Security Considerations
+
+Security is central to the design of this protocol, and these security
+considerations permeate the specification.  Common security considerations
+such as keeping private keys truly private and using adequate lengths for
+symmetric and asymmetric keys must be followed in order to maintain the
+security of this protocol.
+
+Special attention must also be paid to the servers and routers that are
+running the SILC service.  The SILC protocol's security depends greatly
+on the security and the integrity of the servers and administrators that
+are running the service.  It is recommended that some form of registration
+is required by the server and router administrator prior to acceptance to
+the SILC Network.  Even though the SILC protocol is secure in a network
+of mutual distrust between clients, servers, routers and administrators
+of the servers, the client should be able to trust the servers they are
+using if they wish to do so.
+
+It however must be noted that if the client requires absolute security
+by not trusting any of the servers or routers in the SILC Network, it can
+be accomplished by negotiating private keys outside the SILC Network,
+either using SKE or some other key exchange protocol, or to use some
+other external means for distributing the keys.  This applies for all
+messages, private messages and channel messages.
+
+It is important to note that SILC, like any other security protocol, is
+not a foolproof system; the SILC servers and routers could very well be
+compromised.  However, to provide an acceptable level of security and
+usability for end users, the protocol uses many times session keys or
+other keys generated by the servers to secure the messages.  This is an
+intentional design feature to allow ease of use for end users.  This way
+the network is still usable, and remains encrypted even if the external
+means of distributing the keys is not working.  The implementation,
+however, may like to not follow this design feature, and may always
+negotiate the keys outside SILC network.  This is an acceptable solution
+and many times recommended.  The implementation still must be able to
+work with the server generated keys.
+
+If this is unacceptable for the client or end user, the private keys
+negotiated outside the SILC Network should always be used.  In the end
+it is the implementor's choice whether to negotiate private keys by
+default or whether to use the keys generated by the servers.
+
+It is also recommended that router operators in the SILC Network would
+form a joint forum to discuss the router and SILC Network management
+issues.  Also, router operators along with the cell's server operators
+should have a forum to discuss the cell management issues.
+
+
+.ti 0
+6 References
+
+[SILC2]      Riikonen, P., "SILC Packet Protocol", Internet Draft,
+             May 2002.
+
+[SILC3]      Riikonen, P., "SILC Key Exchange and Authentication
+             Protocols", Internet Draft, May 2002.
+
+[SILC4]      Riikonen, P., "SILC Commands", Internet Draft, May 2002.
+
+[IRC]        Oikarinen, J., and Reed D., "Internet Relay Chat Protocol",
+             RFC 1459, May 1993.
+
+[IRC-ARCH]   Kalt, C., "Internet Relay Chat: Architecture", RFC 2810,
+             April 2000.
+
+[IRC-CHAN]   Kalt, C., "Internet Relay Chat: Channel Management", RFC
+             2811, April 2000.
+
+[IRC-CLIENT] Kalt, C., "Internet Relay Chat: Client Protocol", RFC
+             2812, April 2000.
+
+[IRC-SERVER] Kalt, C., "Internet Relay Chat: Server Protocol", RFC
+             2813, April 2000.
+
+[SSH-TRANS]  Ylonen, T., et al, "SSH Transport Layer Protocol",
+             Internet Draft.
+
+[PGP]        Callas, J., et al, "OpenPGP Message Format", RFC 2440,
+             November 1998.
+
+[SPKI]       Ellison C., et al, "SPKI Certificate Theory", RFC 2693,
+             September 1999.
+
+[PKIX-Part1] Housley, R., et al, "Internet X.509 Public Key
+             Infrastructure, Certificate and CRL Profile", RFC 2459,
+             January 1999.
+
+[Schneier]   Schneier, B., "Applied Cryptography Second Edition",
+             John Wiley & Sons, New York, NY, 1996.
+
+[Menezes]    Menezes, A., et al, "Handbook of Applied Cryptography",
+             CRC Press 1997.
+
+[OAKLEY]     Orman, H., "The OAKLEY Key Determination Protocol",
+             RFC 2412, November 1998.
+
+[ISAKMP]     Maughan D., et al, "Internet Security Association and
+             Key Management Protocol (ISAKMP)", RFC 2408, November
+             1998.
+
+[IKE]        Harkins D., and Carrel D., "The Internet Key Exchange
+             (IKE)", RFC 2409, November 1998.
+
+[HMAC]       Krawczyk, H., "HMAC: Keyed-Hashing for Message
+             Authentication", RFC 2104, February 1997.
+
+[PKCS1]      Kalinski, B., and Staddon, J., "PKCS #1 RSA Cryptography
+             Specifications, Version 2.0", RFC 2437, October 1998.
+
+[RFC2119]    Bradner, S., "Key Words for use in RFCs to Indicate
+             Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+[RFC2279]    Yergeau, F., "UTF-8, a transformation format of ISO
+             10646", RFC 2279, January 1998.
+
+[RFC1321]    Rivest R., "The MD5 Message-Digest Algorithm", RFC 1321,
+             April 1992.
+
+[RFC3174]    Eastlake, F., et al., "US Secure Hash Algorithm 1 (SHA1)",
+             RFC 3174, September 2001.
+
+[PKCS7]      Kalinski, B., "PKCS #7: Cryptographic Message Syntax,
+             Version 1.5", RFC 2315, March 1998.
+
+[RFC2253]    Wahl, M., et al., "Lightweight Directory Access Protocol
+             (v3): UTF-8 String Representation of Distinguished Names",
+             RFC 2253, December 1997.
+
+
+.ti 0
+7 Author's Address
+
+.nf
+Pekka Riikonen
+Snellmaninkatu 34 A 15
+70100 Kuopio
+Finland
+
+EMail: priikone@iki.fi
+
+
+.ti 0
+8 Full Copyright Statement
+
+Copyright (C) The Internet Society (2003). All Rights Reserved.
+
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it
+or assist in its implementation may be prepared, copied, published
+and distributed, in whole or in part, without restriction of any
+kind, provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing
+the copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of
+developing Internet standards in which case the procedures for
+copyrights defined in the Internet Standards process must be
+followed, or as required to translate it into languages other than
+English.
+
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+
+This document and the information contained herein is provided on an
+"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
index 41426d40497cc96af54d9858257d251fc5784657..2610cb23ba34be08461735a7b49472551f5c236e 100644 (file)
@@ -157,6 +157,10 @@ General {
        #qos_bytes_limit = 2048;
        #qos_limit_sec = 0;
        #qos_limit_usec = 500000;
+
+       # Debug string.  Debug string can be set to print debugging from
+       # the running server.  The debug is redirected to stderr.
+       # debug_string = "";
 };
 
 #
@@ -242,7 +246,8 @@ ServerInfo {
 # are redirected on the less important ones, thus setting a valid logging
 # file for "Info" will ensure logging for all channels, while setting
 # logging file for "Errors" will ensure logging for channels "Errors"
-# and "Fatals"
+# and "Fatals".  If only, for example, "Info" is set then all logs go to
+# that file (like in example below).
 #
 Logging {
        # Use timestamp in the logging files? (Usually it is a good idea,
@@ -266,26 +271,26 @@ Logging {
        # Informational messages
        Info {
                File = "@LOGSDIR@/silcd.log";
-               Size = "50k";
+               Size = "100k";
        };
 
        # Warning messages
-       Warnings {
-               File = "@LOGSDIR@/silcd_warnings.log";
-               Size = "50k";
-       };
+       #Warnings {
+       #       File = "@LOGSDIR@/silcd_warnings.log";
+       #       Size = "50k";
+       #};
 
        # Error messages
-       Errors {
-               File = "@LOGSDIR@/silcd_errors.log";
-               Size = "50k";
-       };
+       #Errors {
+       #       File = "@LOGSDIR@/silcd_errors.log";
+       #       Size = "50k";
+       #};
 
        # Fatal messages
-       Fatals {
-               File = "@LOGSDIR@/silcd_fatals.log";
-               Size = "50k";
-       };
+       #Fatals {
+       #       File = "@LOGSDIR@/silcd_fatals.log";
+       #       Size = "50k";
+       #};
 };
 
 #
@@ -448,7 +453,8 @@ Admin {
 # If server connections are configured it means that this server is
 # router server.  Normal servers must not configure server connections.
 # Thus, if this server is not router do not configure this section.  If
-# your server is router, this must be configured.
+# your server is router, this must be configured.  The Host (mandatory)
+# specifies the remote server.
 #
 # The authentication data is specified by Passphrase and/or PublicKey.
 # If both are provided then both password and public key based authentication
@@ -474,9 +480,9 @@ ServerConnection {
 # For normal servers only one entry maybe configured to this section.  It
 # must be the router this server will be connected to.  For router servers,
 # this section includes all configured router connections.  The first
-# configured connection is the primary route.  The Host specifies the
-# remote hostname or IP address.  The Port specifies the remote port to
-# connect when Initiator is true.  When Initiator is false the Port
+# configured connection is the primary route.  The Host (mandatory) specifies
+# the remote hostname or IP address.  The Port specifies the remote port
+# to connect when Initiator is true.  When Initiator is false the Port
 # specifies the local port (listener port).
 #
 # The authentication data is specified by Passphrase and/or PublicKey.
index 9c37c0099758b8bbc4f528d53e2ed40b950cca6f..65bf8bdbcf80846fa2017fbf68e8af836dc7c9ab 100644 (file)
@@ -4,13 +4,12 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2001 Pekka Riikonen
+  Copyright (C) 1997 - 2003 Pekka Riikonen
 
   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.
-  
+  the Free Software Foundation; version 2 of the License.
+
   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
@@ -252,10 +251,10 @@ extern "C" {
 #include "silcapputil.h"
 
 /* SILC core library includes */
+#include "silcargument.h"
 #include "silcstatus.h"
 #include "silcid.h"
 #include "silcidcache.h"
-#include "silcargument.h"
 #include "silccommand.h"
 #include "silcmessage.h"
 #include "silcchannel.h"
index e670a75f96950223a118987606e93e7d1abab982..92eb37e33d993c2f816a7d6d9f7eca526899c20c 100644 (file)
@@ -4,13 +4,13 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2001 Pekka Riikonen
+  Copyright (C) 2001, 2003 Pekka Riikonen
 
   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
 
 #ifdef WIN32
 #ifndef DLL
+#ifndef _LIB
 #define DLLAPI __declspec(dllimport)
 #else
-#define DLLAPI // Nada, we use .DEF
+#define DLLAPI /* Nada, we use .DEF */
+#endif
+#else
+#define DLLAPI /* Nada, we use .DEF */
 #endif
 #endif
 
-# Some winsock compatiblity requirements
+/* Some winsock compatiblity requirements */
 #ifndef _WIN32_WINNT
 #define _WIN32_WINNT 0x400
 #else
index b10c4bb5ef7ce72d3ce9540c860fa004d7a84c3e..2d15f87181b300875745641ebf8a6f3d92e3edb8 100644 (file)
@@ -7,7 +7,7 @@
 <br />
 <small>
 Version: @VERSION@<br />
-Copyright &copy; 2001 - 2002 The SILC Project<br />
+Copyright &copy; 1997 - 2003 The SILC Project<br />
 Updated: @DATE@
 </small>
 <br /><br /><br />
index 5a964271658f52abaac40a08af5e8579ef4e0b0a..fa9019b08ed3c8be09d54d3c956d99d70ef239cc 100644 (file)
@@ -11,6 +11,15 @@ specific arguments to the application.  This document describes these
 arguments for all command replies to help SILC client software developers
 to process them.
 
+<br />&nbsp;<br />
+<b>NOTE: </b>The following list of command reply arguments are sent when
+the command was executed successfully.  If an error occurred, the
+`command_reply' client operation's 'success' argument is FALSE, and the
+'status' argument includes the error status.  In this case the arguments
+returned are dependent of the 'status' argument.  See all
+<a href="silcstatus_args.html">SilcStatus error arguments</a> for these
+arguments.
+
 <br />&nbsp;<br />&nbsp;<br />
 <b>command_reply Client Library operation</b>
 
@@ -28,18 +37,19 @@ SilcStatus status, ...);
 </tt>
 
 <br />&nbsp;<br />
-The first argument 'client' is the SILC Client Library context, the 'conn' 
+The first argument 'client' is the SILC Client Library context, the 'conn'
 is the context for the connection to the remote server, the 'cmd_payload'
 is the raw SilcCommandPayload and application usually ignores it, the
 'success' boolean value indicates whether the earlier command was a success
 or not, the 'command' is the command reply enumeration, and the 'status'
 indicates the status of the command reply.  If 'success' is FALSE then
-'status' includes error status.
+'status' includes error status (see <a href="silcstatus_args.html">SilcStatus
+error arguments</a>).
 
 <br />&nbsp;<br />
 Rest of the arguments are 'command' specific and implementation should
 handle them by the SilcCommand for example in a <tt>switch</tt> statement.
-The commands are defined in lib/silccore/silccomand.h header file.  A short 
+The commands are defined in lib/silccore/silccomand.h header file.  A short
 example:
 
 <br />&nbsp;<br />
@@ -64,12 +74,15 @@ example:
 
 <br />&nbsp;<br />
 The following table describes all commands and arguments that the client
-library sends in the 'command_reply' client operation to the application.  
-By default all arguments that the library sends to application are valid 
-pointers.  However, it is possible that some pointers may be NULL.  If 
-this is the case it is separately mentioned that the argument may be NULL.  
-In this case application must ignore that argument.  The 'command_reply'
-arguments per SilcCommand is as follows:
+library sends in the 'command_reply' client operation to the application.
+By default all arguments that the library sends to application are valid
+pointers.  However, it is possible that some pointers may be NULL.  If
+this is the case it is separately mentioned that the argument may be NULL.
+In this case application must ignore that argument.
+
+<br />&nbsp;<br />
+The 'command_reply' arguments for successful SilcCommand replies are as
+follows:
 
 <br />&nbsp;<br />
 <table border="1" width="100%" cellpadding="3" cellspacing="0">
@@ -126,9 +139,12 @@ this command reply.  The 'name' and 'info' may be NULL.
 <tr>
 <td><small>SILC_COMMAND_NICK</td>
 <td><small>
-Returns the new Client ID after user has changed nickname.
+Returns the new Client ID and new nickname inside the SilcClientEntry.
+The `old_client_id' is the odl Client ID used by the client before the
+nickname was changed.
 </td>
-<td width="50%"><small>SilcClientEntry local_entry, char *nickname
+<td width="50%"><small>SilcClientEntry local_entry, char *nickname,
+const SilcClientID *old_client_id
 </td>
 </tr>
 
@@ -171,9 +187,10 @@ parsed with silc_argument_payload_parse function.
 <tr>
 <td><small>SILC_COMMAND_KILL</td>
 <td><small>
-Called after killing a client.  There is no arguments to this reply.
+Called after killing a client.  Returns the client that was killed.
+The `client_entry' may be NULL.
 </td>
-<td width="50%"><small>none
+<td width="50%"><small>SilcClientEntry client_entry
 </td>
 </tr>
 
@@ -235,12 +252,16 @@ silc_client_get_clients_by_list function and pass the 'client_id_list' as
 argument to it.  The 'client_mode_list' includes 32-bit integers one after
 the other and they are in same order as clients in 'client_mode_list'.
 If application resolves the information with silc_client_get_clients_by_list
-parsing the 'client_mode_list' is not necessary.
+parsing the 'client_mode_list' is not necessary.  The 'founder_key' is the
+channel founder's key and may be NULL.  The 'channel_pubkeys' is Argument
+List Payload containing Public Key Payloads of all added channel public
+keys, it may be NULL.
 </td>
 <td width="50%"><small>char *channel_name, SilcChannelEntry channel,
 SilcUInt32 channel_mode, int ignored, SilcBuffer key_payload, NULL, NULL,
 char *topic, char *hmac_name, SilcUInt32 list_count, SilcBuffer client_id_list,
-SilcBuffer client_mode_list
+SilcBuffer client_mode_list, SilcPublicKey founder_key,
+SilcBuffer channel_pubkeys
 </td>
 </tr>
 
@@ -265,9 +286,15 @@ Returns the user mode after changing it.
 <tr>
 <td><small>SILC_COMMAND_CMODE</td>
 <td><small>
-Returns channel's mode after changing it.
+Returns channel's mode after changing it.  Optionally may also return
+founder's public key when it was set.  It may also return the channel
+public key list when the list was altered.  The 'founder_key' and
+'channel_pubkeys' arguments may be NULL.  The 'channel_pubkeys' is an
+Argument List Payload where each argument includes one Public Key
+Payload.
 </td>
-<td width="50%"><small>SilcChannelEntry channel, SilcUInt32 mode
+<td width="50%"><small>SilcChannelEntry channel, SilcUInt32 mode,
+SilcPublicKey founder_key, SilcBuffer channel_pubkeys
 </td>
 </tr>
 
@@ -284,9 +311,10 @@ SilcClientEntry target_client
 <tr>
 <td><small>SILC_COMMAND_KICK</td>
 <td><small>
-Called after kicking a client.  There is no arguments to this reply.
+Called after kicking a client.  Returns the client that was kicked from
+the 'channel'.  The `client_entry' and 'channel' may be NULL.
 </td>
-<td width="50%"><small>none
+<td width="50%"><small>SilcChannelEntry channel, SilcClientEntry client_entry
 </td>
 </tr>
 
@@ -334,7 +362,8 @@ arguments to this reply.
 <tr>
 <td><small>SILC_COMMAND_LEAVE</td>
 <td><small>
-Called after leaving the channel.
+Called after leaving the channel.  Note that the `channel' will become
+invalid after command_reply client operation returns.
 </td>
 <td width="50%"><small>SilcChannelEntry channel
 </td>
@@ -357,7 +386,7 @@ SilcBuffer client_id_list, SilcBuffer client_mode_list
 <td><small>SILC_COMMAND_GETKEY</td>
 <td><small>
 Returns public key of client or server.  The 'public_key' may be NULL.
-The 'entry_type' is used to check what type of pointer the entry' is.  For 
+The 'entry_type' is used to check what type of pointer the entry' is.  For
 SILC_ID_CLIENT SilcClientEntry and for SILC_ID_SERVER SilcServerEntry.
 </td>
 <td width="50%"><small>SilcIdType entry_type, void *entry,
@@ -368,6 +397,6 @@ SilcPublicKey public_key
 </table>
 
 <br />&nbsp;<br />
-SILC protocol defines some additional commands but command replies to 
+SILC protocol defines some additional commands but command replies to
 those commands are not delivered to the application.  Only the command
 replies listed above are delivered to application.
index ebe124acf2458f8e2a8b1dc377f5cc710d462c88..3c9061162a7ed62398c49d11a498994930366da7 100644 (file)
@@ -23,12 +23,12 @@ SilcNotifyType type, ...);
 </tt>
 
 <br />&nbsp;<br />
-The first argument 'client' is the SILC Client Library context, the `conn' 
-is the context for the connection to the remote server, and the `type' is 
-the notify type enumeration sent by the server.  Rest of the arguments are 
-`type' specific and implementation should handle them by the 
-SilcNotifyType for example in a <tt>switch</tt> statement.  The notify 
-types are defined in lib/silccore/silcnotify.h header file.  A short 
+The first argument 'client' is the SILC Client Library context, the `conn'
+is the context for the connection to the remote server, and the `type' is
+the notify type enumeration sent by the server.  Rest of the arguments are
+`type' specific and implementation should handle them by the
+SilcNotifyType for example in a <tt>switch</tt> statement.  The notify
+types are defined in lib/silccore/silcnotify.h header file.  A short
 example:
 
 <br />&nbsp;<br />
@@ -52,12 +52,12 @@ example:
 <b>Arguments</b>
 
 <br />&nbsp;<br />
-The following table describes all notify types and arguments that the 
-client library sends in the 'notify' client operation to the application.  
-By default all arguments that the library sends to application are valid 
-pointers.  However, it is possible that some pointers may be NULL.  If 
-this is the case it is separately mentioned that the argument may be NULL.  
-In this case application must ignore that argument.  The SilcNotifyType 
+The following table describes all notify types and arguments that the
+client library sends in the 'notify' client operation to the application.
+By default all arguments that the library sends to application are valid
+pointers.  However, it is possible that some pointers may be NULL.  If
+this is the case it is separately mentioned that the argument may be NULL.
+In this case application must ignore that argument.  The SilcNotifyType
 arguments per notify type is as follows:
 
 <br />&nbsp;<br />
@@ -82,7 +82,7 @@ The 'message' argument may be NULL.
 <tr>
 <td><small>SILC_NOTIFY_TYPE_INVITE</td>
 <td><small>
-Sent to the client if the user is invited on a channel. The 'channel_name' 
+Sent to the client if the user is invited on a channel. The 'channel_name'
 argument may be NULL.
 </td>
 <td width="50%"><small>SilcClientChannel channel, char *channel_name,
@@ -111,9 +111,9 @@ Sent when someone leaves (parts) the channel.
 <tr>
 <td><small>SILC_NOTIFY_TYPE_SIGNOFF</td>
 <td><small>
-Sent when someone signoff the SILC network.  The 'signoff_message' may be 
-NULL.  The 'leaving_client' SilcClientEntry may be incomplete and contain 
-NULL pointers, application must check it's pointers before attempting to 
+Sent when someone signoff the SILC network.  The 'signoff_message' may be
+NULL.  The 'leaving_client' SilcClientEntry may be incomplete and contain
+NULL pointers, application must check it's pointers before attempting to
 display for example nickname information.
 </td>
 <td width="50%"><small>SilcClientEntry signoff_client, char *signoff_message
@@ -124,8 +124,8 @@ display for example nickname information.
 <td><small>SILC_NOTIFY_TYPE_TOPIC_SET</td>
 <td><small>
 Sent when the topic of a channel is set/changed.  The 'setter_id_type'
-is used to check what type of pointer the 'setter_entry' is.  For 
-SILC_ID_CLIENT SilcClientEntry, for SILC_ID_SERVER SilcServerEntry and for 
+is used to check what type of pointer the 'setter_entry' is.  For
+SILC_ID_CLIENT SilcClientEntry, for SILC_ID_SERVER SilcServerEntry and for
 SILC_ID_CHANNEL SilcChannelEntry.
 </td>
 <td width="50%"><small>SilcIdType setter_id_type, void *setter_entry,
@@ -136,10 +136,11 @@ char *topic, SilcChannelEntry channel
 <tr>
 <td><small>SILC_NOTIFY_TYPE_NICK_CHANGE</td>
 <td><small>
-Sent when someone changes their nickname.  The 'old_client_entry' includes 
-the old nickname and the 'new_client_entry' includes the new nickname.  
-Application must understand that the 'old_client_entry' pointer becomes 
-invalid after returning from the function.
+Sent when someone changes their nickname.  The 'old_client_entry' includes
+the old nickname and the 'new_client_entry' includes the new nickname.
+Application must understand that the 'old_client_entry' pointer becomes
+invalid after returning from the function.  Note that this notify is not
+delivered when user changes its own nickname.
 </td>
 <td width="50%"><small>SilcClientEntry old_client_entry,
 SilcClientEntry new_client_entry
@@ -150,13 +151,20 @@ SilcClientEntry new_client_entry
 <td><small>SILC_NOTIFY_TYPE_CMODE_CHANGE</td>
 <td><small>
 Sent when channel's mode has changed. The 'changer_id_type'
-is used to check what type of pointer the 'changer_entry' is.  For 
-SILC_ID_CLIENT SilcClientEntry, for SILC_ID_SERVER SilcServerEntry and for 
-SILC_ID_CHANNEL SilcChannelEntry.  The 'mode' is the mode mask after the 
-change.  The 'hmac_name' argument may be NULL.
+is used to check what type of pointer the 'changer_entry' is.  For
+SILC_ID_CLIENT SilcClientEntry, for SILC_ID_SERVER SilcServerEntry and for
+SILC_ID_CHANNEL SilcChannelEntry.  The 'mode' is the mode mask after the
+change.  The `cipher_name' is the cipher set for the channel.
+The `hmac_name' is the HMAC set for the channel.  The `passphrase'
+is the passphrase that was set for the channel.  The `founder_key' is the
+founder's public key when it was set for the channel.  The `channel_pubkeys'
+is an Argument List Payload where each argument is Public Key Payload
+containing one channel public key.  The arguments 'cipher_name', 'hmac_name',
+'passphrase', 'founder_key' and 'channel_pubkeys' may be NULL.
 </td>
 <td width="50%"><small>SilcIdType changer_id_type, void *changer_entry,
-SilcUInt32 mode, NULL, char *hmac_name, SilcChannelEntry channel
+SilcUInt32 mode, char *cipher_name, char *hmac_name, char *passphrase,
+SilcPublicKey founder_key, SilcBuffer channel_pubkeys, SilcChannelEntry channel
 </td>
 </tr>
 
@@ -164,8 +172,8 @@ SilcUInt32 mode, NULL, char *hmac_name, SilcChannelEntry channel
 <td><small>SILC_NOTIFY_TYPE_CUMODE_CHANGE</td>
 <td><small>
 Sent when a users mode on a channel has changed. The 'changer_id_type'
-is used to check what type of pointer the 'changer_entry' is.  For 
-SILC_ID_CLIENT SilcClientEntry, for SILC_ID_SERVER SilcServerEntry and for 
+is used to check what type of pointer the 'changer_entry' is.  For
+SILC_ID_CLIENT SilcClientEntry, for SILC_ID_SERVER SilcServerEntry and for
 SILC_ID_CHANNEL SilcChannelEntry.  The 'mode' is the mode mask after the
 change.  The 'target_client' is the client whose mode was changed.
 </td>
@@ -186,9 +194,9 @@ Message of the Day from the server.
 <tr>
 <td><small>SILC_NOTIFY_TYPE_CHANNEL_CHANGE</td>
 <td><small>
-Sent when a channel's Channel ID changes.  It is possible that channel's 
-ID changes and this notify is sent by the server when this happens.  
-Usually application does not need to handle this notify type and may 
+Sent when a channel's Channel ID changes.  It is possible that channel's
+ID changes and this notify is sent by the server when this happens.
+Usually application does not need to handle this notify type and may
 safely ignore it when received.
 </td>
 <td width="50%"><small>SilcChannelEntry channel
@@ -198,8 +206,8 @@ safely ignore it when received.
 <tr>
 <td><small>SILC_NOTIFY_TYPE_SERVER_SIGNOFF</td>
 <td><small>
-Sent when a server quits the network.  The 'clients' is an array 
-SilcClientEntry pointers of size of 'clients_count'.  Each client in the 
+Sent when a server quits the network.  The 'clients' is an array
+SilcClientEntry pointers of size of 'clients_count'.  Each client in the
 entry is one client signing off from the SILC network.
 </td>
 <td width="50%"><small>NULL, SilcClientEntry *clients, SilcUInt32 clients_count
@@ -209,8 +217,8 @@ entry is one client signing off from the SILC network.
 <tr>
 <td><small>SILC_NOTIFY_TYPE_KICKED</td>
 <td><small>
-Sent when a client (possibly our client) is kicked from a channel.  The 
-'kick_message' may be NULL.  If our client was kicked then 'kicked' is our 
+Sent when a client (possibly our client) is kicked from a channel.  The
+'kick_message' may be NULL.  If our client was kicked then 'kicked' is our
 local SilcClientEntry pointer.
 </td>
 <td width="50%"><small>SilcClientEntry kicked, char *kick_message,
@@ -221,10 +229,10 @@ SilcClientEntry kicker, SilcChannelEntry channel
 <tr>
 <td><small>SILC_NOTIFY_TYPE_KILLED</td>
 <td><small>
-Sent when a client (possibly our client) is killed from the network.  The 
-'kill_message' may be NULL.  If our client was killed then 'killed' is our 
-local SilcClientEntry pointer.  The 'killer_type' is used to check what 
-type of pointer the 'killer' is.  For SILC_ID_CLIENT SilcClientEntry, for 
+Sent when a client (possibly our client) is killed from the network.  The
+'kill_message' may be NULL.  If our client was killed then 'killed' is our
+local SilcClientEntry pointer.  The 'killer_type' is used to check what
+type of pointer the 'killer' is.  For SILC_ID_CLIENT SilcClientEntry, for
 SILC_ID_SERVER SilcServerEntry and for SILC_ID_CHANNEL SilcChannelEntry.
 </td>
 <td width="50%"><small>SilcClientEntry killed, char *kill_message,
@@ -236,7 +244,7 @@ SilcIdType killer_type, void *killer, SilcChannelEntry channel
 <td><small>SILC_NOTIFY_TYPE_ERROR</td>
 <td><small>
 Sent when an error occurs while handling some operation (except command)
-from the client.  Application usually cannot handle this notify type and 
+from the client.  Application usually cannot handle this notify type and
 may safely ignore it.
 </td>
 <td width="50%"><small>SilcStatus error
@@ -246,13 +254,13 @@ may safely ignore it.
 <tr>
 <td><small>SILC_NOTIFY_TYPE_WATCH</td>
 <td><small>
-Sent to notify some status change of a client we are wathing.  The 
-SILC_COMMAND_WATCH is used to manage clients we are wathing and this 
-notify type is used to deliver information about that client.  If the 
-client just changed nickname the 'new_nickname' includes the new nickname.  
-Otherwise this pointer is NULL.  The 'user_mode' is the client's mode in 
-the SILC network.  The 'notification' contains the notify type that 
-happened for the 'watched_client' (for example 
+Sent to notify some status change of a client we are wathing.  The
+SILC_COMMAND_WATCH is used to manage clients we are wathing and this
+notify type is used to deliver information about that client.  If the
+client just changed nickname the 'new_nickname' includes the new nickname.
+Otherwise this pointer is NULL.  The 'user_mode' is the client's mode in
+the SILC network.  The 'notification' contains the notify type that
+happened for the 'watched_client' (for example
 SILC_NOTIFY_TYPE_NICK_CHANGE if the client changed their nickname).
 </td>
 <td width="50%"><small>SilcClientEntry watched_client, char *new_nickname,
@@ -263,7 +271,7 @@ SilcUInt32 user_mode, SilcNotifyType notification
 </table>
 
 <br />&nbsp;<br />
-SILC protocol defines some additional notify types but those notify types 
-are not delivered to the application.  Some of those notify types are only 
-delivered between servers and routers and clients never receive them.  
+SILC protocol defines some additional notify types but those notify types
+are not delivered to the application.  Some of those notify types are only
+delivered between servers and routers and clients never receive them.
 Only the notify types listed above are delivered to application.
diff --git a/lib/doc/silcstatus_args.html b/lib/doc/silcstatus_args.html
new file mode 100644 (file)
index 0000000..ca727cb
--- /dev/null
@@ -0,0 +1,491 @@
+<big><b>SilcStatus Arguments</b></big>
+
+<br />&nbsp;<br />
+The <a href="silcstatus-SilcStatus.html">SilcStatus</a> is used to indicate
+a status (usually error status) of command execution and command reply
+status.  It is also used to deliver disconnection status when server
+disconnects client from the server.  For application it is mainly important
+in case of `command_reply' client operation, where the SilcStatus indicates
+the error status of the command that was executed.  If error occurred the
+arguments returned by the `command_reply' are then dependent of the SilcStatus
+type instead of the <a href="command_reply_args.html">SilcCommand
+arguments</a>.
+
+<br />&nbsp;<br />
+This documents describes how the application should interpret the SilcStatus
+type in the `command_reply' client operation to be able to handle all
+error conditions properly.  Any status type can be returned for any
+SilcCommand.  For this reason application should be able to handle any
+error with any command.
+
+
+<br />&nbsp;<br />&nbsp;<br />
+<b>Error Status In command_reply Client Operation</b>
+
+<br />&nbsp;<br />
+When error occurs in execution of a command the `command_reply' client
+operation is called with error status.  In this case the 'success'
+argument of the client operation is set to FALSE, to indicate that command
+execution failed, and the 'status' argument indicates the error.
+If the 'status' argument is SILC_STATUS_OK then error did not occur and the
+arguments are as described in <a href="command_reply_args.html">SilcCommand
+arguments</a>.
+
+<br />&nbsp;<br />
+Application should handle the error status arguments by the SilcStatus
+type for example in a <tt>switch</tt> statement.  The SilcStatus values
+are defined in lib/silccore/silcstatus.h header file.  A short example.
+
+<br />&nbsp;<br />
+<tt>
+&nbsp;&nbsp;switch(status)<br />
+&nbsp;&nbsp;&nbsp;&nbsp;{<br />
+&nbsp;&nbsp;&nbsp;&nbsp;case SILC_STATUS_ERR_NO_SUCH_NICK:<br />
+&nbsp;&nbsp;&nbsp;&nbsp;...<br />
+&nbsp;&nbsp;&nbsp;&nbsp;nick = va_arg(va, char *);<br />
+&nbsp;&nbsp;&nbsp;&nbsp;...<br />
+&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
+&nbsp;&nbsp;&nbsp;&nbsp;case SILC_STATUS_ERR_NO_SUCH_CHANNEL:<br />
+&nbsp;&nbsp;&nbsp;&nbsp;...<br />
+&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
+&nbsp;&nbsp;&nbsp;&nbsp;case SILC_STATUS_ERR_NO_SUCH_SERVER:<br />
+&nbsp;&nbsp;&nbsp;&nbsp;...<br />
+&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
+&nbsp;&nbsp;&nbsp;&nbsp;...<br />
+&nbsp;&nbsp;&nbsp;&nbsp;default:<br />
+&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
+&nbsp;&nbsp;&nbsp;&nbsp;}
+</tt>
+
+
+<br />&nbsp;<br />&nbsp;<br />
+<b>Arguments</b>
+
+<br />&nbsp;<br />
+The following table describes all status values and arguments that the client
+library sends in the 'command_reply' client operation to the application
+in case of error.  All arguments listed below are usually valid when
+returned by the library.  However applicationn must be able to handle that
+any of those arguments may be NULL.
+
+<br />&nbsp;<br />
+The 'command_reply' arguments in case of error are as follows:
+
+<br />&nbsp;<br />
+<table border="1" width="100%" cellpadding="3" cellspacing="0">
+
+<tr>
+<td><small>Name</td>
+<td><small>Description</td>
+<td width="40%"><small>Error Arguments</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_OK</td>
+<td><small>
+No error.
+</td>
+<td width="40%"><small>N/A
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_NO_SUCH_NICK</td>
+<td><small>
+Requested nickname does not exist.  Argument is the unknown name.
+</td>
+<td width="40%"><small>const char *nickname
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_NO_SUCH_CHANNEL</td>
+<td><small>
+The requested channel does not exist.  Argument is the unknown name.
+</td>
+<td width="40%"><small>const char *channel_name
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_NO_SUCH_SERVER</td>
+<td><small>
+The requested server does not exist.  Argument is the unknown name.
+</td>
+<td width="40%"><small>const char *server_name
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_NO_RECIPIENT</td>
+<td><small>
+Command required recipient but none was provided.  No arguments returned.
+<td width="40%"><small>N/A
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_UNKNOWN_COMMAND</td>
+<td><small>
+Command sent to server is unknown or unsupported by the server.  No
+arguments returned.
+</td>
+<td width="40%"><small>N/A
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_WILDCARDS</td>
+<td><small>
+Wildcards were provided by they were not permitted.  No arguments returned.
+</td>
+<td width="40%"><small>N/A
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_NO_CLIENT_ID</td>
+<td><small>
+Client ID was expected as command parameter but was not found.  No
+arguments returned.
+</td>
+<td width="40%"><small>N/A
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_NO_CHANNEL_ID</td>
+<td><small>
+Channel ID was expected as command parameter but was not found.  No
+arguments returned.
+</td>
+<td width="40%"><small>N/A
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_NO_SERVER_ID</td>
+<td><small>
+Server ID was expected as command parameter but was not found.  No
+arguments returned.
+</td>
+<td width="40%"><small>N/A
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_BAD_CLIENT_ID</td>
+<td><small>
+Client ID provided was malformed.  Returns the malformed ID.
+</td>
+<td width="40%"><small>const SilcClientID *client_id
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_BAD_CHANNEL_ID</td>
+<td><small>
+Channel ID provided was malformed.  Returns the malformed ID.
+</td>
+<td width="40%"><small>const SilcChannelID *channel_id
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_BAD_SERVER_ID</td>
+<td><small>
+Server ID provided was malformed.  Returns the malformed ID.
+</td>
+<td width="40%"><small>const SilcServerID *server_id
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_NO_SUCH_CLIENT_ID</td>
+<td><small>
+Client ID provided does not exist.  The unknown ID is returned.
+</td>
+<td width="40%"><small>const SilcClientID *client_id
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID</td>
+<td><small>
+Channel ID provided does not exist.  The unknown ID is returned.
+</td>
+<td width="40%"><small>const SilcChannelID *channel_id
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_NO_SUCH_SERVER_ID</td>
+<td><small>
+Server ID provided does not exist.  The unknown ID is returned.
+</td>
+<td width="40%"><small>const SilcServerID *server_id
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_NOT_ON_CHANNEL</td>
+<td><small>
+The command required for you to be on channel but you were not.
+The channel ID is returned.
+</td>
+<td width="40%"><small>const SilcChannelID *channel_id
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_USER_NOT_ON_CHANNEL</td>
+<td><small>
+The requested target client is not on requested channel.  Returns the
+target client ID and channel ID.
+</td>
+<td width="40%"><small>const SilcClientID *client_id,
+const SilcChannelID *channel_id
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_USER_ON_CHANNEL</td>
+<td><small>
+User were invited on channel they already are on.  Returns the
+target client ID and channel ID.
+</td>
+<td width="40%"><small>const SilcClientID *client_id,
+const SilcChannelID *channel_id
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_NOT_REGISTERED</td>
+<td><small>
+User executed command that requires the client to be registered on the
+server before it may be executed.  No arguments returned.
+</td>
+<td width="40%"><small>N/A
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_NOT_ENOUGH_PARAMS</td>
+<td><small>
+Command required more parameters than provided.  No arguments returned.
+</td>
+<td width="40%"><small>N/A
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_TOO_MANY_PARAMS</td>
+<td><small>
+Too many parameters provided for the command.  No arguments returned.
+</td>
+<td width="40%"><small>N/A
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_PERM_DENIED</td>
+<td><small>
+Generic permission denied error status, to indicat disallowed access.
+No arguments returned.
+</td>
+<td width="40%"><small>N/A
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_BAD_PASSWORD</td>
+<td><small>
+Password provided for channel were not accepted.  Returns the channel ID.
+</td>
+<td width="40%"><small>const SilcChannelID *channel_id
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_CHANNEL_IS_FULL</td>
+<td><small>
+The channel is full and client cannot join the channel.  Returns the
+channel ID.
+</td>
+<td width="40%"><small>const SilcChannelID *channel_id
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_NOT_INVITED</td>
+<td><small>
+The channel is invite only channel and client has not been invited.
+Returns the channel ID.
+</td>
+<td width="40%"><small>const SilcChannelID *channel_id
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_BANNED_FROM_CHANNEL</td>
+<td><small>
+The client has been banned from the channel.  Returns the channel ID.
+</td>
+<td width="40%"><small>const SilcChannelID *channel_id
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_UNKNOWN_MODE</td>
+<td><small>
+Mode provided by the client was unknown to or unsupported by the server.
+No arguments returned.
+</td>
+<td width="40%"><small>N/A
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_NOT_YOU</td>
+<td><small>
+User tried to change someone else's mode which is not allowed.
+No arguments returned.
+</td>
+<td width="40%"><small>N/A
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_NO_CHANNEL_PRIV</td>
+<td><small>
+Command may be executed only by channel operator.  The next argument is
+the channel ID.
+</td>
+<td width="40%"><small>const SilcChannelID *channel_id
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_NO_CHANNEL_FOPRIV</td>
+<td><small>
+Command may be executed only by channel founder.  The next argument is
+the channel ID.
+</td>
+<td width="40%"><small>const SilcChannelID *channel_id
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_NO_SERVER_PRIV</td>
+<td><small>
+Command may be executed only by server operator.  No arguments returned.
+</td>
+<td width="40%"><small>N/A
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_NO_ROUTER_PRIV</td>
+<td><small>
+Command may be executed only by router (SILC) operator.  No arguments returned.
+</td>
+<td width="40%"><small>N/A
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_BAD_NICKNAME</td>
+<td><small>
+Nickname requested contained illegal characters or was malformed.  No
+arguments returned.
+</td>
+<td width="40%"><small>N/A
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_BAD_CHANNEL</td>
+<td><small>
+Channel name requested contained illegal characters or was malformed.  No
+arguments returned.
+</td>
+<td width="40%"><small>N/A
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_AUTH_FAILED</td>
+<td><small>
+The authentication data (passphrase or digital signature) sent as argument
+was wrong and thus authentication failed.  No arguments returned.
+</td>
+<td width="40%"><small>N/A
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_UNKNOWN_ALGORITHM</td>
+<td><small>
+The server does not support requested algorithm.  Returns the unknown
+algorithm.
+</td>
+<td width="40%"><small>const char *alg_name
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_RESOURCE_LIMIT</td>
+<td><small>
+Server cannot or will not accept the action due to resource limitations.
+No arguments returned.
+</td>
+<td width="40%"><small>N/A
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_NO_SUCH_SERVICE</td>
+<td><small>
+Requestes service identifier is unknown.  Returns the unknown service
+identifier.
+</td>
+<td width="40%"><small>const char *service_identifier
+</td>
+</tr>
+
+<tr>
+<td><small>SILC_STATUS_ERR_TIMEDOUT</td>
+<td><small>
+Operation (command execution) or service request timed out, and thus was
+not processed.  This usually happens due to network failure between servers
+and routers in the network.  No arguments returned.
+</td>
+<td width="40%"><small>N/A
+</td>
+</tr>
+<tr>
+
+<td><small>SILC_STATUS_ERR_UNSUPPORTED_PUBLIC_KEY</td>
+<td><small>
+The public key or certificate type is not supported in ths implementation.
+No arguments returned.
+</td>
+<td width="40%"><small>N/A
+</td>
+</tr>
+
+<td><small>SILC_STATUS_ERR_OPERATION_ALLOWED</td>
+<td><small>
+A operation, for example a command, is not allowed or it's execution is
+not allowed.  No arguments returned.
+</td>
+<td width="40%"><small>N/A
+</td>
+</tr>
+
+</table>
+
+<br />&nbsp;<br />
+SILC protocol defines some additional status types but those status
+types are not returned in `command_reply' client operation.  Only
+the status types listed above are delivered to application.
index 84267123723b35e68aa08f8620114dbae708a2d8..d61bcfe7a4e4752daf2832585500ff9b88269244 100644 (file)
@@ -3,6 +3,7 @@
 @FILENAME=silcclientlib.html
 @LINK=silcclient_using.html:Using SILC Client Library Tutorial
 @LINK=command_reply_args.html:Arguments for <b>command_reply</b> Client Operation
+@LINK=silcstatus_args.html:SilcStatus Error Arguments in <b>command_reply</b> Client Operation
 @LINK=notifyargs.html:Arguments for <b>notify</b> Client Operation
 @LINK=silcclient.html:Client Library Interface Reference
 -->
index 745cb698b52daf343e7233769ab7df0f770f7c00..9fc554bf5568f91e2d7e4033da3446747e861a33 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  client.c 
+  client.c
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2002 Pekka Riikonen
+  Copyright (C) 1997 - 2003 Pekka Riikonen
 
   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
@@ -30,7 +30,7 @@ SILC_TASK_CALLBACK(silc_client_rekey_final);
 
 static bool silc_client_packet_parse(SilcPacketParserContext *parser_context,
                                     void *context);
-static void silc_client_packet_parse_type(SilcClient client, 
+static void silc_client_packet_parse_type(SilcClient client,
                                          SilcSocketConnection sock,
                                          SilcPacketContext *packet);
 void silc_client_resolve_auth_method(bool success,
@@ -43,7 +43,7 @@ void silc_client_resolve_auth_method(bool success,
    the client. The `application' is application specific user data pointer
    and caller must free it. */
 
-SilcClient silc_client_alloc(SilcClientOperations *ops, 
+SilcClient silc_client_alloc(SilcClientOperations *ops,
                             SilcClientParams *params,
                             void *application,
                             const char *version_string)
@@ -55,7 +55,7 @@ SilcClient silc_client_alloc(SilcClientOperations *ops,
 
   new_client->internal = silc_calloc(1, sizeof(*new_client->internal));
   new_client->internal->ops = ops;
-  new_client->internal->params = 
+  new_client->internal->params =
     silc_calloc(1, sizeof(*new_client->internal->params));
   if (!version_string)
     version_string = silc_version_string;
@@ -142,7 +142,7 @@ bool silc_client_init(SilcClient client)
   silc_client_protocols_register();
 
   /* Initialize the scheduler */
-  client->schedule = 
+  client->schedule =
     silc_schedule_init(client->internal->params->task_max ?
                       client->internal->params->task_max : 200, client);
   if (!client->schedule)
@@ -211,7 +211,7 @@ static void silc_client_entry_destructor(SilcIDCache cache,
    connection to the connection table and returns a pointer to it. A client
    can have multiple connections to multiple servers. Every connection must
    be added to the client using this function. User data `context' may
-   be sent as argument. This function is normally used only if the 
+   be sent as argument. This function is normally used only if the
    application performed the connecting outside the library. The library
    however may use this internally. */
 
@@ -255,7 +255,7 @@ silc_client_add_connection(SilcClient client,
       return conn;
     }
 
-  client->internal->conns = 
+  client->internal->conns =
     silc_realloc(client->internal->conns, sizeof(*client->internal->conns)
                 * (client->internal->conns_count + 1));
   client->internal->conns[client->internal->conns_count] = conn;
@@ -328,7 +328,8 @@ void silc_client_del_connection(SilcClient client, SilcClientConnection conn)
       silc_free(conn->internal->rekey);
 
       if (conn->internal->active_session) {
-       conn->sock->user_data = NULL;
+       if (conn->sock)
+         conn->sock->user_data = NULL;
        silc_client_ftp_session_free(conn->internal->active_session);
        conn->internal->active_session = NULL;
       }
@@ -360,7 +361,7 @@ void silc_client_add_socket(SilcClient client, SilcSocketConnection sock)
   int i;
 
   if (!client->internal->sockets) {
-    client->internal->sockets = 
+    client->internal->sockets =
       silc_calloc(1, sizeof(*client->internal->sockets));
     client->internal->sockets[0] = silc_socket_dup(sock);
     client->internal->sockets_count = 1;
@@ -374,11 +375,11 @@ void silc_client_add_socket(SilcClient client, SilcSocketConnection sock)
     }
   }
 
-  client->internal->sockets = 
-    silc_realloc(client->internal->sockets, 
+  client->internal->sockets =
+    silc_realloc(client->internal->sockets,
                 sizeof(*client->internal->sockets) *
                 (client->internal->sockets_count + 1));
-  client->internal->sockets[client->internal->sockets_count] = 
+  client->internal->sockets[client->internal->sockets_count] =
     silc_socket_dup(sock);
   client->internal->sockets_count++;
 }
@@ -401,7 +402,7 @@ void silc_client_del_socket(SilcClient client, SilcSocketConnection sock)
   }
 }
 
-static int 
+static int
 silc_client_connect_to_server_internal(SilcClientInternalConnectContext *ctx)
 {
   int sock;
@@ -415,9 +416,9 @@ silc_client_connect_to_server_internal(SilcClientInternalConnectContext *ctx)
 
   /* Register task that will receive the async connect and will
      read the result. */
-  ctx->task = silc_schedule_task_add(ctx->client->schedule, sock, 
+  ctx->task = silc_schedule_task_add(ctx->client->schedule, sock,
                                     silc_client_connect_to_server_start,
-                                    (void *)ctx, 0, 0, 
+                                    (void *)ctx, 0, 0,
                                     SILC_TASK_FD,
                                     SILC_TASK_PRI_NORMAL);
   silc_schedule_set_listen_fd(ctx->client->schedule, sock, SILC_TASK_WRITE,
@@ -429,16 +430,16 @@ silc_client_connect_to_server_internal(SilcClientInternalConnectContext *ctx)
 }
 
 /* Connects to remote server. This is the main routine used to connect
-   to SILC server. Returns -1 on error and the created socket otherwise. 
+   to SILC server. Returns -1 on error and the created socket otherwise.
    The `context' is user context that is saved into the SilcClientConnection
    that is created after the connection is created. Note that application
    may handle the connecting process outside the library. If this is the
    case then this function is not used at all. When the connecting is
    done the `connect' client operation is called. */
 
-bool silc_client_connect_to_server(SilcClient client,
-                                  SilcClientConnectionParams *params,
-                                  int port, char *host, void *context)
+int silc_client_connect_to_server(SilcClient client,
+                                 SilcClientConnectionParams *params,
+                                 int port, char *host, void *context)
 {
   SilcClientInternalConnectContext *ctx;
   SilcClientConnection conn;
@@ -449,7 +450,7 @@ bool silc_client_connect_to_server(SilcClient client,
 
   conn = silc_client_add_connection(client, params, host, port, context);
 
-  client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT, 
+  client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
                             "Connecting to port %d of server %s", port, host);
 
   /* Allocate internal context for connection process. This is
@@ -504,7 +505,7 @@ static void silc_client_start_key_exchange_cb(SilcSocketConnection sock,
 
   /* Perform key exchange protocol. silc_client_connect_to_server_final
      will be called after the protocol is finished. */
-  silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE, 
+  silc_protocol_alloc(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
                      &protocol, (void *)proto_ctx,
                      silc_client_connect_to_server_second);
   if (!protocol) {
@@ -517,9 +518,9 @@ static void silc_client_start_key_exchange_cb(SilcSocketConnection sock,
   conn->sock->protocol = protocol;
 
   /* Register the connection for network input and output. This sets
-     that scheduler will listen for incoming packets for this connection 
+     that scheduler will listen for incoming packets for this connection
      and sets that outgoing packets may be sent to this connection as well.
-     However, this doesn't set the scheduler for outgoing traffic, it will 
+     However, this doesn't set the scheduler for outgoing traffic, it will
      be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
      later when outgoing data is available. */
   context = (void *)client;
@@ -548,7 +549,7 @@ void silc_client_start_key_exchange(SilcClient client,
   silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER, (void *)conn, &conn->sock);
 
   /* Sometimes when doing quick reconnects the new socket may be same as
-     the old one and there might be pending stuff for the old socket. 
+     the old one and there might be pending stuff for the old socket.
      If new one is same then those pending sutff might cause problems.
      Make sure they do not do that. */
   silc_schedule_task_del_by_fd(client->schedule, fd);
@@ -566,11 +567,11 @@ void silc_client_start_key_exchange(SilcClient client,
 
 SILC_TASK_CALLBACK(silc_client_connect_failure)
 {
-  SilcClientKEInternalContext *ctx = 
+  SilcClientKEInternalContext *ctx =
     (SilcClientKEInternalContext *)context;
   SilcClient client = (SilcClient)ctx->client;
 
-  client->internal->ops->connected(client, ctx->sock->user_data, 
+  client->internal->ops->connected(client, ctx->sock->user_data,
                                   SILC_CLIENT_CONN_ERROR);
   if (ctx->packet)
     silc_packet_context_free(ctx->packet);
@@ -586,7 +587,7 @@ SILC_TASK_CALLBACK(silc_client_connect_failure_auth)
     (SilcClientConnAuthInternalContext *)context;
   SilcClient client = (SilcClient)ctx->client;
 
-  client->internal->ops->connected(client, ctx->sock->user_data, 
+  client->internal->ops->connected(client, ctx->sock->user_data,
                                   SILC_CLIENT_CONN_ERROR);
   silc_free(ctx);
 }
@@ -612,8 +613,8 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
       client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR,
                                 "Could not connect to server %s: %s",
                                 ctx->host, strerror(opt));
-      client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT, 
-                                "Connecting to port %d of server %s resumed", 
+      client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
+                                "Connecting to port %d of server %s resumed",
                                 ctx->port, ctx->host);
 
       /* Unregister old connection try */
@@ -636,7 +637,6 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
 
       /* Notify application of failure */
       client->internal->ops->connected(client, conn, SILC_CLIENT_CONN_ERROR);
-      silc_client_del_connection(client, conn);
     }
     return;
   }
@@ -648,13 +648,13 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
   silc_client_start_key_exchange(client, conn, fd);
 }
 
-/* Second part of the connecting to the server. This executed 
+/* Second part of the connecting to the server. This executed
    authentication protocol. */
 
 SILC_TASK_CALLBACK(silc_client_connect_to_server_second)
 {
   SilcProtocol protocol = (SilcProtocol)context;
-  SilcClientKEInternalContext *ctx = 
+  SilcClientKEInternalContext *ctx =
     (SilcClientKEInternalContext *)protocol->context;
   SilcClient client = (SilcClient)ctx->client;
   SilcSocketConnection sock = NULL;
@@ -714,15 +714,15 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_second)
   /* Resolve the authentication method to be used in this connection. The
      completion callback is called after the application has resolved
      the authentication method. */
-  client->internal->ops->get_auth_method(client, sock->user_data, 
+  client->internal->ops->get_auth_method(client, sock->user_data,
                                         sock->hostname,
-                                        sock->port, 
+                                        sock->port,
                                         silc_client_resolve_auth_method,
                                         proto_ctx);
 }
 
 /* Authentication method resolving callback. Application calls this function
-   after we've called the client->internal->ops->get_auth_method 
+   after we've called the client->internal->ops->get_auth_method
    client operation to resolve the authentication method. We will continue
    the executiong of the protocol in this function. */
 
@@ -743,14 +743,14 @@ void silc_client_resolve_auth_method(bool success,
   if (success && auth_data && auth_data_len) {
 
     /* Passphrase must be UTF-8 encoded, if it isn't encode it */
-    if (auth_meth == SILC_AUTH_PASSWORD && 
+    if (auth_meth == SILC_AUTH_PASSWORD &&
        !silc_utf8_valid(auth_data, auth_data_len)) {
       int payload_len = 0;
       unsigned char *autf8 = NULL;
-      payload_len = silc_utf8_encoded_len(auth_data, auth_data_len, 
+      payload_len = silc_utf8_encoded_len(auth_data, auth_data_len,
                                          SILC_STRING_ASCII);
       autf8 = silc_calloc(payload_len, sizeof(*autf8));
-      auth_data_len = silc_utf8_encode(auth_data, auth_data_len, 
+      auth_data_len = silc_utf8_encode(auth_data, auth_data_len,
                                       SILC_STRING_ASCII, autf8, payload_len);
       auth_data = autf8;
     }
@@ -760,8 +760,8 @@ void silc_client_resolve_auth_method(bool success,
   }
 
   /* Allocate the authenteication protocol and execute it. */
-  silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH, 
-                     &proto_ctx->sock->protocol, (void *)proto_ctx, 
+  silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
+                     &proto_ctx->sock->protocol, (void *)proto_ctx,
                      silc_client_connect_to_server_final);
 
   /* Execute the protocol */
@@ -776,7 +776,7 @@ void silc_client_resolve_auth_method(bool success,
 SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
 {
   SilcProtocol protocol = (SilcProtocol)context;
-  SilcClientConnAuthInternalContext *ctx = 
+  SilcClientConnAuthInternalContext *ctx =
     (SilcClientConnAuthInternalContext *)protocol->context;
   SilcClient client = (SilcClient)ctx->client;
   SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
@@ -829,7 +829,7 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
 
     /* Send the packet */
     silc_client_packet_send(client, ctx->sock, SILC_PACKET_RESUME_CLIENT,
-                           NULL, 0, NULL, NULL, 
+                           NULL, 0, NULL, NULL,
                            packet->data, packet->len, TRUE);
     silc_buffer_free(packet);
     silc_buffer_free(auth);
@@ -839,7 +839,7 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
     /* Send NEW_CLIENT packet to the server. We will become registered
        to the SILC network after sending this packet and we will receive
        client ID from the server. */
-    packet = silc_buffer_alloc(2 + 2 + strlen(client->username) + 
+    packet = silc_buffer_alloc(2 + 2 + strlen(client->username) +
                               strlen(client->realname));
     silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
     silc_buffer_format(packet,
@@ -853,7 +853,7 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
 
     /* Send the packet */
     silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
-                           NULL, 0, NULL, NULL, 
+                           NULL, 0, NULL, NULL,
                            packet->data, packet->len, TRUE);
     silc_buffer_free(packet);
   }
@@ -866,7 +866,7 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
   /* Register re-key timeout */
   conn->internal->rekey->timeout = client->internal->params->rekey_secs;
   conn->internal->rekey->context = (void *)client;
-  silc_schedule_task_add(client->schedule, conn->sock->sock, 
+  silc_schedule_task_add(client->schedule, conn->sock->sock,
                         silc_client_rekey_callback,
                         (void *)conn->sock, conn->internal->rekey->timeout, 0,
                         SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
@@ -899,7 +899,7 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
    is used directly only in special cases. Normal cases should use
    silc_server_packet_send. Returns < 0 on error. */
 
-bool silc_client_packet_send_real(SilcClient client,
+int silc_client_packet_send_real(SilcClient client,
                                 SilcSocketConnection sock,
                                 bool force_send)
 {
@@ -919,9 +919,9 @@ bool silc_client_packet_send_real(SilcClient client,
   if (ret != -2)
     return ret;
 
-  /* Mark that there is some outgoing data available for this connection. 
+  /* Mark that there is some outgoing data available for this connection.
      This call sets the connection both for input and output (the input
-     is set always and this call keeps the input setting, actually). 
+     is set always and this call keeps the input setting, actually).
      Actual data sending is performed by silc_client_packet_process. */
   SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(client->schedule, sock->sock);
 
@@ -967,10 +967,10 @@ SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process)
     /* Error */
     if (ret == -1)
       return;
-    
+
     /* The packet has been sent and now it is time to set the connection
-       back to only for input. When there is again some outgoing data 
-       available for this connection it will be set for output as well. 
+       back to only for input. When there is again some outgoing data
+       available for this connection it will be set for output as well.
        This call clears the output setting and sets it only for input. */
     SILC_CLIENT_SET_CONNECTION_FOR_INPUT(client->schedule, fd);
     SILC_UNSET_OUTBUF_PENDING(sock);
@@ -985,7 +985,7 @@ SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process)
     ret = silc_packet_receive(sock);
     if (ret < 0)
       return;
-    
+
     /* EOF */
     if (ret == 0) {
       SILC_LOG_DEBUG(("Read EOF"));
@@ -998,7 +998,7 @@ SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process)
        silc_client_close_connection_real(client, sock, conn);
        return;
       }
-      
+
       SILC_LOG_DEBUG(("EOF from connection %d", sock->sock));
       if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
        client->internal->ops->disconnected(client, conn, 0, NULL);
@@ -1009,12 +1009,12 @@ SILC_TASK_CALLBACK_GLOBAL(silc_client_packet_process)
     /* Process the packet. This will call the parser that will then
        decrypt and parse the packet. */
     if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
-      silc_packet_receive_process(sock, FALSE, conn->internal->receive_key, 
+      silc_packet_receive_process(sock, FALSE, conn->internal->receive_key,
                                  conn->internal->hmac_receive,
                                  conn->internal->psn_receive,
                                  silc_client_packet_parse, client);
     else
-      silc_packet_receive_process(sock, FALSE, NULL, NULL, 0, 
+      silc_packet_receive_process(sock, FALSE, NULL, NULL, 0,
                                  silc_client_packet_parse, client);
   }
 }
@@ -1045,15 +1045,14 @@ static bool silc_client_packet_parse(SilcPacketParserContext *parser_context,
     silc_free(parser_context);
     return FALSE;
   }
-  
+
   /* If protocol for this connection is key exchange or rekey then we'll
      process all packets synchronously, since there might be packets in
      queue that we are not able to decrypt without first processing the
      packets before them. */
-  if ((ret == SILC_PACKET_REKEY || ret == SILC_PACKET_REKEY_DONE) ||
-      (sock->protocol && sock->protocol->protocol && 
-       (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
-       sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY))) {
+  if (sock->protocol && sock->protocol->protocol &&
+      (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
+       sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
 
     /* Parse the incoming packet type */
     silc_client_packet_parse_type(client, sock, packet);
@@ -1064,14 +1063,14 @@ static bool silc_client_packet_parse(SilcPacketParserContext *parser_context,
        the `conn->internal->receive_key' might have become valid by processing
        the previous packet */
     if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
-      silc_packet_receive_process(sock, FALSE, conn->internal->receive_key, 
+      silc_packet_receive_process(sock, FALSE, conn->internal->receive_key,
                                  conn->internal->hmac_receive,
                                  conn->internal->psn_receive,
                                  silc_client_packet_parse, client);
     else
-      silc_packet_receive_process(sock, FALSE, NULL, NULL, 0, 
+      silc_packet_receive_process(sock, FALSE, NULL, NULL, 0,
                                  silc_client_packet_parse, client);
-    
+
     return FALSE;
   }
 
@@ -1085,7 +1084,7 @@ static bool silc_client_packet_parse(SilcPacketParserContext *parser_context,
 /* Parses the packet type and calls what ever routines the packet type
    requires. This is done for all incoming packets. */
 
-void silc_client_packet_parse_type(SilcClient client, 
+void silc_client_packet_parse_type(SilcClient client,
                                   SilcSocketConnection sock,
                                   SilcPacketContext *packet)
 {
@@ -1113,7 +1112,7 @@ void silc_client_packet_parse_type(SilcClient client,
 
   case SILC_PACKET_FAILURE:
     /*
-     * Failure received for some protocol. Set the protocol state to 
+     * Failure received for some protocol. Set the protocol state to
      * error and call the protocol callback. This fill cause error on
      * protocol and it will call the final callback.
      */
@@ -1125,7 +1124,7 @@ void silc_client_packet_parse_type(SilcClient client,
 
   case SILC_PACKET_NOTIFY:
     /*
-     * Received notify message 
+     * Received notify message
      */
     silc_client_notify_by_server(client, sock, packet);
     break;
@@ -1182,9 +1181,9 @@ void silc_client_packet_parse_type(SilcClient client,
     break;
 
   case SILC_PACKET_KEY_EXCHANGE:
-    if (sock->protocol && sock->protocol->protocol && 
+    if (sock->protocol && sock->protocol->protocol &&
        sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
-      SilcClientKEInternalContext *proto_ctx = 
+      SilcClientKEInternalContext *proto_ctx =
        (SilcClientKEInternalContext *)sock->protocol->context;
 
       proto_ctx->packet = silc_packet_context_dup(packet);
@@ -1203,35 +1202,35 @@ void silc_client_packet_parse_type(SilcClient client,
     break;
 
   case SILC_PACKET_KEY_EXCHANGE_1:
-    if (sock->protocol && sock->protocol->protocol && 
+    if (sock->protocol && sock->protocol->protocol &&
        (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
         sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
 
       if (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
-       SilcClientRekeyInternalContext *proto_ctx = 
+       SilcClientRekeyInternalContext *proto_ctx =
          (SilcClientRekeyInternalContext *)sock->protocol->context;
-       
+
        if (proto_ctx->packet)
          silc_packet_context_free(proto_ctx->packet);
-       
+
        proto_ctx->packet = silc_packet_context_dup(packet);
 
        /* Let the protocol handle the packet */
        silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
       } else {
-       SilcClientKEInternalContext *proto_ctx = 
+       SilcClientKEInternalContext *proto_ctx =
          (SilcClientKEInternalContext *)sock->protocol->context;
-       
+
        if (proto_ctx->packet)
          silc_packet_context_free(proto_ctx->packet);
-       
+
        proto_ctx->packet = silc_packet_context_dup(packet);
        proto_ctx->dest_id_type = packet->src_id_type;
        proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
                                            packet->src_id_type);
        if (!proto_ctx->dest_id)
          break;
-       
+
        /* Let the protocol handle the packet */
        silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
       }
@@ -1242,25 +1241,25 @@ void silc_client_packet_parse_type(SilcClient client,
     break;
 
   case SILC_PACKET_KEY_EXCHANGE_2:
-    if (sock->protocol && sock->protocol->protocol && 
+    if (sock->protocol && sock->protocol->protocol &&
        (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
         sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
 
       if (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
-       SilcClientRekeyInternalContext *proto_ctx = 
+       SilcClientRekeyInternalContext *proto_ctx =
          (SilcClientRekeyInternalContext *)sock->protocol->context;
-       
+
        if (proto_ctx->packet)
          silc_packet_context_free(proto_ctx->packet);
-       
+
        proto_ctx->packet = silc_packet_context_dup(packet);
 
        /* Let the protocol handle the packet */
        silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
       } else {
-       SilcClientKEInternalContext *proto_ctx = 
+       SilcClientKEInternalContext *proto_ctx =
          (SilcClientKEInternalContext *)sock->protocol->context;
-       
+
        if (proto_ctx->packet)
          silc_packet_context_free(proto_ctx->packet);
         if (proto_ctx->dest_id)
@@ -1271,7 +1270,7 @@ void silc_client_packet_parse_type(SilcClient client,
                                            packet->src_id_type);
        if (!proto_ctx->dest_id)
          break;
-       
+
        /* Let the protocol handle the packet */
        silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
       }
@@ -1285,7 +1284,7 @@ void silc_client_packet_parse_type(SilcClient client,
     {
       /*
        * Received new ID from server. This packet is received at
-       * the connection to the server.  New ID is also received when 
+       * the connection to the server.  New ID is also received when
        * user changes nickname but in that case the new ID is received
        * as command reply and not as this packet type.
        */
@@ -1325,15 +1324,15 @@ void silc_client_packet_parse_type(SilcClient client,
   case SILC_PACKET_REKEY_DONE:
     SILC_LOG_DEBUG(("Re-key done packet"));
 
-    if (sock->protocol && sock->protocol->protocol && 
+    if (sock->protocol && sock->protocol->protocol &&
        sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
 
-      SilcClientRekeyInternalContext *proto_ctx = 
+      SilcClientRekeyInternalContext *proto_ctx =
        (SilcClientRekeyInternalContext *)sock->protocol->context;
-      
+
       if (proto_ctx->packet)
        silc_packet_context_free(proto_ctx->packet);
-      
+
       proto_ctx->packet = silc_packet_context_dup(packet);
 
       /* Let the protocol handle the packet */
@@ -1341,7 +1340,7 @@ void silc_client_packet_parse_type(SilcClient client,
        silc_protocol_execute(sock->protocol, client->schedule, 0, 0);
       else
        /* Let the protocol handle the packet */
-       silc_protocol_execute(sock->protocol, client->schedule, 
+       silc_protocol_execute(sock->protocol, client->schedule,
                              0, 100000);
     } else {
       SILC_LOG_ERROR(("Received Re-key done packet but no re-key "
@@ -1375,15 +1374,15 @@ void silc_client_packet_parse_type(SilcClient client,
    will be derived from sock argument. Otherwise the valid arguments sent
    are used. */
 
-void silc_client_packet_send(SilcClient client, 
+void silc_client_packet_send(SilcClient client,
                             SilcSocketConnection sock,
-                            SilcPacketType type, 
+                            SilcPacketType type,
                             void *dst_id,
                             SilcIdType dst_id_type,
                             SilcCipher cipher,
                             SilcHmac hmac,
-                            unsigned char *data, 
-                            SilcUInt32 data_len, 
+                            unsigned char *data,
+                            SilcUInt32 data_len,
                             bool force_send)
 {
   SilcPacketContext packetdata;
@@ -1424,13 +1423,13 @@ void silc_client_packet_send(SilcClient client,
   /* Set the packet context pointers */
   packetdata.flags = 0;
   packetdata.type = type;
-  if (sock->user_data && 
+  if (sock->user_data &&
       ((SilcClientConnection)sock->user_data)->local_id_data) {
     packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data;
-    packetdata.src_id_len = 
+    packetdata.src_id_len =
       silc_id_get_len(((SilcClientConnection)sock->user_data)->local_id,
                      SILC_ID_CLIENT);
-  } else { 
+  } else {
     packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
     packetdata.src_id_len = SILC_ID_CLIENT_LEN;
   }
@@ -1445,9 +1444,9 @@ void silc_client_packet_send(SilcClient client,
     packetdata.dst_id_type = SILC_ID_NONE;
   }
   data_len = SILC_PACKET_DATALEN(data_len, (SILC_PACKET_HEADER_LEN +
-                                           packetdata.src_id_len + 
+                                           packetdata.src_id_len +
                                            packetdata.dst_id_len));
-  packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
+  packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
     packetdata.src_id_len + packetdata.dst_id_len;
   if (type == SILC_PACKET_CONNECTION_AUTH)
     SILC_PACKET_PADLEN_MAX(packetdata.truelen, block_len, packetdata.padlen);
@@ -1455,7 +1454,7 @@ void silc_client_packet_send(SilcClient client,
     SILC_PACKET_PADLEN(packetdata.truelen, block_len, packetdata.padlen);
 
   /* Create the outgoing packet */
-  if (!silc_packet_assemble(&packetdata, client->rng, cipher, hmac, sock, 
+  if (!silc_packet_assemble(&packetdata, client->rng, cipher, hmac, sock,
                             data, data_len, (const SilcBuffer)&packet)) {
     SILC_LOG_ERROR(("Error assembling packet"));
     return;
@@ -1463,7 +1462,7 @@ void silc_client_packet_send(SilcClient client,
 
   /* Encrypt the packet */
   if (cipher)
-    silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&packet, 
+    silc_packet_encrypt(cipher, hmac, sequence, (SilcBuffer)&packet,
                         packet.len);
 
   SILC_LOG_HEXDUMP(("Packet (%d), len %d", sequence, packet.len),
@@ -1495,17 +1494,17 @@ bool silc_client_send_packet(SilcClient client,
 void silc_client_packet_queue_purge(SilcClient client,
                                    SilcSocketConnection sock)
 {
-  if (sock && SILC_IS_OUTBUF_PENDING(sock) && 
+  if (sock && SILC_IS_OUTBUF_PENDING(sock) &&
       (SILC_IS_DISCONNECTED(sock) == FALSE)) {
     silc_packet_send(sock, TRUE);
-    SILC_CLIENT_SET_CONNECTION_FOR_INPUT(client->schedule, sock->sock);
     SILC_UNSET_OUTBUF_PENDING(sock);
+    SILC_CLIENT_SET_CONNECTION_FOR_INPUT(client->schedule, sock->sock);
     silc_buffer_clear(sock->outbuf);
   }
 }
 
 /* Closes connection to remote end. Free's all allocated data except
-   for some information such as nickname etc. that are valid at all time. 
+   for some information such as nickname etc. that are valid at all time.
    If the `sock' is NULL then the conn->sock will be used.  If `sock' is
    provided it will be checked whether the sock and `conn->sock' are the
    same (they can be different, ie. a socket can use `conn' as its
@@ -1528,6 +1527,12 @@ void silc_client_close_connection_real(SilcClient client,
   if (!sock)
     sock = conn->sock;
 
+  if (!sock) {
+    if (del && conn)
+      silc_client_del_connection(client, conn);
+    return;
+  }
+
   /* We won't listen for this connection anymore */
   silc_schedule_unset_listen_fd(client->schedule, sock->sock);
 
@@ -1539,9 +1544,9 @@ void silc_client_close_connection_real(SilcClient client,
 
   /* Cancel any active protocol */
   if (sock->protocol) {
-    if (sock->protocol->protocol->type == 
+    if (sock->protocol->protocol->type ==
        SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
-       sock->protocol->protocol->type == 
+       sock->protocol->protocol->type ==
        SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
       sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
       silc_protocol_execute_final(sock->protocol, client->schedule);
@@ -1570,7 +1575,7 @@ void silc_client_close_connection(SilcClient client,
   silc_client_close_connection_real(client, NULL, conn);
 }
 
-/* Called when we receive disconnection packet from server. This 
+/* Called when we receive disconnection packet from server. This
    closes our end properly and displays the reason of the disconnection
    on the screen. */
 
@@ -1586,7 +1591,7 @@ SILC_TASK_CALLBACK(silc_client_disconnected_by_server_later)
   silc_client_close_connection_real(client, sock, sock->user_data);
 }
 
-/* Called when we receive disconnection packet from server. This 
+/* Called when we receive disconnection packet from server. This
    closes our end properly and displays the reason of the disconnection
    on the screen. */
 
@@ -1618,13 +1623,13 @@ void silc_client_disconnected_by_server(SilcClient client,
   SILC_SET_DISCONNECTED(sock);
 
   /* Close connection through scheduler. */
-  silc_schedule_task_add(client->schedule, sock->sock, 
+  silc_schedule_task_add(client->schedule, sock->sock,
                         silc_client_disconnected_by_server_later,
-                        client, 0, 1, SILC_TASK_TIMEOUT, 
+                        client, 0, 1, SILC_TASK_TIMEOUT,
                         SILC_TASK_PRI_NORMAL);
 }
 
-/* Received error message from server. Display it on the screen. 
+/* Received error message from server. Display it on the screen.
    We don't take any action what so ever of the error message. */
 
 void silc_client_error_by_server(SilcClient client,
@@ -1634,7 +1639,7 @@ void silc_client_error_by_server(SilcClient client,
   char *msg;
 
   msg = silc_memdup(message->data, message->len);
-  client->internal->ops->say(client, sock->user_data, 
+  client->internal->ops->say(client, sock->user_data,
                             SILC_CLIENT_MESSAGE_AUDIT, msg);
   silc_free(msg);
 }
@@ -1646,8 +1651,8 @@ SILC_TASK_CALLBACK(silc_client_send_auto_nick)
   SilcClientConnection conn = (SilcClientConnection)context;
   SilcClient client = conn->client;
   if (client)
-    silc_client_command_send(client, conn, SILC_COMMAND_NICK, 
-                            ++conn->cmd_ident, 1, 1, 
+    silc_client_command_send(client, conn, SILC_COMMAND_NICK,
+                            ++conn->cmd_ident, 1, 1,
                             client->nickname, strlen(client->nickname));
 }
 
@@ -1672,7 +1677,7 @@ static void silc_client_resume_session_cb(SilcClient client,
     /* Issue INFO command to fetch the real server name and server
        information and other stuff. */
     silc_client_command_register(client, SILC_COMMAND_INFO, NULL, NULL,
-                                silc_client_command_reply_info_i, 0, 
+                                silc_client_command_reply_info_i, 0,
                                 ++conn->cmd_ident);
     sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
     silc_client_command_send(client, conn, SILC_COMMAND_INFO,
@@ -1707,7 +1712,7 @@ void silc_client_receive_new_id(SilcClient client,
                                conn->local_entry);
     silc_free(conn->local_id);
   }
-  
+
   /* Save the new ID */
 
   if (conn->local_id_data)
@@ -1728,14 +1733,14 @@ void silc_client_receive_new_id(SilcClient client,
   conn->local_entry->id = conn->local_id;
   conn->local_entry->valid = TRUE;
   if (!conn->local_entry->channels)
-    conn->local_entry->channels = silc_hash_table_alloc(1, silc_hash_ptr, 
+    conn->local_entry->channels = silc_hash_table_alloc(1, silc_hash_ptr,
                                                        NULL, NULL,
-                                                       NULL, NULL, NULL, 
+                                                       NULL, NULL, NULL,
                                                        TRUE);
 
   /* Put it to the ID cache */
   silc_idcache_add(conn->internal->client_cache,
-                  strdup(conn->nickname), conn->local_id, 
+                  strdup(conn->nickname), conn->local_id,
                   (void *)conn->local_entry, 0, NULL);
 
   if (connecting) {
@@ -1744,7 +1749,7 @@ void silc_client_receive_new_id(SilcClient client,
     /* Issue IDENTIFY command for itself to get resolved hostname
        correctly from server. */
     silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
-                                silc_client_command_reply_identify_i, 0, 
+                                silc_client_command_reply_identify_i, 0,
                                 ++conn->cmd_ident);
     sidp = silc_id_payload_encode(conn->local_entry->id, SILC_ID_CLIENT);
     silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
@@ -1766,7 +1771,7 @@ void silc_client_receive_new_id(SilcClient client,
       /* Issue INFO command to fetch the real server name and server
         information and other stuff. */
       silc_client_command_register(client, SILC_COMMAND_INFO, NULL, NULL,
-                                  silc_client_command_reply_info_i, 0, 
+                                  silc_client_command_reply_info_i, 0,
                                   ++conn->cmd_ident);
       sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
       silc_client_command_send(client, conn, SILC_COMMAND_INFO,
@@ -1807,7 +1812,7 @@ void silc_client_remove_from_channels(SilcClient client,
    is replaced from ID cache with the new one. If the old ID entry is only
    updated, then this fucntion needs not to be called. */
 
-void silc_client_replace_from_channels(SilcClient client, 
+void silc_client_replace_from_channels(SilcClient client,
                                       SilcClientConnection conn,
                                       SilcClientEntry old,
                                       SilcClientEntry new)
@@ -1820,7 +1825,7 @@ void silc_client_replace_from_channels(SilcClient client,
     /* Replace client entry */
     silc_hash_table_del(chu->client->channels, chu->channel);
     silc_hash_table_del(chu->channel->user_list, chu->client);
-    
+
     chu->client = new;
     silc_hash_table_add(chu->channel->user_list, chu->client, chu);
     silc_hash_table_add(chu->client->channels, chu->channel, chu);
@@ -1860,6 +1865,11 @@ SILC_TASK_CALLBACK_GLOBAL(silc_client_rekey_callback)
 
   SILC_LOG_DEBUG(("Start"));
 
+  /* If rekey protocol is active already wait for it to finish */
+  if (sock->protocol && sock->protocol->protocol &&
+      sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)
+    return;
+
   /* Allocate internal protocol context. This is sent as context
      to the protocol. */
   proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
@@ -1867,21 +1877,15 @@ SILC_TASK_CALLBACK_GLOBAL(silc_client_rekey_callback)
   proto_ctx->sock = silc_socket_dup(sock);
   proto_ctx->responder = FALSE;
   proto_ctx->pfs = conn->internal->rekey->pfs;
-      
+
   /* Perform rekey protocol. Will call the final callback after the
      protocol is over. */
-  silc_protocol_alloc(SILC_PROTOCOL_CLIENT_REKEY, 
+  silc_protocol_alloc(SILC_PROTOCOL_CLIENT_REKEY,
                      &protocol, proto_ctx, silc_client_rekey_final);
   sock->protocol = protocol;
-      
+
   /* Run the protocol */
   silc_protocol_execute(protocol, client->schedule, 0, 0);
-
-  /* Re-register re-key timeout */
-  silc_schedule_task_add(client->schedule, sock->sock, 
-                        silc_client_rekey_callback,
-                        context, conn->internal->rekey->timeout, 0,
-                        SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
 }
 
 /* The final callback for the REKEY protocol. This will actually take the
@@ -1894,6 +1898,7 @@ SILC_TASK_CALLBACK(silc_client_rekey_final)
     (SilcClientRekeyInternalContext *)protocol->context;
   SilcClient client = (SilcClient)ctx->client;
   SilcSocketConnection sock = ctx->sock;
+  SilcClientConnection conn = (SilcClientConnection)sock->user_data;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -1916,6 +1921,13 @@ SILC_TASK_CALLBACK(silc_client_rekey_final)
      go to the network before we quit the protocol. */
   silc_client_packet_queue_purge(client, sock);
 
+  /* Re-register re-key timeout */
+  if (ctx->responder == FALSE)
+    silc_schedule_task_add(client->schedule, sock->sock,
+                          silc_client_rekey_callback,
+                          sock, conn->internal->rekey->timeout, 0,
+                          SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+
   /* Cleanup */
   silc_protocol_free(protocol);
   sock->protocol = NULL;
@@ -1952,7 +1964,7 @@ void silc_client_connection_auth_request(SilcClient client,
   if (ret == -1)
     auth_meth = SILC_AUTH_NONE;
 
-  /* Call the request callback to notify application for received 
+  /* Call the request callback to notify application for received
      authentication method information. */
   if (conn->internal->connauth->callback)
     (*conn->internal->connauth->callback)(client, conn, auth_meth,
@@ -1964,7 +1976,7 @@ void silc_client_connection_auth_request(SilcClient client,
   conn->internal->connauth = NULL;
 }
 
-/* Timeout task callback called if the server does not reply to our 
+/* Timeout task callback called if the server does not reply to our
    connection authentication method request in the specified time interval. */
 
 SILC_TASK_CALLBACK(silc_client_request_authentication_method_timeout)
@@ -1992,7 +2004,7 @@ SILC_TASK_CALLBACK(silc_client_request_authentication_method_timeout)
    The `callback' with `context' will be called after the server has
    replied back with the current authentication method. */
 
-void 
+void
 silc_client_request_authentication_method(SilcClient client,
                                          SilcClientConnection conn,
                                          SilcConnectionAuthRequest callback,
@@ -2018,17 +2030,17 @@ silc_client_request_authentication_method(SilcClient client,
                     SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT),
                     SILC_STR_UI_SHORT(SILC_AUTH_NONE),
                     SILC_STR_END);
-  silc_client_packet_send(client, conn->sock, 
+  silc_client_packet_send(client, conn->sock,
                          SILC_PACKET_CONNECTION_AUTH_REQUEST,
-                         NULL, 0, NULL, NULL, 
+                         NULL, 0, NULL, NULL,
                          packet->data, packet->len, FALSE);
   silc_buffer_free(packet);
 
   /* Register a timeout in case server does not reply anything back. */
   connauth->timeout =
-    silc_schedule_task_add(client->schedule, conn->sock->sock, 
+    silc_schedule_task_add(client->schedule, conn->sock->sock,
                           silc_client_request_authentication_method_timeout,
-                          conn, 
+                          conn,
                           client->internal->params->connauth_request_secs, 0,
                           SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
 }
index 68983d59c6f6692dc5adf3837deca7c95632cd1f..0d4384096b62779c95409bb0d786a5a6f8b8fd5a 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  client_channel.c 
+  client_channel.c
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2002 Pekka Riikonen
+  Copyright (C) 1997 - 2003 Pekka Riikonen
 
   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
@@ -18,7 +18,7 @@
 */
 /* $Id$ */
 /* This file includes channel message sending and receiving routines,
-   channel key receiving and setting, and channel private key handling 
+   channel key receiving and setting, and channel private key handling
    routines. */
 
 #include "silcincludes.h"
 #include "client_internal.h"
 
 /* Sends packet to the `channel'. Packet to channel is always encrypted
-   differently from "normal" packets. SILC header of the packet is 
+   differently from "normal" packets. SILC header of the packet is
    encrypted with the next receiver's key and the rest of the packet is
    encrypted with the channel specific key. Padding and HMAC is computed
    with the next receiver's key. The `data' is the channel message. If
    the `force_send' is TRUE then the packet is sent immediately. */
 
-void silc_client_send_channel_message(SilcClient client, 
+bool silc_client_send_channel_message(SilcClient client,
                                      SilcClientConnection conn,
                                      SilcChannelEntry channel,
                                      SilcChannelPrivateKey key,
                                      SilcMessageFlags flags,
-                                     unsigned char *data, 
-                                     SilcUInt32 data_len, 
+                                     unsigned char *data,
+                                     SilcUInt32 data_len,
                                      bool force_send)
 {
   SilcSocketConnection sock;
@@ -50,6 +50,7 @@ void silc_client_send_channel_message(SilcClient client,
   unsigned char *id_string;
   int block_len;
   SilcChannelUser chu;
+  bool ret = FALSE;
 
   assert(client && conn && channel);
   sock = conn->sock;
@@ -58,18 +59,18 @@ void silc_client_send_channel_message(SilcClient client,
   chu = silc_client_on_channel(channel, conn->local_entry);
   if (!chu) {
     SILC_LOG_ERROR(("Cannot send message to channel we are not joined"));
-    return;
+    return FALSE;
   }
 
   /* Check if it is allowed to send messages to this channel by us. */
   if (channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS && !chu->mode)
-    return;
-  if (channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS && 
+    return FALSE;
+  if (channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS &&
       chu->mode & SILC_CHANNEL_UMODE_CHANOP &&
       !(chu->mode & SILC_CHANNEL_UMODE_CHANFO))
-    return;
+    return FALSE;
   if (chu->mode & SILC_CHANNEL_UMODE_QUIET)
-    return;
+    return FALSE;
 
   /* Take the key to be used */
   if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
@@ -82,13 +83,13 @@ void silc_client_send_channel_message(SilcClient client,
       cipher = channel->curr_key->cipher;
       hmac = channel->curr_key->hmac;
     } else if (!channel->curr_key && channel->private_keys) {
-      /* Use just some private key since we don't know what to use 
+      /* Use just some private key since we don't know what to use
         and private keys are set. */
       silc_dlist_start(channel->private_keys);
       key = silc_dlist_get(channel->private_keys);
       cipher = key->cipher;
       hmac = key->hmac;
-      
+
       /* Use this key as current private key */
       channel->curr_key = key;
     } else {
@@ -102,8 +103,10 @@ void silc_client_send_channel_message(SilcClient client,
     hmac = channel->hmac;
   }
 
-  if (!cipher || !hmac)
-    return;
+  if (!cipher || !hmac) {
+    SILC_LOG_ERROR(("No cipher and HMAC for channel"));
+    return FALSE;
+  }
 
   block_len = silc_cipher_get_block_len(cipher);
 
@@ -111,6 +114,10 @@ void silc_client_send_channel_message(SilcClient client,
   payload = silc_message_payload_encode(flags, data, data_len, TRUE, FALSE,
                                        cipher, hmac, client->rng, NULL,
                                        client->private_key, client->sha1hash);
+  if (!payload) {
+    SILC_LOG_ERROR(("Error encoding channel message"));
+    return FALSE;
+  }
 
   /* Get data used in packet header encryption, keys and stuff. */
   cipher = conn->internal->send_key;
@@ -133,7 +140,7 @@ void silc_client_send_channel_message(SilcClient client,
   data_len = SILC_PACKET_DATALEN(data_len, SILC_PACKET_HEADER_LEN +
                                 packetdata.src_id_len +
                                 packetdata.dst_id_len);
-  packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
+  packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
     packetdata.src_id_len + packetdata.dst_id_len;
   SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
                      packetdata.src_id_len +
@@ -146,10 +153,10 @@ void silc_client_send_channel_message(SilcClient client,
     goto out;
   }
 
-  /* Encrypt the header and padding of the packet. This is encrypted 
+  /* Encrypt the header and padding of the packet. This is encrypted
      with normal session key shared with our server. */
   silc_packet_encrypt(cipher, hmac, conn->internal->psn_send++,
-                     (SilcBuffer)&packet, SILC_PACKET_HEADER_LEN + 
+                     (SilcBuffer)&packet, SILC_PACKET_HEADER_LEN +
                      packetdata.src_id_len + packetdata.dst_id_len +
                      packetdata.padlen);
 
@@ -165,9 +172,13 @@ void silc_client_send_channel_message(SilcClient client,
                           silc_client_rekey_callback, sock, 0, 1,
                           SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
 
+  ret = TRUE;
+
  out:
   silc_buffer_free(payload);
   silc_free(id_string);
+
+  return ret;
 }
 
 typedef struct {
@@ -203,7 +214,7 @@ static void silc_client_channel_message_cb(SilcClient client,
     }
 
     message = silc_message_get_data(res->payload, &message_len);
-    
+
     /* Pass the message to application */
     client->internal->ops->channel_message(
                            client, conn, clients[0], channel, res->payload,
@@ -221,8 +232,8 @@ static void silc_client_channel_message_cb(SilcClient client,
    decrypts the channel message with channel specific key and parses the
    message payload. Finally it displays the message on the screen. */
 
-void silc_client_channel_message(SilcClient client, 
-                                SilcSocketConnection sock, 
+void silc_client_channel_message(SilcClient client,
+                                SilcSocketConnection sock,
                                 SilcPacketContext *packet)
 {
   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
@@ -235,7 +246,7 @@ void silc_client_channel_message(SilcClient client,
   unsigned char *message;
   SilcUInt32 message_len;
 
-  SILC_LOG_DEBUG(("Start"));
+  SILC_LOG_DEBUG(("Received channel message"));
 
   /* Sanity checks */
   if (packet->dst_id_type != SILC_ID_CHANNEL)
@@ -254,7 +265,7 @@ void silc_client_channel_message(SilcClient client,
   if (!channel)
     goto out;
 
-  /* If there is no channel private key then just decrypt the message 
+  /* If there is no channel private key then just decrypt the message
      with the channel key. If private keys are set then just go through
      all private keys and check what decrypts correctly. */
   if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
@@ -267,17 +278,31 @@ void silc_client_channel_message(SilcClient client,
        we will use the old key in decryption. If that fails too then we
        cannot do more and will drop the packet. */
     if (!payload) {
-      if (!channel->old_channel_key) {
-       goto out;
-      }
+      SilcCipher key;
+      SilcHmac hmac;
+      int i;
 
-      payload = silc_message_payload_parse(buffer->data, buffer->len,
-                                          FALSE, FALSE,
-                                          channel->old_channel_key,
-                                          channel->old_hmac);
-      if (!payload) {
+      if (!channel->old_channel_keys ||
+         !silc_dlist_count(channel->old_channel_keys))
        goto out;
+
+      SILC_LOG_DEBUG(("Attempting to decrypt with old channel key(s)"));
+
+      silc_dlist_end(channel->old_channel_keys);
+      silc_dlist_end(channel->old_hmacs);
+      for (i = 0; i < silc_dlist_count(channel->old_channel_keys); i++) {
+       key = silc_dlist_get(channel->old_channel_keys);
+       hmac = silc_dlist_get(channel->old_hmacs);
+       if (!key || !hmac)
+         break;
+
+       payload = silc_message_payload_parse(buffer->data, buffer->len,
+                                            FALSE, FALSE, key, hmac);
+       if (payload)
+         break;
       }
+      if (!payload)
+       goto out;
     }
   } else if (channel->private_keys) {
     SilcChannelPrivateKey entry;
@@ -285,7 +310,7 @@ void silc_client_channel_message(SilcClient client,
     silc_dlist_start(channel->private_keys);
     while ((entry = silc_dlist_get(channel->private_keys)) != SILC_LIST_END) {
       /* Parse the message payload. This also decrypts the payload */
-      payload = silc_message_payload_parse(buffer->data, buffer->len, 
+      payload = silc_message_payload_parse(buffer->data, buffer->len,
                                           FALSE, FALSE,
                                           entry->cipher, entry->hmac);
       if (payload)
@@ -329,29 +354,41 @@ void silc_client_channel_message(SilcClient client,
 }
 
 /* Timeout callback that is called after a short period of time after the
-   new channel key has been created. This removes the old channel key all
-   together. */
+   new channel key has been created.  This removes the first channel key
+   in the list. */
 
 SILC_TASK_CALLBACK(silc_client_save_channel_key_rekey)
 {
   SilcChannelEntry channel = (SilcChannelEntry)context;
+  SilcCipher key;
+  SilcHmac hmac;
+
+  if (channel->old_channel_keys) {
+    silc_dlist_start(channel->old_channel_keys);
+    key = silc_dlist_get(channel->old_channel_keys);
+    if (key) {
+      silc_dlist_del(channel->old_channel_keys, key);
+      silc_cipher_free(key);
+    }
+  }
 
-  if (channel->old_channel_key)
-    silc_cipher_free(channel->old_channel_key);
-  if (channel->old_hmac)
-    silc_hmac_free(channel->old_hmac);
-  channel->old_channel_key = NULL;
-  channel->old_hmac = NULL;
-  channel->rekey_task = NULL;
+  if (channel->old_hmacs) {
+    silc_dlist_start(channel->old_hmacs);
+    hmac = silc_dlist_get(channel->old_hmacs);
+    if (hmac) {
+      silc_dlist_del(channel->old_hmacs, hmac);
+      silc_hmac_free(hmac);
+    }
+  }
 }
 
 /* Saves channel key from encoded `key_payload'. This is used when we
-   receive Channel Key Payload and when we are processing JOIN command 
+   receive Channel Key Payload and when we are processing JOIN command
    reply. */
 
 void silc_client_save_channel_key(SilcClient client,
                                  SilcClientConnection conn,
-                                 SilcBuffer key_payload, 
+                                 SilcBuffer key_payload,
                                  SilcChannelEntry channel)
 {
   unsigned char *id_string, *key, *cipher, *hmac, hash[32];
@@ -383,24 +420,21 @@ void silc_client_save_channel_key(SilcClient client,
       goto out;
   }
 
-  hmac = (channel->hmac ? (char *)silc_hmac_get_name(channel->hmac) : 
+  hmac = (channel->hmac ? (char *)silc_hmac_get_name(channel->hmac) :
          SILC_DEFAULT_HMAC);
 
   /* Save the old key for a short period of time so that we can decrypt
      channel message even after the rekey if some client would be sending
      messages with the old key after the rekey. */
-  if (channel->old_channel_key)
-    silc_cipher_free(channel->old_channel_key);
-  if (channel->old_hmac)
-    silc_hmac_free(channel->old_hmac);
-  if (channel->rekey_task)
-    silc_schedule_task_del(client->schedule, channel->rekey_task);
-  channel->old_channel_key = channel->channel_key;
-  channel->old_hmac = channel->hmac;
-  channel->rekey_task = 
-    silc_schedule_task_add(client->schedule, 0,
-                          silc_client_save_channel_key_rekey, channel,
-                          10, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+  if (!channel->old_channel_keys)
+    channel->old_channel_keys = silc_dlist_init();
+  if (!channel->old_hmacs)
+    channel->old_hmacs = silc_dlist_init();
+  silc_dlist_add(channel->old_channel_keys, channel->channel_key);
+  silc_dlist_add(channel->old_hmacs, channel->hmac);
+  silc_schedule_task_add(client->schedule, 0,
+                        silc_client_save_channel_key_rekey, channel,
+                        10, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
 
   /* Free the old channel key data */
   silc_free(channel->key);
@@ -413,9 +447,9 @@ void silc_client_save_channel_key(SilcClient client,
 
   if (!silc_cipher_alloc(cipher, &channel->channel_key)) {
     client->internal->ops->say(
-                          conn->client, conn, 
+                          conn->client, conn,
                           SILC_CLIENT_MESSAGE_AUDIT,
-                          "Cannot talk to channel: unsupported cipher %s", 
+                          "Cannot talk to channel: unsupported cipher %s",
                           cipher);
     goto out;
   }
@@ -426,7 +460,7 @@ void silc_client_save_channel_key(SilcClient client,
   /* Generate HMAC key from the channel key data and set it */
   silc_hmac_alloc(hmac, NULL, &channel->hmac);
   silc_hash_make(silc_hmac_get_hash(channel->hmac), key, tmp_len, hash);
-  silc_hmac_set_key(channel->hmac, hash, 
+  silc_hmac_set_key(channel->hmac, hash,
                    silc_hash_len(silc_hmac_get_hash(channel->hmac)));
   memset(hash, 0, sizeof(hash));
 
@@ -437,7 +471,7 @@ void silc_client_save_channel_key(SilcClient client,
 
 /* Processes received key for channel. The received key will be used
    to protect the traffic on the channel for now on. Client must receive
-   the key to the channel before talking on the channel is possible. 
+   the key to the channel before talking on the channel is possible.
    This is the key that server has generated, this is not the channel
    private key, it is entirely local setting. */
 
@@ -459,17 +493,17 @@ void silc_client_receive_channel_key(SilcClient client,
    several private keys per one channel. In this case only some of the
    clients on the channel may know the one key and only some the other key.
 
-   If `cipher' and/or `hmac' is NULL then default values will be used 
+   If `cipher' and/or `hmac' is NULL then default values will be used
    (aes-256-cbc for cipher and hmac-sha1-96 for hmac).
 
    The private key for channel is optional. If it is not set then the
    channel messages are encrypted using the channel key generated by the
-   server. However, setting the private key (or keys) for the channel 
+   server. However, setting the private key (or keys) for the channel
    significantly adds security. If more than one key is set the library
    will automatically try all keys at the message decryption phase. Note:
    setting many keys slows down the decryption phase as all keys has to
    be tried in order to find the correct decryption key. However, setting
-   a few keys does not have big impact to the decryption performace. 
+   a few keys does not have big impact to the decryption performace.
 
    NOTE: that this is entirely local setting. The key set using this function
    is not sent to the network at any phase.
@@ -511,8 +545,8 @@ bool silc_client_add_channel_private_key(SilcClient client,
 
   /* Produce the key material */
   keymat = silc_calloc(1, sizeof(*keymat));
-  if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16, 
-                                        client->sha1hash, keymat) 
+  if (silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
+                                        client->sha1hash, keymat)
       != SILC_SKE_STATUS_OK)
     return FALSE;
 
@@ -545,9 +579,9 @@ bool silc_client_add_channel_private_key(SilcClient client,
 
   /* Generate HMAC key from the channel key data and set it */
   silc_hmac_alloc(hmac, NULL, &entry->hmac);
-  silc_hash_make(silc_hmac_get_hash(entry->hmac), entry->key, 
+  silc_hash_make(silc_hmac_get_hash(entry->hmac), entry->key,
                 entry->key_len, hash);
-  silc_hmac_set_key(entry->hmac, hash, 
+  silc_hmac_set_key(entry->hmac, hash,
                    silc_hash_len(silc_hmac_get_hash(entry->hmac)));
   memset(hash, 0, sizeof(hash));
 
@@ -695,7 +729,7 @@ void silc_client_current_channel_private_key(SilcClient client,
   channel->curr_key = key;
 }
 
-/* Returns the SilcChannelUser entry if the `client_entry' is joined on the 
+/* Returns the SilcChannelUser entry if the `client_entry' is joined on the
    channel indicated by the `channel'. NULL if client is not joined on
    the channel. */
 
@@ -704,7 +738,7 @@ SilcChannelUser silc_client_on_channel(SilcChannelEntry channel,
 {
   SilcChannelUser chu;
 
-  if (silc_hash_table_find(channel->user_list, client_entry, NULL, 
+  if (silc_hash_table_find(channel->user_list, client_entry, NULL,
                           (void *)&chu))
     return chu;
 
index 098054804d5fc71d000d9155af996b02606cb7f5..4155d61ed93e77a40f49d779d8f81329e2a96bb8 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  client_internal.h 
+  client_internal.h
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2001 Pekka Riikonen
+  Copyright (C) 1997 - 2001, 2003 Pekka Riikonen
 
   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
@@ -31,14 +31,14 @@ typedef struct {
 
 /* Generic rekey context for connections */
 typedef struct {
-  /* Current sending encryption key, provided for re-key. The `pfs'   
+  /* Current sending encryption key, provided for re-key. The `pfs'
      is TRUE if the Perfect Forward Secrecy is performed in re-key. */
   unsigned char *send_enc_key;
   SilcUInt32 enc_key_len;
   int ske_group;
   bool pfs;
   SilcUInt32 timeout;
-  void *context;   
+  void *context;
 } *SilcClientRekey;
 
 /* Internal context for connection process. This is needed as we
@@ -54,7 +54,7 @@ typedef struct {
   void *context;
 } SilcClientInternalConnectContext;
 
-/* Structure to hold ping time information. Every PING command will 
+/* Structure to hold ping time information. Every PING command will
    add entry of this structure and is removed after reply to the ping
    as been received. */
 struct SilcClientPingStruct {
@@ -65,7 +65,7 @@ struct SilcClientPingStruct {
 
 /* Structure to hold away messages set by user. This is mainly created
    for future extensions where away messages could be set according filters
-   such as nickname and hostname. For now only one away message can 
+   such as nickname and hostname. For now only one away message can
    be set in one connection. */
 struct SilcClientAwayStruct {
   char *away;
@@ -161,7 +161,7 @@ typedef void (*SilcClientResumeSessionCallback)(SilcClient client,
 /* Macros */
 
 /* Registers generic task for file descriptor for reading from network and
-   writing to network. As being generic task the actual task is allocated 
+   writing to network. As being generic task the actual task is allocated
    only once and after that the same task applies to all registered fd's. */
 #define SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(fd)     \
 do {                                                   \
@@ -176,7 +176,7 @@ do {                                                        \
 do {                                                                   \
   silc_schedule_set_listen_fd((s), (fd), SILC_TASK_READ, FALSE);       \
 } while(0)
-     
+
 #define SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(s, fd)                   \
 do {                                                                   \
   silc_schedule_set_listen_fd((s), (fd), (SILC_TASK_READ |             \
@@ -190,6 +190,7 @@ do {                                                                \
                                                                \
   for (__i = 0; __i < (__x)->internal->conns_count; __i++)     \
     if ((__x)->internal->conns[__i] &&                         \
+       (__x)->internal->conns[__i]->sock &&                    \
        (__x)->internal->conns[__i]->sock->sock == (__fd))      \
       break;                                                   \
                                                                \
@@ -221,7 +222,7 @@ void silc_client_packet_send(SilcClient client,
                              unsigned char *data,
                              SilcUInt32 data_len,
                              bool force_send);
-bool silc_client_packet_send_real(SilcClient client,
+int silc_client_packet_send_real(SilcClient client,
                                 SilcSocketConnection sock,
                                 bool force_send);
 void silc_client_ftp_free_sessions(SilcClient client,
@@ -243,18 +244,18 @@ void silc_client_receive_new_id(SilcClient client,
                                SilcIDPayload idp);
 void silc_client_save_channel_key(SilcClient client,
                                  SilcClientConnection conn,
-                                 SilcBuffer key_payload, 
+                                 SilcBuffer key_payload,
                                  SilcChannelEntry channel);
 void silc_client_receive_channel_key(SilcClient client,
                                     SilcSocketConnection sock,
                                     SilcBuffer packet);
-void silc_client_channel_message(SilcClient client, 
-                                SilcSocketConnection sock, 
+void silc_client_channel_message(SilcClient client,
+                                SilcSocketConnection sock,
                                 SilcPacketContext *packet);
 void silc_client_remove_from_channels(SilcClient client,
                                      SilcClientConnection conn,
                                      SilcClientEntry client_entry);
-void silc_client_replace_from_channels(SilcClient client, 
+void silc_client_replace_from_channels(SilcClient client,
                                       SilcClientConnection conn,
                                       SilcClientEntry old,
                                       SilcClientEntry newclient);
@@ -267,8 +268,8 @@ void silc_client_key_agreement(SilcClient client,
 void silc_client_notify_by_server(SilcClient client,
                                  SilcSocketConnection sock,
                                  SilcPacketContext *packet);
-void silc_client_private_message(SilcClient client, 
-                                SilcSocketConnection sock, 
+void silc_client_private_message(SilcClient client,
+                                SilcSocketConnection sock,
                                 SilcPacketContext *packet);
 void silc_client_connection_auth_request(SilcClient client,
                                         SilcSocketConnection sock,
@@ -289,6 +290,8 @@ void silc_client_resume_session(SilcClient client,
 SilcBuffer silc_client_attributes_process(SilcClient client,
                                          SilcSocketConnection sock,
                                          SilcDList attrs);
+void silc_client_packet_queue_purge(SilcClient client,
+                                   SilcSocketConnection sock);
 SILC_TASK_CALLBACK_GLOBAL(silc_client_rekey_callback);
 
 #endif
index b6df9915e7f8456013721d71034863759d9b893b..b5387ef345cc9b4befeb792eb3edce620bcf1491 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  client_notify.c 
+  client_notify.c
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2002 Pekka Riikonen
+  Copyright (C) 1997 - 2003 Pekka Riikonen
 
   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
@@ -33,7 +33,7 @@ typedef struct {
 } *SilcClientNotifyResolve;
 
 SILC_TASK_CALLBACK(silc_client_notify_check_client)
-{ 
+{
   SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
   SilcClient client = res->context;
   SilcClientConnection conn = res->sock->user_data;
@@ -67,7 +67,7 @@ SILC_TASK_CALLBACK(silc_client_notify_del_client_cb)
 static void silc_client_notify_by_server_pending(void *context, void *context2)
 {
   SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
-  SilcClientCommandReplyContext reply = 
+  SilcClientCommandReplyContext reply =
     (SilcClientCommandReplyContext)context2;
 
   SILC_LOG_DEBUG(("Start"));
@@ -122,7 +122,7 @@ static void silc_client_channel_set_wait(SilcClient client,
   }
 }
 
-/* Attaches to the channel's resolving cmd ident and calls the 
+/* Attaches to the channel's resolving cmd ident and calls the
    notify handling with `packet' after it's received. */
 
 static void silc_client_channel_wait(SilcClient client,
@@ -173,7 +173,7 @@ static void silc_client_notify_by_server_resolve(SilcClient client,
     silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
                                 silc_client_command_reply_identify_i, 0,
                                 ++conn->cmd_ident);
-    silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY, 
+    silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
                             conn->cmd_ident, 1, 5, idp->data, idp->len);
     silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
                                silc_client_notify_by_server_pending, res);
@@ -220,16 +220,16 @@ void silc_client_notify_by_server(SilcClient client,
   switch(type) {
   case SILC_NOTIFY_TYPE_NONE:
     /* Notify application */
-    client->internal->ops->notify(client, conn, type, 
+    client->internal->ops->notify(client, conn, type,
                                  silc_argument_get_arg_type(args, 1, NULL));
     break;
 
   case SILC_NOTIFY_TYPE_INVITE:
-    /* 
+    /*
      * Someone invited me to a channel. Find Client and Channel entries
      * for the application.
      */
-    
+
     SILC_LOG_DEBUG(("Notify: INVITE"));
 
     /* Get Channel ID */
@@ -256,7 +256,7 @@ void silc_client_notify_by_server(SilcClient client,
     /* Find Client entry and if not found query it */
     client_entry = silc_client_get_client_by_id(client, conn, client_id);
     if (!client_entry) {
-      silc_client_notify_by_server_resolve(client, conn, packet, 
+      silc_client_notify_by_server_resolve(client, conn, packet,
                                           SILC_ID_CLIENT, client_id);
       goto out;
     }
@@ -267,7 +267,7 @@ void silc_client_notify_by_server(SilcClient client,
       goto out;
 
     /* Notify application */
-    client->internal->ops->notify(client, conn, type, channel, tmp, 
+    client->internal->ops->notify(client, conn, type, channel, tmp,
                                  client_entry);
     break;
 
@@ -279,6 +279,20 @@ void silc_client_notify_by_server(SilcClient client,
 
     SILC_LOG_DEBUG(("Notify: JOIN"));
 
+    /* Get Channel ID */
+    tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+    if (!tmp)
+      goto out;
+
+    channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+    if (!channel_id)
+      goto out;
+
+    /* Get channel entry */
+    channel = silc_client_get_channel_by_id(client, conn, channel_id);
+    if (!channel)
+      break;
+
     /* Get Client ID */
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
@@ -291,7 +305,9 @@ void silc_client_notify_by_server(SilcClient client,
     /* Find Client entry and if not found query it */
     client_entry = silc_client_get_client_by_id(client, conn, client_id);
     if (!client_entry) {
-      silc_client_notify_by_server_resolve(client, conn, packet, 
+      silc_client_channel_set_wait(client, conn, channel,
+                                  conn->cmd_ident + 1);
+      silc_client_notify_by_server_resolve(client, conn, packet,
                                           SILC_ID_CLIENT, client_id);
       goto out;
     }
@@ -299,10 +315,22 @@ void silc_client_notify_by_server(SilcClient client,
     /* If nickname or username hasn't been resolved, do so */
     if (!client_entry->nickname || !client_entry->username) {
       if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
-       client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
+       /* Attach to existing resolving */
+       SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
+       res->packet = silc_packet_context_dup(packet);
+       res->context = client;
+       res->sock = silc_socket_dup(conn->sock);
+       silc_client_command_pending(conn, SILC_COMMAND_NONE,
+                                   client_entry->resolve_cmd_ident,
+                                   silc_client_notify_by_server_pending,
+                                   res);
        goto out;
       }
-      silc_client_notify_by_server_resolve(client, conn, packet, 
+
+      /* Do new resolving */
+      silc_client_channel_set_wait(client, conn, channel,
+                                  conn->cmd_ident + 1);
+      silc_client_notify_by_server_resolve(client, conn, packet,
                                           SILC_ID_CLIENT, client_id);
       client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
       client_entry->resolve_cmd_ident = conn->cmd_ident;
@@ -312,19 +340,11 @@ void silc_client_notify_by_server(SilcClient client,
        silc_client_nickname_format(client, conn, client_entry);
     }
 
-    /* Get Channel ID */
-    tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
-    if (!tmp)
-      goto out;
-
-    channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
-    if (!channel_id)
+    /* If information is being resolved for this channel, wait for it */
+    if (channel->resolve_cmd_ident) {
+      silc_client_channel_wait(client, conn, channel, packet);
       goto out;
-
-    /* Get channel entry */
-    channel = silc_client_get_channel_by_id(client, conn, channel_id);
-    if (!channel)
-      break;
+    }
 
     /* Join the client to channel */
     if (!silc_client_on_channel(channel, client_entry)) {
@@ -346,7 +366,7 @@ void silc_client_notify_by_server(SilcClient client,
      * Someone has left a channel. We will remove it from the channel but
      * we'll keep it in the cache in case we'll need it later.
      */
-    
+
     SILC_LOG_DEBUG(("Notify: LEAVE"));
 
     /* Get Client ID */
@@ -359,7 +379,7 @@ void silc_client_notify_by_server(SilcClient client,
       goto out;
 
     /* Find Client entry */
-    client_entry = 
+    client_entry =
       silc_client_get_client_by_id(client, conn, client_id);
     if (!client_entry)
       goto out;
@@ -382,7 +402,7 @@ void silc_client_notify_by_server(SilcClient client,
     }
 
     /* Some client implementations actually quit network by first doing
-       LEAVE and then immediately SIGNOFF.  We'll check for this by doing 
+       LEAVE and then immediately SIGNOFF.  We'll check for this by doing
        check for the client after 5 - 34 seconds.  If it is not valid after
        that we'll remove the client from cache. */
     if (!silc_hash_table_count(client_entry->channels)) {
@@ -419,7 +439,7 @@ void silc_client_notify_by_server(SilcClient client,
       goto out;
 
     /* Find Client entry */
-    client_entry = 
+    client_entry =
       silc_client_get_client_by_id(client, conn, client_id);
     if (!client_entry)
       goto out;
@@ -474,7 +494,7 @@ void silc_client_notify_by_server(SilcClient client,
       if (!client_entry) {
        silc_client_channel_set_wait(client, conn, channel,
                                     conn->cmd_ident + 1);
-       silc_client_notify_by_server_resolve(client, conn, packet, 
+       silc_client_notify_by_server_resolve(client, conn, packet,
                                             SILC_ID_CLIENT, client_id);
        goto out;
       }
@@ -485,7 +505,7 @@ void silc_client_notify_by_server(SilcClient client,
       if (!server) {
        silc_client_channel_set_wait(client, conn, channel,
                                     conn->cmd_ident + 1);
-       silc_client_notify_by_server_resolve(client, conn, packet, 
+       silc_client_notify_by_server_resolve(client, conn, packet,
                                             SILC_ID_SERVER, server_id);
        server = silc_client_add_server(client, conn, NULL, NULL, server_id);
        if (!server)
@@ -502,12 +522,12 @@ void silc_client_notify_by_server(SilcClient client,
        res->packet = silc_packet_context_dup(packet);
        res->context = client;
        res->sock = silc_socket_dup(conn->sock);
-       silc_client_command_pending(conn, SILC_COMMAND_NONE, 
+       silc_client_command_pending(conn, SILC_COMMAND_NONE,
                                    server->resolve_cmd_ident,
                                    silc_client_notify_by_server_pending, res);
        goto out;
       }
-      
+
       /* Save the pointer to the client_entry pointer */
       client_entry = (SilcClientEntry)server;
     } else {
@@ -519,7 +539,7 @@ void silc_client_notify_by_server(SilcClient client,
       if (!client_entry) {
        silc_client_channel_set_wait(client, conn, channel,
                                     conn->cmd_ident + 1);
-       silc_client_notify_by_server_resolve(client, conn, packet, 
+       silc_client_notify_by_server_resolve(client, conn, packet,
                                             SILC_ID_CHANNEL, channel_id);
        goto out;
       }
@@ -548,7 +568,7 @@ void silc_client_notify_by_server(SilcClient client,
     /*
      * Someone changed their nickname. If we don't have entry for the new
      * ID we will query it and return here after it's done. After we've
-     * returned we fetch the old entry and free it and notify the 
+     * returned we fetch the old entry and free it and notify the
      * application.
      */
 
@@ -580,7 +600,7 @@ void silc_client_notify_by_server(SilcClient client,
       res->packet = silc_packet_context_dup(packet);
       res->context = client;
       res->sock = silc_socket_dup(conn->sock);
-      silc_client_command_pending(conn, SILC_COMMAND_NONE, 
+      silc_client_command_pending(conn, SILC_COMMAND_NONE,
                                  client_entry->resolve_cmd_ident,
                                  silc_client_notify_by_server_pending, res);
       goto out;
@@ -603,11 +623,12 @@ void silc_client_notify_by_server(SilcClient client,
       goto out;
 
     /* Check whether nickname changed at all.  It is possible that nick
-       change notify is received but nickname didn't changed, only the
+       change notify is received but nickname didn't change, only the
        ID changes.  Check whether the hashes in the Client ID match, if
        they do nickname didn't change. */
-    if (SILC_ID_COMPARE_HASH(client_entry->id, client_id)) {
-      /* Nickname didn't change. Update only the ID */
+    if (SILC_ID_COMPARE_HASH(client_entry->id, client_id) &&
+       !strcmp(tmp, client_entry->nickname)) {
+      /* Nickname didn't change.  Update only Client ID. */
       silc_idcache_del_by_context(conn->internal->client_cache,
                                  client_entry);
       silc_free(client_entry->id);
@@ -616,16 +637,16 @@ void silc_client_notify_by_server(SilcClient client,
                       client_entry->id, client_entry, 0, NULL);
 
       /* Notify application */
-      client->internal->ops->notify(client, conn, type, 
+      client->internal->ops->notify(client, conn, type,
                                    client_entry, client_entry);
       break;
     }
 
     /* Create new client entry, and save all old information with the
        new nickname and client ID */
-    client_entry2 = silc_client_add_client(client, conn, NULL, NULL, 
+    client_entry2 = silc_client_add_client(client, conn, NULL, NULL,
                                           client_entry->realname,
-                                          silc_id_dup(client_id, 
+                                          silc_id_dup(client_id,
                                                       SILC_ID_CLIENT), 0);
     if (!client_entry2)
       goto out;
@@ -645,164 +666,195 @@ void silc_client_notify_by_server(SilcClient client,
 
     /* Remove the old from cache */
     silc_idcache_del_by_context(conn->internal->client_cache, client_entry);
-    
+
     /* Replace old ID entry with new one on all channels. */
     silc_client_replace_from_channels(client, conn, client_entry,
                                      client_entry2);
 
     /* Notify application */
-    client->internal->ops->notify(client, conn, type, 
+    client->internal->ops->notify(client, conn, type,
                                  client_entry, client_entry2);
-    
+
     /* Free old client entry */
     silc_client_del_client_entry(client, conn, client_entry);
 
     break;
 
   case SILC_NOTIFY_TYPE_CMODE_CHANGE:
-    /*
-     * Someone changed a channel mode
-     */
+    {
+      /*
+       * Someone changed a channel mode
+       */
+      char *passphrase, *cipher, *hmac;
+      SilcPublicKey founder_key = NULL;
+      SilcBufferStruct chpks;
 
-    SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
+      SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
 
-    /* Get channel entry */
-    channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
-                               SILC_ID_CHANNEL);
-    if (!channel_id)
-      goto out;
-    channel = silc_client_get_channel_by_id(client, conn, channel_id);
-    if (!channel)
-      goto out;
+      /* Get channel entry */
+      channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
+                                 SILC_ID_CHANNEL);
+      if (!channel_id)
+       goto out;
+      channel = silc_client_get_channel_by_id(client, conn, channel_id);
+      if (!channel)
+       goto out;
 
-    /* Get ID */
-    tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
-    if (!tmp)
-      goto out;
-    id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
-    if (!id)
-      goto out;
+      /* Get ID */
+      tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+      if (!tmp)
+       goto out;
+      id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
+      if (!id)
+       goto out;
 
-    /* Find Client entry */
-    if (id_type == SILC_ID_CLIENT) {
       /* Find Client entry */
-      client_id = id;
-      client_entry = silc_client_get_client_by_id(client, conn, client_id);
-      if (!client_entry) {
-       silc_client_channel_set_wait(client, conn, channel,
-                                    conn->cmd_ident + 1);
-       silc_client_notify_by_server_resolve(client, conn, packet, 
-                                            SILC_ID_CLIENT, client_id);
-       goto out;
-      }
+      if (id_type == SILC_ID_CLIENT) {
+       /* Find Client entry */
+       client_id = id;
+       client_entry = silc_client_get_client_by_id(client, conn, client_id);
+       if (!client_entry) {
+         silc_client_channel_set_wait(client, conn, channel,
+                                      conn->cmd_ident + 1);
+         silc_client_notify_by_server_resolve(client, conn, packet,
+                                              SILC_ID_CLIENT, client_id);
+         goto out;
+       }
 
-      if (!client_entry->nickname) {
-       if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
-         /* Attach to existing resolving */
+       if (!client_entry->nickname) {
+         if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
+           /* Attach to existing resolving */
+           SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
+           res->packet = silc_packet_context_dup(packet);
+           res->context = client;
+           res->sock = silc_socket_dup(conn->sock);
+           silc_client_command_pending(conn, SILC_COMMAND_NONE,
+                                       client_entry->resolve_cmd_ident,
+                                       silc_client_notify_by_server_pending,
+                                       res);
+           goto out;
+         }
+
+         /* Do new resolving */
+         silc_client_channel_set_wait(client, conn, channel,
+                                      conn->cmd_ident + 1);
+         silc_client_notify_by_server_resolve(client, conn, packet,
+                                              SILC_ID_CLIENT, client_id);
+         client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
+         client_entry->resolve_cmd_ident = conn->cmd_ident;
+         goto out;
+       }
+      } else if (id_type == SILC_ID_SERVER) {
+       /* Find Server entry */
+       server_id = id;
+       server = silc_client_get_server_by_id(client, conn, server_id);
+       if (!server) {
+         silc_client_channel_set_wait(client, conn, channel,
+                                      conn->cmd_ident + 1);
+         silc_client_notify_by_server_resolve(client, conn, packet,
+                                              SILC_ID_SERVER, server_id);
+         server = silc_client_add_server(client, conn, NULL, NULL, server_id);
+         if (!server)
+           goto out;
+
+         server->resolve_cmd_ident = conn->cmd_ident;
+         server_id = NULL;
+         goto out;
+       }
+
+       /* If entry being resoled, wait for it before processing this notify */
+       if (server->resolve_cmd_ident) {
          SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
          res->packet = silc_packet_context_dup(packet);
          res->context = client;
          res->sock = silc_socket_dup(conn->sock);
-         silc_client_command_pending(conn, SILC_COMMAND_NONE, 
-                                     client_entry->resolve_cmd_ident,
+         silc_client_command_pending(conn, SILC_COMMAND_NONE,
+                                     server->resolve_cmd_ident,
                                      silc_client_notify_by_server_pending,
                                      res);
          goto out;
        }
 
-       /* Do new resolving */
-       silc_client_channel_set_wait(client, conn, channel,
-                                    conn->cmd_ident + 1);
-       silc_client_notify_by_server_resolve(client, conn, packet, 
-                                            SILC_ID_CLIENT, client_id);
-       goto out;
-      }
-    } else if (id_type == SILC_ID_SERVER) {
-      /* Find Server entry */
-      server_id = id;
-      server = silc_client_get_server_by_id(client, conn, server_id);
-      if (!server) {
-       silc_client_channel_set_wait(client, conn, channel,
-                                    conn->cmd_ident + 1);
-       silc_client_notify_by_server_resolve(client, conn, packet, 
-                                            SILC_ID_SERVER, server_id);
-       server = silc_client_add_server(client, conn, NULL, NULL, server_id);
-       if (!server)
+       /* Save the pointer to the client_entry pointer */
+       client_entry = (SilcClientEntry)server;
+      } else {
+       /* Find Channel entry */
+       silc_free(channel_id);
+       channel_id = id;
+       client_entry = (SilcClientEntry)
+         silc_client_get_channel_by_id(client, conn, channel_id);
+       if (!client_entry) {
+         silc_client_channel_set_wait(client, conn, channel,
+                                      conn->cmd_ident + 1);
+         silc_client_notify_by_server_resolve(client, conn, packet,
+                                              SILC_ID_CHANNEL, channel_id);
          goto out;
-
-       server->resolve_cmd_ident = conn->cmd_ident;
-       server_id = NULL;
-       goto out;
+       }
       }
 
-      /* If entry being resoled, wait for it before processing this notify */
-      if (server->resolve_cmd_ident) {
-       SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
-       res->packet = silc_packet_context_dup(packet);
-       res->context = client;
-       res->sock = silc_socket_dup(conn->sock);
-       silc_client_command_pending(conn, SILC_COMMAND_NONE, 
-                                   server->resolve_cmd_ident,
-                                   silc_client_notify_by_server_pending, res);
+      /* Get the mode */
+      tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+      if (!tmp)
        goto out;
-      }
-      
-      /* Save the pointer to the client_entry pointer */
-      client_entry = (SilcClientEntry)server;
-    } else {
-      /* Find Channel entry */
-      silc_free(channel_id);
-      channel_id = id;
-      client_entry = (SilcClientEntry)
-       silc_client_get_channel_by_id(client, conn, channel_id);
-      if (!client_entry) {
-       silc_client_channel_set_wait(client, conn, channel,
-                                    conn->cmd_ident + 1);
-       silc_client_notify_by_server_resolve(client, conn, packet, 
-                                            SILC_ID_CHANNEL, channel_id);
+
+      SILC_GET32_MSB(mode, tmp);
+
+      /* If information is being resolved for this channel, wait for it */
+      if (channel->resolve_cmd_ident) {
+       silc_client_channel_wait(client, conn, channel, packet);
        goto out;
       }
-    }
 
-    /* Get the mode */
-    tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
-    if (!tmp)
-      goto out;
+      /* Save the new mode */
+      channel->mode = mode;
 
-    SILC_GET32_MSB(mode, tmp);
+      /* Get the cipher */
+      cipher = silc_argument_get_arg_type(args, 3, &tmp_len);
 
-    /* If information is being resolved for this channel, wait for it */
-    if (channel->resolve_cmd_ident) {
-      silc_client_channel_wait(client, conn, channel, packet);
-      goto out;
-    }
+      /* Get the hmac */
+      hmac = silc_argument_get_arg_type(args, 4, &tmp_len);
+      if (hmac) {
+       unsigned char hash[32];
 
-    /* Save the new mode */
-    channel->mode = mode;
+       if (channel->hmac)
+         silc_hmac_free(channel->hmac);
+       if (!silc_hmac_alloc(hmac, NULL, &channel->hmac))
+         goto out;
 
-    /* Get the hmac */
-    tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
-    if (tmp) {
-      unsigned char hash[32];
+       silc_hash_make(silc_hmac_get_hash(channel->hmac),
+                      channel->key, channel->key_len / 8,
+                      hash);
+       silc_hmac_set_key(channel->hmac, hash,
+                         silc_hash_len(silc_hmac_get_hash(channel->hmac)));
+       memset(hash, 0, sizeof(hash));
+      }
 
-      if (channel->hmac)
-       silc_hmac_free(channel->hmac);
-      if (!silc_hmac_alloc(tmp, NULL, &channel->hmac))
-       goto out;
+      /* Get the passphrase if it was set */
+      passphrase = silc_argument_get_arg_type(args, 5, &tmp_len);
 
-      silc_hash_make(silc_hmac_get_hash(channel->hmac), 
-                    channel->key, channel->key_len / 8,
-                    hash);
-      silc_hmac_set_key(channel->hmac, hash, 
-                       silc_hash_len(silc_hmac_get_hash(channel->hmac)));
-      memset(hash, 0, sizeof(hash));
-    }
+      /* Get the channel founder key if it was set */
+      tmp = silc_argument_get_arg_type(args, 6, &tmp_len);
+      if (tmp) {
+       if (!silc_pkcs_public_key_payload_decode(tmp, tmp_len, &founder_key))
+         founder_key = NULL;
+      }
 
-    /* Notify application. The channel entry is sent last as this notify
-       is for channel but application don't know it from the arguments
-       sent by server. */
-    client->internal->ops->notify(client, conn, type, id_type,
-                                 client_entry, mode, NULL, tmp, channel);
+      /* Get the channel public key that was added or removed */
+      tmp = silc_argument_get_arg_type(args, 7, &tmp_len);
+      if (tmp)
+       silc_buffer_set(&chpks, tmp, tmp_len);
+
+      /* Notify application. The channel entry is sent last as this notify
+        is for channel but application don't know it from the arguments
+        sent by server. */
+      client->internal->ops->notify(client, conn, type, id_type,
+                                   client_entry, mode, cipher, hmac,
+                                   passphrase, founder_key,
+                                   tmp ? &chpks : NULL, channel);
+
+      if (founder_key)
+       silc_pkcs_public_key_free(founder_key);
+    }
     break;
 
   case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
@@ -837,7 +889,7 @@ void silc_client_notify_by_server(SilcClient client,
       if (!client_entry) {
        silc_client_channel_set_wait(client, conn, channel,
                                     conn->cmd_ident + 1);
-       silc_client_notify_by_server_resolve(client, conn, packet, 
+       silc_client_notify_by_server_resolve(client, conn, packet,
                                             SILC_ID_CLIENT, client_id);
        goto out;
       }
@@ -849,7 +901,7 @@ void silc_client_notify_by_server(SilcClient client,
          res->packet = silc_packet_context_dup(packet);
          res->context = client;
          res->sock = silc_socket_dup(conn->sock);
-         silc_client_command_pending(conn, SILC_COMMAND_NONE, 
+         silc_client_command_pending(conn, SILC_COMMAND_NONE,
                                      client_entry->resolve_cmd_ident,
                                      silc_client_notify_by_server_pending,
                                      res);
@@ -859,8 +911,10 @@ void silc_client_notify_by_server(SilcClient client,
        /* Do new resolving */
        silc_client_channel_set_wait(client, conn, channel,
                                     conn->cmd_ident + 1);
-       silc_client_notify_by_server_resolve(client, conn, packet, 
+       silc_client_notify_by_server_resolve(client, conn, packet,
                                             SILC_ID_CLIENT, client_id);
+        client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
+        client_entry->resolve_cmd_ident = conn->cmd_ident;
        goto out;
       }
     } else if (id_type == SILC_ID_SERVER) {
@@ -870,7 +924,7 @@ void silc_client_notify_by_server(SilcClient client,
       if (!server) {
        silc_client_channel_set_wait(client, conn, channel,
                                     conn->cmd_ident + 1);
-       silc_client_notify_by_server_resolve(client, conn, packet, 
+       silc_client_notify_by_server_resolve(client, conn, packet,
                                             SILC_ID_SERVER, server_id);
        server = silc_client_add_server(client, conn, NULL, NULL, server_id);
        if (!server)
@@ -887,7 +941,7 @@ void silc_client_notify_by_server(SilcClient client,
        res->packet = silc_packet_context_dup(packet);
        res->context = client;
        res->sock = silc_socket_dup(conn->sock);
-       silc_client_command_pending(conn, SILC_COMMAND_NONE, 
+       silc_client_command_pending(conn, SILC_COMMAND_NONE,
                                    server->resolve_cmd_ident,
                                    silc_client_notify_by_server_pending, res);
        goto out;
@@ -904,7 +958,7 @@ void silc_client_notify_by_server(SilcClient client,
       if (!client_entry) {
        silc_client_channel_set_wait(client, conn, channel,
                                     conn->cmd_ident + 1);
-       silc_client_notify_by_server_resolve(client, conn, packet, 
+       silc_client_notify_by_server_resolve(client, conn, packet,
                                             SILC_ID_CHANNEL, channel_id);
        goto out;
       }
@@ -934,10 +988,10 @@ void silc_client_notify_by_server(SilcClient client,
       goto out;
 
     /* Find target Client entry */
-    client_entry2 = 
+    client_entry2 =
       silc_client_get_client_by_id(client, conn, client_id);
     if (!client_entry2) {
-      silc_client_notify_by_server_resolve(client, conn, packet, 
+      silc_client_notify_by_server_resolve(client, conn, packet,
                                           SILC_ID_CLIENT, client_id);
       goto out;
     }
@@ -951,7 +1005,7 @@ void silc_client_notify_by_server(SilcClient client,
        is for channel but application don't know it from the arguments
        sent by server. */
     client->internal->ops->notify(client, conn, type,
-                                 id_type, client_entry, mode, 
+                                 id_type, client_entry, mode,
                                  client_entry2, channel);
     break;
 
@@ -966,7 +1020,7 @@ void silc_client_notify_by_server(SilcClient client,
     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
     if (!tmp)
       goto out;
-    
+
     /* Notify application */
     client->internal->ops->notify(client, conn, type, tmp);
     break;
@@ -1052,7 +1106,7 @@ void silc_client_notify_by_server(SilcClient client,
       /* Find kicker's client entry and if not found resolve it */
       client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
       if (!client_entry2) {
-       silc_client_notify_by_server_resolve(client, conn, packet, 
+       silc_client_notify_by_server_resolve(client, conn, packet,
                                             SILC_ID_CLIENT, client_id);
        goto out;
       } else {
@@ -1067,7 +1121,7 @@ void silc_client_notify_by_server(SilcClient client,
     /* Notify application. The channel entry is sent last as this notify
        is for channel but application don't know it from the arguments
        sent by server. */
-    client->internal->ops->notify(client, conn, type, client_entry, tmp, 
+    client->internal->ops->notify(client, conn, type, client_entry, tmp,
                                  client_entry2, channel);
 
     /* Remove kicked client from channel */
@@ -1137,10 +1191,10 @@ void silc_client_notify_by_server(SilcClient client,
        if (id_type == SILC_ID_CLIENT) {
          /* Find Client entry */
          client_id = id;
-         client_entry2 = silc_client_get_client_by_id(client, conn, 
+         client_entry2 = silc_client_get_client_by_id(client, conn,
                                                       client_id);
          if (!client_entry) {
-           silc_client_notify_by_server_resolve(client, conn, packet, 
+           silc_client_notify_by_server_resolve(client, conn, packet,
                                                 SILC_ID_CLIENT, client_id);
            goto out;
          }
@@ -1149,7 +1203,7 @@ void silc_client_notify_by_server(SilcClient client,
          server_id = id;
          server = silc_client_get_server_by_id(client, conn, server_id);
          if (!server) {
-           silc_client_notify_by_server_resolve(client, conn, packet, 
+           silc_client_notify_by_server_resolve(client, conn, packet,
                                                 SILC_ID_SERVER, server_id);
            server = silc_client_add_server(client, conn, NULL, NULL,
                                            server_id);
@@ -1166,13 +1220,13 @@ void silc_client_notify_by_server(SilcClient client,
            res->packet = silc_packet_context_dup(packet);
            res->context = client;
            res->sock = silc_socket_dup(conn->sock);
-           silc_client_command_pending(conn, SILC_COMMAND_NONE, 
+           silc_client_command_pending(conn, SILC_COMMAND_NONE,
                                        server->resolve_cmd_ident,
                                        silc_client_notify_by_server_pending,
                                        res);
            goto out;
          }
-      
+
          /* Save the pointer to the client_entry pointer */
          client_entry2 = (SilcClientEntry)server;
        } else {
@@ -1180,11 +1234,11 @@ void silc_client_notify_by_server(SilcClient client,
          channel_id = id;
          channel = silc_client_get_channel_by_id(client, conn, channel_id);
          if (!channel) {
-           silc_client_notify_by_server_resolve(client, conn, packet, 
+           silc_client_notify_by_server_resolve(client, conn, packet,
                                                 SILC_ID_CHANNEL, channel_id);
            goto out;
          }
-         
+
          /* Save the pointer to the client_entry pointer */
          client_entry2 = (SilcClientEntry)channel;
          silc_free(channel_id);
@@ -1193,7 +1247,7 @@ void silc_client_notify_by_server(SilcClient client,
       }
 
       /* Notify application. */
-      client->internal->ops->notify(client, conn, type, client_entry, 
+      client->internal->ops->notify(client, conn, type, client_entry,
                                    comment, id_type, client_entry2);
 
       if (client_entry != conn->local_entry)
@@ -1201,7 +1255,7 @@ void silc_client_notify_by_server(SilcClient client,
        silc_client_del_client(client, conn, client_entry);
     }
     break;
-    
+
   case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
     {
       /*
@@ -1221,11 +1275,11 @@ void silc_client_notify_by_server(SilcClient client,
          client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
          if (!client_id)
            goto out;
-         
+
          /* Get the client entry */
          client_entry = silc_client_get_client_by_id(client, conn, client_id);
          if (client_entry) {
-           clients = silc_realloc(clients, sizeof(*clients) * 
+           clients = silc_realloc(clients, sizeof(*clients) *
                                   (clients_count + 1));
            clients[clients_count] = client_entry;
            clients_count++;
@@ -1238,7 +1292,7 @@ void silc_client_notify_by_server(SilcClient client,
       /* Notify application. We don't keep server entries so the server
         entry is returned as NULL. The client's are returned as array
         of SilcClientEntry pointers. */
-      client->internal->ops->notify(client, conn, type, NULL, 
+      client->internal->ops->notify(client, conn, type, NULL,
                                    clients, clients_count);
 
       for (i = 0; i < clients_count; i++) {
@@ -1308,7 +1362,7 @@ void silc_client_notify_by_server(SilcClient client,
       /* Find Client entry and if not found query it */
       client_entry = silc_client_get_client_by_id(client, conn, client_id);
       if (!client_entry) {
-       silc_client_notify_by_server_resolve(client, conn, packet, 
+       silc_client_notify_by_server_resolve(client, conn, packet,
                                             SILC_ID_CLIENT, client_id);
        goto out;
       }
index 36d7bbe43a7eaffd76fe308eb7980b50da6a9867..d0b72c97ccda970a3aaa20306794a02b99c0afb5 100644 (file)
@@ -32,7 +32,7 @@
    message. The `data' is the private message. If the `force_send' is
    TRUE the packet is sent immediately. */
 
-void silc_client_send_private_message(SilcClient client,
+bool silc_client_send_private_message(SilcClient client,
                                      SilcClientConnection conn,
                                      SilcClientEntry client_entry,
                                      SilcMessageFlags flags,
@@ -47,6 +47,7 @@ void silc_client_send_private_message(SilcClient client,
   SilcCipher cipher;
   SilcHmac hmac;
   int block_len;
+  bool ret = FALSE;
 
   assert(client && conn && client_entry);
   sock = conn->sock;
@@ -60,6 +61,10 @@ void silc_client_send_private_message(SilcClient client,
                                       client_entry->hmac_send,
                                       client->rng, NULL, client->private_key,
                                       client->sha1hash);
+  if (!buffer) {
+    SILC_LOG_ERROR(("Error encoding private message"));
+    return FALSE;
+  }
 
   /* If we don't have private message specific key then private messages
      are just as any normal packet thus call normal packet sending.  If
@@ -126,8 +131,12 @@ void silc_client_send_private_message(SilcClient client,
 
   silc_free(packetdata.dst_id);
 
+  ret = TRUE;
+
  out:
   silc_buffer_free(buffer);
+
+  return ret;
 }     
 
 static void silc_client_private_message_cb(SilcClient client,
index 5f1cced0181e16ba2a961337738572356b06ea3b..3efe64ad2c2c6b59d6df4685ee27aa1bd7b91cac 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2002 Pekka Riikonen
+  Copyright (C) 2002, 2003 Pekka Riikonen
 
   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
@@ -99,7 +99,7 @@ SilcBuffer silc_client_get_detach_data(SilcClient client,
 /* Processes the detachment data. This creates channels and other
    stuff according the data found in the the connection parameters.
    This doesn't actually resolve any detailed information from the
-   server.  To do that call silc_client_resume_session function. 
+   server.  To do that call silc_client_resume_session function.
    This returns the old detached session client ID. */
 
 bool silc_client_process_detach_data(SilcClient client,
@@ -114,14 +114,14 @@ bool silc_client_process_detach_data(SilcClient client,
   SILC_LOG_DEBUG(("Start"));
 
   silc_free(conn->nickname);
-  silc_buffer_set(&detach, conn->internal->params.detach_data, 
+  silc_buffer_set(&detach, conn->internal->params.detach_data,
                  conn->internal->params.detach_data_len);
 
   SILC_LOG_HEXDUMP(("Detach data"), detach.data, detach.len);
 
   /* Take the old client ID from the detachment data */
   len = silc_buffer_unformat(&detach,
-                            SILC_STR_UI16_NSTRING_ALLOC(&conn->nickname, 
+                            SILC_STR_UI16_NSTRING_ALLOC(&conn->nickname,
                                                         NULL),
                             SILC_STR_UI16_NSTRING_ALLOC(old_id, old_id_len),
                             SILC_STR_UI_INT(NULL),
@@ -212,7 +212,7 @@ SILC_TASK_CALLBACK(silc_client_resume_call_completion)
   SILC_LOG_DEBUG(("Session completed"));
 
   for (i = 0; i < session->cmd_idents_count; i++)
-    silc_client_command_pending_del(session->conn, SILC_COMMAND_IDENTIFY, 
+    silc_client_command_pending_del(session->conn, SILC_COMMAND_IDENTIFY,
                                    session->cmd_idents[i]);
   silc_free(session->cmd_idents);
 
@@ -294,7 +294,7 @@ void silc_client_resume_session(SilcClient client,
       silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
                                   silc_client_command_reply_resume_special,
                                   0, ++conn->cmd_ident);
-      silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, 
+      silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
                                  conn->cmd_ident,
                                  silc_client_command_resume_identify,
                                  session);
@@ -302,7 +302,7 @@ void silc_client_resume_session(SilcClient client,
       tmp = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
                                        res_argc, res_argv, res_argv_lens,
                                        res_argv_types, conn->cmd_ident);
-      silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND, 
+      silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
                              NULL, 0, NULL, NULL, tmp->data, tmp->len, TRUE);
 
       session->cmd_idents = silc_realloc(session->cmd_idents,
@@ -402,7 +402,7 @@ SILC_CLIENT_CMD_FUNC(resume_identify)
     return;
 
   /* Unregister this command reply */
-  silc_client_command_unregister(client, SILC_COMMAND_IDENTIFY, NULL, 
+  silc_client_command_unregister(client, SILC_COMMAND_IDENTIFY, NULL,
                                 silc_client_command_reply_resume,
                                 cmd->ident);
   return;
@@ -429,7 +429,7 @@ SILC_CLIENT_CMD_FUNC(resume_cmode)
   SILC_LOG_DEBUG(("Start"));
 
   /* Unregister this command reply */
-  silc_client_command_unregister(client, SILC_COMMAND_CMODE, NULL, 
+  silc_client_command_unregister(client, SILC_COMMAND_CMODE, NULL,
                                 silc_client_command_reply_resume,
                                 cmd->ident);
 
@@ -492,7 +492,7 @@ SILC_CLIENT_CMD_FUNC(resume_users)
   SILC_LOG_DEBUG(("Start"));
 
   /* Unregister this command reply */
-  silc_client_command_unregister(client, SILC_COMMAND_USERS, NULL, 
+  silc_client_command_unregister(client, SILC_COMMAND_USERS, NULL,
                                 silc_client_command_reply_users_i,
                                 cmd->ident);
 
@@ -502,19 +502,19 @@ SILC_CLIENT_CMD_FUNC(resume_users)
   /* Get channel ID */
   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
   if (!tmp) {
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto err;
   }
   channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
   if (!channel_id) {
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto err;
   }
 
   /* Get the list count */
   tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
   if (!tmp) {
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto err;
   }
   SILC_GET32_MSB(list_count, tmp);
@@ -522,7 +522,7 @@ SILC_CLIENT_CMD_FUNC(resume_users)
   /* Get Client ID list */
   tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
   if (!tmp) {
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto err;
   }
   silc_buffer_set(&client_id_list, tmp, tmp_len);
@@ -530,7 +530,7 @@ SILC_CLIENT_CMD_FUNC(resume_users)
   /* Get client mode list */
   tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
   if (!tmp) {
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto err;
   }
   silc_buffer_set(&client_mode_list, tmp, tmp_len);
@@ -544,8 +544,8 @@ SILC_CLIENT_CMD_FUNC(resume_users)
   client->internal->ops->command_reply(client, conn, cmd->payload, TRUE,
                                       SILC_COMMAND_JOIN, cmd->status,
                                       channel->channel_name, channel,
-                                      channel->mode, 0, 
-                                      NULL, NULL, NULL, NULL, 
+                                      channel->mode, 0,
+                                      NULL, NULL, NULL, NULL,
                                       channel->hmac, list_count,
                                       &client_id_list, client_mode_list);
 
index 40e1d2566f0eb7c3dbbc510ee7d56e026a5e1e00..557a539c9c8186daa7d4e62a3c345c43372dd95f 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  command.c 
+  command.c
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2002 Pekka Riikonen
+  Copyright (C) 1997 - 2003 Pekka Riikonen
 
   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
@@ -26,7 +26,7 @@
   x->internal->ops->say((x), (c), SILC_CLIENT_MESSAGE_ERROR, \
           "You are not connected to a server, use /SERVER to connect");
 
-/* Command operation that is called at the end of all commands. 
+/* Command operation that is called at the end of all commands.
    Usage: COMMAND(status); */
 #define COMMAND(status) cmd->client->internal->ops->command(cmd->client, \
   cmd->conn, cmd, TRUE, cmd->command->cmd, (status))
@@ -53,8 +53,8 @@ void silc_client_command_send(SilcClient client, SilcClientConnection conn,
   va_start(ap, argc);
 
   packet = silc_command_payload_encode_vap(command, ident, argc, ap);
-  silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND, 
-                         NULL, 0, NULL, NULL, packet->data, 
+  silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
+                         NULL, 0, NULL, NULL, packet->data,
                          packet->len, TRUE);
   silc_buffer_free(packet);
 }
@@ -147,7 +147,7 @@ bool silc_client_command_call(SilcClient client,
   ctx->argv = argv;
   ctx->argv_lens = argv_lens;
   ctx->argv_types = argv_types;
-  
+
   /* Call the command */
   cmd->command(ctx, NULL);
 
@@ -211,7 +211,7 @@ void silc_client_command_pending_del(SilcClientConnection conn,
 SilcClientCommandPendingCallbacks
 silc_client_command_pending_check(SilcClientConnection conn,
                                  SilcClientCommandReplyContext ctx,
-                                 SilcCommand command, 
+                                 SilcCommand command,
                                  SilcUInt16 ident,
                                  SilcUInt32 *callbacks_count)
 {
@@ -276,7 +276,7 @@ SilcClientCommandContext silc_client_command_dup(SilcClientCommandContext ctx)
   return ctx;
 }
 
-/* Command WHOIS. This command is used to query information about 
+/* Command WHOIS. This command is used to query information about
    specific user. */
 
 SILC_CLIENT_CMD_FUNC(whois)
@@ -295,7 +295,7 @@ SILC_CLIENT_CMD_FUNC(whois)
   /* Given without arguments fetches client's own information */
   if (cmd->argc < 2) {
     buffer = silc_id_payload_encode(cmd->conn->local_id, SILC_ID_CLIENT);
-    silc_client_command_send(cmd->client, cmd->conn, SILC_COMMAND_WHOIS, 
+    silc_client_command_send(cmd->client, cmd->conn, SILC_COMMAND_WHOIS,
                             ++conn->cmd_ident,
                             1, 4, buffer->data, buffer->len);
     silc_buffer_free(buffer);
@@ -305,7 +305,7 @@ SILC_CLIENT_CMD_FUNC(whois)
   if (cmd->argc == 2) {
     buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
                                            ++conn->cmd_ident, 1,
-                                           1, cmd->argv[1], 
+                                           1, cmd->argv[1],
                                            cmd->argv_lens[1]);
   } else {
     if (!strcasecmp(cmd->argv[2], "-details"))
@@ -353,7 +353,7 @@ SILC_CLIENT_CMD_FUNC(whowas)
   }
 
   if (cmd->argc < 2 || cmd->argc > 3) {
-    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "Usage: /WHOWAS <nickname>[@<server>] [<count>]");
     COMMAND_ERROR((cmd->argc < 2 ? SILC_STATUS_ERR_NOT_ENOUGH_PARAMS :
                   SILC_STATUS_ERR_TOO_MANY_PARAMS));
@@ -363,7 +363,7 @@ SILC_CLIENT_CMD_FUNC(whowas)
   if (cmd->argc == 2) {
     buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOWAS,
                                            ++conn->cmd_ident, 1,
-                                           1, cmd->argv[1], 
+                                           1, cmd->argv[1],
                                            cmd->argv_lens[1]);
   } else {
     int c = atoi(cmd->argv[2]);
@@ -386,8 +386,8 @@ SILC_CLIENT_CMD_FUNC(whowas)
   silc_client_command_free(cmd);
 }
 
-/* Command IDENTIFY. This command is used to query information about 
-   specific user, especially ID's. 
+/* Command IDENTIFY. This command is used to query information about
+   specific user, especially ID's.
 
    NOTE: This command is used only internally by the client library
    and application MUST NOT call this command directly. */
@@ -409,7 +409,7 @@ SILC_CLIENT_CMD_FUNC(identify)
     goto out;
 
   if (cmd->argc == 2) {
-    buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY, 
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
                                            ++conn->cmd_ident, 1,
                                            1, cmd->argv[1],
                                            cmd->argv_lens[1]);
@@ -417,7 +417,7 @@ SILC_CLIENT_CMD_FUNC(identify)
     int c = atoi(cmd->argv[2]);
     memset(count, 0, sizeof(count));
     SILC_PUT32_MSB(c, count);
-    buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY, 
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
                                            ++conn->cmd_ident, 2,
                                            1, cmd->argv[1],
                                            cmd->argv_lens[1],
@@ -449,7 +449,7 @@ SILC_CLIENT_CMD_FUNC(nick)
   }
 
   if (cmd->argc < 2) {
-    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "Usage: /NICK <nickname>");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
@@ -461,11 +461,11 @@ SILC_CLIENT_CMD_FUNC(nick)
   /* Show current nickname */
   if (cmd->argc < 2) {
     if (cmd->conn) {
-      SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
-         "Your nickname is %s on server %s", 
+      SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+         "Your nickname is %s on server %s",
          conn->nickname, conn->remote_host);
     } else {
-      SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+      SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
          "Your nickname is %s", conn->nickname);
     }
 
@@ -479,7 +479,7 @@ SILC_CLIENT_CMD_FUNC(nick)
   /* Send the NICK command */
   buffer = silc_command_payload_encode(SILC_COMMAND_NICK, 1,
                                       &cmd->argv[1],
-                                      &cmd->argv_lens[1], 
+                                      &cmd->argv_lens[1],
                                       &cmd->argv_types[1],
                                       ++cmd->conn->cmd_ident);
   silc_client_packet_send(cmd->client, cmd->conn->sock,
@@ -520,10 +520,10 @@ SILC_CLIENT_CMD_FUNC(list)
   }
 
   if (!idp)
-    buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST, 
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
                                            ++conn->cmd_ident, 0);
   else
-    buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST, 
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
                                            ++conn->cmd_ident, 1,
                                            1, idp->data, idp->len);
 
@@ -593,16 +593,16 @@ SILC_CLIENT_CMD_FUNC(topic)
   /* Send TOPIC command to the server */
   idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
   if (cmd->argc > 2)
-    buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC, 
-                                           ++conn->cmd_ident, 2, 
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
+                                           ++conn->cmd_ident, 2,
                                            1, idp->data, idp->len,
-                                           2, cmd->argv[2], 
+                                           2, cmd->argv[2],
                                            strlen(cmd->argv[2]));
   else
-    buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC, 
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC,
                                            ++conn->cmd_ident, 1,
                                            1, idp->data, idp->len);
-  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
   silc_buffer_free(idp);
@@ -670,19 +670,19 @@ SILC_CLIENT_CMD_FUNC(invite)
        nickname = strdup(cmd->argv[2]);
 
       /* Find client entry */
-      client_entry = silc_idlist_get_client(client, conn, nickname, 
+      client_entry = silc_idlist_get_client(client, conn, nickname,
                                            cmd->argv[2], TRUE);
       if (!client_entry) {
        if (cmd->pending) {
          COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
          goto out;
        }
-      
+
        /* Client entry not found, it was requested thus mark this to be
           pending command. */
-       silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, 
+       silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
                                    conn->cmd_ident,
-                                   silc_client_command_invite, 
+                                   silc_client_command_invite,
                                    silc_client_command_dup(cmd));
        cmd->pending = 1;
        goto out;
@@ -724,7 +724,7 @@ SILC_CLIENT_CMD_FUNC(invite)
   chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
   if (client_entry) {
     clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
-    buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE, 
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
                                            ++conn->cmd_ident, 4,
                                            1, chidp->data, chidp->len,
                                            2, clidp->data, clidp->len,
@@ -734,7 +734,7 @@ SILC_CLIENT_CMD_FUNC(invite)
                                            args ? args->len : 0);
     silc_buffer_free(clidp);
   } else {
-    buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE, 
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
                                            ++conn->cmd_ident, 3,
                                            1, chidp->data, chidp->len,
                                            3, args ? action : NULL,
@@ -743,7 +743,7 @@ SILC_CLIENT_CMD_FUNC(invite)
                                            args ? args->len : 0);
   }
 
-  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
   silc_buffer_free(chidp);
@@ -774,7 +774,7 @@ SILC_TASK_CALLBACK(silc_client_command_quit_cb)
 }
 
 /* Command QUIT. Closes connection with current server. */
+
 SILC_CLIENT_CMD_FUNC(quit)
 {
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
@@ -788,14 +788,14 @@ SILC_CLIENT_CMD_FUNC(quit)
   }
 
   if (cmd->argc > 1)
-    buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1, 
+    buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
                                         &cmd->argv[1], &cmd->argv_lens[1],
                                         &cmd->argv_types[1], 0);
   else
     buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
                                         NULL, NULL, NULL, 0);
-  silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND, 
-                         NULL, 0, NULL, NULL, 
+  silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
+                         NULL, 0, NULL, NULL,
                          buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
 
@@ -827,7 +827,7 @@ SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
   SilcClientConnection conn = cmd->conn;
   SilcClientEntry target;
   char *nickname = NULL;
-  
+
   /* Parse the typed nickname. */
   if (client->internal->params->nickname_parse)
     client->internal->params->nickname_parse(cmd->argv[1], &nickname);
@@ -835,7 +835,7 @@ SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
     nickname = strdup(cmd->argv[1]);
 
   /* Get the target client */
-  target = silc_idlist_get_client(cmd->client, conn, nickname, 
+  target = silc_idlist_get_client(cmd->client, conn, nickname,
                                  cmd->argv[1], FALSE);
   if (target)
     /* Remove the client from all channels and free it */
@@ -851,7 +851,7 @@ SILC_TASK_CALLBACK(silc_client_command_kill_remove_later)
 SILC_CLIENT_CMD_FUNC(kill_remove)
 {
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
-  SilcClientCommandReplyContext reply = 
+  SilcClientCommandReplyContext reply =
     (SilcClientCommandReplyContext)context2;
   SilcStatus status;
 
@@ -886,7 +886,7 @@ SILC_CLIENT_CMD_FUNC(kill)
   }
 
   if (cmd->argc < 2) {
-    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "Usage: /KILL <nickname> [<comment>] [-pubkey]");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
@@ -899,7 +899,7 @@ SILC_CLIENT_CMD_FUNC(kill)
     nickname = strdup(cmd->argv[1]);
 
   /* Get the target client */
-  target = silc_idlist_get_client(cmd->client, conn, nickname, 
+  target = silc_idlist_get_client(cmd->client, conn, nickname,
                                  cmd->argv[1], TRUE);
   if (!target) {
     if (cmd->pending) {
@@ -909,9 +909,9 @@ SILC_CLIENT_CMD_FUNC(kill)
 
     /* Client entry not found, it was requested thus mark this to be
        pending command. */
-    silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, 
-                               conn->cmd_ident,  
-                               silc_client_command_kill, 
+    silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
+                               conn->cmd_ident,
+                               silc_client_command_kill,
                                silc_client_command_dup(cmd));
     cmd->pending = 1;
     goto out;
@@ -935,8 +935,8 @@ SILC_CLIENT_CMD_FUNC(kill)
   /* Send the KILL command to the server */
   idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
   buffer =
-    silc_command_payload_encode_va(SILC_COMMAND_KILL, 
-                                  ++conn->cmd_ident, 3, 
+    silc_command_payload_encode_va(SILC_COMMAND_KILL,
+                                  ++conn->cmd_ident, 3,
                                   1, idp->data, idp->len,
                                   2, comment, comment ? strlen(comment) : 0,
                                   3, auth ? auth->data : NULL,
@@ -982,12 +982,12 @@ SILC_CLIENT_CMD_FUNC(info)
 
   /* Send the command */
   if (name)
-    buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1, 
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1,
                                            1, name, strlen(name));
   else
     buffer = silc_command_payload_encode(SILC_COMMAND_INFO, 0,
                                         NULL, NULL, NULL, 0);
-  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
   if (name)
@@ -1014,13 +1014,13 @@ SILC_CLIENT_CMD_FUNC(stats)
     goto out;
   }
 
-  idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER); 
-  
+  idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
+
   /* Send the command */
   buffer = silc_command_payload_encode_va(SILC_COMMAND_STATS,
                                          ++conn->cmd_ident, 1,
                                          SILC_ID_SERVER, idp->data, idp->len);
-  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
   silc_buffer_free(idp);
@@ -1032,7 +1032,7 @@ SILC_CLIENT_CMD_FUNC(stats)
   silc_client_command_free(cmd);
 }
 
-/* Command PING. Sends ping to server. This is used to test the 
+/* Command PING. Sends ping to server. This is used to test the
    communication channel. */
 
 SILC_CLIENT_CMD_FUNC(ping)
@@ -1049,12 +1049,12 @@ SILC_CLIENT_CMD_FUNC(ping)
     goto out;
   }
 
-  idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER); 
+  idp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
 
   /* Send the command */
-  buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1, 
+  buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
                                          1, idp->data, idp->len);
-  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
   silc_buffer_free(idp);
@@ -1086,7 +1086,7 @@ SILC_CLIENT_CMD_FUNC(ping)
     conn->internal->ping[i].dest_name = strdup(conn->remote_host);
     conn->internal->ping_count++;
   }
-  
+
   /* Notify application */
   COMMAND(SILC_STATUS_OK);
 
@@ -1101,7 +1101,7 @@ SILC_CLIENT_CMD_FUNC(join)
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
   SilcClientConnection conn = cmd->conn;
   SilcChannelEntry channel;
-  SilcBuffer buffer, idp, auth = NULL;
+  SilcBuffer buffer, idp, auth = NULL, cauth = NULL;
   char *name, *passphrase = NULL, *pu8, *cipher = NULL, *hmac = NULL;
   int i, passphrase_len = 0;
 
@@ -1115,7 +1115,7 @@ SILC_CLIENT_CMD_FUNC(join)
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
-  
+
   /* See if we have joined to the requested channel already */
   channel = silc_client_get_channel(cmd->client, conn, cmd->argv[1]);
   if (channel && silc_client_on_channel(channel, conn->local_entry))
@@ -1138,15 +1138,50 @@ SILC_CLIENT_CMD_FUNC(join)
     } else if (!strcasecmp(cmd->argv[i], "-founder")) {
       auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
                                                cmd->client->private_key,
-                                               cmd->client->rng, 
+                                               cmd->client->rng,
                                                cmd->client->sha1hash,
                                                conn->local_id,
                                                SILC_ID_CLIENT);
       i++;
+    } else if (!strcasecmp(cmd->argv[i], "-auth")) {
+      SilcPublicKey pubkey = cmd->client->public_key;
+      SilcPrivateKey privkey = cmd->client->private_key;
+      unsigned char *pk, pkhash[20], *pubdata;
+      SilcUInt32 pk_len;
+
+      if (cmd->argc >= i + 3) {
+       char *pass = "";
+       if (cmd->argc >= i + 4) {
+         pass = cmd->argv[i + 3];
+         i++;
+       }
+       if (!silc_load_key_pair(cmd->argv[i + 1], cmd->argv[i + 2], pass,
+                               NULL, &pubkey, &privkey)) {
+         SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+             "Could not load key pair, check your arguments");
+         COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+         goto out;
+       }
+       i += 2;
+      }
+
+      pk = silc_pkcs_public_key_encode(pubkey, &pk_len);
+      silc_hash_make(cmd->client->sha1hash, pk, pk_len, pkhash);
+      silc_free(pk);
+      pubdata = silc_rng_get_rn_data(cmd->client->rng, 128);
+      memcpy(pubdata, pkhash, 20);
+      cauth = silc_auth_public_key_auth_generate_wpub(pubkey, privkey,
+                                                     pubdata, 128,
+                                                     cmd->client->sha1hash,
+                                                     conn->local_id,
+                                                     SILC_ID_CLIENT);
+      memset(pubdata, 0, 128);
+      silc_free(pubdata);
+      i++;
     } else {
       /* Passphrases must be UTF-8 encoded, so encode if it is not */
       if (!silc_utf8_valid(cmd->argv[i], cmd->argv_lens[i])) {
-       passphrase_len = silc_utf8_encoded_len(cmd->argv[i], 
+       passphrase_len = silc_utf8_encoded_len(cmd->argv[i],
                                               cmd->argv_lens[i], 0);
        pu8 = silc_calloc(passphrase_len, sizeof(*pu8));
        passphrase_len = silc_utf8_encode(cmd->argv[i], cmd->argv_lens[i],
@@ -1161,20 +1196,22 @@ SILC_CLIENT_CMD_FUNC(join)
 
   /* Send JOIN command to the server */
   buffer =
-    silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 6,
+    silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 7,
                                   1, name, strlen(name),
                                   2, idp->data, idp->len,
                                   3, passphrase, passphrase_len,
                                   4, cipher, cipher ? strlen(cipher) : 0,
                                   5, hmac, hmac ? strlen(hmac) : 0,
                                   6, auth ? auth->data : NULL,
-                                  auth ? auth->len : 0);
-  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+                                  auth ? auth->len : 0,
+                                  7, cauth ? cauth->data : NULL,
+                                  cauth ? cauth->len : 0);
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
   silc_buffer_free(idp);
-  if (auth)
-    silc_buffer_free(auth);
+  silc_buffer_free(auth);
+  silc_buffer_free(cauth);
   if (passphrase)
     memset(passphrase, 0, strlen(passphrase));
   silc_free(passphrase);
@@ -1210,14 +1247,14 @@ SILC_CLIENT_CMD_FUNC(motd)
 
   /* Send TOPIC command to the server */
   if (cmd->argc == 1)
-    buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1, 
-                                           1, conn->remote_host, 
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
+                                           1, conn->remote_host,
                                            strlen(conn->remote_host));
   else
-    buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1, 
-                                           1, cmd->argv[1], 
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
+                                           1, cmd->argv[1],
                                            cmd->argv_lens[1]);
-  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
 
@@ -1247,7 +1284,7 @@ SILC_CLIENT_CMD_FUNC(umode)
   }
 
   if (cmd->argc < 2) {
-    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "Usage: /UMODE +|-<modes>");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
@@ -1361,11 +1398,11 @@ SILC_CLIENT_CMD_FUNC(umode)
 
   /* Send the command packet. We support sending only one mode at once
      that requires an argument. */
-  buffer = 
-    silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2, 
-                                  1, idp->data, idp->len, 
+  buffer =
+    silc_command_payload_encode_va(SILC_COMMAND_UMODE, ++conn->cmd_ident, 2,
+                                  1, idp->data, idp->len,
                                   2, modebuf, sizeof(modebuf));
-  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
   silc_buffer_free(idp);
@@ -1398,7 +1435,7 @@ SILC_CLIENT_CMD_FUNC(cmode)
   }
 
   if (cmd->argc < 3) {
-    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
@@ -1485,7 +1522,7 @@ SILC_CLIENT_CMD_FUNC(cmode)
        mode |= SILC_CHANNEL_MODE_ULIMIT;
        type = 3;
        if (cmd->argc < 4) {
-         SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+         SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
              "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
          COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
          goto out;
@@ -1503,7 +1540,7 @@ SILC_CLIENT_CMD_FUNC(cmode)
        mode |= SILC_CHANNEL_MODE_PASSPHRASE;
        type = 4;
        if (cmd->argc < 4) {
-         SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+         SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
              "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
          COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
          goto out;
@@ -1519,7 +1556,7 @@ SILC_CLIENT_CMD_FUNC(cmode)
        mode |= SILC_CHANNEL_MODE_CIPHER;
        type = 5;
        if (cmd->argc < 4) {
-         SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+         SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
              "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
          COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
          goto out;
@@ -1535,7 +1572,7 @@ SILC_CLIENT_CMD_FUNC(cmode)
        mode |= SILC_CHANNEL_MODE_HMAC;
        type = 6;
        if (cmd->argc < 4) {
-         SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+         SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
              "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
          COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
          goto out;
@@ -1569,7 +1606,7 @@ SILC_CLIENT_CMD_FUNC(cmode)
 
        pk = silc_pkcs_public_key_payload_encode(pubkey);
        auth = silc_auth_public_key_auth_generate(pubkey, privkey,
-                                                 cmd->client->rng, 
+                                                 cmd->client->rng,
                                                  cmd->client->sha1hash,
                                                  conn->local_id,
                                                  SILC_ID_CLIENT);
@@ -1579,6 +1616,65 @@ SILC_CLIENT_CMD_FUNC(cmode)
        mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
       }
       break;
+    case 'C':
+      if (add) {
+       int k;
+       bool chadd = FALSE;
+       SilcPublicKey chpk = NULL;
+
+       mode |= SILC_CHANNEL_MODE_CHANNEL_AUTH;
+       type = 9;
+
+       if (cmd->argc == 3) {
+         /* Send empty command to receive the public key list. */
+         chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+         silc_client_command_send(cmd->client, conn, SILC_COMMAND_CMODE,
+                                  0, 1, 1, chidp->data, chidp->len);
+         silc_buffer_free(chidp);
+
+         /* Notify application */
+         COMMAND(SILC_STATUS_OK);
+         goto out;
+       }
+
+       if (cmd->argc >= 4) {
+         auth = silc_buffer_alloc_size(2);
+         silc_buffer_format(auth,
+                            SILC_STR_UI_SHORT(cmd->argc - 3),
+                            SILC_STR_END);
+       }
+
+       for (k = 3; k < cmd->argc; k++) {
+         if (cmd->argv[k][0] == '+')
+           chadd = TRUE;
+         if (!silc_pkcs_load_public_key(cmd->argv[k] + 1, &chpk,
+                                        SILC_PKCS_FILE_PEM))
+           if (!silc_pkcs_load_public_key(cmd->argv[k] + 1, &chpk,
+                                          SILC_PKCS_FILE_BIN)) {
+             SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+                 "Could not load public key %s, check the filename",
+                 cmd->argv[k]);
+             COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+             silc_buffer_free(auth);
+             goto out;
+           }
+
+         if (chpk) {
+           pk = silc_pkcs_public_key_payload_encode(chpk);
+           auth = silc_argument_payload_encode_one(auth, pk->data, pk->len,
+                                                   chadd ? 0x00 : 0x01);
+           silc_pkcs_public_key_free(chpk);
+           silc_buffer_free(pk);
+           pk = NULL;
+         }
+       }
+
+       arg = auth->data;
+       arg_len = auth->len;
+      } else {
+       mode &= ~SILC_CHANNEL_MODE_CHANNEL_AUTH;
+      }
+      break;
     default:
       COMMAND_ERROR(SILC_STATUS_ERR_UNKNOWN_MODE);
       goto out;
@@ -1592,21 +1688,21 @@ SILC_CLIENT_CMD_FUNC(cmode)
   /* Send the command packet. We support sending only one mode at once
      that requires an argument. */
   if (type && arg) {
-    buffer = 
+    buffer =
       silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 4,
-                                    1, chidp->data, chidp->len, 
+                                    1, chidp->data, chidp->len,
                                     2, modebuf, sizeof(modebuf),
                                     type, arg, arg_len,
                                     8, pk ? pk->data : NULL,
                                     pk ? pk->len : 0);
   } else {
-    buffer = 
+    buffer =
       silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
-                                    1, chidp->data, chidp->len, 
+                                    1, chidp->data, chidp->len,
                                     2, modebuf, sizeof(modebuf));
   }
 
-  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
   silc_buffer_free(chidp);
@@ -1643,7 +1739,7 @@ SILC_CLIENT_CMD_FUNC(cumode)
   }
 
   if (cmd->argc < 4) {
-    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
@@ -1683,14 +1779,14 @@ SILC_CLIENT_CMD_FUNC(cumode)
 
     /* Client entry not found, it was requested thus mark this to be
        pending command. */
-    silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, 
-                               conn->cmd_ident,  
-                               silc_client_command_cumode, 
+    silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
+                               conn->cmd_ident,
+                               silc_client_command_cumode,
                                silc_client_command_dup(cmd));
     cmd->pending = 1;
     goto out;
   }
-  
+
   /* Get the current mode */
   chu = silc_client_on_channel(channel, client_entry);
   if (chu)
@@ -1789,22 +1885,22 @@ SILC_CLIENT_CMD_FUNC(cumode)
 
   /* Send the command packet. We support sending only one mode at once
      that requires an argument. */
-  buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 
-                                         auth ? 4 : 3, 
-                                         1, chidp->data, chidp->len, 
+  buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0,
+                                         auth ? 4 : 3,
+                                         1, chidp->data, chidp->len,
                                          2, modebuf, 4,
                                          3, clidp->data, clidp->len,
-                                         4, auth ? auth->data : NULL, 
+                                         4, auth ? auth->data : NULL,
                                          auth ? auth->len : 0);
-  
-  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
   silc_buffer_free(chidp);
   silc_buffer_free(clidp);
   if (auth)
     silc_buffer_free(auth);
-  
+
   /* Notify application */
   COMMAND(SILC_STATUS_OK);
 
@@ -1834,7 +1930,7 @@ SILC_CLIENT_CMD_FUNC(kick)
   }
 
   if (cmd->argc < 3) {
-    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "Usage: /KICK <channel> <nickname> [<comment>]");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
@@ -1871,10 +1967,10 @@ SILC_CLIENT_CMD_FUNC(kick)
     nickname = strdup(cmd->argv[2]);
 
   /* Get the target client */
-  target = silc_idlist_get_client(cmd->client, conn, nickname, 
+  target = silc_idlist_get_client(cmd->client, conn, nickname,
                                  cmd->argv[2], FALSE);
   if (!target) {
-    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "No such client: %s", cmd->argv[2]);
     COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
     goto out;
@@ -1884,14 +1980,14 @@ SILC_CLIENT_CMD_FUNC(kick)
   idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
   idp2 = silc_id_payload_encode(target->id, SILC_ID_CLIENT);
   if (cmd->argc == 3)
-    buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2, 
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 2,
                                            1, idp->data, idp->len,
                                            2, idp2->data, idp2->len);
   else
-    buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3, 
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_KICK, 0, 3,
                                            1, idp->data, idp->len,
                                            2, idp2->data, idp2->len,
-                                           3, cmd->argv[3], 
+                                           3, cmd->argv[3],
                                            strlen(cmd->argv[3]));
   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
@@ -1928,8 +2024,8 @@ static void silc_client_command_oper_send(unsigned char *data,
                                    data, data_len);
   }
 
-  buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2, 
-                                         1, cmd->argv[1], 
+  buffer = silc_command_payload_encode_va(SILC_COMMAND_OPER, 0, 2,
+                                         1, cmd->argv[1],
                                          strlen(cmd->argv[1]),
                                          2, auth ? auth->data : NULL,
                                          auth ? auth->len : 0);
@@ -1958,7 +2054,7 @@ SILC_CLIENT_CMD_FUNC(oper)
   }
 
   if (cmd->argc < 2) {
-    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "Usage: /OPER <username> [-pubkey]");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
@@ -1979,7 +2075,7 @@ SILC_CLIENT_CMD_FUNC(oper)
 }
 
 static void silc_client_command_silcoper_send(unsigned char *data,
-                                             SilcUInt32 data_len, 
+                                             SilcUInt32 data_len,
                                              void *context)
 {
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
@@ -2000,8 +2096,8 @@ static void silc_client_command_silcoper_send(unsigned char *data,
                                    data, data_len);
   }
 
-  buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2, 
-                                         1, cmd->argv[1], 
+  buffer = silc_command_payload_encode_va(SILC_COMMAND_SILCOPER, 0, 2,
+                                         1, cmd->argv[1],
                                          strlen(cmd->argv[1]),
                                          2, auth ? auth->data : NULL,
                                          auth ? auth->len : 0);
@@ -2030,7 +2126,7 @@ SILC_CLIENT_CMD_FUNC(silcoper)
   }
 
   if (cmd->argc < 2) {
-    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "Usage: /SILCOPER <username> [-pubkey]");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
@@ -2061,7 +2157,7 @@ SILC_CLIENT_CMD_FUNC(ban)
   char *name, *ban = NULL;
   unsigned char action[1];
   SilcPublicKey pubkey = NULL;
-  
+
   if (!cmd->conn) {
     SILC_NOT_CONNECTED(cmd->client, cmd->conn);
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_REGISTERED);
@@ -2069,7 +2165,7 @@ SILC_CLIENT_CMD_FUNC(ban)
   }
 
   if (cmd->argc < 2) {
-    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "Usage: /BAN <channel> "
        "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
@@ -2128,14 +2224,14 @@ SILC_CLIENT_CMD_FUNC(ban)
   chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
 
   /* Send the command */
-  buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN, 
+  buffer = silc_command_payload_encode_va(SILC_COMMAND_BAN,
                                          ++conn->cmd_ident, 3,
                                          1, chidp->data, chidp->len,
                                          2, args ? action : NULL,
                                          args ? 1 : 0,
                                          3, args ? args->data : NULL,
                                          args ? args->len : 0);
-  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
   silc_buffer_free(chidp);
@@ -2164,7 +2260,7 @@ SILC_CLIENT_CMD_FUNC(detach)
 
   buffer = silc_command_payload_encode_va(SILC_COMMAND_DETACH,
                                          ++conn->cmd_ident, 0);
-  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
 
@@ -2206,12 +2302,12 @@ SILC_CLIENT_CMD_FUNC(watch)
     goto out;
   }
 
-  buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH, 
+  buffer = silc_command_payload_encode_va(SILC_COMMAND_WATCH,
                                          ++conn->cmd_ident, 2,
                                          1, idp->data, idp->len,
                                          type, cmd->argv[2],
                                          cmd->argv_lens[2]);
-  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
 
@@ -2231,7 +2327,6 @@ SILC_CLIENT_CMD_FUNC(leave)
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
   SilcClientConnection conn = cmd->conn;
   SilcChannelEntry channel;
-  SilcChannelUser chu;
   SilcBuffer buffer, idp;
   char *name;
 
@@ -2242,7 +2337,7 @@ SILC_CLIENT_CMD_FUNC(leave)
   }
 
   if (cmd->argc != 2) {
-    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "Usage: /LEAVE <channel>");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
@@ -2265,19 +2360,11 @@ SILC_CLIENT_CMD_FUNC(leave)
     goto out;
   }
 
-  /* Remove us from channel */
-  chu = silc_client_on_channel(channel, conn->local_entry);
-  if (chu) {
-    silc_hash_table_del(chu->client->channels, chu->channel);
-    silc_hash_table_del(chu->channel->user_list, chu->client);
-    silc_free(chu);
-  }
-
   /* Send LEAVE command to the server */
   idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
-  buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1, 
+  buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
                                          1, idp->data, idp->len);
-  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
   silc_buffer_free(idp);
@@ -2288,8 +2375,6 @@ SILC_CLIENT_CMD_FUNC(leave)
   if (conn->current_channel == channel)
     conn->current_channel = NULL;
 
-  silc_client_del_channel(cmd->client, cmd->conn, channel);
-
  out:
   silc_client_command_free(cmd);
 }
@@ -2311,7 +2396,7 @@ SILC_CLIENT_CMD_FUNC(users)
   }
 
   if (cmd->argc != 2) {
-    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "Usage: /USERS <channel>");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
@@ -2328,11 +2413,11 @@ SILC_CLIENT_CMD_FUNC(users)
   }
 
   /* Send USERS command to the server */
-  buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS, 
-                                         ++conn->cmd_ident, 1, 
+  buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS,
+                                         ++conn->cmd_ident, 1,
                                          2, name, strlen(name));
-  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, 
-                         NULL, 0, NULL, NULL, buffer->data, 
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
+                         NULL, 0, NULL, NULL, buffer->data,
                          buffer->len, TRUE);
   silc_buffer_free(buffer);
 
@@ -2364,7 +2449,7 @@ SILC_CLIENT_CMD_FUNC(getkey)
   }
 
   if (cmd->argc < 2) {
-    client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO, 
+    client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_INFO,
                     "Usage: /GETKEY <nickname or server name>");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
@@ -2391,14 +2476,14 @@ SILC_CLIENT_CMD_FUNC(getkey)
       if (!cmd->pending) {
        /* This will send the IDENTIFY command for nickname */
        silc_idlist_get_client(client, conn, nickname, cmd->argv[1], TRUE);
-       silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, 
-                                   conn->cmd_ident,  
-                                   silc_client_command_getkey, 
+       silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
+                                   conn->cmd_ident,
+                                   silc_client_command_getkey,
                                    silc_client_command_dup(cmd));
        cmd->pending = 1;
        goto out;
       } else {
-       SilcClientCommandReplyContext reply = 
+       SilcClientCommandReplyContext reply =
          (SilcClientCommandReplyContext)context2;
        SilcStatus error;
 
@@ -2406,16 +2491,16 @@ SILC_CLIENT_CMD_FUNC(getkey)
        silc_command_get_status(reply->payload, NULL, &error);
        if (error == SILC_STATUS_ERR_NO_SUCH_NICK) {
          /* This sends the IDENTIFY command to resolve the server. */
-         silc_client_command_register(client, SILC_COMMAND_IDENTIFY, 
+         silc_client_command_register(client, SILC_COMMAND_IDENTIFY,
                                       NULL, NULL,
                                       silc_client_command_reply_identify_i, 0,
                                       ++conn->cmd_ident);
          silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
-                                  conn->cmd_ident, 1, 
+                                  conn->cmd_ident, 1,
                                   2, cmd->argv[1], cmd->argv_lens[1]);
-         silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, 
-                                     conn->cmd_ident, 
-                                     silc_client_command_getkey, 
+         silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
+                                     conn->cmd_ident,
+                                     silc_client_command_getkey,
                                      silc_client_command_dup(cmd));
          goto out;
        }
@@ -2423,9 +2508,9 @@ SILC_CLIENT_CMD_FUNC(getkey)
        /* If server was not found, then we've resolved both nickname and
           server and did not find anybody. */
        if (error == SILC_STATUS_ERR_NO_SUCH_SERVER) {
-         SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s", 
+         SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
             silc_get_status_message(SILC_STATUS_ERR_NO_SUCH_NICK));
-         SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s", 
+         SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
            silc_get_status_message(error));
          COMMAND_ERROR(SILC_STATUS_ERR_NO_SUCH_NICK);
          goto out;
@@ -2441,9 +2526,9 @@ SILC_CLIENT_CMD_FUNC(getkey)
     idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
   }
 
-  buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1, 
+  buffer = silc_command_payload_encode_va(SILC_COMMAND_GETKEY, 0, 1,
                                          1, idp->data, idp->len);
-  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
   silc_buffer_free(buffer);
   silc_buffer_free(idp);
@@ -2461,11 +2546,11 @@ SILC_CLIENT_CMD_FUNC(getkey)
    searched using the silc_client_command_find by that name.  The
    `command_function' is the function to be called when the command is
    executed, and the `command_reply_function' is the function to be
-   called after the server has sent reply back to the command. 
+   called after the server has sent reply back to the command.
 
    The `ident' is optional identifier for the command.  If non-zero
    the `command_reply_function' for the command type `command' will be
-   called only if the command reply sent by server includes the 
+   called only if the command reply sent by server includes the
    command identifier `ident'. Application usually does not need it
    and set it to zero value. */
 
@@ -2538,7 +2623,7 @@ SILC_CLIENT_CMD_FUNC(connect)
   }
 
   if (cmd->argc < 2) {
-    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "Usage: /CONNECT <server> [<port>]");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
@@ -2550,13 +2635,13 @@ SILC_CLIENT_CMD_FUNC(connect)
   }
 
   if (cmd->argc == 3)
-    buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 2, 
-                                           1, cmd->argv[1], 
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 2,
+                                           1, cmd->argv[1],
                                            strlen(cmd->argv[1]),
                                            2, port, 4);
   else
     buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 1,
-                                           1, cmd->argv[1], 
+                                           1, cmd->argv[1],
                                            strlen(cmd->argv[1]));
   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
@@ -2571,7 +2656,7 @@ SILC_CLIENT_CMD_FUNC(connect)
 
 
 /* CLOSE command. Close server connection to the remote server */
+
 SILC_CLIENT_CMD_FUNC(close)
 {
   SilcClientCommandContext cmd = (SilcClientCommandContext)context;
@@ -2587,7 +2672,7 @@ SILC_CLIENT_CMD_FUNC(close)
   }
 
   if (cmd->argc < 2) {
-    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
+    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
        "Usage: /CLOSE <server> [<port>]");
     COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
@@ -2599,13 +2684,13 @@ SILC_CLIENT_CMD_FUNC(close)
   }
 
   if (cmd->argc == 3)
-    buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 2, 
-                                           1, cmd->argv[1], 
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 2,
+                                           1, cmd->argv[1],
                                            strlen(cmd->argv[1]),
                                            2, port, 4);
   else
     buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 1,
-                                           1, cmd->argv[1], 
+                                           1, cmd->argv[1],
                                            strlen(cmd->argv[1]));
   silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
                          0, NULL, NULL, buffer->data, buffer->len, TRUE);
@@ -2617,7 +2702,7 @@ SILC_CLIENT_CMD_FUNC(close)
  out:
   silc_client_command_free(cmd);
 }
+
 /* SHUTDOWN command. Shutdowns the server. */
 
 SILC_CLIENT_CMD_FUNC(shutdown)
@@ -2631,7 +2716,7 @@ SILC_CLIENT_CMD_FUNC(shutdown)
   }
 
   /* Send the command */
-  silc_client_command_send(cmd->client, cmd->conn, 
+  silc_client_command_send(cmd->client, cmd->conn,
                           SILC_COMMAND_PRIV_SHUTDOWN, 0, 0);
 
   /* Notify application */
@@ -2646,7 +2731,7 @@ SILC_CLIENT_CMD_FUNC(shutdown)
 
 void silc_client_commands_register(SilcClient client)
 {
-  silc_list_init(client->internal->commands, struct SilcClientCommandStruct, 
+  silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
                 next);
 
   SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 3);
@@ -2750,7 +2835,7 @@ void silc_client_command_process(SilcClient client,
 
   /* Get arguments */
   args = silc_command_get_args(payload);
-  
+
   /* Get the command */
   command = silc_command_get(payload);
   switch (command) {
@@ -2805,7 +2890,7 @@ void silc_client_command_process_whois(SilcClient client,
                                         silc_command_get_ident(payload),
                                         1, 11, buffer->data, buffer->len);
   silc_client_packet_send(client, sock, SILC_PACKET_COMMAND_REPLY,
-                         NULL, 0, NULL, NULL, packet->data, 
+                         NULL, 0, NULL, NULL, packet->data,
                          packet->len, TRUE);
   silc_buffer_free(packet);
   silc_buffer_free(buffer);
index 0ae2890bf8c233eee94188c01c2014e99e75a909..a737af8d524f1bc1b498fac34504a7488cd421c4 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  command_reply.c 
+  command_reply.c
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2002 Pekka Riikonen
+  Copyright (C) 1997 - 2003 Pekka Riikonen
 
   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
@@ -25,7 +25,7 @@
  * application through command_reply client operation.  The arguments are
  * exactly same and in same order as the server sent it.  However, ID's are
  * not sent to the application.  Instead, corresponding ID entry is sent
- * to the application.  For example, instead of sending Client ID the 
+ * to the application.  For example, instead of sending Client ID the
  * corresponding SilcClientEntry is sent to the application.  The case is
  * same with for example Channel ID's.  This way application has all the
  * necessary data already in hand without redundant searching.  If ID is
@@ -38,7 +38,7 @@
 
 #define SAY cmd->client->internal->ops->say
 
-/* All functions that call the COMMAND_CHECK_STATUS macro must have 
+/* All functions that call the COMMAND_CHECK_STATUS macro must have
    out: and err: goto labels. out label should call the pending
    command replies, and the err label just handle error condition. */
 
@@ -48,11 +48,11 @@ do {                                                                \
   if (!silc_command_get_status(cmd->payload, NULL, NULL)) {    \
     if (SILC_STATUS_IS_ERROR(cmd->status)) {                   \
       /* Single error */                                       \
-      COMMAND_REPLY_ERROR;                                     \
+      COMMAND_REPLY_ERROR(cmd->status);                                \
       goto out;                                                        \
     }                                                          \
     /* List of errors */                                       \
-    COMMAND_REPLY_ERROR;                                       \
+    COMMAND_REPLY_ERROR(cmd->error);                           \
     if (cmd->status == SILC_STATUS_LIST_END)                   \
       goto out;                                                        \
     goto err;                                                  \
@@ -84,7 +84,7 @@ void silc_client_command_reply_process(SilcClient client,
   SilcCommandPayload payload;
   SilcCommand command;
   SilcCommandCb reply = NULL;
-  
+
   /* Get command reply payload from packet */
   payload = silc_command_payload_parse(buffer->data, buffer->len);
   if (!payload) {
@@ -92,7 +92,7 @@ void silc_client_command_reply_process(SilcClient client,
     SILC_LOG_DEBUG(("Bad command reply packet"));
     return;
   }
-  
+
   /* Allocate command reply context. This must be free'd by the
      command reply routine receiving it. */
   ctx = silc_calloc(1, sizeof(*ctx));
@@ -107,8 +107,8 @@ void silc_client_command_reply_process(SilcClient client,
 
   /* Check for pending commands and mark to be exeucted */
   ctx->callbacks =
-    silc_client_command_pending_check(sock->user_data, ctx, 
-                                     silc_command_get(ctx->payload), 
+    silc_client_command_pending_check(sock->user_data, ctx,
+                                     silc_command_get(ctx->payload),
                                      ctx->ident, &ctx->callbacks_count);
 
   /* Execute command reply */
@@ -138,11 +138,11 @@ void silc_client_command_reply_process(SilcClient client,
 /* Duplicate Command Reply Context by adding reference counter. The context
    won't be free'd untill it hits zero. */
 
-SilcClientCommandReplyContext 
+SilcClientCommandReplyContext
 silc_client_command_reply_dup(SilcClientCommandReplyContext cmd)
 {
   cmd->users++;
-  SILC_LOG_DEBUG(("Command reply context %p refcnt %d->%d", cmd, 
+  SILC_LOG_DEBUG(("Command reply context %p refcnt %d->%d", cmd,
                  cmd->users - 1, cmd->users));
   return cmd;
 }
@@ -152,7 +152,7 @@ silc_client_command_reply_dup(SilcClientCommandReplyContext cmd)
 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
 {
   cmd->users--;
-  SILC_LOG_DEBUG(("Command reply context %p refcnt %d->%d", cmd, 
+  SILC_LOG_DEBUG(("Command reply context %p refcnt %d->%d", cmd,
                  cmd->users + 1, cmd->users));
   if (cmd->users < 1) {
     silc_command_payload_free(cmd->payload);
@@ -160,7 +160,7 @@ void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
   }
 }
 
-static void 
+static void
 silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
                                     SilcStatus status,
                                     bool notify)
@@ -177,27 +177,27 @@ silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
   bool has_channels = FALSE, has_user_modes = FALSE;
   unsigned char *fingerprint;
   SilcUInt32 fingerprint_len;
-  
+
   id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
   if (!id_data) {
     if (notify)
-      COMMAND_REPLY_ERROR;
+      COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     return;
   }
-  
+
   client_id = silc_id_payload_parse_id(id_data, len, NULL);
   if (!client_id) {
     if (notify)
-      COMMAND_REPLY_ERROR;
+      COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     return;
   }
-  
+
   nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
   username = silc_argument_get_arg_type(cmd->args, 4, &len);
   realname = silc_argument_get_arg_type(cmd->args, 5, &len);
   if (!nickname || !username || !realname) {
     if (notify)
-      COMMAND_REPLY_ERROR;
+      COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     return;
   }
 
@@ -227,11 +227,11 @@ silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
   client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
   if (!client_entry) {
     SILC_LOG_DEBUG(("Adding new client entry"));
-    client_entry = 
+    client_entry =
       silc_client_add_client(cmd->client, conn, nickname, username, realname,
                             client_id, mode);
   } else {
-    silc_client_update_client(cmd->client, conn, client_entry, 
+    silc_client_update_client(cmd->client, conn, client_entry,
                              nickname, username, realname, mode);
     silc_free(client_id);
   }
@@ -253,8 +253,8 @@ silc_client_command_reply_whois_save(SilcClientCommandReplyContext cmd,
 
   /* Notify application */
   if (!cmd->callbacks_count && notify)
-    COMMAND_REPLY((SILC_ARGS, client_entry, nickname, username, realname, 
-                  has_channels ? &channels : NULL, mode, idle, 
+    COMMAND_REPLY((SILC_ARGS, client_entry, nickname, username, realname,
+                  has_channels ? &channels : NULL, mode, idle,
                   fingerprint, has_user_modes ? &ch_user_modes : NULL,
                   client_entry->attrs));
 }
@@ -323,13 +323,13 @@ SILC_CLIENT_CMD_REPLY_FUNC(whowas)
 
   id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
   if (!id_data) {
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
-  
+
   client_id = silc_id_payload_parse_id(id_data, len, NULL);
   if (!client_id) {
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
 
@@ -341,12 +341,12 @@ SILC_CLIENT_CMD_REPLY_FUNC(whowas)
   username = silc_argument_get_arg_type(cmd->args, 4, &len);
   realname = silc_argument_get_arg_type(cmd->args, 5, &len);
   if (!nickname || !username) {
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
 
   /* Notify application. We don't save any history information to any
-     cache. Just pass the data to the application for displaying on 
+     cache. Just pass the data to the application for displaying on
      the screen. */
   COMMAND_REPLY((SILC_ARGS, client_entry, nickname, username, realname));
 
@@ -363,7 +363,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(whowas)
   silc_client_command_reply_free(cmd);
 }
 
-static void 
+static void
 silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
                                        SilcStatus status,
                                        bool notify)
@@ -381,17 +381,17 @@ silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
   char *name = NULL, *info = NULL;
   SilcIDPayload idp = NULL;
   SilcIdType id_type;
-  
+
   id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
   if (!id_data) {
     if (notify)
-      COMMAND_REPLY_ERROR;
+      COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     return;
   }
   idp = silc_id_payload_parse(id_data, len);
   if (!idp) {
     if (notify)
-      COMMAND_REPLY_ERROR;
+      COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     return;
   }
 
@@ -410,11 +410,11 @@ silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
     client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
     if (!client_entry) {
       SILC_LOG_DEBUG(("Adding new client entry"));
-      client_entry = 
+      client_entry =
        silc_client_add_client(cmd->client, conn, name, info, NULL,
                               silc_id_dup(client_id, id_type), 0);
     } else {
-      silc_client_update_client(cmd->client, conn, client_entry, 
+      silc_client_update_client(cmd->client, conn, client_entry,
                                name, info, NULL, 0);
     }
 
@@ -438,7 +438,7 @@ silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
                                            silc_id_dup(server_id, id_type));
       if (!server_entry) {
        if (notify)
-         COMMAND_REPLY_ERROR;
+         COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
        return;
       }
     } else {
@@ -482,7 +482,7 @@ silc_client_command_reply_identify_save(SilcClientCommandReplyContext cmd,
 }
 
 /* Received reply for IDENTIFY command. This maybe called several times
-   for one IDENTIFY command as server may reply with list of results. 
+   for one IDENTIFY command as server may reply with list of results.
    This is totally silent and does not print anything on screen. */
 
 SILC_CLIENT_CMD_REPLY_FUNC(identify)
@@ -539,14 +539,15 @@ SILC_CLIENT_CMD_REPLY_FUNC(nick)
   SilcIDPayload idp;
   unsigned char *tmp;
   SilcUInt32 argc, len;
+  SilcClientID old_client_id;
 
   SILC_LOG_DEBUG(("Start"));
 
   if (cmd->error != SILC_STATUS_OK) {
     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
-       "Cannot set nickname: %s", 
+       "Cannot set nickname: %s",
        silc_get_status_message(cmd->error));
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(cmd->error);
     goto out;
   }
 
@@ -554,15 +555,18 @@ SILC_CLIENT_CMD_REPLY_FUNC(nick)
   if (argc < 2 || argc > 3) {
     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
        "Cannot set nickname: bad reply to command");
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
 
+  /* Save old Client ID */
+  old_client_id = *conn->local_id;
+
   /* Take received Client ID */
   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
   idp = silc_id_payload_parse(tmp, len);
   if (!idp) {
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
   silc_client_receive_new_id(cmd->client, cmd->sock, idp);
@@ -580,9 +584,10 @@ SILC_CLIENT_CMD_REPLY_FUNC(nick)
     silc_idcache_add(conn->internal->client_cache, strdup(tmp),
                      conn->local_entry->id, conn->local_entry, 0, NULL);
   }
-    
+
   /* Notify application */
-  COMMAND_REPLY((SILC_ARGS, conn->local_entry, conn->local_entry->nickname));
+  COMMAND_REPLY((SILC_ARGS, conn->local_entry, conn->local_entry->nickname,
+                (const SilcClientID *)&old_client_id));
 
  out:
   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_NICK);
@@ -604,19 +609,19 @@ SILC_CLIENT_CMD_REPLY_FUNC(list)
 
   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
   if (!tmp) {
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
 
   channel_id = silc_id_payload_parse_id(tmp, len, NULL);
   if (!channel_id) {
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
 
   name = silc_argument_get_arg_type(cmd->args, 3, NULL);
   if (!name) {
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
 
@@ -626,14 +631,14 @@ SILC_CLIENT_CMD_REPLY_FUNC(list)
     SILC_GET32_MSB(usercount, tmp);
 
   /* Check whether the channel exists, and add it to cache if it doesn't. */
-  channel_entry = silc_client_get_channel_by_id(cmd->client, conn, 
+  channel_entry = silc_client_get_channel_by_id(cmd->client, conn,
                                                channel_id);
   if (!channel_entry) {
     /* Add new channel entry */
     channel_entry = silc_client_add_channel(cmd->client, conn, name, 0,
                                            channel_id);
     if (!channel_entry) {
-      COMMAND_REPLY_ERROR;
+      COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
       goto out;
     }
     channel_id = NULL;
@@ -670,14 +675,14 @@ SILC_CLIENT_CMD_REPLY_FUNC(topic)
 
   if (cmd->error != SILC_STATUS_OK) {
     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
-       "%s", silc_get_status_message(cmd->error));
-    COMMAND_REPLY_ERROR;
+       "Cannot set topic: %s", silc_get_status_message(cmd->error));
+    COMMAND_REPLY_ERROR(cmd->error);
     goto out;
   }
 
   argc = silc_argument_get_arg_num(cmd->args);
   if (argc < 1 || argc > 3) {
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
 
@@ -699,10 +704,10 @@ SILC_CLIENT_CMD_REPLY_FUNC(topic)
   channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
   if (!channel) {
     silc_free(channel_id);
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
-  
+
   /* Notify application */
   COMMAND_REPLY((SILC_ARGS, channel, topic));
 
@@ -725,8 +730,8 @@ SILC_CLIENT_CMD_REPLY_FUNC(invite)
 
   if (cmd->error != SILC_STATUS_OK) {
     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
-       "%s", silc_get_status_message(cmd->error));
-    COMMAND_REPLY_ERROR;
+       "Cannot invite: %s", silc_get_status_message(cmd->error));
+    COMMAND_REPLY_ERROR(cmd->error);
     goto out;
   }
 
@@ -743,7 +748,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(invite)
   channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
   if (!channel) {
     silc_free(channel_id);
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
 
@@ -751,7 +756,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(invite)
   tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
   if (tmp)
     silc_buffer_set(&buf, tmp, len);
-  
+
   /* Notify application */
   COMMAND_REPLY((SILC_ARGS, channel, tmp ? &buf : NULL));
 
@@ -761,21 +766,38 @@ SILC_CLIENT_CMD_REPLY_FUNC(invite)
 }
 
 /* Received reply to the KILL command. */
+
 SILC_CLIENT_CMD_REPLY_FUNC(kill)
 {
   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+  SilcClientID *client_id;
+  SilcClientEntry client_entry = NULL;
+  SilcUInt32 len;
+  unsigned char *id_data;
 
   if (cmd->error != SILC_STATUS_OK) {
     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
-       "%s", silc_get_status_message(cmd->error));
-    COMMAND_REPLY_ERROR;
+       "Cannot kill: %s", silc_get_status_message(cmd->error));
+    COMMAND_REPLY_ERROR(cmd->error);
     goto out;
   }
 
+  id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
+  if (id_data) {
+    client_id = silc_id_payload_parse_id(id_data, len, NULL);
+    if (!client_id) {
+      COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+      goto out;
+    }
+
+    /* Get the client entry, if exists */
+    client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
+    silc_free(client_id);
+  }
+
   /* Notify application */
-  COMMAND_REPLY((SILC_ARGS));
+  COMMAND_REPLY((SILC_ARGS, client_entry));
 
  out:
   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KILL);
@@ -798,9 +820,9 @@ SILC_CLIENT_CMD_REPLY_FUNC(info)
   SILC_LOG_DEBUG(("Start"));
 
   if (cmd->error != SILC_STATUS_OK) {
-    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s", 
+    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s",
        silc_get_status_message(cmd->error));
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(cmd->error);
     goto out;
   }
 
@@ -855,7 +877,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(stats)
   if (cmd->error != SILC_STATUS_OK) {
     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
        "%s", silc_get_status_message(cmd->error));
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(cmd->error);
     goto out;
   }
 
@@ -888,7 +910,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(ping)
   if (cmd->error != SILC_STATUS_OK) {
     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
        "%s", silc_get_status_message(cmd->error));
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(cmd->error);
     goto out;
   }
 
@@ -896,7 +918,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(ping)
   id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_len,
                      cmd->packet->src_id_type);
   if (!id || !conn->internal->ping) {
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
 
@@ -905,11 +927,11 @@ SILC_CLIENT_CMD_REPLY_FUNC(ping)
       continue;
     if (SILC_ID_SERVER_COMPARE(conn->internal->ping[i].dest_id, id)) {
       diff = curtime - conn->internal->ping[i].start_time;
-      SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, 
-         "Ping reply from %s: %d second%s", 
-         conn->internal->ping[i].dest_name, diff, 
+      SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+         "Ping reply from %s: %d second%s",
+         conn->internal->ping[i].dest_name, diff,
          diff == 1 ? "" : "s");
-      
+
       conn->internal->ping[i].start_time = 0;
       silc_free(conn->internal->ping[i].dest_id);
       conn->internal->ping[i].dest_id = NULL;
@@ -941,6 +963,8 @@ SILC_CLIENT_CMD_REPLY_FUNC(join)
   SilcUInt32 argc, mode = 0, len, list_count;
   char *topic, *tmp, *channel_name = NULL, *hmac;
   SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
+  SilcPublicKey founder_key = NULL;
+  SilcBufferStruct chpklist;
   int i;
 
   SILC_LOG_DEBUG(("Start"));
@@ -948,8 +972,8 @@ SILC_CLIENT_CMD_REPLY_FUNC(join)
   if (cmd->error != SILC_STATUS_OK) {
     if (cmd->error != SILC_STATUS_ERR_USER_ON_CHANNEL)
       SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
-         "%s", silc_get_status_message(cmd->error));
-    COMMAND_REPLY_ERROR;
+         "Cannot join channel: %s", silc_get_status_message(cmd->error));
+    COMMAND_REPLY_ERROR(cmd->error);
     goto out;
   }
 
@@ -957,7 +981,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(join)
   if (argc < 7) {
     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
        "Cannot join channel: Bad reply packet");
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
 
@@ -966,7 +990,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(join)
   if (!tmp) {
     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
        "Cannot join channel: Bad reply packet");
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
   channel_name = tmp;
@@ -976,12 +1000,12 @@ SILC_CLIENT_CMD_REPLY_FUNC(join)
   if (!tmp) {
     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
        "Cannot join channel: Bad reply packet");
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
   channel_id = silc_id_payload_parse_id(tmp, len, NULL);
   if (!channel_id) {
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
 
@@ -1008,7 +1032,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(join)
       silc_client_replace_channel_id(cmd->client, conn, channel, channel_id);
   } else {
     /* Create new channel entry */
-    channel = silc_client_add_channel(cmd->client, conn, channel_name, 
+    channel = silc_client_add_channel(cmd->client, conn, channel_name,
                                      mode, channel_id);
   }
 
@@ -1018,9 +1042,9 @@ SILC_CLIENT_CMD_REPLY_FUNC(join)
   hmac = silc_argument_get_arg_type(cmd->args, 11, NULL);
   if (hmac) {
     if (!silc_hmac_alloc(hmac, NULL, &channel->hmac)) {
-      SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, 
+      SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
          "Cannot join channel: Unsupported HMAC `%s'", hmac);
-      COMMAND_REPLY_ERROR;
+      COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
       goto out;
     }
   }
@@ -1070,7 +1094,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(join)
     client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
     if (!client_entry) {
       /* No, we don't have it, add entry for it. */
-      client_entry = 
+      client_entry =
        silc_client_add_client(cmd->client, conn, NULL, NULL, NULL,
                               silc_id_dup(client_id, SILC_ID_CLIENT), 0);
     }
@@ -1089,31 +1113,39 @@ SILC_CLIENT_CMD_REPLY_FUNC(join)
     silc_buffer_pull(client_id_list, idp_len);
     silc_buffer_pull(client_mode_list, 4);
   }
-  silc_buffer_push(client_id_list, client_id_list->data - 
+  silc_buffer_push(client_id_list, client_id_list->data -
                   client_id_list->head);
-  silc_buffer_push(client_mode_list, client_mode_list->data - 
+  silc_buffer_push(client_mode_list, client_mode_list->data -
                   client_mode_list->head);
 
   /* Save channel key */
   if (keyp && !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY))
     silc_client_save_channel_key(cmd->client, conn, keyp, channel);
 
+  /* Get founder key */
+  tmp = silc_argument_get_arg_type(cmd->args, 15, &len);
+  if (tmp)
+    silc_pkcs_public_key_payload_decode(tmp, len, &founder_key);
+
+  /* Get channel public key list */
+  tmp = silc_argument_get_arg_type(cmd->args, 16, &len);
+  if (tmp)
+    silc_buffer_set(&chpklist, tmp, len);
+
   /* Notify application */
-  COMMAND_REPLY((SILC_ARGS, channel_name, channel, mode, 0, 
+  COMMAND_REPLY((SILC_ARGS, channel_name, channel, mode, 0,
                 keyp ? keyp->head : NULL, NULL,
-                NULL, topic, hmac, list_count, client_id_list, 
-                client_mode_list));
+                NULL, topic, hmac, list_count, client_id_list,
+                client_mode_list, founder_key, tmp ? &chpklist : NULL));
 
  out:
   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
   silc_client_command_reply_free(cmd);
-
-  if (keyp)
-    silc_buffer_free(keyp);
-  if (client_id_list)
-    silc_buffer_free(client_id_list);
-  if (client_mode_list)
-    silc_buffer_free(client_mode_list);
+  if (founder_key)
+    silc_pkcs_public_key_free(founder_key);
+  silc_buffer_free(keyp);
+  silc_buffer_free(client_id_list);
+  silc_buffer_free(client_mode_list);
 }
 
 /* Received reply for MOTD command */
@@ -1128,20 +1160,20 @@ SILC_CLIENT_CMD_REPLY_FUNC(motd)
   if (cmd->error != SILC_STATUS_OK) {
     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
        "%s", silc_get_status_message(cmd->error));
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(cmd->error);
     return;
   }
 
   argc = silc_argument_get_arg_num(cmd->args);
   if (argc > 3) {
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
 
   if (argc == 3) {
     motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
     if (!motd) {
-      COMMAND_REPLY_ERROR;
+      COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
       goto out;
     }
 
@@ -1152,12 +1184,12 @@ SILC_CLIENT_CMD_REPLY_FUNC(motd)
        memset(line, 0, sizeof(line));
        silc_strncat(line, sizeof(line), cp, i - 1);
        cp += i;
-       
+
        if (i == 2)
          line[0] = ' ';
-       
+
        SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO, "%s", line);
-       
+
        if (!strlen(cp))
          break;
        i = 0;
@@ -1184,14 +1216,14 @@ SILC_CLIENT_CMD_REPLY_FUNC(umode)
 
   if (cmd->error != SILC_STATUS_OK) {
     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
-       "%s", silc_get_status_message(cmd->error));
-    COMMAND_REPLY_ERROR;
+       "Cannot change mode: %s", silc_get_status_message(cmd->error));
+    COMMAND_REPLY_ERROR(cmd->error);
     goto out;
   }
 
   tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
   if (!tmp) {
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
 
@@ -1217,11 +1249,13 @@ SILC_CLIENT_CMD_REPLY_FUNC(cmode)
   SilcChannelID *channel_id;
   SilcChannelEntry channel;
   SilcUInt32 len;
+  SilcPublicKey public_key = NULL;
+  SilcBufferStruct channel_pubkeys;
 
   if (cmd->error != SILC_STATUS_OK) {
     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
-       "%s", silc_get_status_message(cmd->error));
-    COMMAND_REPLY_ERROR;
+       "Cannot change mode: %s", silc_get_status_message(cmd->error));
+    COMMAND_REPLY_ERROR(cmd->error);
     goto out;
   }
 
@@ -1237,7 +1271,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(cmode)
   channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
   if (!channel) {
     silc_free(channel_id);
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
 
@@ -1245,7 +1279,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(cmode)
   tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
   if (!tmp) {
     silc_free(channel_id);
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
 
@@ -1253,12 +1287,27 @@ SILC_CLIENT_CMD_REPLY_FUNC(cmode)
   SILC_GET32_MSB(mode, tmp);
   channel->mode = mode;
 
+  /* Get founder public key */
+  tmp = silc_argument_get_arg_type(cmd->args, 4, &len);
+  if (tmp) {
+    if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key))
+      public_key = NULL;
+  }
+
+  /* Get channel public key(s) */
+  tmp = silc_argument_get_arg_type(cmd->args, 5, &len);
+  if (tmp)
+    silc_buffer_set(&channel_pubkeys, tmp, len);
+
   /* Notify application */
-  COMMAND_REPLY((SILC_ARGS, channel, mode));
+  COMMAND_REPLY((SILC_ARGS, channel, mode, public_key,
+                tmp ? &channel_pubkeys : NULL));
 
   silc_free(channel_id);
 
  out:
+  if (public_key)
+    silc_pkcs_public_key_free(public_key);
   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CMODE);
   silc_client_command_reply_free(cmd);
 }
@@ -1276,18 +1325,18 @@ SILC_CLIENT_CMD_REPLY_FUNC(cumode)
   SilcChannelUser chu;
   unsigned char *modev, *tmp, *id;
   SilcUInt32 len, mode;
-  
+
   if (cmd->error != SILC_STATUS_OK) {
     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
-       "%s", silc_get_status_message(cmd->error));
-    COMMAND_REPLY_ERROR;
+       "Cannot change mode: %s", silc_get_status_message(cmd->error));
+    COMMAND_REPLY_ERROR(cmd->error);
     goto out;
   }
-  
+
   /* Get channel mode */
   modev = silc_argument_get_arg_type(cmd->args, 2, NULL);
   if (!modev) {
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
 
@@ -1303,30 +1352,30 @@ SILC_CLIENT_CMD_REPLY_FUNC(cumode)
   channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
   if (!channel) {
     silc_free(channel_id);
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
-  
+
   /* Get Client ID */
   id = silc_argument_get_arg_type(cmd->args, 4, &len);
   if (!id) {
     silc_free(channel_id);
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
   client_id = silc_id_payload_parse_id(id, len, NULL);
   if (!client_id) {
     silc_free(channel_id);
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
-  
+
   /* Get client entry */
   client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
   if (!client_entry) {
     silc_free(channel_id);
     silc_free(client_id);
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
 
@@ -1340,7 +1389,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(cumode)
   COMMAND_REPLY((SILC_ARGS, mode, channel, client_entry));
   silc_free(client_id);
   silc_free(channel_id);
-  
+
  out:
   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CUMODE);
   silc_client_command_reply_free(cmd);
@@ -1350,18 +1399,60 @@ SILC_CLIENT_CMD_REPLY_FUNC(kick)
 {
   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+  SilcClientID *client_id = NULL;
+  SilcChannelID *channel_id = NULL;
+  SilcClientEntry client_entry = NULL;
+  SilcChannelEntry channel = NULL;
+  unsigned char *tmp;
+  SilcUInt32 len;
 
   if (cmd->error != SILC_STATUS_OK) {
     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
-       "%s", silc_get_status_message(cmd->error));
-    COMMAND_REPLY_ERROR;
+       "Cannot kick: %s", silc_get_status_message(cmd->error));
+    COMMAND_REPLY_ERROR(cmd->error);
     goto out;
   }
 
+  /* Take Channel ID */
+  tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+  if (tmp) {
+    channel_id = silc_id_payload_parse_id(tmp, len, NULL);
+    if (!channel_id) {
+      COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+      goto out;
+    }
+
+    /* Get the channel entry */
+    channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
+    if (!channel) {
+      COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+      goto out;
+    }
+  }
+
+  /* Get Client ID */
+  tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
+  if (tmp) {
+    client_id = silc_id_payload_parse_id(tmp, len, NULL);
+    if (!client_id) {
+      COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+      goto out;
+    }
+
+    /* Get client entry */
+    client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
+    if (!client_entry) {
+      COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+      goto out;
+    }
+  }
+
   /* Notify application */
-  COMMAND_REPLY((SILC_ARGS));
+  COMMAND_REPLY((SILC_ARGS, channel, client_entry));
 
  out:
+  silc_free(channel_id);
+  silc_free(client_id);
   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_KICK);
   silc_client_command_reply_free(cmd);
 }
@@ -1374,7 +1465,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
   if (cmd->error != SILC_STATUS_OK) {
     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
        "%s", silc_get_status_message(cmd->error));
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(cmd->error);
     goto out;
   }
 
@@ -1394,7 +1485,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(oper)
   if (cmd->error != SILC_STATUS_OK) {
     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
        "%s", silc_get_status_message(cmd->error));
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(cmd->error);
     goto out;
   }
 
@@ -1415,7 +1506,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(detach)
   if (cmd->error != SILC_STATUS_OK) {
     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
        "%s", silc_get_status_message(cmd->error));
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(cmd->error);
     goto out;
   }
 
@@ -1426,7 +1517,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(detach)
      detach client operation */
   detach = silc_client_get_detach_data(cmd->client, conn);
   if (detach) {
-    cmd->client->internal->ops->detach(cmd->client, conn, 
+    cmd->client->internal->ops->detach(cmd->client, conn,
                                       detach->data, detach->len);
     silc_buffer_free(detach);
   }
@@ -1444,7 +1535,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(watch)
   if (cmd->error != SILC_STATUS_OK) {
     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
        "%s", silc_get_status_message(cmd->error));
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(cmd->error);
     goto out;
   }
 
@@ -1469,7 +1560,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(ban)
   if (cmd->error != SILC_STATUS_OK) {
     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
        "%s", silc_get_status_message(cmd->error));
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(cmd->error);
     goto out;
   }
 
@@ -1486,15 +1577,15 @@ SILC_CLIENT_CMD_REPLY_FUNC(ban)
   channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
   if (!channel) {
     silc_free(channel_id);
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
-  
+
   /* Get the ban list */
   tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
   if (tmp)
     silc_buffer_set(&buf, tmp, len);
-  
+
   /* Notify application */
   COMMAND_REPLY((SILC_ARGS, channel, tmp ? &buf : NULL));
 
@@ -1511,13 +1602,14 @@ SILC_CLIENT_CMD_REPLY_FUNC(leave)
   SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
   SilcChannelID *channel_id;
   SilcChannelEntry channel = NULL;
+  SilcChannelUser chu;
   unsigned char *tmp;
   SilcUInt32 len;
 
   if (cmd->error != SILC_STATUS_OK) {
     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
        "%s", silc_get_status_message(cmd->error));
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(cmd->error);
     goto out;
   }
 
@@ -1532,16 +1624,28 @@ SILC_CLIENT_CMD_REPLY_FUNC(leave)
     channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
     if (!channel) {
       silc_free(channel_id);
-      COMMAND_REPLY_ERROR;
+      COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
       goto out;
     }
 
+    /* Remove us from this channel. */
+    chu = silc_client_on_channel(channel, conn->local_entry);
+    if (chu) {
+      silc_hash_table_del(chu->client->channels, chu->channel);
+      silc_hash_table_del(chu->channel->user_list, chu->client);
+      silc_free(chu);
+    }
+
     silc_free(channel_id);
   }
 
   /* Notify application */
   COMMAND_REPLY((SILC_ARGS, channel));
 
+  /* Now delete the channel. */
+  if (channel)
+    silc_client_del_channel(cmd->client, conn, channel);
+
  out:
   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
   silc_client_command_reply_free(cmd);
@@ -1562,7 +1666,7 @@ static void silc_client_command_reply_users_cb(SilcClient client,
     cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
        "%s", silc_get_status_message(cmd->error));
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(cmd->error);
     SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
     silc_client_command_reply_free(cmd);
     return;
@@ -1575,6 +1679,7 @@ static int
 silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd,
                                     SilcStatus status,
                                     bool notify,
+                                    bool resolve,
                                     SilcGetChannelCallback get_channel,
                                     SilcCommandCb get_clients)
 {
@@ -1596,19 +1701,19 @@ silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd,
   /* Get channel ID */
   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
   if (!tmp) {
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
   channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
   if (!channel_id) {
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
-  
+
   /* Get the list count */
   tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
   if (!tmp) {
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
   SILC_GET32_MSB(list_count, tmp);
@@ -1616,7 +1721,7 @@ silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd,
   /* Get Client ID list */
   tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
   if (!tmp) {
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
   silc_buffer_set(&client_id_list, tmp, tmp_len);
@@ -1624,7 +1729,7 @@ silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd,
   /* Get client mode list */
   tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
   if (!tmp) {
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
   silc_buffer_set(&client_mode_list, tmp, tmp_len);
@@ -1660,19 +1765,21 @@ silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd,
     /* Check if we have this client cached already. */
     client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
     if (!client_entry || !client_entry->username || !client_entry->realname) {
-      /* No we don't have it (or it is incomplete in information), query
-        it from the server. Assemble argument table that will be sent
-        for the WHOIS command later. */
-      res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
-                             (res_argc + 1));
-      res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
-                                  (res_argc + 1));
-      res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
-                                   (res_argc + 1));
-      res_argv[res_argc] = client_id_list.data;
-      res_argv_lens[res_argc] = idp_len;
-      res_argv_types[res_argc] = res_argc + 4;
-      res_argc++;
+      if (resolve) {
+       /* No we don't have it (or it is incomplete in information), query
+          it from the server. Assemble argument table that will be sent
+          for the WHOIS command later. */
+       res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
+                               (res_argc + 1));
+       res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
+                                    (res_argc + 1));
+       res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
+                                     (res_argc + 1));
+       res_argv[res_argc] = client_id_list.data;
+       res_argv_lens[res_argc] = idp_len;
+       res_argv_types[res_argc] = res_argc + 4;
+       res_argc++;
+      }
     } else {
       if (!silc_client_on_channel(channel, client_entry)) {
        chu = silc_calloc(1, sizeof(*chu));
@@ -1701,7 +1808,7 @@ silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd,
     res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
                                          res_argc, res_argv, res_argv_lens,
                                          res_argv_types, conn->cmd_ident);
-    silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, 
+    silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
                            NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
                            TRUE);
 
@@ -1722,14 +1829,14 @@ silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd,
   if (wait_res)
     return 1;
 
-  silc_buffer_push(&client_id_list, (client_id_list.data - 
+  silc_buffer_push(&client_id_list, (client_id_list.data -
                                     client_id_list.head));
-  silc_buffer_push(&client_mode_list, (client_mode_list.data - 
+  silc_buffer_push(&client_mode_list, (client_mode_list.data -
                                       client_mode_list.head));
 
   /* Notify application */
   if (notify)
-    COMMAND_REPLY((SILC_ARGS, channel, list_count, &client_id_list, 
+    COMMAND_REPLY((SILC_ARGS, channel, list_count, &client_id_list,
                   &client_mode_list));
 
  out:
@@ -1750,19 +1857,29 @@ SILC_CLIENT_CMD_REPLY_FUNC(users)
 
   if (cmd->error != SILC_STATUS_OK) {
     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
-       "%s", silc_get_status_message(cmd->error));
-    COMMAND_REPLY_ERROR;
+       "Query failed: %s", silc_get_status_message(cmd->error));
+    COMMAND_REPLY_ERROR(cmd->error);
     goto out;
   }
 
   if (r && !silc_command_get_status(r->payload, NULL, &cmd->error)) {
-    SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
-       "%s", silc_get_status_message(cmd->error));
-    COMMAND_REPLY_ERROR;
-    goto out;
+    if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
+      /* Do not resolve anymore. Server may be sending us some non-existent
+        Client ID (a bug in server), and we want to show the users list
+        anyway. */
+      silc_client_command_reply_users_save(cmd, cmd->status, TRUE, FALSE,
+                                          silc_client_command_reply_users_cb,
+                                          silc_client_command_reply_users);
+      goto out;
+    } else {
+      SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+         "Query failed: %s", silc_get_status_message(cmd->error));
+      COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+      goto out;
+    }
   }
 
-  if (silc_client_command_reply_users_save(cmd, cmd->status, TRUE,
+  if (silc_client_command_reply_users_save(cmd, cmd->status, TRUE, TRUE,
                                           silc_client_command_reply_users_cb,
                                           silc_client_command_reply_users))
     return;
@@ -1794,18 +1911,18 @@ SILC_CLIENT_CMD_REPLY_FUNC(getkey)
   if (cmd->error != SILC_STATUS_OK) {
     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
        "%s", silc_get_status_message(cmd->error));
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(cmd->error);
     goto out;
   }
 
   tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
   if (!tmp) {
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
   idp = silc_id_payload_parse(tmp, len);
   if (!idp) {
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
 
@@ -1815,14 +1932,14 @@ SILC_CLIENT_CMD_REPLY_FUNC(getkey)
     if (!silc_pkcs_public_key_payload_decode(tmp, len, &public_key))
       public_key = NULL;
   }
-   
+
   id_type = silc_id_payload_get_type(idp);
   if (id_type == SILC_ID_CLIENT) {
     /* Received client's public key */
     client_id = silc_id_payload_get_id(idp);
     client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
     if (!client_entry) {
-      COMMAND_REPLY_ERROR;
+      COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
       goto out;
     }
 
@@ -1841,7 +1958,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(getkey)
     server_id = silc_id_payload_get_id(idp);
     server_entry = silc_client_get_server_by_id(cmd->client, conn, server_id);
     if (!server_entry) {
-      COMMAND_REPLY_ERROR;
+      COMMAND_REPLY_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
       goto out;
     }
 
@@ -2008,7 +2125,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(info_i)
     silc_client_add_server(cmd->client, conn, server_name, server_info,
                           silc_id_dup(server_id, SILC_ID_SERVER));
   }
-  
+
  out:
   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
   silc_free(server_id);
@@ -2029,7 +2146,7 @@ static void silc_client_command_reply_users_i_cb(SilcClient client,
     cmd->status = cmd->error = SILC_STATUS_ERR_NO_SUCH_CHANNEL;
     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
        "%s", silc_get_status_message(cmd->error));
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(cmd->error);
     SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS);
     silc_client_command_reply_free(cmd);
     return;
@@ -2046,7 +2163,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(users_i)
 
   /* Save USERS info */
   if (silc_client_command_reply_users_save(
-                                   cmd, cmd->status, FALSE,
+                                   cmd, cmd->status, FALSE, TRUE,
                                    silc_client_command_reply_users_i_cb,
                                    silc_client_command_reply_users_i))
     return;
@@ -2074,7 +2191,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(connect)
   if (cmd->error != SILC_STATUS_OK) {
     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
        "%s", silc_get_status_message(cmd->error));
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(cmd->error);
     goto out;
   }
 
@@ -2094,7 +2211,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(close)
   if (cmd->error != SILC_STATUS_OK) {
     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
        "%s", silc_get_status_message(cmd->error));
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(cmd->error);
     goto out;
   }
 
@@ -2105,7 +2222,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(close)
   SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CLOSE);
   silc_client_command_reply_free(cmd);
 }
+
 SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
 {
   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
@@ -2114,7 +2231,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
   if (cmd->error != SILC_STATUS_OK) {
     SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
        "%s", silc_get_status_message(cmd->error));
-    COMMAND_REPLY_ERROR;
+    COMMAND_REPLY_ERROR(cmd->error);
     goto out;
   }
 
index 3f9e7598fd54b82cd68fe4060d79880299085e0d..4eb8ca18ea428b63345f25ae0234cd7d9a8f14af 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  command_reply.h 
+  command_reply.h
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2001 Pekka Riikonen
+  Copyright (C) 1997 - 2003 Pekka Riikonen
 
   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
@@ -51,16 +51,30 @@ struct SilcClientCommandReplyContextStruct {
 
 /* Macros */
 
-/* Command reply operation that is called at the end of all command replys. 
+/* Command reply operation that is called at the end of all command replys.
    Usage: COMMAND_REPLY((ARGS, argument1, argument2, etc...)), */
 #define COMMAND_REPLY(args) cmd->client->internal->ops->command_reply args
-#define SILC_ARGS cmd->client, cmd->sock->user_data,                   \
+#define SILC_ARGS cmd->client, cmd->sock->user_data,                        \
              cmd->payload, TRUE, silc_command_get(cmd->payload), cmd->status
 
 /* Error reply to application. Usage: COMMAND_REPLY_ERROR; */
-#define COMMAND_REPLY_ERROR cmd->client->internal->ops->               \
-  command_reply(cmd->client, cmd->sock->user_data, cmd->payload,       \
-  FALSE, silc_command_get(cmd->payload), cmd->status)
+#define COMMAND_REPLY_ERROR(error)                                     \
+do {                                                                   \
+  if (cmd->status == SILC_STATUS_OK) {                                 \
+    cmd->client->internal->ops->                                       \
+      command_reply(cmd->client, cmd->sock->user_data, cmd->payload,   \
+                    FALSE, silc_command_get(cmd->payload), error);     \
+  } else {                                                             \
+    void *arg1 = NULL, *arg2 = NULL;                                   \
+    silc_status_get_args(cmd->status, cmd->args, &arg1, &arg2);                \
+    cmd->client->internal->ops->                                       \
+      command_reply(cmd->client, cmd->sock->user_data, cmd->payload,   \
+                    FALSE, silc_command_get(cmd->payload), cmd->status,        \
+                   arg1, arg2);                                        \
+    silc_free(arg1);                                                   \
+    silc_free(arg2);                                                   \
+  }                                                                    \
+} while(0)
 
 /* Macro used to declare command reply functions */
 #define SILC_CLIENT_CMD_REPLY_FUNC(func)                               \
index 6c015ef527f0758c594d0b751a40403cd3e0097d..dfdfc6f3e5d4420367acfcd94dd0e74d5939cea7 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  idlist.c 
+  idlist.c
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2001 - 2002 Pekka Riikonen
+  Copyright (C) 2001 - 2003 Pekka Riikonen
 
   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
@@ -87,7 +87,7 @@ SilcClientEntry *silc_client_get_clients_local(SilcClient client,
          continue;
        }
       }
-      
+
       clients[i++] = id_cache->context;
       found = TRUE;
       if (!silc_idcache_list_next(list, &id_cache))
@@ -146,7 +146,7 @@ SILC_CLIENT_CMD_FUNC(get_client_callback)
   silc_free(i);
 }
 
-/* Finds client entry or entries by the `nickname' and `server'. The 
+/* Finds client entry or entries by the `nickname' and `server'. The
    completion callback will be called when the client entries has been found.
 
    Note: this function is always asynchronous and resolves the client
@@ -195,13 +195,13 @@ void silc_client_get_clients(SilcClient client,
                               ++conn->cmd_ident);
 
   /* Send the command */
-  silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY, 
-                          conn->cmd_ident, 1, 1, userhost, 
+  silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
+                          conn->cmd_ident, 1, 1, userhost,
                           strlen(userhost));
 
   /* Add pending callback */
   silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
-                             silc_client_command_get_client_callback, 
+                             silc_client_command_get_client_callback,
                              (void *)i);
 
   silc_free(userhost);
@@ -232,14 +232,14 @@ SilcClientEntry silc_idlist_get_client(SilcClient client,
 
     if (query) {
       SILC_LOG_DEBUG(("Requesting Client ID from server"));
-      
+
       /* Register our own command reply for this command */
       silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
                                   silc_client_command_reply_identify_i, 0,
                                   ++conn->cmd_ident);
 
       /* Send the command */
-      silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY, 
+      silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
                               conn->cmd_ident, 1, 1, nickname,
                               strlen(nickname));
 
@@ -287,7 +287,6 @@ SilcClientEntry silc_idlist_get_client(SilcClient client,
   return entry;
 }
 
-
 typedef struct {
   SilcClient client;
   SilcClientConnection conn;
@@ -318,6 +317,8 @@ SILC_CLIENT_CMD_FUNC(get_clients_list_callback)
 
   SILC_LOG_DEBUG(("Resolved all clients"));
 
+  clients = silc_calloc(i->list_count, sizeof(*clients));
+
   for (c = 0; c < i->list_count; c++) {
     SilcUInt16 idp_len;
     SilcClientID *client_id;
@@ -332,13 +333,11 @@ SILC_CLIENT_CMD_FUNC(get_clients_list_callback)
     }
 
     /* Get the client entry */
-    if (silc_idcache_find_by_id_one_ext(i->conn->internal->client_cache, 
-                                       (void *)client_id, 
-                                       NULL, NULL, 
+    if (silc_idcache_find_by_id_one_ext(i->conn->internal->client_cache,
+                                       (void *)client_id,
+                                       NULL, NULL,
                                        silc_hash_client_id_compare, NULL,
                                        &id_cache)) {
-      clients = silc_realloc(clients, sizeof(*clients) * 
-                            (clients_count + 1));
       clients[clients_count] = (SilcClientEntry)id_cache->context;
       clients_count++;
       found = TRUE;
@@ -411,7 +410,7 @@ void silc_client_get_clients_by_list(SilcClient client,
     /* Check if we have this client cached already. */
     ret =
       silc_idcache_find_by_id_one_ext(conn->internal->client_cache,
-                                     (void *)client_id, NULL, NULL, 
+                                     (void *)client_id, NULL, NULL,
                                      silc_hash_client_id_compare, NULL,
                                      &id_cache);
 
@@ -424,9 +423,9 @@ void silc_client_get_clients_by_list(SilcClient client,
        if (entry->status & SILC_CLIENT_STATUS_RESOLVING) {
          /* Attach to this resolving and wait until it finishes */
          silc_client_command_pending(
-                           conn, SILC_COMMAND_NONE, 
+                           conn, SILC_COMMAND_NONE,
                            entry->resolve_cmd_ident,
-                           silc_client_command_get_clients_list_callback, 
+                           silc_client_command_get_clients_list_callback,
                            (void *)in);
          wait_res = TRUE;
          in->res_count++;
@@ -458,7 +457,7 @@ void silc_client_get_clients_by_list(SilcClient client,
     silc_buffer_pull(client_id_list, idp_len);
   }
 
-  silc_buffer_push(client_id_list, client_id_list->data - 
+  silc_buffer_push(client_id_list, client_id_list->data -
                   client_id_list->head);
 
   /* Query the client information from server if the list included clients
@@ -470,7 +469,7 @@ void silc_client_get_clients_by_list(SilcClient client,
     res_cmd = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
                                          res_argc, res_argv, res_argv_lens,
                                          res_argv_types, ++conn->cmd_ident);
-    silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND, 
+    silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
                            NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
                            TRUE);
 
@@ -481,7 +480,7 @@ void silc_client_get_clients_by_list(SilcClient client,
 
     /* Process the applications request after reply has been received  */
     silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
-                               silc_client_command_get_clients_list_callback, 
+                               silc_client_command_get_clients_list_callback,
                                (void *)in);
     in->res_count++;
 
@@ -499,6 +498,169 @@ void silc_client_get_clients_by_list(SilcClient client,
   silc_client_command_get_clients_list_callback((void *)in, NULL);
 }
 
+typedef struct {
+  SilcClient client;
+  SilcClientConnection conn;
+  SilcChannelID channel_id;
+  SilcGetClientCallback completion;
+  void *context;
+  int res_count;
+} *GetClientsByChannelInternal;
+
+SILC_CLIENT_CMD_FUNC(get_clients_by_channel_cb)
+{
+  GetClientsByChannelInternal i = context;
+  SilcClientEntry *clients = NULL;
+  SilcUInt32 clients_count = 0;
+  bool found = FALSE;
+  SilcChannelEntry channel;
+  SilcHashTableList htl;
+  SilcChannelUser chu;
+
+  channel = silc_client_get_channel_by_id(i->client, i->conn, &i->channel_id);
+  if (channel && !silc_hash_table_count(channel->user_list)) {
+    clients = silc_calloc(silc_hash_table_count(channel->user_list),
+                         sizeof(*clients));
+    silc_hash_table_list(channel->user_list, &htl);
+    while (silc_hash_table_get(&htl, NULL, (void **)&chu))
+      clients[clients_count++] = chu->client;
+    silc_hash_table_list_reset(&htl);
+    found = TRUE;
+  }
+
+  if (found) {
+    i->completion(i->client, i->conn, clients, clients_count, i->context);
+    silc_free(clients);
+  } else {
+    i->completion(i->client, i->conn, NULL, 0, i->context);
+  }
+
+  silc_free(i);
+}
+
+/* Gets client entries by the channel entry indicated by `channel'.  Thus,
+   it resolves the clients currently on that channel. */
+
+void silc_client_get_clients_by_channel(SilcClient client,
+                                       SilcClientConnection conn,
+                                       SilcChannelEntry channel,
+                                       SilcGetClientCallback completion,
+                                       void *context)
+{
+  GetClientsByChannelInternal in;
+  SilcHashTableList htl;
+  SilcChannelUser chu;
+  SilcClientEntry entry;
+  unsigned char **res_argv = NULL;
+  SilcUInt32 *res_argv_lens = NULL, *res_argv_types = NULL, res_argc = 0;
+  SilcBuffer idp;
+  bool wait_res = FALSE;
+
+  assert(client && conn && channel);
+
+  SILC_LOG_DEBUG(("Start"));
+
+  in = silc_calloc(1, sizeof(*in));
+  in->client = client;
+  in->conn = conn;
+  in->channel_id = *channel->id;
+  in->completion = completion;
+  in->context = context;
+
+  /* If user list does not exist, send USERS command. */
+  if (!channel->user_list || !silc_hash_table_count(channel->user_list)) {
+    SILC_LOG_DEBUG(("Sending USERS"));
+    silc_client_command_register(client, SILC_COMMAND_USERS, NULL, NULL,
+                                silc_client_command_reply_users_i, 0,
+                                ++conn->cmd_ident);
+    silc_client_command_send(client, conn, SILC_COMMAND_USERS,
+                            conn->cmd_ident, 1, 2, channel->channel_name,
+                            strlen(channel->channel_name));
+    silc_client_command_pending(conn, SILC_COMMAND_USERS, conn->cmd_ident,
+                               silc_client_command_get_clients_by_channel_cb,
+                               in);
+    return;
+  }
+
+  silc_hash_table_list(channel->user_list, &htl);
+  while (silc_hash_table_get(&htl, NULL, (void **)&chu)) {
+    entry = chu->client;
+
+    /* If the entry has incomplete info, then resolve it from the server. */
+    if (!entry->nickname || !entry->realname) {
+      if (entry->status & SILC_CLIENT_STATUS_RESOLVING) {
+       /* Attach to this resolving and wait until it finishes */
+       silc_client_command_pending(
+                           conn, SILC_COMMAND_NONE,
+                           entry->resolve_cmd_ident,
+                           silc_client_command_get_clients_by_channel_cb,
+                           (void *)in);
+       wait_res = TRUE;
+       in->res_count++;
+       continue;
+      }
+      entry->status |= SILC_CLIENT_STATUS_RESOLVING;
+      entry->resolve_cmd_ident = conn->cmd_ident + 1;
+
+      idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
+
+      /* No we don't have it, query it from the server. Assemble argument
+        table that will be sent for the WHOIS command later. */
+      res_argv = silc_realloc(res_argv, sizeof(*res_argv) *
+                             (res_argc + 1));
+      res_argv_lens = silc_realloc(res_argv_lens, sizeof(*res_argv_lens) *
+                                  (res_argc + 1));
+      res_argv_types = silc_realloc(res_argv_types, sizeof(*res_argv_types) *
+                                   (res_argc + 1));
+      res_argv[res_argc] = silc_memdup(idp->data, idp->len);
+      res_argv_lens[res_argc] = idp->len;
+      res_argv_types[res_argc] = res_argc + 4;
+      res_argc++;
+
+      silc_buffer_free(idp);
+    }
+  }
+  silc_hash_table_list_reset(&htl);
+
+  /* Query the client information from server if the list included clients
+     that we don't know about. */
+  if (res_argc) {
+    SilcBuffer res_cmd;
+
+    /* Send the WHOIS command to server */
+    res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
+                                         res_argc, res_argv, res_argv_lens,
+                                         res_argv_types, ++conn->cmd_ident);
+    silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
+                           NULL, 0, NULL, NULL, res_cmd->data, res_cmd->len,
+                           TRUE);
+
+    /* Register our own command reply for this command */
+    silc_client_command_register(client, SILC_COMMAND_WHOIS, NULL, NULL,
+                                silc_client_command_reply_whois_i, 0,
+                                conn->cmd_ident);
+
+    /* Process the applications request after reply has been received  */
+    silc_client_command_pending(
+                          conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
+                          silc_client_command_get_clients_by_channel_cb,
+                          (void *)in);
+    in->res_count++;
+
+    silc_buffer_free(res_cmd);
+    silc_free(res_argv);
+    silc_free(res_argv_lens);
+    silc_free(res_argv_types);
+    return;
+  }
+
+  if (wait_res)
+    return;
+
+  /* We have the clients in cache, get them and call the completion */
+  silc_client_command_get_clients_by_channel_cb((void *)in, NULL);
+}
+
 /* Finds entry for client by the client's ID. Returns the entry or NULL
    if the entry was not found. */
 
@@ -512,12 +674,12 @@ SilcClientEntry silc_client_get_client_by_id(SilcClient client,
   if (!client_id)
     return NULL;
 
-  SILC_LOG_DEBUG(("Finding client by ID (%s)", 
+  SILC_LOG_DEBUG(("Finding client by ID (%s)",
                  silc_id_render(client_id, SILC_ID_CLIENT)));
 
   /* Find ID from cache */
   if (!silc_idcache_find_by_id_one_ext(conn->internal->client_cache,
-                                      (void *)client_id, NULL, NULL, 
+                                      (void *)client_id, NULL, NULL,
                                       silc_hash_client_id_compare, NULL,
                                       &id_cache))
     return NULL;
@@ -577,7 +739,7 @@ void silc_client_get_client_by_id_resolve(SilcClient client,
   i->client_id = silc_id_dup(client_id, SILC_ID_CLIENT);
   i->completion = completion;
   i->context = context;
-      
+
   /* Register our own command reply for this command */
   silc_client_command_register(client, SILC_COMMAND_WHOIS, NULL, NULL,
                               silc_client_command_reply_whois_i, 0,
@@ -593,7 +755,7 @@ void silc_client_get_client_by_id_resolve(SilcClient client,
 
   /* Add pending callback */
   silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
-                             silc_client_command_get_client_by_id_callback, 
+                             silc_client_command_get_client_by_id_callback,
                              (void *)i);
 }
 
@@ -610,7 +772,7 @@ void silc_client_get_client_by_id_resolve(SilcClient client,
 
 SilcClientEntry
 silc_client_add_client(SilcClient client, SilcClientConnection conn,
-                      char *nickname, char *username, 
+                      char *nickname, char *username,
                       char *userinfo, SilcClientID *id, SilcUInt32 mode)
 {
   SilcClientEntry client_entry;
@@ -623,7 +785,7 @@ silc_client_add_client(SilcClient client, SilcClientConnection conn,
   client_entry->id = id;
   client_entry->valid = TRUE;
   silc_parse_userfqdn(nickname, &nick, &client_entry->server);
-  silc_parse_userfqdn(username, &client_entry->username, 
+  silc_parse_userfqdn(username, &client_entry->username,
                      &client_entry->hostname);
   if (userinfo)
     client_entry->realname = strdup(userinfo);
@@ -635,9 +797,9 @@ silc_client_add_client(SilcClient client, SilcClientConnection conn,
 
   /* Format the nickname */
   silc_client_nickname_format(client, conn, client_entry);
-  
+
   /* Add client to cache, the non-formatted nickname is saved to cache */
-  if (!silc_idcache_add(conn->internal->client_cache, nick, client_entry->id, 
+  if (!silc_idcache_add(conn->internal->client_cache, nick, client_entry->id,
                        (void *)client_entry, 0, NULL)) {
     silc_free(client_entry->nickname);
     silc_free(client_entry->username);
@@ -685,14 +847,14 @@ void silc_client_update_client(SilcClient client,
   if (nick) {
     /* Remove the old cache entry and create a new one */
     silc_idcache_del_by_context(conn->internal->client_cache, client_entry);
-    silc_idcache_add(conn->internal->client_cache, nick, client_entry->id, 
+    silc_idcache_add(conn->internal->client_cache, nick, client_entry->id,
                     client_entry, 0, NULL);
   }
 }
 
 /* Deletes the client entry and frees all memory. */
 
-void silc_client_del_client_entry(SilcClient client, 
+void silc_client_del_client_entry(SilcClient client,
                                  SilcClientConnection conn,
                                  SilcClientEntry client_entry)
 {
@@ -725,11 +887,13 @@ bool silc_client_del_client(SilcClient client, SilcClientConnection conn,
   bool ret = silc_idcache_del_by_context(conn->internal->client_cache,
                                         client_entry);
 
-  /* Remove from channels */
-  silc_client_remove_from_channels(client, conn, client_entry);
+  if (ret) {
+    /* Remove from channels */
+    silc_client_remove_from_channels(client, conn, client_entry);
 
-  /* Free the client entry data */
-  silc_client_del_client_entry(client, conn, client_entry);
+    /* Free the client entry data */
+    silc_client_del_client_entry(client, conn, client_entry);
+  }
 
   return ret;
 }
@@ -739,7 +903,7 @@ bool silc_client_del_client(SilcClient client, SilcClientConnection conn,
 SilcChannelEntry silc_client_add_channel(SilcClient client,
                                         SilcClientConnection conn,
                                         const char *channel_name,
-                                        SilcUInt32 mode, 
+                                        SilcUInt32 mode,
                                         SilcChannelID *channel_id)
 {
   SilcChannelEntry channel;
@@ -754,7 +918,7 @@ SilcChannelEntry silc_client_add_channel(SilcClient client,
                                             NULL, NULL, NULL, TRUE);
 
   /* Put it to the ID cache */
-  if (!silc_idcache_add(conn->internal->channel_cache, channel->channel_name, 
+  if (!silc_idcache_add(conn->internal->channel_cache, channel->channel_name,
                        (void *)channel->id, (void *)channel, 0, NULL)) {
     silc_free(channel->channel_name);
     silc_hash_table_free(channel->user_list);
@@ -792,7 +956,7 @@ bool silc_client_del_channel(SilcClient client, SilcClientConnection conn,
   SILC_LOG_DEBUG(("Start"));
 
   /* Free all client entrys from the users list. The silc_hash_table_free
-     will free all the entries so they are not freed at the foreach 
+     will free all the entries so they are not freed at the foreach
      callback. */
   silc_hash_table_foreach(channel->user_list, silc_client_del_channel_foreach,
                          NULL);
@@ -805,12 +969,20 @@ bool silc_client_del_channel(SilcClient client, SilcClientConnection conn,
     silc_cipher_free(channel->channel_key);
   if (channel->hmac)
     silc_hmac_free(channel->hmac);
-  if (channel->old_channel_key)
-    silc_cipher_free(channel->old_channel_key);
-  if (channel->old_hmac)
-    silc_hmac_free(channel->old_hmac);
-  if (channel->rekey_task)
-    silc_schedule_task_del(conn->client->schedule, channel->rekey_task);
+  if (channel->old_channel_keys) {
+    SilcCipher key;
+    silc_dlist_start(channel->old_channel_keys);
+    while ((key = silc_dlist_get(channel->old_channel_keys)) != SILC_LIST_END)
+      silc_cipher_free(key);
+    silc_dlist_uninit(channel->old_channel_keys);
+  }
+  if (channel->old_hmacs) {
+    SilcHmac hmac;
+    silc_dlist_start(channel->old_hmacs);
+    while ((hmac = silc_dlist_get(channel->old_hmacs)) != SILC_LIST_END)
+      silc_hmac_free(hmac);
+    silc_dlist_uninit(channel->old_hmacs);
+  }
   silc_client_del_channel_private_keys(client, conn, channel);
   silc_free(channel);
   return ret;
@@ -827,16 +999,16 @@ bool silc_client_replace_channel_id(SilcClient client,
   if (!new_id)
     return FALSE;
 
-  SILC_LOG_DEBUG(("Old Channel ID id(%s)", 
+  SILC_LOG_DEBUG(("Old Channel ID id(%s)",
                  silc_id_render(channel->id, SILC_ID_CHANNEL)));
-  SILC_LOG_DEBUG(("New Channel ID id(%s)", 
+  SILC_LOG_DEBUG(("New Channel ID id(%s)",
                  silc_id_render(new_id, SILC_ID_CHANNEL)));
 
   silc_idcache_del_by_id(conn->internal->channel_cache, channel->id);
   silc_free(channel->id);
   channel->id = new_id;
   return silc_idcache_add(conn->internal->channel_cache,
-                         channel->channel_name, 
+                         channel->channel_name,
                          (void *)channel->id, (void *)channel, 0, NULL);
 
 }
@@ -858,7 +1030,7 @@ SilcChannelEntry silc_client_get_channel(SilcClient client,
 
   SILC_LOG_DEBUG(("Start"));
 
-  if (!silc_idcache_find_by_name_one(conn->internal->channel_cache, channel, 
+  if (!silc_idcache_find_by_name_one(conn->internal->channel_cache, channel,
                                     &id_cache))
     return NULL;
 
@@ -886,7 +1058,7 @@ SilcChannelEntry silc_client_get_channel_by_id(SilcClient client,
 
   SILC_LOG_DEBUG(("Start"));
 
-  if (!silc_idcache_find_by_id_one(conn->internal->channel_cache, channel_id, 
+  if (!silc_idcache_find_by_id_one(conn->internal->channel_cache, channel_id,
                                   &id_cache))
     return NULL;
 
@@ -900,27 +1072,85 @@ SilcChannelEntry silc_client_get_channel_by_id(SilcClient client,
 typedef struct {
   SilcClient client;
   SilcClientConnection conn;
-  SilcChannelID *channel_id;
+  union {
+    SilcChannelID *channel_id;
+    char *channel_name;
+  } u;
   SilcGetChannelCallback completion;
   void *context;
-} *GetChannelByIDInternal;
+} *GetChannelInternal;
+
+SILC_CLIENT_CMD_FUNC(get_channel_resolve_callback)
+{
+  GetChannelInternal i = (GetChannelInternal)context;
+  SilcChannelEntry entry;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  /* Get the channel */
+  entry = silc_client_get_channel(i->client, i->conn, i->u.channel_name);
+  if (entry) {
+    i->completion(i->client, i->conn, &entry, 1, i->context);
+  } else {
+    i->completion(i->client, i->conn, NULL, 0, i->context);
+  }
+
+  silc_free(i->u.channel_name);
+  silc_free(i);
+}
+
+/* Resolves channel entry from the server by the channel name. */
+
+void silc_client_get_channel_resolve(SilcClient client,
+                                    SilcClientConnection conn,
+                                    char *channel_name,
+                                    SilcGetChannelCallback completion,
+                                    void *context)
+{
+  GetChannelInternal i = silc_calloc(1, sizeof(*i));
+
+  assert(client && conn && channel_name);
+
+  SILC_LOG_DEBUG(("Start"));
+
+  i->client = client;
+  i->conn = conn;
+  i->u.channel_name = strdup(channel_name);
+  i->completion = completion;
+  i->context = context;
+
+  /* Register our own command reply for this command */
+  silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
+                              silc_client_command_reply_identify_i, 0,
+                              ++conn->cmd_ident);
+
+  /* Send the command */
+  silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
+                          conn->cmd_ident,
+                          1, 3, channel_name, strlen(channel_name));
+
+  /* Add pending callback */
+  silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
+                             silc_client_command_get_channel_resolve_callback,
+                             (void *)i);
+}
 
 SILC_CLIENT_CMD_FUNC(get_channel_by_id_callback)
 {
-  GetChannelByIDInternal i = (GetChannelByIDInternal)context;
+  GetChannelInternal i = (GetChannelInternal)context;
   SilcChannelEntry entry;
 
   SILC_LOG_DEBUG(("Start"));
 
   /* Get the channel */
-  entry = silc_client_get_channel_by_id(i->client, i->conn, i->channel_id);
+  entry = silc_client_get_channel_by_id(i->client, i->conn, i->u.channel_id);
   if (entry) {
     i->completion(i->client, i->conn, &entry, 1, i->context);
   } else {
     i->completion(i->client, i->conn, NULL, 0, i->context);
   }
 
-  silc_free(i->channel_id);
+  silc_free(i->u.channel_id);
   silc_free(i);
 }
 
@@ -933,7 +1163,7 @@ void silc_client_get_channel_by_id_resolve(SilcClient client,
                                           void *context)
 {
   SilcBuffer idp;
-  GetChannelByIDInternal i = silc_calloc(1, sizeof(*i));
+  GetChannelInternal i = silc_calloc(1, sizeof(*i));
 
   assert(client && conn && channel_id);
 
@@ -941,10 +1171,10 @@ void silc_client_get_channel_by_id_resolve(SilcClient client,
 
   i->client = client;
   i->conn = conn;
-  i->channel_id = silc_id_dup(channel_id, SILC_ID_CHANNEL);
+  i->u.channel_id = silc_id_dup(channel_id, SILC_ID_CHANNEL);
   i->completion = completion;
   i->context = context;
-      
+
   /* Register our own command reply for this command */
   silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
                               silc_client_command_reply_identify_i, 0,
@@ -952,14 +1182,14 @@ void silc_client_get_channel_by_id_resolve(SilcClient client,
 
   /* Send the command */
   idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
-  silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY, 
+  silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
                           conn->cmd_ident,
                           1, 5, idp->data, idp->len);
   silc_buffer_free(idp);
 
   /* Add pending callback */
   silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
-                             silc_client_command_get_channel_by_id_callback, 
+                             silc_client_command_get_channel_by_id_callback,
                              (void *)i);
 }
 
@@ -1093,7 +1323,7 @@ void silc_client_update_server(SilcClient client,
    nickname and replace the old nickname in the client entry. If the
    format string is not specified then this function has no effect. */
 
-void silc_client_nickname_format(SilcClient client, 
+void silc_client_nickname_format(SilcClient client,
                                 SilcClientConnection conn,
                                 SilcClientEntry client_entry)
 {
index 0c68045a362318fc521a1cac211a0a357c16adeb..bc229606f6b0f19b2baa618bcac556730b2a05fb 100644 (file)
@@ -4,13 +4,13 @@
 
   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
 
-  Copyright (C) 1997 - 2001 Pekka Riikonen
+  Copyright (C) 1997 - 2003 Pekka Riikonen
 
   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
@@ -42,7 +42,7 @@ void silc_client_protocol_ke_send_packet(SilcSKE ske,
                                         void *context)
 {
   SilcProtocol protocol = (SilcProtocol)context;
-  SilcClientKEInternalContext *ctx = 
+  SilcClientKEInternalContext *ctx =
     (SilcClientKEInternalContext *)protocol->context;
   SilcClient client = (SilcClient)ctx->client;
 
@@ -66,8 +66,8 @@ static void silc_client_verify_key_cb(bool success, void *context)
   SILC_LOG_DEBUG(("Start"));
 
   /* Call the completion callback back to the SKE */
-  verify->completion(verify->ske, success ? SILC_SKE_STATUS_OK : 
-                    SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY, 
+  verify->completion(verify->ske, success ? SILC_SKE_STATUS_OK :
+                    SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY,
                     verify->completion_context);
 
   silc_free(verify);
@@ -85,7 +85,7 @@ void silc_client_protocol_ke_verify_key(SilcSKE ske,
                                        void *completion_context)
 {
   SilcProtocol protocol = (SilcProtocol)context;
-  SilcClientKEInternalContext *ctx = 
+  SilcClientKEInternalContext *ctx =
     (SilcClientKEInternalContext *)protocol->context;
   SilcClient client = (SilcClient)ctx->client;
   VerifyKeyContext verify;
@@ -98,7 +98,7 @@ void silc_client_protocol_ke_verify_key(SilcSKE ske,
   verify->completion_context = completion_context;
 
   /* Verify public key from user. */
-  client->internal->ops->verify_public_key(client, ctx->sock->user_data, 
+  client->internal->ops->verify_public_key(client, ctx->sock->user_data,
                                           ctx->sock->type,
                                           pk_data, pk_len, pk_type,
                                           silc_client_verify_key_cb, verify);
@@ -130,32 +130,32 @@ void silc_client_protocol_ke_set_keys(SilcSKE ske,
                  &conn->internal->hmac_receive);
 
   if (is_responder == TRUE) {
-    silc_cipher_set_key(conn->internal->send_key, keymat->receive_enc_key, 
+    silc_cipher_set_key(conn->internal->send_key, keymat->receive_enc_key,
                        keymat->enc_key_len);
     silc_cipher_set_iv(conn->internal->send_key, keymat->receive_iv);
-    silc_cipher_set_key(conn->internal->receive_key, keymat->send_enc_key, 
+    silc_cipher_set_key(conn->internal->receive_key, keymat->send_enc_key,
                        keymat->enc_key_len);
     silc_cipher_set_iv(conn->internal->receive_key, keymat->send_iv);
-    silc_hmac_set_key(conn->internal->hmac_send, keymat->receive_hmac_key, 
+    silc_hmac_set_key(conn->internal->hmac_send, keymat->receive_hmac_key,
                      keymat->hmac_key_len);
-    silc_hmac_set_key(conn->internal->hmac_receive, keymat->send_hmac_key, 
+    silc_hmac_set_key(conn->internal->hmac_receive, keymat->send_hmac_key,
                      keymat->hmac_key_len);
   } else {
-    silc_cipher_set_key(conn->internal->send_key, keymat->send_enc_key, 
+    silc_cipher_set_key(conn->internal->send_key, keymat->send_enc_key,
                        keymat->enc_key_len);
     silc_cipher_set_iv(conn->internal->send_key, keymat->send_iv);
-    silc_cipher_set_key(conn->internal->receive_key, keymat->receive_enc_key, 
+    silc_cipher_set_key(conn->internal->receive_key, keymat->receive_enc_key,
                        keymat->enc_key_len);
     silc_cipher_set_iv(conn->internal->receive_key, keymat->receive_iv);
-    silc_hmac_set_key(conn->internal->hmac_send, keymat->send_hmac_key, 
+    silc_hmac_set_key(conn->internal->hmac_send, keymat->send_hmac_key,
                      keymat->hmac_key_len);
-    silc_hmac_set_key(conn->internal->hmac_receive, keymat->receive_hmac_key, 
+    silc_hmac_set_key(conn->internal->hmac_receive, keymat->receive_hmac_key,
                      keymat->hmac_key_len);
   }
 
   /* Rekey stuff */
   conn->internal->rekey = silc_calloc(1, sizeof(*conn->internal->rekey));
-  conn->internal->rekey->send_enc_key = silc_memdup(keymat->send_enc_key, 
+  conn->internal->rekey->send_enc_key = silc_memdup(keymat->send_enc_key,
                                                    keymat->enc_key_len / 8);
   conn->internal->rekey->enc_key_len = keymat->enc_key_len / 8;
 
@@ -179,16 +179,16 @@ SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version,
   if (!silc_parse_version_string(version, &r_protocol_version, NULL, NULL,
                                 NULL, NULL)) {
     client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
-                              "We don't support server version `%s'", 
+                              "We don't support server version `%s'",
                               version);
     return SILC_SKE_STATUS_BAD_VERSION;
   }
 
-  if (!silc_parse_version_string(client->internal->silc_client_version, 
+  if (!silc_parse_version_string(client->internal->silc_client_version,
                                 &l_protocol_version, NULL, NULL,
                                 NULL, NULL)) {
     client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
-                              "We don't support server version `%s'", 
+                              "We don't support server version `%s'",
                               version);
     return SILC_SKE_STATUS_BAD_VERSION;
   }
@@ -196,7 +196,7 @@ SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version,
   /* If remote is too new, don't connect */
   if (l_protocol_version < r_protocol_version) {
     client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_AUDIT,
-                              "We don't support server version `%s'", 
+                              "We don't support server version `%s'",
                               version);
     return SILC_SKE_STATUS_BAD_VERSION;
   }
@@ -207,8 +207,8 @@ SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version,
 }
 
 /* Callback that is called by the SKE to indicate that it is safe to
-   continue the execution of the protocol. Is given as argument to the 
-   silc_ske_initiator_finish or silc_ske_responder_phase_2 functions. 
+   continue the execution of the protocol. Is given as argument to the
+   silc_ske_initiator_finish or silc_ske_responder_phase_2 functions.
    This is called due to the fact that the public key verification
    process is asynchronous and we must not continue the protocl until
    the public key has been verified and this callback is called. */
@@ -217,7 +217,7 @@ static void silc_client_protocol_ke_continue(SilcSKE ske,
                                             void *context)
 {
   SilcProtocol protocol = (SilcProtocol)context;
-  SilcClientKEInternalContext *ctx = 
+  SilcClientKEInternalContext *ctx =
     (SilcClientKEInternalContext *)protocol->context;
   SilcClient client = (SilcClient)ctx->client;
   SilcClientConnection conn = ctx->sock->user_data;
@@ -226,7 +226,7 @@ static void silc_client_protocol_ke_continue(SilcSKE ske,
 
   if (ske->status != SILC_SKE_STATUS_OK) {
     /* Call failure client operation */
-    client->internal->ops->failure(client, conn, protocol, 
+    client->internal->ops->failure(client, conn, protocol,
                                   (void *)ske->status);
     protocol->state = SILC_PROTOCOL_STATE_ERROR;
     silc_protocol_execute(protocol, client->schedule, 0, 0);
@@ -244,7 +244,7 @@ static void silc_client_protocol_ke_continue(SilcSKE ske,
     protocol->state = SILC_PROTOCOL_STATE_END;
   }
 
-  /* Advance protocol state and call the next state if we are responder. 
+  /* Advance protocol state and call the next state if we are responder.
      This happens when this callback was sent to silc_ske_responder_phase_2
      function. */
   if (ctx->responder == TRUE) {
@@ -259,7 +259,7 @@ static void silc_client_protocol_ke_continue(SilcSKE ske,
 SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
 {
   SilcProtocol protocol = (SilcProtocol)context;
-  SilcClientKEInternalContext *ctx = 
+  SilcClientKEInternalContext *ctx =
     (SilcClientKEInternalContext *)protocol->context;
   SilcClient client = (SilcClient)ctx->client;
   SilcClientConnection conn = ctx->sock->user_data;
@@ -284,13 +284,13 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
       silc_ske_set_callbacks(ske, ctx->send_packet, NULL,
                             ctx->verify,
                             silc_client_protocol_ke_continue,
-                            silc_ske_check_version, 
+                            silc_ske_check_version,
                             context);
-      
+
       if (ctx->responder == TRUE) {
        /* Start the key exchange by processing the received security
           properties packet from initiator. */
-       status = 
+       status =
          silc_ske_responder_start(ske, ctx->rng, ctx->sock,
                                   client->internal->silc_client_version,
                                   ctx->packet->buffer, TRUE);
@@ -299,7 +299,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
 
        /* Assemble security properties. */
        silc_ske_assemble_security_properties(
-                                 ske, SILC_SKE_SP_FLAG_MUTUAL, 
+                                 ske, SILC_SKE_SP_FLAG_MUTUAL,
                                  client->internal->silc_client_version,
                                  &start_payload);
 
@@ -332,8 +332,8 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
     break;
   case 2:
     {
-      /* 
-       * Phase 1 
+      /*
+       * Phase 1
        */
       if (ctx->responder == TRUE) {
        /* Sends the selected security properties to the initiator. */
@@ -365,8 +365,8 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
     break;
   case 3:
     {
-      /* 
-       * Phase 2 
+      /*
+       * Phase 2
        */
       if (ctx->responder == TRUE) {
        /* Process the received Key Exchange 1 Payload packet from
@@ -403,14 +403,14 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
     break;
   case 4:
     {
-      /* 
+      /*
        * Finish protocol
        */
       if (ctx->responder == TRUE) {
        /* This creates the key exchange material and sends our
           public parts to the initiator inside Key Exchange 2 Payload. */
-       status = 
-         silc_ske_responder_finish(ctx->ske, 
+       status =
+         silc_ske_responder_finish(ctx->ske,
                                    client->public_key, client->private_key,
                                    SILC_SKE_PK_TYPE_SILC);
 
@@ -430,7 +430,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
       if (status != SILC_SKE_STATUS_OK) {
         if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY) {
           client->internal->ops->say(
-                            client, conn, SILC_CLIENT_MESSAGE_AUDIT, 
+                            client, conn, SILC_CLIENT_MESSAGE_AUDIT,
                             "Received unsupported server %s public key",
                             ctx->sock->hostname);
         } else {
@@ -448,7 +448,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
 
   case SILC_PROTOCOL_STATE_END:
     {
-      /* 
+      /*
        * End protocol
        */
       SilcSKEKeyMaterial *keymat;
@@ -472,7 +472,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
       if (ctx->responder == TRUE)
        silc_ske_end(ctx->ske);
 
-      /* Unregister the timeout task since the protocol has ended. 
+      /* Unregister the timeout task since the protocol has ended.
         This was the timeout task to be executed if the protocol is
         not completed fast enough. */
       if (ctx->timeout_task)
@@ -490,7 +490,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
     /*
      * Error during protocol
      */
-    
+
     /* Send abort notification */
     silc_ske_abort(ctx->ske, ctx->ske->status);
 
@@ -506,7 +506,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
      * Received failure from remote.
      */
 
-    /* Unregister the timeout task since the protocol has ended. 
+    /* Unregister the timeout task since the protocol has ended.
        This was the timeout task to be executed if the protocol is
        not completed fast enough. */
     if (ctx->timeout_task)
@@ -552,7 +552,7 @@ silc_client_get_public_key_auth(SilcClient client,
                                          ske->start_payload_copy->len),
                     SILC_STR_END);
 
-  if (silc_pkcs_sign_with_hash(pkcs, ske->prop->hash, auth->data, 
+  if (silc_pkcs_sign_with_hash(pkcs, ske->prop->hash, auth->data,
                               auth->len, auth_data, auth_data_len)) {
     silc_buffer_free(auth);
     return TRUE;
@@ -565,12 +565,12 @@ silc_client_get_public_key_auth(SilcClient client,
 /* Continues the connection authentication protocol. This funtion may
    be called directly or used as SilcAskPassphrase callback. */
 
-static void 
+static void
 silc_client_conn_auth_continue(unsigned char *auth_data,
                               SilcUInt32 auth_data_len, void *context)
 {
   SilcProtocol protocol = (SilcProtocol)context;
-  SilcClientConnAuthInternalContext *ctx = 
+  SilcClientConnAuthInternalContext *ctx =
     (SilcClientConnAuthInternalContext *)protocol->context;
   SilcClient client = (SilcClient)ctx->client;
   SilcBuffer packet;
@@ -580,12 +580,12 @@ silc_client_conn_auth_continue(unsigned char *auth_data,
   SILC_LOG_DEBUG(("Sending authentication to server"));
 
   /* Passphrase must be UTF-8 encoded, if it isn't encode it */
-  if (ctx->auth_meth == SILC_AUTH_PASSWORD && 
+  if (ctx->auth_meth == SILC_AUTH_PASSWORD &&
       !silc_utf8_valid(auth_data, auth_data_len)) {
-    payload_len = silc_utf8_encoded_len(auth_data, auth_data_len, 
+    payload_len = silc_utf8_encoded_len(auth_data, auth_data_len,
                                        SILC_STRING_ASCII);
     autf8 = silc_calloc(payload_len, sizeof(*autf8));
-    auth_data_len = silc_utf8_encode(auth_data, auth_data_len, 
+    auth_data_len = silc_utf8_encode(auth_data, auth_data_len,
                                     SILC_STRING_ASCII, autf8, payload_len);
     auth_data = autf8;
   }
@@ -606,15 +606,15 @@ silc_client_conn_auth_continue(unsigned char *auth_data,
                          packet->data, packet->len, TRUE);
   silc_buffer_free(packet);
   silc_free(autf8);
-      
+
   /* Next state is end of protocol */
   protocol->state = SILC_PROTOCOL_STATE_END;
 }
-                                                   
+
 SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
 {
   SilcProtocol protocol = (SilcProtocol)context;
-  SilcClientConnAuthInternalContext *ctx = 
+  SilcClientConnAuthInternalContext *ctx =
     (SilcClientConnAuthInternalContext *)protocol->context;
   SilcClient client = (SilcClient)ctx->client;
   SilcClientConnection conn = ctx->sock->user_data;
@@ -627,7 +627,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
   switch(protocol->state) {
   case SILC_PROTOCOL_STATE_START:
     {
-      /* 
+      /*
        * Start protocol. We send authentication data to the server
        * to be authenticated.
        */
@@ -661,14 +661,14 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
       case SILC_AUTH_PUBLIC_KEY:
        if (!ctx->auth_data) {
          /* Public key authentication */
-         silc_client_get_public_key_auth(client, conn, sign, &auth_data_len, 
+         silc_client_get_public_key_auth(client, conn, sign, &auth_data_len,
                                          ctx->ske);
          auth_data = sign;
        } else {
          auth_data = ctx->auth_data;
          auth_data_len = ctx->auth_data_len;
        }
-       
+
        break;
       }
 
@@ -679,7 +679,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
 
   case SILC_PROTOCOL_STATE_END:
     {
-      /* 
+      /*
        * End protocol. Nothing special to be done here.
        */
 
@@ -693,7 +693,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
 
   case SILC_PROTOCOL_STATE_ERROR:
     {
-      /* 
+      /*
        * Error. Send notify to remote.
        */
       unsigned char error[4];
@@ -735,7 +735,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
 
 /* Actually takes the new keys into use. */
 
-static void 
+static void
 silc_client_protocol_rekey_validate(SilcClient client,
                                    SilcClientRekeyInternalContext *ctx,
                                    SilcSocketConnection sock,
@@ -746,24 +746,24 @@ silc_client_protocol_rekey_validate(SilcClient client,
 
   if (ctx->responder == TRUE) {
     if (send) {
-      silc_cipher_set_key(conn->internal->send_key, keymat->receive_enc_key, 
+      silc_cipher_set_key(conn->internal->send_key, keymat->receive_enc_key,
                          keymat->enc_key_len);
       silc_cipher_set_iv(conn->internal->send_key, keymat->receive_iv);
-      silc_hmac_set_key(conn->internal->hmac_send, keymat->receive_hmac_key, 
+      silc_hmac_set_key(conn->internal->hmac_send, keymat->receive_hmac_key,
                        keymat->hmac_key_len);
     } else {
-      silc_cipher_set_key(conn->internal->receive_key, keymat->send_enc_key, 
+      silc_cipher_set_key(conn->internal->receive_key, keymat->send_enc_key,
                          keymat->enc_key_len);
       silc_cipher_set_iv(conn->internal->receive_key, keymat->send_iv);
-      silc_hmac_set_key(conn->internal->hmac_receive, keymat->send_hmac_key, 
+      silc_hmac_set_key(conn->internal->hmac_receive, keymat->send_hmac_key,
                        keymat->hmac_key_len);
     }
   } else {
     if (send) {
-      silc_cipher_set_key(conn->internal->send_key, keymat->send_enc_key, 
+      silc_cipher_set_key(conn->internal->send_key, keymat->send_enc_key,
                          keymat->enc_key_len);
       silc_cipher_set_iv(conn->internal->send_key, keymat->send_iv);
-      silc_hmac_set_key(conn->internal->hmac_send, keymat->send_hmac_key, 
+      silc_hmac_set_key(conn->internal->hmac_send, keymat->send_hmac_key,
                        keymat->hmac_key_len);
     } else {
       silc_cipher_set_key(conn->internal->receive_key,
@@ -788,7 +788,7 @@ silc_client_protocol_rekey_validate(SilcClient client,
 /* This function actually re-generates (when not using PFS) the keys and
    takes them into use. */
 
-static void 
+static void
 silc_client_protocol_rekey_generate(SilcClient client,
                                    SilcClientRekeyInternalContext *ctx,
                                    bool send)
@@ -805,7 +805,7 @@ silc_client_protocol_rekey_generate(SilcClient client,
   keymat = silc_calloc(1, sizeof(*keymat));
   silc_ske_process_key_material_data(conn->internal->rekey->send_enc_key,
                                     conn->internal->rekey->enc_key_len,
-                                    16, key_len, hash_len, 
+                                    16, key_len, hash_len,
                                     conn->internal->hash, keymat);
 
   /* Set the keys into use */
@@ -817,7 +817,7 @@ silc_client_protocol_rekey_generate(SilcClient client,
 /* This function actually re-generates (with PFS) the keys and
    takes them into use. */
 
-static void 
+static void
 silc_client_protocol_rekey_generate_pfs(SilcClient client,
                                        SilcClientRekeyInternalContext *ctx,
                                        bool send)
@@ -837,7 +837,7 @@ silc_client_protocol_rekey_generate_pfs(SilcClient client,
 
   /* Generate the new key */
   keymat = silc_calloc(1, sizeof(*keymat));
-  silc_ske_process_key_material_data(tmpbuf, klen, 16, key_len, hash_len, 
+  silc_ske_process_key_material_data(tmpbuf, klen, 16, key_len, hash_len,
                                     conn->internal->hash, keymat);
 
   /* Set the keys into use */
@@ -851,14 +851,14 @@ silc_client_protocol_rekey_generate_pfs(SilcClient client,
 /* Packet sending callback. This function is provided as packet sending
    routine to the Key Exchange functions. */
 
-static void 
+static void
 silc_client_protocol_rekey_send_packet(SilcSKE ske,
                                       SilcBuffer packet,
                                       SilcPacketType type,
                                       void *context)
 {
   SilcProtocol protocol = (SilcProtocol)context;
-  SilcClientRekeyInternalContext *ctx = 
+  SilcClientRekeyInternalContext *ctx =
     (SilcClientRekeyInternalContext *)protocol->context;
   SilcClient client = (SilcClient)ctx->client;
 
@@ -872,7 +872,7 @@ silc_client_protocol_rekey_send_packet(SilcSKE ske,
 SILC_TASK_CALLBACK(silc_client_protocol_rekey)
 {
   SilcProtocol protocol = (SilcProtocol)context;
-  SilcClientRekeyInternalContext *ctx = 
+  SilcClientRekeyInternalContext *ctx =
     (SilcClientRekeyInternalContext *)protocol->context;
   SilcClient client = (SilcClient)ctx->client;
   SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
@@ -888,7 +888,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey)
   switch(protocol->state) {
   case SILC_PROTOCOL_STATE_START:
     {
-      /* 
+      /*
        * Start protocol.
        */
 
@@ -898,7 +898,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey)
         */
 
        if (ctx->pfs == TRUE) {
-         /* 
+         /*
           * Use Perfect Forward Secrecy, ie. negotiate the key material
           * using the SKE protocol.
           */
@@ -914,16 +914,16 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey)
          silc_ske_group_get_by_number(conn->internal->rekey->ske_group,
                                       &ctx->ske->prop->group);
 
-         silc_ske_set_callbacks(ctx->ske, 
+         silc_ske_set_callbacks(ctx->ske,
                                 silc_client_protocol_rekey_send_packet,
                                 NULL,  NULL, NULL, silc_ske_check_version,
                                 context);
-      
+
          status = silc_ske_responder_phase_2(ctx->ske, ctx->packet->buffer);
          if (status != SILC_SKE_STATUS_OK) {
            SILC_LOG_WARNING(("Error (type %d) during Re-key (PFS)",
                              status));
-           
+
            protocol->state = SILC_PROTOCOL_STATE_ERROR;
            silc_protocol_execute(protocol, client->schedule, 0, 300000);
            return;
@@ -938,30 +938,31 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey)
           */
 
          /* Send the REKEY_DONE to indicate we will take new keys into use */
-         silc_client_packet_send(client, ctx->sock, 
-                                 SILC_PACKET_REKEY_DONE, 
+         silc_client_packet_send(client, ctx->sock,
+                                 SILC_PACKET_REKEY_DONE,
                                  NULL, 0, NULL, NULL, NULL, 0, FALSE);
 
          /* After we send REKEY_DONE we must set the sending encryption
             key to the new key since all packets after this packet must
             encrypted with the new key. */
          silc_client_protocol_rekey_generate(client, ctx, TRUE);
+         silc_client_packet_queue_purge(client, ctx->sock);
 
          /* The protocol ends in next stage. */
          protocol->state = SILC_PROTOCOL_STATE_END;
        }
-      
+
       } else {
        /*
         * We are the initiator of this protocol
         */
 
        /* Start the re-key by sending the REKEY packet */
-       silc_client_packet_send(client, ctx->sock, SILC_PACKET_REKEY, 
+       silc_client_packet_send(client, ctx->sock, SILC_PACKET_REKEY,
                                NULL, 0, NULL, NULL, NULL, 0, FALSE);
 
        if (ctx->pfs == TRUE) {
-         /* 
+         /*
           * Use Perfect Forward Secrecy, ie. negotiate the key material
           * using the SKE protocol.
           */
@@ -970,16 +971,16 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey)
          silc_ske_group_get_by_number(conn->internal->rekey->ske_group,
                                       &ctx->ske->prop->group);
 
-         silc_ske_set_callbacks(ctx->ske, 
+         silc_ske_set_callbacks(ctx->ske,
                                 silc_client_protocol_rekey_send_packet,
                                 NULL,  NULL, NULL, silc_ske_check_version,
                                 context);
-      
+
          status =  silc_ske_initiator_phase_2(ctx->ske, NULL, NULL, 0);
          if (status != SILC_SKE_STATUS_OK) {
            SILC_LOG_WARNING(("Error (type %d) during Re-key (PFS)",
                              status));
-           
+
            protocol->state = SILC_PROTOCOL_STATE_ERROR;
            silc_protocol_execute(protocol, client->schedule, 0, 300000);
            return;
@@ -992,16 +993,17 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey)
           * Do normal and simple re-key.
           */
 
-         /* Send the REKEY_DONE to indicate we will take new keys into use 
-            now. */ 
-         silc_client_packet_send(client, ctx->sock, 
-                                 SILC_PACKET_REKEY_DONE, 
+         /* Send the REKEY_DONE to indicate we will take new keys into use
+            now. */
+         silc_client_packet_send(client, ctx->sock,
+                                 SILC_PACKET_REKEY_DONE,
                                  NULL, 0, NULL, NULL, NULL, 0, FALSE);
 
          /* After we send REKEY_DONE we must set the sending encryption
             key to the new key since all packets after this packet must
             encrypted with the new key. */
          silc_client_protocol_rekey_generate(client, ctx, TRUE);
+         silc_client_packet_queue_purge(client, ctx->sock);
 
          /* The protocol ends in next stage. */
          protocol->state = SILC_PROTOCOL_STATE_END;
@@ -1020,13 +1022,13 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey)
         * Send our KE packe to the initiator now that we've processed
         * the initiator's KE packet.
         */
-       status = silc_ske_responder_finish(ctx->ske, NULL, NULL, 
+       status = silc_ske_responder_finish(ctx->ske, NULL, NULL,
                                           SILC_SKE_PK_TYPE_SILC);
 
          if (status != SILC_SKE_STATUS_OK) {
            SILC_LOG_WARNING(("Error (type %d) during Re-key (PFS)",
                              status));
-           
+
            protocol->state = SILC_PROTOCOL_STATE_ERROR;
            silc_protocol_execute(protocol, client->schedule, 0, 300000);
            return;
@@ -1043,12 +1045,12 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey)
          protocol->state = SILC_PROTOCOL_STATE_ERROR;
          silc_protocol_execute(protocol, client->schedule, 0, 300000);
        }
-       
+
        status = silc_ske_initiator_finish(ctx->ske, ctx->packet->buffer);
        if (status != SILC_SKE_STATUS_OK) {
          SILC_LOG_WARNING(("Error (type %d) during Re-key (PFS)",
                            status));
-         
+
          protocol->state = SILC_PROTOCOL_STATE_ERROR;
          silc_protocol_execute(protocol, client->schedule, 0, 300000);
          return;
@@ -1056,11 +1058,11 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey)
       }
     }
 
-    /* Send the REKEY_DONE to indicate we will take new keys into use 
-       now. */ 
-    silc_client_packet_send(client, ctx->sock, SILC_PACKET_REKEY_DONE, 
+    /* Send the REKEY_DONE to indicate we will take new keys into use
+       now. */
+    silc_client_packet_send(client, ctx->sock, SILC_PACKET_REKEY_DONE,
                            NULL, 0, NULL, NULL, NULL, 0, FALSE);
-    
+
     /* After we send REKEY_DONE we must set the sending encryption
        key to the new key since all packets after this packet must
        encrypted with the new key. */
@@ -1071,7 +1073,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey)
     break;
 
   case SILC_PROTOCOL_STATE_END:
-    /* 
+    /*
      * End protocol
      */
 
index 5750bb203c4239aee49d1e6f6becab9333080e2b..e73e7945097b7b2119c237f4ca10fa53ac43d38d 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  silcclient.h 
+  silcclient.h
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2000 - 2002 Pekka Riikonen
+  Copyright (C) 2000 - 2003 Pekka Riikonen
 
   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
@@ -82,7 +82,7 @@ struct SilcClientStruct {
   char *username;               /* Username, MUST be set by application */
   char *hostname;               /* hostname, MUST be set by application */
   char *realname;               /* Real name, MUST be set be application */
-  
+
   SilcPublicKey public_key;     /* Public key of user, set by application */
   SilcPrivateKey private_key;   /* Private key of user, set by application */
   SilcPKCS pkcs;                /* PKCS allocated by application */
@@ -93,16 +93,16 @@ struct SilcClientStruct {
 
   /* Scheduler, set by library.  Application may use this pointer. */
   SilcSchedule schedule;
-  
+
   /* Random Number Generator. Application should use this as its primary
      random number generator. */
   SilcRng rng;
-  
+
   /* Application specific user data pointer. Client library does not
      touch this.  This the context sent as argument to silc_client_alloc.
      Application can use it freely. */
   void *application;
-     
+
   /* Generic hash context for application usage */
   SilcHash md5hash;
   SilcHash sha1hash;
@@ -110,7 +110,7 @@ struct SilcClientStruct {
   /* Internal data for client library. Application cannot access this
      data at all. */
   SilcClientInternal internal;
-};  
+};
 /***/
 
 /****s* silcclient/SilcClientAPI/SilcClientConnection
@@ -218,7 +218,7 @@ struct SilcClientEntryStruct {
   SilcHmac hmac_send;          /* Private mesage key HMAC for sending */
   SilcHmac hmac_receive;       /* Private mesage key HMAC for receiving */
   unsigned char *key;          /* Set only if application provided the
-                                  key material. NULL if the library 
+                                  key material. NULL if the library
                                   generated the key. */
   SilcUInt32 key_len;          /* Key length */
   SilcClientKeyAgreement ke;   /* Current key agreement context or NULL */
@@ -253,7 +253,8 @@ struct SilcChannelEntryStruct {
   SilcChannelID *id;                        /* Channel ID */
   SilcUInt32 mode;                          /* Channel mode */
 
-  /* All clients that has joined this channel */
+  /* All clients that has joined this channel.  The key to the table is the
+     SilcClientEntry and the context is SilcChannelUser context. */
   SilcHashTable user_list;
 
   /* Channel keys */
@@ -268,9 +269,8 @@ struct SilcChannelEntryStruct {
   SilcChannelPrivateKey curr_key;           /* Current private key */
 
   /* SilcChannelEntry status information */
-  SilcCipher old_channel_key;
-  SilcHmac old_hmac;
-  SilcTask rekey_task;
+  SilcDList old_channel_keys;
+  SilcDList old_hmacs;
   SilcUInt16 resolve_cmd_ident;                     /* Command identifier when
                                                resolving this entry */
 };
@@ -309,7 +309,7 @@ struct SilcServerEntryStruct {
  * DESCRIPTION
  *
  *    Key agreement status types indicating the status of the key
- *    agreement protocol.  These types are returned to the application 
+ *    agreement protocol.  These types are returned to the application
  *    in the SilcKeyAgreementCallback callback function.
  *
  * SOURCE
@@ -442,11 +442,11 @@ typedef void (*SilcVerifyPublicKey)(bool success, void *context);
  *
  * SYNOPSIS
  *
- *    typedef void (*SilcGetAuthMeth)(bool success, 
+ *    typedef void (*SilcGetAuthMeth)(bool success,
  *                                    SilcProtocolAuthMeth auth_meth,
  *                                    const unsigned char *auth_data,
  *                                    SilcUInt32 auth_data_len, void *context);
- * 
+ *
  * DESCRIPTION
  *
  *    Authentication method resolving callback. This is called by the
@@ -459,7 +459,7 @@ typedef void (*SilcVerifyPublicKey)(bool success, void *context);
  *    context sent to the get_auth_method client operation.
  *
  ***/
-typedef void (*SilcGetAuthMeth)(bool success, 
+typedef void (*SilcGetAuthMeth)(bool success,
                                SilcProtocolAuthMeth auth_meth,
                                const unsigned char *auth_data,
                                SilcUInt32 auth_data_len, void *context);
@@ -524,29 +524,29 @@ typedef enum {
  */
 typedef struct {
   /* Message sent to the application by library. `conn' associates the
-     message to a specific connection.  `conn', however, may be NULL. 
+     message to a specific connection.  `conn', however, may be NULL.
      The `type' indicates the type of the message sent by the library.
      The application can for example filter the message according the
      type.  The variable argument list is arguments to the formatted
      message that `msg' may be. */
-  void (*say)(SilcClient client, SilcClientConnection conn, 
+  void (*say)(SilcClient client, SilcClientConnection conn,
              SilcClientMessageType type, char *msg, ...);
 
-  /* Message for a channel. The `sender' is the sender of the message 
-     The `channel' is the channel. The `message' is the message.  Note 
-     that `message' maybe NULL.  The `flags' indicates message flags 
+  /* Message for a channel. The `sender' is the sender of the message
+     The `channel' is the channel. The `message' is the message.  Note
+     that `message' maybe NULL.  The `flags' indicates message flags
      and it is used to determine how the message can be interpreted
      (like it may tell the message is multimedia message). */
-  void (*channel_message)(SilcClient client, SilcClientConnection conn, 
-                         SilcClientEntry sender, SilcChannelEntry channel, 
+  void (*channel_message)(SilcClient client, SilcClientConnection conn,
+                         SilcClientEntry sender, SilcChannelEntry channel,
                          SilcMessagePayload payload, SilcMessageFlags flags,
                          const unsigned char *message,
                          SilcUInt32 message_len);
 
   /* Private message to the client. The `sender' is the sender of the
-     message. The message is `message'and maybe NULL.  The `flags' 
-     indicates message flags  and it is used to determine how the message 
-     can be interpreted (like it may tell the message is multimedia 
+     message. The message is `message'and maybe NULL.  The `flags'
+     indicates message flags  and it is used to determine how the message
+     can be interpreted (like it may tell the message is multimedia
      message). */
   void (*private_message)(SilcClient client, SilcClientConnection conn,
                          SilcClientEntry sender, SilcMessagePayload payload,
@@ -562,7 +562,7 @@ typedef struct {
      for channel the channel entry is sent to application (even if server
      does not send it because client library gets the channel entry from
      the Channel ID in the packet's header). */
-  void (*notify)(SilcClient client, SilcClientConnection conn, 
+  void (*notify)(SilcClient client, SilcClientConnection conn,
                 SilcNotifyType type, ...);
 
   /* Command handler. This function is called always in the command function.
@@ -573,7 +573,7 @@ typedef struct {
      noted that this is not reply from server. This is merely called just
      after application has called the command. Just to tell application
      that the command really was processed. */
-  void (*command)(SilcClient client, SilcClientConnection conn, 
+  void (*command)(SilcClient client, SilcClientConnection conn,
                  SilcClientCommandContext cmd_context, bool success,
                  SilcCommand command, SilcStatus status);
 
@@ -581,8 +581,8 @@ typedef struct {
      function. If error occurs it will be called as well. Normal scenario
      is that it will be called after the received command data has been parsed
      and processed. The function is used to pass the received command data to
-     the application. 
-     
+     the application.
+
      `conn' is the associated client connection. `cmd_payload' is the command
      payload data received from server and it can be ignored. It is provided
      if the application would like to re-parse the received command data,
@@ -594,10 +594,10 @@ typedef struct {
      command defines the number and type of arguments it passes to the
      application (on error they are not sent).
 
-     The arguments are sent in the same order as servers sends them.  The 
-     arguments are same as received from the server except for ID's.  If 
-     ID is received application receives the corresponding entry to the 
-     ID. For example, if Client ID is receives application receives 
+     The arguments are sent in the same order as servers sends them.  The
+     arguments are same as received from the server except for ID's.  If
+     ID is received application receives the corresponding entry to the
+     ID. For example, if Client ID is receives application receives
      SilcClientEntry. */
   void (*command_reply)(SilcClient client, SilcClientConnection conn,
                        SilcCommandPayload cmd_payload, bool success,
@@ -630,11 +630,11 @@ typedef struct {
 
   /* Verifies received public key. The `conn_type' indicates which entity
      (server, client etc.) has sent the public key. If user decides to trust
-     the application may save the key as trusted public key for later 
-     use. The `completion' must be called after the public key has been 
+     the application may save the key as trusted public key for later
+     use. The `completion' must be called after the public key has been
      verified. */
   void (*verify_public_key)(SilcClient client, SilcClientConnection conn,
-                           SilcSocketType conn_type, unsigned char *pk, 
+                           SilcSocketType conn_type, unsigned char *pk,
                            SilcUInt32 pk_len, SilcSKEPKType pk_type,
                            SilcVerifyPublicKey completion, void *context);
 
@@ -652,7 +652,7 @@ typedef struct {
      application must explicitly cast it to correct type.  Usually `failure'
      is 32 bit failure type (see protocol specs for all protocol failure
      types). */
-  void (*failure)(SilcClient client, SilcClientConnection conn, 
+  void (*failure)(SilcClient client, SilcClientConnection conn,
                  SilcProtocol protocol, void *failure);
 
   /* Asks whether the user would like to perform the key agreement protocol.
@@ -678,10 +678,10 @@ typedef struct {
              const char *hostname, SilcUInt16 port);
 
   /* Delivers SILC session detachment data indicated by `detach_data' to the
-     application.  If application has issued SILC_COMMAND_DETACH command     
-     the client session in the SILC network is not quit.  The client remains 
+     application.  If application has issued SILC_COMMAND_DETACH command
+     the client session in the SILC network is not quit.  The client remains
      in the network but is detached.  The detachment data may be used later
-     to resume the session in the SILC Network.  The appliation is   
+     to resume the session in the SILC Network.  The appliation is
      responsible of saving the `detach_data', to for example in a file.
 
      The detachment data can be given as argument to the functions
@@ -745,12 +745,12 @@ typedef struct {
 
   /* Connection authentication method request timeout. If server does not
      reply back the current authentication method when we've requested it
-     in this time interval we'll assume the reply will not come at all. 
+     in this time interval we'll assume the reply will not come at all.
      If set to zero, the default value (2 seconds) will be used. */
   unsigned int connauth_request_secs;
 
   /* Nickname format string. This can be used to order the client library
-     to save the nicknames in the library in a certain format. Since 
+     to save the nicknames in the library in a certain format. Since
      nicknames are not unique in SILC it is possible to have multiple same
      nicknames. Using this format string it is possible to order the library
      to separate the multiple same nicknames from each other. The format
@@ -758,9 +758,9 @@ typedef struct {
      string. If this is NULL then default format is used which is the
      default nickname without anything else. The string MUST be NULL
      terminated.
-     
+
      Following format types are available:
-     
+
      %n  nickname      - the real nickname returned by the server (mandatory)
      %h  hostname      - the stripped hostname of the client
      %H  full hostname - the full hostname of the client
@@ -782,7 +782,7 @@ typedef struct {
   char nickname_format[32];
 
   /* If this is set to TRUE then the `nickname_format' is employed to all
-     saved nicknames even if there are no multiple same nicknames in the 
+     saved nicknames even if there are no multiple same nicknames in the
      cache. By default this is FALSE, which means that the `nickname_format'
      is employed only if the library will receive a nickname that is
      already saved in the cache. It is recommended to leave this to FALSE
@@ -817,7 +817,7 @@ typedef struct {
  *
  * SYNOPSIS
  *
- *    SilcClient silc_client_alloc(SilcClientOperations *ops, 
+ *    SilcClient silc_client_alloc(SilcClientOperations *ops,
  *                                 SilcClientParams *params,
  *                                 void *application,
  *                                 const char *silc_version);
@@ -833,7 +833,7 @@ typedef struct {
  *    application by client->application, client being SilcClient.
  *
  ***/
-SilcClient silc_client_alloc(SilcClientOperations *ops, 
+SilcClient silc_client_alloc(SilcClientOperations *ops,
                             SilcClientParams *params,
                             void *application,
                             const char *version_string);
@@ -956,14 +956,14 @@ typedef struct {
  *
  * SYNOPSIS
  *
- *    bool silc_client_connect_to_server(SilcClient client, 
+ *    int silc_client_connect_to_server(SilcClient client,
  *                                      SilcClientConnectionParams *params,
  *                                      int port, char *host, void *context);
  *
  * DESCRIPTION
  *
  *    Connects to remote server. This is the main routine used to connect
- *    to SILC server. Returns -1 on error and the created socket otherwise. 
+ *    to SILC server. Returns -1 on error and the created socket otherwise.
  *    The `context' is user context that is saved into the SilcClientConnection
  *    that is created after the connection is created. Note that application
  *    may handle the connecting process outside the library. If this is the
@@ -973,9 +973,9 @@ typedef struct {
  *    If the `params' is provided they are used by the routine.
  *
  ***/
-bool silc_client_connect_to_server(SilcClient client, 
-                                  SilcClientConnectionParams *params,
-                                  int port, char *host, void *context);
+int silc_client_connect_to_server(SilcClient client,
+                                 SilcClientConnectionParams *params,
+                                 int port, char *host, void *context);
 
 /****f* silcclient/SilcClientAPI/silc_client_add_connection
  *
@@ -993,12 +993,12 @@ bool silc_client_connect_to_server(SilcClient client,
  *    connection to the connection table and returns a pointer to it. A client
  *    can have multiple connections to multiple servers. Every connection must
  *    be added to the client using this function. User data `context' may
- *    be sent as argument.  If the `params' is provided they are used by 
+ *    be sent as argument.  If the `params' is provided they are used by
  *    the routine.
  *
  * NOTES
  *
- *    This function is normally used only if the application performed 
+ *    This function is normally used only if the application performed
  *    the connecting outside the library, and did not called the
  *    silc_client_connect_to_server function at all. The library
  *    however may use this internally.
@@ -1013,7 +1013,7 @@ silc_client_add_connection(SilcClient client,
  *
  * SYNOPSIS
  *
- *    void silc_client_del_connection(SilcClient client, 
+ *    void silc_client_del_connection(SilcClient client,
  *                                    SilcClientConnection conn);
  *
  * DESCRIPTION
@@ -1030,7 +1030,7 @@ void silc_client_del_connection(SilcClient client, SilcClientConnection conn);
  *
  * SYNOPSIS
  *
- *    void silc_client_add_socket(SilcClient client, 
+ *    void silc_client_add_socket(SilcClient client,
  *                                SilcSocketConnection sock);
  *
  * DESCRIPTION
@@ -1046,7 +1046,7 @@ void silc_client_add_socket(SilcClient client, SilcSocketConnection sock);
  *
  * SYNOPSIS
  *
- *    void silc_client_del_socket(SilcClient client, 
+ *    void silc_client_del_socket(SilcClient client,
  *                                SilcSocketConnection sock);
  *
  * DESCRIPTION
@@ -1076,6 +1076,12 @@ void silc_client_del_socket(SilcClient client, SilcSocketConnection sock);
  *    library. The library however may use this internally.  After the
  *    key exchange is performed the `connect' client operation is called.
  *
+ * NOTES
+ *
+ *    The silc_client_add_connection must be called before calling this
+ *    function to create the SilcClientConnection context for this
+ *    connection.
+ *
  ***/
 void silc_client_start_key_exchange(SilcClient client,
                                    SilcClientConnection conn,
@@ -1091,7 +1097,11 @@ void silc_client_start_key_exchange(SilcClient client,
  * DESCRIPTION
  *
  *    Closes connection to remote end. Free's all allocated data except
- *    for some information such as nickname etc. that are valid at all time. 
+ *    for some information such as nickname etc. that are valid at all time.
+ *    Usually application does not need to directly call this, except
+ *    when explicitly closing the connection, or if an error occurs
+ *    during connection to server (see 'connect' client operation for
+ *    more information).
  *
  ***/
 void silc_client_close_connection(SilcClient client,
@@ -1104,53 +1114,57 @@ void silc_client_close_connection(SilcClient client,
  *
  * SYNOPSIS
  *
- *    void silc_client_send_channel_message(SilcClient client, 
+ *    bool silc_client_send_channel_message(SilcClient client,
  *                                          SilcClientConnection conn,
  *                                          SilcChannelEntry channel,
  *                                          SilcChannelPrivateKey key,
  *                                          SilcMessageFlags flags,
- *                                          unsigned char *data, 
- *                                          SilcUInt32 data_len, 
+ *                                          unsigned char *data,
+ *                                          SilcUInt32 data_len,
  *                                          bool_force_send);
  *
  * DESCRIPTION
  *
  *    Sends packet to the `channel'. Packet to channel is always encrypted
- *    differently from "normal" packets. SILC header of the packet is 
+ *    differently from "normal" packets. SILC header of the packet is
  *    encrypted with the next receiver's key and the rest of the packet is
  *    encrypted with the channel specific key. Padding and HMAC is computed
  *    with the next receiver's key. The `data' is the channel message. If
- *    the `force_send' is TRUE then the packet is sent immediately. 
+ *    the `force_send' is TRUE then the packet is sent immediately.
  *
  *    If `key' is provided then that private key is used to encrypt the
  *    channel message.  If it is not provided, private keys has not been
  *    set at all, the normal channel key is used automatically.  If private
  *    keys are set then the first key (the key that was added first as
- *    private key) is used. 
+ *    private key) is used.
  *
  *    If the `flags' includes SILC_MESSAGE_FLAG_SIGNED the message will be
  *    digitally signed with the SILC key pair.
  *
+ *    Returns TRUE if the message was sent, and FALSE if error occurred or
+ *    the sending is not allowed due to channel modes (like sending is
+ *    blocked).
+ *
  ***/
-void silc_client_send_channel_message(SilcClient client, 
+bool silc_client_send_channel_message(SilcClient client,
                                      SilcClientConnection conn,
                                      SilcChannelEntry channel,
                                      SilcChannelPrivateKey key,
                                      SilcMessageFlags flags,
-                                     unsigned char *data, 
-                                     SilcUInt32 data_len, 
+                                     unsigned char *data,
+                                     SilcUInt32 data_len,
                                      bool force_send);
 
 /****f* silcclient/SilcClientAPI/silc_client_send_private_message
  *
  * SYNOPSIS
  *
- *    void silc_client_send_private_message(SilcClient client,
+ *    bool silc_client_send_private_message(SilcClient client,
  *                                          SilcClientConnection conn,
  *                                          SilcClientEntry client_entry,
  *                                          SilcMessageFlags flags,
- *                                          unsigned char *data, 
- *                                          SilcUInt32 data_len, 
+ *                                          unsigned char *data,
+ *                                          SilcUInt32 data_len,
  *                                          bool force_send);
  *
  * DESCRIPTION
@@ -1161,18 +1175,20 @@ void silc_client_send_channel_message(SilcClient client,
  *    network hence we need this own function for them. This is similar
  *    to silc_client_packet_send_to_channel except that we send private
  *    message. The `data' is the private message. If the `force_send' is
- *    TRUE the packet is sent immediately. 
+ *    TRUE the packet is sent immediately.
  *
  *    If the `flags' includes SILC_MESSAGE_FLAG_SIGNED the message will be
  *    digitally signed with the SILC key pair.
  *
+ *    Returns TRUE if the message was sent, and FALSE if error occurred.
+ *
  ***/
-void silc_client_send_private_message(SilcClient client,
+bool silc_client_send_private_message(SilcClient client,
                                      SilcClientConnection conn,
                                      SilcClientEntry client_entry,
                                      SilcMessageFlags flags,
-                                     unsigned char *data, 
-                                     SilcUInt32 data_len, 
+                                     unsigned char *data,
+                                     SilcUInt32 data_len,
                                      bool force_send);
 
 
@@ -1215,10 +1231,11 @@ typedef void (*SilcGetClientCallback)(SilcClient client,
  *
  * DESCRIPTION
  *
- *    Finds client entry or entries by the `nickname' and `server'. The 
+ *    Finds client entry or entries by the `nickname' and `server'. The
  *    completion callback will be called when the client entries has been
  *    found.  After the server returns the client information it is cached
- *    and can be accesses locally at a later time.
+ *    and can be accesses locally at a later time.  The resolving is done
+ *    with IDENTIFY command.  The `server' may be NULL.
  *
  * NOTES
  *
@@ -1226,7 +1243,13 @@ typedef void (*SilcGetClientCallback)(SilcClient client,
  *    information from the server. Thus, if you already know the client
  *    information then use the silc_client_get_client_by_id function to
  *    get the client entry since this function may be very slow and should
- *    be used only to initially get the client entries. 
+ *    be used only to initially get the client entries.
+ *
+ *    Since this routine resolves with IDENTIFY command only the relevant
+ *    information (user's nickname and username) is resolved.  For example,
+ *    user's real name, channel list and others are not resolved.  Caller
+ *    can/must resolve those separately if they are needed (for example,
+ *    with silc_client_get_client_by_id_resolve).
  *
  ***/
 void silc_client_get_clients(SilcClient client,
@@ -1265,6 +1288,46 @@ SilcClientEntry *silc_client_get_clients_local(SilcClient client,
                                               const char *format,
                                               SilcUInt32 *clients_count);
 
+/****f* silcclient/SilcClientAPI/silc_client_get_clients_by_channel
+ *
+ * SYNOPSIS
+ *
+ *    void silc_client_get_clients_by_channel(SilcClient client,
+ *                                            SilcClientConnection conn,
+ *                                            SilcChannelEntry channel,
+ *                                            SilcGetClientCallback completion,
+ *                                            void *context);
+ *
+ * DESCRIPTION
+ *
+ *    Gets client entries by the channel indicated by `channel'. Thus,
+ *    it resovles the users currently on that channel. If all users are
+ *    already resolved this returns the users from the channel. If the
+ *    users are resolved only partially this resolves the complete user
+ *    information. If no users are resolved on this channel at all, this
+ *    calls USERS command to resolve all users on the channel. The `completion'
+ *    will be called after the entries are available. When server returns
+ *    the client information it will be cached and can be accessed locally
+ *    at a later time.
+ *
+ *    This function can be used for example in SILC_COMMAND_JOIN command
+ *    reply handling in application to resolve users on that channel.  It
+ *    also can be used after calling silc_client_get_channel_resolve to
+ *    resolve users on that channel.
+ *
+ * NOTES
+ *
+ *    The resolving is done with WHOIS command. For this reason this
+ *    command may take a long time because it resolves detailed user
+ *    information.
+ *
+ ***/
+void silc_client_get_clients_by_channel(SilcClient client,
+                                       SilcClientConnection conn,
+                                       SilcChannelEntry channel,
+                                       SilcGetClientCallback completion,
+                                       void *context);
+
 /****f* silcclient/SilcClientAPI/silc_client_get_clients_by_list
  *
  * SYNOPSIS
@@ -1287,6 +1350,14 @@ SilcClientEntry *silc_client_get_clients_local(SilcClient client,
  *    the client information it will be cached and can be accessed locally
  *    at a later time.
  *
+ * NOTES
+ *
+ *    The resolving is done with IDENTIFY command. This means that only
+ *    the relevant information of user (it's nickname and username) is
+ *    resolved. For example, user's real name, channel lists and others
+ *    are not resolved. Caller can/must resolve those separately if they
+ *    are needed (for example, with silc_client_get_client_by_id_resolve).
+ *
  ***/
 void silc_client_get_clients_by_list(SilcClient client,
                                     SilcClientConnection conn,
@@ -1318,7 +1389,7 @@ SilcClientEntry silc_client_get_client_by_id(SilcClient client,
  *
  * SYNOPSIS
  *
- *    void 
+ *    void
  *    silc_client_get_client_by_id_resolve(SilcClient client,
  *                                         SilcClientConnection conn,
  *                                         SilcClientID *client_id,
@@ -1332,7 +1403,8 @@ SilcClientEntry silc_client_get_client_by_id(SilcClient client,
  *    information from the server. Use this only if you know that you
  *    do not have the entry and the only thing you know about the client
  *    is its ID. When server returns the client information it will be
- *    cache and can be accessed locally at a later time.
+ *    cache and can be accessed locally at a later time. The resolving
+ *    is done by sending WHOIS command.
  *
  *    If the `attributes' is non-NULL then the buffer includes Requested
  *    Attributes which can be used to fetch very detailed information
@@ -1395,18 +1467,44 @@ typedef void (*SilcGetChannelCallback)(SilcClient client,
  *
  *    SilcChannelEntry silc_client_get_channel(SilcClient client,
  *                                             SilcClientConnection conn,
- *                                             char *channel);
+ *                                             char *channel_name);
  *
  * DESCRIPTION
  *
  *    Finds entry for channel by the channel name. Returns the entry or NULL
  *    if the entry was not found. It is found only if the client is joined
- *    to the channel. 
+ *    to the channel.  Use silc_client_get_channel_resolve or
+ *    silc_client_get_channel_by_id_resolve to resolve channel that client
+ *    is not joined.
  *
  ***/
 SilcChannelEntry silc_client_get_channel(SilcClient client,
                                         SilcClientConnection conn,
-                                        char *channel);
+                                        char *channel_name);
+
+/****f* silcclient/SilcClientAPI/silc_client_get_channel_resolve
+ *
+ * SYNOPSIS
+ *
+ *    void silc_client_get_channel_resolve(SilcClient client,
+ *                                         SilcClientConnection conn,
+ *                                         char *channel_name,
+ *                                         SilcGetChannelCallback completion,
+ *                                         void *context);
+ *
+ * DESCRIPTION
+ *
+ *    Resolves entry for channel by the channel name from the server.
+ *    The resolving is done with IDENTIFY command. Note that users on
+ *    the channel are not resolved at the same time. Use for example
+ *    silc_client_get_clients_by_channel to resolve all users on a channel.
+ *
+ ***/
+void silc_client_get_channel_resolve(SilcClient client,
+                                    SilcClientConnection conn,
+                                    char *channel_name,
+                                    SilcGetChannelCallback completion,
+                                    void *context);
 
 /****f* silcclient/SilcClientAPI/silc_client_get_channel_by_id
  *
@@ -1431,7 +1529,7 @@ SilcChannelEntry silc_client_get_channel_by_id(SilcClient client,
  *
  * SYNOPSIS
  *
- *    void 
+ *    void
  *    silc_client_get_channel_by_id_resolve(SilcClient client,
  *                                          SilcClientConnection conn,
  *                                          SilcChannelID *channel_id,
@@ -1442,7 +1540,11 @@ SilcChannelEntry silc_client_get_channel_by_id(SilcClient client,
  *
  *    Resolves the channel information (its name mainly) from the server
  *    by the `channel_id'. Use this only if you know that you do not have
- *    the entry cached locally.
+ *    the entry cached locally. The resolving is done with IDENTIFY command.
+ *
+ *    Note that users on the channel are not resolved at the same time.
+ *    Use for example silc_client_get_clients_by_channel to resolve all
+ *    users on a channel.
  *
  ***/
 void silc_client_get_channel_by_id_resolve(SilcClient client,
@@ -1455,7 +1557,7 @@ void silc_client_get_channel_by_id_resolve(SilcClient client,
  *
  * SYNOPSIS
  *
- *    bool silc_client_del_channel(SilcClient client, 
+ *    bool silc_client_del_channel(SilcClient client,
  *                                 SilcClientConnection conn,
  *                                 SilcChannelEntry channel)
  *
@@ -1529,9 +1631,9 @@ bool silc_client_del_server(SilcClient client, SilcClientConnection conn,
  *
  * DESCRIPTION
  *
- *    Returns the ChannelUser entry if the `client_entry' is joined on the 
+ *    Returns the SilcChannelUser entry if the `client_entry' is joined on the
  *    channel indicated by the `channel'. NULL if client is not joined on
- *    the channel. 
+ *    the channel.
  *
  ***/
 SilcChannelUser silc_client_on_channel(SilcChannelEntry channel,
@@ -1585,7 +1687,7 @@ bool silc_client_command_call(SilcClient client,
  *
  * SYNOPSIS
  *
- *    void silc_client_command_send(SilcClient client, 
+ *    void silc_client_command_send(SilcClient client,
  *                                  SilcClientConnection conn,
  *                                  SilcCommand command, SilcUInt16 ident,
  *                                  SilcUInt32 argc, ...);
@@ -1629,13 +1731,13 @@ void silc_client_command_send(SilcClient client, SilcClientConnection conn,
  *    called when an command reply is received to an earlier sent command.
  *    The `reply_cmd' is the command that must be received in order for
  *    the pending command callback indicated by `callback' to be called.
- *    The `callback' will deliver the `context' and 
- *    SilcClientCommandReplyContext which includes the internals of the 
+ *    The `callback' will deliver the `context' and
+ *    SilcClientCommandReplyContext which includes the internals of the
  *    command reply.
  *
  *    The `ident' is a command identifier which was set for the earlier
  *    sent command.  The command reply will include the same identifier
- *    and pending command callback will be called when the reply is 
+ *    and pending command callback will be called when the reply is
  *    received with the same command identifier.  It is possible to
  *    add multiple pending command callbacks for same command and for
  *    same identifier.
@@ -1648,7 +1750,7 @@ void silc_client_command_send(SilcClient client, SilcClientConnection conn,
  *
  *    Note also that the application is notified about the received command
  *    reply through the `command_reply' client operation before calling
- *    the `callback` pending command callback.  That is the normal 
+ *    the `callback` pending command callback.  That is the normal
  *    command reply handling, and is called regardless whether pending
  *    command callbacks are used or not.
  *
@@ -1705,10 +1807,10 @@ void silc_client_command_pending(SilcClientConnection conn,
  *
  *    It is not necessary to set key for normal private message usage. If the
  *    key is not set then the private messages are encrypted using normal
- *    session keys. Setting the private key, however, increases the security. 
+ *    session keys. Setting the private key, however, increases the security.
  *
  *    Returns FALSE if the key is already set for the `client_entry', TRUE
- *    otherwise. 
+ *    otherwise.
  *
  ***/
 bool silc_client_add_private_message_key(SilcClient client,
@@ -1739,7 +1841,7 @@ bool silc_client_add_private_message_key(SilcClient client,
  *    from the SKE key material structure. This structure is received if
  *    the application uses the silc_client_send_key_agreement to negotiate
  *    the key material. The `cipher' and `hmac' SHOULD be provided as it is
- *    negotiated also in the SKE protocol. 
+ *    negotiated also in the SKE protocol.
  *
  ***/
 bool silc_client_add_private_message_key_ske(SilcClient client,
@@ -1762,7 +1864,7 @@ bool silc_client_add_private_message_key_ske(SilcClient client,
  *
  *    Removes the private message from the library. The key won't be used
  *    after this to protect the private messages with the remote `client_entry'
- *    client. Returns FALSE on error, TRUE otherwise. 
+ *    client. Returns FALSE on error, TRUE otherwise.
  *
  ***/
 bool silc_client_del_private_message_key(SilcClient client,
@@ -1777,16 +1879,16 @@ bool silc_client_del_private_message_key(SilcClient client,
  *    silc_client_list_private_message_keys(SilcClient client,
  *                                          SilcClientConnection conn,
  *                                          SilcUInt32 *key_count);
- * 
+ *
  * DESCRIPTION
  *
  *    Returns array of set private message keys associated to the connection
  *    `conn'. Returns allocated SilcPrivateMessageKeys array and the array
  *    count to the `key_count' argument. The array must be freed by the caller
- *    by calling the silc_client_free_private_message_keys function. Note: 
+ *    by calling the silc_client_free_private_message_keys function. Note:
  *    the keys returned in the array is in raw format. It might not be desired
  *    to show the keys as is. The application might choose not to show the keys
- *    at all or to show the fingerprints of the keys. 
+ *    at all or to show the fingerprints of the keys.
  *
  ***/
 SilcPrivateMessageKeys
@@ -1800,18 +1902,18 @@ silc_client_list_private_message_keys(SilcClient client,
  *
  *    void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
  *                                               SilcUInt32 key_count);
- * 
+ *
  * DESCRIPTION
  *
  *    Frees the SilcPrivateMessageKeys array returned by the function
- *    silc_client_list_private_message_keys. 
+ *    silc_client_list_private_message_keys.
  *
  ***/
 void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
                                           SilcUInt32 key_count);
 
 
-/* Channel private key management (client_channel.c, 
+/* Channel private key management (client_channel.c,
    SilcChannelPrivateKey is defined in idlist.h) */
 
 /****f* silcclient/SilcClientAPI/silc_client_add_channel_private_key
@@ -1826,7 +1928,7 @@ void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
  *                                             char *hmac,
  *                                             unsigned char *key,
  *                                             SilcUInt32 key_len);
- * 
+ *
  * DESCRIPTION
  *
  *    Adds private key for channel. This may be set only if the channel's mode
@@ -1840,12 +1942,12 @@ void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
  *
  *    The private key for channel is optional. If it is not set then the
  *    channel messages are encrypted using the channel key generated by the
- *    server. However, setting the private key (or keys) for the channel 
+ *    server. However, setting the private key (or keys) for the channel
  *    significantly adds security. If more than one key is set the library
  *    will automatically try all keys at the message decryption phase. Note:
  *    setting many keys slows down the decryption phase as all keys has to
  *    be tried in order to find the correct decryption key. However, setting
- *    a few keys does not have big impact to the decryption performace. 
+ *    a few keys does not have big impact to the decryption performace.
  *
  * NOTES
  *
@@ -1856,7 +1958,7 @@ void silc_client_free_private_message_keys(SilcPrivateMessageKeys keys,
  *    silc_client_send_key_agreement) then the `key' MUST be the
  *    key->send_enc_key as this is dictated by the SILC protocol. However,
  *    currently it is not expected that the SKE key material would be used
- *    as channel private key. However, this API allows it. 
+ *    as channel private key. However, this API allows it.
  *
  ***/
 bool silc_client_add_channel_private_key(SilcClient client,
@@ -1875,12 +1977,12 @@ bool silc_client_add_channel_private_key(SilcClient client,
  *    bool silc_client_del_channel_private_keys(SilcClient client,
  *                                              SilcClientConnection conn,
  *                                              SilcChannelEntry channel);
- * 
+ *
  * DESCRIPTION
  *
  *    Removes all private keys from the `channel'. The old channel key is used
  *    after calling this to protect the channel messages. Returns FALSE on
- *    on error, TRUE otherwise. 
+ *    on error, TRUE otherwise.
  *
  ***/
 bool silc_client_del_channel_private_keys(SilcClient client,
@@ -1895,15 +1997,15 @@ bool silc_client_del_channel_private_keys(SilcClient client,
  *                                            SilcClientConnection conn,
  *                                            SilcChannelEntry channel,
  *                                            SilcChannelPrivateKey key);
- * 
+ *
  * DESCRIPTION
  *
- *    Removes and frees private key `key' from the channel `channel'. 
- *    The `key' is retrieved by calling the function 
+ *    Removes and frees private key `key' from the channel `channel'.
+ *    The `key' is retrieved by calling the function
  *    silc_client_list_channel_private_keys. The key is not used after
  *    this. If the key was last private key then the old channel key is
  *    used hereafter to protect the channel messages. This returns FALSE
- *    on error, TRUE otherwise. 
+ *    on error, TRUE otherwise.
  *
  ***/
 bool silc_client_del_channel_private_key(SilcClient client,
@@ -1927,7 +2029,7 @@ bool silc_client_del_channel_private_key(SilcClient client,
  *    The caller must free the array by calling the function
  *    silc_client_free_channel_private_keys. The pointers in the array may be
  *    used to delete the specific key by giving the pointer as argument to the
- *    function silc_client_del_channel_private_key. 
+ *    function silc_client_del_channel_private_key.
  *
  ***/
 SilcChannelPrivateKey *
@@ -2004,11 +2106,11 @@ void silc_client_current_channel_private_key(SilcClient client,
  *    the same packet including its hostname and port. If the library receives
  *    the reply from the remote client the `key_agreement' client operation
  *    callback will be called to verify whether the user wants to perform the
- *    key agreement or not. 
+ *    key agreement or not.
  *
  * NOTES
  *
- *    NOTE: If the application provided the `hostname' and the `port' and the 
+ *    NOTE: If the application provided the `hostname' and the `port' and the
  *    remote side initiates the key agreement protocol it is not verified
  *    from the user anymore whether the protocol should be executed or not.
  *    By setting the `hostname' and `port' the user gives permission to
@@ -2019,7 +2121,7 @@ void silc_client_current_channel_private_key(SilcClient client,
  *    perform the key agreement at all. If the key agreement protocol is
  *    performed the `completion' callback with the `context' will be called.
  *    If remote side decides to ignore the request the `completion' will be
- *    called after the specified timeout, `timeout_secs'. 
+ *    called after the specified timeout, `timeout_secs'.
  *
  *    NOTE: If the `hostname' and the `port' was not provided the `completion'
  *    will not be called at all since this does nothing more than sending
@@ -2027,8 +2129,8 @@ void silc_client_current_channel_private_key(SilcClient client,
  *
  *    NOTE: There can be only one active key agreement for one client entry.
  *    Before setting new one, the old one must be finished (it is finished
- *    after calling the completion callback) or the function 
- *    silc_client_abort_key_agreement must be called. 
+ *    after calling the completion callback) or the function
+ *    silc_client_abort_key_agreement must be called.
  *
  ***/
 void silc_client_send_key_agreement(SilcClient client,
@@ -2045,7 +2147,7 @@ void silc_client_send_key_agreement(SilcClient client,
  *
  * SYNOPSIS
  *
- *    void 
+ *    void
  *    silc_client_perform_key_agreement(SilcClient client,
  *                                      SilcClientConnection conn,
  *                                      SilcClientEntry client_entry,
@@ -2066,7 +2168,7 @@ void silc_client_send_key_agreement(SilcClient client,
  *    be called after the key agreement protocol.
  *
  * NOTES
- * 
+ *
  *    NOTE: If the application returns TRUE in the `key_agreement' client
  *    operation the library will automatically start the key agreement. In this
  *    case the application must not call this function. However, application
@@ -2076,7 +2178,7 @@ void silc_client_send_key_agreement(SilcClient client,
  *    specific command). Thus, the API provides both, automatic and manual
  *    initiation of the key agreement. Calling this function is the manual
  *    initiation and returning TRUE in the `key_agreement' client operation
- *    is the automatic initiation. 
+ *    is the automatic initiation.
  *
  ***/
 void silc_client_perform_key_agreement(SilcClient client,
@@ -2102,10 +2204,10 @@ void silc_client_perform_key_agreement(SilcClient client,
  *
  * DESCRIPTION
  *
- *    Same as above but application has created already the connection to 
- *    the remote host. The `sock' is the socket to the remote connection. 
+ *    Same as above but application has created already the connection to
+ *    the remote host. The `sock' is the socket to the remote connection.
  *    Application can use this function if it does not want the client library
- *    to create the connection. 
+ *    to create the connection.
  *
  ***/
 void silc_client_perform_key_agreement_fd(SilcClient client,
@@ -2127,10 +2229,10 @@ void silc_client_perform_key_agreement_fd(SilcClient client,
  * DESCRIPTION
  *
  *    This function can be called to unbind the hostname and the port for
- *    the key agreement protocol. However, this function has effect only 
+ *    the key agreement protocol. However, this function has effect only
  *    before the key agreement protocol has been performed. After it has
- *    been performed the library will automatically unbind the port. The 
- *    `client_entry' is the client to which we sent the key agreement 
+ *    been performed the library will automatically unbind the port. The
+ *    `client_entry' is the client to which we sent the key agreement
  *    request.  The key agreement completion callback will be called
  *    with SILC_KEY_AGREEMENT_ABORTED status.
  *
@@ -2157,8 +2259,8 @@ void silc_client_abort_key_agreement(SilcClient client,
  *    to anyone who sends private message.  The `message' will be sent
  *    automatically back to the the client who send private message.  If
  *    away message is already set this replaces the old message with the
- *    new one.  If `message' is NULL the old away message is removed. 
- *    The sender may freely free the memory of the `message'. 
+ *    new one.  If `message' is NULL the old away message is removed.
+ *    The sender may freely free the memory of the `message'.
  *
  ***/
 void silc_client_set_away_message(SilcClient client,
@@ -2191,10 +2293,10 @@ typedef void (*SilcConnectionAuthRequest)(SilcClient client,
  *
  * SYNOPSIS
  *
- *    void 
+ *    void
  *    silc_client_request_authentication_method(SilcClient client,
  *                                              SilcClientConnection conn,
- *                                              SilcConnectionAuthRequest 
+ *                                              SilcConnectionAuthRequest
  *                                                callback,
  *                                              void *context);
  *
@@ -2209,7 +2311,7 @@ typedef void (*SilcConnectionAuthRequest)(SilcClient client,
  *    replied back with the current authentication method.
  *
  ***/
-void 
+void
 silc_client_request_authentication_method(SilcClient client,
                                          SilcClientConnection conn,
                                          SilcConnectionAuthRequest callback,
@@ -2286,8 +2388,8 @@ typedef enum {
  *    monitoring process.  The `error' will indicate the error type
  *    if `status' is SILC_CLIENT_FILE_MONITOR_ERROR.  The `offset' is the
  *    currently transmitted amount of total `filesize'.  The `client_entry'
- *    indicates the remote client, and the transmission session ID is the 
- *    `session_id'.  The filename being transmitted is indicated by the 
+ *    indicates the remote client, and the transmission session ID is the
+ *    `session_id'.  The filename being transmitted is indicated by the
  *    `filepath'.
  *
  ***/
@@ -2306,7 +2408,7 @@ typedef void (*SilcClientFileMonitor)(SilcClient client,
  *
  * SYNOPSIS
  *
- *    SilcClientFileError 
+ *    SilcClientFileError
  *    silc_client_file_send(SilcClient client,
  *                          SilcClientConnection conn,
  *                          SilcClientFileMonitor monitor,
@@ -2320,7 +2422,7 @@ typedef void (*SilcClientFileMonitor)(SilcClient client,
  *
  * DESCRIPTION
  *
- *    Sends a file indicated by the `filepath' to the remote client 
+ *    Sends a file indicated by the `filepath' to the remote client
  *    indicated by the `client_entry'.  This will negotiate a secret key
  *    with the remote client before actually starting the transmission of
  *    the file.  The `monitor' callback will be called to monitor the
@@ -2329,9 +2431,9 @@ typedef void (*SilcClientFileMonitor)(SilcClient client,
  *    This returns a file session ID for the file transmission to the
  *    `session_id' pointer.  It can be used to close the session (and
  *    abort the file transmission) by calling the silc_client_file_close
- *    function.  The session ID is also returned in the `monitor' callback. 
+ *    function.  The session ID is also returned in the `monitor' callback.
  *
- *    If the `local_ip' is provided then this will try to bind the 
+ *    If the `local_ip' is provided then this will try to bind the
  *    listener for key exchange protocol to that IP.  If `local_port' is
  *    non-zero that port is used.  If `local_ip' is NULL then this will
  *    automatically attempt to bind it to local IP address of the machine.
@@ -2345,7 +2447,7 @@ typedef void (*SilcClientFileMonitor)(SilcClient client,
  *    session.
  *
  ***/
-SilcClientFileError 
+SilcClientFileError
 silc_client_file_send(SilcClient client,
                      SilcClientConnection conn,
                      SilcClientFileMonitor monitor,
@@ -2361,7 +2463,7 @@ silc_client_file_send(SilcClient client,
  *
  * SYNOPSIS
  *
- *    SilcClientFileError 
+ *    SilcClientFileError
  *    silc_client_file_receive(SilcClient client,
  *                             SilcClientConnection conn,
  *                             SilcClientFileMonitor monitor,
@@ -2386,7 +2488,7 @@ silc_client_file_send(SilcClient client,
  *    session.
  *
  ***/
-SilcClientFileError 
+SilcClientFileError
 silc_client_file_receive(SilcClient client,
                         SilcClientConnection conn,
                         SilcClientFileMonitor monitor,
@@ -2467,7 +2569,7 @@ SilcAttributePayload silc_client_attribute_add(SilcClient client,
  *    is non-zero then all attributes of that type are deleted and the
  *    `attr' is ignored.  If `attr' is non-NULL then that specific
  *    attribute is deleted and `attribute' is ignored.
- *    
+ *
  *    You may get all added attributes with the function
  *    silc_client_attributes_get and to get the SilcAttributePayload.
  *    This function Returns TRUE if the attribute was found and deleted.
@@ -2524,10 +2626,10 @@ SilcBuffer silc_client_attributes_request(SilcAttribute attribute, ...);
  *
  * SYNOPSIS
  *
- *     bool silc_client_send_packet(SilcClient client, 
+ *     bool silc_client_send_packet(SilcClient client,
  *                                  SilcClientConnection conn,
- *                                  SilcPacketType type, 
- *                                  const unsigned char *data, 
+ *                                  SilcPacketType type,
+ *                                  const unsigned char *data,
  *                                  SilcUInt32 data_len);
  *
  * DESCRIPTION
@@ -2536,14 +2638,14 @@ SilcBuffer silc_client_attributes_request(SilcAttribute attribute, ...);
  *    to a connection indicated by `conn'.  Usually application does not
  *    need this routine since the Client Library handles the packet
  *    sending.  The `type' indicates the packet type.  If `data' is
- *    NULL then empty packet is sent.  This returns FALSE if packet cannot 
+ *    NULL then empty packet is sent.  This returns FALSE if packet cannot
  *    be sent.
  *
  ***/
-bool silc_client_send_packet(SilcClient client, 
+bool silc_client_send_packet(SilcClient client,
                             SilcClientConnection conn,
-                            SilcPacketType type, 
-                            const unsigned char *data, 
+                            SilcPacketType type,
+                            const unsigned char *data,
                             SilcUInt32 data_len);
 
 #include "command.h"
index f01af8d6ab336ec8e790f399304df7eb42569ed0..7dae40126f105118794fa04d60a7521451d95abb 100644 (file)
@@ -3,7 +3,7 @@
 #
 #  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
 #
-#  Copyright (C) 2000 - 2002 Pekka Riikonen
+#  Copyright (C) 2000 - 2003 Pekka Riikonen
 #
 #  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
@@ -29,7 +29,8 @@ libsilccore_la_SOURCES = \
        silcargument.c \
        silcnotify.c \
        silcauth.c \
-       silcattrs.c
+       silcattrs.c \
+       silcstatus.c
 
 if SILC_DIST_TOOLKIT
 include_HEADERS =      \
index d492ed742576b6e4442812568c86d0634581f679..9c088b51cd67fb3b94311e7d193e3c26d8a4314b 100644 (file)
@@ -71,15 +71,12 @@ SilcArgumentPayload silc_argument_payload_parse(const unsigned char *payload,
                               SILC_STR_UI_SHORT(&p_len),
                               SILC_STR_UI_CHAR(&arg_type),
                               SILC_STR_END);
-    if (ret == -1)
+    if (ret == -1 || p_len > buffer.len - 3)
       goto err;
-    
+
     newp->argv_lens[i] = p_len;
     newp->argv_types[i] = arg_type;
 
-    if (p_len > buffer.len - 3)
-      break;
-    
     /* Get argument data */
     silc_buffer_pull(&buffer, 3);
     ret = silc_buffer_unformat(&buffer,
index 2ba0117b79e0573bc4568281c989bed98a07bee5..7af8f6a052ed5068ee121ee5c3577e6d34b1edd5 100644 (file)
@@ -299,7 +299,7 @@ SilcDList silc_attribute_payload_parse(const unsigned char *payload,
     if (ret == -1)
       goto err;
 
-    if (newp->data_len > buffer.len) {
+    if (newp->data_len > buffer.len - 4) {
       SILC_LOG_ERROR(("Incorrect attribute payload in list"));
       goto err;
     }
@@ -619,7 +619,7 @@ bool silc_attribute_get_object(SilcAttributePayload payload,
        silc_buffer_unformat(&buffer,
                             SILC_STR_UI16_NSTRING_ALLOC(&pk->type, &len),
                             SILC_STR_END);
-      if (res == -1)
+      if (res == -1 || len > buffer.len - 2)
        break;
       pk->data = silc_memdup(payload->data + 2 + len,
                             payload->data_len - 2 - len);
index d42dd66fb0ba747268f7a25cc28e46e11b541f2f..b6bfec6df356d149026c2d65f81ed5e5d01e1436 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  silcauth.c 
+  silcauth.c
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2001 - 2002 Pekka Riikonen
+  Copyright (C) 2001 - 2003 Pekka Riikonen
 
   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
@@ -67,7 +67,7 @@ SilcAuthPayload silc_auth_payload_parse(const unsigned char *data,
     return NULL;
   }
 
-  if (newp->len != buffer.len || 
+  if (newp->len != buffer.len ||
       newp->random_len + newp->auth_len > buffer.len - 8) {
     silc_auth_payload_free(newp);
     return NULL;
@@ -163,13 +163,24 @@ SilcAuthMethod silc_auth_get_method(SilcAuthPayload payload)
   return payload->auth_method;
 }
 
+/* Get the public data from the auth payload. */
+
+unsigned char *silc_auth_get_public_data(SilcAuthPayload payload,
+                                        SilcUInt32 *pubdata_len)
+{
+  if (pubdata_len)
+    *pubdata_len = (SilcUInt32)payload->random_len;
+
+  return payload->random_data;
+}
+
 /* Get the authentication data. If this is passphrase it is UTF-8 encoded. */
 
 unsigned char *silc_auth_get_data(SilcAuthPayload payload,
                                  SilcUInt32 *auth_len)
 {
   if (auth_len)
-    *auth_len = payload->auth_len;
+    *auth_len = (SilcUInt32)payload->auth_len;
 
   return payload->auth_data;
 }
@@ -235,14 +246,7 @@ SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key,
                                              const void *id, SilcIdType type)
 {
   unsigned char *randomdata;
-  unsigned char auth_data[2048 + 1];
-  SilcUInt32 auth_len;
-  unsigned char *tmp;
-  SilcUInt32 tmp_len;
   SilcBuffer buf;
-  SilcPKCS pkcs;
-
-  SILC_LOG_DEBUG(("Generating Authentication Payload with data"));
 
   /* Get 256 bytes of random data */
   if (rng)
@@ -252,8 +256,39 @@ SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key,
   if (!randomdata)
     return NULL;
 
+  buf = silc_auth_public_key_auth_generate_wpub(public_key, private_key,
+                                               randomdata, 256, hash,
+                                               id, type);
+
+  memset(randomdata, 0, 256);
+  silc_free(randomdata);
+
+  return buf;
+}
+
+/* Generates Authentication Payload with authentication data. This is used
+   to do public key based authentication. This generates the random data
+   and the actual authentication data. Returns NULL on error. */
+
+SilcBuffer
+silc_auth_public_key_auth_generate_wpub(SilcPublicKey public_key,
+                                       SilcPrivateKey private_key,
+                                       const unsigned char *pubdata,
+                                       SilcUInt32 pubdata_len,
+                                       SilcHash hash,
+                                       const void *id, SilcIdType type)
+{
+  unsigned char auth_data[2048 + 1];
+  SilcUInt32 auth_len;
+  unsigned char *tmp;
+  SilcUInt32 tmp_len;
+  SilcBuffer buf;
+  SilcPKCS pkcs;
+
+  SILC_LOG_DEBUG(("Generating Authentication Payload with data"));
+
   /* Encode the auth data */
-  tmp = silc_auth_public_key_encode_data(public_key, randomdata, 256, id, 
+  tmp = silc_auth_public_key_encode_data(public_key, pubdata, pubdata_len, id,
                                         type, &tmp_len);
   if (!tmp)
     return NULL;
@@ -271,23 +306,19 @@ SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key,
   if (silc_pkcs_get_key_len(pkcs) / 8 > sizeof(auth_data) - 1 ||
       !silc_pkcs_sign_with_hash(pkcs, hash, tmp, tmp_len, auth_data,
                                &auth_len)) {
-    memset(randomdata, 0, 256);
     memset(tmp, 0, tmp_len);
     silc_free(tmp);
-    silc_free(randomdata);
     silc_pkcs_free(pkcs);
     return NULL;
   }
 
   /* Encode Authentication Payload */
-  buf = silc_auth_payload_encode(SILC_AUTH_PUBLIC_KEY, randomdata, 256,
+  buf = silc_auth_payload_encode(SILC_AUTH_PUBLIC_KEY, pubdata, pubdata_len,
                                 auth_data, auth_len);
 
   memset(tmp, 0, tmp_len);
   memset(auth_data, 0, sizeof(auth_data));
-  memset(randomdata, 0, 256);
   silc_free(tmp);
-  silc_free(randomdata);
   silc_pkcs_free(pkcs);
 
   return buf;
@@ -479,7 +510,7 @@ silc_key_agreement_payload_parse(const unsigned char *payload,
                                                         &newp->hostname_len),
                             SILC_STR_UI_INT(&newp->port),
                             SILC_STR_END);
-  if (ret == -1) {
+  if (ret == -1 || newp->hostname_len > buffer.len - 6) {
     silc_free(newp);
     return NULL;
   }
index 6f874d959873f13ea2e394bb23cb9123e595a8eb..29101966d7ce6208f7b79055477b6ca1a66cd64d 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  silcauth.h 
+  silcauth.h
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2001 - 2002 Pekka Riikonen
+  Copyright (C) 2001 - 2003 Pekka Riikonen
 
   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
@@ -22,8 +22,8 @@
  * DESCRIPTION
  *
  * Implementations of the SILC Authentication Payload and authentication
- * routines.  The SILC Authentication Payload is used to deliver 
- * authentication data usually from client to server in purpose of 
+ * routines.  The SILC Authentication Payload is used to deliver
+ * authentication data usually from client to server in purpose of
  * gaining access to some service.  The Payload and the authentication
  * routines supports both passphrase and public key (signature) based
  * authentication.
@@ -40,7 +40,7 @@
 /****d* silccore/SilcAuthAPI/SilcAuthMethod
  *
  * NAME
- * 
+ *
  *    typedef SilcUInt16 SilcAuthMethod;
  *
  * DESCRIPTION
@@ -66,8 +66,8 @@ typedef SilcUInt16 SilcAuthMethod;
 /****s* silccore/SilcAuthAPI/SilcAuthPayload
  *
  * NAME
- * 
- *    typedef struct SilcAuthPayloadStruct *SilcAuthPayload; 
+ *
+ *    typedef struct SilcAuthPayloadStruct *SilcAuthPayload;
  *
  *
  * DESCRIPTION
@@ -148,6 +148,22 @@ void silc_auth_payload_free(SilcAuthPayload payload);
  ***/
 SilcAuthMethod silc_auth_get_method(SilcAuthPayload payload);
 
+/****f* silccore/SilcAuthAPI/silc_auth_get_public_data
+ *
+ * SYNOPSIS
+ *
+ *    unsigned char *silc_auth_get_public_data(SilcAuthPayload payload,
+ *                                             SilcUInt32 *pubdata_len);
+ *
+ * DESCRIPTION
+ *
+ *    Returns the public data (usually random data) from the payload.
+ *    Caller must not free the returned data.
+ *
+ ***/
+unsigned char *silc_auth_get_public_data(SilcAuthPayload payload,
+                                        SilcUInt32 *pubdata_len);
+
 /****f* silccore/SilcAuthAPI/silc_auth_get_data
  *
  * SYNOPSIS
@@ -173,7 +189,7 @@ unsigned char *silc_auth_get_data(SilcAuthPayload payload,
  *                                                  SilcPrivateKey private_key,
  *                                                  SilcRng rng,
  *                                                  SilcHash hash,
- *                                                  const void *id, 
+ *                                                  const void *id,
  *                                                  SilcIdType type);
  *
  * DESCRIPTION
@@ -195,12 +211,41 @@ SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key,
                                              SilcRng rng, SilcHash hash,
                                              const void *id, SilcIdType type);
 
+/****f* silccore/SilcAuthAPI/silc_auth_public_key_auth_generate_wpub
+ *
+ * SYNOPSIS
+ *
+ *    SilcBuffer
+ *    silc_auth_public_key_auth_generate_wpub(SilcPublicKey public_key,
+ *                                            SilcPrivateKey private_key,
+ *                                            const unsigned char *pubdata,
+ *                                            SilcUInt32 pubdata_len,
+ *                                            SilcHash hash,
+ *                                            const void *id,
+ *                                            SilcIdType type);
+ *
+ * DESCRIPTION
+ *
+ *    Same as silc_auth_public_key_auth_generate but takes the public data
+ *    (usually random data) as argument.  This function can be used when
+ *    the public data must be something else than purely random or its
+ *    structure mut be set before signing.
+ *
+ ***/
+SilcBuffer
+silc_auth_public_key_auth_generate_wpub(SilcPublicKey public_key,
+                                       SilcPrivateKey private_key,
+                                       const unsigned char *pubdata,
+                                       SilcUInt32 pubdata_len,
+                                       SilcHash hash,
+                                       const void *id, SilcIdType type);
+
 /****f* silccore/SilcAuthAPI/silc_auth_public_key_auth_verify
  *
  * SYNOPSIS
  *
  *    bool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
- *                                          SilcPublicKey public_key, 
+ *                                          SilcPublicKey public_key,
  *                                          SilcHash hash,
  *                                          const void *id, SilcIdType type);
  *
@@ -220,9 +265,9 @@ bool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
  *
  *    bool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
  *                                               SilcUInt32 payload_len,
- *                                               SilcPublicKey public_key, 
+ *                                               SilcPublicKey public_key,
  *                                               SilcHash hash,
- *                                               const void *id, 
+ *                                               const void *id,
  *                                               SilcIdType type);
  *
  * DESCRIPTION
@@ -234,7 +279,7 @@ bool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
  ***/
 bool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
                                           SilcUInt32 payload_len,
-                                          SilcPublicKey public_key, 
+                                          SilcPublicKey public_key,
                                           SilcHash hash,
                                           const void *id, SilcIdType type);
 
@@ -242,14 +287,14 @@ bool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
  *
  * SYNOPSIS
  *
- *    bool silc_auth_verify(SilcAuthPayload payload, 
+ *    bool silc_auth_verify(SilcAuthPayload payload,
  *                          SilcAuthMethod auth_method,
- *                          const void *auth_data, SilcUInt32 auth_data_len, 
+ *                          const void *auth_data, SilcUInt32 auth_data_len,
  *                          SilcHash hash, const void *id, SilcIdType type);
  *
  * DESCRIPTION
  *
- *    Verifies the authentication data directly from the Authentication 
+ *    Verifies the authentication data directly from the Authentication
  *    Payload. Supports all authentication methods. If the authentication
  *    method is passphrase based then the `auth_data' and `auth_data_len'
  *    are the passphrase and its length.  The passphrase MUST be UTF-8
@@ -258,24 +303,24 @@ bool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
  *
  ***/
 bool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
-                     const void *auth_data, SilcUInt32 auth_data_len, 
+                     const void *auth_data, SilcUInt32 auth_data_len,
                      SilcHash hash, const void *id, SilcIdType type);
 
 /****f* silccore/SilcAuthAPI/silc_auth_verify_data
  *
  * SYNOPSIS
  *
- *    bool silc_auth_verify_data(const unsigned char *payload, 
+ *    bool silc_auth_verify_data(const unsigned char *payload,
  *                               SilcUInt32 payload_len,
- *                               SilcAuthMethod auth_method, 
+ *                               SilcAuthMethod auth_method,
  *                               const void *auth_data,
- *                               SilcUInt32 auth_data_len, SilcHash hash, 
+ *                               SilcUInt32 auth_data_len, SilcHash hash,
  *                               const void *id, SilcIdType type);
- * 
+ *
  * DESCRIPTION
  *
  *    Same as silc_auth_verify but the payload has not been parsed yet.
- *    Verifies the authentication data directly from the Authentication 
+ *    Verifies the authentication data directly from the Authentication
  *    Payload. Supports all authentication methods. If the authentication
  *    method is passphrase based then the `auth_data' and `auth_data_len'
  *    are the passphrase and its length.  The passphrase MUST be UTF-8
@@ -283,16 +328,16 @@ bool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
  *    `auth_data' is the SilcPublicKey and the `auth_data_len' is ignored.
  *
  ***/
-bool silc_auth_verify_data(const unsigned char *payload, 
+bool silc_auth_verify_data(const unsigned char *payload,
                           SilcUInt32 payload_len,
                           SilcAuthMethod auth_method, const void *auth_data,
-                          SilcUInt32 auth_data_len, SilcHash hash, 
+                          SilcUInt32 auth_data_len, SilcHash hash,
                           const void *id, SilcIdType type);
 
 /****s* silccore/SilcAuthAPI/SilcKeyAgreementPayload
  *
  * NAME
- * 
+ *
  *    typedef struct SilcKeyAgreementPayloadStruct *SilcKeyAgreementPayload;
  *
  * DESCRIPTION
@@ -309,7 +354,7 @@ typedef struct SilcKeyAgreementPayloadStruct *SilcKeyAgreementPayload;
  *
  * SYNOPSIS
  *
- *    SilcKeyAgreementPayload 
+ *    SilcKeyAgreementPayload
  *    silc_key_agreement_payload_parse(const unsigned char *payload,
  *                                     SilcUInt32 payload_len);
  *
@@ -318,7 +363,7 @@ typedef struct SilcKeyAgreementPayloadStruct *SilcKeyAgreementPayload;
  *    Parses and returns an allocated Key Agreement payload.
  *
  ***/
-SilcKeyAgreementPayload 
+SilcKeyAgreementPayload
 silc_key_agreement_payload_parse(const unsigned char *payload,
                                 SilcUInt32 payload_len);
 
index 5c83bbb422801ac4b472c19a18409a4ac8bde860..aa31637823cda4b995bb29c60a0a453a7f62e099 100644 (file)
@@ -109,8 +109,9 @@ SilcDList silc_channel_payload_parse_list(const unsigned char *payload,
     if (ret == -1)
       goto err;
 
-    if ((newp->name_len < 1 || newp->name_len > buffer.len) ||
-       (newp->id_len < 1 || newp->id_len > buffer.len)) {
+    if ((newp->name_len < 1 || newp->name_len > buffer.len - 8) ||
+       (newp->id_len < 1 || newp->id_len > buffer.len - 8) ||
+       (newp->id_len + newp->name_len > buffer.len - 8)) {
       SILC_LOG_ERROR(("Incorrect channel payload in packet, packet dropped"));
       goto err;
     }
index 363bbe0122517421f0b303e170c3c6ced1fca4c2..dc0e64823b193f4622ba1f072205ca6266f20e7a 100644 (file)
@@ -1,16 +1,16 @@
 /*
+
   silccommand.h
+
   Author: Pekka Riikonen <priikone@silcnet.org>
+
   Copyright (C) 1997 - 2001 Pekka Riikonen
+
   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
@@ -51,7 +51,7 @@ typedef void (*SilcCommandCb)(void *context, void *context2);
 /****s* silccore/SilcCommandAPI/SilcCommandPayload
  *
  * NAME
- * 
+ *
  *    typedef struct SilcCommandPayloadStruct *SilcCommandPayload;
  *
  * DESCRIPTION
@@ -67,7 +67,7 @@ typedef struct SilcCommandPayloadStruct *SilcCommandPayload;
 /****d* silccore/SilcCommandAPI/SilcCommandFlags
  *
  * NAME
- * 
+ *
  *    typedef enum { ... } SilcCommandFlags;
  *
  * DESCRIPTION
@@ -98,7 +98,7 @@ typedef enum {
   /* Command is available only for server operators */
   SILC_CF_OPER           = (1L << 4),
 
-  /* Command is available only for SILC (router) operators. If this 
+  /* Command is available only for SILC (router) operators. If this
      is set SILC_CF_OPER is not necessary to be set. */
   SILC_CF_SILC_OPER      = (1L << 5),
 
@@ -108,7 +108,7 @@ typedef enum {
 /****d* silccore/SilcCommandAPI/SilcCommand
  *
  * NAME
- * 
+ *
  *    typedef SilcUInt8 SilcCommand;
  *
  * DESCRIPTION
@@ -168,7 +168,7 @@ typedef SilcUInt8 SilcCommand;
  *
  * SYNOPSIS
  *
- *    SilcCommandPayload 
+ *    SilcCommandPayload
  *    silc_command_payload_parse(const unsigned char *payload,
  *                               SilcUInt32 payload_len);
  *
@@ -208,7 +208,7 @@ SilcBuffer silc_command_payload_encode(SilcCommand cmd,
  *
  * SYNOPSIS
  *
- *    SilcBuffer 
+ *    SilcBuffer
  *    silc_command_payload_encode_payload(SilcCommandPayload payload);
  *
  * DESCRIPTION
@@ -223,31 +223,31 @@ SilcBuffer silc_command_payload_encode_payload(SilcCommandPayload payload);
  *
  * SYNOPSIS
  *
- *    SilcBuffer silc_command_payload_encode_va(SilcCommand cmd, 
- *                                              SilcUInt16 ident, 
+ *    SilcBuffer silc_command_payload_encode_va(SilcCommand cmd,
+ *                                              SilcUInt16 ident,
  *                                              SilcUInt32 argc, ...);
  *
  * DESCRIPTION
  *
  *    Encodes Command payload with variable argument list. The arguments
- *    must be: SilcUInt32, unsigned char *, unsigned int, ... One 
- *    {SilcUInt32, unsigned char * and unsigned int} forms one argument, 
- *    thus `argc' in case when sending one {SilcUInt32, unsigned char * 
+ *    must be: SilcUInt32, unsigned char *, unsigned int, ... One
+ *    {SilcUInt32, unsigned char * and unsigned int} forms one argument,
+ *    thus `argc' in case when sending one {SilcUInt32, unsigned char *
  *    and SilcUInt32} equals one (1) and when sending two of those it
  *    equals two (2), and so on. This has to be preserved or bad things
  *    will happen. The variable arguments is: {type, data, data_len}.
  *
  ***/
-SilcBuffer silc_command_payload_encode_va(SilcCommand cmd, 
-                                         SilcUInt16 ident, 
+SilcBuffer silc_command_payload_encode_va(SilcCommand cmd,
+                                         SilcUInt16 ident,
                                          SilcUInt32 argc, ...);
 
 /****f* silccore/SilcCommandAPI/silc_command_payload_encode_vap
  *
  * SYNOPSIS
  *
- *    SilcBuffer silc_command_payload_encode_vap(SilcCommand cmd, 
- *                                               SilcUInt16 ident, 
+ *    SilcBuffer silc_command_payload_encode_vap(SilcCommand cmd,
+ *                                               SilcUInt16 ident,
  *                                               SilcUInt32 argc, va_list ap);
  *
  * DESCRIPTION
@@ -256,16 +256,16 @@ SilcBuffer silc_command_payload_encode_va(SilcCommand cmd,
  *    takes the va_list as argument.
  *
  ***/
-SilcBuffer silc_command_payload_encode_vap(SilcCommand cmd, 
-                                          SilcUInt16 ident, 
+SilcBuffer silc_command_payload_encode_vap(SilcCommand cmd,
+                                          SilcUInt16 ident,
                                           SilcUInt32 argc, va_list ap);
 
 /****f* silccore/SilcCommandAPI/silc_command_reply_payload_encode_va
  *
  * SYNOPSIS
  *
- *    SilcBuffer 
- *    silc_command_reply_payload_encode_va(SilcCommand cmd, 
+ *    SilcBuffer
+ *    silc_command_reply_payload_encode_va(SilcCommand cmd,
  *                                         SilcStatus status,
  *                                         SilcStatus error,
  *                                         SilcUInt16 ident,
@@ -273,8 +273,8 @@ SilcBuffer silc_command_payload_encode_vap(SilcCommand cmd,
  *
  * DESCRIPTION
  *
- *    Same as silc_command_payload_encode_va except that this is used to 
- *    encode strictly command reply packets.  The `argc' must not count 
+ *    Same as silc_command_payload_encode_va except that this is used to
+ *    encode strictly command reply packets.  The `argc' must not count
  *    `status' and `error' as arguments.  The `status' includes the
  *    command reply status.  If single reply will be sent then it includes
  *    SILC_STATUS_OK if error did not occur.  It includes an error value
@@ -292,8 +292,8 @@ SilcBuffer silc_command_payload_encode_vap(SilcCommand cmd,
  *    replies are sent after the successful replies.
  *
  ***/
-SilcBuffer 
-silc_command_reply_payload_encode_va(SilcCommand cmd, 
+SilcBuffer
+silc_command_reply_payload_encode_va(SilcCommand cmd,
                                     SilcStatus status,
                                     SilcStatus error,
                                     SilcUInt16 ident,
@@ -303,8 +303,8 @@ silc_command_reply_payload_encode_va(SilcCommand cmd,
  *
  * SYNOPSIS
  *
- *    SilcBuffer 
- *    silc_command_reply_payload_encode_vap(SilcCommand cmd, 
+ *    SilcBuffer
+ *    silc_command_reply_payload_encode_vap(SilcCommand cmd,
  *                                          SilcStatus status,
  *                                          SilcStatus error,
  *                                          SilcUInt16 ident, SilcUInt32 argc,
@@ -316,11 +316,11 @@ silc_command_reply_payload_encode_va(SilcCommand cmd,
  *    takes the va_list as argument.
  *
  ***/
-SilcBuffer 
-silc_command_reply_payload_encode_vap(SilcCommand cmd, 
+SilcBuffer
+silc_command_reply_payload_encode_vap(SilcCommand cmd,
                                      SilcStatus status,
                                      SilcStatus error,
-                                     SilcUInt16 ident, SilcUInt32 argc, 
+                                     SilcUInt16 ident, SilcUInt32 argc,
                                      va_list ap);
 
 /****f* silccore/SilcCommandAPI/silc_command_free
@@ -383,7 +383,7 @@ SilcUInt16 silc_command_get_ident(SilcCommandPayload payload);
  *
  * SYNOPSIS
  *
- *    bool silc_command_get_status(SilcCommandPayload payload, 
+ *    bool silc_command_get_status(SilcCommandPayload payload,
  *                                 SilcStatus *status,
  *                                 SilcStatus *error);
  *
@@ -397,7 +397,7 @@ SilcUInt16 silc_command_get_ident(SilcCommandPayload payload);
  *    which indicates that there will be list of errors.
  *
  ***/
-bool silc_command_get_status(SilcCommandPayload payload, 
+bool silc_command_get_status(SilcCommandPayload payload,
                             SilcStatus *status,
                             SilcStatus *error);
 
@@ -405,14 +405,14 @@ bool silc_command_get_status(SilcCommandPayload payload,
  *
  * SYNOPSIS
  *
- *    void silc_command_set_ident(SilcCommandPayload payload, 
+ *    void silc_command_set_ident(SilcCommandPayload payload,
  *                                SilcUInt16 ident);
  *
  * DESCRIPTION
  *
  *    Function to set identifier to already allocated Command Payload. Command
  *    payloads are frequentlly resent in SILC and thusly this makes it easy
- *    to set the identifier without encoding new Command Payload. 
+ *    to set the identifier without encoding new Command Payload.
  *
  ***/
 void silc_command_set_ident(SilcCommandPayload payload, SilcUInt16 ident);
@@ -421,7 +421,7 @@ void silc_command_set_ident(SilcCommandPayload payload, SilcUInt16 ident);
  *
  * SYNOPSIS
  *
- *    void silc_command_set_command(SilcCommandPayload payload, 
+ *    void silc_command_set_command(SilcCommandPayload payload,
  *                                  SilcCommand command);
  *
  * DESCRIPTION
index 9fb5630cf3d2d155f8d488608a84582c301a71c3..741ad9edb8cf9e884ca0fbf7dc74d280c9c10c94 100644 (file)
@@ -422,7 +422,8 @@ typedef struct {
  * DESCRIPTION
  *
  *    Converts an ID of type `type' to data. This can be used to
- *    convert the ID's to data for inclusion in the packets.
+ *    convert the ID's to data for inclusion in the packets.  Use the
+ *    silc_id_get_len to get the length of the ID.
  *
  ***/
 unsigned char *silc_id_id2str(const void *id, SilcIdType type);
index 3d6904e74421b00d962d69e55466f92c9240fa0a..fb284c22237fc333807f9a90b56e4deb264e6d67 100644 (file)
@@ -10,7 +10,7 @@
   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
@@ -26,7 +26,7 @@
 static void silc_idcache_destructor(void *key, void *context,
                                    void *user_context);
 static SilcIDCacheList silc_idcache_list_alloc();
-static void silc_idcache_list_add(SilcIDCacheList list, 
+static void silc_idcache_list_add(SilcIDCacheList list,
                                  SilcIDCacheEntry cache);
 
 /*
@@ -70,9 +70,9 @@ struct SilcIDCacheStruct {
   SilcIdType type;
 };
 
-/* 
+/*
    ID Cache list.
-   
+
    This is returned when searching the cache. Enumeration functions are
    provided to traverse the list; actually this is used as table not as
    list. :)
@@ -94,7 +94,7 @@ struct SilcIDCacheListStruct {
 };
 
 /* Allocates new ID cache object. The initial amount of allocated entries
-   can be sent as argument. If `count' is 0 the system uses default values. 
+   can be sent as argument. If `count' is 0 the system uses default values.
    The `id_type' defines the types of the ID's that will be saved to the
    cache. */
 
@@ -153,7 +153,7 @@ void silc_idcache_free(SilcIDCache cache)
    If the `expire' is TRUE the entry expires in default time and if FALSE
    the entry never expires from the cache. */
 
-bool silc_idcache_add(SilcIDCache cache, char *name, void *id, 
+bool silc_idcache_add(SilcIDCache cache, char *name, void *id,
                      void *context, int expire, SilcIDCacheEntry *ret)
 {
   SilcIDCacheEntry c;
@@ -210,8 +210,10 @@ bool silc_idcache_del(SilcIDCache cache, SilcIDCacheEntry old)
     ret = silc_hash_table_del(cache->context_table, old->context);
   if (old->id)
     ret = silc_hash_table_del(cache->id_table, old->id);
-  else
+  else {
     silc_idcache_destructor(NULL, old, NULL);
+    ret = TRUE;
+  }
 
   return ret;
 }
@@ -232,9 +234,9 @@ bool silc_idcache_del_by_id(SilcIDCache cache, void *id)
    functions are NULL then default values are used. */
 
 bool silc_idcache_del_by_id_ext(SilcIDCache cache, void *id,
-                               SilcHashFunction hash, 
+                               SilcHashFunction hash,
                                void *hash_context,
-                               SilcHashCompare compare, 
+                               SilcHashCompare compare,
                                void *compare_context)
 {
   SilcIDCacheEntry c;
@@ -243,7 +245,7 @@ bool silc_idcache_del_by_id_ext(SilcIDCache cache, void *id,
   SILC_LOG_DEBUG(("Deleting cache entry"));
 
   if (!silc_hash_table_find_ext(cache->id_table, id, NULL, (void *)&c,
-                               hash, hash_context, compare, 
+                               hash, hash_context, compare,
                                compare_context))
     return FALSE;
 
@@ -277,8 +279,10 @@ bool silc_idcache_del_by_context(SilcIDCache cache, void *context)
     ret = silc_hash_table_del(cache->context_table, c->context);
   if (c->id)
     ret = silc_hash_table_del_by_context(cache->id_table, c->id, c);
-  else
+  else {
     silc_idcache_destructor(NULL, c, NULL);
+    ret = TRUE;
+  }
 
   return ret;
 }
@@ -322,7 +326,7 @@ static void silc_idcache_purge_foreach(void *key, void *context,
     if (c->id)
       ret =
        silc_hash_table_del_by_context_ext(cache->id_table, c->id, c,
-                                          NULL, NULL, NULL, NULL, 
+                                          NULL, NULL, NULL, NULL,
                                           silc_idcache_destructor_dummy,
                                           NULL);
     if (ret == TRUE) {
@@ -352,7 +356,7 @@ bool silc_idcache_purge_by_context(SilcIDCache cache, void *context)
   SilcIDCacheEntry c;
   bool ret = FALSE;
 
-  if (!silc_hash_table_find(cache->context_table, context, NULL, 
+  if (!silc_hash_table_find(cache->context_table, context, NULL,
                            (void *)&c))
     return FALSE;
 
@@ -364,7 +368,7 @@ bool silc_idcache_purge_by_context(SilcIDCache cache, void *context)
   if (c->id)
     ret =
       silc_hash_table_del_by_context_ext(cache->id_table, c->id, c,
-                                        NULL, NULL, NULL, NULL, 
+                                        NULL, NULL, NULL, NULL,
                                         silc_idcache_destructor_dummy, NULL);
   if (ret == TRUE) {
     /* Call the destructor */
@@ -416,7 +420,7 @@ bool silc_idcache_get_all(SilcIDCache cache, SilcIDCacheList *ret)
 
 /* Find ID Cache entry by ID. May return multiple entries. */
 
-bool silc_idcache_find_by_id(SilcIDCache cache, void *id, 
+bool silc_idcache_find_by_id(SilcIDCache cache, void *id,
                             SilcIDCacheList *ret)
 {
   SilcIDCacheList list;
@@ -445,21 +449,21 @@ bool silc_idcache_find_by_id(SilcIDCache cache, void *id,
    If `hash' is NULL then the default hash funtion is used and if `compare'
    is NULL default comparison function is used. */
 
-bool silc_idcache_find_by_id_one_ext(SilcIDCache cache, void *id, 
-                                    SilcHashFunction hash, 
+bool silc_idcache_find_by_id_one_ext(SilcIDCache cache, void *id,
+                                    SilcHashFunction hash,
                                     void *hash_context,
-                                    SilcHashCompare compare, 
+                                    SilcHashCompare compare,
                                     void *compare_context,
                                     SilcIDCacheEntry *ret)
 {
   return silc_hash_table_find_ext(cache->id_table, id, NULL, (void *)ret,
-                                 hash, hash_context, compare, 
+                                 hash, hash_context, compare,
                                  compare_context);
 }
 
 /* Find one specific ID entry. */
 
-bool silc_idcache_find_by_id_one(SilcIDCache cache, void *id, 
+bool silc_idcache_find_by_id_one(SilcIDCache cache, void *id,
                                 SilcIDCacheEntry *ret)
 {
   return silc_hash_table_find(cache->id_table, id, NULL, (void *)ret);
@@ -467,10 +471,10 @@ bool silc_idcache_find_by_id_one(SilcIDCache cache, void *id,
 
 /* Finds cache entry by context. */
 
-bool silc_idcache_find_by_context(SilcIDCache cache, void *context, 
+bool silc_idcache_find_by_context(SilcIDCache cache, void *context,
                                  SilcIDCacheEntry *ret)
 {
-  return silc_hash_table_find(cache->context_table, context, NULL, 
+  return silc_hash_table_find(cache->context_table, context, NULL,
                              (void *)ret);
 }
 
@@ -488,7 +492,7 @@ bool silc_idcache_find_by_name(SilcIDCache cache, char *name,
   if (!ret)
     return TRUE;
 
-  silc_hash_table_find_foreach(cache->name_table, name, 
+  silc_hash_table_find_foreach(cache->name_table, name,
                               silc_idcache_get_all_foreach, list);
 
   if (silc_idcache_list_count(list) == 0) {
@@ -555,7 +559,7 @@ static void silc_idcache_list_add(SilcIDCacheList list, SilcIDCacheEntry cache)
     int k;
 
     i = list->cache_dyn_count;
-    list->cache_dyn = silc_realloc(list->cache_dyn, 
+    list->cache_dyn = silc_realloc(list->cache_dyn,
                                   sizeof(*list->cache_dyn) * (i + 5));
     if (!list->cache_dyn)
       return;
@@ -585,7 +589,7 @@ bool silc_idcache_list_first(SilcIDCacheList list, SilcIDCacheEntry *ret)
 
   if (!list->cache[list->pos])
     return FALSE;
-  
+
   if (ret)
     *ret = list->cache[list->pos];
 
@@ -609,17 +613,17 @@ bool silc_idcache_list_next(SilcIDCacheList list, SilcIDCacheEntry *ret)
 
   if (!list->dyn && !list->cache[list->pos])
     return FALSE;
-  
+
   if (list->dyn && !list->cache_dyn[list->pos])
     return FALSE;
-  
+
   if (ret) {
     if (!list->dyn)
       *ret = list->cache[list->pos];
     else
       *ret = list->cache_dyn[list->pos];
   }
-  
+
   return TRUE;
 }
 
index 08ec1feff16ff05c58a09a35a88bfcf2209bae3a..2876ab560e7517066df950002c736092f11e755d 100644 (file)
@@ -78,7 +78,7 @@ bool silc_message_payload_decrypt(unsigned char *data,
   if (!private_message || (private_message && static_key))
     iv_len = silc_cipher_get_block_len(cipher);
 
-  if (data_len < mac_len)
+  if (data_len <= (mac_len + iv_len))
     return FALSE;
 
   if (check_mac) {
@@ -514,7 +514,7 @@ silc_message_signed_payload_parse(const unsigned char *data,
                             SILC_STR_UI16_NSTRING_ALLOC(&sig->sign_data,
                                                         &sig->sign_len),
                             SILC_STR_END);
-  if (ret == -1) {
+  if (ret == -1 || sig->sign_len > buffer.len - sig->pk_len - 2) {
     silc_message_signed_payload_free(sig);
     SILC_LOG_DEBUG(("Malformed SILC_MESSAGE_FLAG_SIGNED Payload"));
     return NULL;
index 9392b3bca1ade1bba9164d525084aa2193129c93..98f9f2247a969229e9594c52a23ce83b07f85566 100644 (file)
@@ -52,6 +52,7 @@
 #define SILC_CHANNEL_MODE_FOUNDER_AUTH 0x0200 /* sets founder auth data */
 #define SILC_CHANNEL_MODE_SILENCE_USERS 0x0400 /* sets founder auth data */
 #define SILC_CHANNEL_MODE_SILENCE_OPERS 0x0800 /* sets founder auth data */
+#define SILC_CHANNEL_MODE_CHANNEL_AUTH 0x1000 /* channel auth (signature) */
 /***/
 
 /****d* silccore/Modes/ChannelUserModes
index 7bac3681106e2d8282b224cda531b985a7b9d7d8..167d7d17a61fcae170a8cf4b8171344b9d6a447a 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  silcpacket.c 
+  silcpacket.c
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2001 Pekka Riikonen
+  Copyright (C) 1997 - 2003 Pekka Riikonen
 
   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
@@ -40,7 +40,7 @@
 int silc_packet_send(SilcSocketConnection sock, bool force_send)
 {
   SILC_LOG_DEBUG(("Sending packet to %s:%d [%s]", sock->hostname,
-                 sock->port,  
+                 sock->port,
                  (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
                   sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
                   sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
@@ -56,21 +56,21 @@ int silc_packet_send(SilcSocketConnection sock, bool force_send)
     ret = silc_socket_write(sock);
 
     if (ret == -1) {
-      SILC_LOG_ERROR(("Error sending packet, dropped: %s", 
+      SILC_LOG_ERROR(("Error sending packet, dropped: %s",
                       strerror(errno)));
     }
     if (ret != -2)
       return ret;
 
     SILC_LOG_DEBUG(("Could not force the send, packet put to queue"));
-  }  
+  }
 
   SILC_LOG_DEBUG(("Packet in queue"));
 
   return -2;
 }
 
-/* Encrypts a packet. This also creates HMAC of the packet before 
+/* Encrypts a packet. This also creates HMAC of the packet before
    encryption and adds the HMAC at the end of the buffer. This assumes
    that there is enough free space at the end of the buffer to add the
    computed HMAC. This is the normal way of encrypting packets, if some
@@ -83,7 +83,7 @@ void silc_packet_encrypt(SilcCipher cipher, SilcHmac hmac, SilcUInt32 sequence,
 
   /* Encrypt the data area of the packet. */
   if (cipher) {
-    SILC_LOG_DEBUG(("Encrypting packet (%d), cipher %s, len %d", 
+    SILC_LOG_DEBUG(("Encrypting packet (%d), cipher %s, len %d",
                    sequence, silc_cipher_get_name(cipher), len));
     silc_cipher_encrypt(cipher, buffer->data, buffer->data, len, NULL);
   }
@@ -114,8 +114,8 @@ bool silc_packet_assemble(SilcPacketContext *packet, SilcRng rng,
                          SilcSocketConnection sock,
                          const unsigned char *data, SilcUInt32 data_len,
                          const SilcBuffer assembled_packet)
-{ 
-  unsigned char tmppad[SILC_PACKET_MAX_PADLEN];   
+{
+  unsigned char tmppad[SILC_PACKET_MAX_PADLEN];
   unsigned int block_len = cipher ? silc_cipher_get_block_len(cipher) : 0;
   int i, ret;
 
@@ -130,7 +130,7 @@ bool silc_packet_assemble(SilcPacketContext *packet, SilcRng rng,
   if (!packet->truelen) {
     data_len = SILC_PACKET_DATALEN(data_len, SILC_PACKET_HEADER_LEN +
                                   packet->src_id_len + packet->dst_id_len);
-    packet->truelen = data_len + SILC_PACKET_HEADER_LEN + 
+    packet->truelen = data_len + SILC_PACKET_HEADER_LEN +
       packet->src_id_len + packet->dst_id_len;
   }
 
@@ -201,7 +201,7 @@ bool silc_packet_send_prepare(SilcSocketConnection sock,
                              SilcUInt32 data_len,
                              SilcHmac hmac,
                              const SilcBuffer packet)
-{ 
+{
   SilcUInt32 totlen;
   unsigned char *oldptr;
   unsigned int mac_len = hmac ? silc_hmac_len(hmac) : 0;
@@ -251,8 +251,8 @@ bool silc_packet_send_prepare(SilcSocketConnection sock,
 
 ******************************************************************************/
 
-static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac, 
-                              SilcUInt32 sequence, SilcBuffer buffer, 
+static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
+                              SilcUInt32 sequence, SilcBuffer buffer,
                               bool normal);
 static bool silc_packet_check_mac(SilcHmac hmac,
                                  const unsigned char *data,
@@ -272,7 +272,7 @@ int silc_packet_receive(SilcSocketConnection sock)
   int ret;
 
   SILC_LOG_DEBUG(("Receiving packet from %s:%d [%s]", sock->hostname,
-                 sock->port, 
+                 sock->port,
                  (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
                   sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
                   sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
@@ -289,8 +289,8 @@ int silc_packet_receive(SilcSocketConnection sock)
    If more than one packet was received this calls the parser multiple
    times.  The parser callback will get context SilcPacketParserContext
    that includes the packet and the `parser_context' sent to this
-   function. 
-   
+   function.
+
    The `local_is_router' indicates whether the caller is router server
    in which case the receiving process of a certain packet types may
    be special.  Normal server and client must set it to FALSE.  The
@@ -313,7 +313,7 @@ bool silc_packet_receive_process(SilcSocketConnection sock,
   unsigned char iv[SILC_CIPHER_MAX_IV_SIZE];
 
   /* Do not process for disconnected connection */
-  if (SILC_IS_DISCONNECTED(sock))
+  if (SILC_IS_DISCONNECTING(sock) || SILC_IS_DISCONNECTED(sock))
     return TRUE;
 
   if (sock->inbuf->len < SILC_PACKET_MIN_HEADER_LEN)
@@ -394,7 +394,7 @@ bool silc_packet_receive_process(SilcSocketConnection sock,
       if (header[3] == SILC_PACKET_PRIVATE_MESSAGE &&
          (header[2] & SILC_PACKET_FLAG_PRIVMSG_KEY))
        parse_ctx->normal = FALSE;
-      else if (header[3] != SILC_PACKET_CHANNEL_MESSAGE || 
+      else if (header[3] != SILC_PACKET_CHANNEL_MESSAGE ||
               (header[3] == SILC_PACKET_CHANNEL_MESSAGE &&
                sock->type == SILC_SOCKET_TYPE_ROUTER))
        parse_ctx->normal = TRUE;
@@ -417,11 +417,11 @@ bool silc_packet_receive_process(SilcSocketConnection sock,
                    paddedlen - block_len);
     if (cipher) {
       silc_cipher_set_iv(cipher, iv);
-      ret = silc_packet_decrypt(cipher, hmac, parse_ctx->packet->sequence, 
-                               parse_ctx->packet->buffer, 
+      ret = silc_packet_decrypt(cipher, hmac, parse_ctx->packet->sequence,
+                               parse_ctx->packet->buffer,
                                parse_ctx->normal);
       if (ret < 0) {
-       SILC_LOG_WARNING(("Packet decryption failed %s:%d [%s] [%s]", 
+       SILC_LOG_WARNING(("Packet decryption failed %s:%d [%s] [%s]",
                          sock->hostname, sock->port,
                          silc_get_packet_name(parse_ctx->packet->type),
                          (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
@@ -437,7 +437,7 @@ bool silc_packet_receive_process(SilcSocketConnection sock,
     silc_buffer_push(parse_ctx->packet->buffer, block_len);
 
     SILC_LOG_HEXDUMP(("Fully decrypted packet, len %d",
-                     parse_ctx->packet->buffer->len), 
+                     parse_ctx->packet->buffer->len),
                     parse_ctx->packet->buffer->data,
                     parse_ctx->packet->buffer->len);
 
@@ -447,6 +447,13 @@ bool silc_packet_receive_process(SilcSocketConnection sock,
 
     /* Call the parser */
     cont = (*parser)(parse_ctx, parser_context);
+
+    /* See if socket disconnected while parsing the packet */
+    if (SILC_IS_DISCONNECTING(sock) || SILC_IS_DISCONNECTED(sock)) {
+      SILC_LOG_DEBUG(("Abandoning packet processing, socket disconnected"));
+      cont = FALSE;
+    }
+
     memset(tmp, 0, sizeof(tmp));
   }
 
@@ -470,7 +477,7 @@ static bool silc_packet_check_mac(SilcHmac hmac,
   if (hmac) {
     unsigned char mac[32], psn[4];
     SilcUInt32 mac_len;
-    
+
     SILC_LOG_DEBUG(("Verifying MAC"));
 
     /* Compute HMAC of packet */
@@ -485,10 +492,10 @@ static bool silc_packet_check_mac(SilcHmac hmac,
       SILC_LOG_ERROR(("MAC failed"));
       return FALSE;
     }
-    
+
     SILC_LOG_DEBUG(("MAC is Ok"));
   }
-  
+
   return TRUE;
 }
 
@@ -496,7 +503,7 @@ static bool silc_packet_check_mac(SilcHmac hmac,
    Return 0 when packet is normal and 1 when it it special, -1 on error. */
 
 static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
-                              SilcUInt32 sequence, SilcBuffer buffer, 
+                              SilcUInt32 sequence, SilcBuffer buffer,
                               bool normal)
 {
   /* If the packet type is not any special type lets decrypt rest
@@ -524,16 +531,16 @@ static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
       /* padding length + src id len + dst id len + header length - 16
         bytes already decrypted, gives the rest of the encrypted packet */
       silc_buffer_push(buffer, block_len);
-      len = (((SilcUInt8)buffer->data[4] + (SilcUInt8)buffer->data[6] + 
+      len = (((SilcUInt8)buffer->data[4] + (SilcUInt8)buffer->data[6] +
              (SilcUInt8)buffer->data[7] + SILC_PACKET_HEADER_LEN) -
             block_len);
+      silc_buffer_pull(buffer, block_len);
 
       if (len > buffer->len) {
        SILC_LOG_ERROR(("Garbage in header of packet, bad packet length, "
                        "packet dropped"));
        return -1;
       }
-      silc_buffer_pull(buffer, block_len);
       if (!silc_cipher_decrypt(cipher, buffer->data, buffer->data,
                               len, NULL)) {
        SILC_LOG_ERROR(("silc_cipher_decrypt failed"));
@@ -546,9 +553,9 @@ static int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
 }
 
 /* Parses the packet. This is called when a whole packet is ready to be
-   parsed. The buffer sent must be already decrypted before calling this 
-   function. The len argument must be the true length of the packet. This 
-   function returns the type of the packet. The data section of the 
+   parsed. The buffer sent must be already decrypted before calling this
+   function. The len argument must be the true length of the packet. This
+   function returns the type of the packet. The data section of the
    buffer is parsed, not head or tail sections. */
 
 SilcPacketType silc_packet_parse(SilcPacketContext *ctx, SilcCipher cipher)
@@ -567,7 +574,7 @@ SilcPacketType silc_packet_parse(SilcPacketContext *ctx, SilcCipher cipher)
   }
 
   /* Parse the buffer. This parses the SILC header of the packet. */
-  len = silc_buffer_unformat(buffer, 
+  len = silc_buffer_unformat(buffer,
                             SILC_STR_UI_SHORT(&ctx->truelen),
                             SILC_STR_UI_CHAR(&ctx->flags),
                             SILC_STR_UI_CHAR(&ctx->type),
@@ -588,7 +595,7 @@ SilcPacketType silc_packet_parse(SilcPacketContext *ctx, SilcCipher cipher)
   }
 
   silc_buffer_pull(buffer, len);
-  ret = silc_buffer_unformat(buffer, 
+  ret = silc_buffer_unformat(buffer,
                             SILC_STR_UI_XNSTRING_ALLOC(&ctx->src_id,
                                                        src_id_len),
                             SILC_STR_UI_CHAR(&dst_id_type),
@@ -613,7 +620,7 @@ SilcPacketType silc_packet_parse(SilcPacketContext *ctx, SilcCipher cipher)
 
   silc_buffer_push(buffer, len);
 
-  SILC_LOG_HEXDUMP(("parsed packet, len %d", ctx->buffer->len), 
+  SILC_LOG_HEXDUMP(("parsed packet, len %d", ctx->buffer->len),
                   ctx->buffer->data, ctx->buffer->len);
 
   /* Pull SILC header and padding from packet */
@@ -648,7 +655,7 @@ SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx,
   }
 
   /* Parse the buffer. This parses the SILC header of the packet. */
-  len = silc_buffer_unformat(buffer, 
+  len = silc_buffer_unformat(buffer,
                             SILC_STR_UI_SHORT(&ctx->truelen),
                             SILC_STR_UI_CHAR(&ctx->flags),
                             SILC_STR_UI_CHAR(&ctx->type),
@@ -671,7 +678,7 @@ SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx,
   }
 
   silc_buffer_pull(buffer, len);
-  ret = silc_buffer_unformat(buffer, 
+  ret = silc_buffer_unformat(buffer,
                             SILC_STR_UI_XNSTRING_ALLOC(&ctx->src_id,
                                                        src_id_len),
                             SILC_STR_UI_CHAR(&dst_id_type),
@@ -698,7 +705,7 @@ SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx,
 
   silc_buffer_push(buffer, len);
 
-  SILC_LOG_HEXDUMP(("parsed packet, len %d", ctx->buffer->len), 
+  SILC_LOG_HEXDUMP(("parsed packet, len %d", ctx->buffer->len),
                   ctx->buffer->data, ctx->buffer->len);
 
   /* Pull SILC header and padding from packet */
diff --git a/lib/silccore/silcstatus.c b/lib/silccore/silcstatus.c
new file mode 100644 (file)
index 0000000..8829a85
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+
+  silcstatus.c
+
+  Author: Pekka Riikonen <priikone@silcnet.org>
+
+  Copyright (C) 2003 Pekka Riikonen
+
+  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; version 2 of the License.
+
+  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.
+
+*/
+/* $Id$ */
+
+#include "silcincludes.h"
+#include "silcstatus.h"
+
+/* Returns arguments by the status type. */
+
+SilcUInt32 silc_status_get_args(SilcStatus status,
+                               SilcArgumentPayload args,
+                               void **ret_arg1, void **ret_arg2)
+{
+  SilcUInt32 num, len;
+  unsigned char *tmp;
+
+  assert(ret_arg1 && ret_arg2);
+
+  num = silc_argument_get_arg_num(args);
+  if (num > 3)
+    return 0;
+  if (num == 0)
+    return 0;
+
+  switch (status) {
+
+  case SILC_STATUS_ERR_NO_SUCH_NICK:
+  case SILC_STATUS_ERR_NO_SUCH_CHANNEL:
+  case SILC_STATUS_ERR_NO_SUCH_SERVER:
+  case SILC_STATUS_ERR_NO_SUCH_SERVICE:
+  case SILC_STATUS_ERR_UNKNOWN_ALGORITHM:
+    tmp = silc_argument_get_arg_type(args, 2, &len);
+    if (!tmp)
+      return 0;
+    *ret_arg1 = silc_memdup(tmp, len);
+    if (!(*ret_arg1))
+      return 0;
+    num = 1;
+    break;
+
+  case SILC_STATUS_ERR_NO_SUCH_CLIENT_ID:
+  case SILC_STATUS_ERR_BAD_CLIENT_ID:
+  case SILC_STATUS_ERR_NO_SUCH_SERVER_ID:
+  case SILC_STATUS_ERR_BAD_SERVER_ID:
+  case SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID:
+  case SILC_STATUS_ERR_BAD_CHANNEL_ID:
+  case SILC_STATUS_ERR_NOT_ON_CHANNEL:
+  case SILC_STATUS_ERR_CHANNEL_IS_FULL:
+  case SILC_STATUS_ERR_NOT_INVITED:
+  case SILC_STATUS_ERR_BANNED_FROM_CHANNEL:
+  case SILC_STATUS_ERR_NO_CHANNEL_PRIV:
+  case SILC_STATUS_ERR_NO_CHANNEL_FOPRIV:
+    tmp = silc_argument_get_arg_type(args, 2, &len);
+    if (!tmp)
+      return 0;
+    *ret_arg1 = silc_id_payload_parse_id(tmp, len, NULL);
+    if (!(*ret_arg1))
+      return 0;
+    num = 1;
+    break;
+
+  case SILC_STATUS_ERR_USER_NOT_ON_CHANNEL:
+  case SILC_STATUS_ERR_USER_ON_CHANNEL:
+    tmp = silc_argument_get_arg_type(args, 2, &len);
+    if (!tmp)
+      return 0;
+    *ret_arg1 = silc_id_payload_parse_id(tmp, len, NULL);
+    if (!(*ret_arg1))
+      return 0;
+    num = 1;
+    tmp = silc_argument_get_arg_type(args, 3, &len);
+    if (!tmp)
+      return num;
+    *ret_arg2 = silc_id_payload_parse_id(tmp, len, NULL);
+    if (!(*ret_arg2))
+      return num;
+    num = 2;
+    break;
+
+  default:
+    return 0;
+    break;
+  }
+
+  return num;
+}
index 4564a55dffe9e7cf37347516d663811b328a77fd..3b5c7cd0ec648fd97cee67c6fbfd0cfada70ec17 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  silcstatus.h 
+  silcstatus.h
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2002 Pekka Riikonen
+  Copyright (C) 2002 - 2003 Pekka Riikonen
 
   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
@@ -36,7 +36,7 @@
 /****d* silccore/StatusTypes/SilcStatus
  *
  * NAME
- * 
+ *
  *    typedef SilcUInt8 SilcStatus
  *
  * DESCRIPTION
@@ -106,4 +106,24 @@ typedef SilcUInt8 SilcStatus;
 
 #define SILC_STATUS_IS_ERROR(status) (status >= SILC_STATUS_ERR_NO_SUCH_NICK)
 
+/****f* silccore/SilcStatusTypes/silc_status_get_args
+ *
+ * SYNOPSIS
+ *
+ *    SilcUInt32 silc_status_get_args(SilcStatus status,
+ *                                    SilcArgumentPayload args,
+ *                                    void **ret_arg1, **ret_arg2);
+ *
+ * DESCRIPTION
+ *
+ *    Parses and returns the arguments from the `args' by the status type
+ *    indicated by `status'.  Returns the number of arguments (0, 1 or 2)
+ *    parsed.  The caller must free with silc_free the returned arguments.
+ *
+ ***/
+SilcUInt32 silc_status_get_args(SilcStatus status,
+                               SilcArgumentPayload args,
+                               void **ret_arg1, void **ret_arg2);
+
+
 #endif /* SILCSTATUS_H */
index 47f7204491e8e6810f2b9556744055b1bb07944b..3dd281ca453b60687de3d847b636417272633bcf 100644 (file)
@@ -73,3 +73,10 @@ endif
 EXTRA_DIST = *.h tests
 
 include $(top_srcdir)/Makefile.defines.in
+
+# Workaround a bug in GCC 2.x which causes memory exhaustion
+# when compiling sha1 with optimizations on UltraSPARC.
+#
+@FIX_SHA1@sha1.lo:
+@FIX_SHA1@     $(LTCOMPILE) -O0 -c -o $@ `test -f 'sha1.c' || echo '$(srcdir)/'`sha1.c
+@FIX_SHA1@
index 9b596d9b93203616280a11db6a26dfd85eceb209..98963739d8565565e05cb5624b4f41107449e0c6 100644 (file)
@@ -256,6 +256,9 @@ RSA_DecodeOneBlock(unsigned char *data,
     if (blockType != bt)
       return NULL;
 
+    if (modulusLen < 2 + 1)
+      return NULL;
+
     dp += 2;
 
     switch (blockType) {
index 5172593256ceae73a24e755d4d677355ff802b9a..7bacd1e098af114fd4663eb4c6b5f9c1720bb3fc 100644 (file)
@@ -236,22 +236,31 @@ SILC_PKCS_API_SET_PUBLIC_KEY(rsa)
     key->pub_set = FALSE;
   }
 
+  if (key_len < 4)
+    return 0;
+
   silc_mp_init(&key->e);
   silc_mp_init(&key->n);
 
   memcpy(tmp, key_data, 4);
   SILC_GET32_MSB(e_len, tmp);
-  if (!e_len || e_len > key_len) {
+  if (!e_len || e_len + 4 > key_len) {
     silc_mp_uninit(&key->e);
     silc_mp_uninit(&key->n);
     return 0;
   }
 
   silc_mp_bin2mp(key_data + 4, e_len, &key->e);
-  
+
+  if (key_len < 4 + e_len + 4) {
+    silc_mp_uninit(&key->e);
+    silc_mp_uninit(&key->n);
+    return 0;
+  }
+
   memcpy(tmp, key_data + 4 + e_len, 4);
   SILC_GET32_MSB(n_len, tmp);
-  if (!n_len || e_len + n_len > key_len) {
+  if (!n_len || e_len + 4 + n_len + 4 > key_len) {
     silc_mp_uninit(&key->e);
     silc_mp_uninit(&key->n);
     return 0;
@@ -286,13 +295,16 @@ SILC_PKCS_API_SET_PRIVATE_KEY(rsa)
     key->pub_set = FALSE;
   }
 
+  if (key_len < 4)
+    return FALSE;
+
   silc_mp_init(&key->e);
   silc_mp_init(&key->n);
   silc_mp_init(&key->d);
 
   memcpy(tmp, key_data, 4);
   SILC_GET32_MSB(e_len, tmp);
-  if (e_len > key_len) {
+  if (e_len + 4 > key_len) {
     silc_mp_uninit(&key->e);
     silc_mp_uninit(&key->n);
     silc_mp_uninit(&key->d);
@@ -301,9 +313,16 @@ SILC_PKCS_API_SET_PRIVATE_KEY(rsa)
 
   silc_mp_bin2mp(key_data + 4, e_len, &key->e);
   
+  if (key_len < e_len + 4 + 4) {
+    silc_mp_uninit(&key->e);
+    silc_mp_uninit(&key->n);
+    silc_mp_uninit(&key->d);
+    return FALSE;
+  }
+
   memcpy(tmp, key_data + 4 + e_len, 4);
   SILC_GET32_MSB(n_len, tmp);
-  if (e_len + n_len > key_len) {
+  if (e_len + 4 + n_len + 4 > key_len) {
     silc_mp_uninit(&key->e);
     silc_mp_uninit(&key->n);
     silc_mp_uninit(&key->d);
@@ -312,9 +331,16 @@ SILC_PKCS_API_SET_PRIVATE_KEY(rsa)
 
   silc_mp_bin2mp(key_data + 4 + e_len + 4, n_len, &key->n);
 
+  if (key_len < e_len + 4 + n_len + 4 + 4) {
+    silc_mp_uninit(&key->e);
+    silc_mp_uninit(&key->n);
+    silc_mp_uninit(&key->d);
+    return FALSE;
+  }
+
   memcpy(tmp, key_data + 4 + e_len + 4 + n_len, 4);
   SILC_GET32_MSB(d_len, tmp);
-  if (e_len + n_len + d_len > key_len) {
+  if (e_len + 4 + n_len + 4 + d_len + 4 > key_len) {
     silc_mp_uninit(&key->e);
     silc_mp_uninit(&key->n);
     silc_mp_uninit(&key->d);
index 83a16d005e4bb6073164dfbc77d171d21c95e274..11dda7c95ad2e1d8c3f22d0101613f72b967dae4 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  silcpkcs.c 
+  silcpkcs.c
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2002 Pekka Riikonen
+  Copyright (C) 1997 - 2003 Pekka Riikonen
 
   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
@@ -42,7 +42,7 @@ SilcDList silc_pkcs_list = NULL;
 const SilcPKCSObject silc_default_pkcs[] =
 {
   /* RSA with PKCS #1 (Uses directly routines from Raw RSA operations) */
-  { "rsa", 
+  { "rsa",
     silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key,
     silc_rsa_get_private_key, silc_rsa_set_public_key,
     silc_rsa_set_private_key, silc_rsa_context_len,
@@ -50,7 +50,7 @@ const SilcPKCSObject silc_default_pkcs[] =
     silc_pkcs1_sign, silc_pkcs1_verify },
 
   /* Raw RSA operations */
-  { "rsa-raw", 
+  { "rsa-raw",
     silc_rsa_init, silc_rsa_clear_keys, silc_rsa_get_public_key,
     silc_rsa_get_private_key, silc_rsa_set_public_key,
     silc_rsa_set_private_key, silc_rsa_context_len,
@@ -136,7 +136,7 @@ bool silc_pkcs_unregister(SilcPKCSObject *pkcs)
   return FALSE;
 }
 
-/* Function that registers all the default PKCS (all builtin PKCS). 
+/* Function that registers all the default PKCS (all builtin PKCS).
    The application may use this to register the default PKCS if specific
    PKCS in any specific order is not wanted. */
 
@@ -260,8 +260,8 @@ char *silc_pkcs_get_supported(void)
     while ((entry = silc_dlist_get(silc_pkcs_list)) != SILC_LIST_END) {
       len += strlen(entry->name);
       list = silc_realloc(list, len + 1);
-      
-      memcpy(list + (len - strlen(entry->name)), 
+
+      memcpy(list + (len - strlen(entry->name)),
             entry->name, strlen(entry->name));
       memcpy(list + len, ",", 1);
       len++;
@@ -274,8 +274,8 @@ char *silc_pkcs_get_supported(void)
       entry = (SilcPKCSObject *)&(silc_default_pkcs[i]);
       len += strlen(entry->name);
       list = silc_realloc(list, len + 1);
-      
-      memcpy(list + (len - strlen(entry->name)), 
+
+      memcpy(list + (len - strlen(entry->name)),
             entry->name, strlen(entry->name));
       memcpy(list + len, ",", 1);
       len++;
@@ -326,7 +326,7 @@ unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, SilcUInt32 *len)
 
 SilcUInt32 silc_pkcs_public_key_set(SilcPKCS pkcs, SilcPublicKey public_key)
 {
-  pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, public_key->pk, 
+  pkcs->key_len = pkcs->pkcs->set_public_key(pkcs->context, public_key->pk,
                                             public_key->pk_len);
   return pkcs->key_len;
 }
@@ -345,7 +345,7 @@ SilcUInt32 silc_pkcs_public_key_data_set(SilcPKCS pkcs, unsigned char *pk,
 SilcUInt32 silc_pkcs_private_key_set(SilcPKCS pkcs, SilcPrivateKey private_key)
 {
   SilcUInt32 key_len;
-  key_len = pkcs->pkcs->set_private_key(pkcs->context, private_key->prv, 
+  key_len = pkcs->pkcs->set_private_key(pkcs->context, private_key->prv,
                                        private_key->prv_len);
   if (!pkcs->key_len)
     pkcs->key_len = key_len;
@@ -390,11 +390,11 @@ bool silc_pkcs_sign(SilcPKCS pkcs, unsigned char *src, SilcUInt32 src_len,
 
 /* Verifies signature */
 
-bool silc_pkcs_verify(SilcPKCS pkcs, unsigned char *signature, 
-                     SilcUInt32 signature_len, unsigned char *data, 
+bool silc_pkcs_verify(SilcPKCS pkcs, unsigned char *signature,
+                     SilcUInt32 signature_len, unsigned char *data,
                      SilcUInt32 data_len)
 {
-  return pkcs->pkcs->verify(pkcs->context, signature, signature_len, 
+  return pkcs->pkcs->verify(pkcs->context, signature, signature_len,
                            data, data_len);
 }
 
@@ -422,10 +422,10 @@ bool silc_pkcs_sign_with_hash(SilcPKCS pkcs, SilcHash hash,
 /* Verifies signature with hash. The `data' is hashed and verified against
    the `signature'. */
 
-bool silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash, 
-                               unsigned char *signature, 
-                               SilcUInt32 signature_len, 
-                               unsigned char *data, 
+bool silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash,
+                               unsigned char *signature,
+                               SilcUInt32 signature_len,
+                               unsigned char *data,
                                SilcUInt32 data_len)
 {
   unsigned char hashr[32];
@@ -437,14 +437,14 @@ bool silc_pkcs_verify_with_hash(SilcPKCS pkcs, SilcHash hash,
 
   SILC_LOG_HEXDUMP(("Hash"), hashr, hash_len);
 
-  ret = pkcs->pkcs->verify(pkcs->context, signature, signature_len, 
+  ret = pkcs->pkcs->verify(pkcs->context, signature, signature_len,
                           hashr, hash_len);
   memset(hashr, 0, sizeof(hashr));
 
   return ret;
 }
 
-/* Encodes and returns SILC public key identifier. If some of the 
+/* Encodes and returns SILC public key identifier. If some of the
    arguments is NULL those are not encoded into the identifier string.
    Protocol says that at least username and host must be provided. */
 
@@ -464,7 +464,7 @@ char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
        (email    ? strlen(email)    : 0) +
        (org      ? strlen(org)      : 0) +
        (country  ? strlen(country)  : 0);
-  
+
   if (len < 3)
     return NULL;
 
@@ -478,9 +478,9 @@ char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
                       SILC_STR_UI32_STRING(username),
                       SILC_STR_END);
     silc_buffer_pull(buf, 3 + strlen(username));
-    tlen = 3 + strlen(username); 
+    tlen = 3 + strlen(username);
   }
-    
+
   if (host) {
     silc_buffer_format(buf,
                       SILC_STR_UI32_STRING(", "),
@@ -488,7 +488,7 @@ char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
                       SILC_STR_UI32_STRING(host),
                       SILC_STR_END);
     silc_buffer_pull(buf, 5 + strlen(host));
-    tlen += 5 + strlen(host); 
+    tlen += 5 + strlen(host);
   }
 
   if (realname) {
@@ -498,7 +498,7 @@ char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
                       SILC_STR_UI32_STRING(realname),
                       SILC_STR_END);
     silc_buffer_pull(buf, 5 + strlen(realname));
-    tlen += 5 + strlen(realname); 
+    tlen += 5 + strlen(realname);
   }
 
   if (email) {
@@ -508,7 +508,7 @@ char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
                       SILC_STR_UI32_STRING(email),
                       SILC_STR_END);
     silc_buffer_pull(buf, 4 + strlen(email));
-    tlen += 4 + strlen(email); 
+    tlen += 4 + strlen(email);
   }
 
   if (org) {
@@ -518,7 +518,7 @@ char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
                       SILC_STR_UI32_STRING(org),
                       SILC_STR_END);
     silc_buffer_pull(buf, 4 + strlen(org));
-    tlen += 4 + strlen(org); 
+    tlen += 4 + strlen(org);
   }
 
   if (country) {
@@ -528,7 +528,7 @@ char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
                       SILC_STR_UI32_STRING(country),
                       SILC_STR_END);
     silc_buffer_pull(buf, 4 + strlen(country));
-    tlen += 4 + strlen(country); 
+    tlen += 4 + strlen(country);
   }
 
   silc_buffer_push(buf, buf->data - buf->head);
@@ -553,16 +553,33 @@ SilcPublicKeyIdentifier silc_pkcs_decode_identifier(char *identifier)
   cp = identifier;
   while (cp) {
     len = strcspn(cp, ",");
+    if (len < 1) {
+      cp = NULL;
+      break;
+    }
     if (len - 1 >= 0 && cp[len - 1] == '\\') {
       while (cp) {
+       if (len + 1 > strlen(cp)) {
+         cp = NULL;
+         break;
+       }
        cp += len + 1;
        len = strcspn(cp, ",") + len;
+       if (len < 1) {
+         cp = NULL;
+         break;
+       }
        if (len - 1 >= 0 && cp[len - 1] != '\\')
          break;
       }
     }
 
+    if (!cp)
+      break;
+
     item = silc_calloc(len + 1, sizeof(char));
+    if (len > strlen(cp))
+      break;
     memcpy(item, cp, len);
 
     if (strstr(item, "UN="))
@@ -577,13 +594,13 @@ SilcPublicKeyIdentifier silc_pkcs_decode_identifier(char *identifier)
       ident->org = strdup(item + strcspn(cp, "=") + 1);
     else if (strstr(item, "C="))
       ident->country = strdup(item + strcspn(cp, "=") + 1);
-    
+
     cp += len;
-    if (strlen(cp) == 0)
+    if (strlen(cp) < 1)
       cp = NULL;
     else
       cp += 1;
-    
+
     if (item)
       silc_free(item);
   }
@@ -608,9 +625,9 @@ void silc_pkcs_free_identifier(SilcPublicKeyIdentifier identifier)
 /* Allocates SILC style public key formed from sent arguments. All data
    is duplicated. */
 
-SilcPublicKey silc_pkcs_public_key_alloc(const char *name, 
+SilcPublicKey silc_pkcs_public_key_alloc(const char *name,
                                         const char *identifier,
-                                        const unsigned char *pk, 
+                                        const unsigned char *pk,
                                         SilcUInt32 pk_len)
 {
   SilcPublicKey public_key;
@@ -697,7 +714,7 @@ silc_pkcs_public_key_encode(SilcPublicKey public_key, SilcUInt32 *len)
                     SILC_STR_UI32_STRING(public_key->name),
                     SILC_STR_UI_SHORT(strlen(public_key->identifier)),
                     SILC_STR_UI32_STRING(public_key->identifier),
-                    SILC_STR_UI_XNSTRING(public_key->pk, 
+                    SILC_STR_UI_XNSTRING(public_key->pk,
                                          public_key->pk_len),
                     SILC_STR_END);
 
@@ -710,7 +727,7 @@ silc_pkcs_public_key_encode(SilcPublicKey public_key, SilcUInt32 *len)
 
 unsigned char *
 silc_pkcs_public_key_data_encode(unsigned char *pk, SilcUInt32 pk_len,
-                                char *pkcs, char *identifier, 
+                                char *pkcs, char *identifier,
                                 SilcUInt32 *len)
 {
   SilcBuffer buf;
@@ -776,7 +793,7 @@ bool silc_pkcs_public_key_decode(unsigned char *data, SilcUInt32 data_len,
   if (ret == -1)
     goto err;
 
-  if (pkcs_len < 1 || identifier_len < 3 || 
+  if (pkcs_len < 1 || identifier_len < 3 ||
       pkcs_len + identifier_len > totlen)
     goto err;
 
@@ -804,7 +821,7 @@ bool silc_pkcs_public_key_decode(unsigned char *data, SilcUInt32 data_len,
     goto err;
 
   /* Try to set the key. If this fails the key must be malformed. This
-     code assumes that the PKCS routine checks the format of the key. 
+     code assumes that the PKCS routine checks the format of the key.
      (check only if PKCS are registered) */
   if (SILC_PKCS_LIST) {
     silc_pkcs_alloc(pkcs_name, &alg);
@@ -812,7 +829,7 @@ bool silc_pkcs_public_key_decode(unsigned char *data, SilcUInt32 data_len,
       goto err;
     silc_pkcs_free(alg);
   }
-  
+
   if (public_key) {
     *public_key = silc_calloc(1, sizeof(**public_key));
     (*public_key)->len = totlen;
@@ -961,7 +978,7 @@ silc_pkcs_private_key_encode(SilcPrivateKey private_key, SilcUInt32 *len)
   silc_buffer_format(buf,
                     SILC_STR_UI_SHORT(strlen(private_key->name)),
                     SILC_STR_UI32_STRING(private_key->name),
-                    SILC_STR_UI_XNSTRING(private_key->prv, 
+                    SILC_STR_UI_XNSTRING(private_key->prv,
                                          private_key->prv_len),
                     SILC_STR_END);
 
@@ -1012,7 +1029,7 @@ bool silc_pkcs_private_key_decode(unsigned char *data, SilcUInt32 data_len,
   silc_buffer_set(&buf, data, data_len);
 
   /* Get algorithm name and identifier */
-  ret = 
+  ret =
     silc_buffer_unformat(&buf,
                         SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
                         SILC_STR_END);
@@ -1042,7 +1059,7 @@ bool silc_pkcs_private_key_decode(unsigned char *data, SilcUInt32 data_len,
     goto err;
 
   /* Try to set the key. If this fails the key must be malformed. This
-     code assumes that the PKCS routine checks the format of the key. 
+     code assumes that the PKCS routine checks the format of the key.
      (check only if PKCS are registered) */
   if (SILC_PKCS_LIST) {
     silc_pkcs_alloc(pkcs_name, &alg);
@@ -1052,7 +1069,7 @@ bool silc_pkcs_private_key_decode(unsigned char *data, SilcUInt32 data_len,
     }
     silc_pkcs_free(alg);
   }
-  
+
   if (private_key) {
     *private_key = silc_calloc(1, sizeof(**private_key));
     (*private_key)->name = pkcs_name;
@@ -1186,7 +1203,7 @@ static bool silc_pkcs_save_private_key_internal(const char *filename,
   }
 
   /* Derive the encryption key from the provided key material.  The key
-     is 256 bits length, and derived by taking hash of the data, then 
+     is 256 bits length, and derived by taking hash of the data, then
      re-hashing the data and the previous digest, and using the first and
      second digest as the key. */
   silc_hash_init(sha1);
@@ -1322,7 +1339,7 @@ bool silc_pkcs_load_public_key(const char *filename, SilcPublicKey *public_key,
   SILC_LOG_DEBUG(("Loading public key `%s' with %s encoding", filename,
                  encoding == SILC_PKCS_FILE_PEM ? "Base64" :
                  encoding == SILC_PKCS_FILE_BIN ? "Binary" : "Unkonwn"));
-  
+
   old = data = silc_file_readfile(filename, &data_len);
   if (!data)
     return FALSE;
@@ -1353,7 +1370,7 @@ bool silc_pkcs_load_public_key(const char *filename, SilcPublicKey *public_key,
       data = silc_pem_decode(data, len, &len);
       memset(old, 0, data_len);
       silc_free(old);
-      old = data; 
+      old = data;
       data_len = len;
       break;
     }
@@ -1390,7 +1407,7 @@ bool silc_pkcs_load_private_key(const char *filename,
   SILC_LOG_DEBUG(("Loading private key `%s' with %s encoding", filename,
                  encoding == SILC_PKCS_FILE_PEM ? "Base64" :
                  encoding == SILC_PKCS_FILE_BIN ? "Binary" : "Unkonwn"));
-  
+
   old = data = silc_file_readfile(filename, &data_len);
   if (!data)
     return FALSE;
@@ -1481,7 +1498,7 @@ bool silc_pkcs_load_private_key(const char *filename,
   }
 
   /* Derive the decryption key from the provided key material.  The key
-     is 256 bits length, and derived by taking hash of the data, then 
+     is 256 bits length, and derived by taking hash of the data, then
      re-hashing the data and the previous digest, and using the first and
      second digest as the key. */
   silc_hash_init(sha1);
index eb1a1f709dca6a7e2c0e26a361ed253a0c542be4..f954542499ebb7261d077db5081cc2ccad0577f1 100644 (file)
@@ -78,7 +78,7 @@ typedef struct SilcPKCSObjectStruct {
  *
  * NAME
  *
- *    typedef struct { ... } *SilcPublicKey;
+ *    typedef struct { ... } *SilcPublicKey, SilcPublicKeyStruct;
  *
  * DESCRIPTION
  *
@@ -98,14 +98,15 @@ typedef struct {
   char *identifier;
   unsigned char *pk;
   SilcUInt32 pk_len;
-} *SilcPublicKey;
+} *SilcPublicKey, SilcPublicKeyStruct;
 /***/
 
 /****s* silccrypt/SilcPKCSAPI/SilcPublicKeyIdentifier
  *
  * NAME
  *
- *    typedef struct { ... } *SilcPublicKeyIdentifier;
+ *    typedef struct { ... } *SilcPublicKeyIdentifier,
+ *                            SilcPublicKeyIdentifierStruct;
  *
  * DESCRIPTION
  *
@@ -124,14 +125,14 @@ typedef struct {
   char *email;
   char *org;
   char *country;
-} *SilcPublicKeyIdentifier;
+} *SilcPublicKeyIdentifier, SilcPublicKeyIdentifierStruct;
 /***/
 
 /****s* silccrypt/SilcPKCSAPI/SilcPrivateKey
  *
  * NAME
  *
- *    typedef struct { ... } *SilcPrivateKey;
+ *    typedef struct { ... } *SilcPrivateKey, SilcPrivateKeyStruct;
  *
  * DESCRIPTION
  *
@@ -145,7 +146,7 @@ typedef struct {
   char *name;
   unsigned char *prv;
   SilcUInt32 prv_len;
-} *SilcPrivateKey;
+} *SilcPrivateKey, SilcPrivateKeyStruct;
 
 /* Public and private key file headers */
 #define SILC_PKCS_PUBLIC_KEYFILE_BEGIN "-----BEGIN SILC PUBLIC KEY-----\n"
index 3a37d36c4901eddbc1ca5adc2cf1c8add85e56b2..11f8076c36546cc9ffc238a69ac45cfc8b4a00f7 100644 (file)
-#include <stdio.h>
-#include <stdlib.h>
+
 #include "silcincludes.h"
 
-#include "aes.h"
+/* Test vectors from RFC3602. */
+
+/* First test vector, 16 bytes plaintext, 128 bits key */
+const unsigned char key1[] = "\x06\xa9\x21\x40\x36\xb8\xa1\x5b\x51\x2e\x03\xd5\x34\x12\x00\x06";
+int key1_len = 16 * 8;
+const unsigned char iv1[] = "\x3d\xaf\xba\x42\x9d\x9e\xb4\x30\xb4\x22\xda\x80\x2c\x9f\xac\x41";
+const unsigned char p1[] = "Single block msg";
+int p1_len = 16;
+const unsigned char c1[] = "\xe3\x53\x77\x9c\x10\x79\xae\xb8\x27\x08\x94\x2d\xbe\x77\x18\x1a";
+
+/* Second test vector, 32 bytes plaintext, 128 bits key */
+const unsigned char key2[] = "\xc2\x86\x69\x6d\x88\x7c\x9a\xa0\x61\x1b\xbb\x3e\x20\x25\xa4\x5a";
+int key2_len = 16 * 8;
+const unsigned char iv2[] = "\x56\x2e\x17\x99\x6d\x09\x3d\x28\xdd\xb3\xba\x69\x5a\x2e\x6f\x58";
+const unsigned char p2[] = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f";
+int p2_len = 32;
+const unsigned char c2[] = "\xd2\x96\xcd\x94\xc2\xcc\xcf\x8a\x3a\x86\x30\x28\xb5\xe1\xdc\x0a\x75\x86\x60\x2d\x25\x3c\xff\xf9\x1b\x82\x66\xbe\xa6\xd6\x1a\xb1";
+
 
-int main()
+int main(int argc, char **argv)
 {
-       int i;
-       unsigned char key[256];
-       unsigned char plain[256];
-       unsigned char plain2[256];
-       unsigned char cipher[256];
-       unsigned char iv[256];
-       void *context;
-       int len;
-
-       memset(&key, 0, sizeof(key));
-       memset(&plain, 0, sizeof(plain));
-       memset(&plain2, 0, sizeof(plain2));
-       memset(&cipher, 0, sizeof(cipher));
-       memset(&iv, 0, sizeof(iv));
-
-       context = malloc(silc_aes_context_len());
-
-       fprintf(stderr, "\nKey:\n");
-#if 0
-       len = 32;
-
-       for (i = 0; i < len; i += 2) {
-               fprintf(stderr, "%02x%02x ", key[i], key[i+1]);
-       }
-
-       fprintf(stderr, "\nSetting key\n");
-       silc_aes_set_key(context, key, len * 8);
-
-       fprintf(stderr, "\nPlaintext:\n");
-       for (i = 0; i < len; i += 2) {
-               plain[i] = i;
-               plain[i+1] = i+1;
-               fprintf(stderr, "%02x%02x ", plain[i], plain[i+1]);
-       }
-
-#else
-       len = 16;
-
-       key[0] = 0x2b;
-       key[1] = 0x7e;
-       key[2] = 0x15;
-       key[3] = 0x16;
-       key[4] = 0x28;
-       key[5] = 0xae;
-       key[6] = 0xd2;
-       key[7] = 0xa6;
-       key[8] = 0xab;
-       key[9] = 0xf7;
-       key[10] = 0x15;
-       key[11] = 0x88;
-       key[12] = 0x09;
-       key[13] = 0xcf;
-       key[14] = 0x4f;
-       key[15] = 0x3c;
-       for (i = 0; i < len ; i += 2) {
-               fprintf(stderr, "%02x%02x ", key[i], key[i+1]);
-       }
-
-       fprintf(stderr, "\nSetting key\n");
-       silc_aes_set_key(context, key, len * 8);
-
-       plain[0] = 0x32;
-       plain[1] = 0x43;
-       plain[2] = 0xf6;
-       plain[3] = 0xa8;
-       plain[4] = 0x88;
-       plain[5] = 0x5a;
-       plain[6] = 0x30;
-       plain[7] = 0x8d;
-       plain[8] = 0x31;
-       plain[9] = 0x31;
-       plain[10] = 0x98;
-       plain[11] = 0xa2;
-       plain[12] = 0xe0;
-       plain[13] = 0x37;
-       plain[14] = 0x07;
-       plain[15] = 0x34;
-
-       fprintf(stderr, "\nPlaintext:\n");
-       for (i = 0; i < len; i += 2) {
-               fprintf(stderr, "%02x%02x ", plain[i], plain[i+1]);
-       }
-
-#endif
-
-       fprintf(stderr, "\n\nEncrypting\n");
-       silc_aes_encrypt_cbc(context, plain, cipher, len, iv);
-
-       fprintf(stderr, "Ciphertext:\n");
-       for (i = 0; i < len; i += 2) {
-               fprintf(stderr, "%02x", cipher[i]);
-               fprintf(stderr, "%02x ", cipher[i+1]);
-       }
-
-       memset(&iv, 0, sizeof(iv));
-
-       fprintf(stderr, "\n\nDecrypting\n");
-       silc_aes_decrypt_cbc(context, cipher, plain2, len, iv);
-
-       fprintf(stderr, "Decryptedtext:\n");
-       for (i = 0; i < len; i += 2) {
-               fprintf(stderr, "%02x", plain2[i]);
-               fprintf(stderr, "%02x ", plain2[i+1]);
-       }
-       fprintf(stderr, "\nDone\n");
-
-       return 0;
+  bool success = FALSE;
+  SilcCipher cipher;
+  unsigned char dst[256], pdst[256];
+  int i;
+
+  if (argc > 1 && !strcmp(argv[1], "-d")) {
+    silc_debug = 1;
+    silc_debug_hexdump = 1;
+    silc_log_set_debug_string("*crypt*,*aes*,*cipher*");
+  }
+
+  SILC_LOG_DEBUG(("Registering builtin hash functions"));
+  silc_cipher_register_default();
+
+  if (!silc_cipher_is_supported("aes-128-cbc")) {
+    SILC_LOG_DEBUG(("aes-128-cbc is not supported"));
+    goto err;
+  }
+
+  SILC_LOG_DEBUG(("Allocating AES-CBC cipher"));
+  if (!silc_cipher_alloc("aes-128-cbc", &cipher)) {
+    SILC_LOG_DEBUG(("Allocating AES-CBC cipher failed"));
+    goto err;
+  }
+
+  /* First test vector */
+  SILC_LOG_DEBUG(("First test vector"));
+  memset(dst, 0, sizeof(dst));
+  memset(pdst, 0, sizeof(pdst));
+  silc_cipher_set_iv(cipher, iv1);
+  assert(silc_cipher_set_key(cipher, key1, key1_len));
+  assert(silc_cipher_encrypt(cipher, p1, dst, p1_len, NULL));
+  SILC_LOG_DEBUG(("block len %d, key len %d, name %s",
+                silc_cipher_get_block_len(cipher),
+                silc_cipher_get_key_len(cipher),
+                silc_cipher_get_name(cipher)));
+  SILC_LOG_HEXDUMP(("Plaintext"), (unsigned char *)p1, p1_len);
+  SILC_LOG_HEXDUMP(("Ciphertext"), (unsigned char *)dst, p1_len);
+  SILC_LOG_HEXDUMP(("Expected ciphertext"), (unsigned char *)c1, p1_len);
+  if (memcmp(dst, c1, p1_len)) {
+    SILC_LOG_DEBUG(("Encrypt failed"));
+    goto err;
+  }
+  SILC_LOG_DEBUG(("Encrypt is successful"));
+  silc_cipher_set_iv(cipher, iv1);
+  assert(silc_cipher_decrypt(cipher, dst, pdst, p1_len, NULL));
+  SILC_LOG_HEXDUMP(("Decrypted plaintext"), (unsigned char *)pdst, p1_len);
+  SILC_LOG_HEXDUMP(("Expected plaintext"), (unsigned char *)p1, p1_len);
+  if (memcmp(pdst, p1, p1_len)) {
+    SILC_LOG_DEBUG(("Decrypt failed"));
+    goto err;
+  }
+  SILC_LOG_DEBUG(("Decrypt is successful"));
+
+
+  /* Second test vector */
+  SILC_LOG_DEBUG(("Second test vector"));
+  memset(dst, 0, sizeof(dst));
+  memset(pdst, 0, sizeof(pdst));
+  silc_cipher_set_iv(cipher, iv2);
+  assert(silc_cipher_set_key(cipher, key2, key2_len));
+  assert(silc_cipher_encrypt(cipher, p2, dst, p2_len, NULL));
+  SILC_LOG_DEBUG(("block len %d, key len %d, name %s",
+                silc_cipher_get_block_len(cipher),
+                silc_cipher_get_key_len(cipher),
+                silc_cipher_get_name(cipher)));
+  SILC_LOG_HEXDUMP(("Plaintext"), (unsigned char *)p2, p2_len);
+  SILC_LOG_HEXDUMP(("Ciphertext"), (unsigned char *)dst, p2_len);
+  SILC_LOG_HEXDUMP(("Expected ciphertext"), (unsigned char *)c2, p2_len);
+  if (memcmp(dst, c2, p2_len)) {
+    SILC_LOG_DEBUG(("Encrypt failed"));
+    goto err;
+  }
+  SILC_LOG_DEBUG(("Encrypt is successful"));
+  silc_cipher_set_iv(cipher, iv2);
+  assert(silc_cipher_decrypt(cipher, dst, pdst, p2_len, NULL));
+  SILC_LOG_HEXDUMP(("Decrypted plaintext"), (unsigned char *)pdst, p2_len);
+  SILC_LOG_HEXDUMP(("Expected plaintext"), (unsigned char *)p2, p2_len);
+  if (memcmp(pdst, p2, p2_len)) {
+    SILC_LOG_DEBUG(("Decrypt failed"));
+    goto err;
+  }
+  SILC_LOG_DEBUG(("Decrypt is successful"));
+
+  success = TRUE;
+
+ err:
+  SILC_LOG_DEBUG(("Testing was %s", success ? "SUCCESS" : "FAILURE"));
+  fprintf(stderr, "Testing was %s\n", success ? "SUCCESS" : "FAILURE");
+
+  silc_cipher_free(cipher);
+  silc_cipher_unregister_all();
+  return success;
 }
index 723ca37f777d26057bbac8777b92815c6315eb4a..1f486afad170656c23a30f0b0a18d9450654a4a6 100644 (file)
@@ -183,6 +183,8 @@ New pair of keys will be created.  Please, answer to following questions.\n\
       while (TRUE) {
        printf("\n");
        pass2 = silc_get_input("Retype private key passphrase: ", TRUE);
+       if (!pass2)
+         pass2 = strdup("");
        if (!strcmp(pass, pass2))
          break;
        fprintf(stderr, "\nPassphrases do not match");
@@ -401,6 +403,8 @@ bool silc_change_private_key_passphrase(const char *prv_filename,
       while (TRUE) {
        printf("\n");
        pass2 = silc_get_input("Retype new passphrase: ", TRUE);
+       if (!pass2)
+         pass2 = strdup("");
        if (!strcmp(pass, pass2))
          break;
        fprintf(stderr, "\nPassphrases do not match");
index 149adc1dffd6a2c587278c10a34654827dd62bd7..4dc1472ae6822fc5bff68575c5db519c7e0c3604 100644 (file)
@@ -591,6 +591,8 @@ SilcBuffer silc_buffer_alloc_size(SilcUInt32 len)
 static inline
 void silc_buffer_clear(SilcBuffer sb)
 {
+  if (!sb)
+    return;
   memset(sb->head, 0, sb->truelen);
   sb->data = sb->head;
   sb->tail = sb->head;
index 51cb5d2c2b2c255a0818955c39847e8430e1d55b..86c155e3a7bb65cd143cfacafa3398b4db365c22 100644 (file)
@@ -1,15 +1,14 @@
 /*
 
-  silcbuffmt.h
+  silcbuffmt.h 
 
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+  Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2000 Pekka Riikonen
+  Copyright (C) 1997 - 2003 Pekka Riikonen
 
   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.
+  the Free Software Foundation; version 2 of the License.
 
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
  *
  * DESCRIPTION
  *
- *    SILC Buffer Format API provides a few functions for formatting
- *    various different data types into a buffer, and retrieving
- *    various data from buffer into specific data types.  It is usefull
- *    to format for example packets and later unformat them.
+ * SILC Buffer Format API provides a few functions for formatting
+ * various different data types into a buffer, and retrieving
+ * various data from buffer into specific data types.  It is usefull
+ * to format for example packets and later unformat them.
  *
  ***/
 
 #ifndef SILCBUFFMT_H
 #define SILCBUFFMT_H
 
+/* Prototypes */
+
+/****f* silcutil/SilcBufferFormatAPI/silc_buffer_format
+ *
+ * SYNOPSIS
+ *
+ *    int silc_buffer_format(SilcBuffer dst, ...);
+ *
+ * DESCRIPTION
+ *
+ *    Formats a buffer from a variable argument list.  Returns -1 on error
+ *    and the length of the formatted buffer otherwise.
+ *
+ * EXAMPLE
+ *
+ *    ret = silc_buffer_format(buffer,
+ *                             SILC_STR_INT(intval),
+ *                             SILC_STR_CHAR(charval),
+ *                             SILC_STR_INT(intval),
+ *                             SILC_STR_SHORT(str_len),
+ *                             SILC_STR_UI_XNSTRING(str, str_len),
+ *                             SILC_STR_END);
+ *    if (ret < 0)
+ *      error;
+ *
+ ***/
+int silc_buffer_format(SilcBuffer dst, ...);
+
+/****f* silcutil/SilcBufferFormatAPI/silc_buffer_unformat
+ *
+ * SYNOPSIS
+ *
+ *    int silc_buffer_unformat(SilcBuffer src, ...);
+ *
+ * DESCRIPTION
+ *
+ *    Unformats a buffer from a variable argument list.  Returns -1 on error
+ *    and the length of the unformatted buffer otherwise.
+ *
+ * EXAMPLE
+ *
+ *    ret = silc_buffer_unformat(buffer,
+ *                               SILC_STR_INT(&intval),
+ *                               SILC_STR_CHAR(&charval),
+ *                               SILC_STR_INT(&intval2),
+ *                               SILC_STR_UI16_NSTRING_ALLOC(&str, &str_len),
+ *                               SILC_STR_END);
+ *    if (ret < 0)
+ *      error;
+ *
+ ***/
+int silc_buffer_unformat(SilcBuffer src, ...);
+
+/****f* silcutil/SilcBufferFormatAPI/silc_buffer_format_vp
+ *
+ * SYNOPSIS
+ *
+ *    int silc_buffer_format_vp(SilcBuffer dst, va_list vp);
+ *
+ * DESCRIPTION
+ *
+ *    Formats a buffer from a variable argument list indicated by the `ap'.
+ *    Returns -1 on error and the length of the formatted buffer otherwise.
+ *
+ ***/
+int silc_buffer_format_vp(SilcBuffer dst, va_list ap);
+
+/****f* silcutil/SilcBufferFormatAPI/silc_buffer_unformat_vp
+ *
+ * SYNOPSIS
+ *
+ *    int silc_buffer_unformat_vp(SilcBuffer src, va_list vp);
+ *
+ * DESCRIPTION
+ *
+ *    Unformats a buffer from a variable argument list indicated by the `ap'.
+ *    Returns -1 on error and the length of the unformatted buffer otherwise.
+ *
+ ***/
+int silc_buffer_unformat_vp(SilcBuffer src, va_list ap);
+
+/****f* silcutil/SilcBufferFormatAPI/silc_buffer_strformat
+ *
+ * SYNOPSIS
+ *
+ *   int silc_buffer_strformat(SilcBuffer dst, ...);
+ *
+ * DESCRIPTION
+ *
+ *   Formats a buffer from variable argument list of strings.  Each
+ *   string must be NULL-terminated and the variable argument list must
+ *   be end with SILC_STR_END argument.  This allows that a string in
+ *   the list can be NULL, in which case it is skipped.  This automatically
+ *   allocates the space for the buffer data but `dst' must be already
+ *   allocated by the caller.
+ *
+ * EXAMPLE
+ *
+ *    ret = silc_buffer_strformat(buffer, "foo", "bar", SILC_STR_END);
+ *    if (ret < 0)
+ *      error;
+ *
+ ***/
+int silc_buffer_strformat(SilcBuffer dst, ...);
+
+/* Macros for expanding parameters into variable function argument list.
+   These are passed to silc_buffer_format and silc_buffer_unformat
+   functions. */
+
 /* Buffer parameter types.
 
    _SI_ = signed
@@ -76,82 +184,129 @@ typedef enum {
   SILC_BUFFER_PARAM_END
 } SilcBufferParamType;
 
-/* Macros for expanding parameters into variable function argument list.
-   These are passed to silc_buffer_format and silc_buffer_unformat
-   functions. */
-
-/* One signed/unsigned character.
-
-   Formatting:    SILC_STR_SI_CHAR(char)
-                  SILC_STR_UI_CHAR(unsigned char)
-   Unformatting:  SILC_STR_SI_CHAR(char *)
-                  SILC_STR_UI_CHAR(unsigned char *)
-
-*/
+/****d* silcutil/SilcBufferFormatAPI/SILC_STR_*_CHAR
+ *
+ * NAME
+ *
+ *    #define SILC_STR_UI_CHAR() ...
+ *    #define SILC_STR_SI_CHAR() ...
+ *
+ * DESCRIPTION
+ *
+ *    One signed/unsigned character.
+ *
+ *    Formatting:    SILC_STR_SI_CHAR(char)
+ *                   SILC_STR_UI_CHAR(unsigned char)
+ *    Unformatting:  SILC_STR_SI_CHAR(char *)
+ *                   SILC_STR_UI_CHAR(unsigned char *)
+ *
+ ***/
 #define SILC_STR_SI_CHAR(x) SILC_BUFFER_PARAM_SI8_CHAR, (x)
 #define SILC_STR_UI_CHAR(x) SILC_BUFFER_PARAM_UI8_CHAR, (x)
 
-/* Signed/SilcUInt16.
-
-   Formatting:    SILC_STR_SI_SHORT(short)
-                  SILC_STR_UI_SHORT(SilcUInt16)
-   Unformatting:  SILC_STR_SI_SHORT(short *)
-                  SILC_STR_UI_SHORT(SilcUInt16 *)
-
-*/
+/****d* silcutil/SilcBufferFormatAPI/SILC_STR_*_SHORT
+ *
+ * NAME
+ *
+ *    #define SILC_STR_UI_SHORT() ...
+ *    #define SILC_STR_SI_SHORT() ...
+ *
+ * DESCRIPTION
+ *
+ *    Signed/SilcUInt16.
+ *
+ *    Formatting:    SILC_STR_SI_SHORT(short)
+ *                   SILC_STR_UI_SHORT(SilcUInt16)
+ *    Unformatting:  SILC_STR_SI_SHORT(short *)
+ *                   SILC_STR_UI_SHORT(SilcUInt16 *)
+ *
+ ***/
 #define SILC_STR_SI_SHORT(x) SILC_BUFFER_PARAM_SI16_SHORT, (x)
 #define SILC_STR_UI_SHORT(x) SILC_BUFFER_PARAM_UI16_SHORT, (x)
 
-/* Signed/SilcUInt32.
-
-   Formatting:    SILC_STR_SI_INT(int)
-                  SILC_STR_UI_INT(SilcUInt32)
-   Unformatting:  SILC_STR_SI_INT(int *)
-                  SILC_STR_UI_INT(SilcUInt32 *)
-
-*/
+/****d* silcutil/SilcBufferFormatAPI/SILC_STR_*_INT
+ *
+ * NAME
+ *
+ *    #define SILC_STR_UI_INT() ...
+ *    #define SILC_STR_SI_INT() ...
+ *
+ * DESCRIPTION
+ *
+ *    Signed/SilcUInt32.
+ *
+ *    Formatting:    SILC_STR_SI_INT(int)
+ *                   SILC_STR_UI_INT(SilcUInt32)
+ *    Unformatting:  SILC_STR_SI_INT(int *)
+ *                   SILC_STR_UI_INT(SilcUInt32 *)
+ *
+ ***/
 #define SILC_STR_SI_INT(x) SILC_BUFFER_PARAM_SI32_INT, (x)
 #define SILC_STR_UI_INT(x) SILC_BUFFER_PARAM_UI32_INT, (x)
 
-/* Signed/SilcUInt64.
-
-   Formatting:    SILC_STR_SI_INT64(int)
-                  SILC_STR_UI_INT64(SilcUInt32)
-   Unformatting:  SILC_STR_SI_INT64(int *)
-                  SILC_STR_UI_INT64(SilcUInt32 *)
-
-*/
+/****d* silcutil/SilcBufferFormatAPI/SILC_STR_*_INT64
+ *
+ * NAME
+ *
+ *    #define SILC_STR_UI_INT64() ...
+ *    #define SILC_STR_SI_INT64() ...
+ *
+ * DESCRIPTION
+ *
+ *    Signed/SilcUInt64.
+ *
+ *     Formatting:    SILC_STR_SI_INT64(int)
+ *                    SILC_STR_UI_INT64(SilcUInt32)
+ *     Unformatting:  SILC_STR_SI_INT64(int *)
+ *                    SILC_STR_UI_INT64(SilcUInt32 *)
+ *
+ ***/
 #define SILC_STR_SI_INT64(x) SILC_BUFFER_PARAM_SI64_INT, (x)
 #define SILC_STR_UI_INT64(x) SILC_BUFFER_PARAM_UI64_INT, (x)
 
-/* Unsigned NULL terminated string. Note that the string must be
-   NULL terminated because strlen() will be used to get the length of
-   the string.
-
-   Formatting:    SILC_STR_UI32_STRING(unsigned char *)
-   Unformatting:  SILC_STR_UI32_STRING(unsigned char **)
-
-   Unformatting procedure will check for length of the string from the
-   buffer before trying to get the string out. Thus, one *must* format the
-   length as UI_INT or UI_SHORT into the buffer *before* formatting the
-   actual string to the buffer, and, in unformatting one must ignore the
-   length of the string because unformatting procedure will take it
-   automatically.
-
-   Example:
-
-   Formatting:    ..., SILC_STR_UI_INT(strlen(string)),
-                       SILC_STR_UI32_STRING(string), ...
-   Unformatting:  ..., SILC_STR_UI32_STRING(&string), ...
-
-   I.e., you ignore the formatted length field in unformatting. If you don't
-   the unformatting procedure might fail and it definitely does not unformat
-   the data reliably.
-
-   _ALLOC routines automatically allocates memory for the variable sent
-   as argument in unformatting.
-
-*/
+/****d* silcutil/SilcBufferFormatAPI/SILC_STR_*_STRING
+ *
+ * NAME
+ *
+ *    #define SILC_STR_UI8_STRING() ...
+ *    #define SILC_STR_UI8_STRING_ALLOC() ...
+ *    #define SILC_STR_UI16_STRING() ...
+ *    #define SILC_STR_UI16_STRING_ALLOC() ...
+ *    #define SILC_STR_UI32_STRING() ...
+ *    #define SILC_STR_UI32_STRING_ALLOC() ...
+ *
+ * DESCRIPTION
+ *
+ *    Unsigned NULL terminated string. Note that the string must be
+ *    NULL terminated because strlen() will be used to get the length of
+ *    the string.
+ *
+ *    Formatting:    SILC_STR_UI32_STRING(unsigned char *)
+ *    Unformatting:  SILC_STR_UI32_STRING(unsigned char **)
+ *
+ *    Unformatting procedure will check for length of the string from the
+ *    buffer before trying to get the string out. Thus, one *must* format the
+ *    length as UI_INT or UI_SHORT into the buffer *before* formatting the
+ *    actual string to the buffer, and, in unformatting one must ignore the
+ *    length of the string because unformatting procedure will take it
+ *    automatically.
+ *
+ *    Example:
+ * 
+ *    Formatting:    ..., SILC_STR_UI_INT(strlen(string)),
+ *                        SILC_STR_UI32_STRING(string), ...
+ *    Unformatting:  ..., SILC_STR_UI32_STRING(&string), ...
+ *
+ *    I.e., you can ignore the formatted length field in unformatting.
+ *
+ *    UI8, UI16 and UI32 means that the length is considered to be
+ *    either char (8 bits), short (16 bits) or int (32 bits) in
+ *    unformatting.
+ *
+ *    _ALLOC routines automatically allocates memory for the variable sent
+ *    as argument in unformatting.
+ *
+ ***/
 #define SILC_STR_UI8_STRING(x) SILC_BUFFER_PARAM_UI8_STRING, (x)
 #define SILC_STR_UI8_STRING_ALLOC(x) SILC_BUFFER_PARAM_UI8_STRING_ALLOC, (x)
 #define SILC_STR_UI16_STRING(x) SILC_BUFFER_PARAM_UI16_STRING, (x)
@@ -159,146 +314,102 @@ typedef enum {
 #define SILC_STR_UI32_STRING(x) SILC_BUFFER_PARAM_UI32_STRING, (x)
 #define SILC_STR_UI32_STRING_ALLOC(x) SILC_BUFFER_PARAM_UI32_STRING_ALLOC, (x)
 
-/* Unsigned string. Second argument is the length of the string.
-
-   Formatting:    SILC_STR_UI32_NSTRING(unsigned char *, SilcUInt32)
-   Unformatting:  SILC_STR_UI32_NSTRING(unsigned char **, SilcUInt32 *)
-
-   Unformatting procedure will check for length of the string from the
-   buffer before trying to get the string out. Thus, one *must* format the
-   length as UI_INT or UI_SHORT into the buffer *before* formatting the
-   actual string to the buffer, and, in unformatting one must ignore the
-   length of the string because unformatting procedure will take it
-   automatically.
-
-   Example:
-
-   Formatting:    ..., SILC_STR_UI_INT(strlen(string)),
-                       SILC_STR_UI32_NSTRING(string, strlen(string)), ...
-   Unformatting:  ..., SILC_STR_UI32_NSTRING(&string, &len), ...
-
-   I.e., you ignore the formatted length field in unformatting. If you don't
-   the unformatting procedure might fail and it definitely does not unformat
-   the data reliably. The length taken from the buffer is returned to the
-   pointer sent as argument (&len in above example).
-
-   UI/SI16 and UI/SI32 means that the length is considered to be either
-   short (16 bits) or int (32 bits) in unformatting.
-
-   _ALLOC routines automatically allocates memory for the variable sent
-   as argument in unformatting.
-
-*/
-#define SILC_STR_UI8_NSTRING(x, l) SILC_BUFFER_PARAM_UI8_NSTRING, (x), (l)
-#define SILC_STR_UI8_NSTRING_ALLOC(x, l) \
-  SILC_BUFFER_PARAM_UI8_NSTRING_ALLOC, (x), (l)
-#define SILC_STR_UI16_NSTRING(x, l) SILC_BUFFER_PARAM_UI16_NSTRING, (x), (l)
-#define SILC_STR_UI16_NSTRING_ALLOC(x, l) \
-  SILC_BUFFER_PARAM_UI16_NSTRING_ALLOC, (x), (l)
-#define SILC_STR_UI32_NSTRING(x, l) SILC_BUFFER_PARAM_UI32_NSTRING, (x), (l)
-#define SILC_STR_UI32_NSTRING_ALLOC(x, l) \
-  SILC_BUFFER_PARAM_UI32_NSTRING_ALLOC, (x), (l)
-
-/* Extended Unsigned string formatting. Second argument is the length of
-   the string.
-
-   Formatting:    This is equal to using *_NSTRING
-   Unformatting:  SILC_STR_UI_XNSTRING(unsigned char **, SilcUInt32)
-
-   This type can be used to take arbitrary length string from the buffer
-   by sending the requested amount of bytes as argument. This differs
-   from *_STRING and *_NSTRING so that this doesn't try to find the
-   length of the data from the buffer but the length of the data is
-   sent as argument. This a handy way to unformat fixed length strings
-   from the buffer without having the length of the string formatted
-   in the buffer.
-
-   _ALLOC routines automatically allocates memory for the variable sent
-   as argument in unformatting.
-
-*/
-#define SILC_STR_UI_XNSTRING(x, l) SILC_BUFFER_PARAM_UI_XNSTRING, (x), (l)
-#define SILC_STR_UI_XNSTRING_ALLOC(x, l) \
-  SILC_BUFFER_PARAM_UI_XNSTRING_ALLOC, (x), (l)
-
-/* Marks end of the argument list. This must be at the end of the
-   argument list or error will occur. */
-#define SILC_STR_END SILC_BUFFER_PARAM_END
-
-/* Prototypes */
-
-/****f* silcutil/SilcBufferFormatAPI/silc_buffer_format
+/****d* silcutil/SilcBufferFormatAPI/SILC_STR_*_NSTRING
  *
- * SYNOPSIS
+ * NAME
  *
- *    int silc_buffer_format(SilcBuffer dst, ...);
+ *    #define SILC_STR_UI8_NSTRING() ...
+ *    #define SILC_STR_UI8_NSTRING_ALLOC() ...
+ *    #define SILC_STR_UI16_NSTRING() ...
+ *    #define SILC_STR_UI16_NSTRING_ALLOC() ...
+ *    #define SILC_STR_UI32_NSTRING() ...
+ *    #define SILC_STR_UI32_NSTRING_ALLOC() ...
  *
  * DESCRIPTION
  *
- *    Formats a buffer from a variable argument list.  Returns -1 on error
- *    and the length of the formatted buffer otherwise.
+ *    Unsigned string. Second argument is the length of the string.
  *
- ***/
-int silc_buffer_format(SilcBuffer dst, ...);
-
-/****f* silcutil/SilcBufferFormatAPI/silc_buffer_unformat
+ *    Formatting:    SILC_STR_UI32_NSTRING(unsigned char *, SilcUInt32)
+ *    Unformatting:  SILC_STR_UI32_NSTRING(unsigned char **, SilcUInt32 *)
  *
- * SYNOPSIS
+ *    Unformatting procedure will check for length of the string from the
+ *    buffer before trying to get the string out. Thus, one *must* format the
+ *    length as UI_INT or UI_SHORT into the buffer *before* formatting the
+ *    actual string to the buffer, and, in unformatting one must ignore the
+ *    length of the string because unformatting procedure will take it
+ *    automatically.
  *
- *    int silc_buffer_unformat(SilcBuffer src, ...);
+ *     Example:
  *
- * DESCRIPTION
+ *     Formatting:    ..., SILC_STR_UI_INT(strlen(string)),
+ *                         SILC_STR_UI32_NSTRING(string, strlen(string)), ...
+ *     Unformatting:  ..., SILC_STR_UI32_NSTRING(&string, &len), ...
  *
- *    Unformats a buffer from a variable argument list.  Returns -1 on error
- *    and the length of the unformatted buffer otherwise.
+ *    I.e., you can ignore the formatted length field in unformatting. The
+ *    length taken from the buffer is returned to the pointer sent as
+ *    argument (&len in above example).
+ *
+ *    UI8, UI16 and UI32 means that the length is considered to be
+ *    either char (8 bits), short (16 bits) or int (32 bits) in
+ *    unformatting.
+ *
+ *    _ALLOC routines automatically allocates memory for the variable sent
+ *    as argument in unformatting.
  *
  ***/
-int silc_buffer_unformat(SilcBuffer src, ...);
+#define SILC_STR_UI8_NSTRING(x, l) SILC_BUFFER_PARAM_UI8_NSTRING, (x), (l)
+#define SILC_STR_UI8_NSTRING_ALLOC(x, l) \
+  SILC_BUFFER_PARAM_UI8_NSTRING_ALLOC, (x), (l)
+#define SILC_STR_UI16_NSTRING(x, l) SILC_BUFFER_PARAM_UI16_NSTRING, (x), (l)
+#define SILC_STR_UI16_NSTRING_ALLOC(x, l) \
+  SILC_BUFFER_PARAM_UI16_NSTRING_ALLOC, (x), (l)
+#define SILC_STR_UI32_NSTRING(x, l) SILC_BUFFER_PARAM_UI32_NSTRING, (x), (l)
+#define SILC_STR_UI32_NSTRING_ALLOC(x, l) \
+  SILC_BUFFER_PARAM_UI32_NSTRING_ALLOC, (x), (l)
 
-/****f* silcutil/SilcBufferFormatAPI/silc_buffer_format_vp
+/****d* silcutil/SilcBufferFormatAPI/SILC_STR_UI_XNSTRING
  *
- * SYNOPSIS
+ * NAME
  *
- *    int silc_buffer_format_vp(SilcBuffer dst, va_list vp);
+ *    #define SILC_STR_UI_XNSTRING() ...
+ *    #define SILC_STR_UI_XNSTRING_ALLOC() ...
  *
  * DESCRIPTION
  *
- *    Formats a buffer from a variable argument list indicated by the `ap'.
- *    Returns -1 on error and the length of the formatted buffer otherwise.
+ *    Extended Unsigned string formatting. Second argument is the length of
+ *    the string.
  *
- ***/
-int silc_buffer_format_vp(SilcBuffer dst, va_list ap);
-
-/****f* silcutil/SilcBufferFormatAPI/silc_buffer_unformat_vp
+ *    Formatting:    SILC_STR_UI_XNSTRING(unsigned char *, SilcUInt32)
+ *    Unformatting:  SILC_STR_UI_XNSTRING(unsigned char **, SilcUInt32)
  *
- * SYNOPSIS
- *
- *    int silc_buffer_unformat_vp(SilcBuffer src, va_list vp);
+ *    This type can be used to take arbitrary length string from the buffer
+ *    by sending the requested amount of bytes as argument. This differs
+ *    from *_STRING and *_NSTRING so that this doesn't try to find the
+ *    length of the data from the buffer but the length of the data is
+ *    sent as argument. This a handy way to unformat fixed length strings
+ *    from the buffer without having the length of the string formatted
+ *    in the buffer.
  *
- * DESCRIPTION
- *
- *    Unformats a buffer from a variable argument list indicated by the `ap'.
- *    Returns -1 on error and the length of the unformatted buffer otherwise.
+ *    _ALLOC routines automatically allocates memory for the variable sent
+ *    as argument in unformatting.
  *
  ***/
-int silc_buffer_unformat_vp(SilcBuffer src, va_list ap);
+#define SILC_STR_UI_XNSTRING(x, l) SILC_BUFFER_PARAM_UI_XNSTRING, (x), (l)
+#define SILC_STR_UI_XNSTRING_ALLOC(x, l) \
+  SILC_BUFFER_PARAM_UI_XNSTRING_ALLOC, (x), (l)
 
-/****f* silcutil/SilcBufferFormatAPI/silc_buffer_strformat
+/****d* silcutil/SilcBufferFormatAPI/SILC_STR_END
  *
- * SYNOPSIS
+ * NAME
  *
- *   int silc_buffer_strformat(SilcBuffer dst, ...);
+ *    #define SILC_STR_END ...
  *
  * DESCRIPTION
  *
- *   Formats a buffer from variable argument list of strings.  Each
- *   string must be NULL-terminated and the variable argument list must
- *   be end with SILC_STR_END argument.  This allows that a string in
- *   the list can be NULL, in which case it is skipped.  This automatically
- *   allocates the space for the buffer data but `dst' must be already
- *   allocated by the caller.
+ *    Marks end of the argument list. This must be at the end of the
+ *    argument list or error will occur.
  *
  ***/
-int silc_buffer_strformat(SilcBuffer dst, ...);
+#define SILC_STR_END SILC_BUFFER_PARAM_END
 
 #endif /* !SILCBUFFMT_H */
index 2066f95719ed0531315ffaebdc7bb2e9d8c36346..03fb2a492e6ac0fdb0b8583580a6ff78ed268bb0 100644 (file)
@@ -95,7 +95,7 @@ char *silc_config_strerror(int errnum)
 static void my_trim_spaces(SilcConfigFile *file)
 {
   register char *r = file->p;
-  while (isspace(*r))
+  while ((*r != '\0' && *r != EOF) && isspace(*r))
     if (*r++ == '\n') file->line++;
   file->p = r;
 }
@@ -103,8 +103,8 @@ static void my_trim_spaces(SilcConfigFile *file)
 static void my_skip_line(SilcConfigFile *file)
 {
   register char *r = file->p;
-  while (*r && (*r != '\n') && (*r != '\r')) r++;
-  file->p = (*r ? r + 1 : r);
+  while ((*r != '\0' && *r != EOF) && (*r != '\n') && (*r != '\r')) r++;
+  file->p = ((*r != '\0' && *r != EOF) ? r + 1 : r);
   file->line++;
 }
 /* Obtains a text token from the current position until first separator.
index 4d45aa86f1e2f2f37bde8231dd3bbd24dd724715..b7f4dfeb3c7e74b5c8568b74e78abe79d2fefdcc 100644 (file)
@@ -397,9 +397,11 @@ char *silc_config_read_current_line(SilcConfigFile *file);
  *    Register option `name' in the entity `ent'. If `cb' is not NULL, it
  *    will be called with the *val pointer pointing to an internally
  *    allocated storage of type described by `type'.
+ *
  *    If `type' is SILC_CONFIG_ARG_BLOCK, then `subtable' must be a valid
  *    pointer to a SilcConfigTable array specifying the options in the
  *    sub-block.
+ *
  *    If the option `name' was already registered in this sub-block or it
  *    matches the reserved word "Include", then this function returns FALSE,
  *    otherwise it returns TRUE.
@@ -425,8 +427,10 @@ bool silc_config_register(SilcConfigEntity ent, const char *name,
  *    Register the tableset of options `table' automatically in the entity
  *    `ent'.  If defined in the table, the callback functions will be called
  *    all with the same context `context'.
+ *
  *    The `table' array must be terminated with an entry with the name field
  *    set to NULL.
+ *
  *    If the table contains invalid data this function returns FALSE, otherwise
  *    it returns TRUE.  If a calling to this function failed, you must destroy
  *    and recreate the entity before retrying, as it's impossible to detect
@@ -449,6 +453,7 @@ bool silc_config_register_table(SilcConfigEntity ent,
  *
  *    Enter the main parsing loop. When this function returns the parsing
  *    is finished in the current block (and sub-blocks).
+ *
  *    When this function exits, the entity is already destroyed, because
  *    of this you should set it to NULL right after the function call.
  *
index d9f6d55267bfd19cbe45526237c4d5381b28a1c6..6966f304a0719faec9c18a5090a0b4971b111c1c 100644 (file)
@@ -2,15 +2,14 @@
 
   silcdlist.h
 
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+  Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2000 Pekka Riikonen
+  Copyright (C) 2000 - 2003 Pekka Riikonen
 
   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.
-  
+  the Free Software Foundation; version 2 of the License.
+
   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
 #define SILDCLIST_H
 
 #include "silclist.h"
+
 /****h* silcutil/SILC Dynamic List Interface
  *
  * DESCRIPTION
  *
- *    SILC Dynamic List API can be used to add opaque contexts to list that
- *    will automatically allocate list entries.  Normal SILC List API cannot
- *    be used for this purpose because in that case the context passed to the
- *    list must be defined as list structure already.  This is not the case in
- *    SilcDList.
+ * SILC Dynamic List API can be used to add opaque contexts to list that
+ * will automatically allocate list entries.  Normal SILC List API cannot
+ * be used for this purpose because in that case the context passed to the
+ * list must be defined as list structure already.  This is not the case in
+ * SilcDList.
  *
- *    This is slower than SilcList because this requires one extra memory
- *    allocation when adding new entries to the list.  The context is probably
- *    allocated already and the new list entry requires one additional memory
- *    allocation.  The memory allocation and freeing is done automatically in
- *    the API and does not show to the caller.
+ * This is slower than SilcList because this requires one extra memory
+ * allocation when adding new entries to the list.  The context is probably
+ * allocated already and the new list entry requires one additional memory
+ * allocation.  The memory allocation and freeing is done automatically in
+ * the API and does not show to the caller.
  *
  ***/
 
@@ -55,7 +54,7 @@
  *
  * SOURCE
  */
-typedef struct {
+typedef struct SilcDListStruct {
   SilcList list;
 } *SilcDList;
 /***/
@@ -65,14 +64,15 @@ typedef struct {
 typedef struct SilcDListEntryStruct {
   void *context;
   struct SilcDListEntryStruct *next;
+  struct SilcDListEntryStruct *prev;
 } *SilcDListEntry;
 
 /****f* silcutil/SilcDListAPI/silc_dlist_init
  *
  * SYNOPSIS
- * 
+ *
  *    static inline
- *    SilcDList silc_dlist_init();
+ *    SilcDList silc_dlist_init(void);
  *
  * DESCRIPTION
  *
@@ -81,12 +81,14 @@ typedef struct SilcDListEntryStruct {
  ***/
 
 static inline
-SilcDList silc_dlist_init()
+SilcDList silc_dlist_init(void)
 {
   SilcDList list;
 
-  list = (SilcDList)silc_calloc(1, sizeof(*list));
-  silc_list_init(list->list, struct SilcDListEntryStruct, next);
+  list = (SilcDList)silc_malloc(sizeof(*list));
+  if (!list)
+    return NULL;
+  silc_list_init_prev(list->list, struct SilcDListEntryStruct, next, prev);
 
   return list;
 }
@@ -148,7 +150,7 @@ int silc_dlist_count(SilcDList list)
  * DESCRIPTION
  *
  *    Set the start of the list. This prepares the list for traversing entries
- *    from the start of the list.
+ *    from the start of the list towards end of the list.
  *
  ***/
 
@@ -158,6 +160,26 @@ void silc_dlist_start(SilcDList list)
   silc_list_start(list->list);
 }
 
+/****f* silcutil/SilcDListAPI/silc_dlist_end
+ *
+ * SYNOPSIS
+ *
+ *    static inline
+ *    void silc_dlist_end(SilcDList list);
+ *
+ * DESCRIPTION
+ *
+ *    Set the end of the list. This prepares the list for traversing entries
+ *    from the end of the list towards start of the list.
+ *
+ ***/
+
+static inline
+void silc_dlist_end(SilcDList list)
+{
+  silc_list_end(list->list);
+}
+
 /****f* silcutil/SilcDListAPI/silc_dlist_add
  *
  * SYNOPSIS
@@ -175,7 +197,9 @@ void silc_dlist_start(SilcDList list)
 static inline
 void silc_dlist_add(SilcDList list, void *context)
 {
-  SilcDListEntry e = (SilcDListEntry)silc_calloc(1, sizeof(*e));
+  SilcDListEntry e = (SilcDListEntry)silc_malloc(sizeof(*e));
+  if (!e)
+    return;
   e->context = context;
   silc_list_add(list->list, e);
 }
@@ -223,12 +247,12 @@ void silc_dlist_del(SilcDList list, void *context)
  *    Returns current entry from the list and moves the list pointer forward
  *    so that calling this next time returns the next entry from the list.
  *    This can be used to traverse the list. Return SILC_LIST_END when the
- *    entire list has been traversed. Later, silc_list_start must be called
- *    again when re-starting list traversing.
+ *    entire list has been traversed. Later, silc_list_start (or
+ *    silc_dlist_end) must be called again when re-starting list traversing.
  *
  * EXAMPLE
  *
- *    // Traverse the list from the beginning to the end 
+ *    // Traverse the list from the beginning to the end
  *    silc_dlist_start(list)
  *    while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
  *      ...
index 696a0220f4c331744216bf9330a3f326276b8b07..6478382a94e51e19eadfe4d6ae261aafa1cceca9 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  silchashtable.c 
+  silchashtable.c
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2001 - 2002 Pekka Riikonen
+  Copyright (C) 2001 - 2003 Pekka Riikonen
 
   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
@@ -19,7 +19,7 @@
 /* Implementation of collision resistant hash table. This is a hash table
    that provides a reliable (what you add stays there, and duplicate keys
    are allowed) with as fast reference to the key as possible. If duplicate
-   keys are a lot in the hash table the lookup gets slower of course. 
+   keys are a lot in the hash table the lookup gets slower of course.
    However, this is reliable and no data is lost at any point. If you know
    that you never have duplicate keys then this is as fast as any simple
    hash table. */
@@ -77,9 +77,9 @@ struct SilcHashTableStruct {
 
 /* Prime sizes for the hash table. The size of the table will always
    be one of these. */
-const SilcUInt32 primesize[42] = 
+const SilcUInt32 primesize[42] =
 {
-  1, 3, 5, 11, 17, 37, 67, 109, 131, 163, 257, 367, 521, 823, 1031, 
+  1, 3, 5, 11, 17, 37, 67, 109, 131, 163, 257, 367, 521, 823, 1031,
   1237, 2053, 2777, 4099, 6247, 8209, 14057, 16411, 21089, 32771, 47431,
   65537, 106721, 131101, 262147, 360163, 524309, 810343, 1048583, 2097169,
   4194319, 6153409, 8388617, 13845163, 16777259, 33554467, 67108879
@@ -91,7 +91,7 @@ static SilcUInt32 silc_hash_table_primesize(SilcUInt32 size, SilcUInt32 *index)
 {
   int i;
 
-  for (i = 0; i < sizeof(primesize); i++)
+  for (i = 0; i < sizeof(primesize) / sizeof(primesize[0]); i++)
     if (primesize[i] >= size) {
       *index = i;
       SILC_HT_DEBUG(("sizeof of the hash table is %d", primesize[*index]));
@@ -110,7 +110,7 @@ static inline SilcHashTableEntry *
 silc_hash_table_find_internal(SilcHashTable ht, void *key,
                              SilcHashTableEntry *prev_entry,
                              SilcHashFunction hash, void *hash_user_context,
-                             SilcHashCompare compare, 
+                             SilcHashCompare compare,
                              void *compare_user_context)
 {
   SilcHashTableEntry *entry, prev = NULL;
@@ -142,9 +142,9 @@ static inline SilcHashTableEntry *
 silc_hash_table_find_internal_context(SilcHashTable ht, void *key,
                                      void *context,
                                      SilcHashTableEntry *prev_entry,
-                                     SilcHashFunction hash, 
+                                     SilcHashFunction hash,
                                      void *hash_user_context,
-                                     SilcHashCompare compare, 
+                                     SilcHashCompare compare,
                                      void *compare_user_context)
 {
   SilcHashTableEntry *entry, prev = NULL;
@@ -206,7 +206,7 @@ silc_hash_table_find_internal_simple(SilcHashTable ht, void *key,
    hash and comparison functions. */
 
 static inline void
-silc_hash_table_find_internal_all(SilcHashTable ht, void *key, 
+silc_hash_table_find_internal_all(SilcHashTable ht, void *key,
                                  SilcHashFunction hash,
                                  void *hash_user_context,
                                  SilcHashCompare compare,
@@ -255,9 +255,9 @@ silc_hash_table_find_internal_all(SilcHashTable ht, void *key,
 
 /* Internal routine to add new key to the hash table */
 
-static inline void
+static inline bool
 silc_hash_table_add_internal(SilcHashTable ht, void *key, void *context,
-                            SilcHashFunction hash, 
+                            SilcHashFunction hash,
                             void *hash_user_context)
 {
   SilcHashTableEntry *entry;
@@ -281,6 +281,8 @@ silc_hash_table_add_internal(SilcHashTable ht, void *key, void *context,
     SILC_HT_DEBUG(("Collision; adding new key to list"));
 
     e->next = silc_calloc(1, sizeof(*e->next));
+    if (!e->next)
+      return FALSE;
     e->next->key = key;
     e->next->context = context;
     ht->entry_count++;
@@ -288,6 +290,8 @@ silc_hash_table_add_internal(SilcHashTable ht, void *key, void *context,
     /* New key */
     SILC_HT_DEBUG(("New key"));
     *entry = silc_calloc(1, sizeof(**entry));
+    if (!(*entry))
+      return FALSE;
     (*entry)->key = key;
     (*entry)->context = context;
     ht->entry_count++;
@@ -295,13 +299,15 @@ silc_hash_table_add_internal(SilcHashTable ht, void *key, void *context,
 
   if (SILC_HASH_REHASH_INC)
     silc_hash_table_rehash(ht, 0);
+
+  return TRUE;
 }
 
 /* Internal routine to replace old key with new one (if it exists) */
 
-static inline void
+static inline bool
 silc_hash_table_replace_internal(SilcHashTable ht, void *key, void *context,
-                                SilcHashFunction hash, 
+                                SilcHashFunction hash,
                                 void *hash_user_context)
 {
   SilcHashTableEntry *entry;
@@ -314,11 +320,13 @@ silc_hash_table_replace_internal(SilcHashTable ht, void *key, void *context,
     /* The entry exists already. We have a collision, replace the old
        key and context. */
     if (ht->destructor)
-      ht->destructor((*entry)->key, (*entry)->context, 
+      ht->destructor((*entry)->key, (*entry)->context,
                     ht->destructor_user_context);
   } else {
     /* New key */
     *entry = silc_calloc(1, sizeof(**entry));
+    if (!(*entry))
+      return FALSE;
     ht->entry_count++;
   }
 
@@ -327,6 +335,8 @@ silc_hash_table_replace_internal(SilcHashTable ht, void *key, void *context,
 
   if (SILC_HASH_REHASH_INC)
     silc_hash_table_rehash(ht, 0);
+
+  return TRUE;
 }
 
 /* Allocates new hash table and returns it.  If the `table_size' is not
@@ -337,7 +347,7 @@ silc_hash_table_replace_internal(SilcHashTable ht, void *key, void *context,
    destructor function, respectively. The `hash' is mandatory, the others
    are optional. */
 
-SilcHashTable silc_hash_table_alloc(SilcUInt32 table_size, 
+SilcHashTable silc_hash_table_alloc(SilcUInt32 table_size,
                                    SilcHashFunction hash,
                                    void *hash_user_context,
                                    SilcHashCompare compare,
@@ -353,10 +363,16 @@ SilcHashTable silc_hash_table_alloc(SilcUInt32 table_size,
     return NULL;
 
   ht = silc_calloc(1, sizeof(*ht));
+  if (!ht)
+    return NULL;
   ht->table = silc_calloc(table_size ? silc_hash_table_primesize(table_size,
                                                                 &size_index) :
                          primesize[SILC_HASH_TABLE_SIZE],
                          sizeof(*ht->table));
+  if (!ht->table) {
+    silc_free(ht);
+    return NULL;
+  }
   ht->table_size = size_index;
   ht->hash = hash;
   ht->compare = compare;
@@ -415,7 +431,7 @@ SilcUInt32 silc_hash_table_count(SilcHashTable ht)
 
 void silc_hash_table_add(SilcHashTable ht, void *key, void *context)
 {
-  silc_hash_table_add_internal(ht, key, context, ht->hash, 
+  silc_hash_table_add_internal(ht, key, context, ht->hash,
                               ht->hash_user_context);
 }
 
@@ -434,14 +450,14 @@ void silc_hash_table_add_ext(SilcHashTable ht, void *key, void *context,
 
 void silc_hash_table_replace(SilcHashTable ht, void *key, void *context)
 {
-  silc_hash_table_replace_internal(ht, key, context, ht->hash, 
+  silc_hash_table_replace_internal(ht, key, context, ht->hash,
                                   ht->hash_user_context);
 }
 
 /* Same as above but with specific hash function. */
 
 void silc_hash_table_replace_ext(SilcHashTable ht, void *key, void *context,
-                                SilcHashFunction hash, 
+                                SilcHashFunction hash,
                                 void *hash_user_context)
 {
   silc_hash_table_replace_internal(ht, key, context, hash, hash_user_context);
@@ -487,9 +503,9 @@ bool silc_hash_table_del(SilcHashTable ht, void *key)
 /* Same as above but with specific hash and compare functions. */
 
 bool silc_hash_table_del_ext(SilcHashTable ht, void *key,
-                            SilcHashFunction hash, 
+                            SilcHashFunction hash,
                             void *hash_user_context,
-                            SilcHashCompare compare, 
+                            SilcHashCompare compare,
                             void *compare_user_context,
                             SilcHashDestructor destructor,
                             void *destructor_user_context)
@@ -501,7 +517,7 @@ bool silc_hash_table_del_ext(SilcHashTable ht, void *key,
                                        hash_user_context ? hash_user_context :
                                        ht->hash_user_context,
                                        compare ? compare : ht->compare,
-                                       compare_user_context ? 
+                                       compare_user_context ?
                                        compare_user_context :
                                        ht->compare_user_context);
   if (*entry == NULL)
@@ -539,13 +555,13 @@ bool silc_hash_table_del_ext(SilcHashTable ht, void *key,
    have duplicate keys. In that case the `context' may be used to check
    whether the correct entry is being deleted. */
 
-bool silc_hash_table_del_by_context(SilcHashTable ht, void *key, 
+bool silc_hash_table_del_by_context(SilcHashTable ht, void *key,
                                    void *context)
 {
   SilcHashTableEntry *entry, prev, e;
 
   entry = silc_hash_table_find_internal_context(ht, key, context, &prev,
-                                               ht->hash, 
+                                               ht->hash,
                                                ht->hash_user_context,
                                                ht->compare,
                                                ht->compare_user_context);
@@ -577,11 +593,11 @@ bool silc_hash_table_del_by_context(SilcHashTable ht, void *key,
 
 /* Same as above but with specific hash and compare functions. */
 
-bool silc_hash_table_del_by_context_ext(SilcHashTable ht, void *key, 
+bool silc_hash_table_del_by_context_ext(SilcHashTable ht, void *key,
                                        void *context,
-                                       SilcHashFunction hash, 
+                                       SilcHashFunction hash,
                                        void *hash_user_context,
-                                       SilcHashCompare compare, 
+                                       SilcHashCompare compare,
                                        void *compare_user_context,
                                        SilcHashDestructor destructor,
                                        void *destructor_user_context)
@@ -590,12 +606,12 @@ bool silc_hash_table_del_by_context_ext(SilcHashTable ht, void *key,
 
   entry = silc_hash_table_find_internal_context(ht, key, context, &prev,
                                                hash ? hash : ht->hash,
-                                               hash_user_context ? 
+                                               hash_user_context ?
                                                hash_user_context :
                                                ht->hash_user_context,
-                                               compare ? 
+                                               compare ?
                                                compare : ht->compare,
-                                               compare_user_context ? 
+                                               compare_user_context ?
                                                compare_user_context :
                                                ht->compare_user_context);
   if (*entry == NULL)
@@ -629,7 +645,7 @@ bool silc_hash_table_del_by_context_ext(SilcHashTable ht, void *key,
 }
 
 /* Finds the entry in the hash table by the provided `key' as fast as
-   possible. Return TRUE if the entry was found and FALSE otherwise. 
+   possible. Return TRUE if the entry was found and FALSE otherwise.
    The found entry is returned to the `ret_key' and `ret_context',
    respectively. If the `ret_key and `ret_context' are NULL then this
    maybe used only to check whether given key exists in the table. */
@@ -639,9 +655,9 @@ bool silc_hash_table_find(SilcHashTable ht, void *key,
 {
   SilcHashTableEntry *entry;
 
-  entry = silc_hash_table_find_internal_simple(ht, key, ht->hash, 
+  entry = silc_hash_table_find_internal_simple(ht, key, ht->hash,
                                               ht->hash_user_context,
-                                              ht->compare, 
+                                              ht->compare,
                                               ht->compare_user_context);
   if (*entry == NULL)
     return FALSE;
@@ -658,20 +674,20 @@ bool silc_hash_table_find(SilcHashTable ht, void *key,
 
 bool silc_hash_table_find_ext(SilcHashTable ht, void *key,
                              void **ret_key, void **ret_context,
-                             SilcHashFunction hash, 
+                             SilcHashFunction hash,
                              void *hash_user_context,
-                             SilcHashCompare compare, 
+                             SilcHashCompare compare,
                              void *compare_user_context)
 {
   SilcHashTableEntry *entry;
 
   entry = silc_hash_table_find_internal_simple(ht, key,
-                                              hash ? hash : ht->hash, 
-                                              hash_user_context ? 
+                                              hash ? hash : ht->hash,
+                                              hash_user_context ?
                                               hash_user_context :
                                               ht->hash_user_context,
                                               compare ? compare :
-                                              ht->compare, 
+                                              ht->compare,
                                               compare_user_context ?
                                               compare_user_context :
                                               ht->compare_user_context);
@@ -692,9 +708,9 @@ bool silc_hash_table_find_by_context(SilcHashTable ht, void *key,
                                     void *context, void **ret_key)
 {
   SilcHashTableEntry *entry;
-  
+
   entry = silc_hash_table_find_internal_context(ht, key, context, NULL,
-                                               ht->hash, 
+                                               ht->hash,
                                                ht->hash_user_context,
                                                ht->compare,
                                                ht->compare_user_context);
@@ -723,20 +739,20 @@ void silc_hash_table_find_foreach(SilcHashTable ht, void *key,
 /* Same as above but with specific hash and comparison functions. */
 
 void silc_hash_table_find_foreach_ext(SilcHashTable ht, void *key,
-                                     SilcHashFunction hash, 
+                                     SilcHashFunction hash,
                                      void *hash_user_context,
-                                     SilcHashCompare compare, 
+                                     SilcHashCompare compare,
                                      void *compare_user_context,
-                                     SilcHashForeach foreach, 
+                                     SilcHashForeach foreach,
                                      void *foreach_user_context)
 {
   silc_hash_table_find_internal_all(ht, key,
-                                   hash ? hash : ht->hash, 
-                                   hash_user_context ? 
+                                   hash ? hash : ht->hash,
+                                   hash_user_context ?
                                    hash_user_context :
                                    ht->hash_user_context,
                                    compare ? compare :
-                                   ht->compare, 
+                                   ht->compare,
                                    compare_user_context ?
                                    compare_user_context :
                                    ht->compare_user_context,
@@ -780,6 +796,7 @@ void silc_hash_table_rehash(SilcHashTable ht, SilcUInt32 new_size)
   int i;
   SilcHashTableEntry *table, e, tmp;
   SilcUInt32 table_size, size_index;
+  bool auto_rehash;
 
   SILC_HT_DEBUG(("Start"));
 
@@ -796,9 +813,13 @@ void silc_hash_table_rehash(SilcHashTable ht, SilcUInt32 new_size)
   /* Take old hash table */
   table = ht->table;
   table_size = ht->table_size;
+  auto_rehash = ht->auto_rehash;
+  ht->auto_rehash = FALSE;
 
   /* Allocate new table */
   ht->table = silc_calloc(primesize[size_index], sizeof(*ht->table));
+  if (!ht->table)
+    return;
   ht->table_size = size_index;
   ht->entry_count = 0;
 
@@ -815,6 +836,8 @@ void silc_hash_table_rehash(SilcHashTable ht, SilcUInt32 new_size)
     }
   }
 
+  ht->auto_rehash = auto_rehash;
+
   /* Remove old table */
   silc_free(table);
 }
@@ -822,12 +845,13 @@ void silc_hash_table_rehash(SilcHashTable ht, SilcUInt32 new_size)
 /* Same as above but with specific hash function. */
 
 void silc_hash_table_rehash_ext(SilcHashTable ht, SilcUInt32 new_size,
-                               SilcHashFunction hash, 
+                               SilcHashFunction hash,
                                void *hash_user_context)
 {
   int i;
   SilcHashTableEntry *table, e, tmp;
   SilcUInt32 table_size, size_index;
+  bool auto_rehash;
 
   SILC_HT_DEBUG(("Start"));
 
@@ -844,9 +868,13 @@ void silc_hash_table_rehash_ext(SilcHashTable ht, SilcUInt32 new_size,
   /* Take old hash table */
   table = ht->table;
   table_size = ht->table_size;
+  auto_rehash = ht->auto_rehash;
+  ht->auto_rehash = FALSE;
 
   /* Allocate new table */
   ht->table = silc_calloc(primesize[size_index], sizeof(*ht->table));
+  if (!ht->table)
+    return;
   ht->table_size = size_index;
   ht->entry_count = 0;
 
@@ -854,7 +882,7 @@ void silc_hash_table_rehash_ext(SilcHashTable ht, SilcUInt32 new_size,
   for (i = 0; i < primesize[table_size]; i++) {
     e = table[i];
     while (e) {
-      silc_hash_table_add_ext(ht, e->key, e->context, hash, 
+      silc_hash_table_add_ext(ht, e->key, e->context, hash,
                              hash_user_context);
       tmp = e;
       e = e->next;
@@ -864,6 +892,8 @@ void silc_hash_table_rehash_ext(SilcHashTable ht, SilcUInt32 new_size,
     }
   }
 
+  ht->auto_rehash = auto_rehash;
+
   /* Remove old table */
   silc_free(table);
 }
index 690eff478f872fccb8b1b55afa2ae88b96bae0a0..478ea184a6a23128f8d710c899bb26a4de2a151b 100644 (file)
@@ -89,8 +89,8 @@ typedef struct SilcHashTableListStruct SilcHashTableList;
 struct SilcHashTableListStruct {
   SilcHashTable ht;
   void *entry;
-  SilcUInt32 index;
-  bool auto_rehash;
+  unsigned int index        : 31;
+  unsigned int auto_rehash  : 1;
 };
 /***/
 
@@ -138,7 +138,7 @@ typedef bool (*SilcHashCompare)(void *key1, void *key2, void *user_context);
  * DESCRIPTION
  *
  *    A destructor callback that the library will call to destroy the 
- *    `key' and `context'.  The appliation provides the function when
+ *    `key' and `context'.  The application provides the function when
  *    allocating a new hash table. The `user_context' is application
  *    specific context and is delivered to the callback.
  *
index 76dcf69239ed1f92e490336ab2a05225671a2be6..60e1bcc4f31e3ef32b44564ad5ebca45a77a62b8 100644 (file)
@@ -1,16 +1,15 @@
 /*
 
-  silclist.h
+  silclist.h 
 
-  Author: Timo Sirainen <tss@iki.fi>
+  Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2002 Timo Sirainen
+  Copyright (C) 2002 - 2003 Pekka Riikonen
 
   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.
-  
+  the Free Software Foundation; version 2 of the License.
+
   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
  *    This is the SilcList context, and is initialized by calling the
  *    function silc_list_init.
  *
- * EXAMPLE
- *
- *     SilcList list;
- *     silc_list_init(list, struct SilcInternalEntryStruct, next);
- *
  ***/
 typedef struct {
-  void *head, *tail;
-  void *current;
-  int offset;
+  void *head;                       /* Start of the list */
+  void *tail;                       /* End of the list */
+  void *current;                    /* Current pointer in list */
+  unsigned int next_offset : 16;     /* Offset to 'next' pointer */
+  unsigned int prev_offset : 16;     /* Offset to 'prev' pointer */
+  unsigned int prev_set    : 1;             /* Set if 'prev' exists */
+  unsigned int end_set     : 1;             /* Set if silc_list_end was called */
+  unsigned int count       : 30;     /* Number of entries in the list */
 } SilcList;
 
 /****d* silcutil/SilcList/SILC_LIST_END
@@ -69,41 +68,21 @@ typedef struct {
 #define SILC_LIST_END NULL
 /***/
 
-/* Initializes SilcList object. Example:
-
-   SilcList list;
-
-   silc_list_init(list, struct SilcInternalEntryStruct, next);
-
-   Where `list' is the defined list, and second argument is the structure
-   of the entries in the list and last argument is the pointer in the entry
-   structure that is used as list member. SilcInternalEntry might be as 
-   follows:
-
-   struct SilcInternalEntryStruct {
-     char *dummy;
-     struct SilcInternalEntryStruct *next; // The list member pointer
-   };
-
-   The `next' pointer in the structure (or some other pointer for that matter)
-   is given for the silc_list_init as the last argument. This pointer is used
-   by the list routines to link the entries together in the list. Your code
-   should not touch the member pointer manually.
-*/
-
 /****f* silcutil/SilcList/silc_list_init
  *
  * SYNOPSIS
  *
- *    #define silc_list_init(list, type, field) ...
+ *    #define silc_list_init(list, type, nextfield) ...
  *
  * DESCRIPTION
  *
  *    This macro initializes the SilcList list.  The `list' is the defined
  *    list, second argument is the structure of the entries in the list,
- *    and last argument is the pointer in the entry structure that is used
- *    as list member.  When using SilcList, you should not touch the
- *    structure member pointer (the `next' for example) manually.
+ *    and last argument is the pointer in the structure that is used
+ *    as next list members.  When using SilcList you must not touch the
+ *    structure member pointers manually.  If your list has also a prev
+ *    pointer should use silc_list_init_prev instead of this call if
+ *    you need to be able traverse the list backwards as well.
  *
  * EXAMPLE
  *
@@ -116,16 +95,53 @@ typedef struct {
  *    silc_list_init(list, struct SilcInternalEntryStruct, next);
  *
  ***/
-#define silc_list_init(list, type, field) \
-  __silc_list_init(&(list), silc_offsetof(type, field))
-
-static inline void __silc_list_init(SilcList *list, int offset)
-{
-  list->head = list->tail = list->current = SILC_LIST_END;
-  list->offset = offset;
-}
+#define silc_list_init(list, type, nextfield)          \
+do {                                                   \
+  (list).count = 0;                                    \
+  (list).next_offset = silc_offsetof(type, nextfield); \
+  (list).prev_set = 0;                                 \
+  (list).prev_offset = 0;                              \
+  (list).head = (list).tail = (list).current = NULL;   \
+} while(0)
 
-#define list_next(list, pos) ((void **) ((char *) (pos) + (list)->offset))
+/****f* silcutil/SilcList/silc_list_init_prev
+ *
+ * SYNOPSIS
+ *
+ *    #define silc_list_init_prev(list, type, nextfield, prevfield) ...
+ *
+ * DESCRIPTION
+ *
+ *    This macro initializes the SilcList list.  The `list' is the defined
+ *    list, second argument is the structure of the entries in the list,
+ *    and last two arguments are the pointers in the structure that is used
+ *    as next and prev list members.  When using SilcList you must not
+ *    touch the structure member pointers manually.
+ *
+ *    Having both next and prev pointers makes it possible to traverse
+ *    list from both ends of the list (from start to end, and from end
+ *    to start).
+ *
+ * EXAMPLE
+ *
+ *    struct SilcInternalEntryStruct {
+ *      char *dummy;
+ *      struct SilcInternalEntryStruct *next; // The list member pointer
+ *      struct SilcInternalEntryStruct *prev; // The list member pointer
+ *    };
+ *
+ *    SilcList list;
+ *    silc_list_init(list, struct SilcInternalEntryStruct, next, prev);
+ *
+ ***/
+#define silc_list_init_prev(list, type, nextfield, prevfield)  \
+do {                                                           \
+  (list).count = 0;                                            \
+  (list).next_offset = silc_offsetof(type, nextfield);         \
+  (list).prev_offset = silc_offsetof(type, prevfield);         \
+  (list).prev_set = 1;                                         \
+  (list).head = (list).tail = (list).current = NULL;           \
+} while(0)
 
 /****f* silcutil/SilcList/silc_list_count
  *
@@ -138,17 +154,7 @@ static inline void __silc_list_init(SilcList *list, int offset)
  *    Returns the number of entries in the list indicated by `list'.
  *
  ***/
-#define silc_list_count(list) __silc_list_count(&(list))
-static inline int __silc_list_count(SilcList *list)
-{
-  int count = 0;
-  void *pos;
-
-  for (pos = list->head; pos != NULL; pos = *list_next(list, pos))
-    count++;
-
-  return count;
-}
+#define silc_list_count(list) (list).count
 
 /****f* silcutil/SilcList/silc_list_start
  *
@@ -159,10 +165,37 @@ static inline int __silc_list_count(SilcList *list)
  * DESCRIPTION
  *
  *    Sets the start of the list.  This prepares the list for traversing
- *    the entries from the start of the list.
+ *    the entries from the start of the list towards end of the list.
+ *
+ ***/
+#define silc_list_start(list)                          \
+  ((list).current = (list).head, (list).end_set = 0)
+
+/****f* silcutil/SilcList/silc_list_end
+ *
+ * SYNOPSIS
+ *
+ *    #define silc_list_end(list) ...
+ *
+ * DESCRIPTION
+ *
+ *    Sets the end of the list.  This prepares the list for traversing
+ *    the entries from the end of the list towards start of the list.
+ *
+ * NOTES
+ *
+ *    You can use this call only if you initialized the list with
+ *    silc_list_init_prev.
  *
  ***/
-#define silc_list_start(list) (list).current = (list).head;
+#define silc_list_end(list)                            \
+  ((list).current = (list).tail, (list).end_set = 1)
+
+/* Macros to get position to next and prev list pointers */
+#define __silc_list_next(list, pos)                            \
+  ((void **)((unsigned char *)(pos) + (list).next_offset))
+#define __silc_list_prev(list, pos)                            \
+  ((void **)((unsigned char *)(pos) + (list).prev_offset))
 
 /****f* silcutil/SilcList/silc_list_add
  *
@@ -176,17 +209,18 @@ static inline int __silc_list_count(SilcList *list)
  *    by `list'.
  *
  ***/
-#define silc_list_add(list, entry) __silc_list_add(&(list), entry)
-static inline void __silc_list_add(SilcList *list, void *data)
-{
-  if (list->head == NULL)
-    list->head = data;
-  else
-    *list_next(list, list->tail) = data;
-
-  list->tail = data;
-  *list_next(list, data) = NULL;
-}
+#define silc_list_add(list, entry)                     \
+do {                                                   \
+  if (!(list).head)                                    \
+    (list).head = (entry);                             \
+  else                                                 \
+    *__silc_list_next(list, (list).tail) = (entry);    \
+  if ((list).prev_set)                                 \
+    *__silc_list_prev(list, entry) = (list).tail;      \
+  (list).tail = (entry);                               \
+  *__silc_list_next(list, entry) = NULL;               \
+  (list).count++;                                      \
+} while(0)
 
 /****f* silcutil/SilcList/silc_list_del
  *
@@ -199,32 +233,31 @@ static inline void __silc_list_add(SilcList *list, void *data)
  *    Remove entry indicated by `entry' from the list indicated by `list'.
  *
  ***/
-#define silc_list_del(list, data) __silc_list_del(&(list), data)
-static inline void __silc_list_del(SilcList *list, void *data)
-{
-  void **pos, *prev;
-
-  prev = NULL;
-  for (pos = &list->head; *pos != NULL; pos = list_next(list, *pos)) {
-    if (*pos == data) {
-      *pos = *list_next(list, data);
-      if (list->current == data)
-        list->current = *pos;
-      break;
-    }
-
-    prev = *pos;
-  }
-
-  if (data == list->tail)
-    list->tail = prev;
-}
+#define silc_list_del(list, entry)                                     \
+do {                                                                   \
+  void **p, *prev;                                                     \
+  prev = NULL;                                                         \
+  for (p = &(list).head; *p; p = __silc_list_next(list, *p)) {         \
+    if (*p == (entry)) {                                               \
+      *p = *__silc_list_next(list, entry);                             \
+      if (*p && (list).prev_set)                                       \
+        *__silc_list_prev(list, *p) = *__silc_list_prev(list, entry);  \
+      if ((list).current == (entry))                                   \
+        (list).current = *p;                                           \
+      (list).count--;                                                  \
+      break;                                                           \
+    }                                                                  \
+    prev = *p;                                                         \
+  }                                                                    \
+  if (entry == (list).tail)                                            \
+    (list).tail = prev;                                                        \
+} while(0)
 
 /****f* silcutil/SilcList/silc_list_get
  *
  * SYNOPSIS
  *
- *    #define silc_list_get(list, entry) ...
+ *    #define silc_list_get(list) ...
  *
  * DESCRIPTION
  *
@@ -233,28 +266,32 @@ static inline void __silc_list_del(SilcList *list, void *data)
  *    return the next entry from the list.  This can be used to traverse
  *    the list.  Returns SILC_LIST_END when the entire list has been
  *    tarversed and no additional entries exist in the list. Later,
- *    silc_list_start must be called again when re-starting the list
- *    tarversing.
+ *    silc_list_start (or silc_list_end) must be called again when
+ *    re-starting the list tarversing.
  *
  * EXAMPLE
  *
  *    // Traverse the list from the beginning to the end 
- *    silc_list_start(list)
+ *    silc_list_start(list);
+ *    while ((entry = silc_list_get(list)) != SILC_LIST_END) {
+ *      ...
+ *    }
+ *
+ *    // Traverse the list from the end to the beginning
+ *    silc_list_end(list);
  *    while ((entry = silc_list_get(list)) != SILC_LIST_END) {
  *      ...
  *    }
  *
  ***/
 #define silc_list_get(x) __silc_list_get(&(x))
-
 static inline
 void *__silc_list_get(SilcList *list)
 {
-  void *pos;
-
-  pos = list->current;
-  if (pos != NULL)
-    list->current = *list_next(list, pos);
+  void *pos = list->current;
+  if (pos)
+    list->current = (list->end_set ? *__silc_list_prev(*list, pos) :
+                    *__silc_list_next(*list, pos));
   return pos;
 }
 
index 337c882e252fe3067b2ed61a00edb17f198455b4..eeaee1edf9283fab06005477da91c21f625835a3 100644 (file)
@@ -41,6 +41,7 @@
  *    This is the main logging channel id. There are currently four known
  *    logging channels (plus the debugging output channel), and they are
  *    ordered by importance.
+ *
  *    See the source code for SILC coding conventions about how to choose
  *    the right output channel.
  *
@@ -433,6 +434,7 @@ extern DLLAPI bool silc_debug_hexdump;
  *
  *    This is the main function for logging output. Please note that you
  *    should rather use one of the logging wrapper macros.
+ *
  *    If you really want to use this function, its usage is quite simple.
  *    The `type' parameter identifies the channel to use, while the `string'
  *    parameter must be a dynamic allocated (null-terminated) buffer, because
@@ -459,6 +461,7 @@ void silc_log_output(SilcLogType type, char *string);
  *    If there has been an error during the opening of this channel, NULL
  *    is returned, even if the file has been previously set with
  *    silc_log_set_file().
+ *
  *    The returned pointer points to internally allocated storage and must
  *    not be freed, modified or stored.
  *
@@ -479,10 +482,11 @@ char *silc_log_get_file(SilcLogType type);
  *    logging file for the channel `type'.  If you specify an illegal filename
  *    a warning message is printed and FALSE is returned.  In this case
  *    logging settings are not changed.
+ *
  *    You can disable logging for a channel by specifying NULL filename, the
- *    maxsize in this case is not important.
- *    The `scheduler' parameter is needed by the internal logging to allow
- *    buffered output and thus to save HD activity.
+ *    maxsize in this case is not important.  The `scheduler' parameter is 
+ *    needed by the internal logging to allow buffered output and thus to 
+ *    save HD activity.
  *
  ***/
 bool silc_log_set_file(SilcLogType type, char *filename, SilcUInt32 maxsize,
@@ -502,10 +506,10 @@ bool silc_log_set_file(SilcLogType type, char *filename, SilcUInt32 maxsize,
  *    trigger the callback function.  If the callback function returns TRUE
  *    SilcLog will assume the input as handled and won't run its default
  *    handler.
+ *
  *    You can disable/remove a callback by setting it to NULL or calling the
- *    function silc_log_reset_callbacks.
- *    If set, the callback function must be in the form described by
- *    SilcLogCb.
+ *    function silc_log_reset_callbacks.  If set, the callback function 
+ *    must be in the form described by SilcLogCb.
  *
  * SEE ALSO
  *    silc_log_reset_callbacks
index a474d1651ce4c4b2cad15636a62b8b46d4462456..5ca563035b4aa6b3008d82a48e04da47628873ac 100644 (file)
@@ -344,16 +344,17 @@ static void silc_schedule_dispatch_nontimeout(SilcSchedule schedule)
   SilcTask task;
   int i;
   SilcUInt32 fd, last_fd = schedule->last_fd;
+  SilcUInt16 revents;
 
   for (i = 0; i <= last_fd; i++) {
     if (schedule->fd_list[i].events == 0)
       continue;
 
-    fd = schedule->fd_list[i].fd;
-
     /* First check whether this fd has task in the fd queue */
     silc_mutex_lock(schedule->fd_queue->lock);
+    fd = schedule->fd_list[i].fd;
     task = silc_task_find(schedule->fd_queue, fd);
+    revents = schedule->fd_list[i].revents;
 
     /* If the task was found then execute its callbacks. If not then
        execute all generic tasks for that fd. */
@@ -363,7 +364,7 @@ static void silc_schedule_dispatch_nontimeout(SilcSchedule schedule)
         in the callback function, ie. it is not valid anymore. */
 
       /* Is the task ready for reading */
-      if (task->valid && schedule->fd_list[i].revents & SILC_TASK_READ) {
+      if (task->valid && revents & SILC_TASK_READ) {
        silc_mutex_unlock(schedule->fd_queue->lock);
        SILC_SCHEDULE_UNLOCK(schedule);
        task->callback(schedule, schedule->app_context,
@@ -373,7 +374,7 @@ static void silc_schedule_dispatch_nontimeout(SilcSchedule schedule)
       }
 
       /* Is the task ready for writing */
-      if (task->valid && schedule->fd_list[i].revents & SILC_TASK_WRITE) {
+      if (task->valid && revents & SILC_TASK_WRITE) {
        silc_mutex_unlock(schedule->fd_queue->lock);
        SILC_SCHEDULE_UNLOCK(schedule);
        task->callback(schedule, schedule->app_context,
@@ -404,7 +405,7 @@ static void silc_schedule_dispatch_nontimeout(SilcSchedule schedule)
           in the callback function, ie. it is not valid anymore. */
 
        /* Is the task ready for reading */                             
-       if (task->valid && schedule->fd_list[i].revents & SILC_TASK_READ &&
+       if (task->valid && revents & SILC_TASK_READ &&
            fd == schedule->fd_list[i].fd) {
          silc_mutex_unlock(schedule->generic_queue->lock);
          SILC_SCHEDULE_UNLOCK(schedule);
@@ -415,7 +416,7 @@ static void silc_schedule_dispatch_nontimeout(SilcSchedule schedule)
        }
 
        /* Is the task ready for writing */                             
-       if (task->valid && schedule->fd_list[i].revents & SILC_TASK_WRITE &&
+       if (task->valid && revents & SILC_TASK_WRITE &&
            fd == schedule->fd_list[i].fd) {
          silc_mutex_unlock(schedule->generic_queue->lock);
          SILC_SCHEDULE_UNLOCK(schedule);
index 6817c5daea20f98150f7c52b3e9f4a696bc97e3e..a49422487a0329c1262989edbe2ff790fce95248 100644 (file)
@@ -103,6 +103,10 @@ SILC_TASK_CALLBACK(silc_socket_heartbeat)
   if (!hb->heartbeat)
     return;
 
+  if (SILC_IS_DISCONNECTING(hb->sock) ||
+      SILC_IS_DISCONNECTED(hb->sock))
+    return;
+
   if (hb->hb_callback)
     hb->hb_callback(hb->sock, hb->hb_context);
 
@@ -250,6 +254,10 @@ void silc_socket_host_lookup(SilcSocketConnection sock,
 
   SILC_LOG_DEBUG(("Performing async host lookup"));
 
+  if (SILC_IS_DISCONNECTING(sock) ||
+      SILC_IS_DISCONNECTED(sock))
+    return;
+
   lookup = silc_calloc(1, sizeof(*lookup));
   lookup->sock = silc_socket_dup(sock);        /* Increase reference counter */
   lookup->callback = callback;
index b685f0557d0b10613f984d09ffcb6a928030fccb..de215d60bb6957aa744536acd020efb59922750b 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2002 Pekka Riikonen
+  Copyright (C) 2002 - 2003 Pekka Riikonen
 
   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
@@ -25,8 +25,7 @@ static unsigned char pem_enc[64] =
 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
 /* Encodes data into PEM encoding. Returns NULL terminated PEM encoded
-   data string. Note: This is originally public domain code and is
-   still PD. */
+   data string. */
 
 char *silc_pem_encode(unsigned char *data, SilcUInt32 len)
 {
@@ -102,8 +101,7 @@ char *silc_pem_encode_file(unsigned char *data, SilcUInt32 data_len)
   return pem2;
 }
 
-/* Decodes PEM into data. Returns the decoded data. Note: This is
-   originally public domain code and is still PD. */
+/* Decodes PEM into data. Returns the decoded data. */
 
 unsigned char *silc_pem_decode(unsigned char *pem, SilcUInt32 pem_len,
                               SilcUInt32 *ret_len)
@@ -232,22 +230,31 @@ SilcUInt32 silc_utf8_encode(const unsigned char *bin, SilcUInt32 bin_len,
       return 0;
       break;
     case SILC_STRING_BMP:
+      if (i + 1 >= bin_len)
+       return 0;
       SILC_GET16_MSB(charval, bin + i);
       i += 1;
       break;
     case SILC_STRING_BMP_LSB:
+      if (i + 1 >= bin_len)
+       return 0;
       SILC_GET16_LSB(charval, bin + i);
       i += 1;
       break;
     case SILC_STRING_UNIVERSAL:
+      if (i + 3 >= bin_len)
+       return 0;
       SILC_GET32_MSB(charval, bin + i);
       i += 3;
       break;
     case SILC_STRING_UNIVERSAL_LSB:
+      if (i + 3 >= bin_len)
+       return 0;
       SILC_GET32_LSB(charval, bin + i);
       i += 3;
       break;
-    case SILC_STRING_LANGUAGE:
+    default:
+      return 0;
       break;
     }
 
@@ -370,8 +377,8 @@ SilcUInt32 silc_utf8_decode(const unsigned char *utf8, SilcUInt32 utf8_len,
     if ((utf8[i] & 0x80) == 0x00) {
       charval = utf8[i] & 0x7f;
     } else if ((utf8[i] & 0xe0) == 0xc0) {
-      if (utf8_len < 2)
-        return 0;
+      if (i + 1 >= utf8_len)
+       return 0;
 
       if ((utf8[i + 1] & 0xc0) != 0x80)
         return 0;
@@ -381,8 +388,8 @@ SilcUInt32 silc_utf8_decode(const unsigned char *utf8, SilcUInt32 utf8_len,
       if (charval < 0x80)
         return 0;
     } else if ((utf8[i] & 0xf0) == 0xe0) {
-      if (utf8_len < 3)
-        return 0;
+      if (i + 2 >= utf8_len)
+       return 0;
 
       if (((utf8[i + 1] & 0xc0) != 0x80) || 
          ((utf8[i + 2] & 0xc0) != 0x80))
@@ -394,8 +401,8 @@ SilcUInt32 silc_utf8_decode(const unsigned char *utf8, SilcUInt32 utf8_len,
       if (charval < 0x800)
         return 0;
     } else if ((utf8[i] & 0xf8) == 0xf0) {
-      if (utf8_len < 4)
-        return 0;
+      if (i + 3 >= utf8_len)
+       return 0;
 
       if (((utf8[i + 1] & 0xc0) != 0x80) || 
          ((utf8[i + 2] & 0xc0) != 0x80) ||
@@ -409,8 +416,8 @@ SilcUInt32 silc_utf8_decode(const unsigned char *utf8, SilcUInt32 utf8_len,
       if (charval < 0x10000)
         return 0;
     } else if ((utf8[i] & 0xfc) == 0xf8) {
-      if (utf8_len < 5)
-        return 0;
+      if (i + 4 >= utf8_len)
+       return 0;
 
       if (((utf8[i + 1] & 0xc0) != 0x80) || 
          ((utf8[i + 2] & 0xc0) != 0x80) ||
@@ -426,8 +433,8 @@ SilcUInt32 silc_utf8_decode(const unsigned char *utf8, SilcUInt32 utf8_len,
       if (charval < 0x200000)
         return 0;
     } else if ((utf8[i] & 0xfe) == 0xfc) {
-      if (utf8_len < 6)
-        return 0;
+      if (i + 5 >= utf8_len)
+       return 0;
 
       if (((utf8[i + 1] & 0xc0) != 0x80) || 
          ((utf8[i + 2] & 0xc0) != 0x80) ||
@@ -463,22 +470,27 @@ SilcUInt32 silc_utf8_decode(const unsigned char *utf8, SilcUInt32 utf8_len,
       return 0;
       break;
     case SILC_STRING_BMP:
-      SILC_PUT16_MSB(charval, bin + enclen);
+      if (bin)
+       SILC_PUT16_MSB(charval, bin + enclen);
       enclen += 2;
       break;
     case SILC_STRING_BMP_LSB:
-      SILC_PUT16_LSB(charval, bin + enclen);
+      if (bin)
+       SILC_PUT16_LSB(charval, bin + enclen);
       enclen += 2;
       break;
     case SILC_STRING_UNIVERSAL:
-      SILC_PUT32_MSB(charval, bin + enclen);
+      if (bin)
+       SILC_PUT32_MSB(charval, bin + enclen);
       enclen += 4;
       break;
     case SILC_STRING_UNIVERSAL_LSB:
-      SILC_PUT32_LSB(charval, bin + enclen);
+      if (bin)
+       SILC_PUT32_LSB(charval, bin + enclen);
       enclen += 4;
       break;
-    case SILC_STRING_LANGUAGE:
+    default:
+      return 0;
       break;
     }
   }
@@ -495,6 +507,15 @@ SilcUInt32 silc_utf8_encoded_len(const unsigned char *bin, SilcUInt32 bin_len,
   return silc_utf8_encode(bin, bin_len, bin_encoding, NULL, 0);
 }
 
+/* Returns the length of decoded string if the `bin' of encoding of
+   `bin_encoding' is decoded with silc_utf8_decode. */
+
+SilcUInt32 silc_utf8_decoded_len(const unsigned char *bin, SilcUInt32 bin_len,
+                                SilcStringEncoding bin_encoding)
+{
+  return silc_utf8_decode(bin, bin_len, bin_encoding, NULL, 0);
+}
+
 /* Returns TRUE if the `utf8' string of length of `utf8_len' is valid
    UTF-8 encoded string, FALSE if it is not UTF-8 encoded string. */
 
index e29be0724152d616371c53980e236a9488b3c3ac..35e9781227bbbf520bceafcf5318ba32ab9d476e 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 2002 Pekka Riikonen
+  Copyright (C) 2002 - 2003 Pekka Riikonen
 
   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
@@ -21,9 +21,9 @@
  *
  * DESCRIPTION
  *
- *    String manipulation utility routines.  These routines provides
- *    various helper functions for encoding, decoding and otherwise
- *    managing strings.
+ * String manipulation utility routines.  These routines provides
+ * various helper functions for encoding, decoding and otherwise
+ * managing strings.
  *
  ***/
 
@@ -83,20 +83,22 @@ unsigned char *silc_pem_decode(unsigned char *pem, SilcUInt32 pem_len,
  * DESCRIPTION
  *
  *    String encoding definitions used with the UTF-8 encoding and
- *    decoding functions.
+ *    decoding functions.  By default, systems should use SILC_STRING_LANGUAGE
+ *    since it encodes and decodes correctly according to local system
+ *    language and character set.
  *
  * SOURCE
  */
 typedef enum {
-  SILC_STRING_ASCII         = 0, /* Any 8 bit ASCII encoding (default) */
-  SILC_STRING_ASCII_ESC     = 1, /* 7 bit ASCII (>0x7f escaped) */
-  SILC_STRING_BMP           = 2, /* 16 bit, UCS-2, BMP, ISO/IEC 10646 */
-  SILC_STRING_BMP_LSB       = 3, /* BMP, least significant byte first */
-  SILC_STRING_UNIVERSAL     = 4, /* 32 bit, UCS-4, Universal, ISO/IEC 10646 */
-  SILC_STRING_UNIVERSAL_LSB = 5, /* Universal, least significant byte first */
-  SILC_STRING_LANGUAGE      = 6, /* Language and charset specific conversion
-                                   on those platforms that support iconv().
-                                   Fallback is SILC_STRING_ASCII. */
+  SILC_STRING_ASCII         = 0,  /* Any 8 bit ASCII encoding (default) */
+  SILC_STRING_ASCII_ESC     = 1,  /* 7 bit ASCII (>0x7f escaped) */
+  SILC_STRING_BMP           = 2,  /* 16 bit, UCS-2, BMP, ISO/IEC 10646 */
+  SILC_STRING_BMP_LSB       = 3,  /* BMP, least significant byte first */
+  SILC_STRING_UNIVERSAL     = 4,  /* 32 bit, UCS-4, Universal, ISO/IEC 10646 */
+  SILC_STRING_UNIVERSAL_LSB = 5,  /* Universal, least significant byte first */
+  SILC_STRING_LANGUAGE      = 6,  /* Language and charset specific conversion
+                                    on those platforms that support iconv().
+                                    Fallback is SILC_STRING_ASCII. */
 } SilcStringEncoding;
 /***/
 
@@ -161,6 +163,23 @@ SilcUInt32 silc_utf8_decode(const unsigned char *utf8, SilcUInt32 utf8_len,
 SilcUInt32 silc_utf8_encoded_len(const unsigned char *bin, SilcUInt32 bin_len,
                                 SilcStringEncoding bin_encoding);
 
+/****f* silcutil/SilcStrUtilAPI/silc_utf8_decoded_len
+ *
+ * SYNOPSIS
+ *
+ *    SilcUInt32 silc_utf8_decoded_len(const unsigned char *bin, 
+ *                                     SilcUInt32 bin_len,
+ *                                     SilcStringEncoding bin_encoding);
+ *
+ * DESCRIPTION
+ *
+ *    Returns the length of decoded string if the `bin' of encoding of
+ *    `bin_encoding' is decoded with silc_utf8_decode. 
+ *
+ ***/
+SilcUInt32 silc_utf8_decoded_len(const unsigned char *bin, SilcUInt32 bin_len,
+                                SilcStringEncoding bin_encoding);
+
 /****f* silcutil/SilcStrUtilAPI/silc_utf8_valid
  *
  * SYNOPSIS
index 032a4eab1b81d0373bf46bdd5b394b6f8ea1107b..f665344eee27d456d5e019a8044e12fe92704213 100644 (file)
    This doesn't remove the newline sign from the destination buffer. The
    argument begin is returned and should be passed again for the function. */
 
-int silc_gets(char *dest, int destlen, const char *src, int srclen,
-             int *begin)
+int silc_gets(char *dest, int destlen, const char *src, int srclen, int begin)
 {
-  int off = *begin;
+  static int start = 0;
   int i;
 
   memset(dest, 0, destlen);
 
-  if (off + 1 >= srclen)
-    return EOF;
+  if (begin != start)
+    start = 0;
 
   i = 0;
-  for ( ; off <= srclen; i++) {
+  for ( ; start <= srclen; i++, start++) {
     if (i > destlen)
       return -1;
 
-    dest[i] = src[off++];
+    dest[i] = src[start];
 
     if (dest[i] == EOF)
       return EOF;
@@ -52,9 +51,9 @@ int silc_gets(char *dest, int destlen, const char *src, int srclen,
     if (dest[i] == '\n')
       break;
   }
-  *begin = off;
+  start++;
 
-  return off;
+  return start;
 }
 
 /* Checks line for illegal characters. Return -1 when illegal character
@@ -653,6 +652,9 @@ char *silc_client_chmode(SilcUInt32 mode, const char *cipher, const char *hmac)
   if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
     strncat(string, "f", 1);
 
+  if (mode & SILC_CHANNEL_MODE_CHANNEL_AUTH)
+    strncat(string, "C", 1);
+
   if (mode & SILC_CHANNEL_MODE_SILENCE_USERS)
     strncat(string, "m", 1);
 
index 2d569528d376b6884418e41f42aaf8f9fd56cea0..57c5b1db9434d3013ab603097fa1dfbafd241995 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  Copyright (C) 1997 - 2003 Pekka Riikonen
+  Copyright (C) 1997 - 2002 Pekka Riikonen
 
   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
@@ -33,7 +33,7 @@
  * SYNOPSIS
  *
  *    int silc_gets(char *dest, int destlen, const char *src, int srclen,
- *                  int *begin);
+ *                  int begin);
  *
  * DESCRIPTION
  *
@@ -42,8 +42,7 @@
  *    argument begin is returned and should be passed again for the function.
  *
  ***/
-int silc_gets(char *dest, int destlen, const char *src, int srclen,
-             int *begin);
+int silc_gets(char *dest, int destlen, const char *src, int srclen, int begin);
 
 /****f* silcutil/SilcUtilAPI/silc_check_line
  *
@@ -483,7 +482,7 @@ int silc_gettimeofday(struct timeval *p);
  *
  * SYNOPSIS
  *
- *    bool silc_compare_timeval(struct timeval *smaller,
+ *    bool silc_compare_timeval(struct timeval *smaller, 
  *                              struct timeval *bigger)
  *
  * DESCRIPTION
@@ -492,7 +491,7 @@ int silc_gettimeofday(struct timeval *p);
  *    time value is smaller than the second time value.
  *
  ***/
-bool silc_compare_timeval(struct timeval *smaller,
+bool silc_compare_timeval(struct timeval *smaller, 
                          struct timeval *bigger);
 
 /****f* silcutil/SilcUtilAPI/silc_string_regexify
index b24a6b4827fa8ae9184f51c208a1ba11e2abdb89..fef2f8fb687c895124ff0c77a23d840db727be8d 100644 (file)
@@ -64,10 +64,13 @@ int silc_gettimeofday(struct timeval *tv)
 
 char *silc_get_username(void)
 {
-  return strdup("foo");
+  DWORD maxlen = 128;
+  char username[maxlen];
+  GetUserName(username, &maxlen);
+  return strdup(username);
 }
 
 char *silc_get_real_name(void)
 {
-  return strdup("Foo T. Bar");
+  return silc_get_username();
 }
diff --git a/prepare b/prepare
index e126805b4cda661156787e9adcc3929b75d8bbdc..397bdca87a7b4b3427f3023dda206777454fc8ef 100755 (executable)
--- a/prepare
+++ b/prepare
@@ -37,7 +37,7 @@
 # SILC Distribution versions. Set here or give the version on the command
 # line as argument.
 #
-SILC_VERSION=0.9.                    # Base version
+SILC_VERSION=0.9.10                    # Base version
 
 #############################################################################
 
index 734c64fb14ab6bee75e7f02ba72cb8c4bf850484..8f4dc98ff9c851d19d8f10b7ee400f333cc50d77 100644 (file)
@@ -20,6 +20,9 @@ AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
 
 SUBDIRS = libsilc libsilcclient
 
-EXTRA_DIST = silcdefs.h silc.dsw copy_dll tests
+EXTRA_DIST =                                   \
+       silcdefs.h silc.dsw copy_dll            \
+       tests all.dsp clean_dist.pl README      \
+       libsilc_static libsilcclient_static
 
 include $(top_srcdir)/Makefile.defines.in
diff --git a/win32/README b/win32/README
new file mode 100644 (file)
index 0000000..658f9c2
--- /dev/null
@@ -0,0 +1,12 @@
+Compiling SILC Toolkit for Win32
+================================
+
+- The MSVC++ 6.0 is required to compile the SILC Toolkit.
+
+- Load the silc.dsw workspace file and build the libsilc and
+  libsilcclient libraries.  Both Debug and Release versions can
+  be compiled.
+
+- The include/ directory includes all include files from the
+  SILC Toolkit.  Use that directory as your include source for
+  SILC include files when you are programming new application.
diff --git a/win32/all.dsp b/win32/all.dsp
new file mode 100644 (file)
index 0000000..2358823
--- /dev/null
@@ -0,0 +1,63 @@
+# Microsoft Developer Studio Project File - Name="all" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Generic Project" 0x010a\r
+\r
+CFG=all - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "all.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "all.mak" CFG="all - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "all - Win32 Release" (based on "Win32 (x86) Generic Project")\r
+!MESSAGE "all - Win32 Debug" (based on "Win32 (x86) Generic Project")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName ""\r
+# PROP Scc_LocalPath ""\r
+MTL=midl.exe\r
+\r
+!IF  "$(CFG)" == "all - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "Release"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Target_Dir ""\r
+\r
+!ELSEIF  "$(CFG)" == "all - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "Debug"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Target_Dir ""\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "all - Win32 Release"\r
+# Name "all - Win32 Debug"\r
+# End Target\r
+# End Project\r
diff --git a/win32/clean_dist.pl b/win32/clean_dist.pl
new file mode 100644 (file)
index 0000000..fe10fba
--- /dev/null
@@ -0,0 +1,165 @@
+#!/usr/bin/perl\r
+\r
+$p = `pwd`;\r
+\r
+if($p =~ /.*(\/win32)/)\r
+{\r
+       @dirents = split('/', $p);\r
+       if(@dirents > 2)\r
+       {\r
+               # check dependencies\r
+               print "Checking dependencies\n";\r
+               @statLibSilcDllDebug = stat("libsilc/Debug/libsilc.dll");\r
+               @statLibSilcExpDebug = stat("libsilc/Debug/libsilc.exp");\r
+               @statLibSilcLibDebug = stat("libsilc/Debug/libsilc.lib");\r
+               if(! @statLibSilcDllDebug || ! @statLibSilcExpDebug || ! @statLibSilcLibDebug)\r
+               {\r
+                       die "Please rebuild libsilc Debug before creating the distribution\n";\r
+               }\r
+               \r
+               @statLibSilcDllRelease = stat("libsilc/Release/libsilc.dll");\r
+               @statLibSilcExpRelease = stat("libsilc/Release/libsilc.exp");\r
+               @statLibSilcLibRelease = stat("libsilc/Release/libsilc.lib");\r
+               if(! @statLibSilcDllRelease || ! @statLibSilcExpRelease || ! @statLibSilcLibRelease)\r
+               {\r
+                       die "Please rebuild libsilc Release before creating the distribution\n";\r
+               }\r
+               \r
+               @statLibSilcClientDllDebug = stat("libsilcclient/Debug/libsilcclient.dll");\r
+               @statLibSilcClientExpDebug = stat("libsilcclient/Debug/libsilcclient.exp");\r
+               @statLibSilcClientLibDebug = stat("libsilcclient/Debug/libsilcclient.lib");\r
+               if(! @statLibSilcClientDllDebug || \r
+                       ! @statLibSilcClientExpDebug || \r
+                       ! @statLibSilcClientLibDebug || \r
+                       (@statLibSilcClientDllDebug[9] < @statLibSilcDllDebug[9]) ||\r
+                       (@statLibSilcClientExpDebug[9] < @statLibSilcExpDebug[9]) ||\r
+                       (@statLibSilcClientLibDebug[9] < @statLibSilcLibDebug[9])\r
+                       )\r
+               {                       \r
+                       die "Please rebuild libsilcclient Debug before creating the distribution\n";\r
+               }\r
+\r
+               @statLibSilcClientDllRelease = stat("libsilcclient/Release/libsilcclient.dll");\r
+               @statLibSilcClientExpRelease = stat("libsilcclient/Release/libsilcclient.exp");\r
+               @statLibSilcClientLibRelease = stat("libsilcclient/Release/libsilcclient.lib");\r
+               if(! @statLibSilcClientDllRelease || \r
+                       ! @statLibSilcClientExpRelease || \r
+                       ! @statLibSilcClientLibRelease ||\r
+                       (@statLibSilcClientDllRelease[9] < @statLibSilcDllRelease[9]) ||\r
+                       (@statLibSilcClientExpRelease[9] < @statLibSilcExpRelease[9]) ||\r
+                       (@statLibSilcClientLibRelease[9] < @statLibSilcLibRelease[9])\r
+                       )\r
+               {\r
+                       die "Please rebuild libsilcclient Release before creating the distribution\n";\r
+               }\r
+\r
+               @statLibSilcStaticLibDebug = stat("libsilc_static/Debug/libsilc_static.lib");\r
+               if(! @statLibSilcStaticLibDebug)\r
+               {\r
+                       die "Please rebuild libsilc_static Debug before creating the distribution\n";\r
+               }\r
+               \r
+               @statLibSilcStaticLibRelease = stat("libsilc_static/Release/libsilc_static.lib");\r
+               if(! @statLibSilcStaticLibRelease)\r
+               {\r
+                       die "Please rebuild libsilc_static Release before creating the distribution\n";\r
+               }\r
+               \r
+               @statLibSilcClientStaticLibDebug = stat("libsilcclient_static/Debug/libsilcclient_static.lib");\r
+               if(! @statLibSilcClientStaticLibDebug || (@statLibSilcClientStaticLibDebug[9] < @statLibSilcStaticLibDebug[9]))\r
+               {                       \r
+                       die "Please rebuild libsilcclient_static Debug before creating the distribution\n";\r
+               }\r
+\r
+               @statLibSilcClientStaticLibRelease = stat("libsilcclient_static/Release/libsilcclient_static.lib");\r
+               if(! @statLibSilcClientStaticLibRelease || (@statLibSilcClientStaticLibRelease[9] < @statLibSilcStaticLibRelease[9]))\r
+               {                       \r
+                       die "Please rebuild libsilcclient_static Release before creating the distribution\n";\r
+               }\r
+\r
+               $index = @dirents - 2;\r
+               $top = @dirents[$index];\r
+               `find . -name \"*.obj\" -exec rm -f \\{} \\;`;\r
+               `find . -name \"*.idb\" -exec rm -f \\{} \\;`;\r
+               `find . -name \"*.pdb\" -exec rm -f \\{} \\;`;\r
+               `find . -name \"*.pch\" -exec rm -f \\{} \\;`;\r
+               `find ../ -name \"*.o\" -exec rm -f \\{} \\;`;\r
+               `find ../ -name \"*.lo\" -exec rm -f \\{} \\;`;\r
+               `find ../ -name \"*.a\" -exec rm -f \\{} \\;`;\r
+               `find ../ -name \"*.la\" -exec rm -f \\{} \\;`;\r
+               `find ../ -name \"*.lai\" -exec rm -f \\{} \\;`;\r
+\r
+               push(@excludeList, "--exclude $top/win32/Debug");\r
+               push(@excludeList, "--exclude $top/win32/libsilc/CVS");\r
+               push(@excludeList, "--exclude $top/win32/libsilc/libsilc.plg");\r
+               push(@excludeList, "--exclude $top/win32/libsilcclient/CVS");\r
+               push(@excludeList, "--exclude $top/win32/libsilcclient/libsilcclient.plg");\r
+               push(@excludeList, "--exclude $top/win32/libsilc_static/CVS");\r
+               push(@excludeList, "--exclude $top/win32/libsilc_static/libsilc_static.plg");\r
+               push(@excludeList, "--exclude $top/win32/libsilcclient_static/CVS");\r
+               push(@excludeList, "--exclude $top/win32/libsilcclient_static/libsilcclient_static.plg");\r
+               push(@excludeList, "--exclude $top/win32/silc.ncb");\r
+               push(@excludeList, "--exclude $top/includes/CVS");\r
+               push(@excludeList, "--exclude $top/lib/silcutil/win32/.cvsignore");\r
+               push(@excludeList, "--exclude $top/lib/silcutil/win32/CVS");\r
+               push(@excludeList, "--exclude $top/win32/all.plg");\r
+               push(@excludeList, "--exclude $top/win32/buildDistAfterAllReleaseAndDebug.plg");\r
+               push(@excludeList, "--exclude $top/win32/CVS");\r
+               push(@excludeList, "--exclude $top/win32/tests/CVS");\r
+               push(@excludeList, "--exclude $top/win32/libsilc/Debug/libsilc.ilk");\r
+               push(@excludeList, "--exclude $top/win32/libsilc/Debug/libsilc.pdb");\r
+               push(@excludeList, "--exclude $top/win32/libsilcclient/Debug/libsilcclient.ilk");\r
+               push(@excludeList, "--exclude $top/win32/libsilcclient/Debug/libsilcclient.pdb");\r
+               push(@excludeList, "--exclude $top/win32/libsilc/Release/libsilc.ilk");\r
+               push(@excludeList, "--exclude $top/win32/libsilc/Release/libsilc.pdb");\r
+               push(@excludeList, "--exclude $top/win32/libsilcclient/Release/libsilcclient.ilk");\r
+               push(@excludeList, "--exclude $top/win32/silc.opt");\r
+               push(@excludeList, "--exclude $top/irssi");\r
+               push(@excludeList, "--exclude $top/doc/CVS");\r
+               push(@excludeList, "--exclude $top/doc/examples/CVS");\r
+               push(@excludeList, "--exclude $top/lib/doc/CVS");\r
+               push(@excludeList, "--exclude $top/lib/silcclient/.libs");\r
+               push(@excludeList, "--exclude $top/lib/silccore/.libs");\r
+               push(@excludeList, "--exclude $top/lib/silccore/tests/CVS");\r
+               push(@excludeList, "--exclude $top/lib/silccrypt/.libs");\r
+               push(@excludeList, "--exclude $top/lib/silccrypt/tests/CVS");\r
+               push(@excludeList, "--exclude $top/lib/silcmath/.libs");\r
+               push(@excludeList, "--exclude $top/lib/silcmath/mpi/.libs");\r
+               push(@excludeList, "--exclude $top/lib/silcsftp/.libs");\r
+               push(@excludeList, "--exclude $top/lib/silcsftp/tests/CVS");\r
+               push(@excludeList, "--exclude $top/lib/silcsim/.libs");\r
+               push(@excludeList, "--exclude $top/lib/silcske/.libs");\r
+               push(@excludeList, "--exclude $top/lib/silcutil/.libs");\r
+               push(@excludeList, "--exclude $top/lib/silcutil/win32/.libs");\r
+               push(@excludeList, "--exclude $top/silcer/CVS");\r
+               push(@excludeList, "--exclude $top/silcer/intl/CVS");\r
+               push(@excludeList, "--exclude $top/silcer/macros/CVS");\r
+               push(@excludeList, "--exclude $top/silcer/pixmaps/CVS");\r
+               push(@excludeList, "--exclude $top/silcer/po/CVS");\r
+               push(@excludeList, "--exclude $top/silcer/src/CVS");\r
+               push(@excludeList, "--exclude $top/silcer/ui/CVS");\r
+               push(@excludeList, "--exclude $top/tutorial/CVS");\r
+               push(@excludeList, "--exclude $top/tutorial/mybot/CVS");\r
+\r
+\r
+\r
+               $excludes = "";\r
+               foreach $entry(@excludeList)\r
+               {\r
+                       $excludes = sprintf("%s%s ", $excludes, $entry);\r
+               }\r
+               \r
+               print "Copying headers\n";\r
+               `rm -rf include`;\r
+               `mkdir -p include`;\r
+               `find ../includes -name \"*.h\" -exec cp \\{} include \\;`;\r
+               `find ../lib -name \"*.h\" -exec cp \\{} include \\;`;\r
+               print "Creating distribution archive.\n";\r
+               `cd ../.. ; tar $excludes -zcvf $top-win32.tgz $top/*` || die "Failed to create distribution\n";        \r
+       }\r
+}\r
+else\r
+{\r
+       die "Please run $0 from the win32 directory of the silc distribution\n";\r
+}\r
+\r
index c6102bb0d5c6000e66a9b57f4fe0f45d2ed6755f..822bafd501e40fda2773fb916b541c6fe252d505 100644 (file)
-;\r
-; Exports file for SILC Core DLL.\r
-;\r
-; This file is generated from MinGW compiled object files using the\r
-; following command:\r
-;\r
-; dlltool --export-all --output-def libsilc.def libsilc.a\r
-;\r
-; ----------------------------------------------------------------------------\r
-;\r
-; If you edit this file by adding or removing any exports be sure to\r
-; preserve the ordinal values (the @ n in the exports) and add new exports\r
-; always at the end of the list with new ordinal value. Do not ever\r
-; add new export with old ordinal value if you need to preserve backwards\r
-; compatiblity. -Pekka\r
-;\r
-EXPORTS\r
-       silc_aes_context_len @ 235 ; \r
-       silc_aes_decrypt_cbc @ 236 ; \r
-       silc_aes_encrypt_cbc @ 237 ; \r
-       silc_aes_set_key @ 238 ; \r
-       silc_aes_set_key_with_string @ 239 ; \r
-       silc_argument_get_arg_num @ 240 ; \r
-       silc_argument_get_arg_type @ 241 ; \r
-       silc_argument_get_first_arg @ 242 ; \r
-       silc_argument_get_next_arg @ 243 ; \r
-       silc_argument_payload_encode @ 244 ; \r
-       silc_argument_payload_encode_payload @ 245 ; \r
-       silc_argument_payload_free @ 246 ; \r
-       silc_argument_payload_parse @ 247 ; \r
-       silc_auth_get_data @ 248 ; \r
-       silc_auth_get_method @ 249 ; \r
-       silc_auth_payload_encode @ 250 ; \r
-       silc_auth_payload_free @ 251 ; \r
-       silc_auth_payload_parse @ 252 ; \r
-       silc_auth_public_key_auth_generate @ 253 ; \r
-       silc_auth_public_key_auth_verify @ 254 ; \r
-       silc_auth_public_key_auth_verify_data @ 255 ; \r
-       silc_auth_verify @ 256 ; \r
-       silc_auth_verify_data @ 257 ; \r
-       silc_blowfish_context_len @ 258 ; \r
-       silc_blowfish_decrypt_cbc @ 259 ; \r
-       silc_blowfish_encrypt_cbc @ 260 ; \r
-       silc_blowfish_set_key @ 261 ; \r
-       silc_blowfish_set_key_with_string @ 262 ; \r
-       silc_buffer_format @ 263 ; \r
-       silc_buffer_unformat @ 264 ; \r
-       silc_calloc @ 265 ; \r
-       silc_cast_context_len @ 266 ; \r
-       silc_cast_decrypt_cbc @ 267 ; \r
-       silc_cast_encrypt_cbc @ 268 ; \r
-       silc_cast_set_key @ 269 ; \r
-       silc_cast_set_key_with_string @ 270 ; \r
-       silc_channel_get_id @ 271 ; \r
-       silc_channel_get_id_parse @ 272 ; \r
-       silc_channel_get_mode @ 273 ; \r
-       silc_channel_get_name @ 274 ; \r
-       silc_channel_key_get_cipher @ 275 ; \r
-       silc_channel_key_get_id @ 276 ; \r
-       silc_channel_key_get_key @ 277 ; \r
-       silc_channel_key_payload_encode @ 278 ; \r
-       silc_channel_key_payload_free @ 279 ; \r
-       silc_channel_key_payload_parse @ 280 ; \r
-       silc_channel_payload_encode @ 289 ; \r
-       silc_channel_payload_free @ 290 ; \r
-       silc_channel_payload_list_free @ 291 ; \r
-       silc_channel_payload_parse @ 292 ; \r
-       silc_channel_payload_parse_list @ 293 ; \r
-       silc_check_line @ 294 ; \r
-       silc_cipher_alloc @ 295 ; \r
-       silc_cipher_decrypt @ 296 ; \r
-       silc_cipher_encrypt @ 297 ; \r
-       silc_cipher_free @ 298 ; \r
-       silc_cipher_get_block_len @ 299 ; \r
-       silc_cipher_get_iv @ 300 ; \r
-       silc_cipher_get_key_len @ 301 ; \r
-       silc_cipher_get_supported @ 302 ; \r
-       silc_cipher_is_supported @ 303 ; \r
-       silc_cipher_list @ 304 ; \r
-       silc_cipher_register @ 305 ; \r
-       silc_cipher_register_default @ 306 ; \r
-       silc_cipher_set_iv @ 307 ; \r
-       silc_cipher_set_key @ 308 ; \r
-       silc_cipher_unregister @ 309 ; \r
-       silc_client_chmode @ 310 ; \r
-       silc_client_chumode @ 311 ; \r
-       silc_client_chumode_char @ 312 ; \r
-       silc_command_get @ 313 ; \r
-       silc_command_get_args @ 314 ; \r
-       silc_command_get_ident @ 315 ; \r
-       silc_command_payload_encode @ 316 ; \r
-       silc_command_payload_encode_payload @ 317 ; \r
-       silc_command_payload_encode_va @ 318 ; \r
-       silc_command_payload_encode_vap @ 319 ; \r
-       silc_command_payload_free @ 320 ; \r
-       silc_command_payload_parse @ 321 ; \r
-       silc_command_reply_payload_encode_va @ 322 ; \r
-       silc_command_set_command @ 323 ; \r
-       silc_command_set_ident @ 324 ; \r
-       silc_config_open @ 327 ; \r
-       silc_debug @ 328 DATA ; \r
-       silc_pem_decode @ 329 ; \r
-       silc_default_ciphers @ 330 DATA ; \r
-       silc_default_hash @ 331 DATA ; \r
-       silc_default_hmacs @ 332 DATA ; \r
-       silc_default_pkcs @ 333 DATA ; \r
-       silc_pem_encode @ 334 ; \r
-       silc_pem_encode_file @ 335 ; \r
-       silc_file_readfile @ 336 ; \r
-       silc_file_writefile @ 337 ; \r
-       silc_file_writefile_mode @ 338 ; \r
-       silc_format @ 339 ; \r
-       silc_free @ 340 ; \r
-       silc_get_time @ 341 ; \r
-       silc_gets @ 342 ; \r
-       silc_gettimeofday @ 343 ; \r
-       silc_hash_alloc @ 344 ; \r
-       silc_hash_client_id_compare @ 345 ; \r
-       silc_hash_data @ 346 ; \r
-       silc_hash_data_compare @ 347 ; \r
-       silc_hash_fingerprint @ 348 ; \r
-       silc_hash_free @ 349 ; \r
-       silc_hash_get_supported @ 350 ; \r
-       silc_hash_id @ 351 ; \r
-       silc_hash_id_compare @ 352 ; \r
-       silc_hash_is_supported @ 353 ; \r
-       silc_hash_len @ 354 ; \r
-       silc_hash_list @ 355 ; \r
-       silc_hash_make @ 356 ; \r
-       silc_hash_ptr @ 357 ; \r
-       silc_hash_register @ 358 ; \r
-       silc_hash_register_default @ 359 ; \r
-       silc_hash_string @ 360 ; \r
-       silc_hash_string_compare @ 361 ; \r
-       silc_hash_table_add @ 362 ; \r
-       silc_hash_table_add_ext @ 363 ; \r
-       silc_hash_table_alloc @ 364 ; \r
-       silc_hash_table_count @ 365 ; \r
-       silc_hash_table_del @ 366 ; \r
-       silc_hash_table_del_by_context @ 367 ; \r
-       silc_hash_table_del_by_context_ext @ 368 ; \r
-       silc_hash_table_del_ext @ 369 ; \r
-       silc_hash_table_find @ 370 ; \r
-       silc_hash_table_find_ext @ 371 ; \r
-       silc_hash_table_find_foreach @ 372 ; \r
-       silc_hash_table_find_foreach_ext @ 373 ; \r
-       silc_hash_table_foreach @ 374 ; \r
-       silc_hash_table_free @ 375 ; \r
-       silc_hash_table_get @ 376 ; \r
-       silc_hash_table_list @ 377 ; \r
-       silc_hash_table_rehash @ 378 ; \r
-       silc_hash_table_rehash_ext @ 379 ; \r
-       silc_hash_table_replace @ 380 ; \r
-       silc_hash_table_replace_ext @ 381 ; \r
-       silc_hash_table_size @ 382 ; \r
-       silc_hash_uint @ 383 ; \r
-       silc_hash_unregister @ 384 ; \r
-       silc_hmac_alloc @ 385 ; \r
-       silc_hmac_free @ 386 ; \r
-       silc_hmac_get_supported @ 387 ; \r
-       silc_hmac_is_supported @ 388 ; \r
-       silc_hmac_len @ 389 ; \r
-       silc_hmac_list @ 390 ; \r
-       silc_hmac_make @ 391 ; \r
-       silc_hmac_make_truncated @ 393 ; \r
-       silc_hmac_make_with_key @ 394 ; \r
-       silc_hmac_register @ 395 ; \r
-       silc_hmac_register_default @ 396 ; \r
-       silc_hmac_set_key @ 397 ; \r
-       silc_hmac_unregister @ 398 ; \r
-       silc_id_dup @ 399 ; \r
-       silc_id_get_len @ 400 ; \r
-       silc_id_id2str @ 401 ; \r
-       silc_id_payload_encode @ 402 ; \r
-       silc_id_payload_free @ 403 ; \r
-       silc_id_payload_get_data @ 404 ; \r
-       silc_id_payload_get_id @ 405 ; \r
-       silc_id_payload_get_len @ 406 ; \r
-       silc_id_payload_get_type @ 407 ; \r
-       silc_id_payload_parse @ 408 ; \r
-       silc_id_payload_parse_id @ 410 ; \r
-       silc_id_render @ 411 ; \r
-       silc_id_str2id @ 412 ; \r
-       silc_idcache_add @ 413 ; \r
-       silc_idcache_alloc @ 414 ; \r
-       silc_idcache_del @ 415 ; \r
-       silc_idcache_del_all @ 416 ; \r
-       silc_idcache_del_by_context @ 417 ; \r
-       silc_idcache_del_by_id @ 418 ; \r
-       silc_idcache_del_by_id_ext @ 419 ; \r
-       silc_idcache_find_by_context @ 420 ; \r
-       silc_idcache_find_by_id @ 421 ; \r
-       silc_idcache_find_by_id_one @ 422 ; \r
-       silc_idcache_find_by_id_one_ext @ 423 ; \r
-       silc_idcache_find_by_name @ 424 ; \r
-       silc_idcache_find_by_name_one @ 425 ; \r
-       silc_idcache_free @ 426 ; \r
-       silc_idcache_get_all @ 427 ; \r
-       silc_idcache_list_count @ 428 ; \r
-       silc_idcache_list_first @ 429 ; \r
-       silc_idcache_list_free @ 430 ; \r
-       silc_idcache_list_next @ 431 ; \r
-       silc_idcache_purge @ 432 ; \r
-       silc_idcache_purge_by_context @ 433 ; \r
-       silc_key_agreement_get_hostname @ 434 ; \r
-       silc_key_agreement_get_port @ 435 ; \r
-       silc_key_agreement_payload_encode @ 436 ; \r
-       silc_key_agreement_payload_free @ 437 ; \r
-       silc_key_agreement_payload_parse @ 438 ; \r
-       silc_log_output @ 439 ; \r
-       silc_log_output_debug @ 440 ; \r
-       silc_log_output_hexdump @ 441 ; \r
-       silc_log_reset_callbacks @ 442 ; \r
-       silc_log_reset_debug_callbacks @ 443 ; \r
-       silc_log_set_callback @ 444 ; \r
-       silc_log_set_debug_callbacks @ 445 ; \r
-       silc_log_set_file @ 446 ; \r
-       silc_malloc @ 448 ; \r
-       silc_math_gen_prime @ 454 ; \r
-       silc_math_prime_test @ 455 ; \r
-       silc_md5_context_len @ 456 ; \r
-       silc_md5_final @ 457 ; \r
-       silc_md5_init @ 458 ; \r
-       silc_md5_transform @ 459 ; \r
-       silc_md5_update @ 460 ; \r
-       silc_mp_abs @ 461 ; \r
-       silc_mp_add @ 462 ; \r
-       silc_mp_add_ui @ 463 ; \r
-       silc_mp_and @ 464 ; \r
-       silc_mp_bin2mp @ 465 ; \r
-       silc_mp_cmp @ 466 ; \r
-       silc_mp_cmp_si @ 467 ; \r
-       silc_mp_cmp_ui @ 468 ; \r
-       silc_mp_div @ 469 ; \r
-       silc_mp_div_2exp @ 470 ; \r
-       silc_mp_div_2exp_qr @ 471 ; \r
-       silc_mp_div_qr @ 472 ; \r
-       silc_mp_div_ui @ 473 ; \r
-       silc_mp_gcd @ 474 ; \r
-       silc_mp_gcdext @ 475 ; \r
-       silc_mp_get_str @ 476 ; \r
-       silc_mp_get_ui @ 477 ; \r
-       silc_mp_init @ 478 ; \r
-       silc_mp_mod @ 479 ; \r
-       silc_mp_mod_2exp @ 480 ; \r
-       silc_mp_mod_ui @ 481 ; \r
-       silc_mp_modinv @ 482 ; \r
-       silc_mp_mp2bin @ 483 ; \r
-       silc_mp_mp2bin_noalloc @ 484 ; \r
-       silc_mp_mul @ 485 ; \r
-       silc_mp_mul_2exp @ 486 ; \r
-       silc_mp_mul_ui @ 487 ; \r
-       silc_mp_neg @ 488 ; \r
-       silc_mp_or @ 489 ; \r
-       silc_mp_pow @ 490 ; \r
-       silc_mp_pow_mod @ 491 ; \r
-       silc_mp_pow_mod_ui @ 492 ; \r
-       silc_mp_pow_ui @ 493 ; \r
-       silc_mp_set @ 494 ; \r
-       silc_mp_set_si @ 495 ; \r
-       silc_mp_set_str @ 496 ; \r
-       silc_mp_set_ui @ 497 ; \r
-       silc_mp_size @ 498 ; \r
-       silc_mp_sizeinbase @ 499 ; \r
-       silc_mp_sqrt @ 500 ; \r
-       silc_mp_sub @ 501 ; \r
-       silc_mp_sub_ui @ 502 ; \r
-       silc_mp_uninit @ 503 ; \r
-       silc_mp_xor @ 504 ; \r
-       silc_mutex_alloc @ 505 ; \r
-       silc_mutex_free @ 506 ; \r
-       silc_mutex_lock @ 507 ; \r
-       silc_mutex_unlock @ 508 ; \r
-       silc_net_accept_connection @ 509 ; \r
-       silc_net_addr2bin @ 510 ; \r
-       silc_net_check_host_by_sock @ 511 ; \r
-       silc_net_check_local_by_sock @ 512 ; \r
-       silc_net_close_connection @ 513 ; \r
-       silc_net_close_server @ 514 ; \r
-       silc_net_create_connection @ 515 ; \r
-       silc_net_create_connection_async @ 516 ; \r
-       silc_net_create_server @ 517 ; \r
-       silc_net_get_local_port @ 518 ; \r
-       silc_net_get_remote_port @ 519 ; \r
-       silc_net_get_socket_opt @ 520 ; \r
-       silc_net_is_ip @ 521 ; \r
-       silc_net_localhost @ 522 ; \r
-       silc_net_set_socket_nonblock @ 523 ; \r
-       silc_net_set_socket_opt @ 524 ; \r
-       silc_net_win32_init @ 525 ; \r
-       silc_net_win32_uninit @ 526 ; \r
-       silc_none_context_len @ 527 ; \r
-       silc_none_decrypt_cbc @ 528 ; \r
-       silc_none_encrypt_cbc @ 529 ; \r
-       silc_none_set_key @ 530 ; \r
-       silc_none_set_key_with_string @ 531 ; \r
-       silc_notify_get_arg_num @ 532 ; \r
-       silc_notify_get_args @ 533 ; \r
-       silc_notify_get_type @ 534 ; \r
-       silc_notify_payload_encode @ 535 ; \r
-       silc_notify_payload_encode_args @ 536 ; \r
-       silc_notify_payload_free @ 537 ; \r
-       silc_notify_payload_parse @ 538 ; \r
-       silc_packet_assemble @ 539 ; \r
-       silc_packet_context_alloc @ 540 ; \r
-       silc_packet_context_dup @ 541 ; \r
-       silc_packet_context_free @ 542 ; \r
-       silc_packet_encrypt @ 544 ; \r
-       silc_packet_parse @ 545 ; \r
-       silc_packet_parse_special @ 546 ; \r
-       silc_packet_receive @ 547 ; \r
-       silc_packet_receive_process @ 548 ; \r
-       silc_packet_send @ 549 ; \r
-       silc_packet_send_prepare @ 550 ; \r
-       silc_parse_command_line @ 551 ; \r
-       silc_parse_userfqdn @ 552 ; \r
-       silc_pkcs1_decrypt @ 553 ; \r
-       silc_pkcs1_encrypt @ 554 ; \r
-       silc_pkcs1_sign @ 555 ; \r
-       silc_pkcs1_verify @ 556 ; \r
-       silc_pkcs_alloc @ 557 ; \r
-       silc_pkcs_decode_identifier @ 558 ; \r
-       silc_pkcs_decrypt @ 559 ; \r
-       silc_pkcs_encode_identifier @ 560 ; \r
-       silc_pkcs_encrypt @ 561 ; \r
-       silc_pkcs_free @ 562 ; \r
-       silc_pkcs_free_identifier @ 563 ; \r
-       silc_pkcs_get_key_len @ 564 ; \r
-       silc_pkcs_get_private_key @ 565 ; \r
-       silc_pkcs_get_public_key @ 566 ; \r
-       silc_pkcs_get_supported @ 567 ; \r
-       silc_pkcs_is_supported @ 568 ; \r
-       silc_pkcs_list @ 569 ; \r
-       silc_pkcs_load_private_key @ 570 ; \r
-       silc_pkcs_load_public_key @ 571 ; \r
-       silc_pkcs_private_key_alloc @ 572 ; \r
-       silc_pkcs_private_key_data_encode @ 573 ; \r
-       silc_pkcs_private_key_data_set @ 574 ; \r
-       silc_pkcs_private_key_decode @ 575 ; \r
-       silc_pkcs_private_key_encode @ 576 ; \r
-       silc_pkcs_private_key_free @ 577 ; \r
-       silc_pkcs_private_key_set @ 578 ; \r
-       silc_pkcs_public_key_alloc @ 579 ; \r
-       silc_pkcs_public_key_data_encode @ 580 ; \r
-       silc_pkcs_public_key_data_set @ 581 ; \r
-       silc_pkcs_public_key_decode @ 582 ; \r
-       silc_pkcs_public_key_encode @ 583 ; \r
-       silc_pkcs_public_key_free @ 584 ; \r
-       silc_pkcs_public_key_set @ 585 ; \r
-       silc_pkcs_register @ 586 ; \r
-       silc_pkcs_register_default @ 587 ; \r
-       silc_pkcs_save_private_key @ 588 ; \r
-       silc_pkcs_save_public_key @ 590 ; \r
-       silc_pkcs_save_public_key_data @ 591 ; \r
-       silc_pkcs_sign @ 592 ; \r
-       silc_pkcs_sign_with_hash @ 593 ; \r
-       silc_pkcs_unregister @ 594 ; \r
-       silc_pkcs_verify @ 595 ; \r
-       silc_pkcs_verify_with_hash @ 596 ; \r
-       silc_protocol_alloc @ 602 ; \r
-       silc_protocol_cancel @ 603 ; \r
-       silc_protocol_execute @ 604 ; \r
-       silc_protocol_execute_final @ 605 ; \r
-       silc_protocol_free @ 606 ; \r
-       silc_protocol_list @ 607 ; \r
-       silc_protocol_register @ 608 ; \r
-       silc_protocol_unregister @ 609 ; \r
-       silc_rc5_context_len @ 610 ; \r
-       silc_rc5_decrypt_cbc @ 611 ; \r
-       silc_rc5_encrypt_cbc @ 612 ; \r
-       silc_rc5_set_key @ 613 ; \r
-       silc_rc5_set_key_with_string @ 614 ; \r
-       silc_rc6_context_len @ 615 ; \r
-       silc_rc6_decrypt_cbc @ 616 ; \r
-       silc_rc6_encrypt_cbc @ 617 ; \r
-       silc_rc6_set_key @ 618 ; \r
-       silc_rc6_set_key_with_string @ 619 ; \r
-       silc_realloc @ 620 ; \r
-       silc_rng_add_noise @ 621 ; \r
-       silc_rng_alloc @ 622 ; \r
-       silc_rng_free @ 623 ; \r
-       silc_rng_get_byte @ 624 ; \r
-       silc_rng_get_rn16 @ 625 ; \r
-       silc_rng_get_rn32 @ 626 ; \r
-       silc_rng_get_rn_data @ 627 ; \r
-       silc_rng_get_rn_string @ 628 ; \r
-       silc_rng_global_add_noise @ 629 ; \r
-       silc_rng_global_get_byte @ 630 ; \r
-       silc_rng_global_get_rn16 @ 631 ; \r
-       silc_rng_global_get_rn32 @ 632 ; \r
-       silc_rng_global_get_rn_data @ 633 ; \r
-       silc_rng_global_get_rn_string @ 634 ; \r
-       silc_rng_global_init @ 635 ; \r
-       silc_rng_global_uninit @ 636 ; \r
-       silc_rng_init @ 637 ; \r
-       silc_rsa_clear_keys @ 638 ; \r
-       silc_rsa_context_len @ 639 ; \r
-       silc_rsa_decrypt @ 640 ; \r
-       silc_rsa_encrypt @ 641 ; \r
-       silc_rsa_get_private_key @ 642 ; \r
-       silc_rsa_get_public_key @ 643 ; \r
-       silc_rsa_init @ 644 ; \r
-       silc_rsa_set_private_key @ 645 ; \r
-       silc_rsa_set_public_key @ 646 ; \r
-       silc_rsa_sign @ 647 ; \r
-       silc_rsa_verify @ 648 ; \r
-       silc_schedule @ 649 ; \r
-       silc_schedule_init @ 650 ; \r
-       silc_schedule_one @ 651 ; \r
-       silc_schedule_set_listen_fd @ 652 ; \r
-       silc_schedule_stop @ 653 ; \r
-       silc_schedule_task_add @ 654 ; \r
-       silc_schedule_task_del @ 655 ; \r
-       silc_schedule_task_del_by_callback @ 656 ; \r
-       silc_schedule_task_del_by_context @ 657 ; \r
-       silc_schedule_task_del_by_fd @ 658 ; \r
-       silc_schedule_uninit @ 659 ; \r
-       silc_schedule_unset_listen_fd @ 660 ; \r
-       silc_schedule_wakeup @ 661 ; \r
-       silc_select @ 665 ; \r
-       silc_sha1_context_len @ 666 ; \r
-       silc_sha1_final @ 667 ; \r
-       silc_sha1_init @ 668 ; \r
-       silc_sha1_transform @ 669 ; \r
-       silc_sha1_update @ 670 ; \r
-       silc_ske_abort @ 671 ; \r
-       silc_ske_alloc @ 672 ; \r
-       silc_ske_assemble_security_properties @ 673 ; \r
-       silc_ske_end @ 675 ; \r
-       silc_ske_free @ 676 ; \r
-       silc_ske_free_key_material @ 677 ; \r
-       silc_ske_group_get_by_name @ 678 ; \r
-       silc_ske_group_get_by_number @ 679 ; \r
-       silc_ske_get_supported_groups @ 680 ; \r
-       silc_ske_group_get_number @ 681 ; \r
-       silc_ske_groups @ 682 ; \r
-       silc_ske_initiator_finish @ 683 ; \r
-       silc_ske_initiator_phase_1 @ 684 ; \r
-       silc_ske_initiator_phase_2 @ 685 ; \r
-       silc_ske_initiator_start @ 686 ; \r
-       silc_ske_payload_ke_decode @ 688 ; \r
-       silc_ske_payload_ke_encode @ 689 ; \r
-       silc_ske_payload_ke_free @ 690 ; \r
-       silc_ske_payload_start_decode @ 691 ; \r
-       silc_ske_payload_start_encode @ 692 ; \r
-       silc_ske_payload_start_free @ 693 ; \r
-       silc_ske_process_key_material @ 694 ; \r
-       silc_ske_process_key_material_data @ 695 ; \r
-       silc_ske_responder_finish @ 696 ; \r
-       silc_ske_responder_phase_1 @ 697 ; \r
-       silc_ske_responder_phase_2 @ 698 ; \r
-       silc_ske_responder_start @ 699 ; \r
-       silc_ske_select_security_properties @ 700 ; \r
-       silc_ske_set_callbacks @ 701 ; \r
-       silc_socket_alloc @ 702 ; \r
-       silc_socket_dup @ 703 ; \r
-       silc_socket_free @ 704 ; \r
-       silc_socket_host_lookup @ 705 ; \r
-       silc_socket_read @ 706 ; \r
-       silc_socket_set_heartbeat @ 707 ; \r
-       silc_socket_write @ 708 ; \r
-       silc_string_compare @ 709 ; \r
-       silc_thread_create @ 710 ; \r
-       silc_thread_exit @ 711 ; \r
-       silc_thread_self @ 712 ; \r
-       silc_thread_wait @ 713 ; \r
-       silc_to_upper @ 715 ; \r
-       silc_twofish_context_len @ 716 ; \r
-       silc_twofish_decrypt_cbc @ 717 ; \r
-       silc_twofish_encrypt_cbc @ 718 ; \r
-       silc_twofish_set_key @ 719 ; \r
-       silc_twofish_set_key_with_string @ 720 ; \r
-       silc_buffer_format_vp @ 789 ; \r
-       silc_buffer_unformat_vp @ 790 ; \r
-       silc_sftp_client_start @ 791 ;\r
-       silc_sftp_client_shutdown @ 792 ;\r
-       silc_sftp_client_receive_process @ 793 ;\r
-       silc_sftp_open @ 794 ;\r
-       silc_sftp_close @ 795 ;\r
-       silc_sftp_read @ 796 ;\r
-       silc_sftp_write @ 797 ;\r
-       silc_sftp_remove @ 798 ;\r
-       silc_sftp_rename @ 799 ;\r
-       silc_sftp_mkdir @ 800 ;\r
-       silc_sftp_rmdir @ 801 ;\r
-       silc_sftp_opendir @ 802 ;\r
-       silc_sftp_readdir @ 803 ;\r
-       silc_sftp_stat @ 804 ;\r
-       silc_sftp_lstat @ 805 ;\r
-       silc_sftp_fstat @ 806 ;\r
-       silc_sftp_setstat @ 807 ;\r
-       silc_sftp_fsetstat @ 808 ;\r
-       silc_sftp_readlink @ 809 ;\r
-       silc_sftp_symlink @ 810 ;\r
-       silc_sftp_realpath @ 811 ;\r
-       silc_sftp_extended @ 812 ;\r
-       silc_sftp_server_start @ 813 ;\r
-       silc_sftp_server_shutdown @ 814 ;\r
-       silc_sftp_server_receive_process @ 815 ;\r
-       silc_sftp_fs_memory @ 816 ;\r
-       silc_sftp_fs_memory_alloc @ 817 ;\r
-       silc_sftp_fs_memory_free @ 818 ;\r
-       silc_sftp_fs_memory_add_dir @ 819 ;\r
-       silc_sftp_fs_memory_del_dir @ 820 ;\r
-       silc_sftp_fs_memory_add_file @ 821 ;\r
-       silc_sftp_fs_memory_del_file @ 822 ;\r
-       silc_file_open @ 824 ;\r
-       silc_file_close @ 825 ;\r
-       silc_file_read @ 826 ;\r
-       silc_file_write @ 827 ;\r
-       silc_file_size @ 828 ;\r
-       silc_hmac_init @ 829 ;\r
-       silc_hmac_update @ 830 ;\r
-       silc_hmac_final @ 831 ;\r
-       silc_hmac_init_with_key @ 832 ;\r
-       silc_hmac_get_name @ 833 ;\r
-       silc_hmac_get_hash @ 834 ;\r
-       silc_net_localip @ 835 ;\r
-       silc_sftp_server_set_monitor @ 836 ;\r
-       silc_net_gethostbyname @ 837 ;\r
-       silc_net_gethostbyaddr @ 838 ;\r
-       silc_net_gethostbyname_async @ 839 ;\r
-       silc_net_gethostbyaddr_async @ 840 ;\r
-       silc_net_is_ip4 @ 841 ;\r
-       silc_net_is_ip6 @ 842 ;\r
-       silc_log_set_debug_string @ 843 ;\r
-       silc_log_reset_all @ 844 ;\r
-       silc_log_flush_all @ 845 ;\r
-       silc_log_get_file @ 846 ;\r
-       silc_log_quick @ 847 DATA ;\r
-       silc_log_flushdelay @ 848 DATA ;\r
-       silc_hash_table_list_reset @ 849 ;\r
-       silc_debug_hexdump @ 850 DATA ;\r
-       silc_memdup @ 851 ;\r
-       silc_command_get_status @ 852 ;\r
-       silc_utf8_encode @ 853 ;\r
-       silc_utf8_decode @ 854 ;\r
-       silc_utf8_encoded_len @ 855 ;\r
-       silc_utf8_valid @ 856 ;\r
-       silc_mime_parse @ 857 ;\r
-       silc_get_status_message @ 858 ;\r
-       silc_get_mode_list @ 859 ;\r
-       silc_hash_table_find_by_context @ 860 ;\r
-       silc_string_is_ascii @ 862 ;\r
-       silc_parse_version_string @ 863 ;\r
-       silc_version_to_num @ 864 ;\r
-       silc_fingerprint @ 865 ;\r
-        silc_get_packet_name @ 866 ;\r
-        silc_get_command_name @ 867 ;\r
-        silc_strncat @ 868 ;\r
-        silc_attribute_payload_parse @ 869 ;\r
-        silc_attribute_payload_encode @ 870 ;\r
-        silc_attribute_payload_alloc @ 871 ;\r
-        silc_attribute_payload_free @ 872 ;\r
-        silc_attribute_payload_list_free @ 873 ;\r
-        silc_attribute_payload_encode_data @ 874 ;\r
-        silc_attribute_get_attribute @ 875 ;\r
-        silc_attribute_get_data @ 876 ;\r
-        silc_attribute_get_object @ 877 ;\r
-        silc_attribute_get_flags @ 878 ;\r
-        silc_attribute_get_verify_data @ 879 ;\r
-        silc_hash_get_name @ 880 ;\r
-       silc_create_key_pair @ 881 ;\r
-       silc_load_key_pair @ 882 ;\r
-       silc_show_public_key @ 883 ;\r
-       silc_change_private_key_passphrase @ 884 ;\r
-       silc_argument_payload_encode_one @ 885 ; \r
-       silc_message_payload_decrypt @ 886 ; \r
-       silc_message_payload_parse @ 887 ; \r
-       silc_message_payload_encrypt @ 888 ; \r
-       silc_message_payload_encode @ 889 ; \r
-       silc_message_payload_free @ 890 ; \r
-       silc_message_get_flags @ 891 ; \r
-       silc_message_get_data @ 892 ; \r
-       silc_message_get_mac @ 893 ; \r
-       silc_message_get_iv @ 894 ; \r
-       silc_message_signed_payload_parse @ 895 ; \r
-       silc_message_signed_payload_encode @ 896 ; \r
-       silc_message_signed_payload_free @ 897 ; \r
-       silc_message_signed_verify @ 898 ; \r
-        silc_message_signed_get_public_key @ 899 ;\r
-        silc_hmac_unregister_all @ 900 ;\r
-        silc_hash_unregister_all @ 901 ;\r
-        silc_pkcs_unregister_all @ 902 ;\r
-        silc_cipher_unregister_all @ 903 ;\r
-        silc_rng_get_byte_fast @ 904 ;\r
-        silc_cipher_get_name @ 905 ;\r
-        silc_hmac_get_name @ 906 ;\r
-        silc_hash_get_name @ 907 ;\r
-        silc_pkcs_public_key_payload_encode @ 908 ;\r
-        silc_pkcs_public_key_payload_decode @ 909 ;\r
-\r
+;
+; Exports file for SILC Core DLL.
+;
+; This file is generated from MinGW compiled object files using the
+; following command:
+;
+; dlltool --export-all --output-def libsilc.def libsilc.a
+;
+; ----------------------------------------------------------------------------
+;
+; If you edit this file by adding or removing any exports be sure to
+; preserve the ordinal values (the @ n in the exports) and add new exports
+; always at the end of the list with new ordinal value. Do not ever
+; add new export with old ordinal value if you need to preserve backwards
+; compatiblity. -Pekka
+;
+EXPORTS
+       silc_aes_context_len @ 235 ;
+       silc_aes_decrypt_cbc @ 236 ;
+       silc_aes_encrypt_cbc @ 237 ;
+       silc_aes_set_key @ 238 ;
+       silc_aes_set_key_with_string @ 239 ;
+       silc_argument_get_arg_num @ 240 ;
+       silc_argument_get_arg_type @ 241 ;
+       silc_argument_get_first_arg @ 242 ;
+       silc_argument_get_next_arg @ 243 ;
+       silc_argument_payload_encode @ 244 ;
+       silc_argument_payload_encode_payload @ 245 ;
+       silc_argument_payload_free @ 246 ;
+       silc_argument_payload_parse @ 247 ;
+       silc_auth_get_data @ 248 ;
+       silc_auth_get_method @ 249 ;
+       silc_auth_payload_encode @ 250 ;
+       silc_auth_payload_free @ 251 ;
+       silc_auth_payload_parse @ 252 ;
+       silc_auth_public_key_auth_generate @ 253 ;
+       silc_auth_public_key_auth_verify @ 254 ;
+       silc_auth_public_key_auth_verify_data @ 255 ;
+       silc_auth_verify @ 256 ;
+       silc_auth_verify_data @ 257 ;
+       silc_blowfish_context_len @ 258 ;
+       silc_blowfish_decrypt_cbc @ 259 ;
+       silc_blowfish_encrypt_cbc @ 260 ;
+       silc_blowfish_set_key @ 261 ;
+       silc_blowfish_set_key_with_string @ 262 ;
+       silc_buffer_format @ 263 ;
+       silc_buffer_unformat @ 264 ;
+       silc_calloc @ 265 ;
+       silc_cast_context_len @ 266 ;
+       silc_cast_decrypt_cbc @ 267 ;
+       silc_cast_encrypt_cbc @ 268 ;
+       silc_cast_set_key @ 269 ;
+       silc_cast_set_key_with_string @ 270 ;
+       silc_channel_get_id @ 271 ;
+       silc_channel_get_id_parse @ 272 ;
+       silc_channel_get_mode @ 273 ;
+       silc_channel_get_name @ 274 ;
+       silc_channel_key_get_cipher @ 275 ;
+       silc_channel_key_get_id @ 276 ;
+       silc_channel_key_get_key @ 277 ;
+       silc_channel_key_payload_encode @ 278 ;
+       silc_channel_key_payload_free @ 279 ;
+       silc_channel_key_payload_parse @ 280 ;
+       silc_channel_payload_encode @ 289 ;
+       silc_channel_payload_free @ 290 ;
+       silc_channel_payload_list_free @ 291 ;
+       silc_channel_payload_parse @ 292 ;
+       silc_channel_payload_parse_list @ 293 ;
+       silc_check_line @ 294 ;
+       silc_cipher_alloc @ 295 ;
+       silc_cipher_decrypt @ 296 ;
+       silc_cipher_encrypt @ 297 ;
+       silc_cipher_free @ 298 ;
+       silc_cipher_get_block_len @ 299 ;
+       silc_cipher_get_iv @ 300 ;
+       silc_cipher_get_key_len @ 301 ;
+       silc_cipher_get_supported @ 302 ;
+       silc_cipher_is_supported @ 303 ;
+       silc_cipher_list @ 304 ;
+       silc_cipher_register @ 305 ;
+       silc_cipher_register_default @ 306 ;
+       silc_cipher_set_iv @ 307 ;
+       silc_cipher_set_key @ 308 ;
+       silc_cipher_unregister @ 309 ;
+       silc_client_chmode @ 310 ;
+       silc_client_chumode @ 311 ;
+       silc_client_chumode_char @ 312 ;
+       silc_command_get @ 313 ;
+       silc_command_get_args @ 314 ;
+       silc_command_get_ident @ 315 ;
+       silc_command_payload_encode @ 316 ;
+       silc_command_payload_encode_payload @ 317 ;
+       silc_command_payload_encode_va @ 318 ;
+       silc_command_payload_encode_vap @ 319 ;
+       silc_command_payload_free @ 320 ;
+       silc_command_payload_parse @ 321 ;
+       silc_command_reply_payload_encode_va @ 322 ;
+       silc_command_set_command @ 323 ;
+       silc_command_set_ident @ 324 ;
+       silc_config_open @ 327 ;
+       silc_debug @ 328 DATA ;
+       silc_pem_decode @ 329 ;
+       silc_default_ciphers @ 330 DATA ;
+       silc_default_hash @ 331 DATA ;
+       silc_default_hmacs @ 332 DATA ;
+       silc_default_pkcs @ 333 DATA ;
+       silc_pem_encode @ 334 ;
+       silc_pem_encode_file @ 335 ;
+       silc_file_readfile @ 336 ;
+       silc_file_writefile @ 337 ;
+       silc_file_writefile_mode @ 338 ;
+       silc_format @ 339 ;
+       silc_free @ 340 ;
+       silc_get_time @ 341 ;
+       silc_gets @ 342 ;
+       silc_gettimeofday @ 343 ;
+       silc_hash_alloc @ 344 ;
+       silc_hash_client_id_compare @ 345 ;
+       silc_hash_data @ 346 ;
+       silc_hash_data_compare @ 347 ;
+       silc_hash_fingerprint @ 348 ;
+       silc_hash_free @ 349 ;
+       silc_hash_get_supported @ 350 ;
+       silc_hash_id @ 351 ;
+       silc_hash_id_compare @ 352 ;
+       silc_hash_is_supported @ 353 ;
+       silc_hash_len @ 354 ;
+       silc_hash_list @ 355 ;
+       silc_hash_make @ 356 ;
+       silc_hash_ptr @ 357 ;
+       silc_hash_register @ 358 ;
+       silc_hash_register_default @ 359 ;
+       silc_hash_string @ 360 ;
+       silc_hash_string_compare @ 361 ;
+       silc_hash_table_add @ 362 ;
+       silc_hash_table_add_ext @ 363 ;
+       silc_hash_table_alloc @ 364 ;
+       silc_hash_table_count @ 365 ;
+       silc_hash_table_del @ 366 ;
+       silc_hash_table_del_by_context @ 367 ;
+       silc_hash_table_del_by_context_ext @ 368 ;
+       silc_hash_table_del_ext @ 369 ;
+       silc_hash_table_find @ 370 ;
+       silc_hash_table_find_ext @ 371 ;
+       silc_hash_table_find_foreach @ 372 ;
+       silc_hash_table_find_foreach_ext @ 373 ;
+       silc_hash_table_foreach @ 374 ;
+       silc_hash_table_free @ 375 ;
+       silc_hash_table_get @ 376 ;
+       silc_hash_table_list @ 377 ;
+       silc_hash_table_rehash @ 378 ;
+       silc_hash_table_rehash_ext @ 379 ;
+       silc_hash_table_replace @ 380 ;
+       silc_hash_table_replace_ext @ 381 ;
+       silc_hash_table_size @ 382 ;
+       silc_hash_uint @ 383 ;
+       silc_hash_unregister @ 384 ;
+       silc_hmac_alloc @ 385 ;
+       silc_hmac_free @ 386 ;
+       silc_hmac_get_supported @ 387 ;
+       silc_hmac_is_supported @ 388 ;
+       silc_hmac_len @ 389 ;
+       silc_hmac_list @ 390 ;
+       silc_hmac_make @ 391 ;
+       silc_hmac_make_truncated @ 393 ;
+       silc_hmac_make_with_key @ 394 ;
+       silc_hmac_register @ 395 ;
+       silc_hmac_register_default @ 396 ;
+       silc_hmac_set_key @ 397 ;
+       silc_hmac_unregister @ 398 ;
+       silc_id_dup @ 399 ;
+       silc_id_get_len @ 400 ;
+       silc_id_id2str @ 401 ;
+       silc_id_payload_encode @ 402 ;
+       silc_id_payload_free @ 403 ;
+       silc_id_payload_get_data @ 404 ;
+       silc_id_payload_get_id @ 405 ;
+       silc_id_payload_get_len @ 406 ;
+       silc_id_payload_get_type @ 407 ;
+       silc_id_payload_parse @ 408 ;
+       silc_id_payload_parse_id @ 410 ;
+       silc_id_render @ 411 ;
+       silc_id_str2id @ 412 ;
+       silc_idcache_add @ 413 ;
+       silc_idcache_alloc @ 414 ;
+       silc_idcache_del @ 415 ;
+       silc_idcache_del_all @ 416 ;
+       silc_idcache_del_by_context @ 417 ;
+       silc_idcache_del_by_id @ 418 ;
+       silc_idcache_del_by_id_ext @ 419 ;
+       silc_idcache_find_by_context @ 420 ;
+       silc_idcache_find_by_id @ 421 ;
+       silc_idcache_find_by_id_one @ 422 ;
+       silc_idcache_find_by_id_one_ext @ 423 ;
+       silc_idcache_find_by_name @ 424 ;
+       silc_idcache_find_by_name_one @ 425 ;
+       silc_idcache_free @ 426 ;
+       silc_idcache_get_all @ 427 ;
+       silc_idcache_list_count @ 428 ;
+       silc_idcache_list_first @ 429 ;
+       silc_idcache_list_free @ 430 ;
+       silc_idcache_list_next @ 431 ;
+       silc_idcache_purge @ 432 ;
+       silc_idcache_purge_by_context @ 433 ;
+       silc_key_agreement_get_hostname @ 434 ;
+       silc_key_agreement_get_port @ 435 ;
+       silc_key_agreement_payload_encode @ 436 ;
+       silc_key_agreement_payload_free @ 437 ;
+       silc_key_agreement_payload_parse @ 438 ;
+       silc_log_output @ 439 ;
+       silc_log_output_debug @ 440 ;
+       silc_log_output_hexdump @ 441 ;
+       silc_log_reset_callbacks @ 442 ;
+       silc_log_reset_debug_callbacks @ 443 ;
+       silc_log_set_callback @ 444 ;
+       silc_log_set_debug_callbacks @ 445 ;
+       silc_log_set_file @ 446 ;
+       silc_malloc @ 448 ;
+       silc_math_gen_prime @ 454 ;
+       silc_math_prime_test @ 455 ;
+       silc_md5_context_len @ 456 ;
+       silc_md5_final @ 457 ;
+       silc_md5_init @ 458 ;
+       silc_md5_transform @ 459 ;
+       silc_md5_update @ 460 ;
+       silc_mp_abs @ 461 ;
+       silc_mp_add @ 462 ;
+       silc_mp_add_ui @ 463 ;
+       silc_mp_and @ 464 ;
+       silc_mp_bin2mp @ 465 ;
+       silc_mp_cmp @ 466 ;
+       silc_mp_cmp_si @ 467 ;
+       silc_mp_cmp_ui @ 468 ;
+       silc_mp_div @ 469 ;
+       silc_mp_div_2exp @ 470 ;
+       silc_mp_div_2exp_qr @ 471 ;
+       silc_mp_div_qr @ 472 ;
+       silc_mp_div_ui @ 473 ;
+       silc_mp_gcd @ 474 ;
+       silc_mp_gcdext @ 475 ;
+       silc_mp_get_str @ 476 ;
+       silc_mp_get_ui @ 477 ;
+       silc_mp_init @ 478 ;
+       silc_mp_mod @ 479 ;
+       silc_mp_mod_2exp @ 480 ;
+       silc_mp_mod_ui @ 481 ;
+       silc_mp_modinv @ 482 ;
+       silc_mp_mp2bin @ 483 ;
+       silc_mp_mp2bin_noalloc @ 484 ;
+       silc_mp_mul @ 485 ;
+       silc_mp_mul_2exp @ 486 ;
+       silc_mp_mul_ui @ 487 ;
+       silc_mp_neg @ 488 ;
+       silc_mp_or @ 489 ;
+       silc_mp_pow @ 490 ;
+       silc_mp_pow_mod @ 491 ;
+       silc_mp_pow_mod_ui @ 492 ;
+       silc_mp_pow_ui @ 493 ;
+       silc_mp_set @ 494 ;
+       silc_mp_set_si @ 495 ;
+       silc_mp_set_str @ 496 ;
+       silc_mp_set_ui @ 497 ;
+       silc_mp_size @ 498 ;
+       silc_mp_sizeinbase @ 499 ;
+       silc_mp_sqrt @ 500 ;
+       silc_mp_sub @ 501 ;
+       silc_mp_sub_ui @ 502 ;
+       silc_mp_uninit @ 503 ;
+       silc_mp_xor @ 504 ;
+       silc_mutex_alloc @ 505 ;
+       silc_mutex_free @ 506 ;
+       silc_mutex_lock @ 507 ;
+       silc_mutex_unlock @ 508 ;
+       silc_net_accept_connection @ 509 ;
+       silc_net_addr2bin @ 510 ;
+       silc_net_check_host_by_sock @ 511 ;
+       silc_net_check_local_by_sock @ 512 ;
+       silc_net_close_connection @ 513 ;
+       silc_net_close_server @ 514 ;
+       silc_net_create_connection @ 515 ;
+       silc_net_create_connection_async @ 516 ;
+       silc_net_create_server @ 517 ;
+       silc_net_get_local_port @ 518 ;
+       silc_net_get_remote_port @ 519 ;
+       silc_net_get_socket_opt @ 520 ;
+       silc_net_is_ip @ 521 ;
+       silc_net_localhost @ 522 ;
+       silc_net_set_socket_nonblock @ 523 ;
+       silc_net_set_socket_opt @ 524 ;
+       silc_net_win32_init @ 525 ;
+       silc_net_win32_uninit @ 526 ;
+       silc_none_context_len @ 527 ;
+       silc_none_decrypt_cbc @ 528 ;
+       silc_none_encrypt_cbc @ 529 ;
+       silc_none_set_key @ 530 ;
+       silc_none_set_key_with_string @ 531 ;
+       silc_notify_get_arg_num @ 532 ;
+       silc_notify_get_args @ 533 ;
+       silc_notify_get_type @ 534 ;
+       silc_notify_payload_encode @ 535 ;
+       silc_notify_payload_encode_args @ 536 ;
+       silc_notify_payload_free @ 537 ;
+       silc_notify_payload_parse @ 538 ;
+       silc_packet_assemble @ 539 ;
+       silc_packet_context_alloc @ 540 ;
+       silc_packet_context_dup @ 541 ;
+       silc_packet_context_free @ 542 ;
+       silc_packet_encrypt @ 544 ;
+       silc_packet_parse @ 545 ;
+       silc_packet_parse_special @ 546 ;
+       silc_packet_receive @ 547 ;
+       silc_packet_receive_process @ 548 ;
+       silc_packet_send @ 549 ;
+       silc_packet_send_prepare @ 550 ;
+       silc_parse_command_line @ 551 ;
+       silc_parse_userfqdn @ 552 ;
+       silc_pkcs1_decrypt @ 553 ;
+       silc_pkcs1_encrypt @ 554 ;
+       silc_pkcs1_sign @ 555 ;
+       silc_pkcs1_verify @ 556 ;
+       silc_pkcs_alloc @ 557 ;
+       silc_pkcs_decode_identifier @ 558 ;
+       silc_pkcs_decrypt @ 559 ;
+       silc_pkcs_encode_identifier @ 560 ;
+       silc_pkcs_encrypt @ 561 ;
+       silc_pkcs_free @ 562 ;
+       silc_pkcs_free_identifier @ 563 ;
+       silc_pkcs_get_key_len @ 564 ;
+       silc_pkcs_get_private_key @ 565 ;
+       silc_pkcs_get_public_key @ 566 ;
+       silc_pkcs_get_supported @ 567 ;
+       silc_pkcs_is_supported @ 568 ;
+       silc_pkcs_list @ 569 ;
+       silc_pkcs_load_private_key @ 570 ;
+       silc_pkcs_load_public_key @ 571 ;
+       silc_pkcs_private_key_alloc @ 572 ;
+       silc_pkcs_private_key_data_encode @ 573 ;
+       silc_pkcs_private_key_data_set @ 574 ;
+       silc_pkcs_private_key_decode @ 575 ;
+       silc_pkcs_private_key_encode @ 576 ;
+       silc_pkcs_private_key_free @ 577 ;
+       silc_pkcs_private_key_set @ 578 ;
+       silc_pkcs_public_key_alloc @ 579 ;
+       silc_pkcs_public_key_data_encode @ 580 ;
+       silc_pkcs_public_key_data_set @ 581 ;
+       silc_pkcs_public_key_decode @ 582 ;
+       silc_pkcs_public_key_encode @ 583 ;
+       silc_pkcs_public_key_free @ 584 ;
+       silc_pkcs_public_key_set @ 585 ;
+       silc_pkcs_register @ 586 ;
+       silc_pkcs_register_default @ 587 ;
+       silc_pkcs_save_private_key @ 588 ;
+       silc_pkcs_save_public_key @ 590 ;
+       silc_pkcs_save_public_key_data @ 591 ;
+       silc_pkcs_sign @ 592 ;
+       silc_pkcs_sign_with_hash @ 593 ;
+       silc_pkcs_unregister @ 594 ;
+       silc_pkcs_verify @ 595 ;
+       silc_pkcs_verify_with_hash @ 596 ;
+       silc_protocol_alloc @ 602 ;
+       silc_protocol_cancel @ 603 ;
+       silc_protocol_execute @ 604 ;
+       silc_protocol_execute_final @ 605 ;
+       silc_protocol_free @ 606 ;
+       silc_protocol_list @ 607 ;
+       silc_protocol_register @ 608 ;
+       silc_protocol_unregister @ 609 ;
+       silc_rc5_context_len @ 610 ;
+       silc_rc5_decrypt_cbc @ 611 ;
+       silc_rc5_encrypt_cbc @ 612 ;
+       silc_rc5_set_key @ 613 ;
+       silc_rc5_set_key_with_string @ 614 ;
+       silc_rc6_context_len @ 615 ;
+       silc_rc6_decrypt_cbc @ 616 ;
+       silc_rc6_encrypt_cbc @ 617 ;
+       silc_rc6_set_key @ 618 ;
+       silc_rc6_set_key_with_string @ 619 ;
+       silc_realloc @ 620 ;
+       silc_rng_add_noise @ 621 ;
+       silc_rng_alloc @ 622 ;
+       silc_rng_free @ 623 ;
+       silc_rng_get_byte @ 624 ;
+       silc_rng_get_rn16 @ 625 ;
+       silc_rng_get_rn32 @ 626 ;
+       silc_rng_get_rn_data @ 627 ;
+       silc_rng_get_rn_string @ 628 ;
+       silc_rng_global_add_noise @ 629 ;
+       silc_rng_global_get_byte @ 630 ;
+       silc_rng_global_get_rn16 @ 631 ;
+       silc_rng_global_get_rn32 @ 632 ;
+       silc_rng_global_get_rn_data @ 633 ;
+       silc_rng_global_get_rn_string @ 634 ;
+       silc_rng_global_init @ 635 ;
+       silc_rng_global_uninit @ 636 ;
+       silc_rng_init @ 637 ;
+       silc_rsa_clear_keys @ 638 ;
+       silc_rsa_context_len @ 639 ;
+       silc_rsa_decrypt @ 640 ;
+       silc_rsa_encrypt @ 641 ;
+       silc_rsa_get_private_key @ 642 ;
+       silc_rsa_get_public_key @ 643 ;
+       silc_rsa_init @ 644 ;
+       silc_rsa_set_private_key @ 645 ;
+       silc_rsa_set_public_key @ 646 ;
+       silc_rsa_sign @ 647 ;
+       silc_rsa_verify @ 648 ;
+       silc_schedule @ 649 ;
+       silc_schedule_init @ 650 ;
+       silc_schedule_one @ 651 ;
+       silc_schedule_set_listen_fd @ 652 ;
+       silc_schedule_stop @ 653 ;
+       silc_schedule_task_add @ 654 ;
+       silc_schedule_task_del @ 655 ;
+       silc_schedule_task_del_by_callback @ 656 ;
+       silc_schedule_task_del_by_context @ 657 ;
+       silc_schedule_task_del_by_fd @ 658 ;
+       silc_schedule_uninit @ 659 ;
+       silc_schedule_unset_listen_fd @ 660 ;
+       silc_schedule_wakeup @ 661 ;
+       silc_select @ 665 ;
+       silc_sha1_context_len @ 666 ;
+       silc_sha1_final @ 667 ;
+       silc_sha1_init @ 668 ;
+       silc_sha1_transform @ 669 ;
+       silc_sha1_update @ 670 ;
+       silc_ske_abort @ 671 ;
+       silc_ske_alloc @ 672 ;
+       silc_ske_assemble_security_properties @ 673 ;
+       silc_ske_end @ 675 ;
+       silc_ske_free @ 676 ;
+       silc_ske_free_key_material @ 677 ;
+       silc_ske_group_get_by_name @ 678 ;
+       silc_ske_group_get_by_number @ 679 ;
+       silc_ske_get_supported_groups @ 680 ;
+       silc_ske_group_get_number @ 681 ;
+       silc_ske_groups @ 682 ;
+       silc_ske_initiator_finish @ 683 ;
+       silc_ske_initiator_phase_1 @ 684 ;
+       silc_ske_initiator_phase_2 @ 685 ;
+       silc_ske_initiator_start @ 686 ;
+       silc_ske_payload_ke_decode @ 688 ;
+       silc_ske_payload_ke_encode @ 689 ;
+       silc_ske_payload_ke_free @ 690 ;
+       silc_ske_payload_start_decode @ 691 ;
+       silc_ske_payload_start_encode @ 692 ;
+       silc_ske_payload_start_free @ 693 ;
+       silc_ske_process_key_material @ 694 ;
+       silc_ske_process_key_material_data @ 695 ;
+       silc_ske_responder_finish @ 696 ;
+       silc_ske_responder_phase_1 @ 697 ;
+       silc_ske_responder_phase_2 @ 698 ;
+       silc_ske_responder_start @ 699 ;
+       silc_ske_select_security_properties @ 700 ;
+       silc_ske_set_callbacks @ 701 ;
+       silc_socket_alloc @ 702 ;
+       silc_socket_dup @ 703 ;
+       silc_socket_free @ 704 ;
+       silc_socket_host_lookup @ 705 ;
+       silc_socket_read @ 706 ;
+       silc_socket_set_heartbeat @ 707 ;
+       silc_socket_write @ 708 ;
+       silc_string_compare @ 709 ;
+       silc_thread_create @ 710 ;
+       silc_thread_exit @ 711 ;
+       silc_thread_self @ 712 ;
+       silc_thread_wait @ 713 ;
+       silc_to_upper @ 715 ;
+       silc_twofish_context_len @ 716 ;
+       silc_twofish_decrypt_cbc @ 717 ;
+       silc_twofish_encrypt_cbc @ 718 ;
+       silc_twofish_set_key @ 719 ;
+       silc_twofish_set_key_with_string @ 720 ;
+       silc_buffer_format_vp @ 789 ;
+       silc_buffer_unformat_vp @ 790 ;
+       silc_sftp_client_start @ 791 ;
+       silc_sftp_client_shutdown @ 792 ;
+       silc_sftp_client_receive_process @ 793 ;
+       silc_sftp_open @ 794 ;
+       silc_sftp_close @ 795 ;
+       silc_sftp_read @ 796 ;
+       silc_sftp_write @ 797 ;
+       silc_sftp_remove @ 798 ;
+       silc_sftp_rename @ 799 ;
+       silc_sftp_mkdir @ 800 ;
+       silc_sftp_rmdir @ 801 ;
+       silc_sftp_opendir @ 802 ;
+       silc_sftp_readdir @ 803 ;
+       silc_sftp_stat @ 804 ;
+       silc_sftp_lstat @ 805 ;
+       silc_sftp_fstat @ 806 ;
+       silc_sftp_setstat @ 807 ;
+       silc_sftp_fsetstat @ 808 ;
+       silc_sftp_readlink @ 809 ;
+       silc_sftp_symlink @ 810 ;
+       silc_sftp_realpath @ 811 ;
+       silc_sftp_extended @ 812 ;
+       silc_sftp_server_start @ 813 ;
+       silc_sftp_server_shutdown @ 814 ;
+       silc_sftp_server_receive_process @ 815 ;
+       silc_sftp_fs_memory @ 816 ;
+       silc_sftp_fs_memory_alloc @ 817 ;
+       silc_sftp_fs_memory_free @ 818 ;
+       silc_sftp_fs_memory_add_dir @ 819 ;
+       silc_sftp_fs_memory_del_dir @ 820 ;
+       silc_sftp_fs_memory_add_file @ 821 ;
+       silc_sftp_fs_memory_del_file @ 822 ;
+       silc_file_open @ 824 ;
+       silc_file_close @ 825 ;
+       silc_file_read @ 826 ;
+       silc_file_write @ 827 ;
+       silc_file_size @ 828 ;
+       silc_hmac_init @ 829 ;
+       silc_hmac_update @ 830 ;
+       silc_hmac_final @ 831 ;
+       silc_hmac_init_with_key @ 832 ;
+       silc_hmac_get_name @ 833 ;
+       silc_hmac_get_hash @ 834 ;
+       silc_net_localip @ 835 ;
+       silc_sftp_server_set_monitor @ 836 ;
+       silc_net_gethostbyname @ 837 ;
+       silc_net_gethostbyaddr @ 838 ;
+       silc_net_gethostbyname_async @ 839 ;
+       silc_net_gethostbyaddr_async @ 840 ;
+       silc_net_is_ip4 @ 841 ;
+       silc_net_is_ip6 @ 842 ;
+       silc_log_set_debug_string @ 843 ;
+       silc_log_reset_all @ 844 ;
+       silc_log_flush_all @ 845 ;
+       silc_log_get_file @ 846 ;
+       silc_log_quick @ 847 DATA ;
+       silc_log_flushdelay @ 848 DATA ;
+       silc_hash_table_list_reset @ 849 ;
+       silc_debug_hexdump @ 850 DATA ;
+       silc_memdup @ 851 ;
+       silc_command_get_status @ 852 ;
+       silc_utf8_encode @ 853 ;
+       silc_utf8_decode @ 854 ;
+       silc_utf8_encoded_len @ 855 ;
+       silc_utf8_valid @ 856 ;
+       silc_mime_parse @ 857 ;
+       silc_get_status_message @ 858 ;
+       silc_get_mode_list @ 859 ;
+       silc_hash_table_find_by_context @ 860 ;
+       silc_string_is_ascii @ 862 ;
+       silc_parse_version_string @ 863 ;
+       silc_version_to_num @ 864 ;
+       silc_fingerprint @ 865 ;
+        silc_get_packet_name @ 866 ;
+        silc_get_command_name @ 867 ;
+        silc_strncat @ 868 ;
+        silc_attribute_payload_parse @ 869 ;
+        silc_attribute_payload_encode @ 870 ;
+        silc_attribute_payload_alloc @ 871 ;
+        silc_attribute_payload_free @ 872 ;
+        silc_attribute_payload_list_free @ 873 ;
+        silc_attribute_payload_encode_data @ 874 ;
+        silc_attribute_get_attribute @ 875 ;
+        silc_attribute_get_data @ 876 ;
+        silc_attribute_get_object @ 877 ;
+        silc_attribute_get_flags @ 878 ;
+        silc_attribute_get_verify_data @ 879 ;
+        silc_hash_get_name @ 880 ;
+       silc_create_key_pair @ 881 ;
+       silc_load_key_pair @ 882 ;
+       silc_show_public_key @ 883 ;
+       silc_change_private_key_passphrase @ 884 ;
+       silc_argument_payload_encode_one @ 885 ;
+       silc_message_payload_decrypt @ 886 ;
+       silc_message_payload_parse @ 887 ;
+       silc_message_payload_encrypt @ 888 ;
+       silc_message_payload_encode @ 889 ;
+       silc_message_payload_free @ 890 ;
+       silc_message_get_flags @ 891 ;
+       silc_message_get_data @ 892 ;
+       silc_message_get_mac @ 893 ;
+       silc_message_get_iv @ 894 ;
+       silc_message_signed_payload_parse @ 895 ;
+       silc_message_signed_payload_encode @ 896 ;
+       silc_message_signed_payload_free @ 897 ;
+       silc_message_signed_verify @ 898 ;
+        silc_message_signed_get_public_key @ 899 ;
+        silc_hmac_unregister_all @ 900 ;
+        silc_hash_unregister_all @ 901 ;
+        silc_pkcs_unregister_all @ 902 ;
+        silc_cipher_unregister_all @ 903 ;
+        silc_rng_get_byte_fast @ 904 ;
+        silc_cipher_get_name @ 905 ;
+        silc_pkcs_public_key_payload_encode @ 908 ;
+        silc_pkcs_public_key_payload_decode @ 909 ;
+       silc_auth_get_public_data @ 910 ;
+       silc_auth_public_key_auth_generate_wpub @ 911 ;
+       silc_status_get_args @ 912 ;
+
index f9b45781389f6876f182055eb02f2c0bb066dac1..83ea65b4c0815aaab9a81d94b841009e7ba14251 100644 (file)
@@ -252,10 +252,6 @@ SOURCE=..\..\lib\silcmath\mpi\mplogic.c
 \r
 SOURCE=..\..\lib\silcmath\mpi\mpmontg.c\r
 # End Source File\r
-# Begin Source File\r
-\r
-SOURCE=..\..\lib\silcmath\mpi\mpprime.c\r
-# End Source File\r
 # End Group\r
 # Begin Source File\r
 \r
diff --git a/win32/libsilc_static/libsilc_static.dsp b/win32/libsilc_static/libsilc_static.dsp
new file mode 100644 (file)
index 0000000..2ca90cd
--- /dev/null
@@ -0,0 +1,697 @@
+# Microsoft Developer Studio Project File - Name="libsilc_static" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Static Library" 0x0104\r
+\r
+CFG=libsilc_static - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "libsilc_static.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "libsilc_static.mak" CFG="libsilc_static - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "libsilc_static - Win32 Release" (based on "Win32 (x86) Static Library")\r
+!MESSAGE "libsilc_static - Win32 Debug" (based on "Win32 (x86) Static Library")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName "Perforce Project"\r
+# PROP Scc_LocalPath "..\.."\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "libsilc_static - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "Release"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c\r
+# ADD CPP /nologo /W2 /GX /O2 /I ".\\" /I "..\\" /I "..\..\\" /I "..\..\includes" /I "..\..\lib\silccore" /I "..\..\lib\silcske" /I "..\..\lib\silcmath" /I "..\..\lib\silcmath\mpi" /I "..\..\lib\silcutil" /I "..\..\lib\silccrypt" /I "..\..\lib\silcsim" /I "..\..\lib\trq" /I "..\..\lib\silcsftp" /I "..\..\lib\contrib" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "MP_API_COMPATIBLE" /YX /FD /c\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LIB32=link.exe -lib\r
+# ADD BASE LIB32 /nologo\r
+# ADD LIB32 /nologo\r
+\r
+!ELSEIF  "$(CFG)" == "libsilc_static - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "Debug"\r
+# PROP BASE Intermediate_Dir "Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "Debug"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c\r
+# ADD CPP /nologo /W2 /Gm /GX /ZI /Od /I ".\\" /I "..\\" /I "..\..\\" /I "..\..\includes" /I "..\..\lib\silccore" /I "..\..\lib\silcske" /I "..\..\lib\silcmath" /I "..\..\lib\silcmath\mpi" /I "..\..\lib\silcutil" /I "..\..\lib\silccrypt" /I "..\..\lib\silcsim" /I "..\..\lib\trq" /I "..\..\lib\silcsftp" /I "..\..\lib\contrib" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "MP_API_COMPATIBLE" /YX /FD /GZ /c\r
+# SUBTRACT CPP /WX\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LIB32=link.exe -lib\r
+# ADD BASE LIB32 /nologo\r
+# ADD LIB32 /nologo\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "libsilc_static - Win32 Release"\r
+# Name "libsilc_static - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Group "silccore"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccore\silcargument.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccore\silcattrs.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccore\silcauth.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccore\silcchannel.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccore\silccommand.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccore\silcid.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccore\silcidcache.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccore\silcmessage.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccore\silcnotify.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccore\silcpacket.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "silcske"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcske\groups.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcske\payload.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcske\silcske.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "silcutil"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\silcapputil.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\silcbuffmt.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\silcconfig.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\silchashtable.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\silclog.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\silcmemory.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\silcnet.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\silcprotocol.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\silcschedule.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\silcsockconn.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\silcstrutil.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\silcutil.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\silcvcard.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\win32\silcwin32mutex.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\win32\silcwin32net.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\win32\silcwin32schedule.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\win32\silcwin32sockconn.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\win32\silcwin32thread.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\win32\silcwin32util.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "silcmath"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Group "mpi"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcmath\mpi\mpi.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcmath\mpi\mplogic.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcmath\mpi\mpmontg.c\r
+# End Source File\r
+# End Group\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcmath\modinv.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcmath\mp_mpi.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcmath\mpbin.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcmath\silcprimegen.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "silccrypt"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\aes.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\blowfish.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\cast.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\md5.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\none.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\pkcs1.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\rc5.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\rc6.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\rsa.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\sha1.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\silccipher.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\silchash.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\silchmac.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\silcpkcs.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\silcrng.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\twofish.c\r
+# End Source File\r
+# End Group\r
+# Begin Group "silcsftp No. 1"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcsftp\sftp_client.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcsftp\sftp_fs_memory.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcsftp\sftp_server.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcsftp\sftp_util.c\r
+# End Source File\r
+# End Group\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Group "silccore No. 1"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccore\silcargument.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccore\silcattrs.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccore\silcauth.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccore\silcchannel.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccore\silccommand.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccore\silcid.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccore\silcidcache.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccore\silcmessage.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccore\silcmode.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccore\silcnotify.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccore\silcprivate.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "silcske No. 1"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcske\groups.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcske\groups_internal.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcske\payload.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcske\silcske.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcske\silcske_status.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "silcutil No. 1"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\silcapputil.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\silcbuffer.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\silcbuffmt.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\silcbufutil.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\silcconfig.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\silcdlist.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\silcfileutil.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\silchashtable.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\silclist.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\silclog.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\silcmemory.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\silcmutex.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\silcnet.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\silcprotocol.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\silcschedule.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\silcschedule_i.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\silcsockconn.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\silcthread.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\silctypes.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\silcutil.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcutil\silcvcard.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "silcmath No. 1"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Group "mpi No. 1"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcmath\mpi\logtab.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcmath\mpi\montmulf.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE="..\..\lib\silcmath\mpi\mpi-config.h"\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE="..\..\lib\silcmath\mpi\mpi-priv.h"\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcmath\mpi\mpi.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcmath\mpi\mplogic.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcmath\mpi\mpprime.h\r
+# End Source File\r
+# End Group\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcmath\mp_mpi.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcmath\silcmath.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcmath\silcmp.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "silccrypt No. 1"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\aes.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\blowfish.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\blowfish_internal.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\cast.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\cast_internal.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\ciphers.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\ciphers_def.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\md5.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\md5_internal.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\none.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\pkcs1.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\rc5.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\rc5_internal.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\rc6.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\rc6_internal.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\rijndael_internal.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\rsa.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\rsa_internal.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\sha1.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\sha1_internal.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\silccipher.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\silcdh.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\silchash.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\silchmac.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\silcpkcs.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\silcrng.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\twofish.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silccrypt\twofish_internal.h\r
+# End Source File\r
+# End Group\r
+# Begin Group "silcsftp"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcsftp\sftp_util.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcsftp\silcsftp.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcsftp\silcsftp_fs.h\r
+# End Source File\r
+# End Group\r
+# End Group\r
+# End Target\r
+# End Project\r
index 942639fd25d8c52b8e381b706ec2e882db4d3fc5..b9c751bda1bc42cc05d87e2c4ac4611937269eea 100644 (file)
 ; compatiblity. -Pekka\r
 ;\r
 EXPORTS\r
-       silc_ske_check_version @ 1 ; \r
-       silc_client_add_channel_private_key @ 2 ; \r
-       silc_client_add_connection @ 3 ; \r
-       silc_client_add_private_message_key @ 4 ; \r
-       silc_client_add_private_message_key_ske @ 5 ; \r
-       silc_client_add_socket @ 6 ; \r
-       silc_client_alloc @ 7 ; \r
-       silc_client_channel_message @ 8 ; \r
-       silc_client_close_connection @ 9 ; \r
-       silc_client_command_alloc @ 10 ; \r
-       silc_client_command_ban @ 11 ; \r
-       silc_client_command_close @ 12 ; \r
-       silc_client_command_cmode @ 13 ; \r
-       silc_client_command_connect @ 14 ; \r
-       silc_client_command_cumode @ 15 ; \r
-       silc_client_command_dup @ 16 ; \r
-       silc_client_command_find @ 17 ; \r
-       silc_client_command_free @ 18 ; \r
-       silc_client_command_get_channel_by_id_callback @ 19 ; \r
-       silc_client_command_get_client_by_id_callback @ 20 ; \r
-       silc_client_command_get_client_callback @ 21 ; \r
-       silc_client_command_get_clients_list_callback @ 22 ; \r
-       silc_client_command_getkey @ 23 ; \r
-       silc_client_command_identify @ 24 ; \r
-       silc_client_command_info @ 25 ; \r
-       silc_client_command_invite @ 26 ; \r
-       silc_client_command_join @ 27 ; \r
-       silc_client_command_kick @ 28 ; \r
-       silc_client_command_kill @ 29 ; \r
-       silc_client_command_leave @ 30 ; \r
-       silc_client_command_list @ 31 ; \r
-       silc_client_command_motd @ 32 ; \r
-       silc_client_command_nick @ 33 ; \r
-       silc_client_command_oper @ 34 ; \r
-       silc_client_command_pending @ 35 ; \r
-       silc_client_command_pending_check @ 36 ; \r
-       silc_client_command_pending_del @ 37 ; \r
-       silc_client_command_ping @ 38 ; \r
-       silc_client_command_quit @ 39 ; \r
-       silc_client_command_reply_ban @ 40 ; \r
-       silc_client_command_reply_close @ 41 ; \r
-       silc_client_command_reply_cmode @ 42 ; \r
-       silc_client_command_reply_connect @ 43 ; \r
-       silc_client_command_reply_cumode @ 44 ; \r
-       silc_client_command_reply_free @ 45 ; \r
-       silc_client_command_reply_getkey @ 46 ; \r
-       silc_client_command_reply_identify @ 47 ; \r
-       silc_client_command_reply_info @ 48 ; \r
-       silc_client_command_reply_invite @ 49 ; \r
-       silc_client_command_reply_join @ 50 ; \r
-       silc_client_command_reply_kick @ 51 ; \r
-       silc_client_command_reply_kill @ 52 ; \r
-       silc_client_command_reply_leave @ 53 ; \r
-       silc_client_command_reply_list @ 54 ; \r
-       silc_client_command_reply_motd @ 55 ; \r
-       silc_client_command_reply_nick @ 56 ; \r
-       silc_client_command_reply_oper @ 57 ; \r
-       silc_client_command_reply_ping @ 58 ; \r
-       silc_client_command_reply_process @ 59 ; \r
-       silc_client_command_reply_shutdown @ 60 ; \r
-       silc_client_command_reply_silcoper @ 61 ; \r
-       silc_client_command_reply_topic @ 62 ; \r
-       silc_client_command_reply_umode @ 63 ; \r
-       silc_client_command_reply_users @ 64 ; \r
-       silc_client_command_reply_whois @ 65 ; \r
-       silc_client_command_reply_whowas @ 66 ; \r
-       silc_client_command_shutdown @ 67 ; \r
-       silc_client_command_silcoper @ 68 ; \r
-       silc_client_command_topic @ 70 ; \r
-       silc_client_command_umode @ 71 ; \r
-       silc_client_command_users @ 72 ; \r
-       silc_client_command_whois @ 73 ; \r
-       silc_client_command_whowas @ 74 ; \r
-       silc_client_connect_to_server @ 75 ; \r
-       silc_client_del_channel @ 76 ; \r
-       silc_client_del_channel_private_key @ 77 ; \r
-       silc_client_del_channel_private_keys @ 78 ; \r
-       silc_client_del_client @ 79 ; \r
-       silc_client_del_client_entry @ 80 ; \r
-       silc_client_del_connection @ 81 ; \r
-       silc_client_del_private_message_key @ 82 ; \r
-       silc_client_del_server @ 83 ; \r
-       silc_client_del_socket @ 84 ; \r
-       silc_client_disconnected_by_server @ 85 ; \r
-       silc_client_error_by_server @ 86 ; \r
-       silc_client_free @ 87 ; \r
-       silc_client_free_channel_private_keys @ 88 ; \r
-       silc_client_free_private_message_keys @ 89 ; \r
-       silc_client_get_channel @ 90 ; \r
-       silc_client_get_channel_by_id @ 91 ; \r
-       silc_client_get_channel_by_id_resolve @ 92 ; \r
-       silc_client_get_client_by_id @ 93 ; \r
-       silc_client_get_client_by_id_resolve @ 94 ; \r
-       silc_client_get_clients @ 95 ; \r
-       silc_client_get_clients_by_list @ 96 ; \r
-       silc_client_get_clients_local @ 97 ; \r
-       silc_client_get_server @ 98 ; \r
-       silc_client_get_server_by_id @ 99 ; \r
-       silc_client_init @ 100 ; \r
-       silc_client_key_agreement @ 101 ; \r
-       silc_client_list_channel_private_keys @ 102 ; \r
-       silc_client_list_private_message_keys @ 103 ; \r
-       silc_client_notify_by_server @ 105 ; \r
-       silc_client_packet_process @ 106 ; \r
-       silc_client_packet_send @ 107 ; \r
-       silc_client_packet_send_real @ 108 ; \r
-       silc_client_perform_key_agreement @ 109 ; \r
-       silc_client_perform_key_agreement_fd @ 110 ; \r
-       silc_client_private_message @ 111 ; \r
-       silc_client_private_message_key @ 112 ; \r
-       silc_client_process_failure @ 113 ; \r
-       silc_client_protocol_ke_send_packet @ 114 ; \r
-       silc_client_protocol_ke_set_keys @ 115 ; \r
-       silc_client_protocol_ke_verify_key @ 116 ; \r
-       silc_client_protocols_register @ 117 ; \r
-       silc_client_protocols_unregister @ 118 ; \r
-       silc_client_receive_channel_key @ 119 ; \r
-       silc_client_receive_new_id @ 120 ; \r
-       silc_client_remove_from_channels @ 121 ; \r
-       silc_client_replace_from_channels @ 122 ; \r
-       silc_client_run @ 123 ; \r
-       silc_client_save_channel_key @ 124 ; \r
-       silc_client_send_channel_message @ 125 ; \r
-       silc_client_command_send @ 126 ; \r
-       silc_client_send_key_agreement @ 127 ; \r
-       silc_client_send_private_message @ 128 ; \r
-       silc_client_send_private_message_key @ 129 ; \r
-       silc_client_start_key_exchange @ 131 ; \r
-       silc_client_stop @ 132 ; \r
-       silc_idlist_get_client @ 137 ; \r
-       silc_client_abort_key_agreement @ 138 ; \r
-       silc_client_set_away_message @ 139 ; \r
-       silc_client_request_authentication_method @ 140 ; \r
+       silc_ske_check_version @ 1 ;\r
+       silc_client_add_channel_private_key @ 2 ;\r
+       silc_client_add_connection @ 3 ;\r
+       silc_client_add_private_message_key @ 4 ;\r
+       silc_client_add_private_message_key_ske @ 5 ;\r
+       silc_client_add_socket @ 6 ;\r
+       silc_client_alloc @ 7 ;\r
+       silc_client_channel_message @ 8 ;\r
+       silc_client_close_connection @ 9 ;\r
+       silc_client_command_alloc @ 10 ;\r
+       silc_client_command_ban @ 11 ;\r
+       silc_client_command_close @ 12 ;\r
+       silc_client_command_cmode @ 13 ;\r
+       silc_client_command_connect @ 14 ;\r
+       silc_client_command_cumode @ 15 ;\r
+       silc_client_command_dup @ 16 ;\r
+       silc_client_command_find @ 17 ;\r
+       silc_client_command_free @ 18 ;\r
+       silc_client_command_get_channel_by_id_callback @ 19 ;\r
+       silc_client_command_get_client_by_id_callback @ 20 ;\r
+       silc_client_command_get_client_callback @ 21 ;\r
+       silc_client_command_get_clients_list_callback @ 22 ;\r
+       silc_client_command_getkey @ 23 ;\r
+       silc_client_command_identify @ 24 ;\r
+       silc_client_command_info @ 25 ;\r
+       silc_client_command_invite @ 26 ;\r
+       silc_client_command_join @ 27 ;\r
+       silc_client_command_kick @ 28 ;\r
+       silc_client_command_kill @ 29 ;\r
+       silc_client_command_leave @ 30 ;\r
+       silc_client_command_list @ 31 ;\r
+       silc_client_command_motd @ 32 ;\r
+       silc_client_command_nick @ 33 ;\r
+       silc_client_command_oper @ 34 ;\r
+       silc_client_command_pending @ 35 ;\r
+       silc_client_command_pending_check @ 36 ;\r
+       silc_client_command_pending_del @ 37 ;\r
+       silc_client_command_ping @ 38 ;\r
+       silc_client_command_quit @ 39 ;\r
+       silc_client_command_reply_ban @ 40 ;\r
+       silc_client_command_reply_close @ 41 ;\r
+       silc_client_command_reply_cmode @ 42 ;\r
+       silc_client_command_reply_connect @ 43 ;\r
+       silc_client_command_reply_cumode @ 44 ;\r
+       silc_client_command_reply_free @ 45 ;\r
+       silc_client_command_reply_getkey @ 46 ;\r
+       silc_client_command_reply_identify @ 47 ;\r
+       silc_client_command_reply_info @ 48 ;\r
+       silc_client_command_reply_invite @ 49 ;\r
+       silc_client_command_reply_join @ 50 ;\r
+       silc_client_command_reply_kick @ 51 ;\r
+       silc_client_command_reply_kill @ 52 ;\r
+       silc_client_command_reply_leave @ 53 ;\r
+       silc_client_command_reply_list @ 54 ;\r
+       silc_client_command_reply_motd @ 55 ;\r
+       silc_client_command_reply_nick @ 56 ;\r
+       silc_client_command_reply_oper @ 57 ;\r
+       silc_client_command_reply_ping @ 58 ;\r
+       silc_client_command_reply_process @ 59 ;\r
+       silc_client_command_reply_shutdown @ 60 ;\r
+       silc_client_command_reply_silcoper @ 61 ;\r
+       silc_client_command_reply_topic @ 62 ;\r
+       silc_client_command_reply_umode @ 63 ;\r
+       silc_client_command_reply_users @ 64 ;\r
+       silc_client_command_reply_whois @ 65 ;\r
+       silc_client_command_reply_whowas @ 66 ;\r
+       silc_client_command_shutdown @ 67 ;\r
+       silc_client_command_silcoper @ 68 ;\r
+       silc_client_command_topic @ 70 ;\r
+       silc_client_command_umode @ 71 ;\r
+       silc_client_command_users @ 72 ;\r
+       silc_client_command_whois @ 73 ;\r
+       silc_client_command_whowas @ 74 ;\r
+       silc_client_connect_to_server @ 75 ;\r
+       silc_client_del_channel @ 76 ;\r
+       silc_client_del_channel_private_key @ 77 ;\r
+       silc_client_del_channel_private_keys @ 78 ;\r
+       silc_client_del_client @ 79 ;\r
+       silc_client_del_client_entry @ 80 ;\r
+       silc_client_del_connection @ 81 ;\r
+       silc_client_del_private_message_key @ 82 ;\r
+       silc_client_del_server @ 83 ;\r
+       silc_client_del_socket @ 84 ;\r
+       silc_client_disconnected_by_server @ 85 ;\r
+       silc_client_error_by_server @ 86 ;\r
+       silc_client_free @ 87 ;\r
+       silc_client_free_channel_private_keys @ 88 ;\r
+       silc_client_free_private_message_keys @ 89 ;\r
+       silc_client_get_channel @ 90 ;\r
+       silc_client_get_channel_by_id @ 91 ;\r
+       silc_client_get_channel_by_id_resolve @ 92 ;\r
+       silc_client_get_client_by_id @ 93 ;\r
+       silc_client_get_client_by_id_resolve @ 94 ;\r
+       silc_client_get_clients @ 95 ;\r
+       silc_client_get_clients_by_list @ 96 ;\r
+       silc_client_get_clients_local @ 97 ;\r
+       silc_client_get_server @ 98 ;\r
+       silc_client_get_server_by_id @ 99 ;\r
+       silc_client_init @ 100 ;\r
+       silc_client_key_agreement @ 101 ;\r
+       silc_client_list_channel_private_keys @ 102 ;\r
+       silc_client_list_private_message_keys @ 103 ;\r
+       silc_client_notify_by_server @ 105 ;\r
+       silc_client_packet_process @ 106 ;\r
+       silc_client_packet_send @ 107 ;\r
+       silc_client_packet_send_real @ 108 ;\r
+       silc_client_perform_key_agreement @ 109 ;\r
+       silc_client_perform_key_agreement_fd @ 110 ;\r
+       silc_client_private_message @ 111 ;\r
+       silc_client_private_message_key @ 112 ;\r
+       silc_client_process_failure @ 113 ;\r
+       silc_client_protocol_ke_send_packet @ 114 ;\r
+       silc_client_protocol_ke_set_keys @ 115 ;\r
+       silc_client_protocol_ke_verify_key @ 116 ;\r
+       silc_client_protocols_register @ 117 ;\r
+       silc_client_protocols_unregister @ 118 ;\r
+       silc_client_receive_channel_key @ 119 ;\r
+       silc_client_receive_new_id @ 120 ;\r
+       silc_client_remove_from_channels @ 121 ;\r
+       silc_client_replace_from_channels @ 122 ;\r
+       silc_client_run @ 123 ;\r
+       silc_client_save_channel_key @ 124 ;\r
+       silc_client_send_channel_message @ 125 ;\r
+       silc_client_command_send @ 126 ;\r
+       silc_client_send_key_agreement @ 127 ;\r
+       silc_client_send_private_message @ 128 ;\r
+       silc_client_send_private_message_key @ 129 ;\r
+       silc_client_start_key_exchange @ 131 ;\r
+       silc_client_stop @ 132 ;\r
+       silc_idlist_get_client @ 137 ;\r
+       silc_client_abort_key_agreement @ 138 ;\r
+       silc_client_set_away_message @ 139 ;\r
+       silc_client_request_authentication_method @ 140 ;\r
        silc_client_file_send @ 141 ;\r
        silc_client_file_receive @ 142 ;\r
        silc_client_file_close @ 143 ;\r
@@ -164,3 +164,5 @@ EXPORTS
         silc_client_attribute_del @ 154 ;\r
         silc_client_attributes_get @ 155 ;\r
         silc_client_attributes_request @ 156 ;\r
+       silc_client_get_channel_resolve @ 157 ;\r
+       silc_client_get_clients_by_channel @ 158 ;\r
diff --git a/win32/libsilcclient_static/libsilcclient_static.dsp b/win32/libsilcclient_static/libsilcclient_static.dsp
new file mode 100644 (file)
index 0000000..55f6bb3
--- /dev/null
@@ -0,0 +1,176 @@
+# Microsoft Developer Studio Project File - Name="libsilcclient_static" - Package Owner=<4>\r
+# Microsoft Developer Studio Generated Build File, Format Version 6.00\r
+# ** DO NOT EDIT **\r
+\r
+# TARGTYPE "Win32 (x86) Static Library" 0x0104\r
+\r
+CFG=libsilcclient_static - Win32 Debug\r
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r
+!MESSAGE use the Export Makefile command and run\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "libsilcclient_static.mak".\r
+!MESSAGE \r
+!MESSAGE You can specify a configuration when running NMAKE\r
+!MESSAGE by defining the macro CFG on the command line. For example:\r
+!MESSAGE \r
+!MESSAGE NMAKE /f "libsilcclient_static.mak" CFG="libsilcclient_static - Win32 Debug"\r
+!MESSAGE \r
+!MESSAGE Possible choices for configuration are:\r
+!MESSAGE \r
+!MESSAGE "libsilcclient_static - Win32 Release" (based on "Win32 (x86) Static Library")\r
+!MESSAGE "libsilcclient_static - Win32 Debug" (based on "Win32 (x86) Static Library")\r
+!MESSAGE \r
+\r
+# Begin Project\r
+# PROP AllowPerConfigDependencies 0\r
+# PROP Scc_ProjName "Perforce Project"\r
+# PROP Scc_LocalPath "..\.."\r
+CPP=cl.exe\r
+RSC=rc.exe\r
+\r
+!IF  "$(CFG)" == "libsilcclient_static - Win32 Release"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 0\r
+# PROP BASE Output_Dir "Release"\r
+# PROP BASE Intermediate_Dir "Release"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 0\r
+# PROP Output_Dir "Release"\r
+# PROP Intermediate_Dir "Release"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c\r
+# ADD CPP /nologo /W2 /GX /O2 /I ".\\" /I "..\\" /I "..\..\\" /I "..\..\includes" /I "..\..\lib\silccore" /I "..\..\lib\silcske" /I "..\..\lib\silcmath" /I "..\..\lib\silcmath\mpi" /I "..\..\lib\silcutil" /I "..\..\lib\silccrypt" /I "..\..\lib\silcsim" /I "..\..\lib\trq" /I "..\..\lib\silcclient" /I "..\..\lib\silcsftp" /I "..\..\lib\contrib" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "MP_API_COMPATIBLE" /YX /FD /c\r
+# ADD BASE RSC /l 0x409 /d "NDEBUG"\r
+# ADD RSC /l 0x409 /d "NDEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LIB32=link.exe -lib\r
+# ADD BASE LIB32 /nologo\r
+# ADD LIB32 /nologo\r
+\r
+!ELSEIF  "$(CFG)" == "libsilcclient_static - Win32 Debug"\r
+\r
+# PROP BASE Use_MFC 0\r
+# PROP BASE Use_Debug_Libraries 1\r
+# PROP BASE Output_Dir "libsilcclient_static___Win32_Debug"\r
+# PROP BASE Intermediate_Dir "libsilcclient_static___Win32_Debug"\r
+# PROP BASE Target_Dir ""\r
+# PROP Use_MFC 0\r
+# PROP Use_Debug_Libraries 1\r
+# PROP Output_Dir "Debug"\r
+# PROP Intermediate_Dir "Debug"\r
+# PROP Target_Dir ""\r
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c\r
+# ADD CPP /nologo /W2 /Gm /GX /ZI /Od /I ".\\" /I "..\\" /I "..\..\\" /I "..\..\includes" /I "..\..\lib\silccore" /I "..\..\lib\silcske" /I "..\..\lib\silcmath" /I "..\..\lib\silcmath\mpi" /I "..\..\lib\silcutil" /I "..\..\lib\silccrypt" /I "..\..\lib\silcsim" /I "..\..\lib\trq" /I "..\..\lib\silcclient" /I "..\..\lib\silcsftp" /I "..\..\lib\contrib" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D "MP_API_COMPATIBLE" /YX /FD /GZ /c\r
+# ADD BASE RSC /l 0x409 /d "_DEBUG"\r
+# ADD RSC /l 0x409 /d "_DEBUG"\r
+BSC32=bscmake.exe\r
+# ADD BASE BSC32 /nologo\r
+# ADD BSC32 /nologo\r
+LIB32=link.exe -lib\r
+# ADD BASE LIB32 /nologo\r
+# ADD LIB32 /nologo\r
+\r
+!ENDIF \r
+\r
+# Begin Target\r
+\r
+# Name "libsilcclient_static - Win32 Release"\r
+# Name "libsilcclient_static - Win32 Debug"\r
+# Begin Group "Source Files"\r
+\r
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
+# Begin Group "silcclient"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcclient\client.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcclient\client_attrs.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcclient\client_channel.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcclient\client_ftp.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcclient\client_keyagr.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcclient\client_notify.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcclient\client_prvmsg.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcclient\client_resume.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcclient\command.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcclient\command_reply.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcclient\idlist.c\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcclient\protocol.c\r
+# End Source File\r
+# End Group\r
+# End Group\r
+# Begin Group "Header Files"\r
+\r
+# PROP Default_Filter "h;hpp;hxx;hm;inl"\r
+# Begin Group "silcclient No. 1"\r
+\r
+# PROP Default_Filter ""\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcclient\client.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcclient\client_internal.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcclient\command.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcclient\command_reply.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcclient\idlist.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcclient\protocol.h\r
+# End Source File\r
+# Begin Source File\r
+\r
+SOURCE=..\..\lib\silcclient\silcapi.h\r
+# End Source File\r
+# End Group\r
+# End Group\r
+# End Target\r
+# End Project\r
index a8cbf4ac14ac65caa7803ee57d37dfd8744a2166..d43152db29ff171f99fbc93876ee62bcd9d3528d 100644 (file)
@@ -3,6 +3,30 @@ Microsoft Developer Studio Workspace File, Format Version 6.00
 \r
 ###############################################################################\r
 \r
+Project: "all"=".\all.dsp" - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name libsilc\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name libsilcclient\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name libsilc_static\r
+    End Project Dependency\r
+    Begin Project Dependency\r
+    Project_Dep_Name libsilcclient_static\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
 Project: "libsilc"=".\libsilc\libsilc.dsp" - Package Owner=<4>\r
 \r
 Package=<5>\r
@@ -15,6 +39,18 @@ Package=<4>
 \r
 ###############################################################################\r
 \r
+Project: "libsilc_static"=".\libsilc_static\libsilc_static.dsp" - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+}}}\r
+\r
+###############################################################################\r
+\r
 Project: "libsilcclient"=".\libsilcclient\libsilcclient.dsp" - Package Owner=<4>\r
 \r
 Package=<5>\r
@@ -23,6 +59,24 @@ Package=<5>
 \r
 Package=<4>\r
 {{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name libsilc\r
+    End Project Dependency\r
+}}}\r
+\r
+###############################################################################\r
+\r
+Project: "libsilcclient_static"=".\libsilcclient_static\libsilcclient_static.dsp" - Package Owner=<4>\r
+\r
+Package=<5>\r
+{{{\r
+}}}\r
+\r
+Package=<4>\r
+{{{\r
+    Begin Project Dependency\r
+    Project_Dep_Name libsilc_static\r
+    End Project Dependency\r
 }}}\r
 \r
 ###############################################################################\r