Moved silc_client_ch[u]mode[_char] to client library from silc/.
authorPekka Riikonen <priikone@silcnet.org>
Wed, 1 Nov 2000 21:44:27 +0000 (21:44 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Wed, 1 Nov 2000 21:44:27 +0000 (21:44 +0000)
NAMES command now shows users modes on joining with nickname

195 files changed:
CHANGES [new file with mode: 0644]
INSTALL
README
README.CVS [new file with mode: 0644]
TODO
acconfig.h
apps/silc/Makefile.am
apps/silc/client.c [deleted file]
apps/silc/client_ops.c [new file with mode: 0644]
apps/silc/client_ops.h [new file with mode: 0644]
apps/silc/clientconfig.c
apps/silc/clientutil.c
apps/silc/clientutil.h
apps/silc/command.c [deleted file]
apps/silc/command_reply.c [deleted file]
apps/silc/local_command.c [new file with mode: 0644]
apps/silc/local_command.h [new file with mode: 0644]
apps/silc/pubkey.pub [deleted file]
apps/silc/screen.c
apps/silc/screen.h
apps/silc/silc.c
apps/silc/silc.h
apps/silc/testi.conf
apps/silcd/Makefile.am
apps/silcd/command.c
apps/silcd/command.h
apps/silcd/command_reply.c
apps/silcd/command_reply.h
apps/silcd/idlist.c
apps/silcd/idlist.h
apps/silcd/protocol.c
apps/silcd/protocol.h
apps/silcd/pubkey.pub [deleted file]
apps/silcd/route.c
apps/silcd/route.h
apps/silcd/server.c
apps/silcd/server.h
apps/silcd/server_internal.h
apps/silcd/server_version.c
apps/silcd/serverconfig.c
apps/silcd/serverconfig.h
apps/silcd/serverid.c
apps/silcd/silc.conf
apps/silcd/silcd.c
apps/silcd/testi.conf [deleted file]
config.guess
config.sub
configure.in
doc/CodingStyle
doc/FAQ
doc/Makefile.am
doc/Makefile.in [deleted file]
doc/development/lib_reference.sgml [new file with mode: 0644]
doc/draft-riikonen-silc-ke-auth-00.nroff
doc/draft-riikonen-silc-ke-auth-01.nroff [new file with mode: 0644]
doc/draft-riikonen-silc-pp-00.nroff
doc/draft-riikonen-silc-pp-01.nroff [new file with mode: 0644]
doc/draft-riikonen-silc-spec-00.nroff
doc/draft-riikonen-silc-spec-01.nroff [new file with mode: 0644]
doc/example_silc.conf
doc/example_silcd.conf
includes/Makefile.in [deleted file]
includes/clientincludes.h
includes/clientlibincludes.h [moved from lib/silccrypt/e2_internal.h with 62% similarity]
includes/serverincludes.h
includes/silcdefs.h.in [deleted file]
includes/silcincludes.h
includes/version.h
lib/Makefile.am
lib/contrib/Makefile.am [new file with mode: 0644]
lib/contrib/getopt.c [new file with mode: 0644]
lib/contrib/getopt.h [new file with mode: 0644]
lib/contrib/getopt1.c [new file with mode: 0644]
lib/silcclient/Makefile.am [new file with mode: 0644]
lib/silcclient/README [new file with mode: 0644]
lib/silcclient/client.c [new file with mode: 0644]
lib/silcclient/client.h [moved from apps/silc/client.h with 55% similarity]
lib/silcclient/command.c [new file with mode: 0644]
lib/silcclient/command.h [moved from apps/silc/command.h with 92% similarity]
lib/silcclient/command_reply.c [new file with mode: 0644]
lib/silcclient/command_reply.h [moved from apps/silc/command_reply.h with 95% similarity]
lib/silcclient/idlist.c [new file with mode: 0644]
lib/silcclient/idlist.h [moved from apps/silc/idlist.h with 67% similarity]
lib/silcclient/ops.h [new file with mode: 0644]
lib/silcclient/protocol.c [moved from apps/silc/protocol.c with 64% similarity]
lib/silcclient/protocol.h [moved from apps/silc/protocol.h with 72% similarity]
lib/silccore/Makefile.am
lib/silccore/id.c
lib/silccore/id.h
lib/silccore/idcache.c
lib/silccore/idcache.h
lib/silccore/silcchannel.c
lib/silccore/silcchannel.h
lib/silccore/silccommand.c
lib/silccore/silccommand.h
lib/silccore/silcnotify.c [new file with mode: 0644]
lib/silccore/silcnotify.h [new file with mode: 0644]
lib/silccore/silcpacket.c
lib/silccore/silcpacket.h
lib/silccore/silcpayload.c [new file with mode: 0644]
lib/silccore/silcpayload.h [new file with mode: 0644]
lib/silccore/silcprotocol.c
lib/silccore/silcprotocol.h
lib/silccore/silcsockconn.c
lib/silccore/silcsockconn.h
lib/silccore/silcutil.c [deleted file]
lib/silccrypt/Makefile.am
lib/silccrypt/blowfish.h
lib/silccrypt/cast.h
lib/silccrypt/ciphers.h
lib/silccrypt/crypton.c [deleted file]
lib/silccrypt/crypton.h [deleted file]
lib/silccrypt/crypton_internal.h [deleted file]
lib/silccrypt/dfc.c [deleted file]
lib/silccrypt/dfc.h [deleted file]
lib/silccrypt/e2.c [deleted file]
lib/silccrypt/e2.h [deleted file]
lib/silccrypt/loki.c [deleted file]
lib/silccrypt/loki.h [deleted file]
lib/silccrypt/loki_internal.h [deleted file]
lib/silccrypt/mars.h
lib/silccrypt/md5.h
lib/silccrypt/none.c
lib/silccrypt/none.h
lib/silccrypt/rc5.h
lib/silccrypt/rc6.h
lib/silccrypt/rijndael.c
lib/silccrypt/rijndael.h
lib/silccrypt/rsa.c
lib/silccrypt/safer.c [deleted file]
lib/silccrypt/safer.h [deleted file]
lib/silccrypt/safer_internal.h [deleted file]
lib/silccrypt/serpent.c [deleted file]
lib/silccrypt/serpent.h [deleted file]
lib/silccrypt/serpent_internal.h [deleted file]
lib/silccrypt/sha1.c
lib/silccrypt/sha1.h
lib/silccrypt/silccipher.c
lib/silccrypt/silchash.c
lib/silccrypt/silchash.h
lib/silccrypt/silchmac.c
lib/silccrypt/silcpkcs.c
lib/silccrypt/silcpkcs.h
lib/silccrypt/silcrng.c
lib/silccrypt/silcrng.h
lib/silccrypt/twofish.h
lib/silcmath/Makefile.am
lib/silcmath/mpbin.c [new file with mode: 0644]
lib/silcmath/mpbin.h [moved from lib/silccrypt/dfc_internal.h with 55% similarity]
lib/silcmath/silcprimegen.c
lib/silcsim/Makefile.am
lib/silcsim/modules/Makefile.in [deleted file]
lib/silcsim/silcsim.c
lib/silcske/Makefile.am
lib/silcske/groups.c
lib/silcske/payload.c
lib/silcske/payload_internal.h
lib/silcske/silcske.c
lib/silcske/silcske.h
lib/silcske/silcske_status.h
lib/silcutil/Makefile.am [new file with mode: 0644]
lib/silcutil/silcbuffer.c [moved from lib/silccore/silcbuffer.c with 79% similarity]
lib/silcutil/silcbuffer.h [moved from lib/silccore/silcbuffer.h with 93% similarity]
lib/silcutil/silcbuffmt.c [moved from lib/silccore/silcbuffmt.c with 96% similarity]
lib/silcutil/silcbuffmt.h [moved from lib/silccore/silcbuffmt.h with 99% similarity]
lib/silcutil/silcbufutil.c [moved from lib/silccore/silcbufutil.c with 63% similarity]
lib/silcutil/silcbufutil.h [moved from lib/silccore/silcbufutil.h with 72% similarity]
lib/silcutil/silcconfig.c [moved from lib/silccore/silcconfig.c with 85% similarity]
lib/silcutil/silcconfig.h [moved from lib/silccore/silcconfig.h with 100% similarity]
lib/silcutil/silclog.c [moved from lib/silccore/silclog.c with 67% similarity]
lib/silcutil/silclog.h [moved from lib/silccore/silclog.h with 76% similarity]
lib/silcutil/silcmemory.c [moved from lib/silccore/silcmemory.c with 58% similarity]
lib/silcutil/silcmemory.h [moved from lib/silccore/silcmemory.h with 100% similarity]
lib/silcutil/silcnet.c [moved from lib/silccore/silcnet.c with 88% similarity]
lib/silcutil/silcnet.h [moved from lib/silccore/silcnet.h with 97% similarity]
lib/silcutil/silcschedule.c [moved from lib/silccore/silcschedule.c with 83% similarity]
lib/silcutil/silcschedule.h [moved from lib/silccore/silcschedule.h with 96% similarity]
lib/silcutil/silctask.c [moved from lib/silccore/silctask.c with 97% similarity]
lib/silcutil/silctask.h [moved from lib/silccore/silctask.h with 100% similarity]
lib/silcutil/silcutil.c [new file with mode: 0644]
lib/silcutil/silcutil.h [moved from lib/silccore/silcutil.h with 60% similarity]
prepare
prepare-clean
public_html/about.html
public_html/contribute.html [new file with mode: 0644]
public_html/copying.html
public_html/docs.html [new file with mode: 0644]
public_html/docs/CodingStyle [new file with mode: 0644]
public_html/download.html [new file with mode: 0644]
public_html/faq.html [new file with mode: 0644]
public_html/features.html
public_html/history.html
public_html/index.html
public_html/press.html [new file with mode: 0644]
public_html/todo.html [new file with mode: 0644]

diff --git a/CHANGES b/CHANGES
new file mode 100644 (file)
index 0000000..bfec5a9
--- /dev/null
+++ b/CHANGES
@@ -0,0 +1,622 @@
+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 
+         silc/clientutil.[ch] to lib/silcclient/client.[ch].  Though, that
+         place sucks, they are utility functions and should be in some
+         other file.
+
+       * Fixed some unsigned int's to unsigned short's.  Patch by cras.
+
+       * Fixed contrib/getopt*.[ch] to not require config.h.  Patch by
+         cras.
+
+Tue Oct 31 20:10:37 EET 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Updated README.
+
+       * Added TRQ (efficient deque and list library) into lib/trq.  This is
+         a very good list library that is currently used in the SILC.  Defined
+         SilcList API over the library because I didn't like the API very
+         much.  See lib/trq/silclist.h for the API and examples of how to
+         use the API.  Fixed various places in the code to use the new
+         SilcList API. The SilcList is meant for lists that has a structure
+         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 
+         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
+         are a lot places where this can replace dynamically allocated
+         tables and I will fix these places, later, to use SilcDList.
+         See lib/trq/silcdlist.h for SilcDList (they are all inline functions,
+         and use TRQ internally).
+
+         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 
+         IDENTIFY commands into server, as required by the protocol.
+
+       * Removed method function pointers from SilcBuffer structure. They
+         weren't used to anything and just increased the context size for
+         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 
+         that it accepts commands in but does not execute them more than once
+         in two seconds.
+
+       * Added silc_net_localhost(), to return local hostname, into
+         lib/silcutil/silcnet.[ch].  Also added client->hostname pointer
+         that must be initialized before calling silc_client_init.
+
+       * Added new function: silc_server_send_notify_on_channels to send
+         notify messages to all channels client has joined.  It is assured
+         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 
+         function is generic and is used by server as well, not only by
+         the logging routines.
+
+       * Added new SKE status type: SILC_SKE_STATUS_BAD_VERSION to indicate
+         the provided version string was not acceptable.  Added new function:
+         silc_ske_check_version into lib/silcske/silcske.h.  The function
+         must be implemented by the application (client or server) and it
+         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) 
+         into SilcPacketContext structure into lib/silccore/silcpacket.h.
+
+       * Added silc_packet_context_dup into lib/silccore/silcpacket.[ch] to
+         duplicate packet context structure.
+
+       * Changed `notify' client operation to send same arguments as client
+         receives from server except for ID's.  ID's are mapped to correct
+         ID entry and that is returned.  Also, if channel entry is not sent
+         by server but the notify is for channel the channel entry is sent
+         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 
+         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 
+         lib/silcclient/idlist.c.  Also, added silc_idlist_get_client_by_id
+         to get (or query) client by ID.
+
+       * Updated TODO list.
+
+       * Added connection authentication status message defined by the
+         protocol: SILC_CONN_AUTH_OK and SILC_CONN_AUTH_FAILED and added the
+         support for these into the code in client and server side.
+
+       * Added generic function silc_client_send_command to send any command
+         with variable argument list.  Application should use this function
+         to send commands if the command functions provided by the library
+         does not suite for the application's user interface needs.
+
+       * Added new `failure' client operation.  Application is notified about
+         received failure packet if client is executing a protocol.  In this
+         case the protocol's execution has failed.
+
+       * Added SKE's end notify to send the SKE_SUCCESS notify message that
+         is required by the protocol.
+
+       * Added SILC_PROTOCOL_STATE_FAILURE to indicate received failure
+         packet from remote.  SILC_PROTOCOL_STATE_ERROR indicates local
+         error at our end.
+
+       * Added status flag to SilcSKE object to indicate realtime status
+         of the SKE protocol.
+
+       * Application receives now exactly same command reply arguments as
+         the library receives from server.  However, if ID is received the
+         corresponding ID entry is returned to the application (eg. Client
+         ID is mapped to correct SilcClientEntry entry and that is returned).
+         Changed command_reply client operation due to this change.
+
+       * Changed all ID's in commands and in command replys as ID Payloads.
+         Change affected both client and server side codes.
+
+         All ID's sent in SILC network (with execption of ID's in SILC
+         Packet header) are sent in ID Payload to support variable length
+         ID's.
+
+       * Server now notifies nick changes and notifies all clients on
+         the channels about the new nickname (about the new Client ID,
+         actually).
+
+       * Implemented CMODE command to change channel modes. Supports all
+         channel modes defined by the protocol specs except ban and invite
+         lists. (Also, private channel key mode is supported but support for
+         setting private channel key in client is missing, thus, this mode
+         has no effect on client side (except that server requires that the
+         client uses private channel key and normal channel traffic does not
+         work anymore)).
+
+         Also, invite mode works per se, but INVITE command does not work
+         yet correctly, so you can set channel as invite only channel but
+         inviting clients to the channel does not work (it is yet to be
+         thought what's the best way to do it).
+
+       * Added new command SILC_COMMAND_CUMODE to change user mode on the
+         channel.  Defined user modes: CHANNEL_FOUNDER and CHANNEL_OPERATOR.
+         Implemented CUMODE command to change user's mode on the channel.
+         Supports all modes defined by the protocol specs.
+
+       * Added NAMES command reply to return users modes on the channel.
+
+       * Removed unnecessary and slow ciphers from lib/silccrypt.
+
+       * Set SO_KEEPALIVE option to connection sockets by default.
+
+       * Added new command reply status: SILC_STATUS_USER_NOT_ON_CHANNEL.
+
+       * Added notify types: MOTD, CMODE_CHANGE and CUMODE_CHANGE.  Also,
+         redefined the Notify Payload into protocol specs.
+
+       * Added silc_id_payload_parse_id to get ID directly from raw
+         ID payload data.
+
+Mon Oct  9 20:57:02 EEST 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * 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.
+
+       * Added silc_id_payload_parse_data into lib/silccore/silcpayload.[ch]
+         to parse ID Payload from raw data.
+
+Sun Oct  8 19:33:08 EEST 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Added flags parameter into silc_ske_assemble_security_properties
+         function in lib/silcske/silcske.[ch].
+
+       * Changed notify client operation to fit better for notify messages
+         sent by server.  The notify payload received from server is now
+         passed to the application (after parsing it to SilcNotifyPayload).
+         It is application's responsibility to retrieve the arguments
+         from the payload and show the message the way it wants.  The message
+         sent by server is implementation specific.
+
+       * Changed public keys to comply with the protocol specification.
+         Old public keys are not supported anymore and are not compatible.
+
+       * Removed nickname from Channel Payload as the latest draft removed
+         it.  The client must resolve the nickname from the NAMES command
+         reply received when it joined the channel.
+
+         Also, changed all channel_xxxx_payload to channel_payload_xxxx.
+
+Sat Oct  7 21:55:01 EEST 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Fixed some errors in protocol specification drafts.
+
+       * Created lib/silccore/silcnotify.c to implement Notify Payload
+         encoding and decoding, lib/silccore/silcpayload.[ch] to implement
+         generic payloads described by protocol specifications.  The file
+         includes implementations for ID Payload and Argument Payload.
+
+       * Changed Command Payload implementation to use the new Argument
+         Payload.  Changed command_xxxx_payload to command_payload_xxxx
+         to comply with SILC coding conventions.
+
+       * Added suppport for Argument Payload handling in Notify Payload
+         implementation as protocol requires it.  Added the new support
+         into server and client lib as well.
+
+Thu Oct  5 21:16:28 EEST 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Added support for multiple nicknames on same channel.  [n] is
+         added locally to the nickname if there are more than one same
+         nicknames on the channel.
+
+       * Server now sends all nicknames that matched WHOIS request.
+         Client also shows the list received from server.
+
+       * Added TOPIC command to client side.  User can now set and show
+         current topic on channel.
+
+       * Added MOTD command to client and server.  Also, server sends the
+         motd when client connects to the server.
+
+       * Changed version strings to comply ISO 8601.
+
+Wed Oct  4 23:29:06 EEST 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Fixed protocol error handling in client library.  It should now
+         cope even if the SKE fails for some reason.
+
+       * Made new protocol specification drafts for submitting to IETF.
+
+       * Implemented TOPIC command to server in silcd/command.c.
+
+       * Added two new notify types into lib/silccore/silcnotify.h:
+         SILC_NOTIFY_TYPE_NICK_CHANGE and SILC_NOTIFY_TYPE_TOPIC_SET to
+         notify nickname change and topic setting/change on a channel.
+
+       * API change of command_reply operation in client library.  The
+         application gets now the status type received from server as well.
+
+Sat Sep 30 16:57:42 EEST 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Removed the function just added to lib/silcutil/silcschedule.[ch].
+
+       * Cras fixed and optimized the packet handling even further and
+         it should work now.  Minor change to the prototype of function
+         silc_packet_receive_process in lib/silccore/silcpacket.[ch].
+
+Sat Sep 30 08:48:47 EEST 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Added new function into lib/silcutil/silcschedule.[ch]:
+         silc_schedule_with_fd to select() a specified fd.  The function
+         returns after timeout expires or data arrives or goes.  The
+         function is used by packet routines to wait that all data is
+         received from network.
+
+       * Fixed data reading from network in lib/silccore/silcpacket.c.
+         The code now assures that all data is read from the fd and then
+         continues packet processing.  This was a bug fix since the code
+         used to drop some data in some circumstances.
+
+       * Added new function into lib/silcclient/client.[ch]:
+         silc_client_start_key_exchange to start key exchange after
+         connection has been established to server.  The code internally
+         now uses this funtion but its main purpose was to provide it
+         for applications that perform their own connecting.  After
+         application has created a connection it merely calls this
+         function to start the key exchange between client and server.
+         The library takes care of everything else after that.
+
+         Updated also lib/silcclient/README to explain the usage of
+         this new function.
+
+       * Do not send to application information that connection has
+         been established.  Application gets notified it by connect
+         operation anyway.
+
+Thu Sep 28 23:40:19 EEST 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Applied cras's patch to add silc_schedule_one function.  The
+         function runs scheduler once and returns.
+
+       * Fixed the scheduler after cras messed it up.  The timeout
+         handling works now as it's supposed to work.
+
+       * Added into lib/silccore/ silcnotify.h to include notify
+         message types support.  Changed silc_server_send_notify*
+         functions, in server.[ch], to support those new notify types.
+         Added the support for the notify types into client library,
+         as well.  Added new notify client operation into ops.h in
+         lib/silcclient/.
+
+       * Changed silc_server_packet_send_to_channel to send normal
+         packets instead of just channel message packets.  The function
+         is now used to send the notify packets to channels.  It is not
+         used to send channel message packets anymore, as server never
+         sends them anymore.
+
+       * Added explicit casting into lib/silcutil/silcbuffmt.c to few
+         va_arg()s as it seems to require it nowadays.  I guess, if SILC
+         is compiled with older va_arg() the new code should work anyway.
+
+Wed Sep 13 18:10:14 EEST 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Splitted core library.  Core library (lib/silccore) includes
+         now only SILC protocol specific core (and common) components.
+         Created new utility library (lib/silcutil) that includes more
+         generic purpose stuff.  The stuff for util library was taken
+         from the old core library.  This was minor and easy split.
+
+       * Created SILC Client Library (lib/silcclient) that includes
+         implementation of the SILC client without user interface.  This
+         was major move from silc/ directory.  The code has been changed
+         so that it is transparent towards the user interface.  The
+         silc/ directory includes now the same user interface as before
+         and it uses the new client library.  Read lib/silcclient/README.
+         Basicly, the client library performs everything else related
+         to SILC except user interface handling.  Also, configuration
+         files are considered to be part of user interface and library
+         does not handle them.
+
+         This change also changed a lot of structures, function naming etc.
+         Most important change was that SilcClientWindow object was
+         renamed to SilcClientConnection in the client library.  Created
+         also new file lib/silcclient/ops.h.  Also added new files
+         silc/local_command.[ch] and silc/client_ops.[ch].
+
+         All these changes were made to make it easier for user interface
+         designers to create what ever user interface for the SILC client
+         they want.
+
+         It is also expected that the server will be moved to lib
+         directory as well and SILC Server Library will be created;
+         sometimes in the future.
+
+       * Removed Local commands from lib/silccore/silccommand.h as
+         they are application specific and new client library does not
+         handle any of those anymore.
+
+       * Several functions moved to lib/silcutil/silcutilc.[ch] from
+         old client implementation in silc/.
+
+       * Added support for callback functions in SILC_LOG_* macros.
+         Application can now set its own callbacks that will be called
+         instead of using the default functions that will always print
+         the debug messages to stderr (or stdout).  Also, debugging can
+         now be disabled by setting silc_debug to FALSE and re-enabled by
+         setting it to TRUE.  Note, that logging will still work even
+         if debugging is disabled.
+
+         New functions in lib/silcutil/silclog.[ch]: silc_log_set_callbacks,
+         silc_log_reset_callbacks, silc_log_set_debug_callbacks and
+         silc_log_reset_debug_callbacks.
+
+       * To enable debugging in silc client one must give now -d
+         option on command line.
+
+       * Changed silc_schedule_init to automatically allocate task queues
+         if they are not allocated before calling it.
+
+Thu Sep  7 10:49:33 EEST 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Added GMP 3.1 into math library.
+
+Sun Aug 20 21:27:26 EEST 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Added SILC_PACKET_REMOVE_CHANNEL_USER to remove a client from
+         a channel in SILC network.  The packet is used by servers and
+         routers to notify other routers that user has left a channel.
+         This little feature was missing until now.  Added the feature
+         to protocol specification as well.
+
+         Added functions: silc_server_send_remove_channel_user and
+         silc_server_remove_channel_user into server.[ch].
+
+       * Added SILC_PACKET_REKEY and SILC_PACKET_REKEY_DONE into
+         lib/silccore/silcpacket.h.  However, they are not implemented
+         yet.
+
+Sat Aug 19 23:04:16 EEST 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Fixed joining to a channel and sending channel messages
+         between server and router.  The channel message sending should
+         now work inside a cell.
+
+Tue Jul 25 20:46:13 EEST 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Fixed the private message sending between server and router.
+         The private message sending should now work inside a cell.
+
+       * Added silc_server_replace_id into server.[ch] to replace
+         existing ID in the SILC network.
+
+       * Added silc_idlist_find_server_by, silc_idlist_replace_client_id
+         and silc_idlist_replace_server_id into idlist.[ch] in server.
+
+Mon Jul 24 18:33:31 EEST 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Fixed the server to server connections.  Server can again now
+         connect to router.  Router to router connections probably does
+         not work just yet.
+
+Thu Jul 20 13:15:01 EEST 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Added dynamic protocol registering support.  Now protocols can
+         registered and unregistered on the fly.  Patch by cras.
+
+Wed Jul 19 19:08:46 EEST 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Added lib/contrib directory to hold routines that some platforms
+         don't have but are needed by SILC.
+
+       * Added getopt.c, getopt1.c and getopt.h from GNU C library
+         into lin/contrib to provide getopt() and getopt_long() for
+         those who don't have it.
+
+Tue Jul 18 20:41:20 EEST 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Added AWAY command to client.  When away message is set and
+         client receives a private message packet the client automatically
+         replies to the sender with the away message.
+
+       * Fixed a bug in lib/silcmath/mpbin.c: silc_mp_mp2bin.  This
+         bug seemed to be the cause of recent problems when compiling
+         with gcc-2.95.
+
+       * Added version detection support to SKE protocol specification
+         and added the new changes to the SKE implementation as well.
+         There were other minor changes in the SKE protocol as well.
+
+         Many changes in lib/silcske/silcske.[ch] and in
+         lib/silcske/payload.[ch].
+
+       * Added ^U functionality, clear input line.  Patch from cras.
+
+Mon Jul 17 23:33:26 EEST 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Mainly small bugfixes on core library.  Fixed some debugging
+         logging and buffer overflow in silclog.c.
+
+       * Updated config.sub and config.guess on the distribution tree.
+
+Sat Jul 15 15:33:48 EEST 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Added command lagging support in server. Client may execute
+         commands now only once in two seconds.
+
+Thu Jul 13 22:10:21 EEST 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Optimized packet reception. MAC computation and checking is now
+         also more optimized.  A lot previously duplicated code is now
+         used as generic by both client and server.
+
+       * Fixed key pair generation in clientutil.c
+
+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 
+         lib/silccore/silcpacket.[ch] from client and server.  Some
+         rewriting of the functions.
+
+       * Moved all generic packet reception/decryption functions to
+         lib/silccore/silcpacket.[ch] from client and server.  The
+         packet processing is now much cleaner in both client and server.
+         These were major changes in both client and server.
+
+       * Created many common functions in server to do packet sending.
+         Previously code were duplicated a lot, this has been removed
+         with these changes.
+
+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 
+         whether it is better now or not but at least the API is more
+         cleaner now.
+
+       * Major rewrite on ID cache stuff on client because of the ID
+         cache API changes.  Added idlist.c to client.
+
+       * Also major rewrite on ID cache stuff on server as well.
+         Major rewrite of idlist.[ch]. SilcXXXList's are now named
+         SilcXXXEntry's.  We won't keep anymore idlist specific pointers
+         in hand, instead they are all put into the ID cache system now.
+         All server_idlist_* routines uses ID cache now instead of
+         traversing its own lists (those lists does not exist anymore).
+         SilcIDList though still exists.  Also, SilcXXXEntry's are
+         now pointers.
+
+Sun Jul  9 15:19:24 EEST 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Finally made the SKE implementation compliant to the protocol
+         specification.  All mp integers are now binary encoded as
+         opposed being HEX encoded.
+
+       * Added lib/silcmath/mpbin.[ch].  Encoding mp intergers to and
+         from binary data.
+
+       * Added into lib/silccore/silcutil.[ch] PEM encoding/decoding
+         functions: silc_[encode/decode]_pem.  Also added function
+         silc_encode_pem_file to PEM encode with newlines ('\n') for
+         saving into a file.
+
+       * SILC public keys are now encoded either PEM or binary.  Same
+         option is for private keys as well.  By default private keys
+         are binary encoded and public keys PEM encoded.  Silly HEX
+         encoding were removed.
+
+       * Added into lib/silccrypt/silchash.[ch] silc_hash_fingerprint
+         function to create fingerprints.
+
+       * Fixed a bug in SHA1; does not change the original data anymore.
+
+       * Partly implemented INFO command on client and server side.
+         Fixed CLEAR command.  Changes to SERVER command; show current
+         server(s) when giving command without arguments.  Added
+         VERSION command to client.
+
+       * Added check to server that unregistered connections cannot
+         execute commands (unless it is specificly allowed).
+
+Thu Jul  6 18:12:24 EEST 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Fixed screen refresh.
+
+       * Fixed channel joining bug from client.  On some circumstances
+         client tried to join to a channel it had already joined.
+
+       * 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. 
+
+         Added into: clientutil.[ch]: silc_client_verify_server_key.
+
+       * Changed SKE protocol's silc_ske_initiator_finish function
+         to accept callback function that verifies the received public
+         key.  Removed old silc_ske_verify_public_key function.
+
+Wed Jul  5 19:19:02 EEST 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Added into silcpkcs[ch]: silc_pkcs_public_key[_data]_set and
+         silc_pkcs_private_key[_data]_set.
+
+       * Made the password and public authentication more cleaner in
+         server's protocol.c.
+
+       * Removed historic and obsolete protocol `channel_auth' from
+         both client and server.
+
+       * Removed wrong way of sending command status messages from
+         server to client in server's command.c.  The old way violated
+         protocol specification.  
+
+         Changes to silccore/silccommand.[ch]: removed
+         silc_command_encode_status_payload -> not needed anymore,
+         changed silc_command_encode_payload_va to accept extra
+         argument on variable argument list.  The argument type must
+         now be provided to the function.  Also, added new function:
+         silc_command_encode_reply_payload_va which is same as
+         normal command_encode_payload_va except command status type
+         is provided as extra argument.
+
+Tue Jul  4 18:26:39 EEST 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Added ~./silc directory handling.  The directory includes the
+         public and private keys for the client.
+
+         Added silc_client_check_silc_dir, silc_client_create_identifier
+         and silc_client_load_keys.
+
+       * Implemented SILC protocol compliant public key.  Added public
+         and private key saving to and loading from files.
+
+         Added into silcpkcs.[ch]: silc_pkcs_encode_identifier,
+         silc_pkcs_public_key_encode[_data], silc_pkcs_public_key_decode,
+         silc_pkcs_private_key_encode[_data], silc_pkcs_private_key_decode,
+         silc_pkcs_public_key_alloc, silc_pkcs_public_key_free,
+         silc_pkcs_private_key_alloc and silc_pkcs_private_key_free.
+
+         Implemented: silc_pkcs_save_[public/private]_key[_data] and
+         silc_pkcs_load_[public/private]_key.
+
+Mon Jul  3 18:51:27 EEST 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Added silc_server_get_route (route.[ch]) to get connection
+         data for the fastest route for given ID.
+
+       * Implemented INVITE command on client and server.  The command
+         were re-defined in the SILC Protocol Specification and the
+         implementation now complies with the specification.
+
+       * Implemented PING command on client and server.
+
+       * Implemented NAMES command on client and server.  The server side
+         supports currently only normal server not router server yet.
+         Some changes to NAMES definition in SILC protocol specification.
+
+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 
+         again.  This change was made to the protocol as well.  Server
+         should not violate the protocol specification anymore.
+
+Fri Jun 30 14:03:26 EEST 2000  Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+       * Added SOCKS4 and SOCKS5 support to SILC client.  SOCKS5
+         was tested.  SOCKS4 was not but should work anyway.
diff --git a/INSTALL b/INSTALL
index c2d5f4b5028c088df3b11bf4f4bfe7027ec22d16..12e7302a0debd6c0a086a435b9a509206fdb4db1 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -19,5 +19,5 @@ give,
 
 WARNING: The debugging is very very heavy and you currently cannot turn
 it off if you have compiled it with this option.  However, if you're
-going to develop or debug SILC you whould compile with this option.
+going to develop or debug SILC you should compile with this option.
 
diff --git a/README b/README
index 1953d9423e2a46defa991fd636baf96eab0493b4..f37377ac669adbe8ba05199805ef02746635b58e 100644 (file)
--- a/README
+++ b/README
@@ -17,13 +17,149 @@ Description
 SILC (Secure Internet Live Conferencing) is a protocol which provides
 secure conferencing services in the Internet over insecure channel.
 SILC is IRC like softwarre although internally they are very different.
-Biggest similiarity between SILC and IRC is that they both provide
+Biggest similarity between SILC and IRC is that they both provide
 conferencing services and that SILC has almost same commands as IRC.  Other
 than that they are nothing alike.  Biggest differences are that SILC is 
 secure what IRC is not in any way.  The network model is also entirely
 different compared to IRC.
 
 
+Running SILC
+============
+
+The development version is still preliminary version and requires some
+work to get it working.  You should, first of all, check the example
+configuration files in ./doc/ directory.  Change them according to your
+needs.
+
+To run SILC client:
+
+       cd silc
+       ./silc -f <config file>
+
+To run SILC server
+
+       cd silcd
+       ./silcd -f <config file>
+
+
+Working Commands
+================
+
+Following commands has been, at least partly, implemented:
+
+
+       /SERVER [<server>[:<port>]]
+
+               Connects to remote SILC server.
+
+       /NICK   [<nickname>]
+
+               Changes/sets nickname.  Note that in SILC there can be
+               multiple same nicknames.  However, the logic on working
+               with multiple nicknames on user interface is pretty much
+               still missing.  Also note that nicknames in SILC are
+               case-sensitive.
+
+       /JOIN   <channel>
+
+               Joins to a channel.  Channel names start with `#'
+               character.
+
+       /LEAVE  <channel>
+
+               Leaves the channel.  If /leave * is given the client
+               leaves the current channel.
+
+       /CMODE  <channel> +|-<modes> [{ <arguments>}]
+
+               Changes/sets channel mode.  Most of the modes require
+               special privileges, such as channel operator or channel
+               founder privileges to work.  The mode is added by adding
+               + before the option(s) and removed by adding - before
+               the option(s).  Following modes are available:
+
+               p               Set/unset channel as private channel
+               s               Set/unset channel as secret channel
+               k               Set/unset that channel uses private channel key
+               i               Set/unset channel as invite only channel
+               t               Set/unset that only channel operator or 
+                               founder may set channel topic
+               l <limit>       Set/unset channel's user limit
+               a <passphrase>  Set/unset passphrase for channel that must
+                               be provided when joining to the channel.
+               b <username!nickname@server>    
+                               Add client to/remove client from ban list
+               I <username!nickname@server>    
+                               Add client to/remove client from invite list
+               c <cipher>[:<keylen>]
+                               Set/unset channel's cipher
+
+               Multiple modes can be set/unset at once if the modes does not
+               require any arguments.  If mode requires an argument then only
+               one mode can be set at once.
+
+       /CUMODE <channel> +|-<modes> <nickname>[@<server>]
+
+               Changes/set user's mode on a channel.  Most of the modes 
+               require that the client who changes some client's mode must
+               be channel founder or channel operator.  Following channel
+               user modes are available:
+
+               a <nickname>[@<server>]
+                               Set/unset all modes (cannot be used to set
+                               both founder and operator rights, can be used
+                               only to remove both modes at once).
+               f <nickname>[@<server>]
+                               Unset channel founder.  Channel founder rights
+                               cannot be set by user (only by server) so this
+                               can be used only to unset the mode.
+               o <nickname>[@<server>]
+                               Set/unset channel operator.  Requires that 
+                               you are channel operator or channel founder.
+
+       /MSG    <nickname> <message>
+
+               Sends private message to remote client.  Support for
+               handling multiple same nicknames with /MSG command is
+               still missing.
+
+       /WHOIS  <nickname>[@<server>] [<count>]
+
+               Gives a little information about a client.  Support for
+               handling multiple same nicknames with this command is
+               still missing.
+
+       /PING   [<server>]
+
+               Pings server.  Only locally connected server may be 
+               pinged.
+
+       /INFO   [<server>]
+
+               Requests information about a server.  If argument is
+               not specified current server is used.
+
+       /AWAY   [<message>]
+
+               Sets away message.  When private message is received and
+               away message is set the client automatically replies to
+               the sender with the away message.  To remove away message
+               give the command without arguments.
+
+       /QUIT
+
+               Quits session.  Connection to remote server is closed.
+
+       /CLEAR
+
+               Clears current screen.
+
+       /VERSION
+
+               Shows client version.
+
+
 Features
 ========
 
@@ -55,6 +191,8 @@ TODO file for more information.]
 
  o Supports data compression with GZIP to improve performance.
 
+ o Supports SOCKS4 and SOCKS5 firewall traversal protocols.
+
  o SIM (SILC Module) support.  Support for loading of shared objects at 
    run-time that provides new and extended features to both SILC client
    and server.  These can provide extra ciphers and extra features to
@@ -124,8 +262,8 @@ Contact
 Feedback and comments are welcome.  You can reach me in the following
 Address. 
 
-[Note that generally bug reports should not be sent just yet as the 
-Developer's Version is full of them and the bug hunt has not even started 
-yet.]
+Official SILC project web site is   : http://silc.pspt.fi
+FTP archive for SILC project is     : ftp://silc.pspt.fi/pub/silc/
+Development mailing list address is : silc-devel@lists.sourceforge.net
 
                                Pekka Riikonen <priikone@poseidon.pspt.fi>
diff --git a/README.CVS b/README.CVS
new file mode 100644 (file)
index 0000000..207c6ca
--- /dev/null
@@ -0,0 +1,148 @@
+Anonymous CVS Access
+====================
+
+Anonymous CVS access is now available to SILC CVS repository. The
+repository includes everything related to SILC project; source codes,
+documentation and web pages.
+
+Also note that this is the closest to real time development you can get
+thus you cannot expect that the source tree would work or even compile.
+While it is our intention that the trunk would always at least compile
+there might be situations when it will not.
+
+
+Howto Checkout The Source Tree
+==============================
+
+The repository can be checked out by using anonymous pserver with CVS.
+There are no password restrictions in the SILC anonymous CVS repository.
+
+For those who are using sh/ksh/bash the check out is done as follows:
+
+export CVSROOT=:pserver:silc@silc.pspt.fi:/storage/silc/CVS
+cvs login
+cvs co silc
+
+For those who are using csh/tcsh the check out is done as follows:
+
+setenv CVSROOT :pserver:silc@silc.pspt.fi:/storage/silc/CVS
+cvs login
+cvs co silc
+
+If you don't want to set $CVSROOT environment variable you can set the
+path to the cvs as command line options:
+
+cvs -d:pserver:silc@silc.pspt.fi:/storage/silc/CVS login
+cvs -d:pserver:silc@silc.pspt.fi:/storage/silc/CVS co silc
+
+What ever method you decide to use, after you have done cvs login you will
+be prompted for password:
+
+       CVS password: silc
+
+Type the password "silc" and press Enter.
+
+The actual SILC source tree is checked out using the cvs co silc command,
+described above. This command will fetch the source tree and save it into
+directory named silc. SILC CVS repository currently does not have any
+branches thus this will check out the trunk. The size of the trunk is
+currently about 8 Mb but will grow in the future.
+
+
+What SILC Source Tree Includes
+==============================
+
+SILC Source tree includes a lot more stuff that appears in public
+distribution.  The source tree includes, for example, internal scripts,
+configuration files, SILC webpages etc.  These never appear on a public
+distribution.
+
+Following directories currently exist in SILC source tree.
+
+  doc/
+
+        Includes all the SILC documentation.  Some of the documentation
+        are generated when distribution is generated.  The automatically
+        generated files must never be commited to CVS.
+
+  includes/
+
+        Includes SILC include files.
+
+  lib/
+
+        Includes SILC libraries.  There maybe libraries on the CVS that
+        does not appear on public distribution.
+
+  public_html/
+
+        Includes the official SILC web pages and everything that relates
+        to them.  This directory never appears on public distribution.
+
+  silc/
+
+        Includes SILC client.  There can be some extra files that will
+        never appear in public distribution, such as, configuration files.
+
+  silcd/
+
+        Includes SILC server.  There can be some extra files that will
+        never appear in public distribution, such as, configuration files.
+
+
+Howto Compile SILC Source Tree
+==============================
+
+After checkout from CVS the SILC source tree must be prepared for 
+configuration and compilation.  To compile the source three, give,
+
+       ./prepare
+       ./configure --enable-debug
+       make
+
+The ./prepare script is included in to the source tree and it never
+appears in public distribution.  The script prepares the source tree
+by creating configuration scripts and Makefiles.  The prepare must be
+run every time you make some changes to configuration scripts (however,
+making changes to Makefile.am's does not require running ./prepare).
+
+As a developer you should read the ./configure script's help by
+giving ./configure --help and study all of its different options.  Also,
+you should configure the script with --enable-debug option as it
+compiles SILC with -g (debugging) option and it enables the 
+SILC_LOG_DEBUG* scripts.  Warning is due here:  The debugging produced
+by both cilent and server is very heavy, thus it is common to test
+the programs as follows:
+
+       ./silc -f configfile 2>log
+       ./silcd -f configfile 2>log
+
+
+Howto Clean SILC Source Tree
+============================
+
+To entirely clear the source tree to the state after it was checked out
+from CVS, give,
+
+       ./prepare-clean
+
+This calls `make distclean' plus removes automatically generated files
+by hand.  It also removes *.log files. However, it will not remove
+any other files you might have created.
+
+
+Makefiles and configuration files
+=================================
+
+Developers should never directly write a Makefile.  All Makefiles are
+always automatically generated by ./prepare and later by ./configure
+scripts.  Instead, developers must write Makefile.am files.  There
+are plenty of examples what they should look like.  If you change
+Makefile.am during development you don't have to run ./prepare, just
+run normal make.
+
+Configuration files are the files that ./prepare automatically generates
+and what will be included into public distribution.  ./prepare creates
+for example the ./configure script that is not commited to the CVS.
+`configure.in' is the file that developers must edit to change ./configure
+script.  After changing one must run  ./prepare.
diff --git a/TODO b/TODO
index ece615c1f8f68cbea8938252ad42fe6f5fb48c3f..f4819f5dc5a4755dd0deccb882082ca0da103753 100644 (file)
--- a/TODO
+++ b/TODO
@@ -11,14 +11,27 @@ help is really appreciated - and needed.
 
                                                        - Pekka
 
-[Latest Note:  The protocol has changed a bit in some parts which 
-causes that the current implementation violates some requirements.
-These are not listed here, currently.]
-
 
 New features TODO
 =================
 
+ o We should replace all short, int, long, unsigned short, unsigned int,
+   unsigned long with some pre-defined datatypes that really are what
+   we want on all platforms.  int16, uint16, int32, uint32 etc. are
+   what we could use or maybe SilcInt16, SilcUInt16 etc.  Also, boolean
+   datatype should be defined.
+
+ o Add boolean (or bool), typedef of unsigned char.
+
+ o More platform supports should be added.  The code is pretty much
+   generic but there are some parts that require porting (SIM).  Also, 
+   some support for different platforms is needed into configure.in.
+
+ o SILC requires currently GCC to work because we use GCC specific 
+   compilation options.  Generally any compiler that supports inline
+   functions and can build shared libraries (for SIMs) should work.  
+   These cases should be included into configure.in.
+
  o Extended SIM (SILC Module) support.  Currently only SILC Cipher API
    and SILC Hash API may be used as SIM's.  What I have in mind is to
    have extended support for SIM's so that basically any SILC API could
@@ -39,28 +52,8 @@ New features TODO
    example code (code that we could use directly pretty easily) for
    other platforms.
 
- o We should replace all short, int, long, unsigned short, unsigned int,
-   unsigned long with some pre-defined datatypes that really are what
-   we want on all platforms.  int16, uint16, int32, uint32 etc. are
-   what we could use or maybe SilcInt16, SilcUInt16 etc.  Also, boolean
-   datatype should be defined.
-
- o More platform supports should be added.  The code is pretty much
-   generic but there are some parts that require porting (SIM).  Also, 
-   some support for different platforms is needed into configure.in.
-
- o SILC requires currently GCC to work because we use GCC specific 
-   compilation options.  Generally any compiler that supports inline
-   functions and can build shared libraries (for SIMs) should work.  
-   These cases should be included into configure.in.
-
-
-TODO In SILC Client
-===================
-
- o Implement all commands.  A lot of commands are still yet to be
-   implemented.  Most of them are trivial but some will require some
-   planning.  Go see the command.c for unimplemented commands.
+TODO In SILC Client Library
+===========================
 
  o Non-blocking connection on the background must be stopped if some
    other connection on same window has established.  Now it is possible
@@ -68,9 +61,6 @@ TODO In SILC Client
    we already have a working connection to some other place; things
    goes bad.
 
- o Finish WHOIS, finish JOIN and other commands that are partly
-   implemented.
-
  o Input line on UI is buggy.  Cursor movement etc bugs.  Too lazy to
    fix it.
 
@@ -86,98 +76,48 @@ TODO In SILC Client
    Currently there cannot be private keys for channels.  Normal channel
    keys (generated by server) are used.  This is required by the protocol.
 
- o Public and private key generation is now done everytime the program
-   is run.  Now, this is only for testing period as I've been lazy to
-   do it any better for now.  This must be fixed.
-
  o I guess, public key authentication (when connecting to a server)
    is not working currently.  It is just matter of loading the keys
    from file and using them (see corresponding code in server, it should
    support public key authentication already).
 
- o Multiple windows support.  Basic support for multiple windows already
-   exists but a lot is still missing to get it working.  Also, some
-   of the existing stuff probably needs to be tweaked a bit before the
-   multiple windows support could be done.  And of course the actual
-   commands that control the windows needs to be written (/WINDDOW).
-
- o Implement /KEYMAP (or similiar) command to remap control and function
-   keys.
-
- o Implement /ALIAS command to make command aliases.
-
- o Implement /set/if/do/while etc as in IRC2.  Maybe post 1.0 task.
-   Some scripting would be good.
-
  o Connection Authentication request resolving is missing and must be
    done.  This is required by the protocol.
 
+ o Move ssh_client_notify_by_server to its own file (like notify.[ch]).
+
  o Key Exchange protocol's responder side is missing from client.  
    Generally it is possible for the client to be responder so it should
    be implemented (See corresponding code from server).  Error handling
    in the KE protocol is also in pretty bad shape in client.
 
- o Configuration file loading from global and from local dirs.  This
-   is currently missing and I guess the global is only used.  Old SILC
-   version (in 1997) had ~./silc directory that I guess should be done
-   now as well.  The code for handling those exists but not in current
-   source tree.
-
- o Configuration file format - could be better.
-
- o Write help files for commands.  Nice format for the help files should
-   be selected.  I'm open for ideas.
-
- o All allocations and freeing needs to be checked for memory leaks.
-   Also, return values from various allocations and functions needs to
-   checked.
-
 
 TODO In SILC Server
 ===================
 
- o Implement all commands on server side.  A lot of commands are still yet
-   to be implemented.  Most of them are trivial but some will require some
-   planning.  Go see the command.c for unimplemented commands.
-
  o DNS/IP lookup blocks the server.  This must be fixed.  Check the
    resolver stuff (resolver(3), resolver(5)).  Either we have to do the
    own resolver stuff (through scheduler, if possible without writing
    too much own stuff) or use threads.
 
- o Lenght of the packet processing timeouts needs to be checked whether
+ o Length of the packet processing timeouts needs to be checked whether
    they are too short or too long.  I haven't really tested whether they
    are suitable.  They should be tested on high load which I haven't done
    at all yet.
 
- o Public and private key generation is now done everytime the program
-   is run.  Now, this is only for testing period as I've been lazy to
-   do it any better for now.  This must be fixed.
+ o INVITE command must set the channel's invite list if channel is 
+   invite-only channel.
 
  o Server says that it is able to listen on multiple ports but currently
    that is bogus.  It can, but internals are for single server.
 
- o Command lagging must implemented.  Those commands (all currently) that
-   has the LAG flag set they must not be allowed to be executed more than
-   once, say, in 2 seconds.
-
  o Command flag usage in general is not implemented yet.
 
  o Client history must be implemented.  Protocol says that server must
    keep history information about clients for some period of time.
 
- o Channel flags and user modes on channels are not implemented yet as
-   /MODE command is not implemented yet in client and server.
-
  o Protocol execution timeouts are hard coded, should be configurable.
 
- o Channel message sending routines uses a lot of common code.  Should
-   create a common function for those instead of writing the same code
-   again everytime, as done now.
-
- o serverutil.c I guess should be created for util-like functions that
-   now resides in server.c, which is getting too big.
-
  o serverconfig.c and the function naming in it is inconsistent.  It is 
    not silc_config_server* it should be silc_server_config*.  As should
    all the SilcConfigServer* types be SilcServerConfig*.
@@ -202,48 +142,26 @@ TODO In SILC Server
  o Statistics are totally missing from the server.  It would be nice
    to gather some statistics.
 
- o All allocations and freeing needs to be checked for memory leaks.
-   Also, return values from various allocations and functions needs to
-   checked.
-
 
 TODO In SILC Libraries
 ======================
 
- o Public key verification in SKE (SILC Key Exchange) protocol is missing,
-   thus currently we trust on all public keys.  This probably doesn't cause
-   bad problems but the mechanism of verifying it from local database
-   (from files) needs to be done (it can open man-in-the-middle-attacks).
-
  o Implement PFS (Perfect Forward Secrecy) flag in SKE (and in client and
    server, actually).  If PFS is set, re-key must cause new key exchange.
    This is required by the SILC protocol.
 
- o Re-key in general is actually missing (from everywhere) and must be done.
+ o silc_id_str2id must also take ID length as argument. Otherwise, variable
+   length ID's (after we add IPv6) will not work.
 
- o SKE does not send correct status types.  Types are defined but not
-   sent.
+ o Re-key in general is actually missing (from everywhere) and must be done.
 
- o Connection authentication protocol does not send correct status types.
-   These types are not defined currently at all.
+ o ID Cache expiry does not work.
 
  o PKCS#1 style RSA public key encryption/decryption/sign/verify is 
    missing, and should be added for interoperability reasons.  The thing 
    I've done now is bad and should be removed as soon as possible (or 
    the protocol should then state the method of how they should be done).
 
- o SILC public key file type is bad.  I'd like to see PEM encoded files.
-   I have public domain code for base64 encoding but it needs to be 
-   rewritten.
-
- o Slow ciphers should be removed.  I think we don't need more than
-   the AES finalists plus blowfish and RC5.
-
- o These slow ciphers actually don't work currently as I've tested
-   only the ones that are worth testing.  The CBC mode on these slow
-   ciphers probably don't work.  No need to worry, these ciphers should
-   be removed.
-
  o Scheduler needs to be analyzed on high load as it might be unfair
    towards select() because it may run timeout tasks before select() and
    after select().  If it is found to be unfair the timeout task running
@@ -269,39 +187,12 @@ TODO In SILC Libraries
    cleaner.  Introducing silc_cipher_encrypt/decrypt/set_key etc.
    functions (I actually don't understand why have I left these un-done).
 
- o Scheduler should automatically allocate task queues if NULL pointers 
-   are passed to the silc_schedule_init.  Would make initialization 
-   cleaner.
-
- o Packet processing routines in client and server are actually pretty
-   much generic and should be moved from the client/server to the library
-   as generic routines (silc_<client/server>_packet_decrypt_rest* etc).
-   This requires heavy changes to the client and server.
-
  o Random Number Generator needs some tweaking.  Reading /dev/random may
    block resulting slow initialization of RNG.  Some other things in the
    RNG may block as well.  Also, I have some pending changes to the RNG 
    that needs to be commited (from Schneier's Yarrow-160 paper).  They 
    should make the RNG even better.
 
- o Logging should be made more generic in a way that application can
-   set to where the logging is destined to.  Now, it is always destined
-   to stdout (or stderr) which is a bad thing for client.  Ie. some
-   sort of logging registration functions or similiar should be done
-   (silclog.[ch] in core).  The actual output of logs should be done
-   by callback function in the application not in lib.
-
- o I don't like the ID cache system currenly implemented.  Ugly and
-   not so good.  Must be rewritten very soon.
-
- o All allocations and freeing needs to be checked for memory leaks.
-
- o There are also checks missing from allocations whether the allocation
-   returns valid memory or NULL.  These are missing in library as well
-   in client and server.  Either all checks has to be added or we will
-   have to make sure that silc_*alloc()s always return valid memory
-   and assert()s if the system's memory allocator (*alloc()) fails.
-
  o silc_buffer_[un]format() needs to be made more stable as it may
    crash the SILC if malformed data is sent as argument.  There are a
    lot of places in client and server where we trust directly data coming
@@ -360,10 +251,4 @@ TODO After 1.0
    nice as SSH is widely used all over the place.  SILC Protocol 
    supports SSH2 public keys.
 
- o IRC support for SILC client.  This would be nice to have on client
-   as it could be used to connect to SILC and IRC.  People wouldn't
-   have to have two different clients when same would work on both.
-   I'd like to see this done as SIM, after the extended SIM support
-   has been added to SILC.
-
  o Cipher optimizations (asm, that this) at least for i386 would be nice.
index 65e1903ecb897aeb2f51a52c7c0599ecf63106ec..17c67b0e4877211b6c5c30fc20b2620db7354db9 100644 (file)
 #undef SILC_SIM
 #undef HAVE_RTLD_NOW
 #undef HAVE_RTLD_LAZY
+
+/* Redefs for SOCKS5 library */
+#undef SOCKS
+#undef SOCKS5
+#undef Rconnect
+#undef Rgetsockname
+#undef Rgetpeername
+#undef Rbind
+#undef Raccept  
+#undef Rlisten
+#undef Rselect
+#undef Rrecvfrom
+#undef Rsendto
+#undef Rrecv
+#undef Rsend
+#undef Rread
+#undef Rwrite
+#undef Rrresvport
+#undef Rshutdown
+#undef Rlisten
+#undef Rclose
+#undef Rdup
+#undef Rdup2
+#undef Rfclose
+#undef Rgethostbyname
index 1b358e63308cf34102a79e80b4b32e86b6367b90..ce3f90f98a56aa83cae4245550e94212d5d89c70 100644 (file)
@@ -22,19 +22,19 @@ bin_PROGRAMS = silc
 
 silc_SOURCES = \
        silc.c \
-       client.c \
-       command.c \
-       command_reply.c \
        clientconfig.c \
        clientutil.c \
-       protocol.c \
-       screen.c
+       local_command.c \
+       screen.c \
+       client_ops.c
 
-LDADD = -L. -L.. -L../lib -lsilc -lcurses
+silc_DEPENDENCIES = ../lib/libsilcclient.a ../lib/libsilc.a
+
+LDADD = -L. -L.. -L../lib -lsilcclient -lsilc -lcurses
 
 EXTRA_DIST = *.h
 
 INCLUDES = -I. -I.. -I../lib/silccore -I../lib/silccrypt \
        -I../lib/silcmath -I../lib/silcske -I../lib/silcsim \
-       -I../includes \
-       -I../lib/silcmath/gmp-3.0.1
+       -I../includes -I../lib/silcclient -I../lib/silcutil \
+       -I../lib/silcmath/gmp -I../lib/trq
diff --git a/apps/silc/client.c b/apps/silc/client.c
deleted file mode 100644 (file)
index 8014179..0000000
+++ /dev/null
@@ -1,2371 +0,0 @@
-/*
-
-  client.c
-
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
-
-  Copyright (C) 1997 - 2000 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
-  GNU General Public License for more details.
-
-*/
-/*
- * $Id$
- * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:56  priikone
- *     Importet from internal CVS/Added Log headers.
- *
- *
- */
-
-#include "clientincludes.h"
-
-/* Static function prototypes */
-static int silc_client_bad_keys(unsigned char key);
-static void silc_client_process_message(SilcClient client);
-static char *silc_client_parse_command(unsigned char *buffer);
-
-/* Static task callback prototypes */
-SILC_TASK_CALLBACK(silc_client_update_clock);
-SILC_TASK_CALLBACK(silc_client_run_commands);
-SILC_TASK_CALLBACK(silc_client_process_key_press);
-SILC_TASK_CALLBACK(silc_client_connect_to_server_start);
-SILC_TASK_CALLBACK(silc_client_connect_to_server_second);
-SILC_TASK_CALLBACK(silc_client_connect_to_server_final);
-SILC_TASK_CALLBACK(silc_client_packet_process);
-SILC_TASK_CALLBACK(silc_client_packet_parse);
-
-SilcClientWindow silc_client_create_main_window(SilcClient client);
-SilcClientWindow silc_client_add_window(SilcClient client,
-                                       int is_current);
-void silc_client_packet_parse_type(SilcClient client, 
-                                  SilcSocketConnection sock,
-                                  SilcPacketContext *packet);
-void silc_client_private_message_process(SilcClient client,
-                                        SilcSocketConnection sock,
-                                        SilcPacketContext *packet);
-
-/* Definitions from version.h */
-extern char *silc_version;
-extern char *silc_name;
-extern char *silc_fullname;
-
-/* Allocates new client object. This has to be done before client may
-   work. After calling this one must call silc_client_init to initialize
-   the client. */
-
-int silc_client_alloc(SilcClient *new_client)
-{
-
-  *new_client = silc_calloc(1, sizeof(**new_client));
-  if (*new_client == NULL) {
-    SILC_LOG_ERROR(("Could not allocate new client object"));
-    return FALSE;
-  }
-
-  (*new_client)->input_buffer = NULL;
-  (*new_client)->screen = NULL;
-  (*new_client)->windows = NULL;
-  (*new_client)->windows_count = 0;
-  (*new_client)->current_win = NULL;
-
-  return TRUE;
-}
-
-/* Free's client object */
-
-void silc_client_free(SilcClient client)
-{
-  if (client) {
-    silc_free(client);
-  }
-}
-
-/* Initializes the client. This makes all the necessary steps to make
-   the client ready to be run. One must call silc_client_run to run the
-   client. */
-
-int silc_client_init(SilcClient client)
-{
-
-  SILC_LOG_DEBUG(("Initializing client"));
-  assert(client);
-
-  client->username = silc_get_username();
-  client->realname = silc_get_real_name();
-
-  /* Register all configured ciphers, PKCS and hash functions. */
-  client->config->client = (void *)client;
-  silc_client_config_register_ciphers(client->config);
-  silc_client_config_register_pkcs(client->config);
-  silc_client_config_register_hashfuncs(client->config);
-
-  /* Initialize hash functions for client to use */
-  silc_hash_alloc("md5", &client->md5hash);
-  silc_hash_alloc("sha1", &client->sha1hash);
-
-  /* Initialize none cipher */
-  silc_cipher_alloc("none", &client->none_cipher);
-
-  /* Initialize random number generator */
-  client->rng = silc_rng_alloc();
-  silc_rng_init(client->rng);
-  silc_math_primegen_init(); /* XXX */
-
-#if 0
-  {
-    SilcCipher twofish;
-    unsigned char *src, *dst, *dec;
-    SilcBuffer packet;
-    int payload_len;
-
-    payload_len = 4 + strlen("pekka riikonen");
-    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(SILC_SOCKET_TYPE_CLIENT),
-                      SILC_STR_UI_XNSTRING("pekka riikonen", 
-                                           strlen("pekka riikonen")),
-                      SILC_STR_END);
-
-    silc_cipher_alloc("twofish", &twofish);
-    twofish->cipher->set_key(twofish->context, "1234567890123456", 16);
-    twofish->set_iv(twofish, "6543210987654321");
-    SILC_LOG_HEXDUMP(("source: len %d", packet->len), 
-                    packet->data, packet->len );
-    silc_packet_encrypt(twofish, packet, packet->len);
-    SILC_LOG_HEXDUMP(("encrypted"), packet->data, packet->len);
-    silc_packet_decrypt(twofish, packet, packet->len);
-    SILC_LOG_HEXDUMP(("decrypted"), packet->data, packet->len);
-
-  }
-
-  {
-    SilcCipher cipher1, cipher2;
-    unsigned char *src, *dst, *dec;
-    int len = strlen("12345678901234561234567890123456123456789012345612345678901234561234567890123456");
-
-    src = silc_calloc(len + 1, sizeof(unsigned char));
-    dst = silc_calloc(len + 1, sizeof(unsigned char));
-    dec = silc_calloc(len + 1, sizeof(unsigned char));
-
-    memcpy(src, "12345678901234561234567890123456123456789012345612345678901234561234567890123456", len);
-    
-    silc_cipher_alloc("twofish", &cipher1);
-    cipher1->cipher->set_key(cipher1->context, "1234567890123456", 128);
-    cipher1->set_iv(cipher1, "6543210987654321");
-
-    silc_cipher_alloc("twofish", &cipher2);
-    cipher2->cipher->set_key(cipher2->context, "1234567890123456", 128);
-    cipher2->set_iv(cipher2, "6543210987654321");
-
-    SILC_LOG_HEXDUMP(("source: %d", len), src, len);
-    cipher1->cipher->encrypt(cipher1->context, src, src, len, cipher1->iv);
-    SILC_LOG_HEXDUMP(("encrypted"), src, len);
-    cipher2->set_iv(cipher2, "6543210987654321");
-    cipher2->cipher->decrypt(cipher2->context, src, src, len, cipher2->iv);
-    SILC_LOG_HEXDUMP(("decrypted"), src, len);
-
-  }
-#endif
-
-  /* Register the task queues. In SILC we have by default three task queues. 
-     One task queue for non-timeout tasks which perform different kind of 
-     I/O on file descriptors, timeout task queue for timeout tasks, and,
-     generic non-timeout task queue whose tasks apply to all connections. */
-  silc_task_queue_alloc(&client->io_queue, TRUE);
-  if (!client->io_queue) {
-    goto err0;
-  }
-  silc_task_queue_alloc(&client->timeout_queue, TRUE);
-  if (!client->timeout_queue) {
-    goto err1;
-  }
-  silc_task_queue_alloc(&client->generic_queue, TRUE);
-  if (!client->generic_queue) {
-    goto err1;
-  }
-
-  /* Initialize the scheduler */
-  silc_schedule_init(client->io_queue, client->timeout_queue, 
-                    client->generic_queue, 5000);
-
-  /* Register the main task that is used in client. This received
-     the key pressings. */
-  if (silc_task_register(client->io_queue, fileno(stdin), 
-                        silc_client_process_key_press,
-                        (void *)client, 0, 0, 
-                        SILC_TASK_FD,
-                        SILC_TASK_PRI_NORMAL) == NULL) {
-    goto err2;
-  }
-
-  /* Register timeout task that updates clock every minute. */
-  if (silc_task_register(client->timeout_queue, 0,
-                        silc_client_update_clock,
-                        (void *)client, 
-                        silc_client_time_til_next_min(), 0,
-                        SILC_TASK_TIMEOUT,
-                        SILC_TASK_PRI_LOW) == NULL) {
-    goto err2;
-  }
-
-  if (client->config->commands) {
-    /* Run user configured commands with timeout */
-    if (silc_task_register(client->timeout_queue, 0,
-                          silc_client_run_commands,
-                          (void *)client, 0, 1,
-                          SILC_TASK_TIMEOUT,
-                          SILC_TASK_PRI_LOW) == NULL) {
-      goto err2;
-    }
-  }
-
-  /* Allocate the input buffer used to save typed characters */
-  client->input_buffer = silc_buffer_alloc(SILC_SCREEN_INPUT_WIN_SIZE);
-  silc_buffer_pull_tail(client->input_buffer, 
-                       SILC_BUFFER_END(client->input_buffer));
-
-  /* Initialize the screen */
-  client->screen = silc_screen_init();
-  silc_client_create_main_window(client);
-  client->screen->input_buffer = client->input_buffer->data;
-  silc_screen_print_coordinates(client->screen, 0);
-
-  return TRUE;
-
- err0:
-  silc_task_queue_free(client->timeout_queue);
- err1:
-  silc_task_queue_free(client->io_queue);
- err2:
-  return FALSE;
-}
-
-/* Stops the client. This is called to stop the client and thus to stop
-   the program. */
-
-void silc_client_stop(SilcClient client)
-{
-  SILC_LOG_DEBUG(("Stopping client"));
-
-  /* Stop the scheduler, although it might be already stopped. This
-     doesn't hurt anyone. This removes all the tasks and task queues,
-     as well. */
-  silc_schedule_stop();
-  silc_schedule_uninit();
-
-  SILC_LOG_DEBUG(("Client client"));
-}
-
-/* Runs the client. */
-
-void silc_client_run(SilcClient client)
-{
-  SILC_LOG_DEBUG(("Running client"));
-
-  /* Start the scheduler, the heart of the SILC client. When this returns
-     the program will be terminated. */
-  silc_schedule();
-}
-
-/* Creates the main window used in SILC client. This is called always
-   at the initialization of the client. If user wants to create more
-   than one windows a new windows are always created by calling 
-   silc_client_add_window. */
-
-SilcClientWindow silc_client_create_main_window(SilcClient client)
-{
-  SilcClientWindow win;
-  void *screen;
-
-  SILC_LOG_DEBUG(("Creating main window"));
-
-  assert(client->screen != NULL);
-
-  win = silc_calloc(1, sizeof(*win));
-  if (win == NULL) {
-    SILC_LOG_ERROR(("Could not allocate new window"));
-    return NULL;
-  }
-
-  client->screen->u_stat_line.program_name = silc_name;
-  client->screen->u_stat_line.program_version = silc_version;
-
-  /* Add the pointers */
-  win->nickname = silc_get_username();
-  win->local_id = NULL;
-  win->local_id_data = NULL;
-  win->local_id_data_len = 0;
-  win->remote_host = NULL;
-  win->remote_port = -1;
-  win->sock = NULL;
-
-  /* Create the actual screen */
-  screen = (void *)silc_screen_create_output_window(client->screen);
-  silc_screen_create_input_window(client->screen);
-  silc_screen_init_upper_status_line(client->screen);
-  silc_screen_init_output_status_line(client->screen);
-  win->screen = screen;
-
-  client->screen->bottom_line->nickname = win->nickname;
-  silc_screen_print_bottom_line(client->screen, 0);
-
-  /* Add the window to windows table */
-  client->windows = silc_calloc(1, sizeof(*client->windows));
-  client->windows[client->windows_count] = win;
-  client->windows_count = 1;
-
-  /* Automatically becomes the current active window */
-  client->current_win = win;
-
-  return win;
-}
-
-/* Allocates and adds new window to the client. This allocates new
-   physical window and internal window for connection specific data. 
-   All the connection specific data is always saved into a window
-   since connection is always associated to a active window. */
-
-SilcClientWindow silc_client_add_window(SilcClient client,
-                                       int is_current)
-{
-  SilcClientWindow win;
-
-  assert(client->screen != NULL);
-
-  win = silc_calloc(1, sizeof(*win));
-  if (win == NULL) {
-    SILC_LOG_ERROR(("Could not allocate new window"));
-    return NULL;
-  }
-
-  /* Add the pointers */
-  win->screen = silc_screen_add_output_window(client->screen);
-  win->sock = NULL;
-
-  /* Add the window to windows table */
-  client->windows = silc_realloc(client->windows, sizeof(*client->windows)
-                                * (client->windows_count + 1));
-  client->windows[client->windows_count] = win;
-  client->windows_count++;
-
-  if (is_current == TRUE)
-    client->current_win = win;
-
-  return win;
-}
-
-/* The main task on SILC client. This processes the key pressings user
-   has made. */
-
-SILC_TASK_CALLBACK(silc_client_process_key_press)
-{
-  SilcClient client = (SilcClient)context;
-  int c;
-
-  /* There is data pending in stdin, this gets it directly */
-  c = wgetch(client->screen->input_win);
-  if (silc_client_bad_keys(c))
-    return;
-
-  SILC_LOG_DEBUG(("Pressed key: %d", c));
-
-  switch(c) {
-    /* 
-     * Special character handling
-     */
-  case KEY_UP: 
-  case KEY_DOWN:
-    break;
-  case KEY_RIGHT:
-    /* Right arrow */
-    SILC_LOG_DEBUG(("RIGHT"));
-    silc_screen_input_cursor_right(client->screen);
-    break;
-  case KEY_LEFT:
-    /* Left arrow */
-    SILC_LOG_DEBUG(("LEFT"));
-    silc_screen_input_cursor_left(client->screen);
-    break;
-  case KEY_BACKSPACE:
-  case KEY_DC:
-  case '\177':
-  case '\b':
-    /* Backspace */
-    silc_screen_input_backspace(client->screen);
-    break;
-  case '\011':
-    /* Tabulator */
-    break;
-  case KEY_IC:
-    /* Insert switch. Turns on/off insert on input window */
-    silc_screen_input_insert(client->screen);
-    break;
-  case CTRL('j'):
-  case '\r':
-    /* Enter, Return. User pressed enter we are ready to
-       process the message. */
-    silc_client_process_message(client);
-    silc_screen_input_reset(client->screen);
-    break;
-  case CTRL('l'):
-    /* Refresh screen, Ctrl^l */
-    silc_screen_refresh_all(client->screen);
-    break;
-  case CTRL('a'):
-  case KEY_HOME:
-  case KEY_BEG:
-    /* Beginning, Home */
-    silc_screen_input_cursor_home(client->screen);
-    break;
-  case CTRL('e'):
-  case KEY_END:
-    /* End */
-    silc_screen_input_cursor_end(client->screen);
-    break;
-  case KEY_LL:
-    /* End */
-    break;
-  case CTRL('g'):
-    /* Bell, Ctrl^g */
-    beep();
-    break;
-  case KEY_DL:
-  case CTRL('u'):
-    /* Delete line */
-    break;
-  default:
-    /* 
-     * Other characters 
-     */
-    if (c < 32) {
-      /* Control codes are printed as reversed */
-      c = (c & 127) | 64;
-      wattron(client->screen->input_win, A_REVERSE);
-      silc_screen_input_print(client->screen, c);
-      wattroff(client->screen->input_win, A_REVERSE);
-    } else  {
-      /* Normal character */
-      silc_screen_input_print(client->screen, c);
-    }
-  }
-
-  silc_screen_print_coordinates(client->screen, 0);
-  silc_screen_refresh_win(client->screen->input_win);
-}
-
-static int silc_client_bad_keys(unsigned char key)
-{
-  /* these are explained in curses.h */
-  switch(key) {
-  case KEY_SF:
-  case KEY_SR:
-  case KEY_NPAGE:
-  case KEY_PPAGE:
-  case KEY_PRINT:
-  case KEY_A1:
-  case KEY_A3:
-  case KEY_B2:
-  case KEY_C1:
-  case KEY_C3:
-  case KEY_UNDO:
-  case KEY_EXIT:
-  case '\v':           /* VT */
-  case '\E':           /* we ignore ESC */
-    return TRUE;
-  default: 
-    return FALSE; 
-  }
-}
-
-/* Processes messages user has typed on the screen. This either sends
-   a packet out to network or if command were written executes it. */
-
-static void silc_client_process_message(SilcClient client)
-{
-  unsigned char *data;
-  unsigned int len;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  data = client->input_buffer->data;
-  len = strlen(data);
-
-  if (data[0] == '/' && data[1] != ' ') {
-    /* Command */
-    unsigned int argc = 0;
-    unsigned char **argv, *tmpcmd;
-    unsigned int *argv_lens, *argv_types;
-    SilcClientCommand *cmd;
-    SilcClientCommandContext ctx;
-
-    /* Get the command */
-    tmpcmd = silc_client_parse_command(data);
-
-    /* Find command match */
-    for (cmd = silc_command_list; cmd->name; cmd++) {
-      if (!strcmp(cmd->name, tmpcmd))
-       break;
-    }
-
-    if (cmd->name == NULL) {
-      silc_say(client, "Invalid command: %s", tmpcmd);
-      silc_free(tmpcmd);
-      goto out;
-    }
-
-    /* Now parse all arguments */
-    silc_client_parse_command_line(data, &argv, &argv_lens, 
-                                  &argv_types, &argc, cmd->max_args);
-    silc_free(tmpcmd);
-
-    SILC_LOG_DEBUG(("Exeuting command: %s", cmd->name));
-
-    /* Allocate command context. This and its internals must be free'd 
-       by the command routine receiving it. */
-    ctx = silc_calloc(1, sizeof(*ctx));
-    ctx->client = client;
-    ctx->sock = client->current_win->sock;
-    ctx->argc = argc;
-    ctx->argv = argv;
-    ctx->argv_lens = argv_lens;
-    ctx->argv_types = argv_types;
-
-    /* Execute command */
-    (*cmd->cb)(ctx);
-
-  } else {
-    /* Normal message to a channel */
-    if (len && client->current_win->current_channel &&
-       client->current_win->current_channel->on_channel == TRUE) {
-      silc_print(client, "> %s", data);
-      silc_client_packet_send_to_channel(client, 
-                                        client->current_win->sock,
-                                        client->current_win->current_channel,
-                                        data, strlen(data), TRUE);
-    }
-  }
-
- out:
-  /* Clear the input buffer */
-  silc_buffer_clear(client->input_buffer);
-  silc_buffer_pull_tail(client->input_buffer, 
-                       SILC_BUFFER_END(client->input_buffer));
-}
-
-/* Returns the command fetched from user typed command line */
-
-static char *silc_client_parse_command(unsigned char *buffer)
-{
-  char *ret;
-  const char *cp = buffer;
-  int len;
-
-  len = strcspn(cp, " ");
-  ret = silc_to_upper((char *)++cp);
-  ret[len - 1] = 0;
-
-  return ret;
-}
-
-/* Parses user typed command line. At most `max_args' is taken. Rest
-   of the line will be allocated as the last argument if there are more
-   than `max_args' arguments in the line. Note that the command name
-   is counted as one argument and is saved. */
-
-void silc_client_parse_command_line(unsigned char *buffer, 
-                                   unsigned char ***parsed,
-                                   unsigned int **parsed_lens,
-                                   unsigned int **parsed_types,
-                                   unsigned int *parsed_num,
-                                   unsigned int max_args)
-{
-  int i, len = 0;
-  int argc = 0;
-  const char *cp = buffer;
-
-  /* Take the '/' away */
-  cp++;
-
-  *parsed = silc_calloc(1, sizeof(**parsed));
-  *parsed_lens = silc_calloc(1, sizeof(**parsed_lens));
-
-  /* Get the command first */
-  len = strcspn(cp, " ");
-  (*parsed)[0] = silc_to_upper((char *)cp);
-  (*parsed_lens)[0] = len;
-  cp += len + 1;
-  argc++;
-
-  /* Parse arguments */
-  if (strchr(cp, ' ') || strlen(cp) != 0) {
-    for (i = 1; i < max_args; i++) {
-
-      if (i != max_args - 1)
-       len = strcspn(cp, " ");
-      else
-       len = strlen(cp);
-      
-      *parsed = silc_realloc(*parsed, sizeof(**parsed) * (argc + 1));
-      *parsed_lens = silc_realloc(*parsed_lens, 
-                                 sizeof(**parsed_lens) * (argc + 1));
-      (*parsed)[argc] = silc_calloc(len + 1, sizeof(char));
-      memcpy((*parsed)[argc], cp, len);
-      (*parsed_lens)[argc] = len;
-      argc++;
-
-      cp += len;
-      if (strlen(cp) == 0)
-       break;
-      else
-       cp++;
-    }
-  }
-
-  /* Save argument types. Protocol defines all argument types but
-     this implementation makes sure that they are always in correct
-     order hence this simple code. */
-  *parsed_types = silc_calloc(argc, sizeof(**parsed_types));
-  for (i = 0; i < argc; i++)
-    (*parsed_types)[i] = i;
-
-  *parsed_num = argc;
-}
-
-/* Updates clock on the screen every minute. */
-
-SILC_TASK_CALLBACK(silc_client_update_clock)
-{
-  SilcClient client = (SilcClient)context;
-
-  /* Update the clock on the screen */
-  silc_screen_print_clock(client->screen);
-
-  /* Re-register this same task */
-  silc_task_register(qptr, 0, silc_client_update_clock, context, 
-                    silc_client_time_til_next_min(), 0,
-                    SILC_TASK_TIMEOUT,
-                    SILC_TASK_PRI_LOW);
-
-  silc_screen_refresh_win(client->screen->input_win);
-}
-
-/* Runs commands user configured in configuration file. This is
-   called when initializing client. */
-
-SILC_TASK_CALLBACK(silc_client_run_commands)
-{
-  SilcClient client = (SilcClient)context;
-  SilcClientConfigSectionCommand *cs;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  cs = client->config->commands;
-  while(cs) {
-    unsigned int argc = 0;
-    unsigned char **argv, *tmpcmd;
-    unsigned int *argv_lens, *argv_types;
-    SilcClientCommand *cmd;
-    SilcClientCommandContext ctx;
-
-    /* Get the command */
-    tmpcmd = silc_client_parse_command(cs->command);
-
-    for (cmd = silc_command_list; cmd->name; cmd++) {
-      if (!strcmp(cmd->name, tmpcmd))
-       break;
-    }
-    
-    if (cmd->name == NULL) {
-      silc_say(client, "Invalid command: %s", tmpcmd);
-      silc_free(tmpcmd);
-      continue;
-    }
-    
-    /* Now parse all arguments */
-    silc_client_parse_command_line(cs->command, &argv, &argv_lens, 
-                                  &argv_types, &argc, cmd->max_args);
-    silc_free(tmpcmd);
-
-    SILC_LOG_DEBUG(("Exeuting command: %s", cmd->name));
-
-    /* Allocate command context. This and its internals must be free'd 
-       by the command routine receiving it. */
-    ctx = silc_calloc(1, sizeof(*ctx));
-    ctx->client = client;
-    ctx->sock = client->current_win->sock;
-    ctx->argc = argc;
-    ctx->argv = argv;
-    ctx->argv_lens = argv_lens;
-    ctx->argv_types = argv_types;
-
-    /* Execute command */
-    (*cmd->cb)(ctx);
-
-    cs = cs->next;
-  }
-}
-
-/* Internal context for connection process. This is needed as we
-   doing asynchronous connecting. */
-typedef struct {
-  SilcClient client;
-  SilcTask task;
-  int sock;
-  char *host;
-  int port;
-  int tries;
-} SilcClientInternalConnectContext;
-
-static int 
-silc_client_connect_to_server_internal(SilcClientInternalConnectContext *ctx)
-{
-  int sock;
-
-  /* XXX In the future we should give up this non-blocking connect all
-     together and use threads instead. */
-  /* Create connection to server asynchronously */
-  sock = silc_net_create_connection_async(ctx->port, ctx->host);
-  if (sock < 0)
-    return -1;
-
-  /* Register task that will receive the async connect and will
-     read the result. */
-  ctx->task = silc_task_register(ctx->client->io_queue, sock, 
-                                silc_client_connect_to_server_start,
-                                (void *)ctx, 0, 0, 
-                                SILC_TASK_FD,
-                                SILC_TASK_PRI_NORMAL);
-  silc_task_reset_iotype(ctx->task, SILC_TASK_WRITE);
-  silc_schedule_set_listen_fd(sock, ctx->task->iomask);
-
-  ctx->sock = sock;
-
-  return sock;
-}
-
-/* Connects to remote server */
-
-int silc_client_connect_to_server(SilcClient client, int port,
-                                 char *host)
-{
-  SilcClientInternalConnectContext *ctx;
-
-  SILC_LOG_DEBUG(("Connecting to port %d of server %s",
-                 port, host));
-
-  silc_say(client, "Connecting to port %d of server %s", port, host);
-
-  client->current_win->remote_host = strdup(host);
-  client->current_win->remote_port = port;
-
-  /* Allocate internal context for connection process. This is
-     needed as we are doing async connecting. */
-  ctx = silc_calloc(1, sizeof(*ctx));
-  ctx->client = client;
-  ctx->host = strdup(host);
-  ctx->port = port;
-  ctx->tries = 0;
-
-  /* Do the actual connecting process */
-  return silc_client_connect_to_server_internal(ctx);
-}
-
-/* Start of the connection to the remote server. This is called after
-   succesful TCP/IP connection has been established to the remote host. */
-
-SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
-{
-  SilcClientInternalConnectContext *ctx =
-    (SilcClientInternalConnectContext *)context;
-  SilcClient client = ctx->client;
-  SilcProtocol protocol;
-  SilcClientKEInternalContext *proto_ctx;
-  int opt, opt_len = sizeof(opt);
-
-  SILC_LOG_DEBUG(("Start"));
-
-  /* Check the socket status as it might be in error */
-  getsockopt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
-  if (opt != 0) {
-    if (ctx->tries < 2) {
-      /* Connection failed but lets try again */
-      silc_say(ctx->client, "Could not connect to server %s: %s",
-              ctx->host, strerror(opt));
-      silc_say(client, "Connecting to port %d of server %s resumed", 
-              ctx->port, ctx->host);
-
-      /* Unregister old connection try */
-      silc_schedule_unset_listen_fd(fd);
-      silc_net_close_connection(fd);
-      silc_task_unregister(client->io_queue, ctx->task);
-
-      /* Try again */
-      silc_client_connect_to_server_internal(ctx);
-      ctx->tries++;
-    } else {
-      /* Connection failed and we won't try anymore */
-      silc_say(ctx->client, "Could not connect to server %s: %s",
-              ctx->host, strerror(opt));
-      silc_schedule_unset_listen_fd(fd);
-      silc_net_close_connection(fd);
-      silc_task_unregister(client->io_queue, ctx->task);
-      silc_free(ctx);
-    }
-    return;
-  }
-
-  silc_schedule_unset_listen_fd(fd);
-  silc_task_unregister(client->io_queue, ctx->task);
-  silc_free(ctx);
-
-  /* Allocate new socket connection object */
-  silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER, 
-                   (void *)client->current_win, 
-                   &client->current_win->sock);
-  if (client->current_win->sock == NULL) {
-    silc_say(client, "Error: Could not allocate connection socket");
-    silc_net_close_connection(fd);
-    return;
-  }
-  client->current_win->sock->hostname = client->current_win->remote_host;
-  client->current_win->sock->port = client->current_win->remote_port;
-
-  /* Allocate internal Key Exchange context. This is sent to the
-     protocol as context. */
-  proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
-  proto_ctx->client = (void *)client;
-  proto_ctx->sock = client->current_win->sock;
-  proto_ctx->rng = client->rng;
-  proto_ctx->responder = FALSE;
-
-  /* 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, 
-                     &protocol, (void *)proto_ctx,
-                     silc_client_connect_to_server_second);
-  if (!protocol) {
-    silc_say(client, "Error: Could not start authentication protocol");
-    return;
-  }
-  client->current_win->sock->protocol = protocol;
-
-  /* Register the connection for network input and output. This sets
-     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 
-     be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
-     later when outgoing data is available. */
-  context = (void *)client;
-  SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(fd);
-
-  /* Execute the protocol */
-  protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
-}
-
-/* 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 *)protocol->context;
-  SilcClient client = (SilcClient)ctx->client;
-  SilcSocketConnection sock = NULL;
-  SilcClientConnAuthInternalContext *proto_ctx;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  if (protocol->state == SILC_PROTOCOL_STATE_ERROR) {
-    /* Error occured during protocol */
-    SILC_LOG_DEBUG(("Error during KE protocol"));
-    silc_protocol_free(protocol);
-    if (ctx->packet)
-      silc_buffer_free(ctx->packet);
-    if (ctx->ske)
-      silc_ske_free(ctx->ske);
-    silc_free(ctx);
-    sock->protocol = NULL;
-    return;
-  }
-
-  /* Allocate internal context for the authentication protocol. This
-     is sent as context for the protocol. */
-  proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
-  proto_ctx->client = (void *)client;
-  proto_ctx->sock = sock = ctx->sock;
-  proto_ctx->ske = ctx->ske;   /* Save SKE object from previous protocol */
-
-  /* Resolve the authentication method to be used in this connection */
-  proto_ctx->auth_meth = SILC_PROTOCOL_CONN_AUTH_NONE;
-  if (client->config->conns) {
-    SilcClientConfigSectionConnection *conn = NULL;
-
-    /* Check if we find a match from user configured connections */
-    conn = silc_client_config_find_connection(client->config,
-                                             sock->hostname,
-                                             sock->port);
-    if (conn) {
-      /* Match found. Use the configured authentication method */
-      proto_ctx->auth_meth = conn->auth_meth;
-      if (conn->auth_data) {
-       proto_ctx->auth_data = strdup(conn->auth_data);
-       proto_ctx->auth_data_len = strlen(conn->auth_data);
-      }
-    } else {
-      /* No match found. Resolve by sending AUTH_REQUEST to server */
-      proto_ctx->auth_meth = SILC_PROTOCOL_CONN_AUTH_NONE;
-    }
-  } else {
-    /* XXX Resolve by sending AUTH_REQUEST to server */
-    proto_ctx->auth_meth = SILC_PROTOCOL_CONN_AUTH_NONE;
-  }
-
-  /* Free old protocol as it is finished now */
-  silc_protocol_free(protocol);
-  if (ctx->packet)
-    silc_buffer_free(ctx->packet);
-  silc_free(ctx);
-  /* silc_free(ctx->keymat....); */
-  sock->protocol = NULL;
-
-  /* Allocate the authentication protocol. This is allocated here
-     but we won't start it yet. We will be receiving party of this
-     protocol thus we will wait that connecting party will make
-     their first move. */
-  silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH, 
-                     &sock->protocol, (void *)proto_ctx, 
-                     silc_client_connect_to_server_final);
-
-  /* Execute the protocol */
-  sock->protocol->execute(client->timeout_queue, 0, sock->protocol, fd, 0, 0);
-}
-
-/* Finalizes the connection to the remote SILC server. This is called
-   after authentication protocol has been completed. This send our
-   user information to the server to receive our client ID from
-   server. */
-
-SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
-{
-  SilcProtocol protocol = (SilcProtocol)context;
-  SilcClientConnAuthInternalContext *ctx = 
-    (SilcClientConnAuthInternalContext *)protocol->context;
-  SilcClient client = (SilcClient)ctx->client;
-  SilcClientWindow win = (SilcClientWindow)ctx->sock->user_data;
-  SilcBuffer packet;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  if (protocol->state == SILC_PROTOCOL_STATE_ERROR) {
-    /* Error occured during protocol */
-    SILC_LOG_DEBUG(("Error during authentication protocol"));
-    silc_protocol_free(protocol);
-    if (ctx->auth_data)
-      silc_free(ctx->auth_data);
-    if (ctx->ske)
-      silc_ske_free(ctx->ske);
-    silc_free(ctx);
-    win->sock->protocol = NULL;
-    return;
-  }
-
-  /* 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) + 
-                            strlen(client->realname));
-  silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
-  silc_buffer_format(packet,
-                    SILC_STR_UI_SHORT(strlen(client->username)),
-                    SILC_STR_UI_XNSTRING(client->username,
-                                         strlen(client->username)),
-                    SILC_STR_UI_SHORT(strlen(client->realname)),
-                    SILC_STR_UI_XNSTRING(client->realname,
-                                         strlen(client->realname)),
-                    SILC_STR_END);
-
-  /* Send the packet */
-  silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
-                         NULL, 0, NULL, NULL, 
-                         packet->data, packet->len, TRUE);
-  silc_buffer_free(packet);
-
-  silc_say(client, "Connected to port %d of host %s",
-          win->remote_port, win->remote_host);
-
-  client->screen->bottom_line->connection = win->remote_host;
-  silc_screen_print_bottom_line(client->screen, 0);
-
-  silc_protocol_free(protocol);
-  if (ctx->auth_data)
-    silc_free(ctx->auth_data);
-  if (ctx->ske)
-    silc_ske_free(ctx->ske);
-  silc_free(ctx);
-  win->sock->protocol = NULL;
-}
-
-typedef struct {
-  SilcPacketContext *packetdata;
-  SilcSocketConnection sock;
-  SilcClient client;
-} SilcClientInternalPacket;
-
-SILC_TASK_CALLBACK(silc_client_packet_process)
-{
-  SilcClient client = (SilcClient)context;
-  SilcSocketConnection sock = NULL;
-  int ret, packetlen, paddedlen;
-
-  SILC_LOG_DEBUG(("Processing packet"));
-
-  SILC_CLIENT_GET_SOCK(client, fd, sock);
-  if (sock == NULL)
-    return;
-
-  /* Packet sending */
-  if (type == SILC_TASK_WRITE) {
-    SILC_LOG_DEBUG(("Writing data to connection"));
-
-    if (sock->outbuf->data - sock->outbuf->head)
-      silc_buffer_push(sock->outbuf, 
-                      sock->outbuf->data - sock->outbuf->head);
-
-    /* Write the packet out to the connection */
-    ret = silc_packet_write(fd, sock->outbuf);
-
-    /* If returned -2 could not write to connection now, will do
-       it later. */
-    if (ret == -2)
-      return;
-    
-    /* Error */
-    if (ret == -1)
-      SILC_LOG_ERROR(("Packet dropped"));
-
-    /* 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. 
-       This call clears the output setting and sets it only for input. */
-    SILC_CLIENT_SET_CONNECTION_FOR_INPUT(fd);
-    SILC_UNSET_OUTBUF_PENDING(sock);
-
-    return;
-  }
-
-  /* Packet receiving */
-  if (type == SILC_TASK_READ) {
-    SILC_LOG_DEBUG(("Reading data from connection"));
-
-    /* Allocate the incoming data buffer if not done already. */
-    if (!sock->inbuf)
-      sock->inbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE);
-
-    /* Read some data from connection */
-    ret = silc_packet_read(fd, sock->inbuf);
-    
-    /* If returned -2 data was not available now, will read it later. */
-    if (ret == -2)
-      return;
-    
-    /* Error */
-    if (ret == -1) {
-      SILC_LOG_ERROR(("Packet dropped"));
-      return;
-    }
-    
-    /* EOF */
-    if (ret == 0) {
-      SILC_LOG_DEBUG(("Read EOF"));
-
-      /* If connection is disconnecting already we will finally
-        close the connection */
-      if (SILC_IS_DISCONNECTING(sock)) {
-       silc_client_close_connection(client, sock);
-       return;
-      }
-      
-      silc_say(client, "Connection closed: premature EOF");
-      SILC_LOG_DEBUG(("Premature EOF from connection %d", sock->sock));
-
-      silc_client_close_connection(client, sock);
-      return;
-    }
-
-    /* Check whether we received a whole packet. If reading went without
-       errors we either read a whole packet or the read packet is 
-       incorrect and will be dropped. */
-    SILC_PACKET_LENGTH(sock->inbuf, packetlen, paddedlen);
-    if (sock->inbuf->len < paddedlen || (packetlen < SILC_PACKET_MIN_LEN)) {
-      SILC_LOG_DEBUG(("Received incorrect packet, dropped"));
-      silc_buffer_clear(sock->inbuf);
-      return;
-    }
-    
-    /* Decrypt a packet coming from server connection */
-    if (sock->type == SILC_SOCKET_TYPE_SERVER ||
-       sock->type == SILC_SOCKET_TYPE_ROUTER) {
-      SilcClientWindow win = (SilcClientWindow)sock->user_data;
-      SilcClientInternalPacket *packet;
-      int mac_len = 0;
-
-      if (win->hmac)
-       mac_len = win->hmac->hash->hash->hash_len;
-
-      if (sock->inbuf->len - 2 > (paddedlen + mac_len)) {
-       /* Received possibly many packets at once */
-
-       while(sock->inbuf->len > 0) {
-         SILC_PACKET_LENGTH(sock->inbuf, packetlen, paddedlen);
-         if (sock->inbuf->len < paddedlen) {
-           SILC_LOG_DEBUG(("Received incorrect packet, dropped"));
-           return;
-         }
-
-         paddedlen += 2;
-         packet = silc_calloc(1, sizeof(*packet));
-         packet->client = client;
-         packet->sock = sock;
-         packet->packetdata = silc_calloc(1, sizeof(*packet->packetdata));
-         packet->packetdata->buffer = silc_buffer_alloc(paddedlen + mac_len);
-         silc_buffer_pull_tail(packet->packetdata->buffer, 
-                               SILC_BUFFER_END(packet->packetdata->buffer));
-         silc_buffer_put(packet->packetdata->buffer, sock->inbuf->data, 
-                         paddedlen + mac_len);
-
-         SILC_LOG_HEXDUMP(("Incoming packet, len %d", 
-                           packet->packetdata->buffer->len),
-                          packet->packetdata->buffer->data, 
-                          packet->packetdata->buffer->len);
-         SILC_LOG_DEBUG(("Packet from server %s, "
-                         "server type %d, packet length %d", 
-                         win->remote_host, win->remote_type, paddedlen));
-
-         /* If this packet is for the current active connection we will
-            parse the packet right away to get it quickly on the screen.
-            Otherwise, it will be parsed with a timeout as the data is
-            for inactive window (which might not be visible at all). */
-         if (SILC_CLIENT_IS_CURRENT_WIN(client, win)) {
-           /* Parse it real soon */
-           silc_task_register(client->timeout_queue, fd, 
-                              silc_client_packet_parse,
-                              (void *)packet, 0, 1, 
-                              SILC_TASK_TIMEOUT,
-                              SILC_TASK_PRI_NORMAL);
-         } else {
-           /* Parse the packet with timeout */
-           silc_task_register(client->timeout_queue, fd, 
-                              silc_client_packet_parse,
-                              (void *)packet, 0, 200000, 
-                              SILC_TASK_TIMEOUT,
-                              SILC_TASK_PRI_NORMAL);
-         }
-
-         /* Pull the packet from inbuf thus we'll get the next one
-            in the inbuf. */
-         silc_buffer_pull(sock->inbuf, paddedlen);
-         if (win->hmac)
-           silc_buffer_pull(sock->inbuf, mac_len);
-       }
-       silc_buffer_clear(sock->inbuf);
-       return;
-      } else {
-       /* Received one packet */
-       
-       SILC_LOG_HEXDUMP(("An incoming packet, len %d", sock->inbuf->len),
-                        sock->inbuf->data, sock->inbuf->len);
-       SILC_LOG_DEBUG(("Packet from server %s, "
-                       "server type %d, packet length %d", 
-                       win->remote_host, win->remote_type, paddedlen));
-       
-       packet = silc_calloc(1, sizeof(*packet));
-       packet->client = client;
-       packet->sock = sock;
-       packet->packetdata = silc_calloc(1, sizeof(*packet->packetdata));
-       packet->packetdata->buffer = silc_buffer_copy(sock->inbuf);
-       silc_buffer_clear(sock->inbuf);
-
-       /* If this packet is for the current active connection we will
-          parse the packet right away to get it quickly on the screen.
-          Otherwise, it will be parsed with a timeout as the data is
-          for inactive window (which might not be visible at all). */
-       if (SILC_CLIENT_IS_CURRENT_WIN(client, win)) {
-         /* Parse it real soon */
-         silc_task_register(client->timeout_queue, fd, 
-                            silc_client_packet_parse,
-                            (void *)packet, 0, 1, 
-                            SILC_TASK_TIMEOUT,
-                            SILC_TASK_PRI_NORMAL);
-         return;
-       } else {
-         /* Parse the packet with timeout */
-         silc_task_register(client->timeout_queue, fd, 
-                            silc_client_packet_parse,
-                            (void *)packet, 0, 200000, 
-                            SILC_TASK_TIMEOUT,
-                            SILC_TASK_PRI_NORMAL);
-         return;
-       }
-      }
-    }
-  }
-  
-  SILC_LOG_ERROR(("Weird, nothing happened - ignoring"));
-}
-
-/* Checks MAC in the packet. Returns TRUE if MAC is Ok. This is called
-   after packet has been totally decrypted and parsed. */
-
-static int silc_client_packet_check_mac(SilcClient client,
-                                       SilcSocketConnection sock,
-                                       SilcBuffer buffer)
-{
-  SilcClientWindow win = (SilcClientWindow)sock->user_data;
-
-  /* Check MAC */
-  if (win->hmac) {
-    int headlen = buffer->data - buffer->head, mac_len;
-    unsigned char *packet_mac, mac[32];
-    
-    SILC_LOG_DEBUG(("Verifying MAC"));
-
-    mac_len = win->hmac->hash->hash->hash_len;
-
-    silc_buffer_push(buffer, headlen);
-
-    /* Take mac from packet */
-    packet_mac = buffer->tail;
-    
-    /* Make MAC and compare */
-    memset(mac, 0, sizeof(mac));
-    silc_hmac_make_with_key(win->hmac, 
-                           buffer->data, buffer->len,
-                           win->hmac_key, win->hmac_key_len, mac);
-#if 0
-    SILC_LOG_HEXDUMP(("PMAC"), packet_mac, mac_len);
-    SILC_LOG_HEXDUMP(("CMAC"), mac, mac_len);
-#endif
-    if (memcmp(mac, packet_mac, mac_len)) {
-      SILC_LOG_DEBUG(("MAC failed"));
-      return FALSE;
-    }
-    
-    SILC_LOG_DEBUG(("MAC is Ok"));
-    memset(mac, 0, sizeof(mac));
-
-    silc_buffer_pull(buffer, headlen);
-  }
-  
-  return TRUE;
-}
-
-/* Decrypts rest of the packet (after decrypting just the SILC header).
-   After calling this function the packet is ready to be parsed by calling 
-   silc_packet_parse. */
-
-static int silc_client_packet_decrypt_rest(SilcClient client, 
-                                          SilcSocketConnection sock,
-                                          SilcBuffer buffer)
-{
-  SilcClientWindow win = (SilcClientWindow)sock->user_data;
-  unsigned int mac_len = 0;
-  
-  /* Decrypt */
-  if (win && win->receive_key) {
-
-    /* Pull MAC from packet before decryption */
-    if (win->hmac) {
-      mac_len = win->hmac->hash->hash->hash_len;
-      if ((buffer->len - mac_len) > SILC_PACKET_MIN_LEN) {
-       silc_buffer_push_tail(buffer, mac_len);
-      } else {
-       SILC_LOG_DEBUG(("Bad MAC length in packet, packet dropped"));
-       return FALSE;
-      }
-    }
-
-    SILC_LOG_DEBUG(("Decrypting rest of the packet"));
-
-    /* Decrypt rest of the packet */
-    silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
-    silc_packet_decrypt(win->receive_key, buffer, buffer->len);
-    silc_buffer_push(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
-
-    SILC_LOG_HEXDUMP(("Fully decrypted packet, len %d", buffer->len),
-                    buffer->data, buffer->len);
-  }
-
-  return TRUE;
-}
-
-/* Decrypts rest of the SILC Packet header that has been decrypted partly
-   already. This decrypts the padding of the packet also.  After calling 
-   this function the packet is ready to be parsed by calling function 
-   silc_packet_parse. This is used in special packet reception. */
-
-static int silc_client_packet_decrypt_rest_special(SilcClient client, 
-                                                 SilcSocketConnection sock,
-                                                 SilcBuffer buffer)
-{
-  SilcClientWindow win = (SilcClientWindow)sock->user_data;
-  unsigned int mac_len = 0;
-
-  /* Decrypt rest of the header plus padding */
-  if (win && win->receive_key) {
-    unsigned short truelen, len1, len2, padlen;
-
-    /* Pull MAC from packet before decryption */
-    if (win->hmac) {
-      mac_len = win->hmac->hash->hash->hash_len;
-      if ((buffer->len - mac_len) > SILC_PACKET_MIN_LEN) {
-       silc_buffer_push_tail(buffer, mac_len);
-      } else {
-       SILC_LOG_DEBUG(("Bad MAC length in packet, packet dropped"));
-       return FALSE;
-      }
-    }
-  
-    SILC_LOG_DEBUG(("Decrypting rest of the header"));
-
-    SILC_GET16_MSB(len1, &buffer->data[4]);
-    SILC_GET16_MSB(len2, &buffer->data[6]);
-
-    truelen = SILC_PACKET_HEADER_LEN + len1 + len2;
-    padlen = SILC_PACKET_PADLEN(truelen);
-    len1 = (truelen + padlen) - (SILC_PACKET_MIN_HEADER_LEN - 2);
-
-    silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
-    SILC_LOG_HEXDUMP(("XXX"), buffer->data, buffer->len);
-    silc_packet_decrypt(win->receive_key, buffer, len1);
-    silc_buffer_push(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
-    SILC_LOG_HEXDUMP(("XXX"), buffer->data, buffer->len);
-  }
-
-  return TRUE;
-}
-
-/* Parses whole packet, received earlier. */
-
-SILC_TASK_CALLBACK(silc_client_packet_parse)
-{
-  SilcClientInternalPacket *packet = (SilcClientInternalPacket *)context;
-  SilcBuffer buffer = packet->packetdata->buffer;
-  SilcClient client = packet->client;
-  SilcSocketConnection sock = packet->sock;
-  SilcClientWindow win = (SilcClientWindow)sock->user_data;
-  int ret;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  /* Decrypt start of the packet header */
-  if (win && win->receive_key)
-    silc_packet_decrypt(win->receive_key, buffer, SILC_PACKET_MIN_HEADER_LEN);
-
-  /* If the packet type is not any special type lets decrypt rest
-     of the packet here. */
-  if (buffer->data[3] != SILC_PACKET_CHANNEL_MESSAGE &&
-      buffer->data[3] != SILC_PACKET_PRIVATE_MESSAGE) {
-  normal:
-    /* Normal packet, decrypt rest of the packet */
-    if (!silc_client_packet_decrypt_rest(client, sock, buffer))
-      goto out;
-
-    /* Parse the packet. Packet type is returned. */
-    ret = silc_packet_parse(packet->packetdata);
-    if (ret == SILC_PACKET_NONE)
-      goto out;
-
-    /* Check MAC */
-    if (!silc_client_packet_check_mac(client, sock, buffer))
-      goto out;
-  } else {
-    /* If private message key is not set for private message it is
-       handled as normal packet. Go back up. */
-    if (buffer->data[3] == SILC_PACKET_PRIVATE_MESSAGE &&
-       !(buffer->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY))
-      goto normal;
-
-    /* Packet requires special handling, decrypt rest of the header.
-       This only decrypts. This does not do any MAC checking, it must
-       be done individually later when doing the special processing. */
-    silc_client_packet_decrypt_rest_special(client, sock, buffer);
-
-    /* Parse the packet header in special way as this is "special"
-       packet type. */
-    ret = silc_packet_parse_special(packet->packetdata);
-    if (ret == SILC_PACKET_NONE)
-      goto out;
-  }
-
-  /* Parse the incoming packet type */
-  silc_client_packet_parse_type(client, sock, packet->packetdata);
-
- out:
-  silc_buffer_clear(packet->packetdata->buffer);
-  silc_free(packet->packetdata);
-  silc_free(packet);
-}
-
-/* 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, 
-                                  SilcSocketConnection sock,
-                                  SilcPacketContext *packet)
-{
-  SilcBuffer buffer = packet->buffer;
-  SilcPacketType type = packet->type;
-
-  SILC_LOG_DEBUG(("Parsing packet type %d", type));
-
-  /* Parse the packet type */
-  switch(type) {
-  case SILC_PACKET_DISCONNECT:
-    silc_client_disconnected_by_server(client, sock, buffer);
-    break;
-  case SILC_PACKET_SUCCESS:
-    /*
-     * Success received for something. For now we can have only
-     * one protocol for connection executing at once hence this
-     * success message is for whatever protocol is executing currently.
-     */
-    if (sock->protocol) {
-      sock->protocol->execute(client->timeout_queue, 0,
-                             sock->protocol, sock->sock, 0, 0);
-    }
-    break;
-  case SILC_PACKET_FAILURE:
-    /*
-     * 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.
-     */
-    if (sock->protocol) {
-      sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
-      sock->protocol->execute(client->timeout_queue, 0,
-                             sock->protocol, sock->sock, 0, 0);
-    }
-    break;
-  case SILC_PACKET_REJECT:
-    break;
-
-  case SILC_PACKET_NOTIFY:
-    /*
-     * Received notify message 
-     */
-    silc_client_notify_by_server(client, sock, buffer);
-    break;
-
-  case SILC_PACKET_ERROR:
-    /*
-     * Received error message
-     */
-    silc_client_error_by_server(client, sock, buffer);
-    break;
-
-  case SILC_PACKET_CHANNEL_MESSAGE:
-    /*
-     * Received message to (from, actually) a channel
-     */
-    silc_client_channel_message(client, sock, packet);
-    break;
-  case SILC_PACKET_CHANNEL_KEY:
-    /*
-     * Received key for a channel. By receiving this key the client will be
-     * able to talk to the channel it has just joined. This can also be
-     * a new key for existing channel as keys expire peridiocally.
-     */
-    silc_client_receive_channel_key(client, sock, buffer);
-    break;
-
-  case SILC_PACKET_PRIVATE_MESSAGE:
-    /*
-     * Received private message
-     */
-    {
-      SilcClientCommandReplyContext ctx;
-      ctx = silc_calloc(1, sizeof(*ctx));
-      ctx->client = client;
-      ctx->sock = sock;
-      ctx->context = buffer;   /* kludge */
-      silc_client_command_reply_msg((void *)ctx);
-    }
-    break;
-  case SILC_PACKET_PRIVATE_MESSAGE_KEY:
-    /*
-     * Received private message key
-     */
-    break;
-
-  case SILC_PACKET_COMMAND_REPLY:
-    /*
-     * Recived reply for a command
-     */
-    silc_client_command_reply_process(client, sock, buffer);
-    break;
-
-  case SILC_PACKET_KEY_EXCHANGE:
-    if (sock->protocol) {
-      SilcClientKEInternalContext *proto_ctx = 
-       (SilcClientKEInternalContext *)sock->protocol->context;
-
-      proto_ctx->packet = buffer;
-
-      /* Let the protocol handle the packet */
-      sock->protocol->execute(client->timeout_queue, 0,
-                             sock->protocol, sock->sock, 0, 0);
-    } else {
-      SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
-                     "protocol active, packet dropped."));
-
-      /* XXX Trigger KE protocol?? Rekey actually! */
-    }
-    break;
-
-  case SILC_PACKET_KEY_EXCHANGE_1:
-    if (sock->protocol) {
-
-    } else {
-      SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
-                     "protocol active, packet dropped."));
-    }
-    break;
-  case SILC_PACKET_KEY_EXCHANGE_2:
-    if (sock->protocol) {
-      SilcClientKEInternalContext *proto_ctx = 
-       (SilcClientKEInternalContext *)sock->protocol->context;
-
-      if (proto_ctx->packet)
-       silc_buffer_free(proto_ctx->packet);
-
-      proto_ctx->packet = buffer;
-
-      /* Let the protocol handle the packet */
-      sock->protocol->execute(client->timeout_queue, 0,
-                             sock->protocol, sock->sock, 0, 0);
-    } else {
-      SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
-                     "protocol active, packet dropped."));
-    }
-    break;
-
-  case SILC_PACKET_NEW_ID:
-    {
-      /*
-       * Received new ID from server. This packet is received at
-       * 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.
-       */
-      unsigned char *id_string;
-      unsigned short id_type;
-      
-      silc_buffer_unformat(buffer,
-                          SILC_STR_UI_SHORT(&id_type),
-                          SILC_STR_UI16_STRING_ALLOC(&id_string),
-                          SILC_STR_END);
-      
-      if ((SilcIdType)id_type != SILC_ID_CLIENT)
-       break;
-
-      silc_client_receive_new_id(client, sock, id_string);
-      silc_free(id_string);
-      break;
-    }
-
-  default:
-    SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
-    break;
-  }
-}
-
-/* Internal routine that sends packet or marks packet to be sent. This
-   is used directly only in special cases. Normal cases should use
-   silc_server_packet_send. Returns < 0 on error. */
-
-static int silc_client_packet_send_real(SilcClient client,
-                                       SilcSocketConnection sock,
-                                       int force_send)
-{
-  /* Send now if forced to do so */
-  if (force_send == TRUE) {
-    int ret;
-    SILC_LOG_DEBUG(("Forcing packet send, packet sent immediately"));
-    ret = silc_packet_write(sock->sock, sock->outbuf);
-
-    if (ret == -1)
-      SILC_LOG_ERROR(("Packet dropped"));
-    if (ret != -2)
-      return ret;
-
-    SILC_LOG_DEBUG(("Could not force the send, packet put to queue"));
-  }  
-
-  SILC_LOG_DEBUG(("Packet in queue"));
-
-  /* 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). 
-     Actual data sending is performed by silc_client_packet_process. */
-  SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(sock->sock);
-
-  /* Mark to socket that data is pending in outgoing buffer. This flag
-     is needed if new data is added to the buffer before the earlier
-     put data is sent to the network. */
-  SILC_SET_OUTBUF_PENDING(sock);
-
-  return 0;
-}
-
-/* Prepare outgoing data buffer for packet sending. */
-
-static void silc_client_packet_send_prepare(SilcClient client,
-                                           SilcSocketConnection sock,
-                                           unsigned int header_len,
-                                           unsigned int padlen,
-                                           unsigned int data_len)
-{
-  int totlen, oldlen;
-
-  totlen = header_len + padlen + data_len;
-
-  /* Prepare the outgoing buffer for packet sending. */
-  if (!sock->outbuf) {
-    /* Allocate new buffer. This is done only once per connection. */
-    SILC_LOG_DEBUG(("Allocating outgoing data buffer"));
-    
-    sock->outbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE);
-    silc_buffer_pull_tail(sock->outbuf, totlen);
-    silc_buffer_pull(sock->outbuf, header_len + padlen);
-  } else {
-    if (SILC_IS_OUTBUF_PENDING(sock)) {
-      /* There is some pending data in the buffer. */
-
-      if ((sock->outbuf->end - sock->outbuf->tail) < data_len) {
-       SILC_LOG_DEBUG(("Reallocating outgoing data buffer"));
-       /* XXX: not done yet */
-      }
-      oldlen = sock->outbuf->len;
-      silc_buffer_pull_tail(sock->outbuf, totlen);
-      silc_buffer_pull(sock->outbuf, header_len + padlen + oldlen);
-    } else {
-      /* Buffer is free for use */
-      silc_buffer_clear(sock->outbuf);
-      silc_buffer_pull_tail(sock->outbuf, totlen);
-      silc_buffer_pull(sock->outbuf, header_len + padlen);
-    }
-  }
-}
-
-/* Sends packet. This doesn't actually send the packet instead it assembles
-   it and marks it to be sent. However, if force_send is TRUE the packet
-   is sent immediately. if dst_id, cipher and hmac are NULL those parameters
-   will be derived from sock argument. Otherwise the valid arguments sent
-   are used. */
-
-void silc_client_packet_send(SilcClient client, 
-                            SilcSocketConnection sock,
-                            SilcPacketType type, 
-                            void *dst_id,
-                            SilcIdType dst_id_type,
-                            SilcCipher cipher,
-                            SilcHmac hmac,
-                            unsigned char *data, 
-                            unsigned int data_len, 
-                            int force_send)
-{
-  SilcPacketContext packetdata;
-  unsigned char *hmac_key = NULL;
-  unsigned int hmac_key_len = 0;
-  unsigned char mac[32];
-  unsigned int mac_len = 0;
-
-  SILC_LOG_DEBUG(("Sending packet, type %d", type));
-
-  /* Get data used in the packet sending, keys and stuff */
-  if ((!cipher || !hmac || !dst_id) && sock->user_data) {
-    if (!cipher && ((SilcClientWindow)sock->user_data)->send_key)
-      cipher = ((SilcClientWindow)sock->user_data)->send_key;
-    if (!hmac && ((SilcClientWindow)sock->user_data)->hmac) {
-      hmac = ((SilcClientWindow)sock->user_data)->hmac;
-      mac_len = hmac->hash->hash->hash_len;
-      hmac_key = ((SilcClientWindow)sock->user_data)->hmac_key;
-      hmac_key_len = ((SilcClientWindow)sock->user_data)->hmac_key_len;
-    }
-    if (!dst_id && ((SilcClientWindow)sock->user_data)->remote_id) {
-      dst_id = ((SilcClientWindow)sock->user_data)->remote_id;
-      dst_id_type = SILC_ID_SERVER;
-    }
-  }
-
-  /* Set the packet context pointers */
-  packetdata.flags = 0;
-  packetdata.type = type;
-  if (((SilcClientWindow)sock->user_data)->local_id_data)
-    packetdata.src_id = ((SilcClientWindow)sock->user_data)->local_id_data;
-  else 
-    packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
-  packetdata.src_id_len = SILC_ID_CLIENT_LEN;
-  packetdata.src_id_type = SILC_ID_CLIENT;
-  if (dst_id) {
-    packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
-    packetdata.dst_id_len = silc_id_get_len(dst_id_type);
-    packetdata.dst_id_type = dst_id_type;
-  } else {
-    packetdata.dst_id = NULL;
-    packetdata.dst_id_len = 0;
-    packetdata.dst_id_type = SILC_ID_NONE;
-  }
-  packetdata.rng = client->rng;
-  packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
-    packetdata.src_id_len + packetdata.dst_id_len;
-  packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
-
-  /* Prepare outgoing data buffer for packet sending */
-  silc_client_packet_send_prepare(client, sock, 
-                                 SILC_PACKET_HEADER_LEN +
-                                 packetdata.src_id_len + 
-                                 packetdata.dst_id_len,
-                                 packetdata.padlen,
-                                 data_len);
-
-  SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
-
-  packetdata.buffer = sock->outbuf;
-
-  /* Put the data to the buffer */
-  if (data && data_len)
-    silc_buffer_put(sock->outbuf, data, data_len);
-
-  /* Create the outgoing packet */
-  silc_packet_assemble(&packetdata);
-
-  /* Compute MAC of the packet */
-  if (hmac) {
-    silc_hmac_make_with_key(hmac, sock->outbuf->data, sock->outbuf->len,
-                           hmac_key, hmac_key_len, mac);
-    silc_buffer_put_tail(sock->outbuf, mac, mac_len);
-    memset(mac, 0, sizeof(mac));
-  }
-
-  /* Encrypt the packet */
-  if (cipher)
-    silc_packet_encrypt(cipher, sock->outbuf, sock->outbuf->len);
-
-  /* Pull MAC into the visible data area */
-  if (hmac)
-    silc_buffer_pull_tail(sock->outbuf, mac_len);
-
-  SILC_LOG_HEXDUMP(("Packet, len %d", sock->outbuf->len),
-                  sock->outbuf->data, sock->outbuf->len);
-
-  /* Now actually send the packet */
-  silc_client_packet_send_real(client, sock, force_send);
-}
-
-/* Sends packet to a channel. Packet to channel is always encrypted
-   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. */
-
-void silc_client_packet_send_to_channel(SilcClient client, 
-                                       SilcSocketConnection sock,
-                                       SilcChannelEntry channel,
-                                       unsigned char *data, 
-                                       unsigned int data_len, 
-                                       int force_send)
-{
-  int i;
-  SilcClientWindow win = (SilcClientWindow)sock->user_data;
-  SilcBuffer payload;
-  SilcPacketContext packetdata;
-  unsigned char *hmac_key = NULL;
-  unsigned int hmac_key_len = 0;
-  unsigned char mac[32];
-  unsigned int mac_len = 0;
-  unsigned char *id_string;
-  SilcCipher cipher;
-  SilcHmac hmac;
-
-  SILC_LOG_DEBUG(("Sending packet to channel"));
-
-  if (!channel || !channel->key) {
-    silc_say(client, "Cannot talk to channel: key does not exist");
-    return;
-  }
-
-  /* Generate IV */
-  if (!channel->iv)
-    for (i = 0; i < 16; i++)
-      channel->iv[i] = silc_rng_get_byte(client->rng);
-  else
-    silc_hash_make(client->md5hash, channel->iv, 16, channel->iv);
-
-  /* Encode the channel payload */
-  payload = silc_channel_encode_payload(strlen(win->nickname), win->nickname,
-                                       data_len, data, 16, channel->iv, 
-                                       client->rng);
-  if (!payload) {
-    silc_say(client, 
-            "Error: Could not create packet to be sent to the channel");
-    return;
-  }
-
-  /* Get data used in packet header encryption, keys and stuff. Rest
-     of the packet (the payload) is, however, encrypted with the 
-     specified channel key. */
-  cipher = win->send_key;
-  hmac = win->hmac;
-  mac_len = hmac->hash->hash->hash_len;
-  hmac_key = win->hmac_key;
-  hmac_key_len = win->hmac_key_len;
-  id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
-
-  /* Set the packet context pointers. The destination ID is always
-     the Channel ID of the channel. Server and router will handle the
-     distribution of the packet. */
-  packetdata.flags = 0;
-  packetdata.type = SILC_PACKET_CHANNEL_MESSAGE;
-  packetdata.src_id = win->local_id_data;
-  packetdata.src_id_len = SILC_ID_CLIENT_LEN;
-  packetdata.src_id_type = SILC_ID_CLIENT;
-  packetdata.dst_id = id_string;
-  packetdata.dst_id_len = SILC_ID_CHANNEL_LEN;
-  packetdata.dst_id_type = SILC_ID_CHANNEL;
-  packetdata.rng = client->rng;
-  packetdata.truelen = payload->len + SILC_PACKET_HEADER_LEN + 
-    packetdata.src_id_len + packetdata.dst_id_len;
-  packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
-                                         packetdata.src_id_len +
-                                         packetdata.dst_id_len));
-
-  /* Prepare outgoing data buffer for packet sending */
-  silc_client_packet_send_prepare(client, sock, 
-                                 SILC_PACKET_HEADER_LEN +
-                                 packetdata.src_id_len + 
-                                 packetdata.dst_id_len,
-                                 packetdata.padlen,
-                                 payload->len);
-
-  packetdata.buffer = sock->outbuf;
-
-  /* Encrypt payload of the packet. This is encrypted with the channel key. */
-  channel->channel_key->cipher->encrypt(channel->channel_key->context,
-                                       payload->data, payload->data,
-                                       payload->len - 16, /* -IV_LEN */
-                                       channel->iv);
-
-  SILC_LOG_HEXDUMP(("XXX"), payload->data, payload->len);
-      
-  /* Put the actual encrypted payload data into the buffer. */
-  silc_buffer_put(sock->outbuf, payload->data, payload->len);
-
-  /* Create the outgoing packet */
-  silc_packet_assemble(&packetdata);
-
-  /* Compute MAC of the packet */
-  silc_hmac_make_with_key(hmac, sock->outbuf->data, sock->outbuf->len,
-                         hmac_key, hmac_key_len, mac);
-  silc_buffer_put_tail(sock->outbuf, mac, mac_len);
-  memset(mac, 0, sizeof(mac));
-
-      SILC_LOG_HEXDUMP(("XXX"), sock->outbuf->data, sock->outbuf->len);
-      
-  /* Encrypt the header and padding of the packet. This is encrypted 
-     with normal session key shared with our server. */
-  silc_packet_encrypt(cipher, sock->outbuf, SILC_PACKET_HEADER_LEN + 
-                     packetdata.src_id_len + packetdata.dst_id_len +
-                     packetdata.padlen);
-
-  /* Pull MAC into the visible data area */
-  silc_buffer_pull_tail(sock->outbuf, mac_len);
-
-  SILC_LOG_HEXDUMP(("Packet to channel, len %d", sock->outbuf->len),
-                  sock->outbuf->data, sock->outbuf->len);
-
-  /* Now actually send the packet */
-  silc_client_packet_send_real(client, sock, force_send);
-  silc_buffer_free(payload);
-  silc_free(id_string);
-}
-
-/* Sends private message to remote client. If private message key has
-   not been set with this client then the message will be encrypted using
-   normal session keys. Private messages are special packets in SILC
-   network hence we need this own function for them. This is similiar
-   to silc_client_packet_send_to_channel except that we send private
-   message. */
-
-void silc_client_packet_send_private_message(SilcClient client,
-                                            SilcSocketConnection sock,
-                                            SilcClientEntry client_entry,
-                                            unsigned char *data, 
-                                            unsigned int data_len, 
-                                            int force_send)
-{
-  SilcClientWindow win = (SilcClientWindow)sock->user_data;
-  SilcBuffer buffer;
-  SilcPacketContext packetdata;
-  unsigned char *hmac_key = NULL;
-  unsigned int hmac_key_len = 0;
-  unsigned char mac[32];
-  unsigned int mac_len = 0;
-  unsigned int nick_len;
-  SilcCipher cipher;
-  SilcHmac hmac;
-
-  SILC_LOG_DEBUG(("Sending private message"));
-
-  /* Create private message payload */
-  nick_len = strlen(client->current_win->nickname);
-  buffer = silc_buffer_alloc(2 + nick_len + data_len);
-  silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
-  silc_buffer_format(buffer,
-                    SILC_STR_UI_SHORT(nick_len),
-                    SILC_STR_UI_XNSTRING(client->current_win->nickname,
-                                         nick_len),
-                    SILC_STR_UI_XNSTRING(data, data_len),
-                    SILC_STR_END);
-
-  /* If we don't have private message specific key then private messages
-     are just as any normal packet thus call normal packet sending.  If
-     the key exist then the encryption process is a bit different and
-     will be done in the rest of this function. */
-  if (!client_entry->send_key) {
-    silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE,
-                           client_entry->id, SILC_ID_CLIENT, NULL, NULL,
-                           buffer->data, buffer->len, force_send);
-    goto out;
-  }
-
-  /* We have private message specific key */
-
-  /* Get data used in the encryption */
-  cipher = client_entry->send_key;
-  hmac = win->hmac;
-  mac_len = hmac->hash->hash->hash_len;
-  hmac_key = win->hmac_key;
-  hmac_key_len = win->hmac_key_len;
-
-  /* Set the packet context pointers. */
-  packetdata.flags = 0;
-  packetdata.type = SILC_PACKET_PRIVATE_MESSAGE;
-  packetdata.src_id = win->local_id_data;
-  packetdata.src_id_len = SILC_ID_CLIENT_LEN;
-  packetdata.src_id_type = SILC_ID_CLIENT;
-  if (client_entry)
-    packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
-  else
-    packetdata.dst_id = win->local_id_data;
-  packetdata.dst_id_len = SILC_ID_CLIENT_LEN;
-  packetdata.dst_id_type = SILC_ID_CLIENT;
-  packetdata.rng = client->rng;
-  packetdata.truelen = buffer->len + SILC_PACKET_HEADER_LEN + 
-    packetdata.src_id_len + packetdata.dst_id_len;
-  packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
-                                         packetdata.src_id_len +
-                                         packetdata.dst_id_len));
-
-  /* Prepare outgoing data buffer for packet sending */
-  silc_client_packet_send_prepare(client, sock, 
-                                 SILC_PACKET_HEADER_LEN +
-                                 packetdata.src_id_len + 
-                                 packetdata.dst_id_len,
-                                 packetdata.padlen,
-                                 buffer->len);
-
-  packetdata.buffer = sock->outbuf;
-
-  /* Encrypt payload of the packet. Encrypt with private message specific
-     key if it exist, otherwise with session key. */
-  cipher->cipher->encrypt(cipher->context, buffer->data, buffer->data,
-                         buffer->len, cipher->iv);
-      
-  /* Put the actual encrypted payload data into the buffer. */
-  silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
-
-  /* Create the outgoing packet */
-  silc_packet_assemble(&packetdata);
-
-  /* Compute MAC of the packet */
-  silc_hmac_make_with_key(hmac, sock->outbuf->data, sock->outbuf->len,
-                         hmac_key, hmac_key_len, mac);
-  silc_buffer_put_tail(sock->outbuf, mac, mac_len);
-  memset(mac, 0, sizeof(mac));
-
-  SILC_LOG_HEXDUMP(("XXX"), sock->outbuf->data, sock->outbuf->len);
-      
-  /* Encrypt the header and padding of the packet. */
-  silc_packet_encrypt(cipher, sock->outbuf, SILC_PACKET_HEADER_LEN + 
-                     packetdata.src_id_len + packetdata.dst_id_len +
-                     packetdata.padlen);
-
-  /* Pull MAC into the visible data area */
-  silc_buffer_pull_tail(sock->outbuf, mac_len);
-
-  SILC_LOG_HEXDUMP(("Private message packet, len %d", sock->outbuf->len),
-                  sock->outbuf->data, sock->outbuf->len);
-
-  /* Now actually send the packet */
-  silc_client_packet_send_real(client, sock, force_send);
-  silc_free(packetdata.dst_id);
-
- out:
-  silc_free(buffer);
-}     
-
-/* Closes connection to remote end. Free's all allocated data except
-   for some information such as nickname etc. that are valid at all time. */
-
-void silc_client_close_connection(SilcClient client,
-                                 SilcSocketConnection sock)
-{
-  SilcClientWindow win;
-  int i;
-
-  /* We won't listen for this connection anymore */
-  silc_schedule_unset_listen_fd(sock->sock);
-
-  /* Unregister all tasks */
-  silc_task_unregister_by_fd(client->io_queue, sock->sock);
-  silc_task_unregister_by_fd(client->timeout_queue, sock->sock);
-
-  /* Close the actual connection */
-  silc_net_close_connection(sock->sock);
-
-  silc_say(client, "Closed connection to host %s", sock->hostname ?
-          sock->hostname : sock->ip);
-
-  /* Free everything */
-  if (sock->user_data) {
-    win = (SilcClientWindow)sock->user_data;
-
-    /* Clear ID caches */
-    for (i = 0; i < 96; i++)
-      silc_idcache_del_all(&win->client_id_cache[i], 
-                          win->client_id_cache_count[i]);
-    for (i = 0; i < 96; i++)
-      silc_idcache_del_all(&win->channel_id_cache[i], 
-                          win->channel_id_cache_count[i]);
-
-    /* Free data */
-    if (win->remote_host)
-      silc_free(win->remote_host);
-    if (win->local_id)
-      silc_free(win->local_id);
-    if (win->local_id_data)
-      silc_free(win->local_id_data);
-    if (win->send_key)
-      silc_cipher_free(win->send_key);
-    if (win->receive_key)
-      silc_cipher_free(win->receive_key);
-    if (win->public_key)
-      silc_pkcs_free(win->public_key);
-    if (win->hmac)
-      silc_hmac_free(win->hmac);
-    if (win->hmac_key) {
-      memset(win->hmac_key, 0, win->hmac_key_len);
-      silc_free(win->hmac_key);
-    }
-
-    win->sock = NULL;
-    win->remote_port = 0;
-    win->remote_type = 0;
-    win->send_key = NULL;
-    win->receive_key = NULL;
-    win->public_key = NULL;
-    win->hmac = NULL;
-    win->hmac_key = NULL;
-    win->hmac_key_len = 0;
-    win->local_id = NULL;
-    win->local_id_data = NULL;
-    win->remote_host = NULL;
-  }
-
-  if (sock->protocol) {
-    silc_protocol_free(sock->protocol);
-    sock->protocol = NULL;
-  }
-  silc_socket_free(sock);
-}
-
-/* Called when we receive disconnection packet from server. This 
-   closes our end properly and displays the reason of the disconnection
-   on the screen. */
-
-void silc_client_disconnected_by_server(SilcClient client,
-                                       SilcSocketConnection sock,
-                                       SilcBuffer message)
-{
-  char *msg;
-
-  SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
-
-  msg = silc_calloc(message->len + 1, sizeof(char));
-  memcpy(msg, message->data, message->len);
-  silc_say(client, msg);
-  silc_free(msg);
-
-  SILC_SET_DISCONNECTED(sock);
-  silc_client_close_connection(client, sock);
-}
-
-/* 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,
-                                SilcSocketConnection sock,
-                                SilcBuffer message)
-{
-  char *msg;
-
-  msg = silc_calloc(message->len + 1, sizeof(char));
-  memcpy(msg, message->data, message->len);
-  silc_say(client, msg);
-  silc_free(msg);
-}
-
-/* Received notify message from server */
-
-void silc_client_notify_by_server(SilcClient client,
-                                 SilcSocketConnection sock,
-                                 SilcBuffer message)
-{
-  char *msg;
-
-  msg = silc_calloc(message->len + 1, sizeof(char));
-  memcpy(msg, message->data, message->len);
-  silc_say(client, msg);
-  silc_free(msg);
-}
-
-/* Processes the received new Client ID from server. Old Client ID is
-   deleted from cache and new one is added. */
-
-void silc_client_receive_new_id(SilcClient client,
-                               SilcSocketConnection sock,
-                               unsigned char *id_string)
-{
-  SilcClientWindow win = (SilcClientWindow)sock->user_data;
-  char *nickname = win->nickname;
-
-#define CIDC(x) win->client_id_cache[(x) - 32]
-#define CIDCC(x) win->client_id_cache_count[(x) - 32]
-
-  /* Delete old ID from ID cache */
-  silc_idcache_del_by_id(CIDC(nickname[0]), CIDCC(nickname[0]),
-                        SILC_ID_CLIENT, win->local_id);
-  
-  /* Save the new ID */
-  if (win->local_id)
-    silc_free(win->local_id);
-  win->local_id = silc_id_str2id(id_string, SILC_ID_CLIENT);
-  if (win->local_id_data)
-    silc_free(win->local_id_data);
-  win->local_id_data = 
-    silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
-  memcpy(win->local_id_data, id_string, SILC_ID_CLIENT_LEN);
-  win->local_id_data_len = SILC_ID_CLIENT_LEN;
-  if (!win->local_entry)
-    win->local_entry = silc_calloc(1, sizeof(*win->local_entry));
-  win->local_entry->nickname = win->nickname;
-  win->local_entry->id = win->local_id;
-  
-  /* Put it to the ID cache */
-  CIDCC(nickname[0]) = silc_idcache_add(&CIDC(nickname[0]), 
-                                       CIDCC(nickname[0]),
-                                       win->nickname, SILC_ID_CLIENT, 
-                                       win->local_id, 
-                                       (void *)win->local_entry);
-#undef CIDC
-#undef CIDCC
-}
-
-/* Processed received Channel ID for a channel. This is called when client
-   joins to channel and server replies with channel ID. The ID is cached. */
-
-void silc_client_new_channel_id(SilcClient client,
-                               SilcSocketConnection sock,
-                               char *channel_name,
-                               unsigned char *id_string)
-{
-  SilcClientWindow win = (SilcClientWindow)sock->user_data;
-  SilcChannelID *id;
-  SilcChannelEntry channel;
-
-  SILC_LOG_DEBUG(("New channel ID"));
-
-#define CIDC(x) win->channel_id_cache[(x) - 32]
-#define CIDCC(x) win->channel_id_cache_count[(x) - 32]
-
-  id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
-  channel = silc_calloc(1, sizeof(*channel));
-  channel->channel_name = channel_name;
-  channel->id = id;
-  win->current_channel = channel;
-  
-  /* Put it to the ID cache */
-  CIDCC(channel_name[0]) = silc_idcache_add(&CIDC(channel_name[0]), 
-                                           CIDCC(channel_name[0]),
-                                           channel_name, SILC_ID_CHANNEL, 
-                                           id, (void *)channel);
-#undef CIDC
-#undef CIDCC
-}
-
-/* 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. 
-   This is the key that server has generated, this is not the channel
-   private key, it is entirely local setting. */
-
-void silc_client_receive_channel_key(SilcClient client,
-                                    SilcSocketConnection sock,
-                                    SilcBuffer packet)
-{
-  int i;
-  unsigned char *id_string, *key, *cipher;
-  unsigned int key_len;
-  SilcClientWindow win = (SilcClientWindow)sock->user_data;
-  SilcChannelID *id;
-  SilcIDCache *id_cache = NULL;
-  SilcChannelEntry channel;
-  SilcChannelKeyPayload payload;
-
-  SILC_LOG_DEBUG(("Received key for channel"));
-  
-#define CIDC(x) win->channel_id_cache[(x)]
-#define CIDCC(x) win->channel_id_cache_count[(x)]
-
-  payload = silc_channel_key_parse_payload(packet);
-  if (!payload)
-    return;
-
-  id_string = silc_channel_key_get_id(payload, NULL);
-  if (!id_string) {
-    silc_channel_key_free_payload(payload);
-    return;
-  }
-  id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
-
-  /* Find channel. XXX: This is bad and slow. */ 
-  for (i = 0; i < 96; i++) {
-    if (CIDC(i) == NULL)
-      continue;
-    if (silc_idcache_find_by_id(CIDC(i), CIDCC(i), (void *)id, 
-                               SILC_ID_CHANNEL, &id_cache))
-      break;
-  }
-
- if (!id_cache)
-    goto out;
-
-  /* Save the key */
-  key = silc_channel_key_get_key(payload, &key_len);
-  cipher = silc_channel_key_get_cipher(payload, NULL);
-
-  channel = (SilcChannelEntry)id_cache->context;
-  channel->key_len = key_len;
-  channel->key = silc_calloc(key_len, sizeof(*channel->key));
-  memcpy(channel->key, key, key_len);
-
-  silc_cipher_alloc(cipher, &channel->channel_key);
-  if (!channel->channel_key) {
-    silc_say(client, "Cannot talk to channel: unsupported cipher %s", cipher);
-    goto out;
-  }
-  channel->channel_key->cipher->set_key(channel->channel_key->context, 
-                                       key, key_len);
-
-  /* Client is now joined to the channel */
-  channel->on_channel = TRUE;
-
- out:
-  silc_free(id);
-  silc_channel_key_free_payload(payload);
-#undef CIDC
-#undef CIDCC
-}
-
-/* Process received message to a channel (or from a channel, really). This
-   decrypts the channel message with channel specific key and parses the
-   channel payload. Finally it displays the message on the screen. */
-
-void silc_client_channel_message(SilcClient client, 
-                                SilcSocketConnection sock, 
-                                SilcPacketContext *packet)
-{
-  int i;
-  SilcClientWindow win = (SilcClientWindow)sock->user_data;
-  SilcBuffer buffer = packet->buffer;
-  SilcChannelPayload payload = NULL;
-  SilcChannelID *id = NULL;
-  SilcChannelEntry channel;
-  SilcIDCache *id_cache = NULL;
-
-#define CIDC(x) win->channel_id_cache[(x)]
-#define CIDCC(x) win->channel_id_cache_count[(x)]
-
-  /* Sanity checks */
-  if (packet->dst_id_type != SILC_ID_CHANNEL)
-    goto out;
-
-  id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
-
-  /* Find the channel entry from channels on this window */
-  for (i = 0; i < 96; i++) {
-    if (CIDC(i) == NULL)
-      continue;
-    if (silc_idcache_find_by_id(CIDC(i), CIDCC(i), (void *)id, 
-                               SILC_ID_CHANNEL, &id_cache))
-      break;
-  }
-
-  if (!id_cache)
-    goto out;
-
-  channel = (SilcChannelEntry)id_cache->context;
-
-  /* Decrypt the channel message payload. Push the IV out of the way,
-     since it is not encrypted (after pushing buffer->tail has the IV). */
-  silc_buffer_push_tail(buffer, 16);
-  channel->channel_key->cipher->decrypt(channel->channel_key->context,
-                                       buffer->data, buffer->data,
-                                       buffer->len, buffer->tail);
-  silc_buffer_pull_tail(buffer, 16);
-
-  /* Parse the channel message payload */
-  payload = silc_channel_parse_payload(buffer);
-  if (!payload)
-    goto out;
-
-  /* Display the message on screen */
-  if (packet->src_id_type == SILC_ID_CLIENT)
-    /* Message from client */
-    silc_print(client, "<%s> %s", silc_channel_get_nickname(payload, NULL),
-              silc_channel_get_data(payload, NULL));
-  else
-    /* Message from server */
-    silc_say(client, "%s", silc_channel_get_data(payload, NULL));
-
- out:
-  if (id)
-    silc_free(id);
-  if (payload)
-    silc_channel_free_payload(payload);
-#undef CIDC
-#undef CIDCC
-}
diff --git a/apps/silc/client_ops.c b/apps/silc/client_ops.c
new file mode 100644 (file)
index 0000000..a127140
--- /dev/null
@@ -0,0 +1,614 @@
+/*
+
+  client_ops.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 2000 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
+  GNU General Public License for more details.
+
+*/
+
+#include "clientincludes.h"
+
+/* Prints a message with three star (*) sign before the actual message
+   on the current output window. This is used to print command outputs
+   and error messages. */
+
+void silc_say(SilcClient client, SilcClientConnection conn, 
+             char *msg, ...)
+{
+  va_list vp;
+  char message[2048];
+  SilcClientInternal app = (SilcClientInternal)client->application;
+
+  memset(message, 0, sizeof(message));
+  strncat(message, "\n***  ", 5);
+
+  va_start(vp, msg);
+  vsprintf(message + 5, msg, vp);
+  va_end(vp);
+  
+  /* Print the message */
+  silc_print_to_window(app->screen->output_win[0], message);
+}
+
+/* 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,
+                         char *sender, char *channel_name, char *msg)
+{
+  /* Message from client */
+  if (!strcmp(conn->current_channel->channel_name, channel_name))
+    silc_print(client, "<%s> %s", sender, msg);
+  else
+    silc_print(client, "<%s:%s> %s", sender, channel_name, msg);
+}
+
+/* Private message to the client. The `sender' is the nickname of the
+   sender received in the packet. */
+
+void silc_private_message(SilcClient client, SilcClientConnection conn,
+                         char *sender, char *msg)
+{
+  silc_print(client, "*%s* %s", sender, msg);
+}
+
+
+/* Notify message to the client. The notify 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 received
+   application receives SilcClientEntry.  Also, if the notify type is
+   for channel the channel entry is sent to application (even if server
+   does not send it). */
+
+void silc_notify(SilcClient client, SilcClientConnection conn, 
+                SilcNotifyType type, ...)
+{
+  SilcClientInternal app = (SilcClientInternal)client->application;
+  va_list vp;
+  char message[4096];
+  SilcClientEntry client_entry, client_entry2;
+  SilcChannelEntry channel_entry;
+  char *tmp;
+  unsigned int tmp_int;
+
+  va_start(vp, type);
+
+  memset(message, 0, sizeof(message));
+
+  /* Get arguments (defined by protocol in silc-pp-01 -draft) */
+  switch(type) {
+  case SILC_NOTIFY_TYPE_NONE:
+    tmp = va_arg(vp, char *);
+    if (!tmp)
+      return;
+    strcpy(message, tmp);
+    break;
+
+  case SILC_NOTIFY_TYPE_INVITE:
+    client_entry = va_arg(vp, SilcClientEntry);
+    channel_entry = va_arg(vp, SilcChannelEntry);
+    snprintf(message, sizeof(message), "%s invites you to channel %s", 
+            client_entry->nickname, channel_entry->channel_name);
+    break;
+
+  case SILC_NOTIFY_TYPE_JOIN:
+    client_entry = va_arg(vp, SilcClientEntry);
+    channel_entry = va_arg(vp, SilcChannelEntry);
+    snprintf(message, sizeof(message), "%s (%s) has joined channel %s", 
+            client_entry->nickname, client_entry->username, 
+            channel_entry->channel_name);
+    break;
+
+  case SILC_NOTIFY_TYPE_LEAVE:
+    client_entry = va_arg(vp, SilcClientEntry);
+    channel_entry = va_arg(vp, SilcChannelEntry);
+    if (client_entry->server)
+      snprintf(message, sizeof(message), "%s@%s has left channel %s", 
+              client_entry->nickname, client_entry->server, 
+              channel_entry->channel_name);
+    else
+      snprintf(message, sizeof(message), "%s has left channel %s", 
+              client_entry->nickname, channel_entry->channel_name);
+    break;
+
+  case SILC_NOTIFY_TYPE_SIGNOFF:
+    client_entry = va_arg(vp, SilcClientEntry);
+    if (client_entry->server)
+      snprintf(message, sizeof(message), "Signoff: %s@%s", 
+              client_entry->nickname, client_entry->server);
+    else
+      snprintf(message, sizeof(message), "Signoff: %s", 
+              client_entry->nickname);
+    break;
+
+  case SILC_NOTIFY_TYPE_TOPIC_SET:
+    client_entry = va_arg(vp, SilcClientEntry);
+    tmp = va_arg(vp, char *);
+    channel_entry = va_arg(vp, SilcChannelEntry);
+    if (client_entry->server)
+      snprintf(message, sizeof(message), "%s@%s set topic on %s: %s", 
+              client_entry->nickname, client_entry->server,
+              channel_entry->channel_name, tmp);
+    else
+      snprintf(message, sizeof(message), "%s set topic on %s: %s", 
+              client_entry->nickname, channel_entry->channel_name, tmp);
+    break;
+
+  case SILC_NOTIFY_TYPE_NICK_CHANGE:
+    client_entry = va_arg(vp, SilcClientEntry);
+    client_entry2 = va_arg(vp, SilcClientEntry);
+    if (client_entry->server && client_entry2->server)
+      snprintf(message, sizeof(message), "%s@%s is known as %s@%s", 
+              client_entry->nickname, client_entry->server,
+              client_entry2->nickname, client_entry2->server);
+    else
+      snprintf(message, sizeof(message), "%s is known as %s", 
+              client_entry->nickname, client_entry2->nickname);
+    break;
+
+  case SILC_NOTIFY_TYPE_CMODE_CHANGE:
+    client_entry = va_arg(vp, SilcClientEntry);
+    tmp = silc_client_chmode(va_arg(vp, unsigned int));
+    channel_entry = va_arg(vp, SilcChannelEntry);
+    if (tmp)
+      snprintf(message, sizeof(message), "%s changed channel mode to +%s", 
+              client_entry->nickname, tmp);
+    else
+      snprintf(message, sizeof(message), "%s removed all channel modes", 
+              client_entry->nickname);
+    if (app->screen->bottom_line->channel_mode)
+      silc_free(app->screen->bottom_line->channel_mode);
+    app->screen->bottom_line->channel_mode = tmp;
+    silc_screen_print_bottom_line(app->screen, 0);
+    break;
+
+  case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
+    client_entry = va_arg(vp, SilcClientEntry);
+    tmp_int = va_arg(vp, unsigned int);
+    tmp = silc_client_chumode(tmp_int);
+    client_entry2 = va_arg(vp, SilcClientEntry);
+    channel_entry = va_arg(vp, SilcChannelEntry);
+    if (tmp)
+      snprintf(message, sizeof(message), "%s changed %s mode to +%s", 
+              client_entry->nickname, client_entry2->nickname, tmp);
+    else
+      snprintf(message, sizeof(message), "%s removed %s modes", 
+              client_entry->nickname, client_entry2->nickname);
+    if (client_entry2 == conn->local_entry) {
+      if (app->screen->bottom_line->mode)
+       silc_free(app->screen->bottom_line->mode);
+      app->screen->bottom_line->mode = silc_client_chumode_char(tmp_int);
+      silc_screen_print_bottom_line(app->screen, 0);
+    }
+    silc_free(tmp);
+    break;
+
+  case SILC_NOTIFY_TYPE_MOTD:
+    {
+      char line[256];
+      int i;
+      tmp = va_arg(vp, unsigned char *);
+
+      i = 0;
+      while(tmp[i] != 0) {
+       if (tmp[i++] == '\n') {
+         memset(line, 0, sizeof(line));
+         strncat(line, tmp, i - 1);
+         tmp += i;
+         
+         silc_say(client, conn, "%s", line);
+         
+         if (!strlen(tmp))
+           break;
+         i = 0;
+       }
+      }
+    }
+    return;
+
+  default:
+    break;
+  }
+
+  silc_print(client, "*** %s", message);
+}
+
+/* Command handler. This function is called always in the command function.
+   If error occurs it will be called as well. `conn' is the associated
+   client connection. `cmd_context' is the command context that was
+   originally sent to the command. `success' is FALSE if error occured
+   during command. `command' is the command being processed. It must be
+   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 silc_command(SilcClient client, SilcClientConnection conn, 
+                 SilcClientCommandContext cmd_context, int success,
+                 SilcCommand command)
+{
+  SilcClientInternal app = (SilcClientInternal)client->application;
+
+  if (!success)
+    return;
+
+  switch(command)
+    {
+    case SILC_COMMAND_QUIT:
+      app->screen->bottom_line->channel = NULL;
+      silc_screen_print_bottom_line(app->screen, 0);
+      break;
+
+    case SILC_COMMAND_LEAVE:
+#if 0
+      if (!strncmp(conn->current_channel->channel_name, name, strlen(name))) {
+       app->screen->bottom_line->channel = NULL;
+       silc_screen_print_bottom_line(app->screen, 0);
+      }
+#endif
+      break;
+
+    }
+}
+
+/* Command reply handler. This function is called always in the command reply
+   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. 
+
+   `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,
+   however, it must be noted that the data is parsed already by the library
+   thus the payload can be ignored. `success' is FALSE if error occured.
+   In this case arguments are not sent to the application. `command' is the
+   command reply being processed. The function has variable argument list
+   and each command defines the number and type of arguments it passes to the
+   application (on error they are not sent). */
+
+void silc_command_reply(SilcClient client, SilcClientConnection conn,
+                       SilcCommandPayload cmd_payload, int success,
+                       SilcCommand command, SilcCommandStatus status, ...)
+{
+  SilcClientInternal app = (SilcClientInternal)client->application;
+  va_list vp;
+  int i;
+
+  if (!success)
+    return;
+
+  va_start(vp, status);
+
+  switch(command)
+    {
+
+    case SILC_COMMAND_JOIN:
+      {
+       unsigned int mode;
+
+       app->screen->bottom_line->channel = va_arg(vp, char *);
+       (void)va_arg(vp, void *);
+       mode = va_arg(vp, unsigned int);
+       app->screen->bottom_line->channel_mode = silc_client_chmode(mode);
+       silc_screen_print_bottom_line(app->screen, 0);
+      }
+      break;
+
+    case SILC_COMMAND_NICK:
+      {
+       SilcClientEntry entry;
+
+       entry = va_arg(vp, SilcClientEntry);
+       silc_say(client, conn, "Your current nickname is %s", entry->nickname);
+       app->screen->bottom_line->nickname = entry->nickname;
+       silc_screen_print_bottom_line(app->screen, 0);
+      }
+      break;
+
+    case SILC_COMMAND_NAMES:
+      for (i = 0; i < conn->current_channel->clients_count; i++)
+       if (conn->current_channel->clients[i].client == conn->local_entry) {
+         if (app->screen->bottom_line->mode)
+           silc_free(app->screen->bottom_line->mode);
+         app->screen->bottom_line->mode = 
+           silc_client_chumode_char(conn->current_channel->clients[i].mode);
+         silc_screen_print_bottom_line(app->screen, 0);
+         break;
+       }
+      break;
+    }
+}
+
+/* Called to indicate that connection was either successfully established
+   or connecting failed.  This is also the first time application receives
+   the SilcClientConnection objecet which it should save somewhere. */
+
+void silc_connect(SilcClient client, SilcClientConnection conn, int success)
+{
+  SilcClientInternal app = (SilcClientInternal)client->application;
+
+  if (success) {
+    app->screen->bottom_line->connection = conn->remote_host;
+    silc_screen_print_bottom_line(app->screen, 0);
+    app->conn = conn;
+  }
+}
+
+/* Called to indicate that connection was disconnected to the server. */
+
+void silc_disconnect(SilcClient client, SilcClientConnection conn)
+{
+  SilcClientInternal app = (SilcClientInternal)client->application;
+
+  app->screen->bottom_line->connection = NULL;
+  silc_screen_print_bottom_line(app->screen, 0);
+}
+
+/* Asks passphrase from user on the input line. */
+
+unsigned char *silc_ask_passphrase(SilcClient client, 
+                                  SilcClientConnection conn)
+{
+  SilcClientInternal app = (SilcClientInternal)conn->client->application;
+  char pass1[256], pass2[256];
+  char *ret;
+  int try = 3;
+
+  while(try) {
+
+    /* Print prompt */
+    wattroff(app->screen->input_win, A_INVIS);
+    silc_screen_input_print_prompt(app->screen, "Passphrase: ");
+    wattron(app->screen->input_win, A_INVIS);
+    
+    /* Get string */
+    memset(pass1, 0, sizeof(pass1));
+    wgetnstr(app->screen->input_win, pass1, sizeof(pass1));
+    
+    /* Print retype prompt */
+    wattroff(app->screen->input_win, A_INVIS);
+    silc_screen_input_print_prompt(app->screen, "Retype passphrase: ");
+    wattron(app->screen->input_win, A_INVIS);
+    
+    /* Get string */
+    memset(pass2, 0, sizeof(pass2));
+    wgetnstr(app->screen->input_win, pass2, sizeof(pass2));
+
+    if (!strncmp(pass1, pass2, strlen(pass2)))
+      break;
+
+    try--;
+  }
+
+  ret = silc_calloc(strlen(pass1), sizeof(char));
+  memcpy(ret, pass1, strlen(pass1));
+
+  memset(pass1, 0, sizeof(pass1));
+  memset(pass2, 0, sizeof(pass2));
+
+  wattroff(app->screen->input_win, A_INVIS);
+  silc_screen_input_reset(app->screen);
+
+  return ret;
+}
+
+/* Verifies received public key. If user decides to trust the key it is
+   saved as trusted server key for later use. If user does not trust the
+   key this returns FALSE. */
+
+int silc_verify_server_key(SilcClient client,
+                          SilcClientConnection conn, 
+                          unsigned char *pk, unsigned int pk_len,
+                          SilcSKEPKType pk_type)
+{
+  SilcSocketConnection sock = conn->sock;
+  char filename[256];
+  char file[256];
+  char *hostname, *fingerprint;
+  struct passwd *pw;
+  struct stat st;
+
+  hostname = sock->hostname ? sock->hostname : sock->ip;
+
+  if (pk_type != SILC_SKE_PK_TYPE_SILC) {
+    silc_say(client, conn, "We don't support server %s key type", hostname);
+    return FALSE;
+  }
+
+  pw = getpwuid(getuid());
+  if (!pw)
+    return FALSE;
+
+  memset(filename, 0, sizeof(filename));
+  memset(file, 0, sizeof(file));
+  snprintf(file, sizeof(file) - 1, "serverkey_%s_%d.pub", hostname,
+          sock->port);
+  snprintf(filename, sizeof(filename) - 1, "%s/.silc/serverkeys/%s", 
+          pw->pw_dir, file);
+
+  /* Check wheter this key already exists */
+  if (stat(filename, &st) < 0) {
+
+    fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
+    silc_say(client, conn, "Received server %s public key", hostname);
+    silc_say(client, conn, "Fingerprint for the server %s key is", hostname);
+    silc_say(client, conn, "%s", fingerprint);
+    silc_free(fingerprint);
+
+    /* Ask user to verify the key and save it */
+    if (silc_client_ask_yes_no(client, 
+       "Would you like to accept the key (y/n)? "))
+      {
+       /* Save the key for future checking */
+       silc_pkcs_save_public_key_data(filename, pk, pk_len, 
+                                      SILC_PKCS_FILE_PEM);
+       return TRUE;
+      }
+  } else {
+    /* The key already exists, verify it. */
+    SilcPublicKey public_key;
+    unsigned char *encpk;
+    unsigned int encpk_len;
+
+    /* Load the key file */
+    if (!silc_pkcs_load_public_key(filename, &public_key, 
+                                  SILC_PKCS_FILE_PEM))
+      if (!silc_pkcs_load_public_key(filename, &public_key, 
+                                    SILC_PKCS_FILE_BIN)) {
+       fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
+       silc_say(client, conn, "Received server %s public key", hostname);
+       silc_say(client, conn, "Fingerprint for the server %s key is", hostname);
+       silc_say(client, conn, "%s", fingerprint);
+       silc_free(fingerprint);
+       silc_say(client, conn, "Could not load your local copy of the server %s key",
+                hostname);
+       if (silc_client_ask_yes_no(client, 
+          "Would you like to accept the key anyway (y/n)? "))
+         {
+           /* Save the key for future checking */
+           unlink(filename);
+           silc_pkcs_save_public_key_data(filename, pk, pk_len,
+                                          SILC_PKCS_FILE_PEM);
+           return TRUE;
+         }
+       
+       return FALSE;
+      }
+  
+    /* Encode the key data */
+    encpk = silc_pkcs_public_key_encode(public_key, &encpk_len);
+    if (!encpk) {
+      fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
+      silc_say(client, conn, "Received server %s public key", hostname);
+      silc_say(client, conn, "Fingerprint for the server %s key is", hostname);
+      silc_say(client, conn, "%s", fingerprint);
+      silc_free(fingerprint);
+      silc_say(client, conn, "Your local copy of the server %s key is malformed",
+              hostname);
+      if (silc_client_ask_yes_no(client, 
+         "Would you like to accept the key anyway (y/n)? "))
+       {
+         /* Save the key for future checking */
+         unlink(filename);
+         silc_pkcs_save_public_key_data(filename, pk, pk_len,
+                                        SILC_PKCS_FILE_PEM);
+         return TRUE;
+       }
+
+      return FALSE;
+    }
+
+    if (memcmp(encpk, pk, encpk_len)) {
+      fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
+      silc_say(client, conn, "Received server %s public key", hostname);
+      silc_say(client, conn, "Fingerprint for the server %s key is", hostname);
+      silc_say(client, conn, "%s", fingerprint);
+      silc_free(fingerprint);
+      silc_say(client, conn, "Server %s key does not match with your local copy",
+              hostname);
+      silc_say(client, conn, "It is possible that the key has expired or changed");
+      silc_say(client, conn, "It is also possible that some one is performing "
+                      "man-in-the-middle attack");
+      
+      /* Ask user to verify the key and save it */
+      if (silc_client_ask_yes_no(client, 
+         "Would you like to accept the key anyway (y/n)? "))
+       {
+         /* Save the key for future checking */
+         unlink(filename);
+         silc_pkcs_save_public_key_data(filename, pk, pk_len,
+                                        SILC_PKCS_FILE_PEM);
+         return TRUE;
+       }
+
+      silc_say(client, conn, "Will not accept server %s key", hostname);
+      return FALSE;
+    }
+
+    /* Local copy matched */
+    return TRUE;
+  }
+
+  silc_say(client, conn, "Will not accept server %s key", hostname);
+  return FALSE;
+}
+
+/* Find authentication method and authentication data by hostname and
+   port. The hostname may be IP address as well. The found authentication
+   method and authentication data is returned to `auth_meth', `auth_data'
+   and `auth_data_len'. The function returns TRUE if authentication method
+   is found and FALSE if not. `conn' may be NULL. */
+
+int silc_get_auth_method(SilcClient client, SilcClientConnection conn,
+                        char *hostname, unsigned short port,
+                        SilcProtocolAuthMeth *auth_meth,
+                        unsigned char **auth_data,
+                        unsigned int *auth_data_len)
+{
+  SilcClientInternal app = (SilcClientInternal)client->application;
+
+  if (app->config->conns) {
+    SilcClientConfigSectionConnection *conn = NULL;
+
+    /* Check if we find a match from user configured connections */
+    conn = silc_client_config_find_connection(app->config,
+                                             hostname,
+                                             port);
+    if (conn) {
+      /* Match found. Use the configured authentication method */
+      *auth_meth = conn->auth_meth;
+
+      if (conn->auth_data) {
+       *auth_data = strdup(conn->auth_data);
+       *auth_data_len = strlen(conn->auth_data);
+      }
+
+      return TRUE;
+    }
+  }
+
+  return FALSE;
+}
+
+/* Notifies application that failure packet was received.  This is called
+   if there is some protocol active in the client.  The `protocol' is the
+   protocol context.  The `failure' is opaque pointer to the failure
+   indication.  Note, that the `failure' is protocol dependant and application
+   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, 
+                 SilcProtocol protocol, void *failure)
+{
+  SilcClientInternal app = (SilcClientInternal)client->application;
+
+}
+
+/* SILC client operations */
+SilcClientOperations ops = {
+  say:                  silc_say,
+  channel_message:      silc_channel_message,
+  private_message:      silc_private_message,
+  notify:               silc_notify,
+  command:              silc_command,
+  command_reply:        silc_command_reply,
+  connect:              silc_connect,
+  disconnect:           silc_disconnect,
+  get_auth_method:      silc_get_auth_method,
+  verify_server_key:    silc_verify_server_key,
+  ask_passphrase:       silc_ask_passphrase,
+  failure:              silc_failure,
+};
diff --git a/apps/silc/client_ops.h b/apps/silc/client_ops.h
new file mode 100644 (file)
index 0000000..db8f1af
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+
+  client_ops.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 2000 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
+  GNU General Public License for more details.
+
+*/
+
+#ifndef CLIENT_OPS_H
+#define CLIENT_OPS_H
+
+void silc_say(SilcClient client, SilcClientConnection conn, char *msg, ...);
+void silc_channel_message(SilcClient client, SilcClientConnection conn,
+                         char *sender, char *channel_name, char *msg);
+void silc_private_message(SilcClient client, SilcClientConnection conn,
+                         char *sender, char *msg);
+void silc_notify(SilcClient client, SilcClientConnection conn, 
+                SilcNotifyType type, ...);
+void silc_command(SilcClient client, SilcClientConnection conn, 
+                 SilcClientCommandContext cmd_context, int success,
+                 SilcCommand command);
+void silc_command_reply(SilcClient client, SilcClientConnection conn,
+                       SilcCommandPayload cmd_payload, int success,
+                       SilcCommand command, SilcCommandStatus status, ...);
+void silc_connect(SilcClient client, SilcClientConnection conn, int success);
+void silc_disconnect(SilcClient client, SilcClientConnection conn);
+unsigned char *silc_ask_passphrase(SilcClient client, 
+                                  SilcClientConnection conn);
+int silc_verify_server_key(SilcClient client, SilcClientConnection conn, 
+                          unsigned char *pk, unsigned int pk_len,
+                          SilcSKEPKType pk_type);
+int silc_get_auth_method(SilcClient client, SilcClientConnection conn,
+                        char *hostname, unsigned short port,
+                        SilcProtocolAuthMeth *auth_meth,
+                        unsigned char **auth_data,
+                        unsigned int *auth_data_len);
+void silc_failure(SilcClient client, SilcClientConnection conn, 
+                 SilcProtocol protocol, void *failure);
+
+#endif
index e55157b30fdee38ec48eb3c322a87f1b2314e70a..b6f5b150a832b58c814b063752ea0ff355e1660a 100644 (file)
   GNU General Public License for more details.
 
 */
-/*
- * $Id$
- * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:56  priikone
- *     Importet from internal CVS/Added Log headers.
- *
- *
- */
+/* $Id$ */
 
 #include "clientincludes.h"
 #include "clientconfig.h"
@@ -60,11 +53,6 @@ SilcClientConfig silc_client_config_alloc(char *filename)
   SILC_LOG_DEBUG(("Allocating new configuration object"));
 
   new = silc_calloc(1, sizeof(*new));
-  if (!new) {
-    fprintf(stderr, "Could not allocate new configuration object");
-    return NULL;
-  }
-
   new->filename = filename;
 
   /* Open configuration file and parse it */
@@ -155,7 +143,7 @@ int silc_client_config_parse(SilcClientConfig config, SilcBuffer buffer,
       
       /* Check for matching sections */
       for (cptr = silc_client_config_sections; cptr->section; cptr++)
-       if (!strcmp(cp, cptr->section))
+       if (!strncasecmp(cp, cptr->section, strlen(cptr->section)))
          break;
 
       if (!cptr->section) {
@@ -490,7 +478,9 @@ int silc_client_config_parse_lines(SilcClientConfig config,
       /* Get command line (this may include parameters as well. They
         will be parsed later with standard command parser when
         executing particular command.) */
-      config->commands->command = strdup(line->data);
+      config->commands->command = silc_calloc(strlen(line->data), 
+                                             sizeof(char));
+      memcpy(config->commands->command, line->data, strlen(line->data) - 1);
       if (ret < 0)
        break;
 
@@ -539,7 +529,8 @@ int silc_client_config_parse_lines(SilcClientConfig config,
 void silc_client_config_register_ciphers(SilcClientConfig config)
 {
   SilcClientConfigSectionAlg *alg;
-  SilcClient client = (SilcClient)config->client;
+  SilcClientInternal app = (SilcClientInternal)config->client;
+  SilcClient client = app->client;
 
   SILC_LOG_DEBUG(("Registering configured ciphers"));
 
@@ -596,11 +587,11 @@ void silc_client_config_register_ciphers(SilcClientConfig config)
        SILC_LOG_DEBUG(("context_len=%p", cipher.context_len));
 
        /* Put the SIM to the table of all SIM's in client */
-       client->sim = silc_realloc(client->sim,
-                                  sizeof(*client->sim) * 
-                                  (client->sim_count + 1));
-       client->sim[client->sim_count] = sim;
-       client->sim_count++;
+       app->sim = silc_realloc(app->sim,
+                                  sizeof(*app->sim) * 
+                                  (app->sim_count + 1));
+       app->sim[app->sim_count] = sim;
+       app->sim_count++;
       } else {
        SILC_LOG_ERROR(("Error configuring ciphers"));
        silc_client_stop(client);
@@ -625,7 +616,8 @@ void silc_client_config_register_ciphers(SilcClientConfig config)
 void silc_client_config_register_pkcs(SilcClientConfig config)
 {
   SilcClientConfigSectionAlg *alg = config->pkcs;
-  SilcClient client = (SilcClient)config->client;
+  SilcClientInternal app = (SilcClientInternal)config->client;
+  SilcClient client = app->client;
   SilcPKCS tmp = NULL;
 
   SILC_LOG_DEBUG(("Registering configured PKCS"));
@@ -649,7 +641,8 @@ void silc_client_config_register_pkcs(SilcClientConfig config)
 void silc_client_config_register_hashfuncs(SilcClientConfig config)
 {
   SilcClientConfigSectionAlg *alg;
-  SilcClient client = (SilcClient)config->client;
+  SilcClientInternal app = (SilcClientInternal)config->client;
+  SilcClient client = app->client;
 
   SILC_LOG_DEBUG(("Registering configured hash functions"));
 
@@ -702,11 +695,11 @@ void silc_client_config_register_hashfuncs(SilcClientConfig config)
        SILC_LOG_DEBUG(("context_len=%p", hash.context_len));
 
        /* Put the SIM to the table of all SIM's in client */
-       client->sim = silc_realloc(client->sim,
-                                  sizeof(*client->sim) * 
-                                  (client->sim_count + 1));
-       client->sim[client->sim_count] = sim;
-       client->sim_count++;
+       app->sim = silc_realloc(app->sim,
+                                  sizeof(*app->sim) * 
+                                  (app->sim_count + 1));
+       app->sim[app->sim_count] = sim;
+       app->sim_count++;
       } else {
        SILC_LOG_ERROR(("Error configuring hash functions"));
        silc_client_stop(client);
index 21043795c0249108bc680645c5583a99488b9461..210f50b02c5d2307f6a8bb4bf12a211bb97e6c38 100644 (file)
   GNU General Public License for more details.
 
 */
-/*
- * $Id$
- * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:56  priikone
- *     Importet from internal CVS/Added Log headers.
- *
- *
- */
+/* $Id$ */
 
 #include "clientincludes.h"
 
-/* Internal routine used to print lines to window. This can split the
+/* Routine used to print lines to window. This can split the
    line neatly if a word would overlap the line. */
 
-static void silc_print_to_window(WINDOW *win, char *message)
+void silc_print_to_window(WINDOW *win, char *message)
 {
   int str_len, len;
 
@@ -62,36 +55,14 @@ static void silc_print_to_window(WINDOW *win, char *message)
   wrefresh(win);
 }
 
-/* Prints a message with three star (*) sign before the actual message
-   on the current output window. This is used to print command outputs
-   and error messages. */
-/* XXX Change to accept SilcClientWindow and use output window 
-   from there (the pointer to the output window must be added to the
-   SilcClientWindow object. */
-
-void silc_say(SilcClient client, char *msg, ...)
-{
-  va_list vp;
-  char message[1024];
-  
-  memset(message, 0, sizeof(message));
-  strncat(message, "\n***  ", 5);
-
-  va_start(vp, msg);
-  vsprintf(message + 5, msg, vp);
-  va_end(vp);
-  
-  /* Print the message */
-  silc_print_to_window(client->screen->output_win[0], message);
-}
-
 /* Prints message to the screen. This is used to print the messages
    user is typed and message that came on channels. */
 
 void silc_print(SilcClient client, char *msg, ...)
 {
   va_list vp;
-  char message[1024];
+  char message[2048];
+  SilcClientInternal app = client->application;
   
   memset(message, 0, sizeof(message));
   strncat(message, "\n ", 2);
@@ -101,7 +72,7 @@ void silc_print(SilcClient client, char *msg, ...)
   va_end(vp);
   
   /* Print the message */
-  silc_print_to_window(client->screen->output_win[0], message);
+  silc_print_to_window(app->screen->output_win[0], message);
 }
 
 /* Returns user's mail path */
@@ -110,8 +81,13 @@ char *silc_get_mail_path()
 {
   char pathbuf[MAXPATHLEN];
   char *path;
+
+#ifndef _PATH_MAILDIR
+#define _PATH_MAILDIR "/var/mail"
+#endif
   
-  if ((path = (char *)getenv("MAIL")) != 0) {
+  path = getenv("MAIL");
+  if (path) {
     strncpy(pathbuf, path, strlen(path));
   } else {
     strcpy(pathbuf, _PATH_MAILDIR);
@@ -138,7 +114,7 @@ int silc_get_number_of_emails()
     fprintf(stderr, "Couldn't open mail file (%s).\n", filename);
   } else {
     while((fscanf(tl, "%s", data)) != EOF) { 
-      if(!strcmp(data, "Subject:"))
+      if(!strcmp(data, "From:"))
        num++;
     }
     
@@ -209,48 +185,39 @@ int silc_client_time_til_next_min()
   return 60 - min->tm_sec;
 }
 
-/* Asks passphrase from user on the input line. */
+/* Asks yes/no from user on the input line. Returns TRUE on "yes" and
+   FALSE on "no". */
 
-char *silc_client_ask_passphrase(SilcClient client)
+int silc_client_ask_yes_no(SilcClient client, char *prompt)
 {
-  char pass1[256], pass2[256];
-  char *ret;
-  int try = 3;
-
-  while(try) {
-
-    /* Print prompt */
-    wattroff(client->screen->input_win, A_INVIS);
-    silc_screen_input_print_prompt(client->screen, "Passphrase: ");
-    wattron(client->screen->input_win, A_INVIS);
-    
-    /* Get string */
-    memset(pass1, 0, sizeof(pass1));
-    wgetnstr(client->screen->input_win, pass1, sizeof(pass1));
-    
-    /* Print retype prompt */
-    wattroff(client->screen->input_win, A_INVIS);
-    silc_screen_input_print_prompt(client->screen, "Retype passphrase: ");
-    wattron(client->screen->input_win, A_INVIS);
-    
-    /* Get string */
-    memset(pass2, 0, sizeof(pass2));
-    wgetnstr(client->screen->input_win, pass2, sizeof(pass2));
-
-    if (!strncmp(pass1, pass2, strlen(pass2)))
-      break;
-
-    try--;
+  SilcClientInternal app = (SilcClientInternal)client->application;
+  char answer[4];
+  int ret;
+
+ again:
+  silc_screen_input_reset(app->screen);
+
+  /* Print prompt */
+  wattroff(app->screen->input_win, A_INVIS);
+  silc_screen_input_print_prompt(app->screen, prompt);
+
+  /* Get string */
+  memset(answer, 0, sizeof(answer));
+  echo();
+  wgetnstr(app->screen->input_win, answer, sizeof(answer));
+  if (!strncasecmp(answer, "yes", strlen(answer)) ||
+      !strncasecmp(answer, "y", strlen(answer))) {
+    ret = TRUE;
+  } else if (!strncasecmp(answer, "no", strlen(answer)) ||
+            !strncasecmp(answer, "n", strlen(answer))) {
+    ret = FALSE;
+  } else {
+    silc_say(client, app->conn, "Type yes or no");
+    goto again;
   }
+  noecho();
 
-  ret = silc_calloc(strlen(pass1), sizeof(char));
-  memcpy(ret, pass1, strlen(pass1));
-
-  memset(pass1, 0, sizeof(pass1));
-  memset(pass2, 0, sizeof(pass2));
-
-  wattroff(client->screen->input_win, A_INVIS);
-  silc_screen_input_reset(client->screen);
+  silc_screen_input_reset(app->screen);
 
   return ret;
 }
@@ -286,7 +253,7 @@ char *silc_client_get_input(const char *prompt)
   fd = open("/dev/tty", O_RDONLY);
   if (fd < 0) {
     fprintf(stderr, "silc: %s\n", strerror(errno));
-    exit(1);
+    return NULL;
   }
 
   memset(input, 0, sizeof(input));
@@ -296,7 +263,7 @@ char *silc_client_get_input(const char *prompt)
 
   if ((read(fd, input, sizeof(input))) < 0) {
     fprintf(stderr, "silc: %s\n", strerror(errno));
-    exit(1);
+    return NULL;
   }
 
   if (strlen(input) <= 1)
@@ -323,7 +290,7 @@ char *silc_client_get_passphrase(const char *prompt)
   fd = open("/dev/tty", O_RDONLY);
   if (fd < 0) {
     fprintf(stderr, "silc: %s\n", strerror(errno));
-    exit(1);
+    return NULL;
   }
 
   signal(SIGINT, SIG_IGN);
@@ -343,7 +310,7 @@ char *silc_client_get_passphrase(const char *prompt)
 
   if ((read(fd, input, sizeof(input))) < 0) {
     fprintf(stderr, "silc: %s\n", strerror(errno));
-    exit(1);
+    return NULL;
   }
 
   if (strlen(input) <= 1) {
@@ -367,18 +334,52 @@ char *silc_client_get_passphrase(const char *prompt)
 #endif
 }
 
+/* Returns identifier string for public key generation. */
+
+char *silc_client_create_identifier()
+{
+  char *username = NULL, *realname = NULL;
+  char hostname[256], email[256];
+  
+  /* Get realname */
+  realname = silc_get_real_name();
+
+  /* Get hostname */
+  memset(hostname, 0, sizeof(hostname));
+  gethostname(hostname, sizeof(hostname));
+
+  /* Get username (mandatory) */
+  username = silc_get_username();
+  if (!username)
+    return NULL;
+
+  /* Create default email address, whether it is right or not */
+  snprintf(email, sizeof(email), "%s@%s", username, hostname);
+
+  return silc_pkcs_encode_identifier(username, hostname, realname, email,
+                                    NULL, NULL);
+}
+
 /* Creates new public key and private key pair. This is used only
    when user wants to create new key pair from command line. */
 
-void silc_client_create_key_pair(char *pkcs_name, int bits)
+int silc_client_create_key_pair(char *pkcs_name, int bits,
+                               char *public_key, char *private_key,
+                               char *identifier, 
+                               SilcPublicKey *ret_pub_key,
+                               SilcPrivateKey *ret_prv_key)
 {
   SilcPKCS pkcs;
+  SilcPublicKey pub_key;
+  SilcPrivateKey prv_key;
   SilcRng rng;
   unsigned char *key;
   unsigned int key_len;
+  char line[256];
   char *pkfile = NULL, *prvfile = NULL;
 
-  printf("\
+  if (!pkcs_name || !public_key || !private_key)
+    printf("\
 New pair of keys will be created.  Please, answer to following questions.\n\
 ");
 
@@ -396,6 +397,11 @@ New pair of keys will be created.  Please, answer to following questions.\n\
     }
   }
 
+  if (!silc_pkcs_is_supported(pkcs_name)) {
+    fprintf(stderr, "Unsupported PKCS `%s'", pkcs_name);
+    return FALSE;
+  }
+
   if (!bits) {
     char *length = NULL;
     length = 
@@ -406,39 +412,320 @@ New pair of keys will be created.  Please, answer to following questions.\n\
       bits = atoi(length);
   }
 
+  if (!identifier) {
+    char *def = silc_client_create_identifier();
+
+    memset(line, 0, sizeof(line));
+    if (def)
+      snprintf(line, sizeof(line), "Identifier [%s]: ", def);
+    else
+      snprintf(line, sizeof(line),
+              "Identifier (eg. UN=jon, HN=jon.dummy.com, "
+              "RN=Jon Johnson, E=jon@dummy.com): ");
+
+    while (!identifier) {
+      identifier = silc_client_get_input(line);
+      if (!identifier && def)
+       identifier = strdup(def);
+    }
+
+    if (def)
+      silc_free(def);
+  }
+
   rng = silc_rng_alloc();
   silc_rng_init(rng);
   silc_math_primegen_init();
 
- again_pk:
-  pkfile = silc_client_get_input("Public key filename: ");
-  if (!pkfile) {
-    printf("Public key filename must be defined\n");
-    goto again_pk;
+  if (!public_key) {
+    memset(line, 0, sizeof(line));
+    snprintf(line, sizeof(line), "Public key filename [%s] ", 
+            SILC_CLIENT_PUBLIC_KEY_NAME);
+    pkfile = silc_client_get_input(line);
+    if (!pkfile)
+      pkfile = SILC_CLIENT_PUBLIC_KEY_NAME;
+  } else {
+    pkfile = public_key;
   }
 
- again_prv:
-  prvfile = silc_client_get_input("Private key filename: ");
-  if (!prvfile) {
-    printf("Private key filename must be defined\n");
-    goto again_prv;
+  if (!private_key) {
+    memset(line, 0, sizeof(line));
+    snprintf(line, sizeof(line), "Public key filename [%s] ", 
+            SILC_CLIENT_PRIVATE_KEY_NAME);
+    prvfile = silc_client_get_input(line);
+    if (!prvfile)
+      prvfile = SILC_CLIENT_PRIVATE_KEY_NAME;
+  } else {
+    prvfile = private_key;
   }
 
   /* Generate keys */
   silc_pkcs_alloc(pkcs_name, &pkcs);
   pkcs->pkcs->init(pkcs->context, bits, rng);
 
-  /* Save keys into file */
+  /* Save public key into file */
   key = silc_pkcs_get_public_key(pkcs, &key_len);
-  silc_pkcs_save_public_key(pkcs, pkfile, key, key_len);
+  pub_key = silc_pkcs_public_key_alloc(pkcs->pkcs->name, identifier,
+                                      key, key_len);
+  silc_pkcs_save_public_key(pkfile, pub_key, SILC_PKCS_FILE_PEM);
+  if (ret_pub_key)
+    *ret_pub_key = pub_key;
+
   memset(key, 0, sizeof(key_len));
   silc_free(key);
+
+  /* Save private key into file */
   key = silc_pkcs_get_private_key(pkcs, &key_len);
-  silc_pkcs_save_private_key(pkcs, prvfile, key, key_len, "");
+  prv_key = silc_pkcs_private_key_alloc(pkcs->pkcs->name, key, key_len);
+
+  silc_pkcs_save_private_key(prvfile, prv_key, NULL, SILC_PKCS_FILE_BIN);
+  if (ret_prv_key)
+    *ret_prv_key = prv_key;
+
+  printf("Public key has been save into `%s'.\n", pkfile);
+  printf("Private key has been saved into `%s'.\n", prvfile);
+  printf("Press <Enter> to continue...\n");
+  getchar();
+
   memset(key, 0, sizeof(key_len));
   silc_free(key);
 
   silc_math_primegen_uninit();
   silc_rng_free(rng);
   silc_pkcs_free(pkcs);
+
+  return TRUE;
+}
+
+/* This checks stats for various SILC files and directories. First it 
+   checks if ~/.silc directory exist and is owned by the correct user. If 
+   it doesn't exist, it will create the directory. After that it checks if
+   user's Public and Private key files exists and that they aren't expired.
+   If they doesn't exist or they are expired, they will be (re)created
+   after return. */
+
+int silc_client_check_silc_dir()
+{
+  char filename[256], file_public_key[256], file_private_key[256];
+  char servfilename[256];
+  char *identifier;
+  struct stat st;
+  struct passwd *pw;
+  int firstime = FALSE;
+  time_t curtime, modtime;
+
+  SILC_LOG_DEBUG(("Checking ~./silc directory"));
+
+  memset(filename, 0, sizeof(filename));
+  memset(file_public_key, 0, sizeof(file_public_key));
+  memset(file_private_key, 0, sizeof(file_private_key));
+
+  pw = getpwuid(getuid());
+  if (!pw) {
+    fprintf(stderr, "silc: %s\n", strerror(errno));
+    return FALSE;
+  }
+
+  identifier = silc_client_create_identifier();
+
+  /* We'll take home path from /etc/passwd file to be sure. */
+  snprintf(filename, sizeof(filename) - 1, "%s/.silc/", pw->pw_dir);
+  snprintf(servfilename, sizeof(servfilename) - 1, "%s/.silc/serverkeys", 
+          pw->pw_dir);
+
+  /*
+   * Check ~/.silc directory
+   */
+  if ((stat(filename, &st)) == -1) {
+    /* If dir doesn't exist */
+    if (errno == ENOENT) {
+      if (pw->pw_uid == geteuid()) {
+       if ((mkdir(filename, 0755)) == -1) {
+         fprintf(stderr, "Couldn't create `%s' directory\n", filename);
+         return FALSE;
+       }
+
+       /* Directory was created. First time running SILC */
+       firstime = TRUE;
+      } else {
+       fprintf(stderr, "Couldn't create `%s' directory due to a wrong uid!\n",
+               filename);
+       return FALSE;
+      }
+    } else {
+      fprintf(stderr, "%s\n", strerror(errno));
+      return FALSE;
+    }
+  } else {
+    
+    /* Check the owner of the dir */
+    if (st.st_uid != 0 && st.st_uid != pw->pw_uid) { 
+      fprintf(stderr, "You don't seem to own `%s' directory\n",
+             filename);
+      return FALSE;
+    }
+    
+    /* Check the permissions of the dir */
+    if ((st.st_mode & 0777) != 0755) {
+      if ((chmod(filename, 0755)) == -1) {
+       fprintf(stderr, "Permissions for `%s' directory must be 0755\n", 
+               filename);
+       return FALSE;
+      }
+    }
+  }
+
+  /*
+   * Check ~./silc/serverkeys directory
+   */
+  if ((stat(servfilename, &st)) == -1) {
+    /* If dir doesn't exist */
+    if (errno == ENOENT) {
+      if (pw->pw_uid == geteuid()) {
+       if ((mkdir(servfilename, 0755)) == -1) {
+         fprintf(stderr, "Couldn't create `%s' directory\n", servfilename);
+         return FALSE;
+       }
+      } else {
+       fprintf(stderr, "Couldn't create `%s' directory due to a wrong uid!\n",
+               servfilename);
+       return FALSE;
+      }
+    } else {
+      fprintf(stderr, "%s\n", strerror(errno));
+      return FALSE;
+    }
+  }
+  
+  /*
+   * Check Public and Private keys
+   */
+  snprintf(file_public_key, sizeof(file_public_key) - 1, "%s%s", 
+          filename, SILC_CLIENT_PUBLIC_KEY_NAME);
+  snprintf(file_private_key, sizeof(file_private_key) - 1, "%s%s", 
+          filename, SILC_CLIENT_PRIVATE_KEY_NAME);
+  
+  /* If running SILC first time */
+  if (firstime) {
+    fprintf(stdout, "Running SILC for the first time\n");
+    silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS, 
+                               SILC_CLIENT_DEF_PKCS_LEN,
+                               file_public_key, file_private_key, 
+                               identifier, NULL, NULL);
+    return TRUE;
+  }
+  
+  if ((stat(file_public_key, &st)) == -1) {
+    /* If file doesn't exist */
+    if (errno == ENOENT) {
+      fprintf(stdout, "Your public key doesn't exist\n");
+      silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS, 
+                                 SILC_CLIENT_DEF_PKCS_LEN,
+                                 file_public_key, 
+                                 file_private_key, identifier, NULL, NULL);
+    } else {
+      fprintf(stderr, "%s\n", strerror(errno));
+      return FALSE;
+    }
+  }
+
+  if ((stat(file_private_key, &st)) == -1) {
+    /* If file doesn't exist */
+    if (errno == ENOENT) {
+      fprintf(stdout, "Your private key doesn't exist\n");
+      silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS, 
+                                 SILC_CLIENT_DEF_PKCS_LEN,
+                                 file_public_key, 
+                                 file_private_key, identifier, NULL, NULL);
+    } else {
+      fprintf(stderr, "%s\n", strerror(errno));
+      return FALSE;
+    }
+  }
+    
+  /* Check the owner of the public key */
+  if (st.st_uid != 0 && st.st_uid != pw->pw_uid) { 
+    fprintf(stderr, "You don't seem to own your public key!?\n");
+    return FALSE;
+  }
+  
+  /* Check the owner of the private key */
+  if (st.st_uid != 0 && st.st_uid != pw->pw_uid) { 
+    fprintf(stderr, "You don't seem to own your private key!?\n");
+    return FALSE;
+  }
+    
+  /* Check the permissions for the private key */
+  if ((st.st_mode & 0777) != 0600) {
+    fprintf(stderr, "Wrong permissions in your private key file `%s'!\n"
+           "Trying to change them ... ", file_private_key);
+    if ((chmod(file_private_key, 0600)) == -1) {
+      fprintf(stderr,
+             "Failed to change permissions for private key file!\n" 
+             "Permissions for your private key file must be 0600.\n");
+      return FALSE;
+    }
+    fprintf(stderr, "Done.\n\n");
+  }
+
+  /* See if the key has expired. */
+  modtime = st.st_mtime;       /* last modified */
+  curtime = time(0) - modtime;
+    
+  /* 86400 is seconds in a day. */
+  if (curtime >= (86400 * SILC_CLIENT_KEY_EXPIRES)) {
+    fprintf(stdout, 
+           "--------------------------------------------------\n"
+           "Your private key has expired and needs to be\n" 
+           "recreated.  This will be done automatically now.\n"
+           "Your new key will expire in %d days from today.\n"
+           "--------------------------------------------------\n",
+           SILC_CLIENT_KEY_EXPIRES);
+
+    silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS, 
+                               SILC_CLIENT_DEF_PKCS_LEN,
+                               file_public_key, 
+                               file_private_key, identifier, NULL, NULL);
+  }
+  
+  if (identifier)
+    silc_free(identifier);
+
+  return TRUE;
+}
+
+/* Loads public and private key from files. */
+
+int silc_client_load_keys(SilcClient client)
+{
+  char filename[256];
+  struct passwd *pw;
+
+  SILC_LOG_DEBUG(("Loading public and private keys"));
+
+  pw = getpwuid(getuid());
+  if (!pw)
+    return FALSE;
+
+  memset(filename, 0, sizeof(filename));
+  snprintf(filename, sizeof(filename) - 1, "%s/.silc/%s", 
+          pw->pw_dir, SILC_CLIENT_PRIVATE_KEY_NAME);
+
+  if (silc_pkcs_load_private_key(filename, &client->private_key,
+                                SILC_PKCS_FILE_BIN) == FALSE)
+    if (silc_pkcs_load_private_key(filename, &client->private_key,
+                                  SILC_PKCS_FILE_PEM) == FALSE)
+      return FALSE;
+
+  memset(filename, 0, sizeof(filename));
+  snprintf(filename, sizeof(filename) - 1, "%s/.silc/%s", 
+          pw->pw_dir, SILC_CLIENT_PUBLIC_KEY_NAME);
+
+  if (silc_pkcs_load_public_key(filename, &client->public_key,
+                               SILC_PKCS_FILE_PEM) == FALSE)
+    if (silc_pkcs_load_public_key(filename, &client->public_key,
+                                 SILC_PKCS_FILE_BIN) == FALSE)
+      return FALSE;
+
+  return TRUE;
 }
index e18cf2d71eef0a5c8f576d3057137e1a8403773c..38f0d9e857b7cfc88e28c0f6cd3c85f093c242cf 100644 (file)
 #define CLIENTUTIL_H
 
 /* Prototypes */
-void silc_say(SilcClient client, char *msg, ...);
+void silc_print_to_window(WINDOW *win, char *message);
 void silc_print(SilcClient client, char *msg, ...);
 char *silc_get_mail_path();
 int silc_get_number_of_emails();
 char *silc_get_username();
 char *silc_get_real_name();
 int silc_client_time_til_next_min();
-char *silc_client_ask_passphrase(SilcClient client);
+int silc_client_ask_yes_no(SilcClient client, char *prompt);
 char *silc_client_get_input(const char *prompt);
 char *silc_client_get_passphrase(const char *prompt);
 void silc_client_list_ciphers();
 void silc_client_list_hash_funcs();
 void silc_client_list_pkcs();
-void silc_client_create_key_pair(char *pkcs_name, int bits);
+char *silc_client_create_identifier();
+int silc_client_create_key_pair(char *pkcs_name, int bits,
+                               char *public_key, char *private_key,
+                               char *identifier, 
+                               SilcPublicKey *ret_pub_key,
+                               SilcPrivateKey *ret_prv_key);
+int silc_client_check_silc_dir();
+int silc_client_load_keys(SilcClient client);
 
 #endif
diff --git a/apps/silc/command.c b/apps/silc/command.c
deleted file mode 100644 (file)
index 96c8e3c..0000000
+++ /dev/null
@@ -1,584 +0,0 @@
-/*
-
-  command.c
-
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
-
-  Copyright (C) 1997 - 2000 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
-  GNU General Public License for more details.
-
-*/
-/*
- * $Id$
- * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:56  priikone
- *     Importet from internal CVS/Added Log headers.
- *
- *
- */
-
-#include "clientincludes.h"
-
-/* Client command list. */
-SilcClientCommand silc_command_list[] =
-{
-  SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", SILC_CF_LAG | SILC_CF_REG, 3),
-  SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", SILC_CF_LAG | SILC_CF_REG, 3),
-  SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 
-                 SILC_CF_LAG | SILC_CF_REG, 3),
-  SILC_CLIENT_CMD(nick, NICK, "NICK", SILC_CF_LAG | SILC_CF_REG, 2),
-  SILC_CLIENT_CMD(list, LIST, "LIST", SILC_CF_LAG | SILC_CF_REG, 2),
-  SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", SILC_CF_LAG | SILC_CF_REG, 2),
-  SILC_CLIENT_CMD(invite, INVITE, "INVITE", SILC_CF_LAG | SILC_CF_REG, 2),
-  SILC_CLIENT_CMD(quit, QUIT, "QUIT", SILC_CF_LAG | SILC_CF_REG, 1),
-  SILC_CLIENT_CMD(kill, KILL, "KILL", 
-                 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
-  SILC_CLIENT_CMD(info, INFO, "INFO", SILC_CF_LAG | SILC_CF_REG, 2),
-  SILC_CLIENT_CMD(connect, CONNECT, "CONNECT",
-                 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
-  SILC_CLIENT_CMD(ping, PING, "PING", SILC_CF_LAG | SILC_CF_REG, 2),
-  SILC_CLIENT_CMD(oper, OPER, "OPER",
-                 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
-  SILC_CLIENT_CMD(join, JOIN, "JOIN", SILC_CF_LAG | SILC_CF_REG, 2),
-  SILC_CLIENT_CMD(motd, MOTD, "MOTD", SILC_CF_LAG | SILC_CF_REG, 2),
-  SILC_CLIENT_CMD(umode, UMODE, "UMODE", SILC_CF_LAG | SILC_CF_REG, 2),
-  SILC_CLIENT_CMD(cmode, CMODE, "CMODE", SILC_CF_LAG | SILC_CF_REG, 2),
-  SILC_CLIENT_CMD(kick, KICK, "KICK", SILC_CF_LAG | SILC_CF_REG, 2),
-  SILC_CLIENT_CMD(restart, RESTART, "RESTART",
-                 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
-  SILC_CLIENT_CMD(close, CLOSE, "CLOSE",
-                 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
-  SILC_CLIENT_CMD(die, DIE, "DIE",
-                 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
-  SILC_CLIENT_CMD(silcoper, SILCOPER, "SILOPER",
-                 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER, 2),
-  SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", SILC_CF_LAG | SILC_CF_REG, 2),
-  SILC_CLIENT_CMD(names, NAMES, "NAMES", SILC_CF_LAG | SILC_CF_REG, 2),
-
-  /*
-   * Local. client specific commands
-   */
-  SILC_CLIENT_CMD(help, HELP, "HELP", SILC_CF_NONE, 2),
-  SILC_CLIENT_CMD(clear, CLEAR, "CLEAR", SILC_CF_NONE, 1),
-  SILC_CLIENT_CMD(version, VERSION, "VERSION", SILC_CF_NONE, 1),
-  SILC_CLIENT_CMD(server, SERVER, "SERVER", SILC_CF_NONE, 2),
-  SILC_CLIENT_CMD(msg, MSG, "MSG", SILC_CF_NONE, 3),
-  SILC_CLIENT_CMD(away, AWAY, "AWAY", SILC_CF_NONE, 2),
-
-  { NULL, 0, NULL, 0},
-};
-
-/* List of pending commands. */
-SilcClientCommandPending *silc_command_pending = NULL;
-
-/* Add new pending command to the list of pending commands. Currently
-   pending commands are executed from command replies, thus we can
-   execute any command after receiving some specific command reply.
-
-   The argument `reply_cmd' is the command reply from where the callback
-   function is to be called, thus, it IS NOT the command to be executed.
-
-   XXX: If needed in the future this support may be extended for
-   commands as well, when any command could be executed after executing
-   some specific command. */
-
-void silc_client_command_pending(SilcCommand reply_cmd,
-                                SilcClientCommandCallback callback,
-                                void *context)
-{
-  SilcClientCommandPending *reply, *r;
-
-  reply = silc_calloc(1, sizeof(*reply));
-  reply->reply_cmd = reply_cmd;
-  reply->context = context;
-  reply->callback = callback;
-
-  if (silc_command_pending == NULL) {
-    silc_command_pending = reply;
-    return;
-  }
-
-  for (r = silc_command_pending; r; r = r->next) {
-    if (r->next == NULL) {
-      r->next = reply;
-      break;
-    }
-  }
-}
-
-/* Deletes pending command by reply command type. */
-
-void silc_client_command_pending_del(SilcCommand reply_cmd)
-{
-  SilcClientCommandPending *r, *tmp;
-  
-  if (silc_command_pending) {
-    if (silc_command_pending->reply_cmd == reply_cmd) {
-      silc_free(silc_command_pending);
-      silc_command_pending = NULL;
-      return;
-    }
-
-    for (r = silc_command_pending; r; r = r->next) {
-      if (r->next && r->next->reply_cmd == reply_cmd) {
-       tmp = r->next;
-       r->next = r->next->next;
-       silc_free(tmp);
-       break;
-      }
-    }
-  }
-}
-
-/* Free command context and its internals */
-
-static void silc_client_command_free(SilcClientCommandContext cmd)
-{
-  int i;
-
-  if (cmd) {
-    for (i = 0; i < cmd->argc; i++)
-      silc_free(cmd->argv[i]);
-    silc_free(cmd);
-  }
-}
-
-/* Command WHOIS. This command is used to query information about 
-   specific user. */
-
-SILC_CLIENT_CMD_FUNC(whois)
-{
-  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
-  SilcBuffer buffer;
-
-  if (cmd->argc < 2 || cmd->argc > 3) {
-    silc_say(cmd->client, "Usage: /WHOIS <nickname>[@<server>] [<count>]");
-    goto out;
-  }
-
-  if (!cmd->client->current_win->sock) {
-    silc_say(cmd->client, 
-            "You are not connected to a server, use /SERVER to connect");
-    goto out;
-  }
-
-  buffer = silc_command_encode_payload(SILC_COMMAND_WHOIS,
-                                      cmd->argc - 1, ++cmd->argv,
-                                      ++cmd->argv_lens, ++cmd->argv_types);
-  silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
-                         SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
-                         buffer->data, buffer->len, TRUE);
-  silc_buffer_free(buffer);
-  cmd->argv--;
-  cmd->argv_lens--;
-  cmd->argv_types--;
-
- out:
-  silc_client_command_free(cmd);
-}
-
-SILC_CLIENT_CMD_FUNC(whowas)
-{
-}
-
-/* Command IDENTIFY. This command is used to query information about 
-   specific user, especially ID's. */
-
-SILC_CLIENT_CMD_FUNC(identify)
-{
-  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
-  SilcBuffer buffer;
-
-  if (cmd->argc < 2 || cmd->argc > 3) {
-    silc_say(cmd->client, "Usage: /IDENTIFY <nickname>[@<server>] [<count>]");
-    goto out;
-  }
-
-  if (!cmd->client->current_win->sock) {
-    silc_say(cmd->client, 
-            "You are not connected to a server, use /SERVER to connect");
-    goto out;
-  }
-
-  buffer = silc_command_encode_payload(SILC_COMMAND_IDENTIFY,
-                                      cmd->argc - 1, ++cmd->argv,
-                                      ++cmd->argv_lens, ++cmd->argv_types);
-  silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
-                         SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
-                         buffer->data, buffer->len, TRUE);
-  silc_buffer_free(buffer);
-  cmd->argv--;
-  cmd->argv_lens--;
-  cmd->argv_types--;
-
- out:
-  silc_client_command_free(cmd);
-}
-
-/* Command NICK. Shows current nickname/sets new nickname on current
-   window. */
-
-SILC_CLIENT_CMD_FUNC(nick)
-{
-  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
-  SilcClientWindow win = NULL;
-  SilcBuffer buffer;
-
-  if (!cmd->sock) {
-    silc_say(cmd->client, 
-            "You are not connected to a server, use /SERVER to connect");
-    goto out;
-  }
-
-  /* Show current nickname */
-  if (cmd->argc < 2) {
-    if (cmd->sock) {
-      silc_say(cmd->client, "Your nickname is %s on server %s", 
-              win->nickname, win->remote_host);
-    } else {
-      silc_say(cmd->client, "Your nickname is %s", win->nickname);
-    }
-    goto out;
-  }
-
-  win = (SilcClientWindow)cmd->sock->user_data;
-
-  /* Set new nickname */
-  buffer = silc_command_encode_payload(SILC_COMMAND_NICK,
-                                      cmd->argc - 1, ++cmd->argv,
-                                      ++cmd->argv_lens, ++cmd->argv_types);
-  silc_client_packet_send(cmd->client, cmd->sock,
-                         SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
-                         buffer->data, buffer->len, TRUE);
-  silc_buffer_free(buffer);
-  cmd->argv--;
-  cmd->argv_lens--;
-  cmd->argv_types--;
-  if (win->nickname)
-    silc_free(win->nickname);
-  win->nickname = strdup(cmd->argv[1]);
-
- out:
-  silc_client_command_free(cmd);
-}
-
-/* Command SERVER. Connects to remote SILC server. This is local command. */
-
-SILC_CLIENT_CMD_FUNC(server)
-{
-  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
-  int len, port;
-  char *hostname;
-
-  if (cmd->argc < 2) {
-    /* Show current servers */
-    if (!cmd->client->current_win->sock) {
-      silc_say(cmd->client, "You are not connected to any server");
-      silc_say(cmd->client, "Usage: /SERVER [<server>[:<port>]]");
-      goto out;
-    }
-
-    goto out;
-  }
-
-  /* See if port is included and then extract it */
-  if (strchr(cmd->argv[1], ':')) {
-    len = strcspn(cmd->argv[1], ":");
-    hostname = silc_calloc(len + 1, sizeof(char));
-    memcpy(hostname, cmd->argv[1], len);
-    port = atoi(cmd->argv[1] + 1 + len);
-  } else {
-    hostname = cmd->argv[1];
-    /* XXX */
-    port = 334;
-  }
-
-  /* Connect asynchronously to not to block user interface */
-  silc_client_connect_to_server(cmd->client, port, hostname);
-
- out:
-  silc_client_command_free(cmd);
-}
-
-SILC_CLIENT_CMD_FUNC(list)
-{
-}
-
-SILC_CLIENT_CMD_FUNC(topic)
-{
-}
-
-SILC_CLIENT_CMD_FUNC(invite)
-{
-}
-
-/* Command QUIT. Closes connection with current server. */
-SILC_CLIENT_CMD_FUNC(quit)
-{
-  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
-  SilcBuffer buffer;
-
-  if (!cmd->client->current_win->sock) {
-    silc_say(cmd->client, 
-            "You are not connected to a server, use /SERVER to connect");
-    goto out;
-  }
-
-  buffer = silc_command_encode_payload(SILC_COMMAND_QUIT, cmd->argc - 1, 
-                                      ++cmd->argv, ++cmd->argv_lens,
-                                      ++cmd->argv_types);
-  silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
-                         SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
-                         buffer->data, buffer->len, TRUE);
-  silc_buffer_free(buffer);
-  cmd->argv--;
-  cmd->argv_lens--;
-  cmd->argv_types--;
-
-  /* Close connection */
-  silc_client_close_connection(cmd->client, cmd->sock);
-  cmd->client->screen->bottom_line->connection = NULL;
-  silc_screen_print_bottom_line(cmd->client->screen, 0);
-
-  silc_client_command_free(cmd);
-}
-
-SILC_CLIENT_CMD_FUNC(kill)
-{
-}
-
-SILC_CLIENT_CMD_FUNC(info)
-{
-}
-
-SILC_CLIENT_CMD_FUNC(connect)
-{
-}
-
-SILC_CLIENT_CMD_FUNC(ping)
-{
-}
-
-SILC_CLIENT_CMD_FUNC(oper)
-{
-}
-
-SILC_CLIENT_CMD_FUNC(trace)
-{
-}
-
-SILC_CLIENT_CMD_FUNC(notice)
-{
-}
-
-/* Command JOIN. Joins to a channel. */
-
-SILC_CLIENT_CMD_FUNC(join)
-{
-  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
-  SilcClientWindow win = NULL;
-  SilcIDCache *id_cache = NULL;
-  SilcBuffer buffer;
-
-#define CIDC(x) win->channel_id_cache[(x) - 32]
-#define CIDCC(x) win->channel_id_cache_count[(x) - 32]
-
-  if (cmd->argc < 2) {
-    /* Show channels currently joined to */
-    if (!cmd->client->current_win->sock) {
-      silc_say(cmd->client, "No current channel for this window");
-      silc_say(cmd->client, 
-              "You are not connected to a server, use /SERVER to connect");
-      goto out;
-
-    }
-
-    goto out;
-  }
-
-  if (!cmd->client->current_win->sock) {
-    silc_say(cmd->client, 
-            "You are not connected to a server, use /SERVER to connect");
-    goto out;
-  }
-
-  win = (SilcClientWindow)cmd->sock->user_data;
-
-  /* See if we have joined to the requested channel already */
-  silc_idcache_find_by_data(CIDC(cmd->argv[1][0]), CIDCC(cmd->argv[1][0]), 
-                           cmd->argv[1], &id_cache);
-
-  if (id_cache) {
-    silc_say(cmd->client, "You are talking to channel %s", cmd->argv[1]);
-    win->current_channel = (SilcChannelEntry)id_cache->context;
-    cmd->client->screen->bottom_line->channel = cmd->argv[1];
-    silc_screen_print_bottom_line(cmd->client->screen, 0);
-    goto out;
-  }
-
-  /* Send JOIN command to the server */
-  buffer = silc_command_encode_payload(SILC_COMMAND_JOIN,
-                                      cmd->argc - 1, ++cmd->argv,
-                                      ++cmd->argv_lens, ++cmd->argv_types);
-  silc_client_packet_send(cmd->client, cmd->client->current_win->sock,
-                         SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
-                         buffer->data, buffer->len, TRUE);
-  silc_buffer_free(buffer);
-  cmd->argv--;
-  cmd->argv_lens--;
-  cmd->argv_types--;
-
- out:
-  silc_client_command_free(cmd);
-#undef CIDC
-#undef CIDCC
-}
-
-SILC_CLIENT_CMD_FUNC(motd)
-{
-}
-
-SILC_CLIENT_CMD_FUNC(umode)
-{
-}
-
-SILC_CLIENT_CMD_FUNC(cmode)
-{
-}
-
-SILC_CLIENT_CMD_FUNC(kick)
-{
-}
-
-SILC_CLIENT_CMD_FUNC(restart)
-{
-}
-SILC_CLIENT_CMD_FUNC(close)
-{
-}
-SILC_CLIENT_CMD_FUNC(die)
-{
-}
-SILC_CLIENT_CMD_FUNC(silcoper)
-{
-}
-
-SILC_CLIENT_CMD_FUNC(leave)
-{
-}
-
-SILC_CLIENT_CMD_FUNC(names)
-{
-}
-
-/*
- * Local commands
- */
-
-/* HELP command. This is local command and shows help on SILC */
-
-SILC_CLIENT_CMD_FUNC(help)
-{
-
-}
-
-/* CLEAR command. This is local command and clears current output window */
-
-SILC_CLIENT_CMD_FUNC(clear)
-{
-  SilcClient client = (SilcClient)context;
-
-  assert(client->current_win != NULL);
-  wclear((WINDOW *)client->current_win->screen);
-  wrefresh((WINDOW *)client->current_win->screen);
-}
-
-/* VERSION command. This is local command and shows version of the client */
-
-SILC_CLIENT_CMD_FUNC(version)
-{
-
-}
-
-/* Command MSG. Sends private message to user or list of users. */
-/* XXX supports only one destination */
-
-SILC_CLIENT_CMD_FUNC(msg)
-{
-  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
-  SilcClientWindow win = NULL;
-  SilcClient client = cmd->client;
-  SilcBuffer buffer;
-  SilcIDCache *id_cache;
-  unsigned int nick_len;
-
-  if (cmd->argc < 3) {
-    silc_say(cmd->client, "Usage: /MSG <nickname> <message>");
-    goto out;
-  }
-
-  if (!cmd->client->current_win->sock) {
-    silc_say(cmd->client, 
-            "You are not connected to a server, use /SERVER to connect");
-    goto out;
-  }
-
-  win = (SilcClientWindow)cmd->sock->user_data;
-
-#define CIDC(x) win->client_id_cache[(x) - 32], \
-                win->client_id_cache_count[(x) - 32]
-
-  /* Find ID from cache */
-  if (silc_idcache_find_by_data(CIDC(cmd->argv[1][0]), cmd->argv[1], 
-                               &id_cache) == FALSE) {
-    SilcClientCommandContext ctx;
-    char ident[512];
-
-    SILC_LOG_DEBUG(("Requesting Client ID from server"));
-
-    /* No ID found. Do query from the server. The query is done by 
-       sending simple IDENTIFY command to the server. */
-    ctx = silc_calloc(1, sizeof(*ctx));
-    ctx->client = client;
-    ctx->sock = cmd->sock;
-    memset(ident, 0, sizeof(ident));
-    snprintf(ident, sizeof(ident), "/IDENTIFY %s", cmd->argv[1]);
-    silc_client_parse_command_line(ident, &ctx->argv, &ctx->argv_lens, 
-                                  &ctx->argv_types, &ctx->argc, 2);
-    silc_client_command_identify(ctx);
-
-    /* Mark this command to be pending command and to be executed after
-       we have received the IDENTIFY reply from server. */
-    silc_client_command_pending(SILC_COMMAND_IDENTIFY, 
-                               silc_client_command_msg, context);
-    return;
-  }
-
-  /* Display the message for our eyes. */
-  silc_print(client, "-> *%s* %s", cmd->argv[1], cmd->argv[2]);
-
-  /* Send the private message */
-  silc_client_packet_send_private_message(client, cmd->sock, id_cache->context,
-                                         cmd->argv[2], cmd->argv_lens[2],
-                                         TRUE);
- out:
-  silc_client_command_free(cmd);
-#undef CIDC
-}
-
-SILC_CLIENT_CMD_FUNC(away)
-{
-}
diff --git a/apps/silc/command_reply.c b/apps/silc/command_reply.c
deleted file mode 100644 (file)
index 491808e..0000000
+++ /dev/null
@@ -1,551 +0,0 @@
-/*
-
-  command_reply.c
-
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
-
-  Copyright (C) 1997 - 2000 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
-  GNU General Public License for more details.
-
-*/
-/*
- * Command reply functions are "the otherside" of the command functions.
- * Reply to a command sent by server is handled by these functions.
- */
-/*
- * $Id$
- * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:56  priikone
- *     Importet from internal CVS/Added Log headers.
- *
- *
- */
-
-#include "clientincludes.h"
-
-/* Client command reply list. */
-SilcClientCommandReply silc_command_reply_list[] =
-{
-  SILC_CLIENT_CMD_REPLY(whois, WHOIS),
-  SILC_CLIENT_CMD_REPLY(whowas, WHOWAS),
-  SILC_CLIENT_CMD_REPLY(identify, IDENTIFY),
-  SILC_CLIENT_CMD_REPLY(nick, NICK),
-  SILC_CLIENT_CMD_REPLY(list, LIST),
-  SILC_CLIENT_CMD_REPLY(topic, TOPIC),
-  SILC_CLIENT_CMD_REPLY(invite, INVITE),
-  SILC_CLIENT_CMD_REPLY(quit, QUIT),
-  SILC_CLIENT_CMD_REPLY(kill, KILL),
-  SILC_CLIENT_CMD_REPLY(info, INFO),
-  SILC_CLIENT_CMD_REPLY(away, AWAY),
-  SILC_CLIENT_CMD_REPLY(connect, CONNECT),
-  SILC_CLIENT_CMD_REPLY(ping, PING),
-  SILC_CLIENT_CMD_REPLY(oper, OPER),
-  SILC_CLIENT_CMD_REPLY(join, JOIN),
-  SILC_CLIENT_CMD_REPLY(motd, MOTD),
-  SILC_CLIENT_CMD_REPLY(umode, UMODE),
-  SILC_CLIENT_CMD_REPLY(cmode, CMODE),
-  SILC_CLIENT_CMD_REPLY(kick, KICK),
-  SILC_CLIENT_CMD_REPLY(restart, RESTART),
-  SILC_CLIENT_CMD_REPLY(close, CLOSE),
-  SILC_CLIENT_CMD_REPLY(die, DIE),
-  SILC_CLIENT_CMD_REPLY(silcoper, SILCOPER),
-  SILC_CLIENT_CMD_REPLY(leave, LEAVE),
-  SILC_CLIENT_CMD_REPLY(names, LEAVE),
-
-  { NULL, 0 },
-};
-
-/* Status message structure. Messages are defined below. */
-typedef struct {
-  SilcCommandStatus status;
-  char *message;
-} SilcCommandStatusMessage;
-
-/* Status messages returned by the server */
-#define STAT(x) SILC_STATUS_ERR_##x
-const SilcCommandStatusMessage silc_command_status_messages[] = {
-
-  { STAT(NO_SUCH_NICK),      "No such nickname" },
-  { STAT(NO_SUCH_CHANNEL),   "No such channel" },
-  { STAT(NO_SUCH_SERVER),    "No such server" },
-  { STAT(TOO_MANY_TARGETS),  "Duplicate recipients. No message delivered" },
-  { STAT(NO_RECIPIENT),      "No recipient given" },
-  { STAT(UNKNOWN_COMMAND),   "Unknown command" },
-  { STAT(WILDCARDS),         "Unknown command" },
-  { STAT(NO_CLIENT_ID),      "No Client ID given" },
-  { STAT(NO_CHANNEL_ID),     "No Channel ID given" },
-  { STAT(BAD_CLIENT_ID),     "Bad Client ID" },
-  { STAT(BAD_CHANNEL_ID),    "Bad Channel ID" },
-  { STAT(NO_SUCH_CLIENT_ID), "No such Client ID" },
-  { STAT(NO_SUCH_CHANNEL_ID),"No such Channel ID" },
-  { STAT(NICKNAME_IN_USE),   "Nickname already exists" },
-  { STAT(NOT_ON_CHANNEL),    "You are not on that channel" },
-  { STAT(USER_ON_CHANNEL),   "User already on channel" },
-  { STAT(NOT_REGISTERED),    "You have not registered" },
-  { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
-  { STAT(TOO_MANY_PARAMS),   "Too many parameters" },
-  { STAT(PERM_DENIED),       "Your host is not among the privileged" },
-  { STAT(BANNED_FROM_SERVER),"You are banned from this server" },
-  { STAT(BAD_PASSWORD),      "Cannot join channel. Incorrect password" },
-  { STAT(CHANNEL_IS_FULL),   "Cannot join channel. Channel is full" },
-  { STAT(NOT_INVITED),     "Cannot join channel. You have not been invited" },
-  { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
-  { STAT(UNKNOWN_MODE),    "Unknown mode" },
-  { STAT(NOT_YOU),         "Cannot change mode for other users" },
-  { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
-  { STAT(NO_SERVER_PRIV),  "Permission denied. You are not server operator" },
-  { STAT(NO_ROUTER_PRIV),  "Permission denied. You are not SILC operator" },
-  { STAT(BAD_NICKNAME),    "Bad nickname" },
-  { STAT(BAD_CHANNEL),     "Bad channel name" },
-  { STAT(AUTH_FAILED),     "Authentication failed" },
-
-  { 0, NULL }
-};
-
-/* Process received command reply. */
-
-void silc_client_command_reply_process(SilcClient client,
-                                      SilcSocketConnection sock,
-                                      SilcBuffer buffer)
-{
-  SilcClientCommandReplyContext ctx;
-  SilcCommandPayload payload;
-
-  /* Get command reply payload from packet */
-  payload = silc_command_parse_payload(buffer);
-  if (!payload) {
-    /* Silently ignore bad reply packet */
-    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));
-  ctx->client = client;
-  ctx->sock = sock;
-  ctx->payload = payload;
-      
-  /* Check for pending commands and mark to be exeucted */
-  SILC_CLIENT_COMMAND_CHECK_PENDING(ctx);
-  
-  /* Execute command reply */
-  SILC_CLIENT_COMMAND_REPLY_EXEC(ctx);
-}
-
-/* Returns status message string */
-
-static char *
-silc_client_command_status_message(SilcCommandStatus status)
-{
-  int i;
-
-  for (i = 0; silc_command_status_messages[i].message; i++) {
-    if (silc_command_status_messages[i].status == status)
-      break;
-  }
-
-  if (silc_command_status_messages[i].message == NULL)
-    return NULL;
-
-  return silc_command_status_messages[i].message;
-}
-
-/* Free command reply context and its internals. */
-
-void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
-{
-  if (cmd) {
-    silc_command_free_payload(cmd->payload);
-    silc_free(cmd);
-  }
-}
-
-/* Received reply for WHOIS command. This maybe called several times
-   for one WHOIS command as server may reply with list of results. */
-
-SILC_CLIENT_CMD_REPLY_FUNC(whois)
-{
-  SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
-  SilcClient client = cmd->client;
-  SilcCommandStatus status;
-  unsigned char *tmp;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
-  SILC_GET16_MSB(status, tmp);
-  if (status != SILC_STATUS_OK) {
-    if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
-      tmp += 2;
-      silc_say(cmd->client, "%s: %s", tmp,
-              silc_client_command_status_message(status));
-      goto out;
-    } else {
-      silc_say(cmd->client, "%s", silc_client_command_status_message(status));
-      goto out;
-    }
-  }
-
-  /* Display one whois reply */
-  if (status == SILC_STATUS_OK) {
-    char buf[256];
-    int argc, len;
-    unsigned char *id_data;
-    char *nickname = NULL, *username = NULL;
-    char *realname = NULL;
-    void *id;
-
-    memset(buf, 0, sizeof(buf));
-
-    argc = silc_command_get_arg_num(cmd->payload);
-    id_data = silc_command_get_arg_type(cmd->payload, 2, NULL);
-
-    nickname = silc_command_get_arg_type(cmd->payload, 3, &len);
-    if (nickname) {
-      strncat(buf, nickname, len);
-      strncat(buf, " is ", 4);
-    }
-
-    username = silc_command_get_arg_type(cmd->payload, 4, &len);
-    if (username) {
-      strncat(buf, username, len);
-    }
-
-    realname = silc_command_get_arg_type(cmd->payload, 5, &len);
-    if (realname) {
-      strncat(buf, " (", 2);
-      strncat(buf, realname, len);
-      strncat(buf, ")", 1);
-    }
-
-#if 0
-    /* Save received Client ID to ID cache */
-    /* XXX Maybe should not be saved as /MSG will get confused */
-    id = silc_id_str2id(id_data, SILC_ID_CLIENT);
-    client->current_win->client_id_cache_count[(int)nickname[0] - 32] =
-    silc_idcache_add(&client->current_win->
-                    client_id_cache[(int)nickname[0] - 32],
-                    client->current_win->
-                    client_id_cache_count[(int)nickname[0] - 32],
-                    strdup(nickname), SILC_ID_CLIENT, id, NULL);
-#endif
-
-    silc_say(cmd->client, "%s", buf);
-   }
-
-  if (status == SILC_STATUS_LIST_START) {
-
-  }
-
-  if (status == SILC_STATUS_LIST_END) {
-
-  }
-
-  SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_WHOIS);
-
- out:
-  silc_client_command_reply_free(cmd);
-}
-
-SILC_CLIENT_CMD_REPLY_FUNC(whowas)
-{
-}
-
-/* Received reply for IDENTIFY command. This maybe called several times
-   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)
-{
-  SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
-  SilcClientWindow win = (SilcClientWindow)cmd->sock->user_data;
-  SilcClientEntry client_entry;
-  SilcCommandStatus status;
-  unsigned char *tmp;
-
-  SILC_LOG_DEBUG(("Start"));
-
-#define CIDC(x) win->client_id_cache[(x) - 32]
-#define CIDCC(x) win->client_id_cache_count[(x) - 32]
-
-  tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
-  SILC_GET16_MSB(status, tmp);
-  if (status != SILC_STATUS_OK) {
-    if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
-      tmp += 2;
-      silc_say(cmd->client, "%s: %s", tmp,
-              silc_client_command_status_message(status));
-      goto out;
-    } else {
-      silc_say(cmd->client, "%s", silc_client_command_status_message(status));
-      goto out;
-    }
-  }
-
-  /* Display one whois reply */
-  if (status == SILC_STATUS_OK) {
-    unsigned char *id_data;
-    char *nickname;
-
-    id_data = silc_command_get_arg_type(cmd->payload, 2, NULL);
-    nickname = silc_command_get_arg_type(cmd->payload, 3, NULL);
-
-    /* Allocate client entry */
-    client_entry = silc_calloc(1, sizeof(*client_entry));
-    client_entry->id = silc_id_str2id(id_data, SILC_ID_CLIENT);
-    client_entry->nickname = strdup(nickname);
-
-    /* Save received Client ID to ID cache */
-    CIDCC(nickname[0]) =
-      silc_idcache_add(&CIDC(nickname[0]), CIDCC(nickname[0]),
-                      client_entry->nickname, SILC_ID_CLIENT, 
-                      client_entry->id, client_entry);
-  }
-
-  if (status == SILC_STATUS_LIST_START) {
-
-  }
-
-  if (status == SILC_STATUS_LIST_END) {
-
-  }
-
-  SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_IDENTIFY);
-
- out:
-  silc_client_command_reply_free(cmd);
-#undef CIDC
-#undef CIDCC
-}
-
-/* Received reply for command NICK. If everything went without errors
-   we just received our new Client ID. */
-
-SILC_CLIENT_CMD_REPLY_FUNC(nick)
-{
-  SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
-  SilcClientWindow win = (SilcClientWindow)cmd->sock->user_data;
-  SilcCommandStatus status;
-  unsigned char *tmp, *id_string;
-  int argc;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
-  SILC_GET16_MSB(status, tmp);
-  if (status != SILC_STATUS_OK) {
-    silc_say(cmd->client, "Cannot set nickname: %s", 
-            silc_client_command_status_message(status));
-    goto out;
-  }
-
-  argc = silc_command_get_arg_num(cmd->payload);
-  if (argc < 2 || argc > 2) {
-    silc_say(cmd->client, "Cannot set nickname: bad reply to command");
-    goto out;
-  }
-
-  /* Take received Client ID */
-  id_string = silc_command_get_arg_type(cmd->payload, 2, NULL);
-  silc_client_receive_new_id(cmd->client, cmd->sock, id_string);
-
-  /* Update nickname on screen */
-  cmd->client->screen->bottom_line->nickname = win->nickname;
-  silc_screen_print_bottom_line(cmd->client->screen, 0);
-
- out:
-  silc_client_command_reply_free(cmd);
-}
-
-SILC_CLIENT_CMD_REPLY_FUNC(list)
-{
-}
-
-SILC_CLIENT_CMD_REPLY_FUNC(topic)
-{
-}
-
-SILC_CLIENT_CMD_REPLY_FUNC(invite)
-{
-}
-SILC_CLIENT_CMD_REPLY_FUNC(quit)
-{
-}
-
-SILC_CLIENT_CMD_REPLY_FUNC(kill)
-{
-}
-
-SILC_CLIENT_CMD_REPLY_FUNC(info)
-{
-}
-
-SILC_CLIENT_CMD_REPLY_FUNC(away)
-{
-}
-
-SILC_CLIENT_CMD_REPLY_FUNC(connect)
-{
-}
-
-SILC_CLIENT_CMD_REPLY_FUNC(ping)
-{
-}
-
-SILC_CLIENT_CMD_REPLY_FUNC(oper)
-{
-}
-
-/* Received reply for JOIN command. */
-
-SILC_CLIENT_CMD_REPLY_FUNC(join)
-{
-  SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
-  SilcClient client = cmd->client;
-  SilcCommandStatus status;
-  unsigned int argc;
-  unsigned char *id_string;
-  char *topic, *tmp, *channel_name;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
-  SILC_GET16_MSB(status, tmp);
-  if (status != SILC_STATUS_OK) {
-    silc_say(cmd->client, "%s", silc_client_command_status_message(status));
-    goto out;
-  }
-
-  argc = silc_command_get_arg_num(cmd->payload);
-  if (argc < 3 || argc > 4) {
-    silc_say(cmd->client, "Cannot join channel: Bad reply packet");
-    goto out;
-  }
-
-  /* Get channel name */
-  tmp = silc_command_get_arg_type(cmd->payload, 2, NULL);
-  channel_name = strdup(tmp);
-
-  /* Get channel ID */
-  id_string = silc_command_get_arg_type(cmd->payload, 3, NULL);
-
-  /* Get topic */
-  topic = silc_command_get_arg_type(cmd->payload, 4, NULL);
-
-  /* Save received Channel ID */
-  silc_client_new_channel_id(cmd->client, cmd->sock, channel_name, id_string);
-
-  /* Print channel name on screen */
-  client->screen->bottom_line->channel = channel_name;
-  silc_screen_print_bottom_line(client->screen, 0);
-
-  if (topic)
-    silc_say(client, "Topic for %s: %s", channel_name, topic);
-
- out:
-  silc_client_command_reply_free(cmd);
-}
-
-SILC_CLIENT_CMD_REPLY_FUNC(motd)
-{
-}
-
-SILC_CLIENT_CMD_REPLY_FUNC(umode)
-{
-}
-
-SILC_CLIENT_CMD_REPLY_FUNC(cmode)
-{
-}
-
-SILC_CLIENT_CMD_REPLY_FUNC(kick)
-{
-}
-
-SILC_CLIENT_CMD_REPLY_FUNC(restart)
-{
-}
-SILC_CLIENT_CMD_REPLY_FUNC(close)
-{
-}
-SILC_CLIENT_CMD_REPLY_FUNC(die)
-{
-}
-SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
-{
-}
-
-SILC_CLIENT_CMD_REPLY_FUNC(leave)
-{
-}
-
-SILC_CLIENT_CMD_REPLY_FUNC(names)
-{
-}
-
-/* Private message received. This processes the private message and
-   finally displays it on the screen. */
-
-SILC_CLIENT_CMD_REPLY_FUNC(msg)
-{
-  SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
-  SilcClient client = cmd->client;
-  SilcBuffer buffer = (SilcBuffer)cmd->context;
-  unsigned short nick_len;
-  unsigned char *nickname, *message;
-  SilcIDCache *id_cache;
-  unsigned char *id_string;
-  void *id;
-
-  /* Get nickname */
-  silc_buffer_unformat(buffer, 
-                      SILC_STR_UI16_NSTRING_ALLOC(&nickname, &nick_len),
-                      SILC_STR_END);
-  silc_buffer_pull(buffer, 2 + nick_len);
-
-#if 0
-  /* Get ID of the sender */
-  id_string = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char *));
-  silc_buffer_push(buffer, SILC_ID_CLIENT_LEN + SILC_ID_CLIENT_LEN);
-  memcpy(id_string, buffer->data, SILC_ID_CLIENT_LEN);
-  silc_buffer_pull(buffer, SILC_ID_CLIENT_LEN + SILC_ID_CLIENT_LEN);
-  id = silc_id_str2id(id_string, SILC_ID_CLIENT);
-  silc_free(id_string);
-
-  /* Nickname should be verified if we don't have it in the cache */
-  if (silc_idcache_find_by_data(client->current_win->
-                               client_id_cache[nickname[0] - 32],
-                               client->current_win->
-                               client_id_cache_count[nickname[0] - 32],
-                               nickname, &id_cache) == FALSE) {
-
-    SilcClientCommandContext ctx;
-    char whois[255];
-
-    /* Private message from unknown source, try to resolve it. */
-
-
-    return;
-  }
-#endif
-     
-  message = silc_calloc(buffer->len + 1, sizeof(char));
-  memcpy(message, buffer->data, buffer->len);
-  silc_print(client, "*%s* %s", nickname, message);
-  memset(message, 0, buffer->len);
-  silc_free(message);
-}
diff --git a/apps/silc/local_command.c b/apps/silc/local_command.c
new file mode 100644 (file)
index 0000000..3d969f7
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+
+  local_command.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 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
+  GNU General Public License for more details.
+
+*/
+/*
+ * $Id$
+ * $Log$
+ * Revision 1.1  2000/09/13 17:47:54  priikone
+ *     Created SILC Client Libary by moving stuff from silc/ directory.
+ *     SILC client library is SILC client without UI. Old UI still exists
+ *     in silc/ directory and uses the new client.
+ *
+ *     Bug fixes and several new functions, structures and functions
+ *     naming changes during the change was made.
+ *
+ */
+
+#include "clientincludes.h"
+
+/* Local commands. */
+SilcClientCommand silc_local_command_list[] =
+{
+  SILC_CLIENT_LCMD(help, HELP, "HELP", 0, 2),
+  SILC_CLIENT_LCMD(clear, CLEAR, "CLEAR", 0, 1),
+  SILC_CLIENT_LCMD(version, VERSION, "VERSION", 0, 1),
+  SILC_CLIENT_LCMD(server, SERVER, "SERVER", 0, 2),
+  SILC_CLIENT_LCMD(msg, MSG, "MSG", 0, 3),
+  SILC_CLIENT_LCMD(away, AWAY, "AWAY", 0, 2),
+
+  { NULL, 0, NULL, 0, 0 },
+};
+
+/* Finds and returns a pointer to the command list. Return NULL if the
+   command is not found. */
+
+SilcClientCommand *silc_client_local_command_find(const char *name)
+{
+  SilcClientCommand *cmd;
+
+  for (cmd = silc_local_command_list; cmd->name; cmd++) {
+    if (!strcmp(cmd->name, name))
+      return cmd;
+  }
+
+  return NULL;
+}
+
+/* HELP command. This is local command and shows help on SILC */
+
+SILC_CLIENT_LCMD_FUNC(help)
+{
+
+}
+
+/* CLEAR command. This is local command and clears current output window */
+
+SILC_CLIENT_LCMD_FUNC(clear)
+{
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClient client = cmd->client;
+  SilcClientInternal app = (SilcClientInternal)client->application;
+
+#if 0
+  wclear((WINDOW *)app->screen);
+  wrefresh((WINDOW *)app->screen);
+#endif
+
+  silc_client_command_free(cmd);
+}
+
+/* VERSION command. This is local command and shows version of the client */
+
+SILC_CLIENT_LCMD_FUNC(version)
+{
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClient client = cmd->client;
+  extern char *silc_version;
+  extern char *silc_name;
+  extern char *silc_fullname;
+
+  silc_say(client, cmd->conn,
+          "%s (%s) version %s", silc_name, silc_fullname,
+          silc_version);
+
+  silc_client_command_free(cmd);
+}
+
+/* Command MSG. Sends private message to user or list of users. Note that
+   private messages are not really commands, they are message packets,
+   however, on user interface it is convenient to show them as commands
+   as that is the common way of sending private messages (like in IRC). */
+/* XXX supports only one destination */
+
+SILC_CLIENT_LCMD_FUNC(msg)
+{
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClientConnection conn = cmd->conn;
+  SilcClient client = cmd->client;
+  SilcClientEntry client_entry = NULL;
+  unsigned int num = 0;
+  char *nickname = NULL, *server = NULL;
+
+  if (!cmd->conn) {
+    silc_say(client, conn,
+            "You are not connected to a server, use /SERVER to connect");
+    goto out;
+  }
+
+  if (cmd->argc < 3) {
+    silc_say(client, conn, "Usage: /MSG <nickname> <message>");
+    goto out;
+  }
+
+  /* Parse the typed nickname. */
+  if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
+    silc_say(client, conn, "Bad nickname");
+    goto out;
+  }
+
+  /* Find client entry */
+  client_entry = silc_idlist_get_client(client, conn, nickname, server, num);
+  if (!client_entry) {
+    /* Client entry not found, it was requested thus mark this to be
+       pending command. */
+    silc_client_command_pending(SILC_COMMAND_IDENTIFY, 
+                               silc_client_local_command_msg, context);
+    return;
+  }
+
+  /* Display the message for our eyes. */
+  silc_print(client, "-> *%s* %s", cmd->argv[1], cmd->argv[2]);
+
+  /* Send the private message */
+  silc_client_packet_send_private_message(client, conn->sock, client_entry,
+                                         cmd->argv[2], cmd->argv_lens[2],
+                                         TRUE);
+
+ out:
+  silc_client_command_free(cmd);
+}
+
+
+/* Command SERVER. Connects to remote SILC server. This is local command. */
+
+SILC_CLIENT_LCMD_FUNC(server)
+{
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClient client = cmd->client;
+  SilcClientConnection conn = cmd->conn;
+  int i = 0, len, port;
+  char *hostname;
+
+  if (cmd->argc < 2) {
+    /* Show current servers */
+
+    if (!cmd->conn) {
+      silc_say(client, conn, "You are not connected to any server");
+      silc_say(client, conn, "Usage: /SERVER [<server>[:<port>]]");
+      goto out;
+    }
+
+    silc_say(client, conn, "Current server: %s on %d %s", 
+            conn->remote_host, conn->remote_port,
+            conn->remote_info ? conn->remote_info : "");
+    
+    silc_say(client, conn, "Server list:");
+    for (i = 0; i < client->conns_count; i++) {
+      silc_say(client, conn, " [%d] %s on %d %s", i + 1,
+              client->conns[i]->remote_host, 
+              client->conns[i]->remote_port,
+              client->conns[i]->remote_info ? 
+              client->conns[i]->remote_info : "");
+    }
+
+    goto out;
+  }
+
+  /* See if port is included and then extract it */
+  if (strchr(cmd->argv[1], ':')) {
+    len = strcspn(cmd->argv[1], ":");
+    hostname = silc_calloc(len + 1, sizeof(char));
+    memcpy(hostname, cmd->argv[1], len);
+    port = atoi(cmd->argv[1] + 1 + len);
+  } else {
+    hostname = cmd->argv[1];
+    port = 706;
+  }
+
+  /* Connect asynchronously to not to block user interface */
+  silc_client_connect_to_server(cmd->client, port, hostname, NULL);
+
+ out:
+  silc_client_command_free(cmd);
+}
+
+/* Local command AWAY. Client replies with away message to whomever sends
+   private message to the client if the away message is set. If this is
+   given without arguments the away message is removed. */
+
+SILC_CLIENT_LCMD_FUNC(away)
+{
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClientConnection conn = cmd->conn;
+  SilcClient client = cmd->client;
+  SilcClientInternal app = (SilcClientInternal)client->application;
+
+  if (!cmd->conn) {
+    silc_say(client, conn,
+            "You are not connected to a server, use /SERVER to connect");
+    goto out;
+  }
+
+  if (cmd->argc == 1) {
+    if (conn->away) {
+      silc_free(conn->away->away);
+      silc_free(conn->away);
+      conn->away = NULL;
+      app->screen->bottom_line->away = FALSE;
+
+      silc_say(client, conn, "Away message removed");
+      silc_screen_print_bottom_line(app->screen, 0);
+    }
+  } else {
+
+    if (conn->away)
+      silc_free(conn->away->away);
+    else
+      conn->away = silc_calloc(1, sizeof(*conn->away));
+    
+    app->screen->bottom_line->away = TRUE;
+    conn->away->away = strdup(cmd->argv[1]);
+
+    silc_say(client, conn, "Away message set: %s", conn->away->away);
+    silc_screen_print_bottom_line(app->screen, 0);
+  }
+
+ out:
+  silc_client_command_free(cmd);
+}
diff --git a/apps/silc/local_command.h b/apps/silc/local_command.h
new file mode 100644 (file)
index 0000000..5673057
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+
+  local_command.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 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
+  GNU General Public License for more details.
+
+*/
+
+#ifndef LOCAL_COMMAND_H
+#define LOCAL_COMMAND_H
+
+/* All local commands */
+extern SilcClientCommand silc_local_command_list[];
+
+/* Local commands */
+#define SILC_LOCAL_COMMAND_HELP                1
+#define SILC_LOCAL_COMMAND_CLEAR       2
+#define SILC_LOCAL_COMMAND_VERSION     3
+#define SILC_LOCAL_COMMAND_SERVER       4
+#define SILC_LOCAL_COMMAND_MSG                 5
+#define SILC_LOCAL_COMMAND_AWAY                6
+
+/* Macros */
+
+/* Macro used for command declaration in command list structure */
+#define SILC_CLIENT_LCMD(func, cmd, name, flags, args) \
+{ silc_client_local_command_##func, SILC_LOCAL_COMMAND_##cmd, \
+  name, flags, args }
+
+/* Macro used to declare command functions */
+#define SILC_CLIENT_LCMD_FUNC(func) \
+void silc_client_local_command_##func(void *context)
+
+/* Prototypes */
+SilcClientCommand *silc_client_local_command_find(const char *name);
+SILC_CLIENT_LCMD_FUNC(help);
+SILC_CLIENT_LCMD_FUNC(clear);
+SILC_CLIENT_LCMD_FUNC(version);
+SILC_CLIENT_LCMD_FUNC(msg);
+SILC_CLIENT_LCMD_FUNC(server);
+SILC_CLIENT_LCMD_FUNC(away);
+
+#endif
diff --git a/apps/silc/pubkey.pub b/apps/silc/pubkey.pub
deleted file mode 100644 (file)
index 7dc0bfd..0000000
Binary files a/apps/silc/pubkey.pub and /dev/null differ
index f3f44567fe182f29d627662f358ce87ef49b3e8d..dba669258178f72b5f6f179b0ce7f635334afa56 100644 (file)
  * old version of the SILC client dating back to 1997.
  */
 /* XXX: Input line handling is really buggy! */
-/*
- * $Id$
- * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:56  priikone
- *     Importet from internal CVS/Added Log headers.
- *
- *
- */
+/* $Id$ */
 
 #include "clientincludes.h"
 
@@ -38,16 +31,7 @@ SilcScreen silc_screen_init()
 {
   SilcScreen new;
 
-  new = silc_malloc(sizeof(*new));
-  if (new == NULL) {
-    SILC_LOG_ERROR(("Could not create new screen object"));
-    return NULL;
-  }
-
-  new->output_win_count = 0;
-  new->input_pos = 0;
-  new->cursor_pos = 0;
-  new->virtual_window = 0;
+  new = silc_calloc(1, sizeof(*new));
   new->insert = TRUE;
 
   initscr();
@@ -68,7 +52,7 @@ WINDOW *silc_screen_create_output_window(SilcScreen screen)
 {
   assert(screen != NULL);
 
-  screen->output_win = silc_malloc(sizeof(*screen->output_win) * 1);
+  screen->output_win = silc_calloc(1, sizeof(*screen->output_win));
   screen->output_win_count = 1;
   screen->output_win[0] = newwin(LINES - 3, COLS, 1, 0);
   scrollok(screen->output_win[0], TRUE);
@@ -111,15 +95,20 @@ void silc_screen_create_input_window(SilcScreen screen)
 
 void silc_screen_init_upper_status_line(SilcScreen screen)
 {
-  int i;
-  int justify;
-  
   assert(screen != NULL);
 
   /* Create upper status line */
   screen->upper_stat_line = newwin(0, COLS, 0, 0);
   scrollok(screen->upper_stat_line, FALSE);
   wattrset(screen->upper_stat_line, A_REVERSE);
+
+  silc_screen_print_upper_stat_line(screen);
+}
+
+void silc_screen_print_upper_stat_line(SilcScreen screen)
+{
+  int i;
+  int justify;
   
   /* Print empty line */
   for (i = 0; i < COLS - 1; i++)
@@ -130,13 +119,6 @@ void silc_screen_init_upper_status_line(SilcScreen screen)
   mvwprintw(screen->upper_stat_line, 0, 1, "%s %s", 
            screen->u_stat_line.program_name, 
            screen->u_stat_line.program_version);
-  /*
-  mvwprintw(screen->upper_stat_line, 0, justify, "[Your Connection: %s]", 
-           stat.uconnect_status[stat.uconnect]);
-  mvwprintw(screen->upper_stat_line, 0, 
-           (justify + justify + justify), "[SILC: %s]", 
-           stat.silc_status[stat.silc]);
-  */
 
   /* Prints clock on upper stat line */        
   silc_screen_print_clock(screen);
@@ -225,6 +207,17 @@ void silc_screen_print_bottom_line(SilcScreen screen, int win_index)
            SILC_SCREEN_MAX_CHANNEL_LEN : len);
   }
 
+  if (line->channel_mode) {
+    len = strlen(line->channel_mode);
+    strncat(buf, " (+", 3);
+    strncat(buf, line->channel_mode, len > SILC_SCREEN_MAX_CHANNEL_LEN ?
+           SILC_SCREEN_MAX_CHANNEL_LEN : len);
+    strncat(buf, ")", 2);
+  }
+
+  if (line->away)
+    strncat(buf, " (away)", 8);
+
   wattrset(screen->output_stat_line[win_index], A_REVERSE);
 
   for (i = 0; i < COLS - 10; i++)
@@ -244,15 +237,20 @@ void silc_screen_refresh_all(SilcScreen screen)
 
   assert(screen != NULL);
 
-  redrawwin(screen->upper_stat_line);
+  wclear(screen->upper_stat_line);
+  silc_screen_print_upper_stat_line(screen);
+
+  wclear(screen->output_stat_line[0]);
+  silc_screen_print_bottom_line(screen, 0);
+  silc_screen_print_coordinates(screen, 0);
 
   for (i = 0; i < screen->output_win_count; i++) {
+    wclear(screen->output_win[i]);
     wrefresh(screen->output_win[i]);
-    redrawwin(screen->output_win[i]);
   }
 
+  wclear(screen->input_win);
   wrefresh(screen->input_win);
-  redrawwin(screen->input_win);
 }
 
 /* Refreshes a window */
@@ -309,9 +307,9 @@ void silc_screen_input_backspace(SilcScreen screen)
       screen->virtual_window--;
       
       waddnstr(win, &buffer[screen->virtual_window * (COLS - 5)], COLS);
-      screen->input_pos = ((screen->virtual_window + 1) * (COLS - 5)) + 1;
-      screen->input_end = ((screen->virtual_window + 1) * (COLS - 5)) + 1;
-      screen->cursor_pos = (COLS - 5) + 1;
+      screen->input_pos = ((screen->virtual_window + 1) * (COLS - 5));
+      screen->input_end = ((screen->virtual_window + 1) * (COLS - 5));
+      screen->cursor_pos = (COLS - 5);
       wrefresh(win);
     }
   }
@@ -413,8 +411,8 @@ void silc_screen_input_cursor_left(SilcScreen screen)
       screen->virtual_window--;
       
       waddnstr(win, &buffer[screen->virtual_window * (COLS - 5)], COLS);
-      screen->input_pos = ((screen->virtual_window + 1) * (COLS - 5)) + 1;
-      screen->cursor_pos = (COLS - 5) + 1;
+      screen->input_pos = ((screen->virtual_window + 1) * (COLS - 5));
+      screen->cursor_pos = (COLS - 5);
       wrefresh(win);
     }
   }
index 25d083b06278c54c619f6351dd2b294a413faf60..ffa89ffd511fa656f78f8c3e89850e7f634056ce 100644 (file)
@@ -26,6 +26,8 @@ typedef struct {
   char *nickname;
   char *connection;
   char *channel;
+  char *channel_mode;
+  int away;
 } *SilcScreenBottomLine;
 
 typedef struct {
@@ -53,8 +55,8 @@ typedef struct {
 
   /* XXX */
   struct upper_status_line {
-    char *program_name;
-    char *program_version;
+    const char *program_name;
+    const char *program_version;
   } u_stat_line;
 
 } SilcScreenObject;
@@ -103,6 +105,7 @@ WINDOW *silc_screen_create_output_window(SilcScreen screen);
 WINDOW *silc_screen_add_output_window(SilcScreen screen);
 void silc_screen_create_input_window(SilcScreen screen);
 void silc_screen_init_upper_status_line(SilcScreen screen);
+void silc_screen_print_upper_stat_line(SilcScreen screen);
 void silc_screen_init_output_status_line(SilcScreen screen);
 void silc_screen_print_clock(SilcScreen screen);
 void silc_screen_print_coordinates(SilcScreen screen, int win_index);
index e510ad2dbcd2a85256324ff9fe27e9d5ea193fff..203224cc900566229cd23798bd6a08ee937ee1e9 100644 (file)
   GNU General Public License for more details.
 
 */
-/*
- * $Id$
- * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:56  priikone
- *     Importet from internal CVS/Added Log headers.
- *
- *
- */
+/* $Id$ */
 
 #include "clientincludes.h"
 #include "version.h"
 
+/* Static function prototypes */
+static int silc_client_bad_keys(unsigned char key);
+static void silc_client_clear_input(SilcClientInternal app);
+static void silc_client_process_message(SilcClientInternal app);
+static char *silc_client_parse_command(unsigned char *buffer);
+
+void silc_client_create_main_window(SilcClientInternal app);
+
+/* Static task callback prototypes */
+SILC_TASK_CALLBACK(silc_client_update_clock);
+SILC_TASK_CALLBACK(silc_client_run_commands);
+SILC_TASK_CALLBACK(silc_client_process_key_press);
+
 /* Long command line options */
 static struct option long_opts[] = 
 {
@@ -42,6 +48,7 @@ static struct option long_opts[] =
   { "private-key", 1, NULL, 'k' },
   { "config-file", 1, NULL, 'f' },
   { "no-silcrc", 0, NULL, 'q' },
+  { "debug", 0, NULL, 'd' },
   { "help", 0, NULL, 'h' },
   { "version", 0, NULL, 'V' },
   { "list-ciphers", 0, NULL, 1 },
@@ -71,6 +78,9 @@ static int opt_create_keypair = FALSE;
 static char *opt_pkcs = NULL;
 static int opt_bits = 0;
 
+/* SILC Client operations */
+extern SilcClientOperations ops;
+
 /* Prints out the usage of silc client */
 
 void usage()
@@ -88,6 +98,7 @@ Usage: silc [options]\n\
   -k, --private-key=FILE       Private key used in SILC\n\
   -f, --config-file=FILE       Alternate configuration file\n\
   -q, --no-silcrc              Don't load ~/.silcrc on startup\n\
+  -d, --debug                  Enable debugging\n\
   -h, --help                   Display this help message\n\
   -V, --version                Display version\n\
       --list-ciphers           List supported ciphers\n\
@@ -106,13 +117,15 @@ int main(int argc, char **argv)
   int opt, option_index = 1;
   int ret;
   SilcClient silc = NULL;
-  SilcClientConfig config = NULL;
-  
+  SilcClientInternal app = NULL;
+
+  silc_debug = FALSE;
+
   if (argc > 1) 
     {
       while ((opt = 
              getopt_long(argc, argv,
-                         "s:p:n:c:b:k:f:qhVC",
+                         "s:p:n:c:b:k:f:qdhVC",
                          long_opts, &option_index)) != EOF)
        {
          switch(opt) 
@@ -155,6 +168,9 @@ int main(int argc, char **argv)
            case 'q':
              opt_no_silcrc = TRUE;
              break;
+           case 'd':
+             silc_debug = TRUE;
+             break;
            case 'h':
              usage();
              exit(0);
@@ -214,36 +230,98 @@ SILC Secure Internet Live Conferencing, version %s\n",
   signal(SIGFPE, SIG_DFL);
   //  signal(SIGINT, SIG_IGN);
   
+#ifdef SOCKS
+  /* Init SOCKS */
+  SOCKSinit(argv[0]);
+#endif
+
+  if (opt_create_keypair == TRUE) {
+    /* Create new key pair and exit */
+    silc_client_create_key_pair(opt_pkcs, opt_bits, 
+                               NULL, NULL, NULL, NULL, NULL);
+    exit(0);
+  }
+
   /* Default configuration file */
   if (!opt_config_file)
     opt_config_file = strdup(SILC_CLIENT_CONFIG_FILE);
 
+  /* Allocate internal application context */
+  app = silc_calloc(1, sizeof(*app));
+
+  /* Allocate new client */
+  app->client = silc = silc_client_alloc(&ops, app);
+  if (!silc)
+    goto fail;
+
   /* Read global configuration file. */
-  config = silc_client_config_alloc(opt_config_file);
-  if (config == NULL)
+  app->config = silc_client_config_alloc(opt_config_file);
+  if (app->config == NULL)
     goto fail;
 
-  if (opt_create_keypair == TRUE) {
-    /* Create new key pair and exit */
-    silc_client_create_key_pair(opt_pkcs, opt_bits);
-    exit(0);
-  }
+  /* XXX Read local configuration file */
 
-  /* Read local configuration file */
+  /* Check ~/.silc directory and public and private keys */
+  if (silc_client_check_silc_dir() == FALSE)
+    goto fail;
 
+  /* Get user information */
+  silc->username = silc_get_username();
+  silc->hostname = silc_net_localhost();
+  silc->realname = silc_get_real_name();
 
-  /* Allocate new client */
-  ret = silc_client_alloc(&silc);
-  if (ret == FALSE)
+  /* Register all configured ciphers, PKCS and hash functions. */
+  app->config->client = (void *)app;
+  silc_client_config_register_ciphers(app->config);
+  silc_client_config_register_pkcs(app->config);
+  silc_client_config_register_hashfuncs(app->config);
+
+  /* Load public and private key */
+  if (silc_client_load_keys(silc) == FALSE)
     goto fail;
 
-  /* Initialize the client */
-  silc->config = config;
+  /* Initialize the client. This initializes the client library and
+     sets everything ready for silc_client_run. */
   ret = silc_client_init(silc);
   if (ret == FALSE)
     goto fail;
 
-  /* Run the client */
+  /* Register the main task that is used in client. This receives
+     the key pressings. */
+  silc_task_register(silc->io_queue, fileno(stdin), 
+                    silc_client_process_key_press,
+                    (void *)silc, 0, 0, 
+                    SILC_TASK_FD,
+                    SILC_TASK_PRI_NORMAL);
+
+  /* Register timeout task that updates clock every minute. */
+  silc_task_register(silc->timeout_queue, 0,
+                    silc_client_update_clock,
+                    (void *)silc, 
+                    silc_client_time_til_next_min(), 0,
+                    SILC_TASK_TIMEOUT,
+                    SILC_TASK_PRI_LOW);
+
+  if (app->config->commands) {
+    /* Run user configured commands with timeout */
+    silc_task_register(silc->timeout_queue, 0,
+                      silc_client_run_commands,
+                      (void *)silc, 0, 1,
+                      SILC_TASK_TIMEOUT,
+                      SILC_TASK_PRI_LOW);
+  }
+
+  /* Allocate the input buffer used to save typed characters */
+  app->input_buffer = silc_buffer_alloc(SILC_SCREEN_INPUT_WIN_SIZE);
+  silc_buffer_pull_tail(app->input_buffer, 
+                       SILC_BUFFER_END(app->input_buffer));
+
+  /* Initialize the screen */
+  silc_client_create_main_window(app);
+  silc_screen_print_coordinates(app->screen, 0);
+
+  /* Run the client. When this returns the application will be
+     terminated. */
   silc_client_run(silc);
 
   /* Stop the client. This probably has been done already but it
@@ -254,9 +332,332 @@ SILC Secure Internet Live Conferencing, version %s\n",
   exit(0);
 
  fail:
-  if (config)
-    silc_client_config_free(config);
+  if (opt_config_file)
+    silc_free(opt_config_file);
+  if (app->config)
+    silc_client_config_free(app->config);
   if (silc)
     silc_client_free(silc);
   exit(1);
 }
+
+/* Creates the main window used in SILC client. This is called always
+   at the initialization of the client. If user wants to create more
+   than one windows a new windows are always created by calling 
+   silc_client_add_window. */
+
+void silc_client_create_main_window(SilcClientInternal app)
+{
+  void *screen;
+
+  SILC_LOG_DEBUG(("Creating main window"));
+
+  app->screen = silc_screen_init();
+  app->screen->input_buffer = app->input_buffer->data;
+  app->screen->u_stat_line.program_name = silc_name;
+  app->screen->u_stat_line.program_version = silc_version;
+
+  /* Create the actual screen */
+  screen = (void *)silc_screen_create_output_window(app->screen);
+  silc_screen_create_input_window(app->screen);
+  silc_screen_init_upper_status_line(app->screen);
+  silc_screen_init_output_status_line(app->screen);
+
+  app->screen->bottom_line->nickname = silc_get_username();
+  silc_screen_print_bottom_line(app->screen, 0);
+}
+
+/* The main task on SILC client. This processes the key pressings user
+   has made. */
+
+SILC_TASK_CALLBACK(silc_client_process_key_press)
+{
+  SilcClient client = (SilcClient)context;
+  SilcClientInternal app = (SilcClientInternal)client->application;
+  int c;
+
+  /* There is data pending in stdin, this gets it directly */
+  c = wgetch(app->screen->input_win);
+  if (silc_client_bad_keys(c))
+    return;
+
+  SILC_LOG_DEBUG(("Pressed key: %d", c));
+
+  switch(c) {
+    /* 
+     * Special character handling
+     */
+  case KEY_UP: 
+  case KEY_DOWN:
+    break;
+  case KEY_RIGHT:
+    /* Right arrow */
+    SILC_LOG_DEBUG(("RIGHT"));
+    silc_screen_input_cursor_right(app->screen);
+    break;
+  case KEY_LEFT:
+    /* Left arrow */
+    SILC_LOG_DEBUG(("LEFT"));
+    silc_screen_input_cursor_left(app->screen);
+    break;
+  case KEY_BACKSPACE:
+  case KEY_DC:
+  case '\177':
+  case '\b':
+    /* Backspace */
+    silc_screen_input_backspace(app->screen);
+    break;
+  case '\011':
+    /* Tabulator */
+    break;
+  case KEY_IC:
+    /* Insert switch. Turns on/off insert on input window */
+    silc_screen_input_insert(app->screen);
+    break;
+  case CTRL('j'):
+  case '\r':
+    /* Enter, Return. User pressed enter we are ready to
+       process the message. */
+    silc_client_process_message(app);
+    break;
+  case CTRL('l'):
+    /* Refresh screen, Ctrl^l */
+    silc_screen_refresh_all(app->screen);
+    break;
+  case CTRL('a'):
+  case KEY_HOME:
+#ifdef KEY_BEG
+  case KEY_BEG:
+#endif
+    /* Beginning, Home */
+    silc_screen_input_cursor_home(app->screen);
+    break;
+  case CTRL('e'):
+#ifdef KEY_END
+  case KEY_END:
+#endif
+  case KEY_LL:
+    /* End */
+    silc_screen_input_cursor_end(app->screen);
+    break;
+  case CTRL('g'):
+    /* Bell, Ctrl^g */
+    beep();
+    break;
+  case KEY_DL:
+  case CTRL('u'):
+    /* Delete line */
+    silc_client_clear_input(app);
+    break;
+  default:
+    /* 
+     * Other characters 
+     */
+    if (c < 32) {
+      /* Control codes are printed as reversed */
+      c = (c & 127) | 64;
+      wattron(app->screen->input_win, A_REVERSE);
+      silc_screen_input_print(app->screen, c);
+      wattroff(app->screen->input_win, A_REVERSE);
+    } else  {
+      /* Normal character */
+      silc_screen_input_print(app->screen, c);
+    }
+  }
+
+  silc_screen_print_coordinates(app->screen, 0);
+  silc_screen_refresh_win(app->screen->input_win);
+}
+
+static int silc_client_bad_keys(unsigned char key)
+{
+  /* these are explained in curses.h */
+  switch(key) {
+  case KEY_SF:
+  case KEY_SR:
+  case KEY_NPAGE:
+  case KEY_PPAGE:
+  case KEY_PRINT:
+  case KEY_A1:
+  case KEY_A3:
+  case KEY_B2:
+  case KEY_C1:
+  case KEY_C3:
+#ifdef KEY_UNDO
+  case KEY_UNDO:
+#endif
+#ifdef KEY_EXIT
+  case KEY_EXIT:
+#endif
+  case '\v':           /* VT */
+  case '\E':           /* we ignore ESC */
+    return TRUE;
+  default: 
+    return FALSE; 
+  }
+}
+
+/* Clears input buffer */
+
+static void silc_client_clear_input(SilcClientInternal app)
+{
+  silc_buffer_clear(app->input_buffer);
+  silc_buffer_pull_tail(app->input_buffer,
+                       SILC_BUFFER_END(app->input_buffer));
+  silc_screen_input_reset(app->screen);
+}
+
+/* Processes messages user has typed on the screen. This either sends
+   a packet out to network or if command were written executes it. */
+
+static void silc_client_process_message(SilcClientInternal app)
+{
+  unsigned char *data;
+  unsigned int len;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  data = app->input_buffer->data;
+  len = strlen(data);
+
+  if (data[0] == '/' && data[1] != ' ') {
+    /* Command */
+    unsigned int argc = 0;
+    unsigned char **argv, *tmpcmd;
+    unsigned int *argv_lens, *argv_types;
+    SilcClientCommand *cmd;
+    SilcClientCommandContext ctx;
+
+    /* Get the command */
+    tmpcmd = silc_client_parse_command(data);
+    cmd = silc_client_local_command_find(tmpcmd);
+    if (!cmd && (cmd = silc_client_command_find(tmpcmd)) == NULL) {
+      silc_say(app->client, app->current_win, "Invalid command: %s", tmpcmd);
+      silc_free(tmpcmd);
+      goto out;
+    }
+
+    /* Now parse all arguments */
+    silc_parse_command_line(data + 1, &argv, &argv_lens, 
+                           &argv_types, &argc, cmd->max_args);
+    silc_free(tmpcmd);
+
+    SILC_LOG_DEBUG(("Executing command: %s", cmd->name));
+
+    /* Allocate command context. This and its internals must be free'd 
+       by the command routine receiving it. */
+    ctx = silc_calloc(1, sizeof(*ctx));
+    ctx->client = app->client;
+    ctx->conn = app->conn;
+    ctx->command = cmd;
+    ctx->argc = argc;
+    ctx->argv = argv;
+    ctx->argv_lens = argv_lens;
+    ctx->argv_types = argv_types;
+
+    /* Execute command */
+    (*cmd->cb)(ctx);
+
+  } else {
+    /* Normal message to a channel */
+    if (len && app->conn->current_channel &&
+       app->conn->current_channel->on_channel == TRUE) {
+      silc_print(app->client, "> %s", data);
+      silc_client_packet_send_to_channel(app->client, 
+                                        app->conn->sock,
+                                        app->conn->current_channel,
+                                        data, strlen(data), TRUE);
+    }
+  }
+
+ out:
+  /* Clear the input buffer */
+  silc_client_clear_input(app);
+}
+
+/* Returns the command fetched from user typed command line */
+
+static char *silc_client_parse_command(unsigned char *buffer)
+{
+  char *ret;
+  const char *cp = buffer;
+  int len;
+
+  len = strcspn(cp, " ");
+  ret = silc_to_upper((char *)++cp);
+  ret[len - 1] = 0;
+
+  return ret;
+}
+
+/* Updates clock on the screen every minute. */
+
+SILC_TASK_CALLBACK(silc_client_update_clock)
+{
+  SilcClient client = (SilcClient)context;
+  SilcClientInternal app = (SilcClientInternal)client->application;
+
+  /* Update the clock on the screen */
+  silc_screen_print_clock(app->screen);
+
+  /* Re-register this same task */
+  silc_task_register(qptr, 0, silc_client_update_clock, context, 
+                    silc_client_time_til_next_min(), 0,
+                    SILC_TASK_TIMEOUT,
+                    SILC_TASK_PRI_LOW);
+
+  silc_screen_refresh_win(app->screen->input_win);
+}
+
+/* Runs commands user configured in configuration file. This is
+   called when initializing client. */
+
+SILC_TASK_CALLBACK(silc_client_run_commands)
+{
+  SilcClient client = (SilcClient)context;
+  SilcClientInternal app = (SilcClientInternal)client->application;
+  SilcClientConfigSectionCommand *cs;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  cs = app->config->commands;
+  while(cs) {
+    unsigned int argc = 0;
+    unsigned char **argv, *tmpcmd;
+    unsigned int *argv_lens, *argv_types;
+    SilcClientCommand *cmd;
+    SilcClientCommandContext ctx;
+
+    /* Get the command */
+    tmpcmd = silc_client_parse_command(cs->command);
+    cmd = silc_client_local_command_find(tmpcmd);
+    if (!cmd && (cmd = silc_client_command_find(tmpcmd)) == NULL) {
+      silc_say(client, app->conn, "Invalid command: %s", tmpcmd);
+      silc_free(tmpcmd);
+      continue;
+    }
+    
+    /* Now parse all arguments */
+    silc_parse_command_line(cs->command + 1, &argv, &argv_lens, 
+                           &argv_types, &argc, cmd->max_args);
+    silc_free(tmpcmd);
+
+    SILC_LOG_DEBUG(("Executing command: %s", cmd->name));
+
+    /* Allocate command context. This and its internals must be free'd 
+       by the command routine receiving it. */
+    ctx = silc_calloc(1, sizeof(*ctx));
+    ctx->client = client;
+    ctx->conn = app->conn;
+    ctx->command = cmd;
+    ctx->argc = argc;
+    ctx->argv = argv;
+    ctx->argv_lens = argv_lens;
+    ctx->argv_types = argv_types;
+
+    /* Execute command */
+    (*cmd->cb)(ctx);
+
+    cs = cs->next;
+  }
+}
index baa83b349de6e9db3a35b664c7e7735b6aed74fe..828e2c03db10071020eeab1ddfa1dfe740756280 100644 (file)
    home directory. This may override global configuration settings. */
 #define SILC_CLIENT_HOME_CONFIG_FILE ".silcrc"
 
+/* Default public and private key file names */
+#define SILC_CLIENT_PUBLIC_KEY_NAME "public_key.pub"
+#define SILC_CLIENT_PRIVATE_KEY_NAME "private_key.prv"
+
+/* Default key expiration time, one year. */
+#define SILC_CLIENT_KEY_EXPIRES 365
+
+/* Default settings for creating key pair */
+#define SILC_CLIENT_DEF_PKCS "rsa"
+#define SILC_CLIENT_DEF_PKCS_LEN 1024
+
+/* XXX This is entirely temporary structure until UI is written again. */
+typedef struct {
+  /* Input buffer that holds the characters user types. This is
+     used only to store the typed chars for a while. */
+  SilcBuffer input_buffer;
+
+  /* The SILC client screen object */
+  SilcScreen screen;
+
+  /* Current physical window */
+  void *current_win;
+
+  SilcClientConnection conn;
+
+  /* Configuration object */
+  SilcClientConfig config;
+
+#ifdef SILC_SIM
+  /* SIM (SILC Module) table */
+  SilcSimContext **sim;
+  unsigned int sim_count;
+#endif
+
+  /* The allocated client */
+  SilcClient client;
+} *SilcClientInternal;
+
+/* Macros */
+
+#ifndef CTRL
+#define CTRL(x) ((x) & 0x1f)   /* Ctrl+x */
+#endif
+
 #endif
index 72dbaed53799f94dc42f308bfff143700cfa3e27..a8a8768ffda5cc4b6ae97403a87780428e044d54 100644 (file)
@@ -16,6 +16,6 @@ sha1::64:20
 #lassi.kuo.fi.ssh.com:passwd::1333
 
 [commands]
-#/server lassi.kuo.fi.ssh.com:1333
+#/server lassi.kuo.fi.ssh.com
 #/server lassi:1334
 #/server leevi:1333
index 385b8ccdc2ba6786cc1b0f871408b83a077c1e75..230ff60f5db0c33312257755085bc2b9db8cf82a 100644 (file)
@@ -32,11 +32,13 @@ silcd_SOURCES = \
        silcd.c \
        server_version.c
 
+silcd_DEPENDENCIES = ../lib/libsilc.a
+
 LDADD = -L. -L.. -L../lib -lsilc
 
 EXTRA_DIST = *.h
 
 INCLUDES = -I. -I.. -I../lib/silccore -I../lib/silccrypt \
        -I../lib/silcmath -I../lib/silcske -I../lib/silcsim \
-       -I../includes \
-       -I../lib/silcmath/gmp-3.0.1
+       -I../includes -I../lib/silcutil \
+       -I../lib/silcmath/gmp -I../lib/trq
index b9a0cc63b90f069216bf6bc42f1a58079f75f260..dbad3bf3689fd06d372e94e038ce2deb4551a733 100644 (file)
   GNU General Public License for more details.
 
 */
-/*
- * $Id$
- * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:56  priikone
- *     Importet from internal CVS/Added Log headers.
- *
- *
- */
+/* $Id$ */
 
 #include "serverincludes.h"
 #include "server_internal.h"
 
+static int silc_server_is_registered(SilcServer server,
+                                    SilcSocketConnection sock,
+                                    SilcServerCommandContext cmd,
+                                    SilcCommand command);
+static void 
+silc_server_command_send_status_reply(SilcServerCommandContext cmd,
+                                     SilcCommand command,
+                                     SilcCommandStatus status);
+static void 
+silc_server_command_send_status_data(SilcServerCommandContext cmd,
+                                    SilcCommand command,
+                                    SilcCommandStatus status,
+                                    unsigned int arg_type,
+                                    unsigned char *arg,
+                                    unsigned int arg_len);
+static void silc_server_command_free(SilcServerCommandContext cmd);
+
 /* Server command list. */
 SilcServerCommand silc_command_list[] =
 {
@@ -50,6 +60,7 @@ SilcServerCommand silc_command_list[] =
   SILC_SERVER_CMD(motd, MOTD, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(umode, UMODE, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(cmode, CMODE, SILC_CF_LAG | SILC_CF_REG),
+  SILC_SERVER_CMD(cumode, CUMODE, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG | SILC_CF_REG),
   SILC_SERVER_CMD(restart, RESTART, 
                  SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
@@ -67,6 +78,111 @@ SilcServerCommand silc_command_list[] =
 /* List of pending commands. */
 SilcServerCommandPending *silc_command_pending = NULL;
 
+/* Returns TRUE if the connection is registered. Unregistered connections
+   usually cannot send commands hence the check. */
+
+static int silc_server_is_registered(SilcServer server,
+                                    SilcSocketConnection sock,
+                                    SilcServerCommandContext cmd,
+                                    SilcCommand command)
+{
+  switch(sock->type) {
+  case SILC_SOCKET_TYPE_CLIENT:
+    {
+      SilcClientEntry client = (SilcClientEntry)sock->user_data;
+      if (client->registered)
+       return TRUE;
+      break;
+    }
+  case SILC_SOCKET_TYPE_SERVER:
+  case SILC_SOCKET_TYPE_ROUTER:
+    {
+      SilcServerEntry serv = (SilcServerEntry)sock->user_data;
+      if (serv->registered)
+       return TRUE;
+      break;
+    }
+  default:
+    break;
+  }
+
+  silc_server_command_send_status_reply(cmd, command,
+                                       SILC_STATUS_ERR_NOT_REGISTERED);
+  silc_server_command_free(cmd);
+  return FALSE;
+}
+
+/* Processes received command packet. */
+
+void silc_server_command_process(SilcServer server,
+                                SilcSocketConnection sock,
+                                SilcPacketContext *packet)
+{
+  SilcServerCommandContext ctx;
+  SilcServerCommand *cmd;
+
+#if 0
+  /* Check whether it is allowed for this connection to execute any
+     command. */
+  if (sock->type == SILC_SOCKET_TYPE_CLIENT) {
+    time_t curtime;
+    SilcClientEntry client = (SilcClientEntry)sock->user_data;
+
+    if (!client)
+      goto out;
+
+    /* Allow only one command executed in 2 seconds. */
+    curtime = time(NULL);
+    if (client->last_command && (curtime - client->last_command) < 2)
+      goto out;
+
+    /* Update access time */
+    client->last_command = curtime;
+  }
+#endif
+  
+  /* Allocate command context. This must be free'd by the
+     command routine receiving it. */
+  ctx = silc_calloc(1, sizeof(*ctx));
+  ctx->server = server;
+  ctx->sock = sock;
+  ctx->packet = packet;        /* Save original packet */
+  
+  /* Parse the command payload in the packet */
+  ctx->payload = silc_command_payload_parse(packet->buffer);
+  if (!ctx->payload) {
+    SILC_LOG_ERROR(("Bad command payload, packet dropped"));
+    silc_buffer_free(packet->buffer);
+    silc_free(ctx);
+    return;
+  }
+  ctx->args = silc_command_get_args(ctx->payload);
+  
+  /* Execute command. If this fails the packet is dropped. */
+  for (cmd = silc_command_list; cmd->cb; cmd++)
+    if (cmd->cmd == silc_command_get(ctx->payload)) {
+
+      if (!(cmd->flags & SILC_CF_REG)) {
+       cmd->cb(ctx);
+       break;
+      }
+      
+      if (silc_server_is_registered(server, sock, ctx, cmd->cmd)) {
+       cmd->cb(ctx);
+       break;
+      }
+    }
+
+  if (cmd == NULL) {
+    SILC_LOG_ERROR(("Unknown command, packet dropped"));
+    silc_free(ctx);
+    goto out;
+  }
+
+ out:
+  silc_buffer_free(packet->buffer);
+}
+
 /* Add new pending command to the list of pending commands. Currently
    pending commands are executed from command replies, thus we can
    execute any command after receiving some specific command reply.
@@ -132,48 +248,45 @@ static void silc_server_command_free(SilcServerCommandContext cmd)
   }
 }
 
-/* Sends command status message as command reply packet. */
+/* Sends simple status message as command reply packet */
 
 static void 
-silc_server_command_send_status_msg(SilcServerCommandContext cmd,
-                                   SilcCommand command,
-                                   SilcCommandStatus status,
-                                   unsigned char *msg,
-                                   unsigned int msg_len)
+silc_server_command_send_status_reply(SilcServerCommandContext cmd,
+                                     SilcCommand command,
+                                     SilcCommandStatus status)
 {
-  SilcBuffer sp_buf, buffer;
+  SilcBuffer buffer;
 
   SILC_LOG_DEBUG(("Sending command status %d", status));
 
-  sp_buf = silc_command_encode_status_payload(status, msg, msg_len);
-  buffer = silc_command_encode_payload_va(command, 1, 
-                                         sp_buf->data, sp_buf->len);
+  buffer = silc_command_reply_payload_encode_va(command, status, 0, 0);
   silc_server_packet_send(cmd->server, cmd->sock,
                          SILC_PACKET_COMMAND_REPLY, 0, 
                          buffer->data, buffer->len, FALSE);
   silc_buffer_free(buffer);
-  silc_buffer_free(sp_buf);
 }
 
-/* Sends simple status message as command reply packet */
+/* Sends command status reply with one extra argument. The argument
+   type must be sent as argument. */
 
 static void 
-silc_server_command_send_status_reply(SilcServerCommandContext cmd,
-                                     SilcCommand command,
-                                     SilcCommandStatus status)
+silc_server_command_send_status_data(SilcServerCommandContext cmd,
+                                    SilcCommand command,
+                                    SilcCommandStatus status,
+                                    unsigned int arg_type,
+                                    unsigned char *arg,
+                                    unsigned int arg_len)
 {
-  SilcBuffer sp_buf, buffer;
+  SilcBuffer buffer;
 
   SILC_LOG_DEBUG(("Sending command status %d", status));
 
-  sp_buf = silc_command_encode_status_payload(status, NULL, 0);
-  buffer = silc_command_encode_payload_va(command, 1, 
-                                         sp_buf->data, sp_buf->len);
+  buffer = silc_command_reply_payload_encode_va(command, status, 0, 1,
+                                               arg_type, arg, arg_len);
   silc_server_packet_send(cmd->server, cmd->sock,
                          SILC_PACKET_COMMAND_REPLY, 0, 
                          buffer->data, buffer->len, FALSE);
   silc_buffer_free(buffer);
-  silc_buffer_free(sp_buf);
 }
 
 /* Server side of command WHOIS. Processes user's query and sends found 
@@ -182,153 +295,202 @@ silc_server_command_send_status_reply(SilcServerCommandContext cmd,
 SILC_SERVER_CMD_FUNC(whois)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
-  char *tmp, *nick = NULL, *server = NULL;
-  unsigned int argc, count = 0, len;
-  SilcClientList *entry;
-  SilcBuffer sp_buf, packet;
-  unsigned char *id_string;
+  SilcServer server = cmd->server;
+  char *tmp, *nick = NULL, *server_name = NULL;
+  unsigned int i, argc, count = 0, len, clients_count;
+  int use_id = FALSE;
+  SilcClientID *client_id = NULL;
+  SilcBuffer packet, idp;
+  SilcClientEntry *clients = NULL, entry;
+  SilcCommandStatus status;
 
   SILC_LOG_DEBUG(("Start"));
 
-  argc = silc_command_get_arg_num(cmd->payload);
+  argc = silc_argument_get_arg_num(cmd->args);
   if (argc < 1) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
                                          SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
-  if (argc > 2) {
+  if (argc > 3) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
                                          SILC_STATUS_ERR_TOO_MANY_PARAMS);
     goto out;
   }
 
-  /* Get the nickname@server string and parse it. */
-  tmp = silc_command_get_first_arg(cmd->payload, NULL);
-  if (tmp) {
-    if (strchr(tmp, '@')) {
-      len = strcspn(tmp, "@");
-      nick = silc_calloc(len + 1, sizeof(char));
-      memcpy(nick, tmp, len);
-      server = silc_calloc(strlen(tmp) - len, sizeof(char));
-      memcpy(server, tmp + len + 1, strlen(tmp) - len - 1);
+  /* If client ID is in the command it must be used instead of nickname */
+  tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+  if (!tmp) {
+
+    /* No ID, get the nickname@server string and parse it. */
+    tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+    if (tmp) {
+      if (strchr(tmp, '@')) {
+       len = strcspn(tmp, "@");
+       nick = silc_calloc(len + 1, sizeof(char));
+       memcpy(nick, tmp, len);
+       server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
+       memcpy(server_name, tmp + len + 1, strlen(tmp) - len - 1);
+      } else {
+       nick = strdup(tmp);
+      }
     } else {
-      nick = strdup(tmp);
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
+                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+      goto out;
     }
   } else {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
-                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
+    /* Command includes ID, use that */
+    client_id = silc_id_payload_parse_id(tmp, len);
+    use_id = TRUE;
   }
 
   /* Get the max count of reply messages allowed */
-  if (argc == 2) {
-    tmp = silc_command_get_next_arg(cmd->payload, NULL);
+  if (argc == 3) {
+    tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
     if (!tmp) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
                                            SILC_STATUS_ERR_TOO_MANY_PARAMS);
       if (nick)
        silc_free(nick);
-      if (server)
-       silc_free(server);
+      if (server_name)
+       silc_free(server_name);
       goto out;
     }
     count = atoi(tmp);
   }
 
-  /* Then, make the query from our local client list */
-  entry = silc_idlist_find_client_by_nickname(cmd->server->local_list->clients,
-                                             nick, server);
-  if (!entry) {
+  /* Get all clients matching that nickname */
+  if (!use_id) {
+    clients = silc_idlist_get_clients_by_nickname(server->local_list, 
+                                                 nick, server_name,
+                                                 &clients_count);
+  } else {
+    entry = silc_idlist_find_client_by_id(server->local_list, client_id);
+    if (entry) {
+      clients = silc_calloc(1, sizeof(*clients));
+      clients[0] = entry;
+      clients_count = 1;
+    }
+  }
 
+  if (!clients) {
+    
     /* If we are normal server and are connected to a router we will
        make global query from the router. */
-    if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone) {
+    if (server->server_type == SILC_SERVER && !server->standalone) {
 
       goto ok;
     }
     
     /* If we are router then we will check our global list as well. */
-    if (cmd->server->server_type == SILC_ROUTER) {
+    if (server->server_type == SILC_ROUTER) {
       entry =
-       silc_idlist_find_client_by_nickname(cmd->server->global_list->clients,
-                                           nick, server);
+       silc_idlist_find_client_by_nickname(server->global_list,
+                                           nick, server_name);
       if (!entry) {
-       silc_server_command_send_status_msg(cmd, SILC_COMMAND_WHOIS,
-                                           SILC_STATUS_ERR_NO_SUCH_NICK,
-                                           tmp, strlen(tmp));
+       silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
+                                            SILC_STATUS_ERR_NO_SUCH_NICK,
+                                            3, tmp, strlen(tmp));
        goto out;
       }
       goto ok;
     }
 
-    silc_server_command_send_status_msg(cmd, SILC_COMMAND_WHOIS,
-                                       SILC_STATUS_ERR_NO_SUCH_NICK,
-                                       tmp, strlen(tmp));
+    silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS,
+                                        SILC_STATUS_ERR_NO_SUCH_NICK,
+                                        3, tmp, strlen(tmp));
     goto out;
   }
 
  ok:
+
   /* XXX, works only for local server info */
 
-  /* Send WHOIS reply */
-  id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
-  tmp = silc_command_get_first_arg(cmd->payload, NULL),
-  sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
+  status = SILC_STATUS_OK;
+  if (clients_count > 1)
+    status = SILC_STATUS_LIST_START;
 
-  /* XXX */
-  if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
-    char nh[256], uh[256];
-    SilcSocketConnection hsock;
+  for (i = 0; i < clients_count; i++) {
+    entry = clients[i];
 
-    memset(uh, 0, sizeof(uh));
-    memset(nh, 0, sizeof(nh));
+    if (count && i - 1 == count)
+      break;
 
-    strncat(nh, entry->nickname, strlen(entry->nickname));
-    strncat(nh, "@", 1);
-    len = entry->router ? strlen(entry->router->server_name) :
-      strlen(cmd->server->server_name);
-    strncat(nh, entry->router ? entry->router->server_name :
-           cmd->server->server_name, len);
+    if (clients_count > 2)
+      status = SILC_STATUS_LIST_ITEM;
 
-    strncat(uh, entry->username, strlen(entry->username));
-    strncat(uh, "@", 1);
-    hsock = (SilcSocketConnection)entry->connection;
-    len = hsock->hostname ? strlen(hsock->hostname) : strlen(hsock->ip);
-    strncat(uh, hsock->hostname ? hsock->hostname : hsock->ip, len);
+    if (clients_count > 1 && i == clients_count - 1)
+      status = SILC_STATUS_LIST_END;
 
+    /* Send WHOIS reply */
+    idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
+    tmp = silc_argument_get_first_arg(cmd->args, NULL);
+    
     /* XXX */
-    if (entry->userinfo)
-      packet = 
-        silc_command_encode_payload_va(SILC_COMMAND_WHOIS, 5, 
-                                      sp_buf->data, sp_buf->len,
-                                      id_string, SILC_ID_CLIENT_LEN,
-                                      nh, strlen(nh),
-                                      uh, strlen(uh),
-                                      entry->userinfo, 
-                                      strlen(entry->userinfo));
-    else
-      packet = 
-        silc_command_encode_payload_va(SILC_COMMAND_WHOIS, 4,
-                                      sp_buf->data, sp_buf->len,
-                                      id_string, SILC_ID_CLIENT_LEN,
-                                      nh, strlen(nh),
-                                      uh, strlen(uh));
+    if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
+      char nh[256], uh[256];
+      unsigned char idle[4];
+      SilcSocketConnection hsock;
 
-  } else {
-    /* XXX */
-    packet = 
-      silc_command_encode_payload_va(SILC_COMMAND_WHOIS, 4, 
-                                    sp_buf->data, sp_buf->len,
-                                    id_string, SILC_ID_CLIENT_LEN,
-                                    entry->nickname, strlen(entry->nickname),
-                                    tmp, strlen(tmp)); /* XXX */
+      memset(uh, 0, sizeof(uh));
+      memset(nh, 0, sizeof(nh));
+      
+      strncat(nh, entry->nickname, strlen(entry->nickname));
+      strncat(nh, "@", 1);
+      len = entry->router ? strlen(entry->router->server_name) :
+       strlen(server->server_name);
+      strncat(nh, entry->router ? entry->router->server_name :
+             server->server_name, len);
+      
+      strncat(uh, entry->username, strlen(entry->username));
+      strncat(uh, "@", 1);
+      hsock = (SilcSocketConnection)entry->connection;
+      len = hsock->hostname ? strlen(hsock->hostname) : strlen(hsock->ip);
+      strncat(uh, hsock->hostname ? hsock->hostname : hsock->ip, len);
+      
+      SILC_PUT32_MSB((time(NULL) - entry->last_receive), idle);
+      
+      /* XXX */
+      if (entry->userinfo)
+       packet = 
+         silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
+                                              status, 0, 5, 
+                                              2, idp->data, idp->len,
+                                              3, nh, strlen(nh),
+                                              4, uh, strlen(uh),
+                                              5, entry->userinfo, 
+                                              strlen(entry->userinfo),
+                                              7, idle, 4);
+      else
+       packet = 
+         silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
+                                              status, 0, 4, 
+                                              2, idp->data, idp->len,
+                                              3, nh, strlen(nh),
+                                              4, uh, strlen(uh),
+                                              7, idle, 4);
+      
+    } else {
+      /* XXX */
+      packet = 
+       silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS, 
+                                            status, 0, 3, 
+                                            2, idp->data, idp->len,
+                                            3, entry->nickname, 
+                                            strlen(entry->nickname),
+                                            4, tmp, strlen(tmp)); /* XXX */
+    }
+    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);
+    silc_free(clients);
   }
-  silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
-                         0, packet->data, packet->len, FALSE);
 
-  silc_free(id_string);
-  silc_buffer_free(packet);
-  silc_free(sp_buf);
+  if (client_id)
+    silc_free(client_id);
 
  out:
   silc_server_command_free(cmd);
@@ -341,47 +503,58 @@ SILC_SERVER_CMD_FUNC(whowas)
 SILC_SERVER_CMD_FUNC(identify)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
-  char *tmp, *nick = NULL, *server = NULL;
+  SilcServer server = cmd->server;
+  char *tmp, *nick = NULL, *server_name = NULL;
   unsigned int argc, count = 0, len;
-  SilcClientList *entry;
-  SilcBuffer sp_buf, packet;
-  unsigned char *id_string;
+  int use_id = FALSE;
+  SilcClientID *client_id = NULL;
+  SilcClientEntry entry;
+  SilcBuffer packet, idp;
 
   SILC_LOG_DEBUG(("Start"));
 
-  argc = silc_command_get_arg_num(cmd->payload);
+  argc = silc_argument_get_arg_num(cmd->args);
   if (argc < 1) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
                                          SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
-  if (argc > 2) {
+  if (argc > 3) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
                                          SILC_STATUS_ERR_TOO_MANY_PARAMS);
     goto out;
   }
 
-  /* Get the nickname@server string and parse it. */
-  tmp = silc_command_get_first_arg(cmd->payload, NULL);
-  if (tmp) {
-    if (strchr(tmp, '@')) {
-      len = strcspn(tmp, "@");
-      nick = silc_calloc(len + 1, sizeof(char));
-      memcpy(nick, tmp, len);
-      server = silc_calloc(strlen(tmp) - len, sizeof(char));
-      memcpy(server, tmp + len + 1, strlen(tmp) - len - 1);
+  /* If client ID is in the command it must be used instead of nickname */
+  tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+  if (!tmp) {
+
+    /* Get the nickname@server string and parse it. */
+    tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+    if (tmp) {
+      if (strchr(tmp, '@')) {
+       len = strcspn(tmp, "@");
+       nick = silc_calloc(len + 1, sizeof(char));
+       memcpy(nick, tmp, len);
+       server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
+       memcpy(server_name, tmp + len + 1, strlen(tmp) - len - 1);
+      } else {
+       nick = strdup(tmp);
+      }
     } else {
-      nick = strdup(tmp);
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
+                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+      goto out;
     }
   } else {
-    silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
-                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
-    goto out;
+    /* Command includes ID, use that */
+    client_id = silc_id_payload_parse_id(tmp, len);
+    use_id = TRUE;
   }
 
   /* Get the max count of reply messages allowed */
-  if (argc == 2) {
-    tmp = silc_command_get_next_arg(cmd->payload, NULL);
+  if (argc == 3) {
+    tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
     if (!tmp) {
       silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
                                            SILC_STATUS_ERR_TOO_MANY_PARAMS);
@@ -390,75 +563,78 @@ SILC_SERVER_CMD_FUNC(identify)
     count = atoi(tmp);
   }
 
-  /* Then, make the query from our local client list */
-  entry = silc_idlist_find_client_by_hash(cmd->server->local_list->clients,
-                                         nick, cmd->server->md5hash);
-  if (!entry) {
-
-    /* If we are normal server and are connected to a router we will
-       make global query from the router. */
-    if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone) {
-      SilcBuffer buffer = cmd->packet->buffer;
+  /* Find client */
+  if (!use_id) {
+    entry = silc_idlist_find_client_by_nickname(server->local_list,
+                                               nick, NULL);
+    if (!entry)
+      entry = silc_idlist_find_client_by_hash(server->global_list,
+                                             nick, server->md5hash);
+  } else {
+    entry = silc_idlist_find_client_by_id(server->local_list, client_id);
+  }
 
-      /* Forward the received IDENTIFY command to our router */
-      silc_buffer_push(buffer, buffer->data - buffer->head);
-      silc_server_packet_forward(cmd->server, (SilcSocketConnection)
-                                cmd->server->id_entry->router->connection,
-                                buffer->data, buffer->len,
-                                TRUE);
-      goto out;
-    }
+  /* If client was not found and if we are normal server and are connected
+     to a router we will make global query from the router. */
+  if (!entry && server->server_type == SILC_SERVER && !server->standalone &&
+      !cmd->pending) {
+    SilcBuffer buffer = cmd->packet->buffer;
     
-    /* If we are router then we will check our global list as well. */
-    if (cmd->server->server_type == SILC_ROUTER) {
-      entry = 
-       silc_idlist_find_client_by_hash(cmd->server->global_list->clients,
-                                       nick, cmd->server->md5hash);
-      if (!entry) {
-       silc_server_command_send_status_msg(cmd, SILC_COMMAND_IDENTIFY,
-                                           SILC_STATUS_ERR_NO_SUCH_NICK,
-                                           tmp, strlen(tmp));
-       goto out;
-      }
-      goto ok;
-    }
+    SILC_LOG_DEBUG(("Requesting identify from router"));
+    
+    /* Send IDENTIFY command to our router */
+    silc_buffer_push(buffer, buffer->data - buffer->head);
+    silc_server_packet_forward(server, (SilcSocketConnection)
+                              server->id_entry->router->connection,
+                              buffer->data, buffer->len, TRUE);
+    return;
+  }
 
-    silc_server_command_send_status_msg(cmd, SILC_COMMAND_IDENTIFY,
-                                       SILC_STATUS_ERR_NO_SUCH_NICK,
-                                       tmp, strlen(tmp));
+  /* If we are router we have checked our local list by nickname and our
+     global list by hash so far. It is possible that the client is still not
+     found and we'll check it from local list by hash. */
+  if (!entry && server->server_type == SILC_ROUTER)
+    entry = silc_idlist_find_client_by_hash(server->local_list,
+                                           nick, server->md5hash);
+
+  if (!entry) {
+    /* The client definitely does not exist */
+    silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+                                        SILC_STATUS_ERR_NO_SUCH_NICK,
+                                        3, tmp, strlen(tmp));
     goto out;
   }
 
- ok:
   /* Send IDENTIFY reply */
-  id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
-  tmp = silc_command_get_first_arg(cmd->payload, NULL);
-  sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
-  packet = silc_command_encode_payload_va(SILC_COMMAND_IDENTIFY, 3,
-                                         sp_buf->data, sp_buf->len,
-                                         id_string, SILC_ID_CLIENT_LEN,
-                                         nick, strlen(nick));
+  idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
+  tmp = silc_argument_get_first_arg(cmd->args, NULL);
+  packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
+                                               SILC_STATUS_OK, 0, 2,
+                                               2, idp->data, idp->len, 
+                                               3, nick, strlen(nick));
   if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
     void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
-    silc_server_packet_send_dest(cmd->server, cmd->sock, 
+    silc_server_packet_send_dest(server, cmd->sock, 
                                 SILC_PACKET_COMMAND_REPLY, 0,
                                 id, cmd->packet->src_id_type,
                                 packet->data, packet->len, FALSE);
     silc_free(id);
-  } else
-    silc_server_packet_send(cmd->server, cmd->sock, 
+  } else {
+    silc_server_packet_send(server, cmd->sock, 
                            SILC_PACKET_COMMAND_REPLY, 0, 
                            packet->data, packet->len, FALSE);
+  }
 
-  silc_free(id_string);
   silc_buffer_free(packet);
-  silc_free(sp_buf);
+  silc_buffer_free(idp);
+  if (client_id)
+    silc_free(client_id);
 
  out:
   if (nick)
     silc_free(nick);
-  if (server)
-    silc_free(server);
+  if (server_name)
+    silc_free(server_name);
   silc_server_command_free(cmd);
 }
 
@@ -485,27 +661,23 @@ static int silc_server_command_bad_chars(char *nick)
 SILC_SERVER_CMD_FUNC(nick)
 {
   SilcServerCommandContext cmd = (SilcServerCommandContext)context;
-  SilcClientList *id_entry = (SilcClientList *)cmd->sock->user_data;
+  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
   SilcServer server = cmd->server;
-  SilcBuffer packet, sp_buf;
+  SilcBuffer packet, nidp, oidp;
   SilcClientID *new_id;
-  char *id_string;
   char *nick;
 
   SILC_LOG_DEBUG(("Start"));
 
-#define LCC(x) server->local_list->client_cache[(x) - 32]
-#define LCCC(x) server->local_list->client_cache_count[(x) - 32]
-
   /* Check number of arguments */
-  if (silc_command_get_arg_num(cmd->payload) < 1) {
+  if (silc_argument_get_arg_num(cmd->args) < 1) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
                                          SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
     goto out;
   }
 
   /* Check nickname */
-  nick = silc_command_get_arg_type(cmd->payload, 1, NULL);
+  nick = silc_argument_get_arg_type(cmd->args, 1, NULL);
   if (silc_server_command_bad_chars(nick) == TRUE) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
                                          SILC_STATUS_ERR_BAD_NICKNAME);
@@ -521,7 +693,7 @@ SILC_SERVER_CMD_FUNC(nick)
      ID and ask to replace it with the old one. */
   if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone)
     silc_server_send_replace_id(server, server->id_entry->router->connection, 
-                               FALSE, id_entry->id,
+                               FALSE, client->id,
                                SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
                                new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
 
@@ -529,62 +701,284 @@ SILC_SERVER_CMD_FUNC(nick)
      routers in SILC. */
   if (cmd->server->server_type == SILC_ROUTER && !cmd->server->standalone)
     silc_server_send_replace_id(server, server->id_entry->router->connection,  
-                               TRUE, id_entry->id,
+                               TRUE, client->id,
                                SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
                                new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
 
   /* Remove old cache entry */
-  silc_idcache_del_by_id(LCC(id_entry->nickname[0]),
-                        LCCC(id_entry->nickname[0]), 
-                        SILC_ID_CLIENT, id_entry->id); 
-  
+  silc_idcache_del_by_id(server->local_list->clients, SILC_ID_CLIENT, 
+                        client->id); 
+
+  oidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+
   /* Free old ID */
-  if (id_entry->id) {
-    memset(id_entry->id, 0, SILC_ID_CLIENT_LEN);
-    silc_free(id_entry->id);
+  if (client->id) {
+    memset(client->id, 0, SILC_ID_CLIENT_LEN);
+    silc_free(client->id);
   }
 
   /* Save the nickname as this client is our local client */
-  if (id_entry->nickname)
-    silc_free(id_entry->nickname);
+  if (client->nickname)
+    silc_free(client->nickname);
 
-  id_entry->nickname = strdup(nick);
-  id_entry->id = new_id;
+  client->nickname = strdup(nick);
+  client->id = new_id;
 
   /* Update client cache */
-  LCCC(nick[0]) = silc_idcache_add(&LCC(nick[0]), LCCC(nick[0]),
-                                  id_entry->nickname, SILC_ID_CLIENT, 
-                                  id_entry->id, (void *)id_entry);
+  silc_idcache_add(server->local_list->clients, client->nickname, 
+                  SILC_ID_CLIENT, client->id, (void *)client, TRUE);
+
+  nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+
+  /* Send NICK_CHANGE notify */
+  silc_server_send_notify_on_channels(server, client, 
+                                     SILC_NOTIFY_TYPE_NICK_CHANGE, 2,
+                                     oidp->data, oidp->len, 
+                                     nidp->data, nidp->len);
 
   /* Send the new Client ID as reply command back to client */
-  id_string = silc_id_id2str(id_entry->id, SILC_ID_CLIENT);
-  sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
-  packet = silc_command_encode_payload_va(SILC_COMMAND_NICK, 2, 
-                                         sp_buf->data, sp_buf->len,
-                                         id_string, SILC_ID_CLIENT_LEN);
+  packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NICK, 
+                                               SILC_STATUS_OK, 0, 1, 
+                                               2, nidp->data, nidp->len);
   silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
                          0, packet->data, packet->len, FALSE);
 
-  silc_free(id_string);
   silc_buffer_free(packet);
-  silc_free(sp_buf);
-
+  silc_buffer_free(nidp);
+  silc_buffer_free(oidp);
+  
  out:
   silc_server_command_free(cmd);
-#undef LCC
-#undef LCCC
 }
 
 SILC_SERVER_CMD_FUNC(list)
 {
 }
 
+/* Server side of TOPIC command. Sets topic for channel and/or returns
+   current topic to client. */
+
 SILC_SERVER_CMD_FUNC(topic)
 {
+  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+  SilcServer server = cmd->server;
+  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+  SilcChannelID *channel_id;
+  SilcChannelEntry channel;
+  SilcChannelClientEntry chl;
+  SilcBuffer packet, idp;
+  unsigned char *tmp;
+  unsigned int argc, tmp_len;
+
+  /* Check number of arguments */
+  argc = silc_argument_get_arg_num(cmd->args);
+  if (argc < 1) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+    goto out;
+  }
+  if (argc > 2) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
+                                         SILC_STATUS_ERR_TOO_MANY_PARAMS);
+    goto out;
+  }
+
+  /* Get Channel ID */
+  tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+  if (!tmp) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
+                                         SILC_STATUS_ERR_NO_CHANNEL_ID);
+    goto out;
+  }
+  channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+  /* Check whether the channel exists */
+  channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
+  if (!channel) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
+                                         SILC_STATUS_ERR_NO_SUCH_CHANNEL);
+    goto out;
+  }
+
+  if (argc > 1) {
+    /* Get the topic */
+    tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
+    if (!tmp) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
+                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+      goto out;
+    }
+
+    if (strlen(tmp) > 256) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
+                                           SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+      goto out;
+    }
+
+    /* See whether has rights to change topic */
+    silc_list_start(channel->user_list);
+    while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+      if (chl->client == client) {
+       if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
+         silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
+                                               SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+         goto out;
+       } else {
+         break;
+       }
+      }
+    }
+
+    /* Set the topic for channel */
+    if (channel->topic)
+      silc_free(channel->topic);
+    channel->topic = strdup(tmp);
+
+    idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+
+    /* Send notify about topic change to all clients on the channel */
+    silc_server_send_notify_to_channel(server, channel,
+                                      SILC_NOTIFY_TYPE_TOPIC_SET, 2,
+                                      idp->data, idp->len,
+                                      channel->topic, strlen(channel->topic));
+    silc_buffer_free(idp);
+  }
+
+  /* Send the topic to client as reply packet */
+  idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
+  if (channel->topic)
+    packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC, 
+                                                 SILC_STATUS_OK, 0, 2, 
+                                                 2, idp->data, idp->len,
+                                                 3, channel->topic, 
+                                                 strlen(channel->topic));
+  else
+    packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC, 
+                                                 SILC_STATUS_OK, 0, 1, 
+                                                 2, idp->data, idp->len);
+  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);
+  silc_free(channel_id);
+
+ out:
+  silc_server_command_free(cmd);
 }
 
+/* Server side of INVITE command. Invites some client to join some channel. */
+
 SILC_SERVER_CMD_FUNC(invite)
 {
+  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+  SilcServer server = cmd->server;
+  SilcSocketConnection sock = cmd->sock, dest_sock;
+  SilcClientEntry sender, dest;
+  SilcClientID *dest_id;
+  SilcChannelEntry channel;
+  SilcChannelID *channel_id;
+  SilcBuffer sidp;
+  unsigned char *tmp;
+  unsigned int argc, len;
+
+  /* Check number of arguments */
+  argc = silc_argument_get_arg_num(cmd->args);
+  if (argc < 1) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+    goto out;
+  }
+  if (argc > 2) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+                                         SILC_STATUS_ERR_TOO_MANY_PARAMS);
+    goto out;
+  }
+
+  /* Get destination ID */
+  tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
+  if (!tmp) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+                                         SILC_STATUS_ERR_NO_CLIENT_ID);
+    goto out;
+  }
+  dest_id = silc_id_payload_parse_id(tmp, len);
+
+  /* Get Channel ID */
+  tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+  if (!tmp) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+                                         SILC_STATUS_ERR_NO_CHANNEL_ID);
+    goto out;
+  }
+  channel_id = silc_id_payload_parse_id(tmp, len);
+
+  /* Check whether the channel exists */
+  channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
+  if (!channel) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+                                         SILC_STATUS_ERR_NO_SUCH_CHANNEL);
+    goto out;
+  }
+
+  /* Check whether the sender of this command is on the channel. */
+  sender = (SilcClientEntry)sock->user_data;
+  if (!silc_server_client_on_channel(sender, channel)) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+                                         SILC_STATUS_ERR_NOT_ON_CHANNEL);
+    goto out;
+  }
+
+  /* Check whether the channel is invite-only channel. If yes then the
+     sender of this command must be at least channel operator. */
+  if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
+    SilcChannelClientEntry chl;
+
+    silc_list_start(channel->user_list);
+    while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
+      if (chl->client == sender) {
+       if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
+         silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+                                               SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+         goto out;
+       }
+       break;
+      }
+  }
+
+  /* Find the connection data for the destination. If it is local we will
+     send it directly otherwise we will send it to router for routing. */
+  dest = silc_idlist_find_client_by_id(server->local_list, dest_id);
+  if (dest)
+    dest_sock = (SilcSocketConnection)dest->connection;
+  else
+    dest_sock = silc_server_get_route(server, dest_id, SILC_ID_CLIENT);
+
+  /* Check whether the requested client is already on the channel. */
+  /* XXX if we are normal server we don't know about global clients on
+     the channel thus we must request it (NAMES command), check from
+     local cache as well. */
+  if (silc_server_client_on_channel(dest, channel)) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+                                         SILC_STATUS_ERR_USER_ON_CHANNEL);
+    goto out;
+  }
+
+  sidp = silc_id_payload_encode(sender->id, SILC_ID_CLIENT);
+
+  /* Send notify to the client that is invited to the channel */
+  silc_server_send_notify_dest(server, dest_sock, dest_id, SILC_ID_CLIENT,
+                              SILC_NOTIFY_TYPE_INVITE, 2, 
+                              sidp->data, sidp->len, tmp, len);
+
+  /* Send command reply */
+  silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+                                       SILC_STATUS_OK);
+
+  silc_buffer_free(sidp);
+
+ out:
+  silc_server_command_free(cmd);
 }
 
 /* Quits connection to client. This gets called if client won't
@@ -625,29 +1019,139 @@ SILC_SERVER_CMD_FUNC(kill)
 {
 }
 
+/* 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)
 {
+  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+  SilcServer server = cmd->server;
+  SilcBuffer packet, idp;
+  unsigned int argc;
+  char info_string[256], *dest_server;
+
+  argc = silc_argument_get_arg_num(cmd->args);
+  if (argc < 1) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+    goto out;
+  }
+  if (argc > 1) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
+                                         SILC_STATUS_ERR_TOO_MANY_PARAMS);
+    goto out;
+  }
+
+  /* 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_INFO,
+                                         SILC_STATUS_ERR_NO_SUCH_SERVER);
+    goto out;
+  }
+
+  if (!strncasecmp(dest_server, server->server_name, strlen(dest_server))) {
+    /* Send our reply */
+    memset(info_string, 0, sizeof(info_string));
+    snprintf(info_string, sizeof(info_string), 
+            "location: %s server: %s admin: %s <%s>",
+            server->config->admin_info->location,
+            server->config->admin_info->server_type,
+            server->config->admin_info->admin_name,
+            server->config->admin_info->admin_email);
+
+    idp = silc_id_payload_encode(server->id, SILC_ID_SERVER);
+
+    packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
+                                                 SILC_STATUS_OK, 0, 2,
+                                                 2, idp->data, idp->len,
+                                                 3, info_string, 
+                                                 strlen(info_string));
+    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);
+  } else {
+    /* Send this command to the requested server */
+
+    if (server->server_type == SILC_SERVER && !server->standalone) {
+
+    }
+
+    if (server->server_type == SILC_ROUTER) {
+
+    }
+  }
+  
+ out:
+  silc_server_command_free(cmd);
 }
 
 SILC_SERVER_CMD_FUNC(connect)
 {
 }
 
-SILC_SERVER_CMD_FUNC(ping)
-{
-}
+/* Server side of command PING. This just replies to the ping. */
 
-SILC_SERVER_CMD_FUNC(oper)
+SILC_SERVER_CMD_FUNC(ping)
 {
-}
+  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+  SilcServer server = cmd->server;
+  SilcServerID *id;
+  unsigned int argc, len;
+  unsigned char *tmp;
 
-typedef struct {
-  char *channel_name;
+  argc = silc_argument_get_arg_num(cmd->args);
+  if (argc < 1) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+    goto out;
+  }
+  if (argc > 2) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
+                                         SILC_STATUS_ERR_TOO_MANY_PARAMS);
+    goto out;
+  }
+
+  /* Get Server ID */
+  tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
+  if (!tmp) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
+                                         SILC_STATUS_ERR_NO_SERVER_ID);
+    goto out;
+  }
+  id = silc_id_payload_parse_id(tmp, len);
+
+  if (!SILC_ID_SERVER_COMPARE(id, server->id)) {
+    /* Send our reply */
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
+                                         SILC_STATUS_OK);
+  } else {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
+                                         SILC_STATUS_ERR_NO_SUCH_SERVER);
+    goto out;
+  }
+
+  silc_free(id);
+
+ out:
+  silc_server_command_free(cmd);
+}
+
+SILC_SERVER_CMD_FUNC(oper)
+{
+}
+
+typedef struct {
+  char *channel_name;
   char *nickname;
   char *username;
   char *hostname;
-  SilcChannelList *channel;
+  SilcChannelEntry channel;
   SilcServer server;
+  SilcClientEntry client;
 } JoinInternalContext;
 
 SILC_TASK_CALLBACK(silc_server_command_join_notify)
@@ -655,10 +1159,15 @@ SILC_TASK_CALLBACK(silc_server_command_join_notify)
   JoinInternalContext *ctx = (JoinInternalContext *)context;
 
   if (ctx->channel->key && ctx->channel->key_len) {
+    SilcBuffer clidp;
+
+    clidp = silc_id_payload_encode(ctx->client->id, SILC_ID_CLIENT);
+
     silc_server_send_notify_to_channel(ctx->server, ctx->channel,
-                                      "%s (%s@%s) has joined channel %s",
-                                      ctx->nickname, ctx->username,
-                                      ctx->hostname, ctx->channel_name);
+                                      SILC_NOTIFY_TYPE_JOIN, 1,
+                                      clidp->data, clidp->len);
+
+    silc_buffer_free(clidp);
     silc_free(ctx);
   } else {
     silc_task_register(ctx->server->timeout_queue, fd,
@@ -667,6 +1176,33 @@ SILC_TASK_CALLBACK(silc_server_command_join_notify)
   }
 }
 
+/* Assembles NAMES command and executes it. This is called when client
+   joins to a channel and we wan't to send NAMES command reply to the 
+   client. */
+
+void silc_server_command_send_names(SilcServer server,
+                                   SilcSocketConnection sock,
+                                   SilcChannelEntry channel)
+{
+  SilcServerCommandContext cmd;
+  SilcBuffer buffer, idp;
+
+  idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+  buffer = silc_command_payload_encode_va(SILC_COMMAND_NAMES, 0, 1,
+                                         1, idp->data, idp->len);
+
+  cmd = silc_calloc(1, sizeof(*cmd));
+  cmd->payload = silc_command_payload_parse(buffer);
+  cmd->args = silc_command_get_args(cmd->payload);
+  cmd->server = server;
+  cmd->sock = sock;
+  cmd->pending = FALSE;
+
+  silc_server_command_names((void *)cmd);
+  silc_free(buffer);
+  silc_free(idp);
+}
+
 /* Server side of command JOIN. Joins client into requested channel. If 
    the channel does not exist it will be created. */
 
@@ -676,22 +1212,20 @@ SILC_SERVER_CMD_FUNC(join)
   SilcServer server = cmd->server;
   SilcSocketConnection sock = cmd->sock;
   SilcBuffer buffer = cmd->packet->buffer;
-  int argc, i, tmp_len;
-  char *tmp, *channel_name = NULL, *cipher = NULL, *id_string = NULL;
-  unsigned char *passphrase;
-  SilcChannelList *channel;
+  int argc, i, k, tmp_len;
+  char *tmp, *channel_name = NULL, *cipher = NULL;
+  unsigned char *passphrase = NULL, mode[4];
+  unsigned int umode = 0;
+  SilcChannelEntry channel;
+  SilcChannelClientEntry chl;
   SilcServerID *router_id;
-  SilcIDCache *id_cache;
-  SilcBuffer packet, sp_buf;
-  SilcClientList *client;
+  SilcBuffer packet, idp;
+  SilcClientEntry client;
 
   SILC_LOG_DEBUG(("Start"));
 
-#define LCC(x) server->local_list->channel_cache[(x) - 32]
-#define LCCC(x) server->local_list->channel_cache_count[(x) - 32]
-
   /* Check number of parameters */
-  argc = silc_command_get_arg_num(cmd->payload);
+  argc = silc_argument_get_arg_num(cmd->args);
   if (argc < 1) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
                                          SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
@@ -704,36 +1238,48 @@ SILC_SERVER_CMD_FUNC(join)
   }
 
   /* Get channel name */
-  tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
-  if (silc_server_command_bad_chars(tmp) == TRUE) {
+  tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+  if (!tmp) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+    goto out;
+  }
+  channel_name = tmp;
+
+  if (silc_server_command_bad_chars(channel_name) == TRUE) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
                                          SILC_STATUS_ERR_BAD_CHANNEL);
+    silc_free(channel_name);
     goto out;
   }
-  channel_name = strdup(tmp);
 
   /* Get passphrase */
-  tmp = silc_command_get_arg_type(cmd->payload, 2, &tmp_len);
+  tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
   if (tmp) {
     passphrase = silc_calloc(tmp_len, sizeof(*passphrase));
     memcpy(passphrase, tmp, tmp_len);
   }
   
   /* Get cipher name */
-  cipher = silc_command_get_arg_type(cmd->payload, 3, NULL);
+  cipher = silc_argument_get_arg_type(cmd->args, 3, NULL);
 
   /* See if the channel exists */
-  if (silc_idcache_find_by_data(LCC(channel_name[0]), LCCC(channel_name[0]), 
-                               channel_name, &id_cache) == FALSE) {
+  channel = 
+    silc_idlist_find_channel_by_name(server->local_list, channel_name);
+  if (!channel) {
     /* Channel not found */
-    id_cache = NULL;
 
     /* If we are standalone server we don't have a router, we just create 
        the channel by  ourselves. */
     if (server->standalone) {
       router_id = server->id;
-      channel = silc_server_new_channel(server, router_id, 
-                                       cipher, channel_name);
+      channel = silc_server_new_channel(server, router_id, cipher, 
+                                       channel_name);
+      umode |= SILC_CHANNEL_UMODE_CHANOP;
+      umode |= SILC_CHANNEL_UMODE_CHANFO;
+      if (!channel)
+       goto out;
+
       goto join_channel;
     }
 
@@ -743,12 +1289,11 @@ SILC_SERVER_CMD_FUNC(join)
        joins the client to it) - if we are normal server. */
     if (server->server_type == SILC_SERVER) {
 
-      /* Forward the received JOIN command to the router */
+      /* Forward the original JOIN command to the router */
       silc_buffer_push(buffer, buffer->data - buffer->head);
       silc_server_packet_forward(server, (SilcSocketConnection)
                                 server->id_entry->router->connection,
-                                buffer->data, buffer->len,
-                                TRUE);
+                                buffer->data, buffer->len, TRUE);
       
       /* Add the command to be pending. It will be re-executed after
         router has replied back to us. */
@@ -761,7 +1306,7 @@ SILC_SERVER_CMD_FUNC(join)
 
   /* If we are router and the channel does not exist we will check our
      global list for the channel. */
-  if (!id_cache && server->server_type == SILC_ROUTER) {
+  if (!channel && server->server_type == SILC_ROUTER) {
 
     /* Notify all routers about the new channel in SILC network. */
     if (!server->standalone) {
@@ -774,37 +1319,95 @@ SILC_SERVER_CMD_FUNC(join)
 
   }
 
-  channel = (SilcChannelList *)id_cache->context;
-
  join_channel:
 
-  /* XXX must check whether the client already is on the channel */
+  /*
+   * Check channel modes
+   */
+
+  /* Check invite list if channel is invite-only channel */
+  if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
+    if (channel->mode & SILC_CHANNEL_MODE_INVITE_LIST) {
+      /* Invite list is specified. Check whether client is invited in the
+        list. If not, then check whether it has been invited otherwise. */
+
+    } else {
+      /* XXX client must be invited to be able to join the channel */
+    }
+  }
+
+  /* Check ban list if set */
+  if (channel->mode & SILC_CHANNEL_MODE_BAN) {
+
+  }
+
+  /* Check the channel passphrase if set. */
+  if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
+    if (!passphrase || memcmp(channel->mode_data.passphrase, passphrase,
+                             strlen(channel->mode_data.passphrase))) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+                                           SILC_STATUS_ERR_BAD_PASSWORD);
+      goto out;
+    }
+  }
+
+  /* Check user count limit if set. */
+  if (channel->mode & SILC_CHANNEL_MODE_ULIMIT) {
+    if (silc_list_count(channel->user_list) + 1 > 
+       channel->mode_data.user_limit) {
+      silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+                                           SILC_STATUS_ERR_CHANNEL_IS_FULL);
+      goto out;
+    }
+  }
 
-  /* Join the client to the channel */
-  i = channel->user_list_count;
-  channel->user_list = silc_realloc(channel->user_list, 
-                                   sizeof(*channel->user_list) * (i + 1));
-  channel->user_list[i].mode = SILC_CHANNEL_UMODE_NONE;
+  /*
+   * Client is allowed to join to the channel. Make it happen.
+   */
 
   /* If the JOIN request was forwarded to us we will make a bit slower
      query to get the client pointer. Otherwise, we get the client pointer
      real easy. */
   if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
-    client = (SilcClientList *)sock->user_data;
-    channel->user_list[i].client = client;
+    client = (SilcClientEntry)sock->user_data;
   } else {
     void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
-    client = silc_idlist_find_client_by_id(server->local_list->clients, id);
-    channel->user_list[i].client = client;
+    client = silc_idlist_find_client_by_id(server->local_list, id);
+    if (!client) {
+      /* XXX */
+      goto out;
+    }
     silc_free(id);
   }
-  channel->user_list_count++;
 
+  /* Check whether the client already is on the channel */
+  if (silc_server_client_on_channel(client, channel)) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+                                         SILC_STATUS_ERR_USER_ON_CHANNEL);
+    goto out;
+  }
+
+  /* Join the client to the channel by adding it to channel's user list */
+  chl = silc_calloc(1, sizeof(*chl));
+  chl->mode = umode;
+  chl->client = client;
+  silc_list_add(channel->user_list, chl);
+
+  /* Add the channel to client's channel list */
   i = client->channel_count;
-  client->channel = silc_realloc(client->channel, 
-                                sizeof(*client->channel) * (i + 1));
-  client->channel[i] = channel;
-  client->channel_count++;
+  for (k = 0; k < client->channel_count; k++) {
+    if (client->channel[k] == NULL) {
+      client->channel[k] = channel;
+      break;
+    }
+  }
+  if (k >= i) {
+    i = client->channel_count;
+    client->channel = silc_realloc(client->channel, 
+                                  sizeof(*client->channel) * (i + 1));
+    client->channel[i] = channel;
+    client->channel_count++;
+  }
 
   /* Notify router about new user on channel. If we are normal server
      we send it to our router, if we are router we send it to our
@@ -813,24 +1416,30 @@ SILC_SERVER_CMD_FUNC(join)
 
   }
 
-  /* Send Channel ID to the client */
+  /* Send command reply to the client. Client receives the Channe ID,
+     channel mode and possibly other information in this reply packet. */
   if (!cmd->pending) {
-    id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
-    sp_buf = silc_command_encode_status_payload(SILC_STATUS_OK, NULL, 0);
+    idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+    SILC_PUT32_MSB(channel->mode, mode);
+
     if (!channel->topic)
       packet = 
-       silc_command_encode_payload_va(SILC_COMMAND_JOIN, 3,
-                                      sp_buf->data, sp_buf->len,
-                                      channel_name, strlen(channel_name),
-                                      id_string, SILC_ID_CHANNEL_LEN);
+       silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
+                                            SILC_STATUS_OK, 0, 3,
+                                            2, channel_name, 
+                                            strlen(channel_name),
+                                            3, idp->data, idp->len,
+                                            4, mode, 4);
     else
       packet = 
-       silc_command_encode_payload_va(SILC_COMMAND_JOIN, 4,
-                                      sp_buf->data, sp_buf->len,
-                                      channel_name, strlen(channel_name),
-                                      id_string, SILC_ID_CHANNEL_LEN,
-                                      channel->topic, 
-                                      strlen(channel->topic));
+       silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
+                                            SILC_STATUS_OK, 0, 4, 
+                                            2, channel_name, 
+                                            strlen(channel_name),
+                                            3, idp->data, idp->len,
+                                            4, mode, 4,
+                                            5, channel->topic, 
+                                            strlen(channel->topic));
 
     if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
       void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
@@ -842,38 +1451,38 @@ SILC_SERVER_CMD_FUNC(join)
     } else
       silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0, 
                              packet->data, packet->len, FALSE);
-    
     silc_buffer_free(packet);
-    silc_free(sp_buf);
-  }
 
-  /* Send channel key to the client. Client cannot start transmitting
-     to the channel until we have sent the key. */
-  if (!cmd->pending) {
+    /* Send channel key to the client. Client cannot start transmitting
+       to the channel until we have sent the key. */
     tmp_len = strlen(channel->channel_key->cipher->name);
     packet = 
-      silc_channel_key_encode_payload(SILC_ID_CHANNEL_LEN, 
-                                     id_string, tmp_len, 
+      silc_channel_key_payload_encode(idp->len, idp->data, 
+                                     strlen(channel->channel_key->
+                                            cipher->name),
                                      channel->channel_key->cipher->name,
-                                     channel->key_len, channel->key);
+                                     channel->key_len / 8, channel->key);
     
     silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0, 
                            packet->data, packet->len, FALSE);
+
     silc_buffer_free(packet);
+    silc_buffer_free(idp);
   }
 
-  if (id_string)
-    silc_free(id_string);
-
   /* Finally, send notify message to all clients on the channel about
      new user on the channel. */
   if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
     if (!cmd->pending) {
+      SilcBuffer clidp;
+
+      clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+      
       silc_server_send_notify_to_channel(server, channel,
-                                        "%s (%s@%s) has joined channel %s",
-                                        client->nickname, client->username,
-                                        sock->hostname ? sock->hostname :
-                                        sock->ip, channel_name);
+                                        SILC_NOTIFY_TYPE_JOIN, 1,
+                                        clidp->data, clidp->len);
+      
+      silc_buffer_free(clidp);
     } else {
       /* This is pending command request. Send the notify after we have
         received the key for the channel from the router. */
@@ -884,38 +1493,715 @@ SILC_SERVER_CMD_FUNC(join)
       ctx->hostname = sock->hostname ? sock->hostname : sock->ip;
       ctx->channel = channel;
       ctx->server = server;
+      ctx->client = client;
       silc_task_register(server->timeout_queue, sock->sock,
                         silc_server_command_join_notify, ctx,
-                        0, 100000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+                        0, 10000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
     }
   }
 
+  /* Send NAMES command reply to the joined channel so the user sees who
+     is currently on the channel. */
+  silc_server_command_send_names(server, sock, channel);
+
  out:
   silc_server_command_free(cmd);
-#undef LCC
-#undef LCCC
 }
 
-/* Server side of command MOTD. Sends servers current "message of the
+/* Server side of command MOTD. Sends server's current "message of the
    day" to the client. */
 
 SILC_SERVER_CMD_FUNC(motd)
 {
-
+  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+  SilcServer server = cmd->server;
+  unsigned int argc;
+  char *motd;
+  int motd_len;
+  
   SILC_LOG_DEBUG(("Start"));
 
+  argc = silc_argument_get_arg_num(cmd->args);
+  if (argc < 1) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+    goto out;
+  }
+  if (argc > 2) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
+                                         SILC_STATUS_ERR_TOO_MANY_PARAMS);
+    goto out;
+  }
+
+  /* XXX show currently only our motd */
+
+  if (server->config && server->config->motd && 
+      server->config->motd->motd_file) {
+
+    /* Send motd */
+    motd = silc_file_read(server->config->motd->motd_file, &motd_len);
+    if (!motd)
+      goto out;
+
+    motd[motd_len] = 0;
+    silc_server_command_send_status_data(cmd, SILC_COMMAND_MOTD,
+                                        SILC_STATUS_OK,
+                                        2, motd, motd_len);
+    goto out;
+  } else {
+    /* No motd */
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_MOTD,
+                                         SILC_STATUS_OK);
+  }
+
+ out:
+  silc_server_command_free(cmd);
 }
 
 SILC_SERVER_CMD_FUNC(umode)
 {
 }
 
+/* Checks that client has rights to add or remove channel modes. If any
+   of the checks fails FALSE is returned. */
+
+int silc_server_check_cmode_rights(SilcChannelEntry channel,
+                                  SilcChannelClientEntry client,
+                                  unsigned int mode)
+{
+  int is_op = client->mode & SILC_CHANNEL_UMODE_CHANOP;
+  int is_fo = client->mode & SILC_CHANNEL_UMODE_CHANFO;
+
+  /* Check whether has rights to change anything */
+  if (!is_op && !is_fo)
+    return FALSE;
+
+  /* Check whether has rights to change everything */
+  if (is_op && is_fo)
+    return TRUE;
+
+  /* We know that client is channel operator, check that they are not
+     changing anything that requires channel founder rights. Rest of the
+     modes are available automatically for channel operator. */
+
+  if (mode & SILC_CHANNEL_MODE_PRIVKEY) {
+    if (is_op && !is_fo)
+      return FALSE;
+  } else {
+    if (channel->mode & SILC_CHANNEL_MODE_PRIVATE) {
+      if (is_op && !is_fo)
+       return FALSE;
+    }
+  }
+  
+  if (mode & SILC_CHANNEL_MODE_PASSPHRASE) {
+    if (is_op && !is_fo)
+      return FALSE;
+  } else {
+    if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
+      if (is_op && !is_fo)
+       return FALSE;
+    }
+  }
+
+  if (mode & SILC_CHANNEL_MODE_CIPHER) {
+    if (is_op && !is_fo)
+      return FALSE;
+  } else {
+    if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
+      if (is_op && !is_fo)
+       return FALSE;
+    }
+  }
+  
+  return TRUE;
+}
+
+/* Server side command of CMODE. Changes channel mode */
+
 SILC_SERVER_CMD_FUNC(cmode)
 {
+  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+  SilcServer server = cmd->server;
+  SilcSocketConnection sock = cmd->sock;
+  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+  SilcChannelID *channel_id;
+  SilcClientID *client_id;
+  SilcChannelEntry channel;
+  SilcChannelClientEntry chl;
+  SilcBuffer packet, cidp;
+  unsigned char *tmp, *tmp_id, *tmp_mask;
+  unsigned int argc, mode_mask, tmp_len, tmp_len2;
+  int i;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  argc = silc_argument_get_arg_num(cmd->args);
+  if (argc < 2) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+    goto out;
+  }
+  if (argc > 8) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                         SILC_STATUS_ERR_TOO_MANY_PARAMS);
+    goto out;
+  }
+
+  /* Get Channel ID */
+  tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
+  if (!tmp_id) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                         SILC_STATUS_ERR_NO_CHANNEL_ID);
+    goto out;
+  }
+  channel_id = silc_id_payload_parse_id(tmp_id, tmp_len2);
+
+  /* Get the channel mode mask */
+  tmp_mask = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+  if (!tmp_mask) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+    goto out;
+  }
+  SILC_GET32_MSB(mode_mask, tmp_mask);
+
+  /* Get channel entry */
+  channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
+  if (!channel) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                         SILC_STATUS_ERR_NO_SUCH_CHANNEL);
+    goto out;
+  }
+
+  /* Check whether this client is on the channel */
+  if (!silc_server_client_on_channel(client, channel)) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                         SILC_STATUS_ERR_NOT_ON_CHANNEL);
+    goto out;
+  }
+
+  /* Get entry to the channel user list */
+  silc_list_start(channel->user_list);
+  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
+    if (chl->client == client)
+      break;
+
+  /* Check that client has rights to change any requested channel modes */
+  if (!silc_server_check_cmode_rights(channel, chl, mode_mask)) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                         SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+    goto out;
+  }
+
+  /*
+   * Check the modes. Modes that requires nothing special operation are
+   * not checked here.
+   */
+
+  if (mode_mask & SILC_CHANNEL_MODE_PRIVKEY) {
+    /* Channel uses private keys to protect traffic. Client(s) has set the
+       key locally they want to use, server does not know that key. */
+    /* Nothing interesting to do here now */
+  } else {
+    if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
+      /* The mode is removed and we need to generate and distribute
+        new channel key. Clients are not using private channel keys
+        anymore after this. */
+      unsigned int key_len;
+      unsigned char channel_key[32];
+
+      /* XXX Duplicated code, make own function for this!! LEAVE uses this
+        as well */
+
+      /* Re-generate channel key */
+      key_len = channel->key_len / 8;
+      for (i = 0; i < key_len; i++)
+       channel_key[i] = silc_rng_get_byte(server->rng);
+      channel->channel_key->cipher->set_key(channel->channel_key->context, 
+                                           channel_key, key_len);
+      memset(channel->key, 0, key_len);
+      silc_free(channel->key);
+      channel->key = silc_calloc(key_len, sizeof(*channel->key));
+      memcpy(channel->key, channel_key, key_len);
+      memset(channel_key, 0, sizeof(channel_key));
+      
+      /* Encode channel key payload to be distributed on the channel */
+      packet = 
+       silc_channel_key_payload_encode(tmp_len2, tmp_id,
+                                       strlen(channel->channel_key->
+                                              cipher->name),
+                                       channel->channel_key->cipher->name,
+                                       key_len, channel->key);
+      
+      /* If we are normal server then we will send it to our router.  If we
+        are router we will send it to all local servers that has clients on
+        the channel */
+      if (server->server_type == SILC_SERVER) {
+       if (!server->standalone)
+         silc_server_packet_send(server, 
+                                 cmd->server->id_entry->router->connection,
+                                 SILC_PACKET_CHANNEL_KEY, 0, packet->data,
+                                 packet->len, TRUE);
+      } else {
+       
+      }
+      
+      /* Send to locally connected clients on the channel */
+      silc_server_packet_send_local_channel(server, channel, 
+                                           SILC_PACKET_CHANNEL_KEY, 0,
+                                           packet->data, packet->len, FALSE);
+      silc_buffer_free(packet);
+    }
+  }
+  
+  if (mode_mask & SILC_CHANNEL_MODE_ULIMIT) {
+    /* User limit is set on channel */
+    unsigned int user_limit;
+      
+    /* Get user limit */
+    tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
+    if (!tmp) {
+      if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT)) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+       goto out;
+      }
+    } else {
+      SILC_GET32_MSB(user_limit, tmp);
+      channel->mode_data.user_limit = user_limit;
+    }
+  } else {
+    if (channel->mode & SILC_CHANNEL_MODE_ULIMIT)
+      /* User limit mode is unset. Remove user limit */
+      channel->mode_data.user_limit = 0;
+  }
+
+  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) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+       goto out;
+      }
+
+      /* Save the passphrase */
+      channel->mode_data.passphrase = strdup(tmp);
+    }
+  } else {
+    if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
+      /* Passphrase mode is unset. remove the passphrase */
+      if (channel->mode_data.passphrase) {
+       silc_free(channel->mode_data.passphrase);
+       channel->mode_data.passphrase = NULL;
+      }
+    }
+  }
+
+  if (mode_mask & SILC_CHANNEL_MODE_BAN) {
+    if (!(channel->mode & SILC_CHANNEL_MODE_BAN)) {
+      /* Ban list is specified for channel */
+
+      /* Get ban list */
+      tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
+      if (!tmp) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+       goto out;
+      }
+
+      /* XXX check that channel founder is not banned */
+
+      /* Save the ban list */
+      channel->mode_data.ban_list = strdup(tmp);
+    }
+  } else {
+    if (channel->mode & SILC_CHANNEL_MODE_BAN) {
+      /* Ban mode is unset. Remove the entire ban list */
+      if (channel->mode_data.ban_list) {
+       silc_free(channel->mode_data.ban_list);
+       channel->mode_data.ban_list = NULL;
+      }
+    }
+  }
+
+  if (mode_mask & SILC_CHANNEL_MODE_INVITE_LIST) {
+    if (!(channel->mode & SILC_CHANNEL_MODE_INVITE_LIST)) {
+      /* Invite list is specified for channel */
+
+      /* Get invite list */
+      tmp = silc_argument_get_arg_type(cmd->args, 6, NULL);
+      if (!tmp) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+       goto out;
+      }
+
+      /* Save the invite linst */
+      channel->mode_data.invite_list = strdup(tmp);
+    }
+  } else {
+    if (channel->mode & SILC_CHANNEL_MODE_INVITE_LIST) {
+      /* Invite list mode is unset. Remove the entire invite list */
+      if (channel->mode_data.invite_list) {
+       silc_free(channel->mode_data.invite_list);
+       channel->mode_data.invite_list = NULL;
+      }
+    }
+  }
+
+  if (mode_mask & SILC_CHANNEL_MODE_CIPHER) {
+    if (!(channel->mode & SILC_CHANNEL_MODE_CIPHER)) {
+      /* Cipher to use protect the traffic */
+      unsigned int key_len = 128;
+      unsigned char channel_key[32];
+      char *cp;
+
+      /* Get cipher */
+      tmp = silc_argument_get_arg_type(cmd->args, 8, NULL);
+      if (!tmp) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+                                             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+       goto out;
+      }
+
+      cp = strchr(tmp, ':');
+      if (cp) {
+       key_len = atoi(cp);
+       *cp = '\0';
+      }
+
+      /* XXX Duplicated code, make own function for this!! */
+    
+      /* Delete old cipher and allocate the new one */
+      silc_cipher_free(channel->channel_key);
+      silc_cipher_alloc(tmp, &channel->channel_key);
+
+      /* Re-generate channel key */
+      key_len /= 8;
+      if (key_len > sizeof(channel_key))
+       key_len = sizeof(channel_key);
+
+      for (i = 0; i < key_len; i++)
+       channel_key[i] = silc_rng_get_byte(server->rng);
+      channel->channel_key->cipher->set_key(channel->channel_key->context, 
+                                           channel_key, key_len);
+      memset(channel->key, 0, key_len);
+      silc_free(channel->key);
+      channel->key = silc_calloc(key_len, sizeof(*channel->key));
+      memcpy(channel->key, channel_key, key_len);
+      memset(channel_key, 0, sizeof(channel_key));
+    
+      /* Encode channel key payload to be distributed on the channel */
+      packet = 
+       silc_channel_key_payload_encode(tmp_len2, tmp_id,
+                                       strlen(channel->channel_key->
+                                              cipher->name),
+                                       channel->channel_key->cipher->name,
+                                       key_len, channel->key);
+    
+      /* If we are normal server then we will send it to our router.  If we
+        are router we will send it to all local servers that has clients on
+        the channel */
+      if (server->server_type == SILC_SERVER) {
+       if (!server->standalone)
+         silc_server_packet_send(server, 
+                                 cmd->server->id_entry->router->connection,
+                                 SILC_PACKET_CHANNEL_KEY, 0, packet->data,
+                                 packet->len, TRUE);
+      } else {
+       
+      }
+    
+      /* Send to locally connected clients on the channel */
+      silc_server_packet_send_local_channel(server, channel, 
+                                           SILC_PACKET_CHANNEL_KEY, 0,
+                                         packet->data, packet->len, FALSE);
+      silc_buffer_free(packet);
+    }
+  } else {
+    if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
+      /* Cipher mode is unset. Remove the cipher and revert back to 
+        default cipher */
+      unsigned int key_len;
+      unsigned char channel_key[32];
+
+      if (channel->mode_data.cipher) {
+       silc_free(channel->mode_data.cipher);
+       channel->mode_data.cipher = NULL;
+       channel->mode_data.key_len = 0;
+      }
+
+      /* Generate new cipher and key for the channel */
+
+      /* XXX Duplicated code, make own function for this!! */
+
+      /* Delete old cipher and allocate default one */
+      silc_cipher_free(channel->channel_key);
+      if (!channel->cipher)
+       silc_cipher_alloc("twofish", &channel->channel_key);
+      else
+       silc_cipher_alloc(channel->cipher, &channel->channel_key);
+
+      /* Re-generate channel key */
+      key_len = channel->key_len / 8;
+      for (i = 0; i < key_len; i++)
+       channel_key[i] = silc_rng_get_byte(server->rng);
+      channel->channel_key->cipher->set_key(channel->channel_key->context, 
+                                           channel_key, key_len);
+      memset(channel->key, 0, key_len);
+      silc_free(channel->key);
+      channel->key = silc_calloc(key_len, sizeof(*channel->key));
+      memcpy(channel->key, channel_key, key_len);
+      memset(channel_key, 0, sizeof(channel_key));
+      
+      /* Encode channel key payload to be distributed on the channel */
+      packet = 
+       silc_channel_key_payload_encode(tmp_len2, tmp_id,
+                                       strlen(channel->channel_key->
+                                              cipher->name),
+                                       channel->channel_key->cipher->name,
+                                       key_len, channel->key);
+      
+      /* If we are normal server then we will send it to our router.  If we
+        are router we will send it to all local servers that has clients on
+        the channel */
+      if (server->server_type == SILC_SERVER) {
+       if (!server->standalone)
+         silc_server_packet_send(server, 
+                                 cmd->server->id_entry->router->connection,
+                                 SILC_PACKET_CHANNEL_KEY, 0, packet->data,
+                                 packet->len, TRUE);
+      } else {
+       
+      }
+      
+      /* Send to locally connected clients on the channel */
+      silc_server_packet_send_local_channel(server, channel, 
+                                           SILC_PACKET_CHANNEL_KEY, 0,
+                                           packet->data, packet->len, FALSE);
+      silc_buffer_free(packet);
+    }
+  }
+
+  /* Finally, set the mode */
+  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, channel, 
+                                    SILC_NOTIFY_TYPE_CMODE_CHANGE, 2,
+                                    cidp->data, cidp->len, 
+                                    tmp_mask, tmp_len);
+  silc_free(cidp);
+
+  /* Send command reply to sender */
+  packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
+                                               SILC_STATUS_OK, 0, 1,
+                                               2, tmp_mask, 4);
+  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
+                         packet->data, packet->len, FALSE);
+    
+  silc_buffer_free(packet);
+  silc_free(channel_id);
+
+ out:
+  silc_server_command_free(cmd);
+}
+
+/* Server side of CUMODE command. Changes client's mode on a channel. */
+
+SILC_SERVER_CMD_FUNC(cumode)
+{
+  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+  SilcServer server = cmd->server;
+  SilcSocketConnection sock = cmd->sock;
+  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+  SilcChannelID *channel_id;
+  SilcClientID *client_id;
+  SilcChannelEntry channel;
+  SilcClientEntry target_client;
+  SilcChannelClientEntry chl;
+  SilcBuffer packet, idp;
+  unsigned char *tmp, *tmp_id, *tmp_mask;
+  unsigned int argc, target_mask, sender_mask, tmp_len;
+  int i, notify = FALSE;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  argc = silc_argument_get_arg_num(cmd->args);
+  if (argc < 3) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+    goto out;
+  }
+  if (argc > 3) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                         SILC_STATUS_ERR_TOO_MANY_PARAMS);
+    goto out;
+  }
+
+  /* Get Channel ID */
+  tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+  if (!tmp_id) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                         SILC_STATUS_ERR_NO_CHANNEL_ID);
+    goto out;
+  }
+  channel_id = silc_id_payload_parse_id(tmp_id, tmp_len);
+
+  /* Get channel entry */
+  channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
+  if (!channel) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                         SILC_STATUS_ERR_NO_SUCH_CHANNEL);
+    goto out;
+  }
+
+  /* Check whether sender is on the channel */
+  if (!silc_server_client_on_channel(client, channel)) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                         SILC_STATUS_ERR_NOT_ON_CHANNEL);
+    goto out;
+  }
+
+  /* Check that client has rights to change other's rights */
+  silc_list_start(channel->user_list);
+  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+    if (chl->client == client) {
+      if (!(chl->mode & SILC_CHANNEL_UMODE_CHANFO) &&
+         !(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                             SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+       goto out;
+      }
+
+      sender_mask = chl->mode;
+      break;
+    }
+  }
+  
+  /* Get the target client's channel mode mask */
+  tmp_mask = silc_argument_get_arg_type(cmd->args, 2, NULL);
+  if (!tmp_mask) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+    goto out;
+  }
+  SILC_GET32_MSB(target_mask, tmp_mask);
+
+  /* Get target Client ID */
+  tmp_id = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
+  if (!tmp_id) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                         SILC_STATUS_ERR_NO_CHANNEL_ID);
+    goto out;
+  }
+  client_id = silc_id_payload_parse_id(tmp_id, tmp_len);
+
+  /* Get target client's entry */
+  target_client = silc_idlist_find_client_by_id(server->local_list, client_id);
+  if (!client) {
+    /* XXX If target client is not one of mine send to primary route */
+  }
+
+  /* Check whether target client is on the channel */
+  if (!silc_server_client_on_channel(target_client, channel)) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                         SILC_STATUS_ERR_USER_NOT_ON_CHANNEL);
+    goto out;
+  }
+
+  /* Get entry to the channel user list */
+  silc_list_start(channel->user_list);
+  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
+    if (chl->client == target_client)
+      break;
+
+  /* 
+   * 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 && chl->client != target_client) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                         SILC_STATUS_ERR_NOT_YOU);
+    goto out;
+  }
+
+  if (target_mask & SILC_CHANNEL_UMODE_CHANFO) {
+    /* Cannot promote anyone to channel founder */
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                         SILC_STATUS_ERR_NOT_YOU);
+    goto out;
+  } else {
+    if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
+      if (target_client == client) {
+       /* Remove channel founder rights from itself */
+       chl->mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+       notify = TRUE;
+      } else {
+       silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+                                             SILC_STATUS_ERR_NOT_YOU);
+       goto out;
+      }
+    }
+  }
+
+  if (target_mask & SILC_CHANNEL_UMODE_CHANOP) {
+    /* Promote to operator */
+    if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
+      chl->mode |= SILC_CHANNEL_UMODE_CHANOP;
+      notify = TRUE;
+    }
+  } else {
+    if (chl->mode & SILC_CHANNEL_UMODE_CHANOP) {
+      /* Demote to normal user */
+      chl->mode &= ~SILC_CHANNEL_UMODE_CHANOP;
+      notify = TRUE;
+    }
+  }
+
+  /* Send notify to channel, notify only if mode was actually changed. */
+  if (notify) {
+    idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+    silc_server_send_notify_to_channel(server, channel,
+                                      SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
+                                      idp->data, idp->len,
+                                      tmp_mask, 4, tmp_id, tmp_len);
+    silc_buffer_free(idp);
+  }
+
+  /* Send command reply to sender */
+  packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CUMODE,
+                                               SILC_STATUS_OK, 0, 2,
+                                               2, tmp_mask, 4,
+                                               3, tmp_id, tmp_len);
+  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
+                         packet->data, packet->len, FALSE);
+    
+  silc_buffer_free(packet);
+  silc_free(channel_id);
+  silc_free(client_id);
+
+ out:
+  silc_server_command_free(cmd);
 }
 
+/* Server side of KICK command. Kicks client out of channel. */
+
 SILC_SERVER_CMD_FUNC(kick)
 {
+  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+  SilcServer server = cmd->server;
+  SilcSocketConnection sock = cmd->sock;
+  SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+
 }
 
 SILC_SERVER_CMD_FUNC(restart)
@@ -934,10 +2220,253 @@ SILC_SERVER_CMD_FUNC(silcoper)
 {
 }
 
+/* Server side command of LEAVE. Removes client from a channel. */
+
 SILC_SERVER_CMD_FUNC(leave)
 {
+  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+  SilcServer server = cmd->server;
+  SilcSocketConnection sock = cmd->sock;
+  SilcClientEntry id_entry = (SilcClientEntry)cmd->sock->user_data;
+  SilcChannelID *id;
+  SilcChannelEntry channel;
+  SilcBuffer packet;
+  unsigned int i, argc, key_len, len;
+  unsigned char *tmp, channel_key[32];
+
+  SILC_LOG_DEBUG(("Start"));
+
+  argc = silc_argument_get_arg_num(cmd->args);
+  if (argc < 1) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+    goto out;
+  }
+  if (argc > 2) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
+                                         SILC_STATUS_ERR_TOO_MANY_PARAMS);
+    goto out;
+  }
+
+  /* Get Channel ID */
+  tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
+  if (!tmp) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
+                                         SILC_STATUS_ERR_NO_CHANNEL_ID);
+    goto out;
+  }
+  id = silc_id_payload_parse_id(tmp, len);
+
+  /* Get channel entry */
+  channel = silc_idlist_find_channel_by_id(server->local_list, id);
+  if (!channel) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
+                                         SILC_STATUS_ERR_NO_SUCH_CHANNEL);
+    goto out;
+  }
+
+  /* Check whether this client is on the channel */
+  if (!silc_server_client_on_channel(id_entry, channel)) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
+                                         SILC_STATUS_ERR_NOT_ON_CHANNEL);
+    goto out;
+  }
+
+  /* Notify routers that they should remove this client from their list
+     of clients on the channel. */
+  if (!server->standalone)
+    silc_server_send_remove_channel_user(server, 
+                                        server->id_entry->router->connection,
+                                        server->server_type == SILC_ROUTER ?
+                                        TRUE : FALSE, id_entry->id, id);
+
+  /* Remove client from channel */
+  i = silc_server_remove_from_one_channel(server, sock, channel, id_entry,
+                                         TRUE);
+  silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
+                                       SILC_STATUS_OK);
+
+  /* If the channel does not exist anymore we won't send anything */
+  if (!i)
+    goto out;
+
+  /* Re-generate channel key */
+  key_len = channel->key_len / 8;
+  for (i = 0; i < key_len; i++)
+    channel_key[i] = silc_rng_get_byte(server->rng);
+  channel->channel_key->cipher->set_key(channel->channel_key->context, 
+                                       channel_key, key_len);
+  memset(channel->key, 0, key_len);
+  silc_free(channel->key);
+  channel->key = silc_calloc(key_len, sizeof(*channel->key));
+  memcpy(channel->key, channel_key, key_len);
+  memset(channel_key, 0, sizeof(channel_key));
+
+  /* Encode channel key payload to be distributed on the channel */
+  packet = 
+    silc_channel_key_payload_encode(len, tmp,
+                                   strlen(channel->channel_key->cipher->name),
+                                   channel->channel_key->cipher->name,
+                                   key_len, channel->key);
+
+  /* If we are normal server then we will send it to our router.  If we
+     are router we will send it to all local servers that has clients on
+     the channel */
+  if (server->server_type == SILC_SERVER) {
+    if (!server->standalone)
+      silc_server_packet_send(server, 
+                             cmd->server->id_entry->router->connection,
+                             SILC_PACKET_CHANNEL_KEY, 0, packet->data,
+                             packet->len, TRUE);
+  } else {
+
+  }
+
+  /* Send to locally connected clients on the channel */
+  silc_server_packet_send_local_channel(server, channel, 
+                                       SILC_PACKET_CHANNEL_KEY, 0,
+                                       packet->data, packet->len, FALSE);
+
+  silc_buffer_free(packet);
+  silc_free(id);
+
+ out:
+  silc_server_command_free(cmd);
 }
 
+/* Server side of command NAMES. Resolves clients and their names currently
+   joined on the requested channel. The name list is sent back to the
+   client. */
+
 SILC_SERVER_CMD_FUNC(names)
 {
+  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+  SilcServer server = cmd->server;
+  SilcChannelEntry channel;
+  SilcChannelClientEntry chl;
+  SilcChannelID *id;
+  SilcBuffer packet;
+  unsigned int i, len, len2, tmp_len, argc;
+  unsigned char *tmp;
+  char *name_list = NULL, *n;
+  SilcBuffer client_id_list;
+  SilcBuffer client_mode_list;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  argc = silc_argument_get_arg_num(cmd->args);
+  if (argc < 1) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_NAMES,
+                                         SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+    goto out;
+  }
+  if (argc > 2) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_NAMES,
+                                         SILC_STATUS_ERR_TOO_MANY_PARAMS);
+    goto out;
+  }
+
+  /* Get Channel ID */
+  tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+  if (!tmp) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
+                                         SILC_STATUS_ERR_NO_CHANNEL_ID);
+    goto out;
+  }
+  id = silc_id_payload_parse_id(tmp, tmp_len);
+
+  /* Check whether the channel exists. If we are normal server and the
+     channel does not exist we will send this same command to our router
+     which will know if the channel exists. */
+  channel = silc_idlist_find_channel_by_id(server->local_list, id);
+  if (!channel) {
+    if (server->server_type == SILC_SERVER && !server->standalone) {
+      /* XXX Send names command */
+
+      cmd->pending = TRUE;
+      silc_server_command_pending(SILC_COMMAND_NAMES, 
+                                 silc_server_command_names, context);
+      return;
+    }
+
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+                                         SILC_STATUS_ERR_NO_SUCH_CHANNEL);
+    goto out;
+  }
+
+  /* Assemble the name list now */
+  name_list = NULL;
+  len = 0;
+  silc_list_start(channel->user_list);
+  i = 0;
+  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+    n = chl->client->nickname;
+    if (n) {
+      len2 = strlen(n);
+      len += len2;
+      name_list = silc_realloc(name_list, sizeof(*name_list) * (len + 1));
+      memcpy(name_list + (len - len2), n, len2);
+      name_list[len] = 0;
+
+      if (i == silc_list_count(channel->user_list) - 1)
+       break;
+      memcpy(name_list + len, ",", 1);
+      len++;
+      i++;
+    }
+  }
+  if (!name_list)
+    name_list = "";
+
+  /* Assemble the Client ID list now */
+  client_id_list = silc_buffer_alloc((SILC_ID_CLIENT_LEN + 4) * 
+                                    silc_list_count(channel->user_list));
+  silc_buffer_pull_tail(client_id_list, SILC_BUFFER_END(client_id_list));
+  silc_list_start(channel->user_list);
+  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+    SilcBuffer idp;
+
+    idp = silc_id_payload_encode(chl->client->id, SILC_ID_CLIENT);
+    silc_buffer_format(client_id_list,
+                      SILC_STR_UI_XNSTRING(idp->data, idp->len),
+                      SILC_STR_END);
+    silc_buffer_pull(client_id_list, idp->len);
+    silc_buffer_free(idp);
+  }
+  silc_buffer_push(client_id_list, 
+                  client_id_list->data - client_id_list->head);
+
+  /* Assemble mode list */
+  client_mode_list = silc_buffer_alloc(4 * 
+                                      silc_list_count(channel->user_list));
+  silc_buffer_pull_tail(client_mode_list, SILC_BUFFER_END(client_mode_list));
+  silc_list_start(channel->user_list);
+  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+    SILC_PUT32_MSB(chl->mode, client_mode_list->data);
+    silc_buffer_pull(client_mode_list, 4);
+  }
+  silc_buffer_push(client_mode_list, 
+                  client_mode_list->data - client_mode_list->head);
+
+  /* Send reply */
+  packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NAMES,
+                                               SILC_STATUS_OK, 0, 4,
+                                               2, tmp, tmp_len,
+                                               3, name_list, 
+                                               strlen(name_list),
+                                               4, client_id_list->data,
+                                               client_id_list->len,
+                                               5, client_mode_list->data,
+                                               client_mode_list->len);
+  silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0, 
+                         packet->data, packet->len, FALSE);
+    
+  silc_buffer_free(packet);
+  silc_free(name_list);
+  silc_buffer_free(client_id_list);
+  silc_buffer_free(client_mode_list);
+  silc_free(id);
+
+ out:
+  silc_server_command_free(cmd);
 }
index d7ed494402f85815512825d49220991aab85bb6e..1ced0891082df4ea576fa14e50edf7a0a3154f43 100644 (file)
@@ -52,6 +52,7 @@ typedef struct {
   SilcServer server;
   SilcSocketConnection sock;
   SilcCommandPayload payload;
+  SilcArgumentPayload args;
   SilcPacketContext *packet;
   int pending;
 } *SilcServerCommandContext;
@@ -82,24 +83,6 @@ extern SilcServerCommandPending *silc_command_pending;
 #define SILC_SERVER_CMD_FUNC(func) \
 void silc_server_command_##func(void *context)
 
-/* Macro used to execute commands */
-#define SILC_SERVER_COMMAND_EXEC(ctx)                          \
-do {                                                           \
-  SilcServerCommand *cmd;                                      \
-                                                               \
-  for (cmd = silc_command_list; cmd->cb; cmd++)                        \
-    if (cmd->cmd == silc_command_get(ctx->payload)) {          \
-      cmd->cb(ctx);                                            \
-      break;                                                   \
-    }                                                          \
-                                                               \
-  if (cmd == NULL) {                                           \
-    SILC_LOG_ERROR(("Unknown command, packet dropped"));       \
-    silc_free(ctx);                                            \
-    return;                                                    \
-  }                                                            \
-} while(0)
-
 /* Checks for pending commands */
 #define SILC_SERVER_COMMAND_CHECK_PENDING(ctx)         \
 do {                                                   \
@@ -128,6 +111,9 @@ do {                                                        \
 } while(0)
 
 /* Prototypes */
+void silc_server_command_process(SilcServer server,
+                                SilcSocketConnection sock,
+                                SilcPacketContext *packet);
 void silc_server_command_pending(SilcCommand reply_cmd,
                                 SilcCommandCb callback,
                                 void *context);
@@ -152,6 +138,7 @@ SILC_SERVER_CMD_FUNC(join);
 SILC_SERVER_CMD_FUNC(motd);
 SILC_SERVER_CMD_FUNC(umode);
 SILC_SERVER_CMD_FUNC(cmode);
+SILC_SERVER_CMD_FUNC(cumode);
 SILC_SERVER_CMD_FUNC(kick);
 SILC_SERVER_CMD_FUNC(ignore);
 SILC_SERVER_CMD_FUNC(restart);
index 815a858509f92ab281d2b9c21b5bcccc25938d62..4ec3a8c37629d2d4a2a34d30b1efcfff8dafa10f 100644 (file)
   GNU General Public License for more details.
 
 */
-/*
- * $Id$
- * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:56  priikone
- *     Importet from internal CVS/Added Log headers.
- *
- *
- */
+/* $Id$ */
 
 #include "serverincludes.h"
 #include "server_internal.h"
 #include "command_reply.h"
 
 /* Server command reply list. Not all commands have reply function as
-   they are never sent as forwarded command packets by server. More
-   maybe added later if need appears. */
+   they are never sent by server. More maybe added later if need appears. */
 SilcServerCommandReply silc_command_reply_list[] =
 {
   SILC_SERVER_CMD_REPLY(join, JOIN),
+  SILC_SERVER_CMD_REPLY(identify, IDENTIFY),
 
   { NULL, 0 },
 };
@@ -50,7 +43,7 @@ void silc_server_command_reply_process(SilcServer server,
   SilcCommandPayload payload;
 
   /* Get command reply payload from packet */
-  payload = silc_command_parse_payload(buffer);
+  payload = silc_command_payload_parse(buffer);
   if (!payload) {
     /* Silently ignore bad reply packet */
     SILC_LOG_DEBUG(("Bad command reply packet"));
@@ -63,6 +56,7 @@ void silc_server_command_reply_process(SilcServer server,
   ctx->server = server;
   ctx->sock = sock;
   ctx->payload = payload;
+  ctx->args = silc_command_get_args(ctx->payload);
       
   /* Check for pending commands and mark to be exeucted */
   SILC_SERVER_COMMAND_CHECK_PENDING(ctx);
@@ -91,42 +85,41 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
   SilcServer server = cmd->server;
   SilcCommandStatus status;
   SilcChannelID *id;
-  SilcChannelList *entry;
-  unsigned int argc;
+  SilcChannelEntry entry;
+  unsigned int len;
   unsigned char *id_string;
   char *channel_name, *tmp;
 
-#define LCC(x) server->local_list->channel_cache[(x) - 32]
-#define LCCC(x) server->local_list->channel_cache_count[(x) - 32]
-
   SILC_LOG_DEBUG(("Start"));
 
-  tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
+  tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
   SILC_GET16_MSB(status, tmp);
   if (status != SILC_STATUS_OK)
     goto out;
 
   /* Get channel name */
-  tmp = silc_command_get_arg_type(cmd->payload, 2, NULL);
+  tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
   if (!tmp)
     goto out;
 
   /* Get channel ID */
-  id_string = silc_command_get_arg_type(cmd->payload, 3, NULL);
+  id_string = silc_argument_get_arg_type(cmd->args, 3, &len);
   if (!id_string)
     goto out;
 
   channel_name = strdup(tmp);
 
   /* Add the channel to our local list. */
-  id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
-  silc_idlist_add_channel(&server->local_list->channels, channel_name, 
-                         SILC_CHANNEL_MODE_NONE, id, 
-                         server->id_entry->router, NULL, &entry);
-  LCCC(channel_name[0]) = silc_idcache_add(&LCC(channel_name[0]), 
-                                          LCCC(channel_name[0]),
-                                          channel_name, SILC_ID_CHANNEL, 
-                                          (void *)id, (void *)entry);
+  id = silc_id_payload_parse_id(id_string, len);
+  entry = silc_idlist_add_channel(server->local_list, channel_name, 
+                                 SILC_CHANNEL_MODE_NONE, id, 
+                                 server->id_entry->router, NULL);
+  if (!entry) {
+    silc_free(channel_name);
+    silc_free(id);
+    goto out;
+  }
+
   entry->global_users = TRUE;
 
   /* Execute pending JOIN command so that the client who originally
@@ -135,6 +128,60 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
 
  out:
   silc_server_command_reply_free(cmd);
-#undef LCC
-#undef LCCC
+}
+
+/* Received reply for forwarded IDENTIFY command. We have received the
+   requested identify information now and we will cache it. After this we
+   will call the pending command so that the requestee gets the information
+   after all. */
+
+SILC_SERVER_CMD_REPLY_FUNC(identify)
+{
+  SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
+  SilcServer server = cmd->server;
+  SilcCommandStatus status;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
+  if (status != SILC_STATUS_OK)
+    goto out;
+
+  /* Process one identify reply */
+  if (status == SILC_STATUS_OK) {
+    SilcClientID *client_id;
+    unsigned int len;
+    unsigned char *id_data;
+    char *nickname, *username;
+
+    id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
+    nickname = silc_argument_get_arg_type(cmd->args, 3, NULL);
+    if (!id_data || !nickname)
+      goto out;
+
+    username = silc_argument_get_arg_type(cmd->args, 4, NULL);
+    client_id = silc_id_payload_parse_id(id_data, len);
+
+    /* Add the client always to our global list. If normal or router server
+       ever gets here it means they don't have this client's information
+       in their cache. */
+    silc_idlist_add_client(server->global_list, strdup(nickname),
+                          username, NULL, client_id, NULL, NULL, NULL,
+                          NULL, NULL, NULL, NULL);
+  }
+
+  if (status == SILC_STATUS_LIST_START) {
+
+  }
+
+  if (status == SILC_STATUS_LIST_END) {
+
+  }
+
+  /* Execute pending IDENTIFY command so that the client who originally
+     requested the identify information will get it after all. */
+  SILC_SERVER_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_IDENTIFY);
+
+ out:
+  silc_server_command_reply_free(cmd);
 }
index 0e67aa287dbb2dddb0119ca1fe7df8f42d28c6e2..c8faa73c7648d883dc83ccd3ae8169f069932b46 100644 (file)
@@ -35,6 +35,7 @@ typedef struct {
   SilcServer server;
   SilcSocketConnection sock;
   SilcCommandPayload payload;
+  SilcArgumentPayload args;
 
   /* If defined this executes the pending command. */
   void *context;
@@ -73,5 +74,6 @@ void silc_server_command_reply_process(SilcServer server,
                                       SilcSocketConnection sock,
                                       SilcBuffer buffer);
 SILC_SERVER_CMD_REPLY_FUNC(join);
+SILC_SERVER_CMD_REPLY_FUNC(identify);
 
 #endif
index 5f04a26fd691c81ce893bf4a0d34d1128d4b8de2..358bef33f467826ace5549b419c4c4dc7652fcf5 100644 (file)
   GNU General Public License for more details.
 
 */
-/*
- * $Id$
- * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:56  priikone
- *     Importet from internal CVS/Added Log headers.
- *
- *
- */
+/* $Id$ */
 
 #include "serverincludes.h"
 #include "idlist.h"
 
-/* Adds a new server to the list. The pointer sent as argument is allocated
-   and returned. */
+/******************************************************************************
 
-void silc_idlist_add_server(SilcServerList **list, 
-                           char *server_name, int server_type,
-                           SilcServerID *id, SilcServerList *router,
-                           SilcCipher send_key, SilcCipher receive_key,
-                           SilcPKCS public_key, SilcHmac hmac, 
-                           SilcServerList **new_idlist)
-{
-  SilcServerList *last, *idlist;
+                          Server entry functions
 
-  SILC_LOG_DEBUG(("Adding new server to id list"));
+******************************************************************************/
 
-  idlist = silc_calloc(1, sizeof(*idlist));
-  if (idlist == NULL) {
-    SILC_LOG_ERROR(("Could not allocate new server list object"));
-    *new_idlist = NULL;
-    return;
-  }
+/* Add new server entry. This adds the new server entry to ID cache and
+   returns the allocated entry object or NULL on error. This is called
+   when new server connects to us. We also add ourselves to cache with
+   this function. */
 
-  /* Set the pointers */
-  idlist->server_name = server_name;
-  idlist->server_type = server_type;
-  idlist->id = id;
-  idlist->router = router;
-  idlist->send_key = send_key;
-  idlist->receive_key = receive_key;
-  idlist->public_key = public_key;
-  idlist->hmac = hmac;
-  idlist->next = idlist;
-  idlist->prev = idlist;
-
-  /* First on the list? */
-  if (!*list) {
-    *list = idlist;
-    *new_idlist = idlist;
-    return;
+SilcServerEntry 
+silc_idlist_add_server(SilcIDList id_list, 
+                      char *server_name, int server_type,
+                      SilcServerID *id, SilcServerEntry router,
+                      SilcCipher send_key, SilcCipher receive_key,
+                      SilcPKCS pkcs, SilcHmac hmac, 
+                      SilcPublicKey public_key, void *connection)
+{
+  SilcServerEntry server;
+
+  SILC_LOG_DEBUG(("Adding new server entry"));
+
+  server = silc_calloc(1, sizeof(*server));
+  server->server_name = server_name;
+  server->server_type = server_type;
+  server->id = id;
+  server->router = router;
+  server->send_key = send_key;
+  server->receive_key = receive_key;
+  server->pkcs = pkcs;
+  server->hmac = hmac;
+  server->public_key = public_key;
+  server->connection = connection;
+
+  if (!silc_idcache_add(id_list->servers, server->server_name, SILC_ID_SERVER,
+                       (void *)server->id, (void *)server, TRUE)) {
+    silc_free(server);
+    return NULL;
   }
 
-  /* Add it to the list */
-  last = (*list)->prev;
-  last->next = idlist;
-  (*list)->prev = idlist;
-  idlist->next = (*list);
-  idlist->prev = last;
+  return server;
+}
+
+/* Finds server by Server ID */
+
+SilcServerEntry
+silc_idlist_find_server_by_id(SilcIDList id_list, SilcServerID *id)
+{
+  SilcIDCacheEntry id_cache = NULL;
+  SilcServerEntry server;
+
+  if (!id)
+    return NULL;
+
+  SILC_LOG_DEBUG(("Finding server by ID"));
+
+  if (!silc_idcache_find_by_id_one(id_list->servers, (void *)id, 
+                                  SILC_ID_SERVER, &id_cache))
+    return NULL;
+
+  server = (SilcServerEntry)id_cache->context;
 
-  if (new_idlist)
-    *new_idlist = idlist;
+  return server;
 }
 
-/* Adds a new client to the client list. This is called when new client 
-   connection is accepted to the server. This adds all the relevant data 
-   about the client and session with it to the list. This list is 
-   referenced for example when sending message to the client. */
-
-void silc_idlist_add_client(SilcClientList **list, char *nickname,
-                           char *username, char *userinfo,
-                           SilcClientID *id, SilcServerList *router,
-                           SilcCipher send_key, SilcCipher receive_key,
-                           SilcPKCS public_key, SilcHmac hmac, 
-                           SilcClientList **new_idlist)
+/* Replaces old Server ID with new one */ 
+
+SilcServerEntry
+silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id,
+                             SilcServerID *new_id)
 {
-  SilcClientList *last, *idlist;
+  SilcIDCacheEntry id_cache = NULL;
+  SilcServerEntry server;
 
-  SILC_LOG_DEBUG(("Adding new client to id list"));
+  if (!old_id || !new_id)
+    return NULL;
 
-  idlist = silc_calloc(1, sizeof(*idlist));
-  if (idlist == NULL) {
-    SILC_LOG_ERROR(("Could not allocate new client list object"));
-    return;
-  }
+  SILC_LOG_DEBUG(("Replacing Server ID"));
 
-  /* Set the pointers */
-  idlist->nickname = nickname;
-  idlist->username = username;
-  idlist->userinfo = userinfo;
-  idlist->id = id;
-  idlist->router = router;
-  idlist->send_key = send_key;
-  idlist->receive_key = receive_key;
-  idlist->public_key = public_key;
-  idlist->hmac = hmac;
-  idlist->next = idlist;
-  idlist->prev = idlist;
-
-  /* First on the list? */
-  if (!(*list)) {
-    *list = idlist;
-    if (new_idlist)
-      *new_idlist = idlist;
-    return;
-  }
+  if (!silc_idcache_find_by_id_one(id_list->servers, (void *)old_id, 
+                                  SILC_ID_SERVER, &id_cache))
+    return NULL;
+
+  server = (SilcServerEntry)id_cache->context;
+  silc_free(server->id);
+  server->id = new_id;
+  id_cache->id = (void *)new_id;
+
+  return server;
+}
+
+/******************************************************************************
+
+                          Client entry functions
+
+******************************************************************************/
 
-  /* Add it to the list */
-  last = (*list)->prev;
-  last->next = idlist;
-  (*list)->prev = idlist;
-  idlist->next = *list;
-  idlist->prev = last;
+/* Add new client entry. This adds the client entry to ID cache system
+   and returns the allocated client entry or NULL on error.  This is
+   called when new client connection is accepted to the server. */
 
-  if (new_idlist)
-    *new_idlist = idlist;
+SilcClientEntry
+silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username,
+                      char *userinfo, SilcClientID *id, 
+                      SilcServerEntry router,
+                      SilcCipher send_key, SilcCipher receive_key,
+                      SilcPKCS pkcs, SilcHmac hmac, 
+                      SilcPublicKey public_key, void *connection)
+{
+  SilcClientEntry client;
+
+  SILC_LOG_DEBUG(("Adding new client entry"));
+
+  client = silc_calloc(1, sizeof(*client));
+  client->nickname = nickname;
+  client->username = username;
+  client->userinfo = userinfo;
+  client->id = id;
+  client->router = router;
+  client->send_key = send_key;
+  client->receive_key = receive_key;
+  client->pkcs = pkcs;
+  client->hmac = hmac;
+  client->public_key = public_key;
+  client->connection = connection;
+
+  if (!silc_idcache_add(id_list->clients, client->nickname, SILC_ID_CLIENT,
+                       (void *)client->id, (void *)client, TRUE)) {
+    silc_free(client);
+    return NULL;
+  }
+
+  return client;
 }
 
-/* Free client entry.  This free's everything. */
+/* Free client entry. This free's everything and removes the entry
+   from ID cache. */
 
-void silc_idlist_del_client(SilcClientList **list, SilcClientList *entry)
+void silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry)
 {
   if (entry) {
+    /* Remove from cache */
+    if (entry->id)
+      silc_idcache_del_by_id(id_list->clients, SILC_ID_CLIENT, 
+                            (void *)entry->id);
+
+    /* Free data */
     if (entry->nickname)
       silc_free(entry->nickname);
     if (entry->username)
@@ -151,213 +182,227 @@ void silc_idlist_del_client(SilcClientList **list, SilcClientList *entry)
       silc_cipher_free(entry->send_key);
     if (entry->receive_key)
       silc_cipher_free(entry->receive_key);
+    if (entry->pkcs)
+      silc_pkcs_free(entry->pkcs);
     if (entry->public_key)
-      silc_pkcs_free(entry->public_key);
+      silc_pkcs_public_key_free(entry->public_key);
     if (entry->hmac)
       silc_hmac_free(entry->hmac);
-    if (entry->hmac_key) {
-      memset(entry->hmac_key, 0, entry->hmac_key_len);
-      silc_free(entry->hmac_key);
-    }
+  }
+}
 
-    /* Last one in list? */
-    if (*list == entry && entry->next == entry) {
-      *list = NULL;
-      silc_free(entry);
-      return;
-    }
+/* Returns all clients matching requested nickname. Number of clients is
+   returned to `clients_count'. Caller must free the returned table. */
 
-    /* At the start of list? */
-    if (*list == entry && entry->next != entry) {
-      *list = entry->next;
-      entry->next->prev = entry->prev;
-      entry->prev->next = *list;
-      silc_free(entry);
-      return;
-    }
+SilcClientEntry *
+silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname,
+                                   char *server, unsigned int *clients_count)
+{
+  SilcIDCacheList list = NULL;
+  SilcIDCacheEntry id_cache = NULL;
+  SilcClientEntry *clients;
+  int i;
 
-    /* Remove from list */
-    entry->prev->next = entry->next;
-    entry->next->prev = entry->prev;
-    silc_free(entry);
-    return;
-  }
+  if (!silc_idcache_find_by_data(id_list->clients, nickname, &list))
+    return NULL;
+
+  clients = silc_calloc(silc_idcache_list_count(list), sizeof(*clients));
+
+  i = 0;
+  silc_idcache_list_first(list, &id_cache);
+  clients[i++] = (SilcClientEntry)id_cache->context;
+
+  while (silc_idcache_list_next(list, &id_cache))
+    clients[i++] = (SilcClientEntry)id_cache->context;
+  
+  silc_idcache_list_free(list);
+  
+  if (clients_count)
+    *clients_count = i;
+
+  return clients;
 }
 
-SilcClientList *
-silc_idlist_find_client_by_nickname(SilcClientList *list,
-                                   char *nickname,
+/* Finds client entry by nickname. */
+
+SilcClientEntry
+silc_idlist_find_client_by_nickname(SilcIDList id_list, char *nickname,
                                    char *server)
 {
-  SilcClientList *first, *entry;
+  SilcIDCacheList list = NULL;
+  SilcIDCacheEntry id_cache = NULL;
+  SilcClientEntry client = NULL;
 
   SILC_LOG_DEBUG(("Finding client by nickname"));
 
-  if (!list)
-    return NULL;
+  if (server) {
+    if (!silc_idcache_find_by_data(id_list->clients, nickname, &list))
+      return NULL;
 
-  first = entry = list;
-  if (!strcmp(entry->nickname, nickname)) {
-    SILC_LOG_DEBUG(("Found"));
-    return entry;
-  }
-  entry = entry->next;
+#if 0
+    while (silc_idcache_list_next(list, &id_cache)) {
+      client = (SilcClientEntry)id_cache->context;
 
-  while(entry != first) {
-    if (!strcmp(entry->nickname, nickname)) {
-      SILC_LOG_DEBUG(("Found"));
-      return entry;
+      if (!strcmp(server, XXX, strlen(server)))
+       break;
+
+      client = NULL;
     }
+#endif
+
+   silc_idcache_list_free(list);
+
+   if (!client)
+     return NULL;
+  } else {
+    if (!silc_idcache_find_by_data_one(id_list->clients, nickname, &id_cache))
+      return NULL;
 
-    entry = entry->next;
+    client = (SilcClientEntry)id_cache->context;
   }
 
-  return NULL;
+  return client;
 }
 
-SilcClientList *
-silc_idlist_find_client_by_hash(SilcClientList *list,
-                               char *nickname, SilcHash md5hash)
-{
-  SilcClientList *first, *entry;
-  unsigned char hash[16];
+/* Finds client by nickname hash. */
 
-  SILC_LOG_DEBUG(("Finding client by nickname hash"));
+SilcClientEntry
+silc_idlist_find_client_by_hash(SilcIDList id_list, char *nickname,
+                               SilcHash md5hash)
+{
+  SilcIDCacheList list = NULL;
+  SilcIDCacheEntry id_cache = NULL;
+  SilcClientEntry client = NULL;
+  unsigned char hash[32];
 
-  if (!list)
-    return NULL;
+  SILC_LOG_DEBUG(("Finding client by hash"));
 
-  /* Make hash of the nickname */
   silc_hash_make(md5hash, nickname, strlen(nickname), hash);
 
-  first = entry = list;
-  if (entry && !SILC_ID_COMPARE_HASH(entry->id, hash)) {
-    SILC_LOG_DEBUG(("Found"));
-    return entry;
+  if (!silc_idcache_find_by_id(id_list->clients, SILC_ID_CACHE_ANY, 
+                              SILC_ID_CLIENT, &list))
+    return NULL;
+
+  if (!silc_idcache_list_first(list, &id_cache)) {
+    silc_idcache_list_free(list);
+    return NULL;
   }
-  entry = entry->next;
 
-  while(entry != first) {
-    if (entry && !SILC_ID_COMPARE_HASH(entry->id, hash)) {
-      SILC_LOG_DEBUG(("Found"));
-      return entry;
-    }
+  while (id_cache) {
+    client = (SilcClientEntry)id_cache->context;
+    
+    if (client && !SILC_ID_COMPARE_HASH(client->id, hash))
+      break;
 
-    entry = entry->next;
+    id_cache = NULL;
+    client = NULL;
+
+    if (!silc_idcache_list_next(list, &id_cache))
+      break;
   }
+  
+  silc_idcache_list_free(list);
 
-  return NULL;
+  return client;
 }
 
-SilcClientList *
-silc_idlist_find_client_by_id(SilcClientList *list, SilcClientID *id)
-{
-  SilcClientList *first, *entry;
+/* Finds client by Client ID */
 
-  SILC_LOG_DEBUG(("Finding client by Client ID"));
+SilcClientEntry
+silc_idlist_find_client_by_id(SilcIDList id_list, SilcClientID *id)
+{
+  SilcIDCacheEntry id_cache = NULL;
+  SilcClientEntry client;
 
-  if (!list)
+  if (!id)
     return NULL;
 
-  first = entry = list;
-  if (entry && !SILC_ID_CLIENT_COMPARE(entry->id, id)) {
-    SILC_LOG_DEBUG(("Found"));
-    return entry;
-  }
-  entry = entry->next;
+  SILC_LOG_DEBUG(("Finding client by ID"));
 
-  while(entry != first) {
-    if (entry && !SILC_ID_CLIENT_COMPARE(entry->id, id)) {
-      SILC_LOG_DEBUG(("Found"));
-      return entry;
-    }
+  if (!silc_idcache_find_by_id_one(id_list->clients, (void *)id, 
+                                  SILC_ID_CLIENT, &id_cache))
+    return NULL;
 
-    entry = entry->next;
-  }
+  client = (SilcClientEntry)id_cache->context;
 
-  return NULL;
+  return client;
 }
 
-/* Adds new channel to the list. */
+/* Replaces old Client ID with new one */
 
-void silc_idlist_add_channel(SilcChannelList **list, 
-                            char *channel_name, int mode,
-                            SilcChannelID *id, SilcServerList *router,
-                            SilcCipher channel_key,
-                            SilcChannelList **new_idlist)
+SilcClientEntry
+silc_idlist_replace_client_id(SilcIDList id_list, SilcClientID *old_id,
+                             SilcClientID *new_id)
 {
-  SilcChannelList *last, *idlist;
+  SilcIDCacheEntry id_cache = NULL;
+  SilcClientEntry client;
 
-  SILC_LOG_DEBUG(("Adding new channel to id list"));
+  if (!old_id || !new_id)
+    return NULL;
 
-  idlist = silc_calloc(1, sizeof(*idlist));
-  if (idlist == NULL) {
-    SILC_LOG_ERROR(("Could not allocate new channel list object"));
-    return;
-  }
+  SILC_LOG_DEBUG(("Replacing Client ID"));
 
-  /* Set the pointers */
-  idlist->channel_name = channel_name;
-  idlist->mode = mode;
-  idlist->id = id;
-  idlist->router = router;
-  idlist->channel_key = channel_key;
-  idlist->next = idlist;
-  idlist->prev = idlist;
-
-  /* First on the list? */
-  if (!*list) {
-    *list = idlist;
-    if (new_idlist)
-      *new_idlist = idlist;
-    return;
-  }
+  if (!silc_idcache_find_by_id_one(id_list->clients, (void *)old_id, 
+                                  SILC_ID_CLIENT, &id_cache))
+    return NULL;
 
-  /* Add it to the list */
-  last = (*list)->prev;
-  last->next = idlist;
-  (*list)->prev = idlist;
-  idlist->next = (*list);
-  idlist->prev = last;
+  client = (SilcClientEntry)id_cache->context;
+  silc_free(client->id);
+  client->id = new_id;
+  id_cache->id = (void *)new_id;
 
-  if (new_idlist)
-    *new_idlist = idlist;
+  return client;
 }
 
-SilcChannelList *
-silc_idlist_find_channel_by_id(SilcChannelList *list, SilcChannelID *id)
-{
-  SilcChannelList *first, *entry;
 
-  SILC_LOG_DEBUG(("Finding channel by Channel ID"));
+/******************************************************************************
 
-  if (!list)
-    return NULL;
+                          Channel entry functions
 
-  first = entry = list;
-  if (entry && !SILC_ID_CHANNEL_COMPARE(entry->id, id)) {
-    SILC_LOG_DEBUG(("Found"));
-    return entry;
-  }
-  entry = entry->next;
+******************************************************************************/
 
-  while(entry != first) {
-    if (entry && !SILC_ID_CHANNEL_COMPARE(entry->id, id)) {
-      SILC_LOG_DEBUG(("Found"));
-      return entry;
-    }
+/* Add new channel entry. This add the new channel entry to the ID cache
+   system and returns the allocated entry or NULL on error. */
 
-    entry = entry->next;
+SilcChannelEntry
+silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode,
+                       SilcChannelID *id, SilcServerEntry router,
+                       SilcCipher channel_key)
+{
+  SilcChannelEntry channel;
+
+  channel = silc_calloc(1, sizeof(*channel));
+  channel->channel_name = channel_name;
+  channel->mode = mode;
+  channel->id = id;
+  channel->router = router;
+  channel->channel_key = channel_key;
+  silc_list_init(channel->user_list, struct SilcChannelClientEntryStruct, 
+                next);
+
+  if (!silc_idcache_add(id_list->channels, channel->channel_name, 
+                       SILC_ID_CHANNEL, (void *)channel->id, 
+                       (void *)channel, TRUE)) {
+    silc_free(channel);
+    return NULL;
   }
 
-  return NULL;
+  return channel;
 }
 
 /* Free channel entry.  This free's everything. */
 
-void silc_idlist_del_channel(SilcChannelList **list, SilcChannelList *entry)
+void silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
 {
   if (entry) {
+    SilcChannelClientEntry chl;
+
+    /* Remove from cache */
+    if (entry->id)
+      silc_idcache_del_by_id(id_list->channels, SILC_ID_CHANNEL, 
+                            (void *)entry->id);
+
+    /* Free data */
     if (entry->channel_name)
       silc_free(entry->channel_name);
     if (entry->id)
@@ -367,34 +412,64 @@ void silc_idlist_del_channel(SilcChannelList **list, SilcChannelList *entry)
     if (entry->channel_key)
       silc_cipher_free(entry->channel_key);
     if (entry->key) {
-      memset(entry->key, 0, entry->key_len);
+      memset(entry->key, 0, entry->key_len / 8);
       silc_free(entry->key);
     }
     memset(entry->iv, 0, sizeof(entry->iv));
+    
+    silc_list_start(entry->user_list);
+    while ((chl = silc_list_get(entry->user_list)) != SILC_LIST_END) {
+      silc_list_del(entry->user_list, chl);
+      silc_free(chl);
+    }
+  }
+}
 
-    if (entry->user_list_count)
-      silc_free(entry->user_list);
+/* Finds channel by channel name. Channel names are unique and they
+   are not case-sensitive. */
 
-    /* Last one in list? */
-    if (*list == entry && entry->next == entry) {
-      *list = NULL;
-      silc_free(entry);
-      return;
-    }
+SilcChannelEntry
+silc_idlist_find_channel_by_name(SilcIDList id_list, char *name)
+{
+  SilcIDCacheList list = NULL;
+  SilcIDCacheEntry id_cache = NULL;
+  SilcChannelEntry channel;
 
-    /* At the start of list? */
-    if (*list == entry && entry->next != entry) {
-      *list = entry->next;
-      entry->next->prev = entry->prev;
-      entry->prev->next = *list;
-      silc_free(entry);
-      return;
-    }
+  SILC_LOG_DEBUG(("Finding channel by name"));
 
-    /* Remove from list */
-    entry->prev->next = entry->next;
-    entry->next->prev = entry->prev;
-    silc_free(entry);
-    return;
+  if (!silc_idcache_find_by_data_loose(id_list->channels, name, &list))
+    return NULL;
+  
+  if (!silc_idcache_list_first(list, &id_cache)) {
+    silc_idcache_list_free(list);
+    return NULL;
   }
+
+  channel = (SilcChannelEntry)id_cache->context;
+
+  silc_idcache_list_free(list);
+
+  return channel;
+}
+
+/* Finds channel by Channel ID. */
+
+SilcChannelEntry
+silc_idlist_find_channel_by_id(SilcIDList id_list, SilcChannelID *id)
+{
+  SilcIDCacheEntry id_cache = NULL;
+  SilcChannelEntry channel;
+
+  if (!id)
+    return NULL;
+
+  SILC_LOG_DEBUG(("Finding channel by ID"));
+
+  if (!silc_idcache_find_by_id_one(id_list->channels, (void *)id, 
+                                  SILC_ID_CHANNEL, &id_cache))
+    return NULL;
+
+  channel = (SilcChannelEntry)id_cache->context;
+
+  return channel;
 }
index b18b90ddb6dc533d0f59c98a7e39828dfce2ca06..aa444f46f59b78a92ad7f440f83780407bbf4ea2 100644 (file)
 #define IDLIST_H
 
 /* Forward declarations */
-typedef struct SilcServerListStruct SilcServerList;
-typedef struct SilcClientListStruct SilcClientList;
-typedef struct SilcChannelListStruct SilcChannelList;
+typedef struct SilcServerEntryStruct *SilcServerEntry;
+typedef struct SilcClientEntryStruct *SilcClientEntry;
+typedef struct SilcChannelEntryStruct *SilcChannelEntry;
 
 /* 
-   SILC Server list object.
+   SILC Server entry object.
 
-   This list holds information about servers in SILC network. However, 
-   contents of this list is highly dependent of what kind of server we are 
-   (normal server or router server) and whether the list is used as a local 
-   list or a global list. These factors dictates the contents of this list.
+   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 list is defined as follows:
+   This entry is defined as follows:
 
    Server type   List type      Contents
    =======================================================================
@@ -61,16 +61,21 @@ typedef struct SilcChannelListStruct SilcChannelList;
        the server SILC will ever need. These are also the informations
        that is broadcasted between servers and routers in the SILC network.
 
-   struct SilcServerListStruct *router
+   long last_receive
+
+       Time when data was received from the server last time.
+
+   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 
        it doesn't have a route this is NULL.
 
    SilcCipher send_key
-   
    SilcCipher receive_key
 
+       Data sending and receiving keys.
+
    void *connection
 
        A pointer, usually, to the socket list for fast referencing to
@@ -79,37 +84,39 @@ typedef struct SilcChannelListStruct SilcChannelList;
        list.
    
 */
-struct SilcServerListStruct {
+struct SilcServerEntryStruct {
   char *server_name;
   int server_type;
   SilcServerID *id;
+  long last_receive;
+
+  /* TRUE when server is registered to server */
+  int registered;
 
   /* Pointer to the router */
-  struct SilcServerListStruct *router;
+  SilcServerEntry router;
 
   /* Keys */
   SilcCipher send_key;
   SilcCipher receive_key;
-  SilcPKCS public_key;
+  SilcPKCS pkcs;
+  SilcPublicKey public_key;
   SilcHmac hmac;
   unsigned char *hmac_key;
   unsigned int hmac_key_len;
 
   /* Connection data */
   void *connection;
-
-  struct SilcServerListStruct *next;
-  struct SilcServerListStruct *prev;
 };
 
 /* 
-   SILC Client list object.
+   SILC Client entry object.
 
-   This list holds information about connected clients ie. users in the SILC
-   network. The contents of this list is depended on whether we are normal 
+   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 
    server or router server and whether the list is a local or global list.
 
-   This list is defined as follows:
+   This entry is defined as follows:
 
    Server type   List type      Contents
    =======================================================================
@@ -164,7 +171,24 @@ struct SilcServerListStruct {
        Client's mode.  Client maybe for example server operator or
        router operator (SILC operator).
 
-   SilcServerList *router
+   long last_receive
+
+       Time of last time data was received from the client. This is
+       result of normal time().
+
+   long last_command
+
+       Time of last time client executed command. We are strict and will
+       not allow any command to be exeucted more than once in about
+       2 seconds. This is result of normal time().
+
+   int registered
+
+       Boolean value to indicate whether this client has registered itself
+       to the server. After KE and authentication protocols has been
+       successfully completed will client become registered.
+
+   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 
@@ -175,13 +199,11 @@ struct SilcServerListStruct {
        The actual session key established by key exchange protcol between
        connecting parties. This is used for both encryption and decryption.
 
-   SilcPKCS public_key
+   SilcPKCS pkcs
 
-       Public key of the client. This maybe NULL.
+       PKCS of the client. This maybe NULL.
 
    SilcHmac hmac
-   unsigned char *hmac_key
-   unsigned int hmac_key_len
 
        MAC key used to compute MAC's for packets. 
 
@@ -193,64 +215,68 @@ struct SilcServerListStruct {
        list.
 
 */
-struct SilcClientListStruct {
+struct SilcClientEntryStruct {
   char *nickname;
   char *username;
   char *userinfo;
   SilcClientID *id;
   int mode;
 
+  /* Time of last accesses of the client */
+  long last_receive;
+  long last_command;
+
+  /* TRUE when client is registered to server */
+  int registered;
+
   /* Pointer to the router */
-  SilcServerList *router;
+  SilcServerEntry router;
 
-  /* Pointers to channels this client has joined */
-  SilcChannelList **channel;
+  /* List of channels client has joined to */
+  SilcChannelEntry *channel;
   unsigned int channel_count;
 
   /* Keys */
   SilcCipher send_key;
   SilcCipher receive_key;
-  SilcPKCS public_key;
+  SilcPKCS pkcs;
   SilcHmac hmac;
-  unsigned char *hmac_key;
-  unsigned int hmac_key_len;
+  SilcPublicKey public_key;
 
   /* Connection data */
   void *connection;
-
-  struct SilcClientListStruct *next;
-  struct SilcClientListStruct *prev;
 };
 
 /* 
-   SILC Channel Client list structure.
+   SILC Channel Client entry structure.
 
-   This list used only by the SilcChannelList object and it holds information 
-   about current clients (ie. users) on channel. Following short description 
-   of the fields:
+   This entry used only by the SilcChannelEntry object and it holds
+   information about current clients (ie. users) on channel. Following
+   short description  of the fields:
 
-   SilcClientList client
+   SilcClientEntry client
 
        Pointer to the client list. This is the client currently on channel.
 
-   int mode
+   unsigned int mode
 
        Client's current mode on the channel.
 
 */
-typedef struct SilcChannelClientListStruct {
-  SilcClientList *client;
-  int mode;
-} SilcChannelClientList;
+typedef struct SilcChannelClientEntryStruct {
+  SilcClientEntry client;
+  unsigned int mode;
+  struct SilcChannelClientEntryStruct *next;
+} *SilcChannelClientEntry;
 
 /* 
-   SILC Channel list object.
+   SILC Channel entry object.
 
-   This list holds information about channels in SILC network. The contents 
-   of this list 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 list is defined as follows:
+   This entry is defined as follows:
 
    Server type   List type      Contents
    =======================================================================
@@ -265,9 +291,10 @@ typedef struct SilcChannelClientListStruct {
 
        Logical name of the channel.
 
-   int mode
+   unsigned int mode
 
-       Current mode of the channel.
+       Current mode of the channel.  See lib/silccore/silcchannel.h for
+       all modes.
 
    SilcChannelID *id
 
@@ -288,40 +315,61 @@ typedef struct SilcChannelClientListStruct {
 
        Current topic of the channel.
 
-   SilcServerList *router
+   char *cipher
+
+       Default cipher of the channel. If this is NULL then server picks
+       the cipher to be used. This can be set at SILC_COMMAND_JOIN.
+
+   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 
        to this channel.
 
-   SilcCipher send_key
+   SilcCipher channel_key
 
+       The key of the channel (the cipher actually).
 
-   SilcCipher receive_key
+   unsigned char *key
+   unsigned int key_len
+
+       Raw key data of the channel key.
+
+   unsigned char iv[SILC_CIPHER_MAX_IV_SIZE]
+
+       Current initial vector. Initial vector is received always along
+       with the channel packet. By default this is filled with NULL.
 
 */
-struct SilcChannelListStruct {
+struct SilcChannelEntryStruct {
   char *channel_name;
-  int mode;
+  unsigned int mode;
   SilcChannelID *id;
   int global_users;
   char *topic;
+  char *cipher;
+
+  /* Data that is related to different channel modes. */
+  struct {
+    unsigned int user_limit;
+    unsigned char *passphrase;
+    unsigned char *ban_list;
+    unsigned char *invite_list;
+    unsigned char *cipher;
+    unsigned int key_len;
+  } mode_data;
 
   /* List of users on channel */
-  SilcChannelClientList *user_list;
-  unsigned int user_list_count;
+  SilcList user_list;
 
   /* Pointer to the router */
-  SilcServerList *router;
+  SilcServerEntry router;
 
   /* Channel keys */
   SilcCipher channel_key;
   unsigned char *key;
   unsigned int key_len;
   unsigned char iv[SILC_CIPHER_MAX_IV_SIZE];
-
-  struct SilcChannelListStruct *next;
-  struct SilcChannelListStruct *prev;
 };
 
 /* 
@@ -329,22 +377,22 @@ struct SilcChannelListStruct {
 
    As for remainder these lists are defined as follows:
 
-   List        Server type   List type      Contents
+   Entry list (cache)  Server type   List type      Contents
    =======================================================================
-   servers     server        local list     Server itself
-   servers     server        global list    NULL
-   servers     router        local list     All servers in cell
-   servers     router        global list    All servers in SILC
+   servers             server        local list     Server itself
+   servers             server        global list    NULL
+   servers             router        local list     All servers in cell
+   servers             router        global list    All servers in SILC
 
-   clients     server        local list     All clients in server
-   clients     server        global list    NULL
-   clients     router        local list     All clients in cell
-   clients     router        global list    All clients in SILC
+   clients             server        local list     All clients in server
+   clients             server        global list    NULL
+   clients             router        local list     All clients in cell
+   clients             router        global list    All clients in SILC
 
-   channels    server        local list     All channels in server
-   channels    server        global list    NULL
-   channels    router        local list     All channels in cell
-   channels    router        global list    All channels in SILC
+   channels            server        local list     All channels in server
+   channels            server        global list    NULL
+   channels            router        local list     All channels in cell
+   channels            router        global list    All channels in SILC
 
    As seen on the list normal server never defines a global list. This is
    because of normal server don't know anything about anything global data,
@@ -352,77 +400,87 @@ struct SilcChannelListStruct {
    other hand, always define local and global lists because routers really
    know all the relevant data in the SILC network.
 
-*/
-typedef struct SilcIDListStruct {
-  SilcServerList *servers;
-  SilcClientList *clients;
-  SilcChannelList *channels;
+   This object is used as local and global list by the server/router.
+   Above table shows how this is defined on different conditions.
 
-  /* ID Caches. Caches are used to perform fast search on the ID's. */
-  SilcIDCache *server_cache[96];
-  unsigned int server_cache_count[96];
-  SilcIDCache *client_cache[96];
-  unsigned int client_cache_count[96];
-  SilcIDCache *channel_cache[96];
-  unsigned int channel_cache_count[96];
-} SilcIDListObject;
+   This object holds pointers to the ID cache system. Every ID cache entry
+   has a specific context pointer to allocated entry (server, client or
+   channel entry).
 
-typedef SilcIDListObject *SilcIDList;
+*/
+typedef struct SilcIDListStruct {
+  SilcIDCache servers;
+  SilcIDCache clients;
+  SilcIDCache channels;
+} *SilcIDList;
 
 /*
-   Temporary ID List object.
+   Temporary ID Entry object.
 
-   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.
+   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.
 
-   This is not in any list. This is always individually allocated
-   and used as such.
+   This is not in any list. This is always individually allocated and
+   used as such.
 
 */
 typedef struct {
   SilcCipher send_key;
   SilcCipher receive_key;
   SilcPKCS pkcs;
+  SilcPublicKey public_key;
 
   SilcHmac hmac;
   unsigned char *hmac_key;
   unsigned int hmac_key_len;
 
   /* SilcComp comp */
-} SilcIDListUnknown;
+} *SilcUnknownEntry;
 
 /* Prototypes */
-void silc_idlist_add_server(SilcServerList **list, 
-                           char *server_name, int server_type,
-                           SilcServerID *id, SilcServerList *router,
-                           SilcCipher send_key, SilcCipher receive_key,
-                           SilcPKCS public_key, SilcHmac hmac, 
-                           SilcServerList **new_idlist);
-void silc_idlist_add_client(SilcClientList **list, char *nickname,
-                           char *username, char *userinfo,
-                           SilcClientID *id, SilcServerList *router,
-                           SilcCipher send_key, SilcCipher receive_key,
-                           SilcPKCS public_key, SilcHmac hmac, 
-                           SilcClientList **new_idlist);
-void silc_idlist_del_client(SilcClientList **list, SilcClientList *entry);
-SilcClientList *
-silc_idlist_find_client_by_nickname(SilcClientList *list,
-                                   char *nickname,
+SilcServerEntry 
+silc_idlist_add_server(SilcIDList id_list, 
+                      char *server_name, int server_type,
+                      SilcServerID *id, SilcServerEntry router,
+                      SilcCipher send_key, SilcCipher receive_key,
+                      SilcPKCS pkcs, SilcHmac hmac, 
+                      SilcPublicKey public_key, void *connection);
+SilcServerEntry
+silc_idlist_find_server_by_id(SilcIDList id_list, SilcServerID *id);
+SilcServerEntry
+silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id,
+                             SilcServerID *new_id);
+SilcClientEntry
+silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username,
+                      char *userinfo, SilcClientID *id, 
+                      SilcServerEntry router,
+                      SilcCipher send_key, SilcCipher receive_key,
+                      SilcPKCS pkcs, SilcHmac hmac, 
+                      SilcPublicKey public_key, void *connection);
+void silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry);
+SilcClientEntry *
+silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname,
+                                   char *server, unsigned int *clients_count);
+SilcClientEntry
+silc_idlist_find_client_by_nickname(SilcIDList id_list, char *nickname,
                                    char *server);
-SilcClientList *
-silc_idlist_find_client_by_hash(SilcClientList *list,
-                               char *nickname, SilcHash hash);
-SilcClientList *
-silc_idlist_find_client_by_id(SilcClientList *list, SilcClientID *id);
-void silc_idlist_add_channel(SilcChannelList **list, 
-                            char *channel_name, int mode,
-                            SilcChannelID *id, SilcServerList *router,
-                            SilcCipher channel_key,
-                            SilcChannelList **new_idlist);
-SilcChannelList *
-silc_idlist_find_channel_by_id(SilcChannelList *list, SilcChannelID *id);
-void silc_idlist_del_channel(SilcChannelList **list, SilcChannelList *entry);
+SilcClientEntry
+silc_idlist_find_client_by_hash(SilcIDList id_list, char *nickname,
+                               SilcHash md5hash);
+SilcClientEntry
+silc_idlist_find_client_by_id(SilcIDList id_list, SilcClientID *id);
+SilcClientEntry
+silc_idlist_replace_client_id(SilcIDList id_list, SilcClientID *old_id,
+                             SilcClientID *new_id);
+SilcChannelEntry
+silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode,
+                       SilcChannelID *id, SilcServerEntry router,
+                       SilcCipher channel_key);
+void silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry);
+SilcChannelEntry
+silc_idlist_find_channel_by_name(SilcIDList id_list, char *name);
+SilcChannelEntry
+silc_idlist_find_channel_by_id(SilcIDList id_list, SilcChannelID *id);
 
 #endif
index 60d491705041f334956f622a56042bcf5fedee93..b8cb0090fd7fc50774b5da577f0319edbc5a3252 100644 (file)
 /*
  * Server side of the protocols.
  */
-/*
- * $Id$
- * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:56  priikone
- *     Importet from internal CVS/Added Log headers.
- *
- *
- */
+/* $Id$ */
 
 #include "serverincludes.h"
 #include "server_internal.h"
 
 SILC_TASK_CALLBACK(silc_server_protocol_connection_auth);
-SILC_TASK_CALLBACK(silc_server_protocol_channel_auth);
 SILC_TASK_CALLBACK(silc_server_protocol_key_exchange);
 
-/* SILC client protocol list */
-const SilcProtocolObject silc_protocol_list[] =
-{
-  { SILC_PROTOCOL_SERVER_CONNECTION_AUTH, 
-    silc_server_protocol_connection_auth },
-  { SILC_PROTOCOL_SERVER_CHANNEL_AUTH, 
-    silc_server_protocol_channel_auth },
-  { SILC_PROTOCOL_SERVER_KEY_EXCHANGE, 
-    silc_server_protocol_key_exchange },
-
-  { SILC_PROTOCOL_SERVER_NONE, NULL },
-};
+extern char *silc_version_string;
 
 /*
  * Key Exhange protocol functions
@@ -81,7 +62,7 @@ static void silc_server_protocol_ke_set_keys(SilcSKE ske,
                                             SilcHash hash,
                                             int is_responder)
 {
-  SilcIDListUnknown *conn_data;
+  SilcUnknownEntry conn_data;
   SilcHash nhash;
 
   SILC_LOG_DEBUG(("Setting new key into use"));
@@ -119,6 +100,7 @@ static void silc_server_protocol_ke_set_keys(SilcSKE ske,
      If yes, we need to change KE protocol to get the initiators
      public key. */
   silc_pkcs_alloc(pkcs->pkcs->name, &conn_data->pkcs);
+  conn_data->public_key = silc_pkcs_public_key_alloc(XXX);
   silc_pkcs_set_public_key(conn_data->pkcs, ske->ke2_payload->pk_data, 
                           ske->ke2_payload->pk_len);
 #endif
@@ -126,14 +108,19 @@ static void silc_server_protocol_ke_set_keys(SilcSKE ske,
   /* Save HMAC key to be used in the communication. */
   silc_hash_alloc(hash->hash->name, &nhash);
   silc_hmac_alloc(nhash, &conn_data->hmac);
-  conn_data->hmac_key_len = keymat->hmac_key_len;
-  conn_data->hmac_key = silc_calloc(conn_data->hmac_key_len,
-                                   sizeof(unsigned char));
-  memcpy(conn_data->hmac_key, keymat->hmac_key, keymat->hmac_key_len);
+  silc_hmac_set_key(conn_data->hmac, keymat->hmac_key, keymat->hmac_key_len);
 
   sock->user_data = (void *)conn_data;
 }
 
+/* XXX TODO */
+
+SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version,
+                                    unsigned int len)
+{
+  return SILC_SKE_STATUS_OK;
+}
+
 /* Performs key exchange protocol. This is used for both initiator
    and responder key exchange. This is performed always when accepting
    new connection to the server. This may be called recursively. */
@@ -164,17 +151,21 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
       /* Allocate Key Exchange object */
       ske = silc_ske_alloc();
       ctx->ske = ske;
+      ske->rng = server->rng;
       
       if (ctx->responder == TRUE) {
        /* Start the key exchange by processing the received security
           properties packet from initiator. */
        status = silc_ske_responder_start(ske, ctx->rng, ctx->sock,
+                                         silc_version_string,
                                          ctx->packet, NULL, NULL);
       } else {
        SilcSKEStartPayload *start_payload;
 
        /* Assemble security properties. */
-       silc_ske_assemble_security_properties(ske, &start_payload);
+       silc_ske_assemble_security_properties(ske, SILC_SKE_SP_FLAG_NONE, 
+                                             silc_version_string,
+                                             &start_payload);
 
        /* Start the key exchange by sending our security properties
           to the remote end. */
@@ -258,6 +249,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
           Key Exhange 1 Payload to the responder. */
        status = 
          silc_ske_initiator_phase_2(ctx->ske,
+                                    server->public_key,
                                     silc_server_protocol_ke_send_packet,
                                     context);
       }
@@ -285,34 +277,20 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
        * Finish protocol
        */
       if (ctx->responder == TRUE) {
-       unsigned char *pk, *prv;
-       unsigned int pk_len, prv_len;
-
-       /* Get our public key to be sent to the initiator */
-       pk = silc_pkcs_get_public_key(server->public_key, &pk_len);
-
-       /* Get out private key to sign some data. */
-       prv = silc_pkcs_get_private_key(server->public_key, &prv_len);
-
        /* 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, 
-                                   pk, pk_len, prv, prv_len,
+                                   server->public_key, server->private_key,
                                    SILC_SKE_PK_TYPE_SILC,
                                    silc_server_protocol_ke_send_packet,
                                    context);
-
-       memset(pk, 0, pk_len);
-       memset(prv, 0, prv_len);
-       silc_free(pk);
-       silc_free(prv);
       } else {
        /* Finish the protocol. This verifies the Key Exchange 2 payload
           sent by responder. */
        status = 
          silc_ske_initiator_finish(ctx->ske,
-                                   ctx->packet, NULL, NULL);
+                                   ctx->packet, NULL, NULL, NULL, NULL);
       }
 
       if (status != SILC_SKE_STATUS_OK) {
@@ -335,6 +313,7 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
       protocol->state = SILC_PROTOCOL_STATE_END;
     }
     break;
+
   case SILC_PROTOCOL_STATE_END:
     {
       /* 
@@ -371,11 +350,17 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
        silc_protocol_free(protocol);
     }
     break;
+
   case SILC_PROTOCOL_STATE_ERROR:
     /*
      * Error occured
      */
 
+    /* Send abort notification */
+    silc_ske_abort(ctx->ske, ctx->ske->status, 
+                  silc_server_protocol_ke_send_packet,
+                  context);
+
     /* 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. */
@@ -388,6 +373,25 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
     else
       silc_protocol_free(protocol);
     break;
+
+  case SILC_PROTOCOL_STATE_FAILURE:
+    /*
+     * We have received failure from remote
+     */
+
+    /* 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_task_unregister(server->timeout_queue, ctx->timeout_task);
+
+    /* On error the final callback is always called. */
+    if (protocol->final_callback)
+      protocol->execute_final(server->timeout_queue, 0, protocol, fd);
+    else
+      silc_protocol_free(protocol);
+    break;
+
   case SILC_PROTOCOL_STATE_UNKNOWN:
     break;
   }
@@ -397,6 +401,72 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
  * Connection Authentication protocol functions
  */
 
+/* XXX move these to somehwere else */
+
+int silc_server_password_authentication(SilcServer server, char *auth1, 
+                                       char *auth2)
+{
+  if (!auth1 || !auth2)
+    return FALSE;
+
+  if (!memcmp(auth1, auth2, strlen(auth1)))
+    return TRUE;
+
+  return FALSE;
+}
+
+int silc_server_public_key_authentication(SilcServer server,
+                                         char *pkfile,
+                                         unsigned char *sign,
+                                         unsigned int sign_len,
+                                         SilcSKE ske)
+{
+  SilcPublicKey pub_key;
+  SilcPKCS pkcs;
+  int len;
+  SilcBuffer auth;
+
+  if (!pkfile || !sign)
+    return FALSE;
+
+  /* Load public key from file */
+  if (!silc_pkcs_load_public_key(pkfile, &pub_key, SILC_PKCS_FILE_PEM))
+    if (!silc_pkcs_load_public_key(pkfile, &pub_key, SILC_PKCS_FILE_BIN))
+      return FALSE;
+
+  silc_pkcs_alloc(pub_key->name, &pkcs);
+  if (!silc_pkcs_public_key_set(pkcs, pub_key)) {
+    silc_pkcs_free(pkcs);
+    return FALSE;
+  }
+
+  /* Make the authentication data. Protocol says it is HASH plus
+     KE Start Payload. */
+  len = ske->hash_len + ske->start_payload_copy->len;
+  auth = silc_buffer_alloc(len);
+  silc_buffer_pull_tail(auth, len);
+  silc_buffer_format(auth,
+                    SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
+                    SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
+                                         ske->start_payload_copy->len),
+                    SILC_STR_END);
+
+  /* Verify signature */
+  if (pkcs->pkcs->verify(pkcs->context, sign, sign_len,
+                        auth->data, auth->len))
+    {
+      silc_pkcs_free(pkcs);
+      silc_pkcs_public_key_free(pub_key);
+      silc_buffer_free(auth);
+      return TRUE;
+    }
+
+  silc_pkcs_free(pkcs);
+  silc_pkcs_public_key_free(pub_key);
+  silc_buffer_free(auth);
+  return FALSE;
+}
+
 /* Performs connection authentication protocol. If responder, we 
    authenticate the remote data received. If initiator, we will send
    authentication data to the remote end. */
@@ -426,10 +496,15 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
        /*
         * We are receiving party
         */
+       int ret;
        unsigned short payload_len;
        unsigned short conn_type;
        unsigned char *auth_data;
 
+       SILC_LOG_INFO(("Performing authentication protocol for %s",
+                      ctx->sock->hostname ? ctx->sock->hostname :
+                      ctx->sock->ip));
+
        /* Parse the received authentication data packet. The received
           payload is Connection Auth Payload. */
        silc_buffer_unformat(ctx->packet,
@@ -498,13 +573,14 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
            case SILC_PROTOCOL_CONN_AUTH_PASSWORD:
              /* Password authentication */
              SILC_LOG_DEBUG(("Password authentication"));
-             if (auth_data) {
-               if (!memcmp(client->auth_data, auth_data, strlen(auth_data))) {
-                 memset(auth_data, 0, payload_len);
-                 silc_free(auth_data);
-                 auth_data = NULL;
-                 break;
-               }
+             ret = silc_server_password_authentication(server, auth_data,
+                                                       client->auth_data);
+
+             if (ret) {
+               memset(auth_data, 0, payload_len);
+               silc_free(auth_data);
+               auth_data = NULL;
+               break;
              }
 
              /* Authentication failed */
@@ -519,37 +595,17 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
            case SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY:
              /* Public key authentication */
              SILC_LOG_DEBUG(("Public key authentication"));
-             if (auth_data) {
-               SilcIDListUnknown *conn_data;
-               SilcPKCS pkcs;
-               
-               conn_data = (SilcIDListUnknown *)ctx->sock->user_data;
-               
-               /* Load public key from file */
-               if (silc_pkcs_load_public_key(client->auth_data,
-                                             &pkcs) == FALSE) {
-                 
-                 /* Authentication failed */
-                 SILC_LOG_ERROR(("Authentication failed "
-                                 "- could not read public key file"));
-                 memset(auth_data, 0, payload_len);
-                 silc_free(auth_data);
-                 auth_data = NULL;
-                 protocol->state = SILC_PROTOCOL_STATE_ERROR;
-                 protocol->execute(server->timeout_queue, 0, 
-                                   protocol, fd, 0, 300000);
-                 return;
-               }
-               
-               /* Verify hash value HASH from KE protocol */
-               if (pkcs->pkcs->verify(pkcs->context,
-                                      auth_data, payload_len,
-                                      ctx->ske->hash, 
-                                      ctx->ske->hash_len)
-                   == TRUE) {
-                 silc_pkcs_free(pkcs);
-                 break;
-               }
+             ret = silc_server_public_key_authentication(server, 
+                                                         client->auth_data,
+                                                         auth_data,
+                                                         payload_len, 
+                                                         ctx->ske);
+                                                         
+             if (ret) {
+               memset(auth_data, 0, payload_len);
+               silc_free(auth_data);
+               auth_data = NULL;
+               break;
              }
 
              SILC_LOG_ERROR(("Authentication failed"));
@@ -596,13 +652,14 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
            case SILC_PROTOCOL_CONN_AUTH_PASSWORD:
              /* Password authentication */
              SILC_LOG_DEBUG(("Password authentication"));
-             if (auth_data) {
-               if (!memcmp(serv->auth_data, auth_data, strlen(auth_data))) {
-                 memset(auth_data, 0, payload_len);
-                 silc_free(auth_data);
-                 auth_data = NULL;
-                 break;
-               }
+             ret = silc_server_password_authentication(server, auth_data,
+                                                       serv->auth_data);
+
+             if (ret) {
+               memset(auth_data, 0, payload_len);
+               silc_free(auth_data);
+               auth_data = NULL;
+               break;
              }
              
              /* Authentication failed */
@@ -617,37 +674,17 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
            case SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY:
              /* Public key authentication */
              SILC_LOG_DEBUG(("Public key authentication"));
-             if (auth_data) {
-               SilcIDListUnknown *conn_data;
-               SilcPKCS pkcs;
-               
-               conn_data = (SilcIDListUnknown *)ctx->sock->user_data;
-               
-               /* Load public key from file */
-               if (silc_pkcs_load_public_key(serv->auth_data,
-                                             &pkcs) == FALSE) {
-                 
-                 /* Authentication failed */
-                 SILC_LOG_ERROR(("Authentication failed "
-                                 "- could not read public key file"));
-                 memset(auth_data, 0, payload_len);
-                 silc_free(auth_data);
-                 auth_data = NULL;
-                 protocol->state = SILC_PROTOCOL_STATE_ERROR;
-                 protocol->execute(server->timeout_queue, 0, 
-                                   protocol, fd, 0, 300000);
-                 return;
-               }
-               
-               /* Verify hash value HASH from KE protocol */
-               if (pkcs->pkcs->verify(pkcs->context,
-                                      auth_data, payload_len,
-                                      ctx->ske->hash, 
-                                      ctx->ske->hash_len)
-                   == TRUE) {
-                 silc_pkcs_free(pkcs);
-                 break;
-               }
+             ret = silc_server_public_key_authentication(server, 
+                                                         serv->auth_data,
+                                                         auth_data,
+                                                         payload_len, 
+                                                         ctx->ske);
+                                                         
+             if (ret) {
+               memset(auth_data, 0, payload_len);
+               silc_free(auth_data);
+               auth_data = NULL;
+               break;
              }
 
              SILC_LOG_ERROR(("Authentication failed"));
@@ -694,13 +731,14 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
            case SILC_PROTOCOL_CONN_AUTH_PASSWORD:
              /* Password authentication */
              SILC_LOG_DEBUG(("Password authentication"));
-             if (auth_data) {
-               if (!memcmp(serv->auth_data, auth_data, strlen(auth_data))) {
-                 memset(auth_data, 0, payload_len);
-                 silc_free(auth_data);
-                 auth_data = NULL;
-                 break;
-               }
+             ret = silc_server_password_authentication(server, auth_data,
+                                                       serv->auth_data);
+
+             if (ret) {
+               memset(auth_data, 0, payload_len);
+               silc_free(auth_data);
+               auth_data = NULL;
+               break;
              }
              
              /* Authentication failed */
@@ -715,37 +753,17 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
            case SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY:
              /* Public key authentication */
              SILC_LOG_DEBUG(("Public key authentication"));
-             if (auth_data) {
-               SilcIDListUnknown *conn_data;
-               SilcPKCS pkcs;
-               
-               conn_data = (SilcIDListUnknown *)ctx->sock->user_data;
-               
-               /* Load public key from file */
-               if (silc_pkcs_load_public_key(serv->auth_data,
-                                             &pkcs) == FALSE) {
-                 
-                 /* Authentication failed */
-                 SILC_LOG_ERROR(("Authentication failed "
-                                 "- could not read public key file"));
-                 memset(auth_data, 0, payload_len);
-                 silc_free(auth_data);
-                 auth_data = NULL;
-                 protocol->state = SILC_PROTOCOL_STATE_ERROR;
-                 protocol->execute(server->timeout_queue, 0, 
-                                   protocol, fd, 0, 300000);
-                 return;
-               }
-               
-               /* Verify hash value HASH from KE protocol */
-               if (pkcs->pkcs->verify(pkcs->context,
-                                      auth_data, payload_len,
-                                      ctx->ske->hash, 
-                                      ctx->ske->hash_len)
-                   == TRUE) {
-                 silc_pkcs_free(pkcs);
-                 break;
-               }
+             ret = silc_server_public_key_authentication(server, 
+                                                         serv->auth_data,
+                                                         auth_data,
+                                                         payload_len, 
+                                                         ctx->ske);
+                                                         
+             if (ret) {
+               memset(auth_data, 0, payload_len);
+               silc_free(auth_data);
+               auth_data = NULL;
+               break;
              }
 
              SILC_LOG_ERROR(("Authentication failed"));
@@ -851,10 +869,13 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
       /* 
        * End protocol
        */
+      unsigned char ok[4];
 
-      /* Succesfully authenticated */
-      silc_server_packet_send(server, ctx->sock, SILC_PACKET_SUCCESS, 
-                             0, NULL, 0, TRUE);
+      SILC_PUT32_MSB(SILC_CONN_AUTH_OK, ok);
+
+      /* Authentication failed */
+      silc_server_packet_send(server, ctx->sock, SILC_PACKET_FAILURE,
+                             0, ok, 4, TRUE);
 
       /* Unregister the timeout task since the protocol has ended. 
         This was the timeout task to be executed if the protocol is
@@ -872,12 +893,15 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
   case SILC_PROTOCOL_STATE_ERROR:
     {
       /*
-       * Error 
+       * Error. Send notify to remote.
        */
+      unsigned char error[4];
+
+      SILC_PUT32_MSB(SILC_CONN_AUTH_FAILED, error);
 
       /* Authentication failed */
       silc_server_packet_send(server, ctx->sock, SILC_PACKET_FAILURE,
-                             0, NULL, 0, TRUE);
+                             0, error, 4, TRUE);
 
       /* Unregister the timeout task since the protocol has ended. 
         This was the timeout task to be executed if the protocol is
@@ -892,11 +916,46 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
        silc_protocol_free(protocol);
     }
     break;
+
+  case SILC_PROTOCOL_STATE_FAILURE:
+    /*
+     * We have received failure from remote
+     */
+
+    /* 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_task_unregister(server->timeout_queue, ctx->timeout_task);
+
+    /* On error the final callback is always called. */
+    if (protocol->final_callback)
+      protocol->execute_final(server->timeout_queue, 0, protocol, fd);
+    else
+      silc_protocol_free(protocol);
+    break;
+
   case SILC_PROTOCOL_STATE_UNKNOWN:
     break;
   }
 }
 
-SILC_TASK_CALLBACK(silc_server_protocol_channel_auth)
+/* Registers protocols used in server. */
+
+void silc_server_protocols_register(void)
+{
+  silc_protocol_register(SILC_PROTOCOL_SERVER_CONNECTION_AUTH,
+                        silc_server_protocol_connection_auth);
+  silc_protocol_register(SILC_PROTOCOL_SERVER_KEY_EXCHANGE,
+                        silc_server_protocol_key_exchange);
+}
+
+/* Unregisters protocols */
+
+void silc_server_protocols_unregister(void)
 {
+  silc_protocol_unregister(SILC_PROTOCOL_SERVER_CONNECTION_AUTH,
+                          silc_server_protocol_connection_auth);
+  silc_protocol_unregister(SILC_PROTOCOL_SERVER_KEY_EXCHANGE,
+                          silc_server_protocol_key_exchange);
 }
index b9505cf43f9118854034914fa109ec3bbe355a8a..67d76a638df0fe1ac618fde04afefdeaf3631337 100644 (file)
@@ -24,8 +24,7 @@
 /* SILC client protocol types */
 #define SILC_PROTOCOL_SERVER_NONE 0
 #define SILC_PROTOCOL_SERVER_CONNECTION_AUTH 1
-#define SILC_PROTOCOL_SERVER_CHANNEL_AUTH 2
-#define SILC_PROTOCOL_SERVER_KEY_EXCHANGE 3
+#define SILC_PROTOCOL_SERVER_KEY_EXCHANGE 2
 /* #define SILC_PROTOCOL_SERVER_MAX 255 */
 
 /* Internal context for Key Exchange protocol. */
@@ -79,5 +78,7 @@ typedef struct {
 } SilcServerConnAuthInternalContext;
 
 /* Prototypes */
+void silc_server_protocols_register(void);
+void silc_server_protocols_unregister(void);
 
 #endif
diff --git a/apps/silcd/pubkey.pub b/apps/silcd/pubkey.pub
deleted file mode 100644 (file)
index cf4ed9b..0000000
Binary files a/apps/silcd/pubkey.pub and /dev/null differ
index 43b60d380b639ce4de0f8cad10525a58d94eb641..5edd731512182d2c9a3a1a4d1d4bbf9f759b145d 100644 (file)
 /*
  * $Id$
  * $Log$
+ * Revision 1.4  2000/07/12 05:59:41  priikone
+ *     Major rewrite of ID Cache system. Support added for the new
+ *     ID cache system. Major rewrite of ID List stuff on server.  All
+ *     SilcXXXList's are now called SilcXXXEntry's and they are pointers
+ *     by default. A lot rewritten ID list functions.
+ *
+ * Revision 1.3  2000/07/05 06:14:01  priikone
+ *     Global costemic changes.
+ *
+ * Revision 1.2  2000/07/04 08:30:24  priikone
+ *     Added silc_server_get_route to return communication object
+ *     for fastest route.
+ *
  * Revision 1.1.1.1  2000/06/27 11:36:56  priikone
- *     Importet from internal CVS/Added Log headers.
+ *     Imported from internal CVS/Added Log headers.
  *
  *
  */
 
 #include "serverincludes.h"
+#include "server_internal.h"
 #include "route.h"
 
 /* Route cache hash table */
@@ -41,7 +55,7 @@ SilcServerRouteTable silc_route_cache[SILC_SERVER_ROUTE_SIZE];
    index value generated by silc_server_route_hash. */
 
 void silc_server_route_add(unsigned int index, unsigned int dest,
-                          SilcServerList *router)
+                          SilcServerEntry router)
 {
   silc_route_cache[index].dest = dest;
   silc_route_cache[index].router = router;
@@ -50,7 +64,7 @@ void silc_server_route_add(unsigned int index, unsigned int dest,
 /* Checksk whether destination has a specific router. Returns the
    router data if found, NULL otherwise. */
 
-SilcServerList *silc_server_route_check(unsigned int dest, 
+SilcServerEntry silc_server_route_check(unsigned int dest, 
                                        unsigned short port)
 {
   unsigned int index;
@@ -63,3 +77,41 @@ SilcServerList *silc_server_route_check(unsigned int dest,
 
   return NULL;
 }
+
+/* Returns the connection object for the fastest route for the given ID.
+   If we are normal server then this just returns our primary route. If
+   we are router we will do route lookup. */
+
+SilcSocketConnection silc_server_get_route(SilcServer server, void *id,
+                                          SilcIdType id_type)
+{
+  unsigned int dest = 0;
+  unsigned short port = 0;
+  SilcServerEntry router = NULL;
+
+  if (server->server_type == SILC_SERVER)
+    return (SilcSocketConnection)server->id_entry->router->connection;
+  
+  switch(id_type) {
+  case SILC_ID_CLIENT:
+    dest = ((SilcClientID *)id)->ip.s_addr;
+    port = server->id->port;
+    break;
+  case SILC_ID_SERVER:
+    dest = ((SilcServerID *)id)->ip.s_addr;
+    port = ((SilcServerID *)id)->port;
+    break;
+  case SILC_ID_CHANNEL:
+    dest = ((SilcChannelID *)id)->ip.s_addr;
+    port = ((SilcChannelID *)id)->port;
+    break;
+  default:
+    return NULL;
+  }
+
+  router = silc_server_route_check(dest, port);
+  if (!router)
+    return (SilcSocketConnection)server->id_entry->router->connection;
+
+  return (SilcSocketConnection)router->connection;
+}
index aec76e69ff7201e0de735fa3d2bb74312d971a6b..b04118d798b681f8c186482c20e3ce250046a352 100644 (file)
        Destination IPv4 address.  Can be used to quickly check whether
        the found route entry is what the caller wanted.
 
-   SilcServerList *router
+   SilcServerEntry router
 
        Pointer to the router specific data.
 
 */
 typedef struct {
   unsigned int dest;
-  SilcServerList *router;
+  SilcServerEntry router;
 } SilcServerRouteTable;
 
 /* Route cache hash table */
@@ -70,8 +70,10 @@ unsigned int silc_server_route_hash(unsigned int addr,
 
 /* Prototypes */
 void silc_server_route_add(unsigned int index, unsigned int dest,
-                          SilcServerList *router);
-SilcServerList *silc_server_route_check(unsigned int dest, 
+                          SilcServerEntry router);
+SilcServerEntry silc_server_route_check(unsigned int dest, 
                                        unsigned short port);
+SilcSocketConnection silc_server_get_route(SilcServer server, void *id,
+                                          SilcIdType id_type);
 
 #endif
index 636b428fdeb2ff2c698d0e4904be130d5b5e9e7d..3611f4293bb669032be1fcf6f3b2feab5c51dc31 100644 (file)
  * servicing the SILC connections. This is also a SILC router as a router 
  * is also normal server.
  */
-/*
- * $Id$
- * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:56  priikone
- *     Importet from internal CVS/Added Log headers.
- *
- *
- */
+/* $Id$ */
 
 #include "serverincludes.h"
 #include "server_internal.h"
@@ -42,25 +35,10 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection);
 SILC_TASK_CALLBACK(silc_server_accept_new_connection_second);
 SILC_TASK_CALLBACK(silc_server_accept_new_connection_final);
 SILC_TASK_CALLBACK(silc_server_packet_process);
-SILC_TASK_CALLBACK(silc_server_packet_parse);
+SILC_TASK_CALLBACK(silc_server_packet_parse_real);
 SILC_TASK_CALLBACK(silc_server_timeout_remote);
 
-/* XXX */
-void silc_server_packet_parse_type(SilcServer server, 
-                                  SilcSocketConnection sock,
-                                  SilcPacketContext *packet);
-
-static int silc_server_packet_check_mac(SilcServer server,
-                                       SilcSocketConnection sock,
-                                       SilcBuffer buffer);
-static int silc_server_packet_decrypt_rest(SilcServer server, 
-                                          SilcSocketConnection sock,
-                                          SilcBuffer buffer);
-static int silc_server_packet_decrypt_rest_special(SilcServer server, 
-                                                  SilcSocketConnection sock,
-                                                  SilcBuffer buffer);
-
-extern char server_version[];
+extern char *server_version;
 
 /* Allocates a new SILC server object. This has to be done before the server
    can be used. After allocation one must call silc_server_init to initialize
@@ -69,27 +47,17 @@ extern char server_version[];
 
 int silc_server_alloc(SilcServer *new_server)
 {
+  SilcServer server;
+
   SILC_LOG_DEBUG(("Allocating new server object"));
 
-  *new_server = silc_calloc(1, sizeof(**new_server));
-  if (*new_server == NULL) {
-    SILC_LOG_ERROR(("Could not allocate new server object"));
-    return FALSE;
-  }
+  server = silc_calloc(1, sizeof(*server));
+  server->server_type = SILC_SERVER;
+  server->standalone = FALSE;
+  server->local_list = silc_calloc(1, sizeof(*server->local_list));
+  server->global_list = silc_calloc(1, sizeof(*server->global_list));
 
-  /* Set default values */
-  (*new_server)->server_name = NULL;
-  (*new_server)->server_type = SILC_SERVER;
-  (*new_server)->standalone = FALSE;
-  (*new_server)->id = NULL;
-  (*new_server)->io_queue = NULL;
-  (*new_server)->timeout_queue = NULL;
-  (*new_server)->local_list = silc_calloc(1, sizeof(SilcIDListObject));
-  (*new_server)->global_list = silc_calloc(1, sizeof(SilcIDListObject));
-  (*new_server)->rng = NULL;
-  (*new_server)->md5hash = NULL;
-  (*new_server)->sha1hash = NULL;
-  /*  (*new_server)->public_key = NULL;*/
+  *new_server = server;
 
   return TRUE;
 }
@@ -121,10 +89,9 @@ void silc_server_free(SilcServer server)
 
 int silc_server_init(SilcServer server)
 {
-  int *sock = NULL, sock_count, i;
+  int *sock = NULL, sock_count = 0, i;
   SilcServerID *id;
-  SilcServerList *id_entry;
-  SilcHashObject hash;
+  SilcServerEntry id_entry;
 
   SILC_LOG_DEBUG(("Initializing server"));
   assert(server);
@@ -156,36 +123,51 @@ int silc_server_init(SilcServer server)
     unsigned char *public_key;
     unsigned char *private_key;
     unsigned int pk_len, prv_len;
+    struct stat st;
 
-    if (silc_pkcs_alloc("rsa", &server->public_key) == FALSE) {
-      SILC_LOG_ERROR(("Could not create RSA key pair"));
-      goto err0;
-    }
+    if (stat("pubkey.pub", &st) < 0 && stat("privkey.prv", &st) < 0) {
 
-    if (server->public_key->pkcs->init(server->public_key->context, 
-                                      1024, server->rng) == FALSE) {
-      SILC_LOG_ERROR(("Could not generate RSA key pair"));
-      goto err0;
+      if (silc_pkcs_alloc("rsa", &server->pkcs) == FALSE) {
+       SILC_LOG_ERROR(("Could not create RSA key pair"));
+       goto err0;
+      }
+      
+      if (server->pkcs->pkcs->init(server->pkcs->context, 
+                                  1024, server->rng) == FALSE) {
+       SILC_LOG_ERROR(("Could not generate RSA key pair"));
+       goto err0;
+      }
+      
+      public_key = server->pkcs->pkcs->get_public_key(server->pkcs->context,
+                                                     &pk_len);
+      private_key = server->pkcs->pkcs->get_private_key(server->pkcs->context,
+                                                       &prv_len);
+      
+      SILC_LOG_HEXDUMP(("public key"), public_key, pk_len);
+      SILC_LOG_HEXDUMP(("private key"), private_key, prv_len);
+      
+      server->public_key = 
+       silc_pkcs_public_key_alloc("rsa", "UN=root, HN=dummy",
+                                  public_key, pk_len);
+      server->private_key = 
+       silc_pkcs_private_key_alloc("rsa", private_key, prv_len);
+      
+      /* XXX Save keys */
+      silc_pkcs_save_public_key("pubkey.pub", server->public_key,
+                               SILC_PKCS_FILE_PEM);
+      silc_pkcs_save_private_key("privkey.prv", server->private_key, NULL,
+                                SILC_PKCS_FILE_BIN);
+
+      memset(public_key, 0, pk_len);
+      memset(private_key, 0, prv_len);
+      silc_free(public_key);
+      silc_free(private_key);
+    } else {
+      silc_pkcs_load_public_key("pubkey.pub", &server->public_key,
+                               SILC_PKCS_FILE_PEM);
+      silc_pkcs_load_private_key("privkey.prv", &server->private_key,
+                                SILC_PKCS_FILE_BIN);
     }
-
-    public_key = 
-      server->public_key->pkcs->get_public_key(server->public_key->context,
-                                              &pk_len);
-    private_key = 
-      server->public_key->pkcs->get_private_key(server->public_key->context,
-                                               &prv_len);
-
-    SILC_LOG_HEXDUMP(("public key"), public_key, pk_len);
-    SILC_LOG_HEXDUMP(("private key"), private_key, prv_len);
-
-    /* XXX Save keys */
-    silc_pkcs_save_public_key(server->public_key, "pubkey.pub",
-                             public_key,  pk_len);
-
-    memset(public_key, 0, pk_len);
-    memset(private_key, 0, prv_len);
-    silc_free(public_key);
-    silc_free(private_key);
   }
 
   /* Create a listening server. Note that our server can listen on
@@ -206,6 +188,20 @@ int silc_server_init(SilcServer server)
     sock_count++;
   }
 
+  /* Initialize ID caches */
+  server->local_list->clients = silc_idcache_alloc(0);
+  server->local_list->servers = silc_idcache_alloc(0);
+  server->local_list->channels = silc_idcache_alloc(0);
+
+  /* XXX for now these are allocated for normal server as well as these
+     hold some global information that the server has fetched from its
+     router. For router these are used as they are supposed to be used
+     on router. The XXX can be remoevd later if this is the way we are
+     going to do this in the normal server as well. */
+  server->global_list->clients = silc_idcache_alloc(0);
+  server->global_list->servers = silc_idcache_alloc(0);
+  server->global_list->channels = silc_idcache_alloc(0);
+
   /* Allocate the entire socket list that is used in server. Eventually 
      all connections will have entry in this table (it is a table of 
      pointers to the actual object that is allocated individually 
@@ -234,13 +230,16 @@ int silc_server_init(SilcServer server)
        beacuse we haven't established a route yet. It will be done later. 
        For now, NULL is sent as router. This allocates new entry to
        the ID list. */
-    silc_idlist_add_server(&server->local_list->servers, 
-                          server->config->server_info->server_name,
-                          server->server_type, server->id, NULL,
-                          server->send_key, server->receive_key,
-                          NULL, NULL, &id_entry);
-    if (!id_entry)
+    id_entry = 
+      silc_idlist_add_server(server->local_list,
+                            server->config->server_info->server_name,
+                            server->server_type, server->id, NULL,
+                            server->send_key, server->receive_key,
+                            NULL, NULL, NULL, NULL);
+    if (!id_entry) {
+      SILC_LOG_ERROR(("Could not add ourselves to cache"));
       goto err0;
+    }
     
     /* Add ourselves also to the socket table. The entry allocated above
        is sent as argument for fast referencing in the future. */
@@ -274,9 +273,12 @@ int silc_server_init(SilcServer server)
     goto err1;
   }
 
+  /* Register protocols */
+  silc_server_protocols_register();
+
   /* Initialize the scheduler */
-  silc_schedule_init(server->io_queue, server->timeout_queue, 
-                    server->generic_queue, 
+  silc_schedule_init(&server->io_queue, &server->timeout_queue, 
+                    &server->generic_queue, 
                     SILC_SERVER_MAX_CONNECTIONS);
   
   /* Add the first task to the queue. This is task that is executed by
@@ -326,6 +328,8 @@ void silc_server_stop(SilcServer server)
   silc_schedule_stop();
   silc_schedule_uninit();
 
+  silc_server_protocols_unregister();
+
   SILC_LOG_DEBUG(("Server stopped"));
 }
 
@@ -398,13 +402,13 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router)
       newsocket->protocol = protocol;
       
       /* Register a timeout task that will be executed if the protocol
-        is not executed within 15 seconds. For now, this is a hard coded 
-        limit. After 15 secs the connection will be closed if the key 
+        is not executed within 60 seconds. For now, this is a hard coded 
+        limit. After 60 secs the connection will be closed if the key 
         exchange protocol has not been executed. */
       proto_ctx->timeout_task = 
        silc_task_register(server->timeout_queue, sock, 
                           silc_server_timeout_remote,
-                          context, 15, 0,
+                          context, 60, 0,
                           SILC_TASK_TIMEOUT,
                           SILC_TASK_PRI_LOW);
 
@@ -470,13 +474,13 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router)
       newsocket->protocol = protocol;
 
       /* Register a timeout task that will be executed if the protocol
-        is not executed within 15 seconds. For now, this is a hard coded 
-        limit. After 15 secs the connection will be closed if the key 
+        is not executed within 60 seconds. For now, this is a hard coded 
+        limit. After 60 secs the connection will be closed if the key 
         exchange protocol has not been executed. */
       proto_ctx->timeout_task = 
        silc_task_register(server->timeout_queue, sock, 
                           silc_server_timeout_remote,
-                          context, 15, 0,
+                          context, 60, 0,
                           SILC_TASK_TIMEOUT,
                           SILC_TASK_PRI_LOW);
 
@@ -619,8 +623,8 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
     (SilcServerConnAuthInternalContext *)protocol->context;
   SilcServer server = (SilcServer)ctx->server;
   SilcSocketConnection sock = ctx->sock;
-  SilcServerList *id_entry;
-  SilcIDListUnknown *conn_data;
+  SilcServerEntry id_entry;
+  SilcUnknownEntry conn_data;
   SilcBuffer packet;
   unsigned char *id_string;
 
@@ -681,20 +685,21 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_final)
 
   /* Add the connected router to local server list */
   server->standalone = FALSE;
-  conn_data = (SilcIDListUnknown *)sock->user_data;
-  silc_idlist_add_server(&server->local_list->servers, 
-                        sock->hostname ? sock->hostname : sock->ip,
-                        SILC_ROUTER, ctx->dest_id, NULL,
-                        conn_data->send_key, conn_data->receive_key,
-                        conn_data->pkcs, conn_data->hmac, &id_entry);
-
-  id_entry->hmac_key = conn_data->hmac_key;
-  id_entry->hmac_key_len = conn_data->hmac_key_len;
-  id_entry->connection = sock;
-  sock->user_data = (void *)id_entry;
-  sock->type = SILC_SOCKET_TYPE_ROUTER;
-  server->id_entry->router = id_entry;
-
+  conn_data = (SilcUnknownEntry)sock->user_data;
+  id_entry =
+    silc_idlist_add_server(server->local_list, 
+                          sock->hostname ? sock->hostname : sock->ip,
+                          SILC_ROUTER, ctx->dest_id, NULL,
+                          conn_data->send_key, conn_data->receive_key,
+                          conn_data->pkcs, conn_data->hmac, NULL, sock);
+  if (id_entry) {
+    id_entry->hmac_key = conn_data->hmac_key;
+    id_entry->hmac_key_len = conn_data->hmac_key_len;
+    sock->user_data = (void *)id_entry;
+    sock->type = SILC_SOCKET_TYPE_ROUTER;
+    server->id_entry->router = id_entry;
+  }
+    
   /* Free the temporary connection data context from key exchange */
   silc_free(conn_data);
 
@@ -757,6 +762,9 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection)
     return;
   }
 
+  SILC_LOG_INFO(("Incoming connection from %s (%s)", newsocket->hostname,
+                newsocket->ip));
+
   /* Allocate internal context for key exchange protocol. This is
      sent as context for the protocol. */
   proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
@@ -774,13 +782,13 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection)
                      silc_server_accept_new_connection_second);
 
   /* Register a timeout task that will be executed if the connector
-     will not start the key exchange protocol within 15 seconds. For
-     now, this is a hard coded limit. After 15 secs the connection will
+     will not start the key exchange protocol within 60 seconds. For
+     now, this is a hard coded limit. After 60 secs the connection will
      be closed if the key exchange protocol has not been started. */
   proto_ctx->timeout_task = 
     silc_task_register(server->timeout_queue, newsocket->sock, 
                       silc_server_timeout_remote,
-                      context, 15, 0,
+                      context, 60, 0,
                       SILC_TASK_TIMEOUT,
                       SILC_TASK_PRI_LOW);
 
@@ -820,7 +828,8 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_second)
     if (ctx->dest_id)
       silc_free(ctx->dest_id);
     silc_free(ctx);
-    sock->protocol = NULL;
+    if (sock)
+      sock->protocol = NULL;
     silc_server_disconnect_remote(server, sock, "Server closed connection: "
                                  "Key exchange failed");
     return;
@@ -886,7 +895,8 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
     if (ctx->dest_id)
       silc_free(ctx->dest_id);
     silc_free(ctx);
-    sock->protocol = NULL;
+    if (sock)
+      sock->protocol = NULL;
     silc_server_disconnect_remote(server, sock, "Server closed connection: "
                                  "Authentication failed");
     return;
@@ -896,60 +906,71 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
   switch(sock->type) {
   case SILC_SOCKET_TYPE_CLIENT:
     {
-      SilcClientList *id_entry = NULL;
-      SilcIDListUnknown *conn_data = sock->user_data;
+      SilcClientEntry client;
+      SilcUnknownEntry conn_data = (SilcUnknownEntry)sock->user_data;
 
       SILC_LOG_DEBUG(("Remote host is client"));
-
-      /* Add the client to the client ID list. We have not created the
-        client ID for the client yet. This is done when client registers
-        itself by sending NEW_CLIENT packet. */
-      silc_idlist_add_client(&server->local_list->clients, 
-                            NULL, NULL, NULL, NULL, NULL,
-                            conn_data->send_key, conn_data->receive_key, 
-                            conn_data->pkcs, conn_data->hmac, &id_entry);
-
-      id_entry->hmac_key = conn_data->hmac_key;
-      id_entry->hmac_key_len = conn_data->hmac_key_len;
-      id_entry->connection = sock;
+      SILC_LOG_INFO(("Connection from %s (%s) is client", sock->hostname,
+                    sock->ip));
+
+      /* Add the client to the client ID cache. The nickname and Client ID
+        and other information is created after we have received NEW_CLIENT
+        packet from client. */
+      client = 
+       silc_idlist_add_client(server->local_list, NULL, NULL, NULL, NULL,
+                              NULL, conn_data->send_key, 
+                              conn_data->receive_key, conn_data->pkcs,
+                              conn_data->hmac, NULL, sock);
+      if (!client) {
+       SILC_LOG_ERROR(("Could not add new client to cache"));
+       silc_free(conn_data);
+       break;
+      }
 
       /* Free the temporary connection data context from key exchange */
       silc_free(conn_data);
 
-      /* Mark the entry to the ID list to the socket connection for
-        fast referencing in the future. */
-      sock->user_data = (void *)id_entry;
+      /* Add to sockets internal pointer for fast referencing */
+      sock->user_data = (void *)client;
       break;
     }
   case SILC_SOCKET_TYPE_SERVER:
   case SILC_SOCKET_TYPE_ROUTER:
     {
-      SilcServerList *id_entry;
-      SilcIDListUnknown *conn_data = sock->user_data;
-      
+      SilcServerEntry new_server;
+      SilcUnknownEntry conn_data = (SilcUnknownEntry)sock->user_data;
+
       SILC_LOG_DEBUG(("Remote host is %s", 
                      sock->type == SILC_SOCKET_TYPE_SERVER ? 
                      "server" : "router"));
+      SILC_LOG_INFO(("Connection from %s (%s) is %s", sock->hostname,
+                    sock->ip, sock->type == SILC_SOCKET_TYPE_SERVER ? 
+                    "server" : "router"));
+
+      /* Add the server into server cache. The server name and Server ID
+        is updated after we have received NEW_SERVER packet from the
+        server. */
+      new_server = 
+       silc_idlist_add_server(server->local_list, NULL,
+                              sock->type == SILC_SOCKET_TYPE_SERVER ?
+                              SILC_SERVER : SILC_ROUTER, NULL, NULL,
+                              conn_data->send_key, conn_data->receive_key,
+                              conn_data->pkcs, conn_data->hmac, NULL, sock);
+      if (!new_server) {
+       SILC_LOG_ERROR(("Could not add new server to cache"));
+       silc_free(conn_data);
+       break;
+      }
       
-      /* Add the server to the ID list. We don't have the server's ID
-        yet but we will receive it after the server sends NEW_SERVER
-        packet to us. */
-      silc_idlist_add_server(&server->local_list->servers, NULL,
-                            sock->type == SILC_SOCKET_TYPE_SERVER ?
-                            SILC_SERVER : SILC_ROUTER, NULL, NULL,
-                            conn_data->send_key, conn_data->receive_key,
-                            conn_data->pkcs, conn_data->hmac, &id_entry);
-
-      id_entry->hmac_key = conn_data->hmac_key;
-      id_entry->hmac_key_len = conn_data->hmac_key_len;
-      id_entry->connection = sock;
-
-      /* Free the temporary connection data context from key exchange */
+      new_server->registered = TRUE;
+      new_server->hmac_key = conn_data->hmac_key;
+      new_server->hmac_key_len = conn_data->hmac_key_len;
+      
+      /* Free the temporary connection data context from protocols */
       silc_free(conn_data);
 
-      /* Mark the entry to the ID list to the socket connection for
-        fast referencing in the future. */
-      sock->user_data = (void *)id_entry;
+      /* Add to sockets internal pointer for fast referencing */
+      sock->user_data = (void *)new_server;
 
       /* There is connection to other server now, if it is router then
         we will have connection to outside world.  If we are router but
@@ -979,6 +1000,35 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final)
   sock->protocol = NULL;
 }
 
+/* Internal routine that sends packet or marks packet to be sent. This
+   is used directly only in special cases. Normal cases should use
+   silc_server_packet_send. Returns < 0 error. */
+
+static int silc_server_packet_send_real(SilcServer server,
+                                       SilcSocketConnection sock,
+                                       int force_send)
+{
+  int ret;
+
+  /* Send the packet */
+  ret = silc_packet_send(sock, force_send);
+  if (ret != -2)
+    return ret;
+
+  /* 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). 
+     Actual data sending is performed by silc_server_packet_process. */
+  SILC_SET_CONNECTION_FOR_OUTPUT(sock->sock);
+
+  /* Mark to socket that data is pending in outgoing buffer. This flag
+     is needed if new data is added to the buffer before the earlier
+     put data is sent to the network. */
+  SILC_SET_OUTBUF_PENDING(sock);
+
+  return 0;
+}
+
 typedef struct {
   SilcPacketContext *packetdata;
   SilcServer server;
@@ -994,7 +1044,9 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
 {
   SilcServer server = (SilcServer)context;
   SilcSocketConnection sock = server->sockets[fd];
-  int ret, packetlen, paddedlen;
+  SilcCipher cipher = NULL;
+  SilcHmac hmac = NULL;
+  int ret;
 
   SILC_LOG_DEBUG(("Processing packet"));
 
@@ -1006,18 +1058,13 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
       silc_buffer_push(sock->outbuf, 
                       sock->outbuf->data - sock->outbuf->head);
 
-    /* Write the packet out to the connection */
-    ret = silc_packet_write(fd, sock->outbuf);
+    ret = silc_server_packet_send_real(server, sock, TRUE);
 
     /* If returned -2 could not write to connection now, will do
        it later. */
     if (ret == -2)
       return;
     
-    /* Error */
-    if (ret == -1)
-      SILC_LOG_ERROR(("Could not write, packet dropped"));
-
     /* 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. 
@@ -1033,22 +1080,10 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
   if (type == SILC_TASK_READ) {
     SILC_LOG_DEBUG(("Reading data from connection"));
 
-    /* Allocate the incoming data buffer if not done already. */
-    if (!sock->inbuf)
-      sock->inbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE);
-
     /* Read some data from connection */
-    ret = silc_packet_read(fd, sock->inbuf);
-    
-    /* If returned -2 data was not available now, will read it later. */
-    if (ret == -2)
-      return;
-    
-    /* Error */
-    if (ret == -1) {
-      SILC_LOG_ERROR(("Could not read, packet dropped"));
+    ret = silc_packet_receive(sock);
+    if (ret < 0)
       return;
-    }
     
     /* EOF */
     if (ret == 0) {
@@ -1078,489 +1113,127 @@ SILC_TASK_CALLBACK(silc_server_packet_process)
       return;
     }
 
-    /* Check whether we received a whole packet. If reading went without
-       errors we either read a whole packet or the read packet is 
-       incorrect and will be dropped. */
-    SILC_PACKET_LENGTH(sock->inbuf, packetlen, paddedlen);
-    if (sock->inbuf->len < paddedlen || (packetlen < SILC_PACKET_MIN_LEN)) {
-      SILC_LOG_DEBUG(("Received incorrect packet, dropped"));
-      silc_buffer_clear(sock->inbuf);
-      silc_server_disconnect_remote(server, sock, "Incorrect packet");
-      return;
-    }
+    switch (sock->type) {
+    case SILC_SOCKET_TYPE_CLIENT:
+      {
+       SilcClientEntry clnt = (SilcClientEntry)sock->user_data;
+       if (!clnt)
+         break;
 
-    /* Decrypt a packet coming from client. */
-    if (sock->type == SILC_SOCKET_TYPE_CLIENT) {
-      SilcClientList *clnt = (SilcClientList *)sock->user_data;
-      SilcServerInternalPacket *packet;
-      int mac_len = 0;
-      
-      if (clnt->hmac)
-       mac_len = clnt->hmac->hash->hash->hash_len;
-
-      if (sock->inbuf->len - 2 > (paddedlen + mac_len)) {
-       /* Received possibly many packets at once */
-
-       while(sock->inbuf->len > 0) {
-         SILC_PACKET_LENGTH(sock->inbuf, packetlen, paddedlen);
-         if (sock->inbuf->len < paddedlen) {
-           SILC_LOG_DEBUG(("Receive incorrect packet, dropped"));
-           return;
-         }
-
-         paddedlen += 2;
-         packet = silc_calloc(1, sizeof(*packet));
-         packet->server = server;
-         packet->sock = sock;
-         packet->packetdata = silc_calloc(1, sizeof(*packet->packetdata));
-         packet->packetdata->buffer = silc_buffer_alloc(paddedlen + mac_len);
-         silc_buffer_pull_tail(packet->packetdata->buffer, 
-                               SILC_BUFFER_END(packet->packetdata->buffer));
-         silc_buffer_put(packet->packetdata->buffer, sock->inbuf->data, 
-                         paddedlen + mac_len);
-         if (clnt) {
-           packet->cipher = clnt->receive_key;
-           packet->hmac = clnt->hmac;
-         }
-
-         SILC_LOG_HEXDUMP(("Incoming packet, len %d", 
-                           packet->packetdata->buffer->len),
-                          packet->packetdata->buffer->data, 
-                          packet->packetdata->buffer->len);
-
-         /* Parse the packet with timeout */
-         silc_task_register(server->timeout_queue, fd, 
-                            silc_server_packet_parse,
-                            (void *)packet, 0, 100000, 
-                            SILC_TASK_TIMEOUT,
-                            SILC_TASK_PRI_NORMAL);
-
-         /* Pull the packet from inbuf thus we'll get the next one
-            in the inbuf. */
-         silc_buffer_pull(sock->inbuf, paddedlen);
-         if (clnt->hmac)
-           silc_buffer_pull(sock->inbuf, mac_len);
-       }
-       silc_buffer_clear(sock->inbuf);
-       return;
-      } else {
-       SILC_LOG_HEXDUMP(("An incoming packet, len %d", sock->inbuf->len),
-                        sock->inbuf->data, sock->inbuf->len);
-       
-       SILC_LOG_DEBUG(("Packet from client, length %d", paddedlen));
-       
-       packet = silc_calloc(1, sizeof(*packet));
-       packet->packetdata = silc_calloc(1, sizeof(*packet->packetdata));
-       packet->packetdata->buffer = silc_buffer_copy(sock->inbuf);
-       packet->server = server;
-       packet->sock = sock;
-       if (clnt) {
-         packet->cipher = clnt->receive_key;
-         packet->hmac = clnt->hmac;
-       }
-       silc_buffer_clear(sock->inbuf);
-       
-       /* The packet is ready to be parsed now. However, this is a client 
-          connection so we will parse the packet with timeout. */
-       silc_task_register(server->timeout_queue, fd, 
-                          silc_server_packet_parse,
-                          (void *)packet, 0, 100000, 
-                          SILC_TASK_TIMEOUT,
-                          SILC_TASK_PRI_NORMAL);
-       return;
-      }
-    }
-    
-    /* Decrypt a packet coming from server connection */
-    if (sock->type == SILC_SOCKET_TYPE_SERVER ||
-       sock->type == SILC_SOCKET_TYPE_ROUTER) {
-      SilcServerList *srvr = (SilcServerList *)sock->user_data;
-      SilcServerInternalPacket *packet;
-      int mac_len = 0;
-      
-      if (srvr->hmac)
-       mac_len = srvr->hmac->hash->hash->hash_len;
-
-      if (sock->inbuf->len - 2 > (paddedlen + mac_len)) {
-       /* Received possibly many packets at once */
-
-       while(sock->inbuf->len > 0) {
-         SILC_PACKET_LENGTH(sock->inbuf, packetlen, paddedlen);
-         if (sock->inbuf->len < paddedlen) {
-           SILC_LOG_DEBUG(("Received incorrect packet, dropped"));
-           return;
-         }
-
-         paddedlen += 2;
-         packet = silc_calloc(1, sizeof(*packet));
-         packet->server = server;
-         packet->sock = sock;
-         packet->packetdata = silc_calloc(1, sizeof(*packet->packetdata));
-         packet->packetdata->buffer = silc_buffer_alloc(paddedlen + mac_len);
-         silc_buffer_pull_tail(packet->packetdata->buffer, 
-                               SILC_BUFFER_END(packet->packetdata->buffer));
-         silc_buffer_put(packet->packetdata->buffer, sock->inbuf->data, 
-                         paddedlen + mac_len);
-         if (srvr) {
-           packet->cipher = srvr->receive_key;
-           packet->hmac = srvr->hmac;
-         }
-
-         SILC_LOG_HEXDUMP(("Incoming packet, len %d", 
-                           packet->packetdata->buffer->len),
-                          packet->packetdata->buffer->data, 
-                          packet->packetdata->buffer->len);
-
-         SILC_LOG_DEBUG(("Packet from %s %s, packet length %d", 
-                         srvr->server_type == SILC_SERVER ? 
-                         "server" : "router",
-                         srvr->server_name, paddedlen));
-       
-         /* Parse it real soon as the packet is from server. */
-         silc_task_register(server->timeout_queue, fd, 
-                            silc_server_packet_parse,
-                            (void *)packet, 0, 1, 
-                            SILC_TASK_TIMEOUT,
-                            SILC_TASK_PRI_NORMAL);
-
-         /* Pull the packet from inbuf thus we'll get the next one
-            in the inbuf. */
-         silc_buffer_pull(sock->inbuf, paddedlen);
-         if (srvr->hmac)
-           silc_buffer_pull(sock->inbuf, mac_len);
-       }
-       silc_buffer_clear(sock->inbuf);
-       return;
-      } else {
+       clnt->last_receive = time(NULL);
 
-       SILC_LOG_HEXDUMP(("An incoming packet, len %d", sock->inbuf->len),
-                        sock->inbuf->data, sock->inbuf->len);
-       
-       SILC_LOG_DEBUG(("Packet from %s %s, packet length %d", 
-                       srvr->server_type == SILC_SERVER ? 
-                       "server" : "router",
-                       srvr->server_name, paddedlen));
-       
-       packet = silc_calloc(1, sizeof(*packet));
-       packet->packetdata = silc_calloc(1, sizeof(*packet->packetdata));
-       packet->packetdata->buffer = silc_buffer_copy(sock->inbuf);
-       packet->server = server;
-       packet->sock = sock;
-       if (srvr) {
-         packet->cipher = srvr->receive_key;
-         packet->hmac = srvr->hmac;
-       }
-       silc_buffer_clear(sock->inbuf);
-       
-       /* The packet is ready to be parsed now. However, this is a client 
-          connection so we will parse the packet with timeout. */
-       silc_task_register(server->timeout_queue, fd, 
-                          silc_server_packet_parse,
-                          (void *)packet, 0, 1, 
-                          SILC_TASK_TIMEOUT,
-                          SILC_TASK_PRI_NORMAL);
-       return;
+       cipher = clnt->receive_key;
+       hmac = clnt->hmac;
+       break;
       }
-    }
+    case SILC_SOCKET_TYPE_SERVER:
+    case SILC_SOCKET_TYPE_ROUTER:
+      {
+       SilcServerEntry srvr = (SilcServerEntry)sock->user_data;
+       if (!srvr)
+         break;
 
-    /* Decrypt a packet coming from client. */
-    if (sock->type == SILC_SOCKET_TYPE_UNKNOWN) {
-      SilcIDListUnknown *conn_data = (SilcIDListUnknown *)sock->user_data;
-      SilcServerInternalPacket *packet;
-      
-      SILC_LOG_HEXDUMP(("Incoming packet, len %d", sock->inbuf->len),
-                      sock->inbuf->data, sock->inbuf->len);
-
-      SILC_LOG_DEBUG(("Packet from unknown connection, length %d", 
-                     paddedlen));
-
-      packet = silc_calloc(1, sizeof(*packet));
-      packet->packetdata = silc_calloc(1, sizeof(*packet->packetdata));
-      packet->packetdata->buffer = silc_buffer_copy(sock->inbuf);
-      packet->server = server;
-      packet->sock = sock;
-      if (conn_data) {
-       packet->cipher = conn_data->receive_key;
-       packet->hmac = conn_data->hmac;
-      }
+       srvr->last_receive = time(NULL);
 
-      silc_buffer_clear(sock->inbuf);
+       cipher = srvr->receive_key;
+       hmac = srvr->hmac;
+       break;
+      }
+    case SILC_SOCKET_TYPE_UNKNOWN:
+      {
+       SilcUnknownEntry conn_data = (SilcUnknownEntry)sock->user_data;
+       if (!conn_data)
+         break;
 
-      /* The packet is ready to be parsed now. However, this is unknown 
-        connection so we will parse the packet with timeout. */
-      silc_task_register(server->timeout_queue, fd, 
-                        silc_server_packet_parse,
-                        (void *)packet, 0, 100000, 
-                        SILC_TASK_TIMEOUT,
-                        SILC_TASK_PRI_NORMAL);
+       cipher = conn_data->receive_key;
+       hmac = conn_data->hmac;
+       break;
+      }
+    default:
       return;
     }
+    /* Process the packet. This will call the parser that will then
+       decrypt and parse the packet. */
+    silc_packet_receive_process(sock, cipher, hmac,
+                               silc_server_packet_parse, server);
   }
-
-  SILC_LOG_ERROR(("Weird, nothing happened - ignoring"));
 }
 
-/* Checks MAC in the packet. Returns TRUE if MAC is Ok. This is called
-   after packet has been totally decrypted and parsed. */
+/* Parses whole packet, received earlier. */
 
-static int silc_server_packet_check_mac(SilcServer server,
-                                       SilcSocketConnection sock,
-                                       SilcBuffer buffer)
+SILC_TASK_CALLBACK(silc_server_packet_parse_real)
 {
-  SilcHmac hmac = NULL;
-  unsigned char *hmac_key = NULL;
-  unsigned int hmac_key_len = 0;
-  unsigned int mac_len = 0;
-
-  switch(sock->type) {
-  case SILC_SOCKET_TYPE_CLIENT:
-    if (sock->user_data) {
-      hmac = ((SilcClientList *)sock->user_data)->hmac;
-      hmac_key = ((SilcClientList *)sock->user_data)->hmac_key;
-      hmac_key_len = ((SilcClientList *)sock->user_data)->hmac_key_len;
-    }
-    break;
-  case SILC_SOCKET_TYPE_SERVER:
-  case SILC_SOCKET_TYPE_ROUTER:
-    if (sock->user_data) {
-      hmac = ((SilcServerList *)sock->user_data)->hmac;
-      hmac_key = ((SilcServerList *)sock->user_data)->hmac_key;
-      hmac_key_len = ((SilcServerList *)sock->user_data)->hmac_key_len;
-    }
-    break;
-  default:
-    if (sock->user_data) {
-      hmac = ((SilcIDListUnknown *)sock->user_data)->hmac;
-      hmac_key = ((SilcIDListUnknown *)sock->user_data)->hmac_key;
-      hmac_key_len = ((SilcIDListUnknown *)sock->user_data)->hmac_key_len;
-    }
-  }
-
-  /* Check MAC */
-  if (hmac) {
-    int headlen = buffer->data - buffer->head;
-    unsigned char *packet_mac, mac[32];
-    
-    SILC_LOG_DEBUG(("Verifying MAC"));
+  SilcPacketParserContext *parse_ctx = (SilcPacketParserContext *)context;
+  SilcServer server = (SilcServer)parse_ctx->context;
+  SilcSocketConnection sock = parse_ctx->sock;
+  SilcPacketContext *packet = parse_ctx->packet;
+  SilcBuffer buffer = packet->buffer;
+  int ret;
 
-    mac_len = hmac->hash->hash->hash_len;
+  SILC_LOG_DEBUG(("Start"));
 
-    silc_buffer_push(buffer, headlen);
-    
-    /* Take mac from packet */
-    packet_mac = buffer->tail;
-    
-    /* Make MAC and compare */
-    memset(mac, 0, sizeof(mac));
-    silc_hmac_make_with_key(hmac, 
-                           buffer->data, buffer->len,
-                           hmac_key, hmac_key_len, mac);
-#if 0
-    SILC_LOG_HEXDUMP(("PMAC"), packet_mac, mac_len);
-    SILC_LOG_HEXDUMP(("CMAC"), mac, mac_len);
-#endif
-    if (memcmp(mac, packet_mac, mac_len)) {
-      SILC_LOG_DEBUG(("MAC failed"));
-      return FALSE;
-    }
-    
-    SILC_LOG_DEBUG(("MAC is Ok"));
-    memset(mac, 0, sizeof(mac));
+  /* Decrypt the received packet */
+  ret = silc_packet_decrypt(parse_ctx->cipher, parse_ctx->hmac, 
+                           buffer, packet);
+  if (ret < 0)
+    goto out;
 
-    silc_buffer_pull(buffer, headlen);
+  if (ret == 0) {
+    /* Parse the packet. Packet type is returned. */
+    ret = silc_packet_parse(packet);
+  } else {
+    /* Parse the packet header in special way as this is "special"
+       packet type. */
+    ret = silc_packet_parse_special(packet);
   }
-  
-  return TRUE;
-}
 
-/* Decrypts rest of the packet (after decrypting just the SILC header).
-   After calling this function the packet is ready to be parsed by calling 
-   silc_packet_parse. */
-
-static int silc_server_packet_decrypt_rest(SilcServer server, 
-                                          SilcSocketConnection sock,
-                                          SilcBuffer buffer)
-{
-  SilcCipher session_key = NULL;
-  SilcHmac hmac = NULL;
-  unsigned int mac_len = 0;
-
-  switch(sock->type) {
-  case SILC_SOCKET_TYPE_CLIENT:
-    if (sock->user_data) {
-      session_key = ((SilcClientList *)sock->user_data)->receive_key;
-      hmac = ((SilcClientList *)sock->user_data)->hmac;
-    }
-    break;
-  case SILC_SOCKET_TYPE_SERVER:
-  case SILC_SOCKET_TYPE_ROUTER:
-    if (sock->user_data) {
-      session_key = ((SilcServerList *)sock->user_data)->receive_key;
-      hmac = ((SilcServerList *)sock->user_data)->hmac;
-    }
-    break;
-  default:
-    if (sock->user_data) {
-      session_key = ((SilcIDListUnknown *)sock->user_data)->receive_key;
-      hmac = ((SilcIDListUnknown *)sock->user_data)->hmac;
-    }
-  }
+  if (ret == SILC_PACKET_NONE)
+    goto out;
   
-  /* Decrypt */
-  if (session_key) {
-
-    /* Pull MAC from packet before decryption */
-    if (hmac) {
-      mac_len = hmac->hash->hash->hash_len;
-      if ((buffer->len - mac_len) > SILC_PACKET_MIN_LEN) {
-       silc_buffer_push_tail(buffer, mac_len);
-      } else {
-       SILC_LOG_DEBUG(("Bad MAC length in packet, packet dropped"));
-       return FALSE;
-      }
-    }
-
-    SILC_LOG_DEBUG(("Decrypting rest of the packet"));
-
-    /* Decrypt rest of the packet */
-    silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
-    silc_packet_decrypt(session_key, buffer, buffer->len);
-    silc_buffer_push(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
-
-    SILC_LOG_HEXDUMP(("Fully decrypted packet, len %d", buffer->len),
-                    buffer->data, buffer->len);
-  }
+  /* Parse the incoming packet type */
+  silc_server_packet_parse_type(server, sock, packet);
 
-  return TRUE;
+ out:
+  silc_buffer_clear(sock->inbuf);
+  if (packet->src_id)
+    silc_free(packet->src_id);
+  if (packet->dst_id)
+    silc_free(packet->dst_id);
+  silc_free(packet);
+  silc_free(parse_ctx);
 }
 
-/* Decrypts rest of the SILC Packet header that has been decrypted partly
-   already. This decrypts the padding of the packet also.  After calling 
-   this function the packet is ready to be parsed by calling function 
-   silc_packet_parse. */
+/* Parser callback called by silc_packet_receive_process. This merely
+   registers timeout that will handle the actual parsing whem appropriate. */
 
-static int silc_server_packet_decrypt_rest_special(SilcServer server, 
-                                                  SilcSocketConnection sock,
-                                                  SilcBuffer buffer)
+void silc_server_packet_parse(SilcPacketParserContext *parser_context)
 {
-  SilcCipher session_key = NULL;
-  SilcHmac hmac = NULL;
-  unsigned int mac_len = 0;
+  SilcServer server = (SilcServer)parser_context->context;
+  SilcSocketConnection sock = parser_context->sock;
 
-  switch(sock->type) {
+  switch (sock->type) {
   case SILC_SOCKET_TYPE_CLIENT:
-    if (sock->user_data) {
-      session_key = ((SilcClientList *)sock->user_data)->receive_key;
-      hmac = ((SilcClientList *)sock->user_data)->hmac;
-    }
+  case SILC_SOCKET_TYPE_UNKNOWN:
+    /* Parse the packet with timeout */
+    silc_task_register(server->timeout_queue, sock->sock,
+                      silc_server_packet_parse_real,
+                      (void *)parser_context, 0, 100000,
+                      SILC_TASK_TIMEOUT,
+                      SILC_TASK_PRI_NORMAL);
     break;
   case SILC_SOCKET_TYPE_SERVER:
   case SILC_SOCKET_TYPE_ROUTER:
-    if (sock->user_data) {
-      session_key = ((SilcServerList *)sock->user_data)->receive_key;
-      hmac = ((SilcServerList *)sock->user_data)->hmac;
-    }
+    /* Packets from servers are parsed as soon as possible */
+    silc_task_register(server->timeout_queue, sock->sock,
+                      silc_server_packet_parse_real,
+                      (void *)parser_context, 0, 1,
+                      SILC_TASK_TIMEOUT,
+                      SILC_TASK_PRI_NORMAL);
     break;
   default:
-    if (sock->user_data) {
-      session_key = ((SilcIDListUnknown *)sock->user_data)->receive_key;
-      hmac = ((SilcIDListUnknown *)sock->user_data)->hmac;
-    }
-  }
-  
-  /* Decrypt rest of the header plus padding */
-  if (session_key) {
-    unsigned short truelen, len1, len2, padlen;
-
-    /* Pull MAC from packet before decryption */
-    if (hmac) {
-      mac_len = hmac->hash->hash->hash_len;
-      if ((buffer->len - mac_len) > SILC_PACKET_MIN_LEN) {
-       silc_buffer_push_tail(buffer, mac_len);
-      } else {
-       SILC_LOG_DEBUG(("Bad MAC length in packet, packet dropped"));
-       return FALSE;
-      }
-    }
-  
-    SILC_LOG_DEBUG(("Decrypting rest of the header"));
-
-    SILC_GET16_MSB(len1, &buffer->data[4]);
-    SILC_GET16_MSB(len2, &buffer->data[6]);
-
-    truelen = SILC_PACKET_HEADER_LEN + len1 + len2;
-    padlen = SILC_PACKET_PADLEN(truelen);
-    len1 = (truelen + padlen) - (SILC_PACKET_MIN_HEADER_LEN - 2);
-
-    silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
-    silc_packet_decrypt(session_key, buffer, len1);
-    silc_buffer_push(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
-  }
-
-  return TRUE;
-}
-
-/* Parses whole packet, received earlier. This packet is usually received
-   from client. */
-
-SILC_TASK_CALLBACK(silc_server_packet_parse)
-{
-  SilcServerInternalPacket *packet = (SilcServerInternalPacket *)context;
-  SilcServer server = packet->server;
-  SilcSocketConnection sock = packet->sock;
-  SilcBuffer buffer = packet->packetdata->buffer;
-  int ret;
-
-  SILC_LOG_DEBUG(("Start"));
-
-  /* Decrypt start of the packet header */
-  if (packet->cipher)
-    silc_packet_decrypt(packet->cipher, buffer, SILC_PACKET_MIN_HEADER_LEN);
-
-  /* If the packet type is not any special type lets decrypt rest
-     of the packet here. */
-  if (buffer->data[3] != SILC_PACKET_CHANNEL_MESSAGE &&
-      buffer->data[3] != SILC_PACKET_PRIVATE_MESSAGE) {
-  normal:
-    /* Normal packet, decrypt rest of the packet */
-    if (!silc_server_packet_decrypt_rest(server, sock, buffer))
-      goto out;
-
-    /* Parse the packet. Packet type is returned. */
-    ret = silc_packet_parse(packet->packetdata);
-    if (ret == SILC_PACKET_NONE)
-      goto out;
-
-    /* Check MAC */
-    if (!silc_server_packet_check_mac(server, sock, buffer))
-      goto out;
-  } else {
-    /* If private message key is not set for private message it is
-       handled as normal packet. Go back up. */
-    if (buffer->data[3] == SILC_PACKET_PRIVATE_MESSAGE &&
-       !(buffer->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY))
-      goto normal;
-
-    /* Packet requires special handling, decrypt rest of the header.
-       This only decrypts. This does not do any MAC checking, it must
-       be done individually later when doing the special processing. */
-    silc_server_packet_decrypt_rest_special(server, sock, buffer);
-
-    /* Parse the packet header in special way as this is "special"
-       packet type. */
-    ret = silc_packet_parse_special(packet->packetdata);
-    if (ret == SILC_PACKET_NONE)
-      goto out;
+    return;
   }
-  
-  /* Parse the incoming packet type */
-  silc_server_packet_parse_type(server, sock, packet->packetdata);
-
- out:
-  silc_buffer_clear(sock->inbuf);
-  //  silc_buffer_free(packetdata->packetdata->buffer);
-  silc_free(packet->packetdata);
-  silc_free(packet);
 }
 
 /* Parses the packet type and calls what ever routines the packet type
@@ -1593,7 +1266,18 @@ void silc_server_packet_parse_type(SilcServer server,
     }
     break;
   case SILC_PACKET_FAILURE:
+    /*
+     * Failure received for something. For now we can have only
+     * one protocol for connection executing at once hence this
+     * failure message is for whatever protocol is executing currently.
+     */
     SILC_LOG_DEBUG(("Failure packet"));
+    if (sock->protocol) {
+      /* XXX Audit the failure type */
+      sock->protocol->state = SILC_PROTOCOL_STATE_FAILURE;
+      sock->protocol->execute(server->timeout_queue, 0,
+                             sock->protocol, sock->sock, 0, 0);
+    }
     break;
   case SILC_PACKET_REJECT:
     SILC_LOG_DEBUG(("Reject packet"));
@@ -1628,37 +1312,11 @@ void silc_server_packet_parse_type(SilcServer server,
      * Command packets
      */
   case SILC_PACKET_COMMAND:
-    {
-      /*
-       * Recived command. Allocate command context and execute the command.
-       */
-      SilcServerCommandContext ctx;
-
-      SILC_LOG_DEBUG(("Command packet"));
-
-      /* Router cannot send command packet */
-      if (sock->type == SILC_SOCKET_TYPE_ROUTER)
-       break;
-
-      /* Allocate command context. This must be free'd by the
-        command routine receiving it. */
-      ctx = silc_calloc(1, sizeof(*ctx));
-      ctx->server = server;
-      ctx->sock = sock;
-      ctx->packet = packet;    /* Save original packet */
-
-      /* Parse the command payload in the packet */
-      ctx->payload = silc_command_parse_payload(buffer);
-      if (!ctx->payload) {
-       SILC_LOG_ERROR(("Bad command payload, packet dropped"));
-       silc_free(ctx);
-       return;
-      }
-
-      /* Execute command. If this fails the packet is dropped. */
-      SILC_SERVER_COMMAND_EXEC(ctx);
-      silc_buffer_free(buffer);
-    }
+    /*
+     * Recived command. Allocate command context and execute the command.
+     */
+    SILC_LOG_DEBUG(("Command packet"));
+    silc_server_command_process(server, sock, packet);
     break;
 
   case SILC_PACKET_COMMAND_REPLY:
@@ -1814,100 +1472,52 @@ void silc_server_packet_parse_type(SilcServer server,
   case SILC_PACKET_NEW_SERVER:
     /*
      * Received new server packet. This includes Server ID and some other
-     * information that we may save. This is after server as connected to us.
+     * information that we may save. This is received after server has 
+     * connected to us.
      */
     SILC_LOG_DEBUG(("New Server packet"));
     silc_server_new_server(server, sock, packet);
     break;
 
-  default:
-    SILC_LOG_ERROR(("Incorrect packet type %d, packet dropped", type));
+  case SILC_PACKET_NEW_CHANNEL:
     break;
-  }
-  
-}
-
-/* Internal routine that sends packet or marks packet to be sent. This
-   is used directly only in special cases. Normal cases should use
-   silc_server_packet_send. Returns < 0 error. */
-
-static int silc_server_packet_send_real(SilcServer server,
-                                       SilcSocketConnection sock,
-                                       int force_send)
-{
-  /* Send now if forced to do so */
-  if (force_send == TRUE) {
-    int ret;
-    SILC_LOG_DEBUG(("Forcing packet send, packet sent immediately"));
-    ret = silc_packet_write(sock->sock, sock->outbuf);
-
-    silc_buffer_clear(sock->outbuf);
 
-    if (ret == -1)
-      SILC_LOG_ERROR(("Could not write, packet dropped"));
-    if (ret != -2) {
-      silc_buffer_clear(sock->outbuf);
-      return ret;
-    }
-
-    SILC_LOG_DEBUG(("Could not force the send, packet put to queue"));
-  }  
-
-  SILC_LOG_DEBUG(("Packet in queue"));
-
-  /* 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). 
-     Actual data sending is performed by silc_server_packet_process. */
-  SILC_SET_CONNECTION_FOR_OUTPUT(sock->sock);
-
-  /* Mark to socket that data is pending in outgoing buffer. This flag
-     is needed if new data is added to the buffer before the earlier
-     put data is sent to the network. */
-  SILC_SET_OUTBUF_PENDING(sock);
+  case SILC_PACKET_NEW_CHANNEL_USER:
+    break;
 
-  return 0;
-}
+  case SILC_PACKET_NEW_CHANNEL_LIST:
+    break;
 
-/* Prepare outgoing data buffer for packet sending. This is internal
-   routine and must always be called before sending any packets out. */
+  case SILC_PACKET_NEW_CHANNEL_USER_LIST:
+    break;
 
-static void silc_server_packet_send_prepare(SilcServer server, 
-                                           SilcSocketConnection sock,
-                                           unsigned int header_len,
-                                           unsigned int padlen,
-                                           unsigned int data_len)
-{
-  int totlen, oldlen;
+  case SILC_PACKET_REPLACE_ID:
+    /*
+     * Received replace ID packet. This sends the old ID that is to be
+     * replaced with the new one included into the packet. Client must not
+     * send this packet.
+     */
+    SILC_LOG_DEBUG(("Replace ID packet"));
+    silc_server_replace_id(server, sock, packet);
+    break;
 
-  totlen = header_len + padlen + data_len;
+  case SILC_PACKET_REMOVE_ID:
+    break;
 
-  /* Prepare the outgoing buffer for packet sending. */
-  if (!sock->outbuf) {
-    /* Allocate new buffer. This is done only once per connection. */
-    SILC_LOG_DEBUG(("Allocating outgoing data buffer"));
-    
-    sock->outbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE);
-    silc_buffer_pull_tail(sock->outbuf, totlen);
-    silc_buffer_pull(sock->outbuf, header_len + padlen);
-  } else {
-    if (SILC_IS_OUTBUF_PENDING(sock)) {
-      /* There is some pending data in the buffer. */
+  case SILC_PACKET_REMOVE_CHANNEL_USER:
+    /*
+     * Received packet to remove user from a channel. Routers notify other
+     * routers about a user leaving a channel.
+     */
+    SILC_LOG_DEBUG(("Remove Channel User packet"));
+    silc_server_remove_channel_user(server, sock, packet);
+    break;
 
-      if ((sock->outbuf->end - sock->outbuf->tail) < data_len) {
-       SILC_LOG_DEBUG(("Reallocating outgoing data buffer"));
-       /* XXX: not done yet */
-      }
-      oldlen = sock->outbuf->len;
-      silc_buffer_pull_tail(sock->outbuf, totlen);
-      silc_buffer_pull(sock->outbuf, header_len + padlen + oldlen);
-    } else {
-      /* Buffer is free for use */
-      silc_buffer_clear(sock->outbuf);
-      silc_buffer_pull_tail(sock->outbuf, totlen);
-      silc_buffer_pull(sock->outbuf, header_len + padlen);
-    }
+  default:
+    SILC_LOG_ERROR(("Incorrect packet type %d, packet dropped", type));
+    break;
   }
+  
 }
 
 /* Assembles a new packet to be sent out to network. This doesn't actually
@@ -1927,18 +1537,21 @@ void silc_server_packet_send(SilcServer server,
   void *dst_id = NULL;
   SilcIdType dst_id_type = SILC_ID_NONE;
 
+  if (!sock)
+    return;
+
   /* Get data used in the packet sending, keys and stuff */
   switch(sock->type) {
   case SILC_SOCKET_TYPE_CLIENT:
-    if (((SilcClientList *)sock->user_data)->id) {
-      dst_id = ((SilcClientList *)sock->user_data)->id;
+    if (((SilcClientEntry)sock->user_data)->id) {
+      dst_id = ((SilcClientEntry)sock->user_data)->id;
       dst_id_type = SILC_ID_CLIENT;
     }
     break;
   case SILC_SOCKET_TYPE_SERVER:
   case SILC_SOCKET_TYPE_ROUTER:
-    if (((SilcServerList *)sock->user_data)->id) {
-      dst_id = ((SilcServerList *)sock->user_data)->id;
+    if (((SilcServerEntry)sock->user_data)->id) {
+      dst_id = ((SilcServerEntry)sock->user_data)->id;
       dst_id_type = SILC_ID_SERVER;
     }
     break;
@@ -1970,10 +1583,6 @@ void silc_server_packet_send_dest(SilcServer server,
   SilcPacketContext packetdata;
   SilcCipher cipher = NULL;
   SilcHmac hmac = NULL;
-  unsigned char *hmac_key = NULL;
-  unsigned int hmac_key_len = 0;
-  unsigned char mac[32];
-  unsigned int mac_len = 0;
   unsigned char *dst_id_data = NULL;
   unsigned int dst_id_len = 0;
 
@@ -1983,38 +1592,23 @@ void silc_server_packet_send_dest(SilcServer server,
   switch(sock->type) {
   case SILC_SOCKET_TYPE_CLIENT:
     if (sock->user_data) {
-      cipher = ((SilcClientList *)sock->user_data)->send_key;
-      hmac = ((SilcClientList *)sock->user_data)->hmac;
-      if (hmac) {
-       mac_len = hmac->hash->hash->hash_len;
-       hmac_key = ((SilcClientList *)sock->user_data)->hmac_key;
-       hmac_key_len = ((SilcClientList *)sock->user_data)->hmac_key_len;
-      }
+      cipher = ((SilcClientEntry)sock->user_data)->send_key;
+      hmac = ((SilcClientEntry)sock->user_data)->hmac;
     }
     break;
   case SILC_SOCKET_TYPE_SERVER:
   case SILC_SOCKET_TYPE_ROUTER:
     if (sock->user_data) {
-      cipher = ((SilcServerList *)sock->user_data)->send_key;
-      hmac = ((SilcServerList *)sock->user_data)->hmac;
-      if (hmac) {
-       mac_len = hmac->hash->hash->hash_len;
-       hmac_key = ((SilcServerList *)sock->user_data)->hmac_key;
-       hmac_key_len = ((SilcServerList *)sock->user_data)->hmac_key_len;
-      }
+      cipher = ((SilcServerEntry)sock->user_data)->send_key;
+      hmac = ((SilcServerEntry)sock->user_data)->hmac;
     }
     break;
   default:
     if (sock->user_data) {
       /* We don't know what type of connection this is thus it must
         be in authentication phase. */
-      cipher = ((SilcIDListUnknown *)sock->user_data)->send_key;
-      hmac = ((SilcIDListUnknown *)sock->user_data)->hmac;
-      if (hmac) {
-       mac_len = hmac->hash->hash->hash_len;
-       hmac_key = ((SilcIDListUnknown *)sock->user_data)->hmac_key;
-       hmac_key_len = ((SilcIDListUnknown *)sock->user_data)->hmac_key_len;
-      }
+      cipher = ((SilcUnknownEntry)sock->user_data)->send_key;
+      hmac = ((SilcUnknownEntry)sock->user_data)->hmac;
     }
     break;
   }
@@ -2039,12 +1633,12 @@ void silc_server_packet_send_dest(SilcServer server,
   packetdata.rng = server->rng;
 
   /* Prepare outgoing data buffer for packet sending */
-  silc_server_packet_send_prepare(server, sock, 
-                                 SILC_PACKET_HEADER_LEN +
-                                 packetdata.src_id_len + 
-                                 packetdata.dst_id_len,
-                                 packetdata.padlen,
-                                 data_len);
+  silc_packet_send_prepare(sock, 
+                          SILC_PACKET_HEADER_LEN +
+                          packetdata.src_id_len + 
+                          packetdata.dst_id_len,
+                          packetdata.padlen,
+                          data_len);
 
   SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
 
@@ -2057,21 +1651,9 @@ void silc_server_packet_send_dest(SilcServer server,
   /* Create the outgoing packet */
   silc_packet_assemble(&packetdata);
 
-  /* Compute MAC of the packet */
-  if (hmac) {
-    silc_hmac_make_with_key(hmac, sock->outbuf->data, sock->outbuf->len,
-                           hmac_key, hmac_key_len, mac);
-    silc_buffer_put_tail(sock->outbuf, mac, mac_len);
-    memset(mac, 0, sizeof(mac));
-  }
-
   /* Encrypt the packet */
   if (cipher)
-    silc_packet_encrypt(cipher, sock->outbuf, sock->outbuf->len);
-
-  /* Pull MAC into the visible data area */
-  if (hmac)
-    silc_buffer_pull_tail(sock->outbuf, mac_len);
+    silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
 
   SILC_LOG_HEXDUMP(("Outgoing packet, len %d", sock->outbuf->len),
                   sock->outbuf->data, sock->outbuf->len);
@@ -2099,10 +1681,6 @@ void silc_server_packet_forward(SilcServer server,
 {
   SilcCipher cipher = NULL;
   SilcHmac hmac = NULL;
-  unsigned char *hmac_key = NULL;
-  unsigned int hmac_key_len = 0;
-  unsigned char mac[32];
-  unsigned int mac_len = 0;
 
   SILC_LOG_DEBUG(("Forwarding packet"));
 
@@ -2110,25 +1688,15 @@ void silc_server_packet_forward(SilcServer server,
   switch(sock->type) {
   case SILC_SOCKET_TYPE_CLIENT:
     if (sock->user_data) {
-      cipher = ((SilcClientList *)sock->user_data)->send_key;
-      hmac = ((SilcClientList *)sock->user_data)->hmac;
-      if (hmac) {
-       mac_len = hmac->hash->hash->hash_len;
-       hmac_key = ((SilcClientList *)sock->user_data)->hmac_key;
-       hmac_key_len = ((SilcClientList *)sock->user_data)->hmac_key_len;
-      }
+      cipher = ((SilcClientEntry )sock->user_data)->send_key;
+      hmac = ((SilcClientEntry )sock->user_data)->hmac;
     }
     break;
   case SILC_SOCKET_TYPE_SERVER:
   case SILC_SOCKET_TYPE_ROUTER:
     if (sock->user_data) {
-      cipher = ((SilcServerList *)sock->user_data)->send_key;
-      hmac = ((SilcServerList *)sock->user_data)->hmac;
-      if (hmac) {
-       mac_len = hmac->hash->hash->hash_len;
-       hmac_key = ((SilcServerList *)sock->user_data)->hmac_key;
-       hmac_key_len = ((SilcServerList *)sock->user_data)->hmac_key_len;
-      }
+      cipher = ((SilcServerEntry )sock->user_data)->send_key;
+      hmac = ((SilcServerEntry )sock->user_data)->hmac;
     }
     break;
   default:
@@ -2138,7 +1706,7 @@ void silc_server_packet_forward(SilcServer server,
   }
 
   /* Prepare outgoing data buffer for packet sending */
-  silc_server_packet_send_prepare(server, sock, 0, 0, data_len);
+  silc_packet_send_prepare(sock, 0, 0, data_len);
 
   /* Mungle the packet flags and add the FORWARDED flag */
   if (data)
@@ -2148,21 +1716,9 @@ void silc_server_packet_forward(SilcServer server,
   if (data && data_len)
     silc_buffer_put(sock->outbuf, data, data_len);
 
-  /* Compute MAC of the packet */
-  if (hmac) {
-    silc_hmac_make_with_key(hmac, sock->outbuf->data, sock->outbuf->len,
-                           hmac_key, hmac_key_len, mac);
-    silc_buffer_put_tail(sock->outbuf, mac, mac_len);
-    memset(mac, 0, sizeof(mac));
-  }
-
   /* Encrypt the packet */
   if (cipher)
-    silc_packet_encrypt(cipher, sock->outbuf, sock->outbuf->len);
-
-  /* Pull MAC into the visible data area */
-  if (hmac)
-    silc_buffer_pull_tail(sock->outbuf, mac_len);
+    silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
 
   SILC_LOG_HEXDUMP(("Forwarded packet, len %d", sock->outbuf->len),
                   sock->outbuf->data, sock->outbuf->len);
@@ -2171,13 +1727,61 @@ void silc_server_packet_forward(SilcServer server,
   silc_server_packet_send_real(server, sock, force_send);
 }
 
+/* Internal routine to actually create the channel packet and send it
+   to network. This is common function in channel message sending. If
+   `channel_message' is TRUE this encrypts the message as it is strictly
+   a channel message. If FALSE normal encryption process is used. */
+
+static void
+silc_server_packet_send_to_channel_real(SilcServer server,
+                                       SilcSocketConnection sock,
+                                       SilcPacketContext *packet,
+                                       SilcCipher cipher,
+                                       SilcHmac hmac,
+                                       unsigned char *data,
+                                       unsigned int data_len,
+                                       int channel_message,
+                                       int force_send)
+{
+  packet->truelen = data_len + SILC_PACKET_HEADER_LEN + 
+    packet->src_id_len + packet->dst_id_len;
+
+  /* Prepare outgoing data buffer for packet sending */
+  silc_packet_send_prepare(sock, 
+                          SILC_PACKET_HEADER_LEN +
+                          packet->src_id_len + 
+                          packet->dst_id_len,
+                          packet->padlen,
+                          data_len);
+
+  packet->buffer = sock->outbuf;
+
+  /* Put the data to buffer, assemble and encrypt the packet. The packet
+     is encrypted with normal session key shared with the client. */
+  silc_buffer_put(sock->outbuf, data, data_len);
+  silc_packet_assemble(packet);
+  if (channel_message)
+    silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN + 
+                       packet->src_id_len + packet->dst_id_len +
+                       packet->padlen);
+  else
+    silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
+    
+  SILC_LOG_HEXDUMP(("Channel packet, len %d", sock->outbuf->len),
+                  sock->outbuf->data, sock->outbuf->len);
+
+  /* Now actually send the packet */
+  silc_server_packet_send_real(server, sock, force_send);
+}
+
 /* 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. */
 
 void silc_server_packet_send_to_channel(SilcServer server,
-                                       SilcChannelList *channel,
+                                       SilcChannelEntry channel,
+                                       SilcPacketType type,
                                        unsigned char *data,
                                        unsigned int data_len,
                                        int force_send)
@@ -2185,39 +1789,22 @@ void silc_server_packet_send_to_channel(SilcServer server,
   int i;
   SilcSocketConnection sock = NULL;
   SilcPacketContext packetdata;
-  SilcClientList *client = NULL;
-  SilcServerList **routed = NULL;
+  SilcClientEntry client = NULL;
+  SilcServerEntry *routed = NULL;
+  SilcChannelClientEntry chl;
   unsigned int routed_count = 0;
-  unsigned char *hmac_key = NULL;
-  unsigned int hmac_key_len = 0;
-  unsigned char mac[32];
-  unsigned int mac_len = 0;
   SilcCipher cipher;
   SilcHmac hmac;
-  SilcBuffer payload;
-
-  SILC_LOG_DEBUG(("Sending packet to channel"));
 
-  /* Generate IV */
-  for (i = 0; i < 16; i++)
-    channel->iv[i] = silc_rng_get_byte(server->rng);
-
-  /* Encode the channel payload */
-  payload = silc_channel_encode_payload(0, "", data_len, data, 
-                                       16, channel->iv, server->rng);
-  if (!payload)
+  /* This doesn't send channel message packets */
+  if (type == SILC_PACKET_CHANNEL_MESSAGE)
     return;
   
-  /* Encrypt payload of the packet. This is encrypted with the 
-     channel key. */
-  channel->channel_key->cipher->encrypt(channel->channel_key->context,
-                                       payload->data, payload->data,
-                                       payload->len - 16, /* -IV_LEN */
-                                       channel->iv);
+  SILC_LOG_DEBUG(("Sending packet to channel"));
 
   /* Set the packet context pointers. */
   packetdata.flags = 0;
-  packetdata.type = SILC_PACKET_CHANNEL_MESSAGE;
+  packetdata.type = type;
   packetdata.src_id = silc_id_id2str(server->id, SILC_ID_SERVER);
   packetdata.src_id_len = SILC_ID_SERVER_LEN;
   packetdata.src_id_type = SILC_ID_SERVER;
@@ -2225,71 +1812,33 @@ void silc_server_packet_send_to_channel(SilcServer server,
   packetdata.dst_id_len = SILC_ID_CHANNEL_LEN;
   packetdata.dst_id_type = SILC_ID_CHANNEL;
   packetdata.rng = server->rng;
-  packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
-                                         packetdata.src_id_len +
-                                         packetdata.dst_id_len));
+  packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
+    packetdata.src_id_len + packetdata.dst_id_len;
+  packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
 
   /* If there are global users in the channel we will send the message
      first to our router for further routing. */
   if (server->server_type == SILC_SERVER && !server->standalone &&
       channel->global_users) {
-    SilcServerList *router;
+    SilcServerEntry router;
 
     /* Get data used in packet header encryption, keys and stuff. */
     router = server->id_entry->router;
     sock = (SilcSocketConnection)router->connection;
     cipher = router->send_key;
     hmac = router->hmac;
-    mac_len = hmac->hash->hash->hash_len;
-    hmac_key = router->hmac_key;
-    hmac_key_len = router->hmac_key_len;
-    
-    SILC_LOG_DEBUG(("Sending packet to router for routing"));
-
-    packetdata.truelen = payload->len + SILC_PACKET_HEADER_LEN + 
-      packetdata.src_id_len + packetdata.dst_id_len;
-
-    /* Prepare outgoing data buffer for packet sending */
-    silc_server_packet_send_prepare(server, sock, 
-                                   SILC_PACKET_HEADER_LEN +
-                                   packetdata.src_id_len + 
-                                   packetdata.dst_id_len,
-                                   packetdata.padlen,
-                                   payload->len);
-    packetdata.buffer = sock->outbuf;
-
-    /* Put the original packet into the buffer. */
-    silc_buffer_put(sock->outbuf, payload->data, payload->len);
-    
-    /* Create the outgoing packet */
-    silc_packet_assemble(&packetdata);
-    
-    /* Compute MAC of the packet. MAC is computed from the header,
-       padding and the relayed packet. */
-    silc_hmac_make_with_key(hmac, sock->outbuf->data, sock->outbuf->len,
-                           hmac_key, hmac_key_len, mac);
-    silc_buffer_put_tail(sock->outbuf, mac, mac_len);
-    memset(mac, 0, sizeof(mac));
-
-    /* Encrypt the header and padding of the packet. This is encrypted 
-       with normal session key shared with the client. */
-    silc_packet_encrypt(cipher, sock->outbuf, SILC_PACKET_HEADER_LEN + 
-                       packetdata.src_id_len + packetdata.dst_id_len +
-                       packetdata.padlen);
     
-    /* Pull MAC into the visible data area */
-    silc_buffer_pull_tail(sock->outbuf, mac_len);
-    
-    SILC_LOG_HEXDUMP(("Channel packet, len %d", sock->outbuf->len),
-                    sock->outbuf->data, sock->outbuf->len);
+    SILC_LOG_DEBUG(("Sending channel message to router for routing"));
 
-    /* Now actually send the packet */
-    silc_server_packet_send_real(server, sock, force_send);
+    silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+                                           cipher, hmac, data,
+                                           data_len, FALSE, force_send);
   }
 
   /* Send the message to clients on the channel's client list. */
-  for (i = 0; i < channel->user_list_count; i++) {
-    client = channel->user_list[i].client;
+  silc_list_start(channel->user_list);
+  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+    client = chl->client;
 
     /* If client has router set it is not locally connected client and
        we will route the message to the router set in the client. */
@@ -2299,55 +1848,19 @@ void silc_server_packet_send_to_channel(SilcServer server,
       /* Check if we have sent the packet to this route already */
       for (k = 0; k < routed_count; k++)
        if (routed[k] == client->router)
-         continue;
+         break;
+      if (k < routed_count)
+       continue;
 
       /* Get data used in packet header encryption, keys and stuff. */
       sock = (SilcSocketConnection)client->router->connection;
       cipher = client->router->send_key;
       hmac = client->router->hmac;
-      mac_len = hmac->hash->hash->hash_len;
-      hmac_key = client->router->hmac_key;
-      hmac_key_len = client->router->hmac_key_len;
-      
-      packetdata.truelen = payload->len + SILC_PACKET_HEADER_LEN + 
-       packetdata.src_id_len + packetdata.dst_id_len;
-
-      /* Prepare outgoing data buffer for packet sending */
-      silc_server_packet_send_prepare(server, sock, 
-                                     SILC_PACKET_HEADER_LEN +
-                                     packetdata.src_id_len + 
-                                     packetdata.dst_id_len,
-                                     packetdata.padlen,
-                                     payload->len);
-      packetdata.buffer = sock->outbuf;
-
-      /* Put the encrypted payload data into the buffer. */
-      silc_buffer_put(sock->outbuf, payload->data, payload->len);
-      
-      /* Create the outgoing packet */
-      silc_packet_assemble(&packetdata);
-      
-      /* Compute MAC of the packet. MAC is computed from the header,
-        padding and the relayed packet. */
-      silc_hmac_make_with_key(hmac, sock->outbuf->data, sock->outbuf->len,
-                             hmac_key, hmac_key_len, mac);
-      silc_buffer_put_tail(sock->outbuf, mac, mac_len);
-      memset(mac, 0, sizeof(mac));
-
-      /* Encrypt the header and padding of the packet. This is encrypted 
-        with normal session key shared with the client. */
-      silc_packet_encrypt(cipher, sock->outbuf, SILC_PACKET_HEADER_LEN + 
-                         packetdata.src_id_len + packetdata.dst_id_len +
-                         packetdata.padlen);
-      
-      /* Pull MAC into the visible data area */
-      silc_buffer_pull_tail(sock->outbuf, mac_len);
-      
-      SILC_LOG_HEXDUMP(("Packet to channel, len %d", sock->outbuf->len),
-                      sock->outbuf->data, sock->outbuf->len);
 
-      /* Now actually send the packet */
-      silc_server_packet_send_real(server, sock, force_send);
+      /* Send the packet */
+      silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+                                             cipher, hmac, data,
+                                             data_len, FALSE, force_send);
 
       /* We want to make sure that the packet is routed to same router
         only once. Mark this route as sent route. */
@@ -2368,49 +1881,11 @@ void silc_server_packet_send_to_channel(SilcServer server,
       sock = (SilcSocketConnection)client->connection;
       cipher = client->send_key;
       hmac = client->hmac;
-      mac_len = hmac->hash->hash->hash_len;
-      hmac_key = client->hmac_key;
-      hmac_key_len = client->hmac_key_len;
-      
-      packetdata.truelen = payload->len + SILC_PACKET_HEADER_LEN + 
-       packetdata.src_id_len + packetdata.dst_id_len;
-
-      /* Prepare outgoing data buffer for packet sending */
-      silc_server_packet_send_prepare(server, sock, 
-                                     SILC_PACKET_HEADER_LEN +
-                                     packetdata.src_id_len + 
-                                     packetdata.dst_id_len,
-                                     packetdata.padlen,
-                                     payload->len);
-      packetdata.buffer = sock->outbuf;
-
-      /* Put the encrypted payload data into the buffer. */
-      silc_buffer_put(sock->outbuf, payload->data, payload->len);
-      
-      /* Create the outgoing packet */
-      silc_packet_assemble(&packetdata);
-      
-      /* Compute MAC of the packet. MAC is computed from the header,
-        padding and the relayed packet. */
-      silc_hmac_make_with_key(hmac, sock->outbuf->data, sock->outbuf->len,
-                             hmac_key, hmac_key_len, mac);
-      silc_buffer_put_tail(sock->outbuf, mac, mac_len);
-      memset(mac, 0, sizeof(mac));
-
-      /* Encrypt the header and padding of the packet. This is encrypted 
-        with normal session key shared with the client. */
-      silc_packet_encrypt(cipher, sock->outbuf, SILC_PACKET_HEADER_LEN + 
-                         packetdata.src_id_len + packetdata.dst_id_len +
-                         packetdata.padlen);
       
-      /* Pull MAC into the visible data area */
-      silc_buffer_pull_tail(sock->outbuf, mac_len);
-      
-      SILC_LOG_HEXDUMP(("Packet to channel, len %d", sock->outbuf->len),
-                      sock->outbuf->data, sock->outbuf->len);
-
-      /* Now actually send the packet */
-      silc_server_packet_send_real(server, sock, force_send);
+      /* Send the packet */
+      silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+                                             cipher, hmac, data,
+                                             data_len, FALSE, force_send);
     }
   }
 
@@ -2418,7 +1893,6 @@ void silc_server_packet_send_to_channel(SilcServer server,
     silc_free(routed);
   silc_free(packetdata.src_id);
   silc_free(packetdata.dst_id);
-  silc_buffer_free(payload);
 }
 
 /* This routine is explicitly used to relay messages to some channel.
@@ -2432,7 +1906,7 @@ void silc_server_packet_send_to_channel(SilcServer server,
 
 void silc_server_packet_relay_to_channel(SilcServer server,
                                         SilcSocketConnection sender_sock,
-                                        SilcChannelList *channel,
+                                        SilcChannelEntry channel,
                                         void *sender, 
                                         SilcIdType sender_type,
                                         unsigned char *data,
@@ -2442,20 +1916,15 @@ void silc_server_packet_relay_to_channel(SilcServer server,
   int i, found = FALSE;
   SilcSocketConnection sock = NULL;
   SilcPacketContext packetdata;
-  SilcClientList *client = NULL;
-  SilcServerList **routed = NULL;
+  SilcClientEntry client = NULL;
+  SilcServerEntry *routed = NULL;
+  SilcChannelClientEntry chl;
   unsigned int routed_count = 0;
-  unsigned char *hmac_key = NULL;
-  unsigned int hmac_key_len = 0;
-  unsigned char mac[32];
-  unsigned int mac_len = 0;
   SilcCipher cipher;
   SilcHmac hmac;
 
   SILC_LOG_DEBUG(("Relaying packet to channel"));
 
-  SILC_LOG_HEXDUMP(("XXX %d", data_len), data, data_len);
-
   /* Set the packet context pointers. */
   packetdata.flags = 0;
   packetdata.type = SILC_PACKET_CHANNEL_MESSAGE;
@@ -2474,7 +1943,7 @@ void silc_server_packet_relay_to_channel(SilcServer server,
      first to our router for further routing. */
   if (server->server_type == SILC_SERVER && !server->standalone &&
       channel->global_users) {
-    SilcServerList *router;
+    SilcServerEntry router;
 
     router = server->id_entry->router;
 
@@ -2485,57 +1954,19 @@ void silc_server_packet_relay_to_channel(SilcServer server,
       sock = (SilcSocketConnection)router->connection;
       cipher = router->send_key;
       hmac = router->hmac;
-      mac_len = hmac->hash->hash->hash_len;
-      hmac_key = router->hmac_key;
-      hmac_key_len = router->hmac_key_len;
-      
-      SILC_LOG_DEBUG(("Sending packet to router for routing"));
-      
-      packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
-       packetdata.src_id_len + packetdata.dst_id_len;
-      
-      /* Prepare outgoing data buffer for packet sending */
-      silc_server_packet_send_prepare(server, sock, 
-                                     SILC_PACKET_HEADER_LEN +
-                                     packetdata.src_id_len + 
-                                     packetdata.dst_id_len,
-                                     packetdata.padlen,
-                                     data_len);
-      packetdata.buffer = sock->outbuf;
-      
-      /* Put the original packet into the buffer. */
-      silc_buffer_put(sock->outbuf, data, data_len);
-      
-      /* Create the outgoing packet */
-      silc_packet_assemble(&packetdata);
-      
-      /* Compute MAC of the packet. MAC is computed from the header,
-        padding and the relayed packet. */
-      silc_hmac_make_with_key(hmac, sock->outbuf->data, sock->outbuf->len,
-                             hmac_key, hmac_key_len, mac);
-      silc_buffer_put_tail(sock->outbuf, mac, mac_len);
-      memset(mac, 0, sizeof(mac));
-      
-      /* Encrypt the header and padding of the packet. This is encrypted 
-        with normal session key shared with the client. */
-      silc_packet_encrypt(cipher, sock->outbuf, SILC_PACKET_HEADER_LEN + 
-                         packetdata.src_id_len + packetdata.dst_id_len +
-                         packetdata.padlen);
-      
-      /* Pull MAC into the visible data area */
-      silc_buffer_pull_tail(sock->outbuf, mac_len);
-      
-      SILC_LOG_HEXDUMP(("Channel packet, len %d", sock->outbuf->len),
-                      sock->outbuf->data, sock->outbuf->len);
-      
-      /* Now actually send the packet */
-      silc_server_packet_send_real(server, sock, force_send);
+
+      SILC_LOG_DEBUG(("Sending channel message to router for routing"));
+
+      silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+                                             cipher, hmac, data,
+                                             data_len, TRUE, force_send);
     }
   }
 
   /* Send the message to clients on the channel's client list. */
-  for (i = 0; i < channel->user_list_count; i++) {
-    client = channel->user_list[i].client;
+  silc_list_start(channel->user_list);
+  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+    client = chl->client;
 
     if (client) {
 
@@ -2546,8 +1977,7 @@ void silc_server_packet_relay_to_channel(SilcServer server,
       }
 
       /* If the client has set router it means that it is not locally
-        connected client and we won't send message to those in this
-        function (they will be routed separately by the caller). */
+        connected client and we will route the packet further. */
       if (server->server_type == SILC_ROUTER && client->router) {
        int k;
 
@@ -2561,55 +1991,19 @@ void silc_server_packet_relay_to_channel(SilcServer server,
        /* Check if we have sent the packet to this route already */
        for (k = 0; k < routed_count; k++)
          if (routed[k] == client->router)
-           continue;
+           break;
+       if (k < routed_count)
+         continue;
        
        /* Get data used in packet header encryption, keys and stuff. */
        sock = (SilcSocketConnection)client->router->connection;
        cipher = client->router->send_key;
        hmac = client->router->hmac;
-       mac_len = hmac->hash->hash->hash_len;
-       hmac_key = client->router->hmac_key;
-       hmac_key_len = client->router->hmac_key_len;
-       
-       packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
-         packetdata.src_id_len + packetdata.dst_id_len;
-       
-       /* Prepare outgoing data buffer for packet sending */
-       silc_server_packet_send_prepare(server, sock, 
-                                       SILC_PACKET_HEADER_LEN +
-                                       packetdata.src_id_len + 
-                                       packetdata.dst_id_len,
-                                       packetdata.padlen,
-                                       data_len);
-       packetdata.buffer = sock->outbuf;
-       
-       /* Put the original packet into the buffer. */
-       silc_buffer_put(sock->outbuf, data, data_len);
-       
-       /* Create the outgoing packet */
-       silc_packet_assemble(&packetdata);
-       
-       /* Compute MAC of the packet. MAC is computed from the header,
-          padding and the relayed packet. */
-       silc_hmac_make_with_key(hmac, sock->outbuf->data, sock->outbuf->len,
-                               hmac_key, hmac_key_len, mac);
-       silc_buffer_put_tail(sock->outbuf, mac, mac_len);
-       memset(mac, 0, sizeof(mac));
-       
-       /* Encrypt the header and padding of the packet. This is encrypted 
-          with normal session key shared with the client. */
-       silc_packet_encrypt(cipher, sock->outbuf, SILC_PACKET_HEADER_LEN + 
-                           packetdata.src_id_len + packetdata.dst_id_len +
-                           packetdata.padlen);
-       
-       /* Pull MAC into the visible data area */
-       silc_buffer_pull_tail(sock->outbuf, mac_len);
-       
-       SILC_LOG_HEXDUMP(("Packet to channel, len %d", sock->outbuf->len),
-                        sock->outbuf->data, sock->outbuf->len);
-       
-       /* Now actually send the packet */
-       silc_server_packet_send_real(server, sock, force_send);
+
+       /* Send the packet */
+       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+                                               cipher, hmac, data,
+                                               data_len, TRUE, force_send);
        
        /* We want to make sure that the packet is routed to same router
           only once. Mark this route as sent route. */
@@ -2620,60 +2014,21 @@ void silc_server_packet_relay_to_channel(SilcServer server,
        
        continue;
       }
-      
-      /* XXX Check client's mode on the channel. */
 
+      /* XXX Check client's mode on the channel. */
 
       /* Get data used in packet header encryption, keys and stuff. */
       sock = (SilcSocketConnection)client->connection;
       cipher = client->send_key;
       hmac = client->hmac;
-      mac_len = hmac->hash->hash->hash_len;
-      hmac_key = client->hmac_key;
-      hmac_key_len = client->hmac_key_len;
-      
+
       SILC_LOG_DEBUG(("Sending packet to client %s", 
                      sock->hostname ? sock->hostname : sock->ip));
 
-      packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
-       packetdata.src_id_len + packetdata.dst_id_len;
-
-      /* Prepare outgoing data buffer for packet sending */
-      silc_server_packet_send_prepare(server, sock, 
-                                     SILC_PACKET_HEADER_LEN +
-                                     packetdata.src_id_len + 
-                                     packetdata.dst_id_len,
-                                     packetdata.padlen,
-                                     data_len);
-      packetdata.buffer = sock->outbuf;
-
-      /* Put the original packet into the buffer. */
-      silc_buffer_put(sock->outbuf, data, data_len);
-      
-      /* Create the outgoing packet */
-      silc_packet_assemble(&packetdata);
-      
-      /* Compute MAC of the packet. MAC is computed from the header,
-        padding and the relayed packet. */
-      silc_hmac_make_with_key(hmac, sock->outbuf->data, sock->outbuf->len,
-                             hmac_key, hmac_key_len, mac);
-      silc_buffer_put_tail(sock->outbuf, mac, mac_len);
-      memset(mac, 0, sizeof(mac));
-
-      /* Encrypt the header and padding of the packet. This is encrypted 
-        with normal session key shared with the client. */
-      silc_packet_encrypt(cipher, sock->outbuf, SILC_PACKET_HEADER_LEN + 
-                         packetdata.src_id_len + packetdata.dst_id_len +
-                         packetdata.padlen);
-      
-      /* Pull MAC into the visible data area */
-      silc_buffer_pull_tail(sock->outbuf, mac_len);
-      
-      SILC_LOG_HEXDUMP(("Channel packet, len %d", sock->outbuf->len),
-                      sock->outbuf->data, sock->outbuf->len);
-
-      /* Now actually send the packet */
-      silc_server_packet_send_real(server, sock, force_send);
+      /* Send the packet */
+      silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+                                             cipher, hmac, data,
+                                             data_len, TRUE, force_send);
     }
   }
 
@@ -2681,6 +2036,44 @@ void silc_server_packet_relay_to_channel(SilcServer server,
   silc_free(packetdata.dst_id);
 }
 
+/* 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. 
+   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. */
+
+void silc_server_packet_send_local_channel(SilcServer server,
+                                          SilcChannelEntry channel,
+                                          SilcPacketType type,
+                                          SilcPacketFlags flags,
+                                          unsigned char *data,
+                                          unsigned int data_len,
+                                          int force_send)
+{
+  int i;
+  SilcClientEntry client;
+  SilcChannelClientEntry chl;
+  SilcSocketConnection sock = NULL;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  /* Send the message to clients on the channel's client list. */
+  silc_list_start(channel->user_list);
+  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+    client = chl->client;
+
+    if (client) {
+      sock = (SilcSocketConnection)client->connection;
+
+      /* Send the packet to the client */
+      silc_server_packet_send_dest(server, sock, type, flags, client->id,
+                                  SILC_ID_CLIENT, data, data_len,
+                                  force_send);
+    }
+  }
+}
+
 /* Relays received command reply packet to the correct destination. The
    destination must be one of our locally connected client or the packet
    will be ignored. This is called when server has forwarded one of
@@ -2692,19 +2085,15 @@ void silc_server_packet_relay_command_reply(SilcServer server,
                                            SilcPacketContext *packet)
 {
   SilcBuffer buffer = packet->buffer;
-  SilcClientList *client;
+  SilcClientEntry client;
   SilcClientID *id;
   SilcSocketConnection dst_sock;
-  unsigned char mac[32];
-  unsigned int mac_len = 0;
 
   SILC_LOG_DEBUG(("Start"));
 
   /* Source must be server or router */
-  /* XXX: actually it must be only router */
   if (packet->src_id_type != SILC_ID_SERVER &&
-      (sock->type != SILC_SOCKET_TYPE_SERVER ||
-       sock->type != SILC_SOCKET_TYPE_ROUTER))
+      sock->type != SILC_SOCKET_TYPE_ROUTER)
     goto out;
 
   /* Destination must be client */
@@ -2717,42 +2106,25 @@ void silc_server_packet_relay_command_reply(SilcServer server,
   id = silc_id_str2id(packet->dst_id, SILC_ID_CLIENT);
 
   /* Destination must be one of ours */
-  client = silc_idlist_find_client_by_id(server->local_list->clients, id);
+  client = silc_idlist_find_client_by_id(server->local_list, id);
   if (!client) {
     silc_free(id);
     goto out;
   }
 
   /* Relay the packet to the client */
-  if (client->hmac)
-    mac_len = client->hmac->hash->hash->hash_len;
 
   dst_sock = (SilcSocketConnection)client->connection;
-
   silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len 
                   + packet->dst_id_len + packet->padlen);
-  silc_server_packet_send_prepare(server, dst_sock, 0, 0, buffer->len);
+
+  silc_packet_send_prepare(dst_sock, 0, 0, buffer->len);
   silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
-  
-  /* Compute new HMAC */
-  if (client->hmac) {
-    memset(mac, 0, sizeof(mac));
-    silc_hmac_make_with_key(client->hmac, 
-                           dst_sock->outbuf->data, 
-                           dst_sock->outbuf->len,
-                           client->hmac_key, 
-                           client->hmac_key_len, 
-                           mac);
-    silc_buffer_put_tail(dst_sock->outbuf, mac, mac_len);
-    memset(mac, 0, sizeof(mac));
-  }
-    
-  /* Encrypt */
+
+  /* Encrypt packet */
   if (client && client->send_key)
-    silc_packet_encrypt(client->send_key, dst_sock->outbuf, buffer->len);
-    
-  if (client->hmac)
-    silc_buffer_pull_tail(dst_sock->outbuf, mac_len);
+    silc_packet_encrypt(client->send_key, client->hmac, 
+                       dst_sock->outbuf, buffer->len);
     
   /* Send the packet */
   silc_server_packet_send_real(server, dst_sock, FALSE);
@@ -2812,7 +2184,7 @@ void silc_server_disconnect_remote(SilcServer server,
 }
 
 /* Free's user_data pointer from socket connection object. As this 
-   pointer maybe anything we wil switch here to find the corrent
+   pointer maybe anything we wil switch here to find the correct
    data type and free it the way it needs to be free'd. */
 
 void silc_server_free_sock_user_data(SilcServer server, 
@@ -2820,26 +2192,17 @@ void silc_server_free_sock_user_data(SilcServer server,
 {
   SILC_LOG_DEBUG(("Start"));
 
-#define LCC(x) server->local_list->client_cache[(x) - 32]
-#define LCCC(x) server->local_list->client_cache_count[(x) - 32]
-
   switch(sock->type) {
   case SILC_SOCKET_TYPE_CLIENT:
     {
-      SilcClientList *user_data = (SilcClientList *)sock->user_data;
+      SilcClientEntry user_data = (SilcClientEntry )sock->user_data;
 
       /* Remove client from all channels */
       silc_server_remove_from_channels(server, sock, user_data);
 
-      /* Clear ID cache */
-      if (user_data->nickname && user_data->id)
-       silc_idcache_del_by_id(LCC(user_data->nickname[0]),
-                              LCCC(user_data->nickname[0]),
-                              SILC_ID_CLIENT, user_data->id);
-
       /* Free the client entry and everything in it */
       /* XXX must take some info to history before freeing */
-      silc_idlist_del_client(&server->local_list->clients, user_data);
+      silc_idlist_del_client(server->local_list, user_data);
       break;
     }
   case SILC_SOCKET_TYPE_SERVER:
@@ -2851,7 +2214,7 @@ void silc_server_free_sock_user_data(SilcServer server,
     break;
   default:
     {
-      SilcIDListUnknown *user_data = (SilcIDListUnknown *)sock->user_data;
+      SilcUnknownEntry user_data = (SilcUnknownEntry)sock->user_data;
 
       if (user_data->send_key)
        silc_cipher_free(user_data->send_key);
@@ -2880,13 +2243,19 @@ void silc_server_free_sock_user_data(SilcServer server,
 
 void silc_server_remove_from_channels(SilcServer server, 
                                      SilcSocketConnection sock,
-                                     SilcClientList *client)
+                                     SilcClientEntry client)
 {
   int i, k;
-  SilcChannelList *channel;
+  SilcChannelEntry channel;
+  SilcChannelClientEntry chl;
+  SilcBuffer chidp, clidp;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  if (!client || !client->id)
+    return;
 
-#define LCC(x) server->local_list->channel_cache[(x) - 32]
-#define LCCC(x) server->local_list->channel_cache_count[(x) - 32]
+  clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
 
   /* Remove the client from all channels. The client is removed from
      the channels' user list. */
@@ -2895,39 +2264,135 @@ void silc_server_remove_from_channels(SilcServer server,
     if (!channel)
       continue;
 
+    chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+
     /* Remove from channel */
-    for (k = 0; k < channel->user_list_count; k++) {
-      if (channel->user_list[k].client == client) {
+    silc_list_start(channel->user_list);
+    while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+      if (chl->client == client) {
 
        /* If this client is last one on the channel the channel
           is removed all together. */
-       if (channel->user_list_count == 1) {
-         silc_idcache_del_by_id(LCC(channel->channel_name[0]),
-                                LCCC(channel->channel_name[0]),
-                                SILC_ID_CHANNEL, channel->id);
-         silc_idlist_del_channel(&server->local_list->channels, channel);
+       if (silc_list_count(channel->user_list) == 1) {
+
+         /* However, if the channel has marked global users then the 
+            channel is not created locally, and this does not remove the
+            channel globally from SILC network, in this case we will
+            notify that this client has left the channel. */
+         if (channel->global_users)
+           silc_server_send_notify_to_channel(server, channel,
+                                              SILC_NOTIFY_TYPE_SIGNOFF, 1,
+                                              clidp->data, clidp->len);
+
+         silc_idlist_del_channel(server->local_list, channel);
          break;
        }
 
-       channel->user_list[k].client = NULL;
-       channel->user_list[k].mode = SILC_CHANNEL_UMODE_NONE;
+       silc_list_del(channel->user_list, chl);
+       silc_free(chl);
 
-       /* XXX */
        /* Send notify to channel about client leaving SILC and thus
           the entire channel. */
        silc_server_send_notify_to_channel(server, channel,
-                                          "%s has left channel %s",
-                                          client->nickname,
-                                          channel->channel_name);
+                                          SILC_NOTIFY_TYPE_SIGNOFF, 1,
+                                          clidp->data, clidp->len);
       }
     }
+
+    silc_buffer_free(chidp);
   }
 
   if (client->channel_count)
     silc_free(client->channel);
   client->channel = NULL;
-#undef LCC
-#undef LCCC
+  silc_buffer_free(clidp);
+}
+
+/* Removes client from one channel. This is used for example when client
+   calls LEAVE command to remove itself from the channel. Returns TRUE
+   if channel still exists and FALSE if the channel is removed when
+   last client leaves the channel. If `notify' is FALSE notify messages
+   are not sent. */
+
+int silc_server_remove_from_one_channel(SilcServer server, 
+                                       SilcSocketConnection sock,
+                                       SilcChannelEntry channel,
+                                       SilcClientEntry client,
+                                       int notify)
+{
+  int i, k;
+  SilcChannelEntry ch;
+  SilcChannelClientEntry chl;
+  SilcBuffer clidp;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+
+  /* Remove the client from the channel. The client is removed from
+     the channel's user list. */
+  for (i = 0; i < client->channel_count; i++) {
+    ch = client->channel[i];
+    if (!ch || ch != channel)
+      continue;
+
+    client->channel[i] = NULL;
+
+    /* Remove from channel */
+    silc_list_start(channel->user_list);
+    while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+      if (chl->client == client) {
+       
+       /* If this client is last one on the channel the channel
+          is removed all together. */
+       if (silc_list_count(channel->user_list) == 1) {
+         /* Notify about leaving client if this channel has global users,
+            ie. the channel is not created locally. */
+         if (notify && channel->global_users)
+           silc_server_send_notify_to_channel(server, channel,
+                                              SILC_NOTIFY_TYPE_LEAVE, 1,
+                                              clidp->data, clidp->len);
+
+         silc_idlist_del_channel(server->local_list, channel);
+         silc_buffer_free(clidp);
+         return FALSE;
+       }
+       
+       silc_list_del(channel->user_list, chl);
+       silc_free(chl);
+
+       /* Send notify to channel about client leaving the channel */
+       if (notify)
+         silc_server_send_notify_to_channel(server, channel,
+                                            SILC_NOTIFY_TYPE_LEAVE, 1,
+                                            clidp->data, clidp->len);
+      }
+    }
+  }
+
+  silc_buffer_free(clidp);
+  return TRUE;
+}
+
+/* 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 
+   `client' which is faster than checking the user list from `channel'. */
+
+int silc_server_client_on_channel(SilcClientEntry client,
+                                 SilcChannelEntry channel)
+{
+  int i;
+
+  if (!client || !channel)
+    return FALSE;
+
+  for (i = 0; i < client->channel_count; i++) {
+    if (client->channel[i] == channel)
+      return TRUE;
+  }
+
+  return FALSE;
 }
 
 /* Timeout callback. This is called if connection is idle or for some
@@ -2945,114 +2410,37 @@ SILC_TASK_CALLBACK(silc_server_timeout_remote)
 }
 
 /* Internal routine used to send (relay, route) private messages to some
-   destination. This is used to by normal server to send the message to
-   its primary route and router uses this to send it to any route it
-   wants. If the private message key does not exist then the message
+   destination. If the private message key does not exist then the message
    is re-encrypted, otherwise we just pass it along. */
+
 static void 
 silc_server_private_message_send_internal(SilcServer server,
                                          SilcSocketConnection dst_sock,
-                                         SilcServerList *router,
+                                         SilcCipher cipher,
+                                         SilcHmac hmac,
                                          SilcPacketContext *packet)
 {
   SilcBuffer buffer = packet->buffer;
 
   /* Send and re-encrypt if private messge key does not exist */
   if ((packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY) == FALSE) {
-    unsigned char mac[32];
-    unsigned int mac_len = 0;
-    
-    if (router->hmac)
-      mac_len = router->hmac->hash->hash->hash_len;
-    
-    silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len 
-                    + packet->dst_id_len + packet->padlen);
-    silc_server_packet_send_prepare(server, dst_sock, 0, 0, buffer->len);
-    silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
-    
-    /* Compute new HMAC */
-    if (router->hmac) {
-      mac_len = router->hmac->hash->hash->hash_len;
-      memset(mac, 0, sizeof(mac));
-      silc_hmac_make_with_key(router->hmac, 
-                             dst_sock->outbuf->data, 
-                             dst_sock->outbuf->len,
-                             router->hmac_key, 
-                             router->hmac_key_len, 
-                             mac);
-      silc_buffer_put_tail(dst_sock->outbuf, mac, mac_len);
-      memset(mac, 0, sizeof(mac));
-    }
-    
-    silc_packet_encrypt(router->send_key, dst_sock->outbuf, buffer->len);
-    
-    if (router->hmac)
-      silc_buffer_pull_tail(dst_sock->outbuf, mac_len);
-    
-    /* Send the packet */
-    silc_server_packet_send_real(server, dst_sock, FALSE);
-
-  } else {
-    /* Key exist so just send it */
-    silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len 
-                    + packet->dst_id_len + packet->padlen);
-    silc_server_packet_send_prepare(server, dst_sock, 0, 0, buffer->len);
-    silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
-    silc_server_packet_send_real(server, dst_sock, FALSE);
-  }
-}
-
-/* Internal routine to send the received private message packet to
-   our locally connected client. */
-static void
-silc_server_private_message_send_local(SilcServer server,
-                                      SilcSocketConnection dst_sock,
-                                      SilcClientList *client,
-                                      SilcPacketContext *packet)
-{
-  SilcBuffer buffer = packet->buffer;
-
-  /* Re-encrypt packet if needed */
-  if ((packet->flags & SILC_PACKET_FLAG_PRIVMSG_KEY) == FALSE) {
-    unsigned char mac[32];
-    unsigned int mac_len = 0;
 
-    if (client->hmac)
-      mac_len = client->hmac->hash->hash->hash_len;
-    
     silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len 
                     + packet->dst_id_len + packet->padlen);
-    silc_server_packet_send_prepare(server, dst_sock, 0, 0, buffer->len);
+    silc_packet_send_prepare(dst_sock, 0, 0, buffer->len);
     silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
     
-    /* Compute new HMAC */
-    if (client->hmac) {
-      memset(mac, 0, sizeof(mac));
-      silc_hmac_make_with_key(client->hmac, 
-                             dst_sock->outbuf->data, 
-                             dst_sock->outbuf->len,
-                             client->hmac_key, 
-                             client->hmac_key_len, 
-                             mac);
-      silc_buffer_put_tail(dst_sock->outbuf, mac, mac_len);
-      memset(mac, 0, sizeof(mac));
-    }
-    
-    /* Encrypt */
-    if (client && client->send_key)
-      silc_packet_encrypt(client->send_key, dst_sock->outbuf, 
-                         buffer->len);
-    
-    if (client->hmac)
-      silc_buffer_pull_tail(dst_sock->outbuf, mac_len);
+    /* Re-encrypt packet */
+    silc_packet_encrypt(cipher, hmac, dst_sock->outbuf, buffer->len);
     
     /* Send the packet */
     silc_server_packet_send_real(server, dst_sock, FALSE);
+
   } else {
     /* Key exist so just send it */
     silc_buffer_push(buffer, SILC_PACKET_HEADER_LEN + packet->src_id_len 
                     + packet->dst_id_len + packet->padlen);
-    silc_server_packet_send_prepare(server, dst_sock, 0, 0, buffer->len);
+    silc_packet_send_prepare(dst_sock, 0, 0, buffer->len);
     silc_buffer_put(dst_sock->outbuf, buffer->data, buffer->len);
     silc_server_packet_send_real(server, dst_sock, FALSE);
   }
@@ -3070,31 +2458,27 @@ void silc_server_private_message(SilcServer server,
 {
   SilcBuffer buffer = packet->buffer;
   SilcClientID *id;
-  SilcServerList *router;
+  SilcServerEntry router;
   SilcSocketConnection dst_sock;
-  SilcClientList *client;
+  SilcClientEntry client;
 
   SILC_LOG_DEBUG(("Start"));
 
   if (!packet->dst_id) {
-    SILC_LOG_DEBUG(("Bad Client ID in private message packet"));
+    SILC_LOG_ERROR(("Bad Client ID in private message packet, dropped"));
     goto err;
   }
 
   /* Decode destination Client ID */
   id = silc_id_str2id(packet->dst_id, SILC_ID_CLIENT);
   if (!id) {
-    SILC_LOG_DEBUG(("Could not decode destination Client ID"));
+    SILC_LOG_ERROR(("Could not decode destination Client ID, dropped"));
     goto err;
   }
 
   /* If the destination belongs to our server we don't have to route
      the message anywhere but to send it to the local destination. */
-  /* XXX: Should use local cache to search but the current idcache system
-     is so sucky that it cannot be used... it MUST be rewritten! Using
-     this search is probably faster than if we'd use here the current
-     idcache system. */
-  client =  silc_idlist_find_client_by_id(server->local_list->clients, id);
+  client = silc_idlist_find_client_by_id(server->local_list, id);
   if (client) {
     /* It exists, now deliver the message to the destination */
     dst_sock = (SilcSocketConnection)client->connection;
@@ -3102,13 +2486,23 @@ void silc_server_private_message(SilcServer server,
     /* If we are router and the client has router then the client is in
        our cell but not directly connected to us. */
     if (server->server_type == SILC_ROUTER && client->router) {
+      /* We are of course in this case the client's router thus the real
+        "router" of the client is the server who owns the client. Thus
+        we will send the packet to that server. */
+      router = (SilcServerEntry)dst_sock->user_data;
+      //      assert(client->router == server->id_entry);
+
       silc_server_private_message_send_internal(server, dst_sock,
-                                               client->router, packet);
+                                               router->send_key,
+                                               router->hmac,
+                                               packet);
       goto out;
     }
 
     /* Seems that client really is directly connected to us */
-    silc_server_private_message_send_local(server, dst_sock, client, packet);
+    silc_server_private_message_send_internal(server, dst_sock, 
+                                             client->send_key,
+                                             client->hmac, packet);
     goto out;
   }
 
@@ -3116,31 +2510,29 @@ void silc_server_private_message(SilcServer server,
      server our action is to send the packet to our router. */
   if (server->server_type == SILC_SERVER && !server->standalone) {
     router = server->id_entry->router;
-    dst_sock = (SilcSocketConnection)router->connection;
 
     /* Send to primary route */
-    silc_server_private_message_send_internal(server, dst_sock, router,
-                                             packet);
-    goto out;
-  }
+    if (router) {
+      dst_sock = (SilcSocketConnection)router->connection;
+      silc_server_private_message_send_internal(server, dst_sock, 
+                                               router->send_key,
+                                               router->hmac, packet);
+    }
+    goto out;
+  }
 
   /* We are router and we will perform route lookup for the destination 
-     and send the message to the correct route. */
+     and send the message to fastest route. */
   if (server->server_type == SILC_ROUTER && !server->standalone) {
+    dst_sock = silc_server_get_route(server, id, SILC_ID_CLIENT);
+    router = (SilcServerEntry)dst_sock->user_data;
 
-    /* If we don't have specific route for the destination we will send
-       it to our primary route (default route). */
-    router = silc_server_route_check(id->ip.s_addr, server->id->port);
-    if (router) {
-      dst_sock = (SilcSocketConnection)router->connection;
-    } else {
-      router = server->id_entry->router;
-      dst_sock = (SilcSocketConnection)router->connection;
-    }
+    /* Get fastest route and send packet. */
+    if (router)
+      silc_server_private_message_send_internal(server, dst_sock, 
+                                               router->send_key,
+                                               router->hmac, packet);
 
-    /* Send packet */
-    silc_server_private_message_send_internal(server, dst_sock, 
-                                             router, packet);
     goto out;
   }
 
@@ -3151,43 +2543,22 @@ void silc_server_private_message(SilcServer server,
   silc_buffer_free(buffer);
 }
 
-SilcChannelList *silc_find_channel(SilcServer server, SilcChannelID *id)
-{
-  int i;
-  SilcIDCache *id_cache;
-
-#define LCC(x) server->local_list->channel_cache[(x)]
-#define LCCC(x) server->local_list->channel_cache_count[(x)]
-
-  for (i = 0; i < 96; i++) {
-    if (LCC(i) == NULL)
-      continue;
-    if (silc_idcache_find_by_id(LCC(i), LCCC(i), (void *)id, 
-                               SILC_ID_CHANNEL, &id_cache))
-      return (SilcChannelList *)id_cache->context;
-  }
-  
-  return NULL;
-#undef LCC
-#undef LCCC
-}
-
-/* Process received channel message. */
+/* Process received channel message. The message can be originated from
+   client or server. */
 
 void silc_server_channel_message(SilcServer server,
                                 SilcSocketConnection sock,
                                 SilcPacketContext *packet)
 {
-  SilcChannelList *channel = NULL;
+  SilcChannelEntry channel = NULL;
+  SilcChannelClientEntry chl;
+  SilcClientEntry client = NULL;
   SilcChannelID *id = NULL;
-  SilcClientID *sender;
+  void *sender = NULL;
   SilcBuffer buffer = packet->buffer;
+  int i;
 
   SILC_LOG_DEBUG(("Processing channel message"));
-  
-  /* Check MAC */
-  if (!silc_server_packet_check_mac(server, sock, buffer))
-    goto out;
 
   /* Sanity checks */
   if (packet->dst_id_type != SILC_ID_CHANNEL) {
@@ -3196,28 +2567,49 @@ void silc_server_channel_message(SilcServer server,
     goto out;
   }
 
-  /* Send to local clients */
+  /* Find channel entry */
   id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
-  channel = silc_find_channel(server, id);
+  channel = silc_idlist_find_channel_by_id(server->local_list, id);
   if (!channel) {
     SILC_LOG_DEBUG(("Could not find channel"));
     goto out;
   }
 
+  /* See that this client is on the channel. If the message is coming
+     from router we won't do the check as the message is from client that
+     we don't know about. Also, if the original sender is not client
+     (as it can be server as well) we don't do the check. */
+  sender = silc_id_str2id(packet->src_id, packet->src_id_type);
+  if (sock->type != SILC_SOCKET_TYPE_ROUTER && 
+      packet->src_id_type == SILC_ID_CLIENT) {
+    silc_list_start(channel->user_list);
+    while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+      if (chl->client && !SILC_ID_CLIENT_COMPARE(chl->client->id, sender))
+       break;
+    }
+    if (chl == SILC_LIST_END)
+      goto out;
+  }
+
   /* Distribute the packet to our local clients. This will send the
      packet for further routing as well, if needed. */
-  sender = silc_id_str2id(packet->src_id, packet->src_id_type);
   silc_server_packet_relay_to_channel(server, sock, channel, sender,
                                      packet->src_id_type,
                                      packet->buffer->data,
                                      packet->buffer->len, FALSE);
 
  out:
+  if (sender)
+    silc_free(sender);
+  if (id)
+    silc_free(id);
   silc_buffer_free(buffer);
 }
 
 /* Received channel key packet. We distribute the key to all of our locally
-   connected clients on the channel. Router ignores the packet. */
+   connected clients on the channel. */
+/* XXX Router must accept this packet and distribute the key to all its
+   server that has clients on the channel */
 
 void silc_server_channel_key(SilcServer server,
                             SilcSocketConnection sock,
@@ -3226,57 +2618,59 @@ void silc_server_channel_key(SilcServer server,
   SilcBuffer buffer = packet->buffer;
   SilcChannelKeyPayload payload = NULL;
   SilcChannelID *id = NULL;
-  SilcChannelList *channel;
-  SilcClientList *client;
-  unsigned char *key;
-  unsigned int key_len;
+  SilcChannelEntry channel;
+  SilcChannelClientEntry chl;
+  SilcClientEntry client;
+  unsigned char *tmp;
+  unsigned int tmp_len;
   char *cipher;
   int i;
 
-  if (server->server_type == SILC_ROUTER)
-    goto out;
-
   if (packet->src_id_type != SILC_ID_SERVER &&
       sock->type != SILC_SOCKET_TYPE_ROUTER)
     goto out;
 
   /* Decode channel key payload */
-  payload = silc_channel_key_parse_payload(buffer);
+  payload = silc_channel_key_payload_parse(buffer);
   if (!payload) {
     SILC_LOG_ERROR(("Bad channel key payload, dropped"));
-    SILC_LOG_DEBUG(("Bad channel key payload, dropped"));
+    goto out;
   }
 
   /* Get channel ID */
-  id = silc_id_str2id(silc_channel_key_get_id(payload, NULL), SILC_ID_CHANNEL);
+  tmp = silc_channel_key_get_id(payload, &tmp_len);
+  id = silc_id_payload_parse_id(tmp, tmp_len);
   if (!id)
     goto out;
 
   /* Get the channel entry */
-  channel = silc_idlist_find_channel_by_id(server->local_list->channels, id);
+  channel = silc_idlist_find_channel_by_id(server->local_list, id);
   if (!channel) {
     SILC_LOG_ERROR(("Received key for non-existent channel"));
-    SILC_LOG_DEBUG(("Received key for non-existent channel"));
     goto out;
   }
 
   /* Save the key for us as well */
-  key = silc_channel_key_get_key(payload, &key_len);
-  if (!key)
+  tmp = silc_channel_key_get_key(payload, &tmp_len);
+  if (!tmp)
     goto out;
   cipher = silc_channel_key_get_cipher(payload, NULL);;
   if (!cipher)
     goto out;
-  channel->key_len = key_len;
-  channel->key = silc_calloc(key_len, sizeof(unsigned char));
-  memcpy(channel->key, key, key_len);
-  silc_cipher_alloc(cipher, &channel->channel_key);
+  if (!silc_cipher_alloc(cipher, &channel->channel_key))
+    goto out;
+
+  channel->key_len = tmp_len * 8;
+  channel->key = silc_calloc(tmp_len, sizeof(unsigned char));
+  memcpy(channel->key, tmp, tmp_len);
   channel->channel_key->cipher->set_key(channel->channel_key->context, 
-                                       key, key_len);
+                                       tmp, tmp_len);
 
   /* Distribute the key to all clients on the channel */
-  for (i = 0; i < channel->user_list_count; i++) {
-    client = channel->user_list[i].client;
+  /* XXX Some other sender should be used, I think this is not correct */
+  silc_list_start(channel->user_list);
+  while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+    client = chl->client;
 
     if (client)
       silc_server_packet_send_dest(server, client->connection,
@@ -3289,10 +2683,31 @@ void silc_server_channel_key(SilcServer server,
   if (id)
     silc_free(id);
   if (payload)
-    silc_channel_key_free_payload(payload);
+    silc_channel_key_payload_free(payload);
   silc_buffer_free(buffer);
 }
 
+/* Sends current motd to client */
+
+void silc_server_send_motd(SilcServer server,
+                          SilcSocketConnection sock)
+{
+  char *motd;
+  int motd_len;
+
+  if (server->config && server->config->motd && 
+      server->config->motd->motd_file) {
+
+    motd = silc_file_read(server->config->motd->motd_file, &motd_len);
+    if (!motd)
+      return;
+
+    silc_server_send_notify(server, sock, SILC_NOTIFY_TYPE_MOTD, 1,
+                           motd, motd_len);
+    silc_free(motd);
+  }
+}
+
 /* Sends error message. Error messages may or may not have any 
    implications. */
 
@@ -3312,41 +2727,207 @@ void silc_server_send_error(SilcServer server,
                          buf, strlen(buf), FALSE);
 }
 
-/* Sends notify message */
+/* Sends notify message. If format is TRUE the variable arguments are
+   formatted and the formatted string is sent as argument payload. If it is
+   FALSE then each argument is sent as separate argument and their format
+   in the argument list must be { argument data, argument length }. */
 
 void silc_server_send_notify(SilcServer server,
                             SilcSocketConnection sock,
-                            const char *fmt, ...)
+                            SilcNotifyType type,
+                            unsigned int argc, ...)
 {
   va_list ap;
-  unsigned char buf[4096];
+  SilcBuffer packet;
 
-  memset(buf, 0, sizeof(buf));
-  va_start(ap, fmt);
-  vsprintf(buf, fmt, ap);
-  va_end(ap);
+  va_start(ap, argc);
 
+  packet = silc_notify_payload_encode(type, argc, ap);
   silc_server_packet_send(server, sock, SILC_PACKET_NOTIFY, 0, 
-                         buf, strlen(buf), FALSE);
+                         packet->data, packet->len, FALSE);
+  silc_buffer_free(packet);
+}
+
+/* Sends notify message destined to specific entity. */
+
+void silc_server_send_notify_dest(SilcServer server,
+                                 SilcSocketConnection sock,
+                                 void *dest_id,
+                                 SilcIdType dest_id_type,
+                                 SilcNotifyType type,
+                                 unsigned int argc, ...)
+{
+  va_list ap;
+  SilcBuffer packet;
+
+  va_start(ap, argc);
+
+  packet = silc_notify_payload_encode(type, argc, ap);
+  silc_server_packet_send_dest(server, sock, SILC_PACKET_NOTIFY, 0, 
+                              dest_id, dest_id_type,
+                              packet->data, packet->len, FALSE);
+  silc_buffer_free(packet);
 }
 
 /* Sends notify message to a channel. The notify message sent is 
    distributed to all clients on the channel. */
 
 void silc_server_send_notify_to_channel(SilcServer server,
-                                       SilcChannelList *channel,
-                                       const char *fmt, ...)
+                                       SilcChannelEntry channel,
+                                       SilcNotifyType type,
+                                       unsigned int argc, ...)
 {
   va_list ap;
-  unsigned char buf[4096];
+  SilcBuffer packet;
 
-  memset(buf, 0, sizeof(buf));
-  va_start(ap, fmt);
-  vsprintf(buf, fmt, ap);
-  va_end(ap);
+  va_start(ap, argc);
+
+  packet = silc_notify_payload_encode(type, argc, ap);
+  silc_server_packet_send_to_channel(server, channel, 
+                                    SILC_PACKET_NOTIFY,
+                                    packet->data, packet->len, FALSE);
+  silc_buffer_free(packet);
+}
+
+/* Send notify message to all clients the client has joined. It is quaranteed
+   that the message is sent only once to a client (ie. if a client is joined
+   on two same channel it will receive only one notify message). Also, this
+   sends only to local clients (locally connected if we are server, and to
+   local servers if we are router). */
+
+void silc_server_send_notify_on_channels(SilcServer server,
+                                        SilcClientEntry client,
+                                        SilcNotifyType type,
+                                        unsigned int argc, ...)
+{
+  int i, j, k;
+  SilcSocketConnection sock = NULL;
+  SilcPacketContext packetdata;
+  SilcClientEntry c;
+  SilcClientEntry *sent_clients = NULL;
+  unsigned int sent_clients_count = 0;
+  SilcServerEntry *routed = NULL;
+  unsigned int routed_count = 0;
+  SilcChannelEntry channel;
+  SilcChannelClientEntry chl;
+  SilcCipher cipher;
+  SilcHmac hmac;
+  SilcBuffer packet;
+  unsigned char *data;
+  unsigned int data_len;
+  int force_send = FALSE;
+  va_list ap;
+
+  if (!client->channel_count)
+    return;
+
+  va_start(ap, argc);
+  packet = silc_notify_payload_encode(type, argc, ap);
+  data = packet->data;
+  data_len = packet->len;
+
+  /* Set the packet context pointers. */
+  packetdata.flags = 0;
+  packetdata.type = SILC_PACKET_NOTIFY;
+  packetdata.src_id = silc_id_id2str(server->id, SILC_ID_SERVER);
+  packetdata.src_id_len = SILC_ID_SERVER_LEN;
+  packetdata.src_id_type = SILC_ID_SERVER;
+  packetdata.rng = server->rng;
+
+  for (i = 0; i < client->channel_count; i++) {
+    channel = client->channel[i];
+
+    if (!channel)
+      continue;
+
+    /* Send the message to clients on the channel's client list. */
+    silc_list_start(channel->user_list);
+    while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+      c = chl->client;
+      
+      /* Check if we have sent the packet to this client already */
+      for (k = 0; k < sent_clients_count; k++)
+       if (sent_clients[k] == c)
+         break;
+      if (k < sent_clients_count)
+       continue;
 
-  silc_server_packet_send_to_channel(server, channel, buf, 
-                                    strlen(buf), FALSE);
+      /* If we are router and if this client has router set it is not
+        locally connected client and we will route the message to the
+        router set in the client. */
+      if (c && c->router && server->server_type == SILC_ROUTER) {
+       /* Check if we have sent the packet to this route already */
+       for (k = 0; k < routed_count; k++)
+         if (routed[k] == c->router)
+           break;
+       if (k < routed_count)
+         continue;
+       
+       /* Get data used in packet header encryption, keys and stuff. */
+       sock = (SilcSocketConnection)c->router->connection;
+       cipher = c->router->send_key;
+       hmac = c->router->hmac;
+       
+       packetdata.dst_id = silc_id_id2str(c->router->id, SILC_ID_SERVER);
+       packetdata.dst_id_len = SILC_ID_SERVER_LEN;
+       packetdata.dst_id_type = SILC_ID_SERVER;
+       packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
+         packetdata.src_id_len + packetdata.dst_id_len;
+       packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
+
+       /* Send the packet */
+       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+                                               cipher, hmac, data,
+                                               data_len, FALSE, force_send);
+       
+       silc_free(packetdata.dst_id);
+
+       /* We want to make sure that the packet is routed to same router
+          only once. Mark this route as sent route. */
+       k = routed_count;
+       routed = silc_realloc(routed, sizeof(*routed) * (k + 1));
+       routed[k] = c->router;
+       routed_count++;
+
+       continue;
+      }
+
+      /* Send to locally connected client */
+      if (c) {
+       
+       /* Get data used in packet header encryption, keys and stuff. */
+       sock = (SilcSocketConnection)c->connection;
+       cipher = c->send_key;
+       hmac = c->hmac;
+       
+       packetdata.dst_id = silc_id_id2str(c->id, SILC_ID_CLIENT);
+       packetdata.dst_id_len = SILC_ID_CLIENT_LEN;
+       packetdata.dst_id_type = SILC_ID_CLIENT;
+       packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
+         packetdata.src_id_len + packetdata.dst_id_len;
+       packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
+
+       /* Send the packet */
+       silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+                                               cipher, hmac, 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_count + 1));
+       sent_clients[sent_clients_count] = c;
+       sent_clients_count++;
+      }
+    }
+  }
+
+  if (routed_count)
+    silc_free(routed);
+  if (sent_clients_count)
+    silc_free(sent_clients);
+  silc_free(packetdata.src_id);
 }
 
 /* Sends New ID Payload to remote end. The packet is used to distribute
@@ -3361,26 +2942,13 @@ void silc_server_send_new_id(SilcServer server,
                             void *id, SilcIdType id_type, 
                             unsigned int id_len)
 {
-  SilcBuffer packet;
-  unsigned char *id_string;
-
-  id_string = silc_id_id2str(id, id_type);
-  if (!id_string)
-    return;
-
-  packet = silc_buffer_alloc(2 + 2 + id_len);
-  silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
-  silc_buffer_format(packet,
-                    SILC_STR_UI_SHORT(id_type),
-                    SILC_STR_UI_SHORT(id_len),
-                    SILC_STR_UI_XNSTRING(id_string, id_len),
-                    SILC_STR_END);
+  SilcBuffer idp;
 
+  idp = silc_id_payload_encode(id, id_type);
   silc_server_packet_send(server, sock, SILC_PACKET_NEW_ID, 
                          broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, 
-                         packet->data, packet->len, FALSE);
-  silc_free(id_string);
-  silc_buffer_free(packet);
+                         idp->data, idp->len, FALSE);
+  silc_buffer_free(idp);
 }
 
 /* Sends Replace ID payload to remote end. This is used to replace old
@@ -3430,24 +2998,135 @@ void silc_server_send_replace_id(SilcServer server,
   silc_buffer_free(packet);
 }
 
+/* This function is used to send Remove Channel User payload. This may sent
+   by server but is usually used only by router to notify other routers that
+   user has left a channel. Normal server sends this packet to its router
+   to notify that the router should not hold a record about this client
+   on a channel anymore. Router distributes it further to other routers. */
+
+void silc_server_send_remove_channel_user(SilcServer server,
+                                         SilcSocketConnection sock,
+                                         int broadcast,
+                                         void *client_id, void *channel_id)
+{
+  SilcBuffer packet;
+  unsigned char *clid, *chid;
+
+  clid = silc_id_id2str(client_id, SILC_ID_CLIENT);
+  if (!clid)
+    return;
+
+  chid = silc_id_id2str(channel_id, SILC_ID_CHANNEL);
+  if (!chid)
+    return;
+
+  packet = silc_buffer_alloc(2 + 2 + SILC_ID_CLIENT_LEN + SILC_ID_CHANNEL_LEN);
+  silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+  silc_buffer_format(packet,
+                    SILC_STR_UI_SHORT(SILC_ID_CLIENT_LEN),
+                    SILC_STR_UI_XNSTRING(clid, SILC_ID_CLIENT_LEN),
+                    SILC_STR_UI_SHORT(SILC_ID_CHANNEL_LEN),
+                    SILC_STR_UI_XNSTRING(chid, SILC_ID_CHANNEL_LEN),
+                    SILC_STR_END);
+
+  silc_server_packet_send(server, sock, SILC_PACKET_REMOVE_CHANNEL_USER, 
+                         broadcast ? SILC_PACKET_FLAG_BROADCAST : 0, 
+                         packet->data, packet->len, FALSE);
+  silc_free(clid);
+  silc_free(chid);
+  silc_buffer_free(packet);
+}
+
+/* Received packet to replace a ID. This checks that the requested ID
+   exists and replaces it with the new one. */
+
+void silc_server_replace_id(SilcServer server,
+                           SilcSocketConnection sock,
+                           SilcPacketContext *packet)
+{
+  SilcBuffer buffer = packet->buffer;
+  unsigned char *old_id = NULL, *new_id = NULL;
+  SilcIdType old_id_type, new_id_type;
+  unsigned short old_id_len, new_id_len;
+  void *id = NULL, *id2 = NULL;
+
+  if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
+      packet->src_id_type == SILC_ID_CLIENT)
+    return;
+
+  SILC_LOG_DEBUG(("Replacing ID"));
+
+  silc_buffer_unformat(buffer,
+                      SILC_STR_UI_SHORT(&old_id_type),
+                      SILC_STR_UI16_NSTRING_ALLOC(&old_id, &old_id_len),
+                      SILC_STR_UI_SHORT(&new_id_type),
+                      SILC_STR_UI16_NSTRING_ALLOC(&new_id, &new_id_len),
+                      SILC_STR_END);
+
+  if (old_id_type != new_id_type)
+    goto out;
+
+  if (old_id_len != silc_id_get_len(old_id_type) ||
+      new_id_len != silc_id_get_len(new_id_type))
+    goto out;
+
+  id = silc_id_str2id(old_id, old_id_type);
+  if (!id)
+    goto out;
+
+  id2 = silc_id_str2id(new_id, new_id_type);
+  if (!id2)
+    goto out;
+
+  /* Replace the old ID */
+  switch(old_id_type) {
+  case SILC_ID_CLIENT:
+    if (silc_idlist_replace_client_id(server->local_list, id, id2) == NULL)
+      if (server->server_type == SILC_ROUTER)
+       silc_idlist_replace_client_id(server->global_list, id, id2);
+    break;
+
+  case SILC_ID_SERVER:
+    if (silc_idlist_replace_server_id(server->local_list, id, id2) == NULL)
+      if (server->server_type == SILC_ROUTER)
+       silc_idlist_replace_server_id(server->global_list, id, id2);
+    break;
+
+  case SILC_ID_CHANNEL:
+    /* XXX Hmm... Basically this cannot occur. Channel ID's cannot be
+       re-generated. */
+    silc_free(id2);
+    break;
+
+  default:
+    silc_free(id2);
+    break;
+  }
+
+ out:
+  if (id)
+    silc_free(id);
+  if (old_id)
+    silc_free(old_id);
+  if (new_id)
+    silc_free(new_id);
+}
+
 /* Creates new channel. */
 
-SilcChannelList *silc_server_new_channel(SilcServer server, 
+SilcChannelEntry silc_server_new_channel(SilcServer server, 
                                         SilcServerID *router_id,
                                         char *cipher, char *channel_name)
 {
-  int i, channel_len;
+  int i, channel_len, key_len;
   SilcChannelID *channel_id;
-  SilcChannelList *entry;
+  SilcChannelEntry entry;
   SilcCipher key;
   unsigned char channel_key[32], *id_string;
   SilcBuffer packet;
 
   SILC_LOG_DEBUG(("Creating new channel"));
 
-#define LCC(x) server->local_list->channel_cache[(x) - 32]
-#define LCCC(x) server->local_list->channel_cache_count[(x) - 32]
-
   /* Create channel key */
   for (i = 0; i < 32; i++)
     channel_key[i] = silc_rng_get_byte(server->rng);
@@ -3456,21 +3135,31 @@ SilcChannelList *silc_server_new_channel(SilcServer server,
     cipher = "twofish";
 
   /* Allocate keys */
+  key_len = 16;
   silc_cipher_alloc(cipher, &key);
-  key->cipher->set_key(key->context, channel_key, 16);
+  key->cipher->set_key(key->context, channel_key, key_len);
+
+  channel_name = strdup(channel_name);
 
   /* Create the channel */
   silc_id_create_channel_id(router_id, server->rng, &channel_id);
-  silc_idlist_add_channel(&server->local_list->channels, channel_name, 
-                         SILC_CHANNEL_MODE_NONE, channel_id, NULL, /*XXX*/
-                         key, &entry);
-  LCCC(channel_name[0]) = silc_idcache_add(&LCC(channel_name[0]), 
-                                          LCCC(channel_name[0]),
-                                          channel_name, SILC_ID_CHANNEL, 
-                                          channel_id, (void *)entry);
-  entry->key = silc_calloc(16, sizeof(*entry->key));
-  entry->key_len = 16;
-  memcpy(entry->key, channel_key, 16);
+  entry = silc_idlist_add_channel(server->local_list, channel_name, 
+                                 SILC_CHANNEL_MODE_NONE, channel_id, 
+                                 NULL, key);
+  if (!entry) {
+    silc_free(channel_name);
+    return NULL;
+  }
+
+#if 0
+  /* Add to cache */
+  silc_idcache_add(server->local_list->channels, channel_name,
+                  SILC_ID_CHANNEL, channel_id, (void *)entry, TRUE);
+#endif
+
+  entry->key = silc_calloc(key_len, sizeof(*entry->key));
+  entry->key_len = key_len * 8;
+  memcpy(entry->key, channel_key, key_len);
   memset(channel_key, 0, sizeof(channel_key));
 
   /* Notify other routers about the new channel. We send the packet
@@ -3498,59 +3187,71 @@ SilcChannelList *silc_server_new_channel(SilcServer server,
     silc_buffer_free(packet);
   }
 
-#undef LCC
-#undef LCCC
   return entry;
 }
 
 /* Create new client. This processes incoming NEW_CLIENT packet and creates
-   Client ID for the client and adds it to lists and cache. */
+   Client ID for the client. Client becomes registered after calling this
+   functions. */
 
-SilcClientList *silc_server_new_client(SilcServer server,
+SilcClientEntry silc_server_new_client(SilcServer server,
                                       SilcSocketConnection sock,
                                       SilcPacketContext *packet)
 {
   SilcBuffer buffer = packet->buffer;
-  SilcClientList *id_entry;
-  char *username = NULL, *realname = NULL, *id_string;
+  SilcClientEntry client;
+  SilcIDCacheEntry cache;
+  SilcClientID *client_id;
   SilcBuffer reply;
+  char *username = NULL, *realname = NULL, *id_string;
 
   SILC_LOG_DEBUG(("Creating new client"));
 
   if (sock->type != SILC_SOCKET_TYPE_CLIENT)
     return NULL;
 
-#define LCC(x) server->local_list->client_cache[(x) - 32]
-#define LCCC(x) server->local_list->client_cache_count[(x) - 32]
+  /* Take client entry */
+  client = (SilcClientEntry)sock->user_data;
 
+  /* Fetch the old client cache entry so that we can update it. */
+  if (!silc_idcache_find_by_context(server->local_list->clients,
+                                   sock->user_data, &cache)) {
+    SILC_LOG_ERROR(("Lost client's cache entry - bad thing"));
+    return NULL;
+  }
+
+  /* Parse incoming packet */
   silc_buffer_unformat(buffer,
                       SILC_STR_UI16_STRING_ALLOC(&username),
                       SILC_STR_UI16_STRING_ALLOC(&realname),
                       SILC_STR_END);
 
-  /* Set the pointers to the client list and create new client ID */
-  id_entry = (SilcClientList *)sock->user_data;
-  id_entry->nickname = strdup(username);
-  id_entry->username = username;
-  id_entry->userinfo = realname;
+  /* Create Client ID */
   silc_id_create_client_id(server->id, server->rng, server->md5hash,
-                          username, &id_entry->id);
+                          username, &client_id);
+
+  /* Update client entry */
+  client->registered = TRUE;
+  client->nickname = strdup(username);
+  client->username = username;
+  client->userinfo = realname;
+  client->id = client_id;
 
-  /* Add to client cache */
-  LCCC(username[0]) = silc_idcache_add(&LCC(username[0]), 
-                                      LCCC(username[0]),
-                                      username, SILC_ID_CLIENT, 
-                                      id_entry->id, (void *)id_entry);
+  /* Update the cache entry */
+  cache->id = (void *)client_id;
+  cache->type = SILC_ID_CLIENT;
+  cache->data = username;
+  silc_idcache_sort_by_data(server->local_list->clients);
 
   /* Notify our router about new client on the SILC network */
   if (!server->standalone)
     silc_server_send_new_id(server, (SilcSocketConnection) 
                            server->id_entry->router->connection, 
                            server->server_type == SILC_SERVER ? TRUE : FALSE,
-                           id_entry->id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
+                           client->id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
   
   /* Send the new client ID to the client. */
-  id_string = silc_id_id2str(id_entry->id, SILC_ID_CLIENT);
+  id_string = silc_id_id2str(client->id, SILC_ID_CLIENT);
   reply = silc_buffer_alloc(2 + 2 + SILC_ID_CLIENT_LEN);
   silc_buffer_pull_tail(reply, SILC_BUFFER_END(reply));
   silc_buffer_format(reply,
@@ -3562,30 +3263,28 @@ SilcClientList *silc_server_new_client(SilcServer server,
                          reply->data, reply->len, FALSE);
   silc_free(id_string);
   silc_buffer_free(reply);
-  
-  /* Send some nice info to the client */
-  silc_server_send_notify(server, sock, 
-                         "Welcome to the SILC Network %s@%s",
-                         username, 
-                         sock->hostname ? sock->hostname : sock->ip);
-  silc_server_send_notify(server, sock,
-                         "Your host is %s, running version %s",
-                         server->config->server_info->server_name,
-                         server_version);
-  silc_server_send_notify(server, sock, 
-                         "Your connection is secured with %s cipher, "
-                         "key length %d bits",
-                         id_entry->send_key->cipher->name,
-                         id_entry->send_key->cipher->key_len);
-  silc_server_send_notify(server, sock, 
-                         "Your current nickname is %s",
-                         id_entry->nickname);
-
-  /* XXX Send motd */
 
-#undef LCC
-#undef LCCC
-  return id_entry;
+  /* Send some nice info to the client */
+  SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
+                         ("Welcome to the SILC Network %s@%s",
+                          username, sock->hostname));
+  SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
+                         ("Your host is %s, running version %s",
+                          server->config->server_info->server_name,
+                          server_version));
+  SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
+                         ("Your connection is secured with %s cipher, "
+                          "key length %d bits",
+                          client->send_key->cipher->name,
+                          client->send_key->cipher->key_len));
+  SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
+                         ("Your current nickname is %s",
+                          client->nickname));
+
+  /* Send motd */
+  silc_server_send_motd(server, sock);
+
+  return client;
 }
 
 /* Create new server. This processes incoming NEW_SERVER packet and
@@ -3593,16 +3292,19 @@ SilcClientList *silc_server_new_client(SilcServer server,
    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
+   to the server. If router uses this it means that one of the cell's
    servers is connected to the router. */
 
-SilcServerList *silc_server_new_server(SilcServer server,
+SilcServerEntry silc_server_new_server(SilcServer server,
                                       SilcSocketConnection sock,
                                       SilcPacketContext *packet)
 {
   SilcBuffer buffer = packet->buffer;
-  SilcServerList *id_entry;
+  SilcServerEntry new_server;
+  SilcIDCacheEntry cache;
+  SilcServerID *server_id;
   unsigned char *server_name, *id_string;
+  unsigned short id_len;
 
   SILC_LOG_DEBUG(("Creating new server"));
 
@@ -3610,39 +3312,52 @@ SilcServerList *silc_server_new_server(SilcServer server,
       sock->type != SILC_SOCKET_TYPE_ROUTER)
     return NULL;
 
-#define LSC(x) server->local_list->server_cache[(x) - 32]
-#define LSCC(x) server->local_list->server_cache_count[(x) - 32]
+  /* Take server entry */
+  new_server = (SilcServerEntry)sock->user_data;
+
+  /* Fetch the old server cache entry so that we can update it. */
+  if (!silc_idcache_find_by_context(server->local_list->servers,
+                                   sock->user_data, &cache)) {
+    SILC_LOG_ERROR(("Lost server's cache entry - bad thing"));
+    return NULL;
+  }
 
+  /* Parse the incoming packet */
   silc_buffer_unformat(buffer,
-                      SILC_STR_UI16_STRING_ALLOC(&id_string),
+                      SILC_STR_UI16_NSTRING_ALLOC(&id_string, &id_len),
                       SILC_STR_UI16_STRING_ALLOC(&server_name),
                       SILC_STR_END);
 
-  /* Save ID and name */
-  id_entry = (SilcServerList *)sock->user_data;
-  id_entry->id = silc_id_str2id(id_string, SILC_ID_SERVER);
-  id_entry->server_name = server_name;
-  
-  /* Add to server cache */
-  LSCC(server_name[0]) = 
-    silc_idcache_add(&LSC(server_name[0]), 
-                    LSCC(server_name[0]),
-                    server_name, SILC_ID_SERVER, 
-                    id_entry->id, (void *)id_entry);
+  if (id_len > buffer->len) {
+    silc_free(id_string);
+    silc_free(server_name);
+    return NULL;
+  }
+
+  /* Get Server ID */
+  server_id = silc_id_payload_parse_id(id_string, id_len);
+  silc_free(id_string);
+
+  /* Update client entry */
+  new_server->registered = TRUE;
+  new_server->server_name = server_name;
+  new_server->id = server_id;
+
+  /* Update the cache entry */
+  cache->id = (void *)server_id;
+  cache->type = SILC_ID_SERVER;
+  cache->data = server_name;
+  silc_idcache_sort_by_data(server->local_list->servers);
 
   /* Distribute the information about new server in the SILC network
      to our router. If we are normal server we won't send anything
      since this connection must be our router connection. */
   if (server->server_type == SILC_ROUTER && !server->standalone)
     silc_server_send_new_id(server, server->id_entry->router->connection,
-                           TRUE, id_entry->id, SILC_ID_SERVER, 
+                           TRUE, new_server->id, SILC_ID_SERVER, 
                            SILC_ID_SERVER_LEN);
 
-  silc_free(id_string);
-
-#undef LSC
-#undef LSCC
-  return id_entry;
+  return new_server;
 }
 
 /* Processes incoming New ID Payload. New ID Payload is used to distribute
@@ -3653,74 +3368,148 @@ void silc_server_new_id(SilcServer server, SilcSocketConnection sock,
                        SilcPacketContext *packet)
 {
   SilcBuffer buffer = packet->buffer;
+  SilcIDList id_list;
+  SilcServerEntry tmpserver, router;
+  SilcSocketConnection router_sock;
+  SilcIDPayload idp;
   SilcIdType id_type;
-  unsigned char *id_string;
-  void *id;
+  void *id, *tmpid;
 
   SILC_LOG_DEBUG(("Processing new ID"));
 
   if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
-      server->server_type == SILC_SERVER)
+      server->server_type == SILC_SERVER ||
+      packet->src_id_type != SILC_ID_SERVER)
     return;
 
-  silc_buffer_unformat(buffer,
-                      SILC_STR_UI_SHORT(&id_type),
-                      SILC_STR_UI16_STRING_ALLOC(&id_string),
-                      SILC_STR_END);
+  idp = silc_id_payload_parse(buffer);
+  if (!idp)
+    return;
+
+  id_type = silc_id_payload_get_type(idp);
 
   /* Normal server cannot have other normal server connections */
   if (id_type == SILC_ID_SERVER && sock->type == SILC_SOCKET_TYPE_SERVER)
     goto out;
 
-  id = silc_id_str2id(id_string, id_type);
+  id = silc_id_payload_get_id(idp);
   if (!id)
     goto out;
 
-  /* XXX Do check whether the packet is coming outside the cell or
-     from someone inside the cell.  If outside use global lists otherwise
-     local lists. */
-  /* XXX If using local list set the idlist->connection to the sender's
-     socket connection as it is used in packet sending */
+  /* If the packet is originated from the one who sent it to us we know
+     that the ID belongs to our cell, unless the sender was router. */
+  tmpid = silc_id_str2id(packet->src_id, SILC_ID_SERVER);
+  tmpserver = (SilcServerEntry)sock->user_data;
+
+  if (!SILC_ID_SERVER_COMPARE(tmpid, tmpserver->id) &&
+      sock->type == SILC_SOCKET_TYPE_SERVER) {
+    id_list = server->local_list;
+    router_sock = sock;
+    router = sock->user_data;
+    /*    router = server->id_entry; */
+  } else {
+    id_list = server->global_list;
+    router_sock = (SilcSocketConnection)server->id_entry->router->connection;
+    router = server->id_entry->router;
+  }
+
+  silc_free(tmpid);
 
   switch(id_type) {
   case SILC_ID_CLIENT:
     {
-      SilcClientList *idlist;
+      SilcClientEntry idlist;
 
       /* Add the client to our local list. We are router and we keep
         cell specific local database of all clients in the cell. */
-      silc_idlist_add_client(&server->local_list->clients, NULL, NULL, NULL,
-                            id, sock->user_data, NULL, NULL, 
-                            NULL, NULL, &idlist);
-      idlist->connection = sock;
+      idlist = silc_idlist_add_client(id_list, NULL, NULL, NULL,
+                                     id, router, NULL, NULL, 
+                                     NULL, NULL, NULL, router_sock);
     }
     break;
 
   case SILC_ID_SERVER:
     {
-      SilcServerList *idlist;
+      SilcServerEntry idlist;
 
       /* Add the server to our local list. We are router and we keep
         cell specific local database of all servers in the cell. */
-      silc_idlist_add_server(&server->local_list->servers, NULL, 0,
-                            id, server->id_entry, NULL, NULL, 
-                          NULL, NULL, &idlist);
-      idlist->connection = sock;
+      idlist = silc_idlist_add_server(id_list, NULL, 0,
+                                     id, router, NULL, NULL, 
+                                     NULL, NULL, NULL, router_sock);
     }
     break;
 
   case SILC_ID_CHANNEL:
     /* Add the channel to our local list. We are router and we keep
        cell specific local database of all channels in the cell. */
-    silc_idlist_add_channel(&server->local_list->channels, NULL, 0,
-                           id, server->id_entry, NULL, NULL);
+    silc_idlist_add_channel(id_list, NULL, 0, id, router, NULL);
     break;
 
   default:
-    goto out;
     break;
   }
 
  out:
-  silc_free(id_string);
+  silc_id_payload_free(idp);
+}
+
+/* Received packet to remove a user from a channel. Routers notify other
+   routers that user has left a channel. Client must not send this packet. 
+   Normal server may send this packet but ignores if it receives one. */
+
+void silc_server_remove_channel_user(SilcServer server,
+                                    SilcSocketConnection sock,
+                                    SilcPacketContext *packet)
+{
+  SilcBuffer buffer = packet->buffer;
+  unsigned char *tmp1 = NULL, *tmp2 = NULL;
+  SilcClientID *client_id = NULL;
+  SilcChannelID *channel_id = NULL;
+  SilcChannelEntry channel;
+  SilcClientEntry client;
+
+  SILC_LOG_DEBUG(("Removing user from channel"));
+
+  if (sock->type == SILC_SOCKET_TYPE_CLIENT ||
+      server->server_type == SILC_SERVER)
+    return;
+
+  silc_buffer_unformat(buffer,
+                      SILC_STR_UI16_STRING_ALLOC(&tmp1),
+                      SILC_STR_UI16_STRING_ALLOC(&tmp2),
+                      SILC_STR_END);
+
+  if (!tmp1 || !tmp2)
+    goto out;
+
+  client_id = silc_id_str2id(tmp1, SILC_ID_CLIENT);
+  channel_id = silc_id_str2id(tmp2, SILC_ID_CHANNEL);
+  if (!client_id || !channel_id)
+    goto out;
+
+  /* XXX routers should check server->global_list as well */
+  /* Get channel entry */
+  channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
+  if (!channel)
+    goto out;
+  
+  /* XXX routers should check server->global_list as well */
+  /* Get client entry */
+  client = silc_idlist_find_client_by_id(server->local_list, client_id);
+  if (!client)
+    goto out;
+
+  /* Remove from channel */
+  silc_server_remove_from_one_channel(server, sock, channel, client, FALSE);
+
+ out:
+  if (tmp1)
+    silc_free(tmp1);
+  if (tmp2)
+    silc_free(tmp2);
+  if (client_id)
+    silc_free(client_id);
+  if (channel_id)
+    silc_free(channel_id);
 }
index ebe661c92ed7c860ba7bfe4dea44d90ab370516e..41379eab36342905ccee30bce80c8503f9dbf17a 100644 (file)
@@ -33,12 +33,28 @@ typedef struct SilcServerObjectStruct *SilcServer;
 #define SILC_SERVER 0
 #define SILC_ROUTER 1
 
+/* Macros */
+
+/* This macro is used to send notify messages with formatted string. The
+   string is formatted with arguments and the formatted string is sent as
+   argument. */
+#define SILC_SERVER_SEND_NOTIFY(server, sock, type, fmt)                   \
+do {                                                                       \
+  char *__fmt__ = silc_format fmt;                                         \
+  silc_server_send_notify(server, sock, type, 1, __fmt__, strlen(__fmt__)); \
+  silc_free(__fmt__);                                                      \
+} while(0);
+
 /* Prototypes */
 int silc_server_alloc(SilcServer *new_server);
 void silc_server_free(SilcServer server);
 int silc_server_init(SilcServer server);
 void silc_server_run(SilcServer server);
 void silc_server_stop(SilcServer server);
+void silc_server_packet_parse(SilcPacketParserContext *parser_context);
+void silc_server_packet_parse_type(SilcServer server, 
+                                  SilcSocketConnection sock,
+                                  SilcPacketContext *packet);
 void silc_server_packet_send(SilcServer server,
                             SilcSocketConnection sock, 
                             SilcPacketType type, 
@@ -60,18 +76,26 @@ void silc_server_packet_forward(SilcServer server,
                                unsigned char *data, unsigned int data_len,
                                int force_send);
 void silc_server_packet_send_to_channel(SilcServer server,
-                                       SilcChannelList *channel,
+                                       SilcChannelEntry channel,
+                                       SilcPacketType type,
                                        unsigned char *data,
                                        unsigned int data_len,
                                        int force_send);
 void silc_server_packet_relay_to_channel(SilcServer server,
                                         SilcSocketConnection sender_sock,
-                                        SilcChannelList *channel,
+                                        SilcChannelEntry channel,
                                         void *sender, 
                                         SilcIdType sender_type,
                                         unsigned char *data,
                                         unsigned int data_len,
                                         int force_send);
+void silc_server_packet_send_local_channel(SilcServer server,
+                                          SilcChannelEntry channel,
+                                          SilcPacketType type,
+                                          SilcPacketFlags flags,
+                                          unsigned char *data,
+                                          unsigned int data_len,
+                                          int force_send);
 void silc_server_packet_relay_command_reply(SilcServer server,
                                            SilcSocketConnection sock,
                                            SilcPacketContext *packet);
@@ -81,7 +105,14 @@ void silc_server_free_sock_user_data(SilcServer server,
                                     SilcSocketConnection sock);
 void silc_server_remove_from_channels(SilcServer server, 
                                      SilcSocketConnection sock,
-                                     SilcClientList *client);
+                                     SilcClientEntry client);
+int silc_server_remove_from_one_channel(SilcServer server, 
+                                       SilcSocketConnection sock,
+                                       SilcChannelEntry channel,
+                                       SilcClientEntry client,
+                                       int notify);
+int silc_server_client_on_channel(SilcClientEntry client,
+                                 SilcChannelEntry channel);
 void silc_server_disconnect_remote(SilcServer server,
                                   SilcSocketConnection sock,
                                   const char *fmt, ...);
@@ -94,15 +125,29 @@ void silc_server_channel_message(SilcServer server,
 void silc_server_channel_key(SilcServer server,
                             SilcSocketConnection sock,
                             SilcPacketContext *packet);
+void silc_server_send_motd(SilcServer server,
+                          SilcSocketConnection sock);
 void silc_server_send_error(SilcServer server,
                            SilcSocketConnection sock,
                            const char *fmt, ...);
 void silc_server_send_notify(SilcServer server,
                             SilcSocketConnection sock,
-                            const char *fmt, ...);
+                            SilcNotifyType type,
+                            unsigned int argc, ...);
+void silc_server_send_notify_dest(SilcServer server,
+                                 SilcSocketConnection sock,
+                                 void *dest_id,
+                                 SilcIdType dest_id_type,
+                                 SilcNotifyType type,
+                                 unsigned int argc, ...);
 void silc_server_send_notify_to_channel(SilcServer server,
-                                       SilcChannelList *channel,
-                                       const char *fmt, ...);
+                                       SilcChannelEntry channel,
+                                       SilcNotifyType type,
+                                       unsigned int argc, ...);
+void silc_server_send_notify_on_channels(SilcServer server,
+                                        SilcClientEntry client,
+                                        SilcNotifyType type,
+                                        unsigned int argc, ...);
 void silc_server_send_new_id(SilcServer server,
                             SilcSocketConnection sock,
                             int broadcast,
@@ -115,16 +160,26 @@ void silc_server_send_replace_id(SilcServer server,
                                 unsigned int old_id_len,
                                 void *new_id, SilcIdType new_id_type,
                                 unsigned int new_id_len);
-SilcChannelList *silc_server_new_channel(SilcServer server, 
+void silc_server_send_remove_channel_user(SilcServer server,
+                                         SilcSocketConnection sock,
+                                         int broadcast,
+                                         void *client_id, void *channel_id);
+void silc_server_replace_id(SilcServer server,
+                           SilcSocketConnection sock,
+                           SilcPacketContext *packet);
+SilcChannelEntry silc_server_new_channel(SilcServer server, 
                                         SilcServerID *router_id,
                                         char *cipher, char *channel_name);
-SilcClientList *silc_server_new_client(SilcServer server,
+SilcClientEntry silc_server_new_client(SilcServer server,
                                       SilcSocketConnection sock,
                                       SilcPacketContext *packet);
-SilcServerList *silc_server_new_server(SilcServer server,
+SilcServerEntry silc_server_new_server(SilcServer server,
                                       SilcSocketConnection sock,
                                       SilcPacketContext *packet);
 void silc_server_new_id(SilcServer server, SilcSocketConnection sock,
                        SilcPacketContext *packet);
+void silc_server_remove_channel_user(SilcServer server,
+                                    SilcSocketConnection sock,
+                                    SilcPacketContext *packet);
 
 #endif
index 3ed7cbebefe272157760d62fa616fade08795389..0093ac8429a5ade3e586f515d5a872c2c40fbe9b 100644 (file)
@@ -40,7 +40,7 @@ typedef struct SilcServerObjectStruct {
   int listenning;
   SilcServerID *id;
   SilcIdType id_type;
-  SilcServerList *id_entry;
+  SilcServerEntry id_entry;
 
   /* SILC server task queues */
   SilcTaskQueue io_queue;
@@ -60,7 +60,9 @@ typedef struct SilcServerObjectStruct {
   SilcCipher none_cipher;
 
   /* Server public key */
-  SilcPKCS public_key;
+  SilcPKCS pkcs;
+  SilcPublicKey public_key;
+  SilcPrivateKey private_key;
 
   /* Hash objects for general hashing */
   SilcHash md5hash;
index 22984a51326514a927311be184ef7a070ff4d694..34992677e5f56639b42f268b5021ef5665a6f118 100644 (file)
   GNU General Public License for more details.
 
 */
-/*
- * $Id$
- * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:56  priikone
- *     Importet from internal CVS/Added Log headers.
- *
- *
- */
 
 #include "serverincludes.h"
+#include "version_internal.h"
 
-const char server_version[] = "27062000";
+const char *server_version = SILC_VERSION_STRING;
index 2f617c2621c8676c31b8513a41c081c924461391..fc89baced403a8e8979e93e68c18893263bab274 100644 (file)
 /*
  * $Id$
  * $Log$
+ * Revision 1.4  2000/10/06 08:10:23  priikone
+ *     Added WHOIS to send multiple replies if multiple nicknames are
+ *     found.
+ *     Added MOTD command and [motd] config section and server also sends
+ *     motd to client on connection now.
+ *     Fixed TOPIC command some more.
+ *
+ * Revision 1.3  2000/07/10 05:41:20  priikone
+ *     Added missing token to administrative information.
+ *
+ * Revision 1.2  2000/07/05 06:14:01  priikone
+ *     Global costemic changes.
+ *
  * Revision 1.1.1.1  2000/06/27 11:36:56  priikone
- *     Importet from internal CVS/Added Log headers.
+ *     Imported from internal CVS/Added Log headers.
  *
  *
  */
@@ -183,6 +196,8 @@ SilcConfigServerSection silc_config_server_sections[] = {
     SILC_CONFIG_SERVER_SECTION_TYPE_DENY_CONNECTION, 4 },
   { "[RedirectClient]", 
     SILC_CONFIG_SERVER_SECTION_TYPE_REDIRECT_CLIENT, 2 },
+  { "[motd]", 
+    SILC_CONFIG_SERVER_SECTION_TYPE_MOTD, 1 },
   
   { NULL, SILC_CONFIG_SERVER_SECTION_TYPE_NONE, 0 }
 };
@@ -243,6 +258,7 @@ void silc_config_server_free(SilcConfigServer config)
     silc_free(config->routers);
     silc_free(config->denied);
     silc_free(config->redirect);
+    silc_free(config->motd);
     silc_free(config);
   }
 }
@@ -305,7 +321,7 @@ int silc_config_server_parse(SilcConfigServer config, SilcBuffer buffer,
       
       /* Check for matching sections */
       for (cptr = silc_config_server_sections; cptr->section; cptr++)
-       if (!strcmp(cp, cptr->section))
+       if (!strncasecmp(cp, cptr->section, strlen(cptr->section)))
          break;
 
       if (!cptr->section) {
@@ -576,6 +592,11 @@ int silc_config_server_parse_lines(SilcConfigServer config,
       if (!config->admin_info)
        config->admin_info = silc_calloc(1, sizeof(*config->admin_info));
 
+      /* Get location */
+      ret = silc_config_get_token(line, &config->admin_info->location);
+      if (ret < 0)
+       break;
+
       /* Get server type */
       ret = silc_config_get_token(line, &config->admin_info->server_type);
       if (ret < 0)
@@ -969,6 +990,20 @@ int silc_config_server_parse_lines(SilcConfigServer config,
       check = TRUE;
       break;
 
+    case SILC_CONFIG_SERVER_SECTION_TYPE_MOTD:
+
+      if (!config->motd)
+       config->motd = silc_calloc(1, sizeof(*config->motd));
+
+      /* Get motd file */
+      ret = silc_config_get_token(line, &config->motd->motd_file);
+      if (ret < 0)
+       break;
+
+      check = TRUE;
+      checkmask |= (1L << pc->section->type);
+      break;
+
     case SILC_CONFIG_SERVER_SECTION_TYPE_NONE:
     default:
       /* Error */
index 56ed10eb129e107081e2aad1f7fa0e4863798832..5b7a1d54cd2bc70859ccc73b90a06565a9f4f5be 100644 (file)
@@ -42,6 +42,7 @@ typedef struct {
 
 /* Holds server's administrative information from config file */
 typedef struct {
+  char *location;
   char *server_type;
   char *admin_name;
   char *admin_email;
@@ -132,6 +133,11 @@ typedef struct {
   unsigned short port;
 } SilcConfigServerSectionRedirectClient;
 
+/* Holds motd file */
+typedef struct {
+  char *motd_file;
+} SilcConfigServerSectionMotd;
+
 /* 
    SILC Server Config object. 
 
@@ -161,6 +167,7 @@ typedef struct {
   SilcConfigServerSectionAdminConnection *admins;
   SilcConfigServerSectionDenyConnection *denied;
   SilcConfigServerSectionRedirectClient *redirect;
+  SilcConfigServerSectionMotd *motd;
 } SilcConfigServerObject;
 
 typedef SilcConfigServerObject *SilcConfigServer;
@@ -182,6 +189,7 @@ typedef enum {
   SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_CONNECTION,
   SILC_CONFIG_SERVER_SECTION_TYPE_DENY_CONNECTION,
   SILC_CONFIG_SERVER_SECTION_TYPE_REDIRECT_CLIENT,
+  SILC_CONFIG_SERVER_SECTION_TYPE_MOTD,
 } SilcConfigServerSectionType;
 
 /* SILC Configuration Section structure. */
index 767faace3c1b002e3d17e2257919847aba6619bc..26f010cb5db046d80cb19d435f5c84165bafac2f 100644 (file)
@@ -20,8 +20,8 @@
 /*
  * $Id$
  * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:56  priikone
- *     Importet from internal CVS/Added Log headers.
+ * Revision 1.1  2000/06/27 11:36:56  priikone
+ * Initial revision
  *
  *
  */
index d7d444778c50eb823d67d99f636a01b965ed0d04..515f8ba0d50dea45e71ffea1011e300655f6d429 100644 (file)
@@ -13,26 +13,26 @@ sha1::64:20
 #dss::1024
 
 [AdminInfo]
-Mun huone:Mun servo:Pekka Riikonen:priikone@poseidon.pspt.fi
+Pohjois-Savo Poly-Technics:SILC Test Server:Pekka Riikonen:priikone@poseidon.pspt.fi
 
 [ServerInfo]
-silc.pspt.fi:193.166.51.47:Kuopio, Finland:1333
+silc.pspt.fi:193.166.51.47:Kuopio, Finland:706
 
 [ListenPort]
-193.166.51.47:193.166.51.47:1333
+193.166.51.47:193.166.51.47:706
 
 [Logging]
 infologfile:silcd.log:10000
-#warninglogfile:/var/log/silcd_warning.log:10000
-#errorlogfile:ERROR.log:10000
-#fatallogfile:/var/log/silcd_error.log:
+warninglogfile:silcd.log:
+errorlogfile:silcd.log:10000
+fatallogfile:silcd.log:
 
 [ConnectionClass]
 1:100:100:100
 2:200:300:400
 
 [ClientConnection]
-:::1333:1
+:::706:1
 
 [AdminConnection]
 
index 0de8874a5d8fe8353af8c4b64958b6ebb7162cca..1abc46ddd0702063c40fd8cea14d19daea8a35fb 100644 (file)
 /*
  * $Id$
  * $Log$
+ * Revision 1.3  2000/09/29 07:13:05  priikone
+ *     Added support for notify type sending in notify payload.
+ *     Removed Log headers from the file.
+ *     Enabled debug messages by default for server.
+ *
+ * Revision 1.2  2000/07/05 06:14:01  priikone
+ *     Global costemic changes.
+ *
  * Revision 1.1.1.1  2000/06/27 11:36:56  priikone
- *     Importet from internal CVS/Added Log headers.
+ *     Imported from internal CVS/Added Log headers.
  *
  *
  */
@@ -67,6 +75,8 @@ int main(int argc, char **argv)
   char *config_file = NULL;
   SilcServer silcd;
 
+  silc_debug = TRUE;
+
   /* Parse command line arguments */
   if (argc > 1) {
     while ((opt = getopt_long(argc, argv, "cf:hV",
diff --git a/apps/silcd/testi.conf b/apps/silcd/testi.conf
deleted file mode 100644 (file)
index e5417e2..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-[Cipher]
-rc6:/home/priikone/silc/lib/silcsim/modules/rc6.sim.so:16:16
-twofish:/home/priikone/silc/lib/silcsim/modules/twofish.sim.so:16:16
-mars:/home/priikone/silc/lib/silcsim/modules/mars.sim.so:16:16
-none:/home/priikone/silc/lib/silcsim/modules/none.sim.so:0:0
-
-[HashFunction]
-md5::64:16
-sha1::64:20
-
-#[PKCS]
-#rsa::1024
-#dss::1024
-
-[AdminInfo]
-Mun huone:Mun servo:Pekka Riikonen:priikone@poseidon.pspt.fi
-
-[ServerInfo]
-lassi.kuo.fi.ssh.com:10.2.1.6:Kuopio, Finland:1333
-
-[ListenPort]
-10.2.1.6:10.2.1.6:1333
-
-[Logging]
-infologfile:silcd.log:10000
-#warninglogfile:/var/log/silcd_warning.log:10000
-errorlogfile:silcd2_error.log:10000
-#fatallogfile:/var/log/silcd_error.log:
-
-[ConnectionClass]
-1:100:100:100
-2:200:300:400
-
-[ClientConnection]
-10.2.1.199:passwd:priikone:333:1
-:::1333:1
-
-[AdminConnection]
-
-[ServerConnection]
-
-[RouterConnection]
-
-[DenyConnection]
-[RedirectClient]
index 1d27287d5bc6a06b62816cc19bcd2ca594c44933..e1b5871708010cf0962a293681cd941b915125e3 100755 (executable)
@@ -1,6 +1,7 @@
 #! /bin/sh
 # Attempt to guess a canonical system name.
-#   Copyright (C) 1992, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999
+#   Free Software Foundation, Inc.
 #
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -23,7 +24,7 @@
 
 # Written by Per Bothner <bothner@cygnus.com>.
 # The master version of this file is at the FSF in /home/gd/gnu/lib.
-# Please send patches to the Autoconf mailing list <autoconf@gnu.org>.
+# Please send patches to <autoconf-patches@gnu.org>.
 #
 # This script attempts to guess a canonical system name similar to
 # config.sub.  If it succeeds, it prints the system name on stdout, and
 # (but try to keep the structure clean).
 #
 
+# Use $HOST_CC if defined. $CC may point to a cross-compiler
+if test x"$CC_FOR_BUILD" = x; then
+  if test x"$HOST_CC" != x; then
+    CC_FOR_BUILD="$HOST_CC"
+  else
+    if test x"$CC" != x; then
+      CC_FOR_BUILD="$CC"
+    else
+      CC_FOR_BUILD=cc
+    fi
+  fi
+fi
+
+
 # This is needed to find uname on a Pyramid OSx when run in the BSD universe.
 # (ghazi@noc.rutgers.edu 8/24/94.)
 if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
@@ -78,7 +93,7 @@ main:
        ret \$31,(\$26),1
        .end main
 EOF
-       ${CC-cc} $dummy.s -o $dummy 2>/dev/null
+       $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
        if test "$?" = 0 ; then
                ./$dummy
                case "$?" in
@@ -100,7 +115,13 @@ EOF
                esac
        fi
        rm -f $dummy.s $dummy
-       echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr [[A-Z]] [[a-z]]`
+       echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+       exit 0 ;;
+    Alpha\ *:Windows_NT*:*)
+       # How do we know it's Interix rather than the generic POSIX subsystem?
+       # Should we change UNAME_MACHINE based on the output of uname instead
+       # of the specific Alpha model?
+       echo alpha-pc-interix
        exit 0 ;;
     21064:Windows_NT:50:3)
        echo alpha-dec-winnt3.5
@@ -135,6 +156,9 @@ EOF
     wgrisc:OpenBSD:*:*)
        echo mipsel-unknown-openbsd${UNAME_RELEASE}
        exit 0 ;;
+    *:OS/390:*:*)
+       echo i370-ibm-openedition
+       exit 0 ;;
     arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
        echo arm-acorn-riscix${UNAME_RELEASE}
        exit 0;;
@@ -144,7 +168,7 @@ EOF
     SR2?01:HI-UX/MPP:*:*)
        echo hppa1.1-hitachi-hiuxmpp
        exit 0;;
-    Pyramid*:OSx*:*:*|MIS*:OSx*:*:*|MIS*:SMP_DC-OSx*:*:*)
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
        # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
        if test "`(/bin/universe) 2>/dev/null`" = att ; then
                echo pyramid-pyramid-sysv3
@@ -203,6 +227,32 @@ EOF
     atari*:OpenBSD:*:*)
        echo m68k-unknown-openbsd${UNAME_RELEASE}
        exit 0 ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor 
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+       exit 0 ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+       echo m68k-atari-mint${UNAME_RELEASE}
+        exit 0 ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+       exit 0 ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+        echo m68k-milan-mint${UNAME_RELEASE}
+        exit 0 ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+        echo m68k-hades-mint${UNAME_RELEASE}
+        exit 0 ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+        echo m68k-unknown-mint${UNAME_RELEASE}
+        exit 0 ;;
     sun3*:NetBSD:*:*)
        echo m68k-sun-netbsd${UNAME_RELEASE}
        exit 0 ;;
@@ -236,7 +286,7 @@ EOF
     VAX*:ULTRIX*:*:*)
        echo vax-dec-ultrix${UNAME_RELEASE}
        exit 0 ;;
-    2020:CLIX:*:*)
+    2020:CLIX:*:* | 2430:CLIX:*:*)
        echo clipper-intergraph-clix${UNAME_RELEASE}
        exit 0 ;;
     mips:*:*:UMIPS | mips:*:*:RISCos)
@@ -260,7 +310,7 @@ EOF
          exit (-1);
        }
 EOF
-       ${CC-cc} $dummy.c -o $dummy \
+       $CC_FOR_BUILD $dummy.c -o $dummy \
          && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
          && rm $dummy.c $dummy && exit 0
        rm -f $dummy.c $dummy
@@ -281,15 +331,18 @@ EOF
     AViiON:dgux:*:*)
         # DG/UX returns AViiON for all architectures
         UNAME_PROCESSOR=`/usr/bin/uname -p`
-        if [ $UNAME_PROCESSOR = mc88100 -o $UNAME_PROCESSOR = mc88110 ] ; then
-       if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \
-            -o ${TARGET_BINARY_INTERFACE}x = x ] ; then
+       if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110]
+       then
+           if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+              [ ${TARGET_BINARY_INTERFACE}x = x ]
+           then
                echo m88k-dg-dgux${UNAME_RELEASE}
-       else
+           else
                echo m88k-dg-dguxbcs${UNAME_RELEASE}
+           fi
+       else
+           echo i586-dg-dgux${UNAME_RELEASE}
        fi
-        else echo i586-dg-dgux${UNAME_RELEASE}
-        fi
        exit 0 ;;
     M88*:DolphinOS:*:*)        # DolphinOS (SVR3)
        echo m88k-dolphin-sysv3
@@ -326,7 +379,7 @@ EOF
                        exit(0);
                        }
 EOF
-               ${CC-cc} $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0
+               $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0
                rm -f $dummy.c $dummy
                echo rs6000-ibm-aix3.2.5
        elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
@@ -374,7 +427,7 @@ EOF
        case "${UNAME_MACHINE}" in
            9000/31? )            HP_ARCH=m68000 ;;
            9000/[34]?? )         HP_ARCH=m68k ;;
-           9000/6?? | 9000/7?? | 9000/80[024] | 9000/8?[136790] | 9000/892 )
+           9000/[678][0-9][0-9])
               sed 's/^              //' << EOF >$dummy.c
               #include <stdlib.h>
               #include <unistd.h>
@@ -406,7 +459,7 @@ EOF
                   exit (0);
               }
 EOF
-       (${CC-cc} $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy`
+       (CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy`
        rm -f $dummy.c $dummy
        esac
        HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
@@ -438,7 +491,7 @@ EOF
          exit (0);
        }
 EOF
-       ${CC-cc} $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0
+       $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0
        rm -f $dummy.c $dummy
        echo unknown-hitachi-hiuxwe2
        exit 0 ;;
@@ -448,10 +501,7 @@ EOF
     9000/8??:4.3bsd:*:*)
        echo hppa1.0-hp-bsd
        exit 0 ;;
-    *9??*:MPE*:*:*)
-       echo hppa1.0-hp-mpeix
-       exit 0 ;;
-    *9??*:MPE*:*:*)
+    *9??*:MPE/iX:*:*)
        echo hppa1.0-hp-mpeix
        exit 0 ;;
     hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
@@ -470,6 +520,9 @@ EOF
     parisc*:Lites*:*:*)
        echo hppa1.1-hp-lites
        exit 0 ;;
+    hppa*:OpenBSD:*:*)
+       echo hppa-unknown-openbsd
+       exit 0 ;;
     C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
        echo c1-convex-bsd
         exit 0 ;;
@@ -503,13 +556,13 @@ EOF
        echo t90-cray-unicos${UNAME_RELEASE}
        exit 0 ;;
     CRAY*T3E:*:*:*)
-       echo t3e-cray-unicosmk${UNAME_RELEASE}
+       echo alpha-cray-unicosmk${UNAME_RELEASE}
        exit 0 ;;
     CRAY-2:*:*:*)
        echo cray2-cray-unicos
         exit 0 ;;
     F300:UNIX_System_V:*:*)
-        FUJITSU_SYS=`uname -p | tr [A-Z] [a-z] | sed -e 's/\///'`
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
         FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
         echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
         exit 0 ;;
@@ -522,12 +575,12 @@ EOF
     hp300:OpenBSD:*:*)
        echo m68k-unknown-openbsd${UNAME_RELEASE}
        exit 0 ;;
-    sparc*:BSD/OS:*:*)
-       echo sparc-unknown-bsdi${UNAME_RELEASE}
-       exit 0 ;;
     i?86:BSD/386:*:* | i?86:BSD/OS:*:*)
        echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
        exit 0 ;;
+    sparc*:BSD/OS:*:*)
+       echo sparc-unknown-bsdi${UNAME_RELEASE}
+       exit 0 ;;
     *:BSD/OS:*:*)
        echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
        exit 0 ;;
@@ -541,7 +594,7 @@ EOF
        echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
        exit 0 ;;
     *:NetBSD:*:*)
-       echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+       echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*//'`
        exit 0 ;;
     *:OpenBSD:*:*)
        echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
@@ -552,6 +605,15 @@ EOF
     i*:MINGW*:*)
        echo ${UNAME_MACHINE}-pc-mingw32
        exit 0 ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+       # How do we know it's Interix rather than the generic POSIX subsystem?
+       # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+       # UNAME_MACHINE based on the output of uname instead of i386?
+       echo i386-pc-interix
+       exit 0 ;;
+    i*:UWIN*:*)
+       echo ${UNAME_MACHINE}-pc-uwin
+       exit 0 ;;
     p*:CYGWIN*:*)
        echo powerpcle-unknown-cygwin
        exit 0 ;;
@@ -562,16 +624,11 @@ EOF
        echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
        exit 0 ;;
     *:Linux:*:*)
-#      # uname on the ARM produces all sorts of strangeness, and we need to
-#      # filter it out.
-#      case "$UNAME_MACHINE" in
-#        armv*)                      UNAME_MACHINE=$UNAME_MACHINE ;;
-#        arm* | sa110*)              UNAME_MACHINE="arm" ;;
-#      esac
 
        # The BFD linker knows what the default object file format is, so
-       # first see if it will tell us.
-       ld_help_string=`ld --help 2>&1`
+       # first see if it will tell us. cd to the root directory to prevent
+       # problems with other programs or directories called `ld' in the path.
+       ld_help_string=`cd /; ld --help 2>&1`
        ld_supported_emulations=`echo $ld_help_string \
                         | sed -ne '/supported emulations:/!d
                                    s/[         ][      ]*/ /g
@@ -579,13 +636,70 @@ EOF
                                    s/ .*//
                                    p'`
         case "$ld_supported_emulations" in
-         i?86linux)  echo "${UNAME_MACHINE}-pc-linux-gnuaout"      ; exit 0 ;;
-         i?86coff)   echo "${UNAME_MACHINE}-pc-linux-gnucoff"      ; exit 0 ;;
-         sparclinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
-         armlinux)   echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
-         m68klinux)  echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;;
-         elf32arm)   echo "${UNAME_MACHINE}-unknown-linux-gnu"     ; exit 0 ;;
-         elf32ppc)   echo "powerpc-unknown-linux-gnu"              ; exit 0 ;;
+         *ia64)
+               echo "${UNAME_MACHINE}-unknown-linux"
+               exit 0
+               ;;
+         i?86linux)
+               echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+               exit 0
+               ;;
+         i?86coff)
+               echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+               exit 0
+               ;;
+         sparclinux)
+               echo "${UNAME_MACHINE}-unknown-linux-gnuaout"
+               exit 0
+               ;;
+         armlinux)
+               echo "${UNAME_MACHINE}-unknown-linux-gnuaout"
+               exit 0
+               ;;
+         elf32arm*)
+               echo "${UNAME_MACHINE}-unknown-linux-gnu"
+               exit 0
+               ;;
+         armelf_linux*)
+               echo "${UNAME_MACHINE}-unknown-linux-gnu"
+               exit 0
+               ;;
+         m68klinux)
+               echo "${UNAME_MACHINE}-unknown-linux-gnuaout"
+               exit 0
+               ;;
+         elf32ppc)
+               # Determine Lib Version
+               cat >$dummy.c <<EOF
+#include <features.h>
+#if defined(__GLIBC__)
+extern char __libc_version[];
+extern char __libc_release[];
+#endif
+main(argc, argv)
+     int argc;
+     char *argv[];
+{
+#if defined(__GLIBC__)
+  printf("%s %s\n", __libc_version, __libc_release);
+#else
+  printf("unkown\n");
+#endif
+  return 0;
+}
+EOF
+               LIBC=""
+               $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null
+               if test "$?" = 0 ; then
+                       ./$dummy | grep 1\.99 > /dev/null
+                       if test "$?" = 0 ; then
+                               LIBC="libc1"
+                       fi
+               fi      
+               rm -f $dummy.c $dummy
+               echo powerpc-unknown-linux-gnu${LIBC}
+               exit 0
+               ;;
        esac
 
        if test "${UNAME_MACHINE}" = "alpha" ; then
@@ -607,7 +721,7 @@ EOF
                .end main
 EOF
                LIBC=""
-               ${CC-cc} $dummy.s -o $dummy 2>/dev/null
+               $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
                if test "$?" = 0 ; then
                        ./$dummy
                        case "$?" in
@@ -652,7 +766,7 @@ EOF
   return 0;
 }
 EOF
-         ${CC-cc} $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0
+         $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0
          rm -f $dummy.c $dummy
        else
          # Either a pre-BFD a.out linker (linux-gnuoldld)
@@ -695,7 +809,7 @@ EOF
   return 0;
 }
 EOF
-         ${CC-cc} $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0
+         $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0
          rm -f $dummy.c $dummy
        fi ;;
 # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.  earlier versions
@@ -712,10 +826,20 @@ EOF
        echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
        exit 0 ;;
     i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*)
+       UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
        if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
-               echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE}
+               echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+       else
+               echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+       fi
+       exit 0 ;;
+    i?86:*:5:7*)
+        # Fixed at (any) Pentium or better
+        UNAME_MACHINE=i586
+        if [ ${UNAME_SYSTEM} = "UnixWare" ] ; then
+           echo ${UNAME_MACHINE}-sco-sysv${UNAME_RELEASE}uw${UNAME_VERSION}
        else
-               echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE}
+           echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE}
        fi
        exit 0 ;;
     i?86:*:3.2:*)
@@ -727,18 +851,15 @@ EOF
                (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
                (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
                        && UNAME_MACHINE=i586
+               (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \
+                       && UNAME_MACHINE=i686
+               (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \
+                       && UNAME_MACHINE=i686
                echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
        else
                echo ${UNAME_MACHINE}-pc-sysv32
        fi
        exit 0 ;;
-    i?86:UnixWare:*:*)
-       if /bin/uname -X 2>/dev/null >/dev/null ; then
-         (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
-           && UNAME_MACHINE=i586
-       fi
-       echo ${UNAME_MACHINE}-unixware-${UNAME_RELEASE}-${UNAME_VERSION}
-       exit 0 ;;
     pc:*:*:*)
         # uname -m prints for DJGPP always 'pc', but it prints nothing about
         # the processor, so we play safe by assuming i386.
@@ -825,7 +946,7 @@ EOF
     news*:NEWS-OS:*:6*)
        echo mips-sony-newsos6
        exit 0 ;;
-    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R4000:UNIX_SV:*:*)
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
        if [ -d /usr/nec ]; then
                echo mips-nec-sysv${UNAME_RELEASE}
        else
@@ -853,6 +974,9 @@ EOF
     *:Rhapsody:*:*)
        echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
        exit 0 ;;
+    *:QNX:*:4*)
+       echo i386-qnx-qnx${UNAME_VERSION}
+       exit 0 ;;
 esac
 
 #echo '(No uname command or uname output not recognized.)' 1>&2
@@ -959,7 +1083,7 @@ main ()
 }
 EOF
 
-${CC-cc} $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm $dummy.c $dummy && exit 0
+$CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm $dummy.c $dummy && exit 0
 rm -f $dummy.c $dummy
 
 # Apollos put the system type in the environment.
index ecf770cea1c44bab8155178bee51c97c62c7432a..28426bb8fa0abac1f35de4b4b587faeff310a936 100755 (executable)
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Configuration validation subroutine script, version 1.1.
-#   Copyright (C) 1991, 92-97, 1998 Free Software Foundation, Inc.
+#   Copyright (C) 1991, 92-97, 1998, 1999 Free Software Foundation, Inc.
 # This file is (in principle) common to ALL GNU software.
 # The presence of a machine in this file suggests that SOME GNU software
 # can handle that machine.  It does not imply ALL GNU software can.
@@ -98,11 +98,21 @@ case $os in
                os=
                basic_machine=$1
                ;;
+       -sim | -cisco | -oki | -wec | -winbond)
+               os=
+               basic_machine=$1
+               ;;
+       -scout)
+               ;;
+       -wrs)
+               os=-vxworks
+               basic_machine=$1
+               ;;
        -hiux*)
                os=-hiuxwe2
                ;;
        -sco5)
-               os=sco3.2v5
+               os=-sco3.2v5
                basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
                ;;
        -sco4)
@@ -121,6 +131,9 @@ case $os in
                os=-sco3.2v2
                basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
                ;;
+       -udk*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
        -isc)
                os=-isc2.2
                basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
@@ -143,23 +156,33 @@ case $os in
        -psos*)
                os=-psos
                ;;
+       -mint | -mint[0-9]*)
+               basic_machine=m68k-atari
+               os=-mint
+               ;;
 esac
 
 # Decode aliases for certain CPU-COMPANY combinations.
 case $basic_machine in
        # Recognize the basic CPU types without company name.
        # Some are omitted here because they have special meanings below.
-       tahoe | i860 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \
+       tahoe | i860 | ia64 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \
                | arme[lb] | pyramid | mn10200 | mn10300 | tron | a29k \
-               | 580 | i960 | h8300 | hppa | hppa1.0 | hppa1.1 | hppa2.0 \
-               | hppa2.0w \
-               | alpha | alphaev5 | alphaev56 | we32k | ns16k | clipper \
-               | i370 | sh | powerpc | powerpcle | 1750a | dsp16xx | pdp11 \
-               | mips64 | mipsel | mips64el | mips64orion | mips64orionel \
-               | mipstx39 | mipstx39el | armv[34][lb] \
-               | sparc | sparclet | sparclite | sparc64 | v850)
+               | 580 | i960 | h8300 \
+               | hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \
+               | alpha | alphaev[4-7] | alphaev56 | alphapca5[67] \
+               | we32k | ns16k | clipper | i370 | sh | powerpc | powerpcle \
+               | 1750a | dsp16xx | pdp11 | mips16 | mips64 | mipsel | mips64el \
+               | mips64orion | mips64orionel | mipstx39 | mipstx39el \
+               | mips64vr4300 | mips64vr4300el | mips64vr4100 | mips64vr4100el \
+               | mips64vr5000 | miprs64vr5000el | mcore \
+               | sparc | sparclet | sparclite | sparc64 | sparcv9 | v850 | c4x \
+               | thumb | d10v | fr30)
                basic_machine=$basic_machine-unknown
                ;;
+       m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | z8k | v70 | h8500 | w65 | pj | pjl)
+               ;;
+
        # We use `pc' rather than `unknown'
        # because (1) that's what they normally are, and
        # (2) the word "unknown" tends to confuse beginning users.
@@ -172,28 +195,45 @@ case $basic_machine in
                exit 1
                ;;
        # Recognize the basic CPU types with company name.
-       vax-* | tahoe-* | i[34567]86-* | i860-* | m32r-* | m68k-* | m68000-* \
+       # FIXME: clean up the formatting here.
+       vax-* | tahoe-* | i[34567]86-* | i860-* | ia64-* | m32r-* | m68k-* | m68000-* \
              | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \
              | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \
-             | power-* | none-* | 580-* | cray2-* | h8300-* | i960-* \
-             | xmp-* | ymp-* | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* \
-             | hppa2.0w-* \
-             | alpha-* | alphaev5-* | alphaev56-* | we32k-* | cydra-* \
-             | ns16k-* | pn-* | np1-* | xps100-* | clipper-* | orion-* \
+             | power-* | none-* | 580-* | cray2-* | h8300-* | h8500-* | i960-* \
+             | xmp-* | ymp-* \
+             | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* | hppa2.0w-* | hppa2.0n-* \
+             | alpha-* | alphaev[4-7]-* | alphaev56-* | alphapca5[67]-* \
+             | we32k-* | cydra-* | ns16k-* | pn-* | np1-* | xps100-* \
+             | clipper-* | orion-* \
              | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \
-             | sparc64-* | mips64-* | mipsel-* | armv[34][lb]-*\
-             | mips64el-* | mips64orion-* | mips64orionel-*  \
-             | mipstx39-* | mipstx39el-* \
-             | f301-* | armv*-*)
+             | sparc64-* | sparcv9-* | sparc86x-* | mips16-* | mips64-* | mipsel-* \
+             | mips64el-* | mips64orion-* | mips64orionel-* \
+             | mips64vr4100-* | mips64vr4100el-* | mips64vr4300-* | mips64vr4300el-* \
+             | mipstx39-* | mipstx39el-* | mcore-* \
+             | f301-* | armv*-* | t3e-* \
+             | m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | d10v-* \
+             | thumb-* | v850-* | d30v-* | tic30-* | c30-* | fr30-* )
                ;;
        # Recognize the various machine names and aliases which stand
        # for a CPU type and a company and sometimes even an OS.
+       386bsd)
+               basic_machine=i386-unknown
+               os=-bsd
+               ;;
        3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
                basic_machine=m68000-att
                ;;
        3b*)
                basic_machine=we32k-att
                ;;
+       a29khif)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       adobe68k)
+               basic_machine=m68010-adobe
+               os=-scout
+               ;;
        alliant | fx80)
                basic_machine=fx80-alliant
                ;;
@@ -223,6 +263,10 @@ case $basic_machine in
                basic_machine=m68k-apollo
                os=-sysv
                ;;
+       apollo68bsd)
+               basic_machine=m68k-apollo
+               os=-bsd
+               ;;
        aux)
                basic_machine=m68k-apple
                os=-aux
@@ -299,6 +343,10 @@ case $basic_machine in
        encore | umax | mmax)
                basic_machine=ns32k-encore
                ;;
+       es1800 | OSE68k | ose68k | ose | OSE)
+               basic_machine=m68k-ericsson
+               os=-ose
+               ;;
        fx2800)
                basic_machine=i860-alliant
                ;;
@@ -317,6 +365,14 @@ case $basic_machine in
                basic_machine=h8300-hitachi
                os=-hms
                ;;
+       h8300xray)
+               basic_machine=h8300-hitachi
+               os=-xray
+               ;;
+       h8500hms)
+               basic_machine=h8500-hitachi
+               os=-hms
+               ;;
        harris)
                basic_machine=m88k-harris
                os=-sysv3
@@ -332,13 +388,30 @@ case $basic_machine in
                basic_machine=m68k-hp
                os=-hpux
                ;;
+       hp3k9[0-9][0-9] | hp9[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
        hp9k2[0-9][0-9] | hp9k31[0-9])
                basic_machine=m68000-hp
                ;;
        hp9k3[2-9][0-9])
                basic_machine=m68k-hp
                ;;
-       hp9k7[0-9][0-9] | hp7[0-9][0-9] | hp9k8[0-9]7 | hp8[0-9]7)
+       hp9k6[0-9][0-9] | hp6[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hp9k7[0-79][0-9] | hp7[0-79][0-9])
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k78[0-9] | hp78[0-9])
+               # FIXME: really hppa2.0-hp
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+               # FIXME: really hppa2.0-hp
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[0-9][13679] | hp8[0-9][13679])
                basic_machine=hppa1.1-hp
                ;;
        hp9k8[0-9][0-9] | hp8[0-9][0-9])
@@ -347,17 +420,16 @@ case $basic_machine in
        hppa-next)
                os=-nextstep3
                ;;
-       hp3k9[0-9][0-9] | hp9[0-9][0-9])
-               basic_machine=hppa1.0-hp
-               os=-mpeix
+       hppaosf)
+               basic_machine=hppa1.1-hp
+               os=-osf
                ;;
-       hp3k9[0-9][0-9] | hp9[0-9][0-9])
-               basic_machine=hppa1.0-hp
-               os=-mpeix
+       hppro)
+               basic_machine=hppa1.1-hp
+               os=-proelf
                ;;
        i370-ibm* | ibm*)
                basic_machine=i370-ibm
-               os=-mvs
                ;;
 # I'm not sure what "Sysv32" means.  Should this be sysv3.2?
        i[34567]86v32)
@@ -376,6 +448,25 @@ case $basic_machine in
                basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
                os=-solaris2
                ;;
+       i386mach)
+               basic_machine=i386-mach
+               os=-mach
+               ;;
+       i386-vsta | vsta)
+               basic_machine=i386-unknown
+               os=-vsta
+               ;;
+       i386-go32 | go32)
+               basic_machine=i386-unknown
+               os=-go32
+               ;;
+       i386-mingw32 | mingw32)
+               basic_machine=i386-unknown
+               os=-mingw32
+               ;;
+       i386-qnx | qnx)
+               basic_machine=i386-qnx
+               ;;
        iris | iris4d)
                basic_machine=mips-sgi
                case $os in
@@ -404,6 +495,10 @@ case $basic_machine in
        miniframe)
                basic_machine=m68000-convergent
                ;;
+       *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+               basic_machine=m68k-atari
+               os=-mint
+               ;;
        mipsel*-linux*)
                basic_machine=mipsel-unknown
                os=-linux-gnu
@@ -418,12 +513,28 @@ case $basic_machine in
        mips3*)
                basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
                ;;
+       monitor)
+               basic_machine=m68k-rom68k
+               os=-coff
+               ;;
+       msdos)
+               basic_machine=i386-unknown
+               os=-msdos
+               ;;
+       mvs)
+               basic_machine=i370-ibm
+               os=-mvs
+               ;;
        ncr3000)
                basic_machine=i486-ncr
                os=-sysv4
                ;;
+       netbsd386)
+               basic_machine=i386-unknown
+               os=-netbsd
+               ;;
        netwinder)
-               basic_machine=armv4l-corel
+               basic_machine=armv4l-rebel
                os=-linux
                ;;
        news | news700 | news800 | news900)
@@ -438,6 +549,10 @@ case $basic_machine in
                basic_machine=mips-sony
                os=-newsos
                ;;
+       necv70)
+               basic_machine=v70-nec
+               os=-sysv
+               ;;
        next | m*-next )
                basic_machine=m68k-next
                case $os in
@@ -463,9 +578,25 @@ case $basic_machine in
                basic_machine=i960-intel
                os=-nindy
                ;;
+       mon960)
+               basic_machine=i960-intel
+               os=-mon960
+               ;;
        np1)
                basic_machine=np1-gould
                ;;
+       op50n-* | op60c-*)
+               basic_machine=hppa1.1-oki
+               os=-proelf
+               ;;
+       OSE68000 | ose68000)
+               basic_machine=m68000-ericsson
+               os=-ose
+               ;;
+       os68k)
+               basic_machine=m68k-none
+               os=-os68k
+               ;;
        pa-hitachi)
                basic_machine=hppa1.1-hitachi
                os=-hiuxwe2
@@ -483,19 +614,19 @@ case $basic_machine in
         pc532 | pc532-*)
                basic_machine=ns32k-pc532
                ;;
-       pentium | p5 | k5 | nexen)
+       pentium | p5 | k5 | k6 | nexen)
                basic_machine=i586-pc
                ;;
-       pentiumpro | p6 | k6 | 6x86)
+       pentiumpro | p6 | 6x86)
                basic_machine=i686-pc
                ;;
        pentiumii | pentium2)
                basic_machine=i786-pc
                ;;
-       pentium-* | p5-* | k5-* | nexen-*)
+       pentium-* | p5-* | k5-* | k6-* | nexen-*)
                basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
                ;;
-       pentiumpro-* | p6-* | k6-* | 6x86-*)
+       pentiumpro-* | p6-* | 6x86-*)
                basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
                ;;
        pentiumii-* | pentium2-*)
@@ -519,12 +650,20 @@ case $basic_machine in
        ps2)
                basic_machine=i386-ibm
                ;;
+       rom68k)
+               basic_machine=m68k-rom68k
+               os=-coff
+               ;;
        rm[46]00)
                basic_machine=mips-siemens
                ;;
        rtpc | rtpc-*)
                basic_machine=romp-ibm
                ;;
+       sa29200)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
        sequent)
                basic_machine=i386-sequent
                ;;
@@ -532,6 +671,10 @@ case $basic_machine in
                basic_machine=sh-hitachi
                os=-hms
                ;;
+       sparclite-wrs)
+               basic_machine=sparclite-wrs
+               os=-vxworks
+               ;;
        sps7)
                basic_machine=m68k-bull
                os=-sysv2
@@ -539,6 +682,13 @@ case $basic_machine in
        spur)
                basic_machine=spur-unknown
                ;;
+       st2000)
+               basic_machine=m68k-tandem
+               ;;
+       stratus)
+               basic_machine=i860-stratus
+               os=-sysv4
+               ;;
        sun2)
                basic_machine=m68000-sun
                ;;
@@ -583,6 +733,10 @@ case $basic_machine in
                basic_machine=i386-sequent
                os=-dynix
                ;;
+       t3e)
+               basic_machine=t3e-cray
+               os=-unicos
+               ;;
        tx39)
                basic_machine=mipstx39-unknown
                ;;
@@ -600,6 +754,10 @@ case $basic_machine in
                basic_machine=a29k-nyu
                os=-sym1
                ;;
+       v810 | necv810)
+               basic_machine=v810-nec
+               os=-none
+               ;;
        vaxv)
                basic_machine=vax-dec
                os=-sysv
@@ -623,6 +781,14 @@ case $basic_machine in
                basic_machine=a29k-wrs
                os=-vxworks
                ;;
+       w65*)
+               basic_machine=w65-wdc
+               os=-none
+               ;;
+       w89k-*)
+               basic_machine=hppa1.1-winbond
+               os=-proelf
+               ;;
        xmp)
                basic_machine=xmp-cray
                os=-unicos
@@ -630,6 +796,10 @@ case $basic_machine in
         xps | xps100)
                basic_machine=xps100-honeywell
                ;;
+       z8k-*-coff)
+               basic_machine=z8k-unknown
+               os=-sim
+               ;;
        none)
                basic_machine=none-none
                os=-none
@@ -637,6 +807,15 @@ case $basic_machine in
 
 # Here we handle the default manufacturer of certain CPU types.  It is in
 # some cases the only manufacturer, in others, it is the most popular.
+       w89k)
+               basic_machine=hppa1.1-winbond
+               ;;
+       op50n)
+               basic_machine=hppa1.1-oki
+               ;;
+       op60c)
+               basic_machine=hppa1.1-oki
+               ;;
        mips)
                if [ x$os = x-linux-gnu ]; then
                        basic_machine=mips-unknown
@@ -659,7 +838,7 @@ case $basic_machine in
        we32k)
                basic_machine=we32k-att
                ;;
-       sparc)
+       sparc | sparcv9)
                basic_machine=sparc-sun
                ;;
         cydra)
@@ -671,6 +850,16 @@ case $basic_machine in
        orion105)
                basic_machine=clipper-highlevel
                ;;
+       mac | mpw | mac-mpw)
+               basic_machine=m68k-apple
+               ;;
+       pmac | pmac-mpw)
+               basic_machine=powerpc-apple
+               ;;
+       c4x*)
+               basic_machine=c4x-none
+               os=-coff
+               ;;
        *)
                echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
                exit 1
@@ -724,14 +913,21 @@ case $os in
              | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
              | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
              | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
-             | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* \
+             | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
              | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
              | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
              | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
-             | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -rhapsody* \
-             | -openstep* | -mpeix* | -oskit*)
+             | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
+             | -interix* | -uwin* | -rhapsody* | -opened* | -openstep* | -oskit*)
        # Remember, each alternative MUST END IN *, to match a version number.
                ;;
+       -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+             | -windows* | -osx | -abug | -netware* | -os9* | -beos* \
+             | -macos* | -mpw* | -magic* | -mon960* | -lnews*)
+               ;;
+       -mac*)
+               os=`echo $os | sed -e 's|mac|macos|'`
+               ;;
        -linux*)
                os=`echo $os | sed -e 's|linux|linux-gnu|'`
                ;;
@@ -741,6 +937,9 @@ case $os in
        -sunos6*)
                os=`echo $os | sed -e 's|sunos6|solaris3|'`
                ;;
+       -opened*)
+               os=-openedition
+               ;;
        -osfrose*)
                os=-osfrose
                ;;
@@ -756,6 +955,9 @@ case $os in
        -acis*)
                os=-aos
                ;;
+       -386bsd)
+               os=-bsd
+               ;;
        -ctix* | -uts*)
                os=-sysv
                ;;
@@ -775,6 +977,9 @@ case $os in
        -oss*)
                os=-sysv3
                ;;
+        -qnx)
+               os=-qnx4
+               ;;
        -svr4)
                os=-sysv4
                ;;
@@ -787,9 +992,18 @@ case $os in
        # This must come after -sysvr4.
        -sysv*)
                ;;
+       -ose*)
+               os=-ose
+               ;;
+       -es1800*)
+               os=-ose
+               ;;
        -xenix)
                os=-xenix
                ;;
+        -*mint | -*MiNT)
+               os=-mint
+               ;;
        -none)
                ;;
        *)
@@ -815,7 +1029,7 @@ case $basic_machine in
        *-acorn)
                os=-riscix1.2
                ;;
-       arm*-corel)
+       arm*-rebel)
                os=-linux
                ;;
        arm*-semi)
@@ -839,6 +1053,15 @@ case $basic_machine in
                # default.
                # os=-sunos4
                ;;
+       m68*-cisco)
+               os=-aout
+               ;;
+       mips*-cisco)
+               os=-elf
+               ;;
+       mips*-*)
+               os=-elf
+               ;;
        *-tti)  # must be before sparc entry or we get the wrong os.
                os=-sysv3
                ;;
@@ -851,6 +1074,15 @@ case $basic_machine in
        *-ibm)
                os=-aix
                ;;
+       *-wec)
+               os=-proelf
+               ;;
+       *-winbond)
+               os=-proelf
+               ;;
+       *-oki)
+               os=-proelf
+               ;;
        *-hp)
                os=-hpux
                ;;
@@ -914,6 +1146,18 @@ case $basic_machine in
        f301-fujitsu)
                os=-uxpv
                ;;
+       *-rom68k)
+               os=-coff
+               ;;
+       *-*bug)
+               os=-coff
+               ;;
+       *-apple)
+               os=-macos
+               ;;
+       *-atari*)
+               os=-mint
+               ;;
        *)
                os=-none
                ;;
@@ -935,10 +1179,10 @@ case $basic_machine in
                        -aix*)
                                vendor=ibm
                                ;;
-                       -hpux*)
-                               vendor=hp
+                       -beos*)
+                               vendor=be
                                ;;
-                       -mpeix*)
+                       -hpux*)
                                vendor=hp
                                ;;
                        -mpeix*)
@@ -959,7 +1203,7 @@ case $basic_machine in
                        -genix*)
                                vendor=ns
                                ;;
-                       -mvs*)
+                       -mvs* | -opened*)
                                vendor=ibm
                                ;;
                        -ptx*)
@@ -971,6 +1215,15 @@ case $basic_machine in
                        -aux*)
                                vendor=apple
                                ;;
+                       -hms*)
+                               vendor=hitachi
+                               ;;
+                       -mpw* | -macos*)
+                               vendor=apple
+                               ;;
+                       -*mint | -*MiNT)
+                               vendor=atari
+                               ;;
                esac
                basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
                ;;
index a1382119841f93fc8225101d240352a808ac857b..2a3b4ad0a1228c7fa201e0a523d6d2caf0cc8853 100644 (file)
@@ -33,7 +33,7 @@ case "$target" in
     ;;
 esac
 
-AM_INIT_AUTOMAKE(silc, 28062000)
+AM_INIT_AUTOMAKE(silc, 20001101)
 AC_PREREQ(2.3)
 AM_CONFIG_HEADER(includes/silcdefs.h)
 
@@ -68,7 +68,7 @@ AC_HEADER_STAT
 AC_CHECK_HEADERS(unistd.h string.h getopt.h errno.h fcntl.h assert.h)
 AC_CHECK_HEADERS(sys/types.h sys/stat.h sys/time.h)
 AC_CHECK_HEADERS(netinet/in.h netinet/tcp.h netdb.h)
-AC_CHECK_HEADERS(pwd.h grp.h termcap.h)
+AC_CHECK_HEADERS(pwd.h grp.h termcap.h paths.h)
 AC_CHECK_HEADERS(ncurses.h signal.h ctype.h)
 AC_CHECK_HEADERS(arpa/inet.h sys/mman.h)
 
@@ -114,13 +114,110 @@ AC_ARG_ENABLE(debug,
     ;;
   *)
     AC_MSG_RESULT(no)
-    CFLAGS="-O2 $CFLAGS"
+    CFLAGS="-O2 -g $CFLAGS"
     ;;
-esac ], CFLAGS="-O2 $CFLAGS"
+esac ], CFLAGS="-O2 -g $CFLAGS"
         AC_MSG_RESULT(no))
 
-# XXX
-#LIBS="$LIBS -lefence"
+# SOCKS4 support checking
+AC_MSG_CHECKING(whether to support SOCKS4)
+AC_ARG_WITH(socks4,
+[  --with-socks4[=PATH]    Compile with SOCKS4 support.],
+[ case "$withval" in
+  no)
+    AC_MSG_RESULT(no)
+    ;;
+  *)
+    AC_MSG_RESULT(yes)
+    socks=4
+
+    if test -d "$withval/include"; then
+      CFLAGS="$CFLAGS -I$withval/include"
+    else
+      CFLAGS="$CFLAGS -I$withval"
+    fi
+    if test -d "$withval/lib"; then
+      withval="-L$withval/lib -lsocks"
+    else
+      withval="-L$withval -lsocks"
+    fi
+
+    LIBS="$withval $LIBS"
+
+    AC_TRY_LINK([],
+                [ Rconnect(); ],
+                [],
+                [ AC_MSG_ERROR(Could not find SOCKS4 library.)])
+      ;;
+  esac ],
+  AC_MSG_RESULT(no)
+)   
+
+# SOCKS5 support checking
+AC_MSG_CHECKING(whether to support SOCKS5)
+AC_ARG_WITH(socks5,
+[  --with-socks5[=PATH]    Compile with SOCKS5 support.],
+[ case "$withval" in
+  no)
+    AC_MSG_RESULT(no)
+    ;;
+  *)
+    AC_MSG_RESULT(yes)
+    socks=5
+
+    if test -d "$withval/include"; then
+      CFLAGS="$CFLAGS -I$withval/include"
+    else
+      CFLAGS="$CFLAGS -I$withval"
+    fi
+    if test -d "$withval/lib"; then
+      withval="-L$withval/lib -lsocks5"
+    else
+      withval="-L$withval -lsocks5"
+    fi 
+
+    LIBS="$withval $LIBS"
+
+    AC_TRY_LINK([],
+                [ SOCKSconnect(); ],
+                [],
+                [ AC_MSG_ERROR(Could not find SOCKS5 library.)])
+      ;;
+  esac ],
+  AC_MSG_RESULT(no)
+)   
+
+if test "x$socks" = "x4"; then
+  AC_DEFINE(SOCKS)
+  CFLAGS="$CFLAGS -Dconnect=Rconnect -Dgetsockname=Rgetsockname -Dbind=Rbind -Daccept=Raccept -Dlisten=Rlisten -Dselect=Rselect"
+fi
+
+if test "x$socks" = "x5"; then
+  AC_DEFINE(SOCKS)
+  AC_DEFINE(SOCKS5)
+  AC_DEFINE(Rconnect, SOCKSconnect)
+  AC_DEFINE(Rgetsockname, SOCKSgetsockname)
+  AC_DEFINE(Rgetpeername, SOCKSgetpeername)
+  AC_DEFINE(Rbind, SOCKSbind)
+  AC_DEFINE(Raccept, SOCKSaccept)
+  AC_DEFINE(Rlisten, SOCKSlisten)
+  AC_DEFINE(Rselect, SOCKSselect)
+  AC_DEFINE(Rrecvfrom, SOCKSrecvfrom)
+  AC_DEFINE(Rsendto, SOCKSsendto)
+  AC_DEFINE(Rrecv, SOCKSrecv)
+  AC_DEFINE(Rsend, SOCKSsend)
+  AC_DEFINE(Rread, SOCKSread)
+  AC_DEFINE(Rwrite, SOCKSwrite)
+  AC_DEFINE(Rrresvport, SOCKSrresvport)
+  AC_DEFINE(Rshutdown, SOCKSshutdown)
+  AC_DEFINE(Rlisten, SOCKSlisten)
+  AC_DEFINE(Rclose, SOCKSclose)
+  AC_DEFINE(Rdup, SOCKSdup)
+  AC_DEFINE(Rdup2, SOCKSdup2)
+  AC_DEFINE(Rfclose, SOCKSfclose)
+  AC_DEFINE(Rgethostbyname, SOCKSgethostbyname)
+fi
+
 
 AC_ARG_WITH(silcd-config-file,
 [  --with-silcd-config-file[=PATH]
@@ -128,20 +225,27 @@ AC_ARG_WITH(silcd-config-file,
                           server.],
 [ AC_DEFINE_UNQUOTED(SILC_SERVER_CONFIG_FILE, "$withval") ])
 
+# XXX
+#LIBS="$LIBS -lefence"
+
 # Other configure scripts
 #AC_CONFIG_SUBDIRS(lib/zlib)
-AC_CONFIG_SUBDIRS(lib/silcmath/gmp-3.0.1)
+AC_CONFIG_SUBDIRS(lib/silcmath/gmp)
+AC_CONFIG_SUBDIRS(lib/trq)
 
 AC_OUTPUT( \
 Makefile
 doc/Makefile
 includes/Makefile
 lib/Makefile
+lib/contrib/Makefile
+lib/silcclient/Makefile
 lib/silccore/Makefile
 lib/silccrypt/Makefile
 lib/silcmath/Makefile
 lib/silcsim/Makefile
 lib/silcsim/modules/Makefile
 lib/silcske/Makefile
+lib/silcutil/Makefile
 silc/Makefile
 silcd/Makefile)
index 0393f347ca1e73a3555fa04eca0a0873afa55760..251deb918c967d66cd05e3dd1f5cb6a7928f0afe 100644 (file)
@@ -1,7 +1,7 @@
 Coding Style in SILC source tree
 ================================
 
-This documents describes the coding style and coding conventions used
+This document describes the coding style and coding conventions used
 in the SILC source tree.  The purpose of the document is to describe the
 common way to program for SILC and thus should be learned when programming
 new code.  The document describes various conventions regarding variable
@@ -152,7 +152,7 @@ The <module> is the module you are programming currently.  You should
 have a pretty good idea what you are programming and what the module
 does.  For example, <cipher>, <config>, <command>, <packet>, etc.
 
-The <function> is the describtion of the functionality of the function
+The <function> is the description of the functionality of the function
 you are writing.  Naturally it should be self explanatory and weird
 short names should be avoided.  It is better to have long function
 names than some odd name that does not tell what it is about.  Function
@@ -283,7 +283,7 @@ General Appearance
 ==================
 
 The code should be clean and good to eye, although the function of it
-must always superseed the appearance.  However, it is nice to read code
+must always supersede the appearance.  However, it is nice to read code
 that looks good.  Here are some issues on general appearance.
 
        o Use empty lines when appropriate but not too much.  There
@@ -305,15 +305,16 @@ that looks good.  Here are some issues on general appearance.
 
        o If you are not sure about how something should be done or
          the code you've done is not finished, it should be commented
-         with XXX plus explanation what is going on.
+         with XXX plus explanation what is going on.  For example,
+          /* XXX hmm... how is this flushed? */
 
 
 Source Files
 
 All source files starts with header that includes the name of the author,
 copyright notice and the copyright policy, usually part of GNU GPL licence.
-Now, if this really isn't that important but some sort of header should
-be in all source files.
+Now, this really isn't that important but some sort of header should be in
+all source files.
 
 In the start of the source files should include the #include's that are
 needed.  All library source files must include `silcincludes.h', this is
@@ -336,6 +337,14 @@ functions if any of those exist.  After macros should include the
 public prototypes of the functions.  Go see any header file as an example.
 
 
+Using gotos
+===========
+
+Gotos are used in the SILC code quite often.  If you know how to use
+goto's properly then it is ok to use them for example to optimize the
+code.  However, if you don't know how to use goto's do not use them.
+
+
 Debug Messages
 ==============
 
@@ -388,7 +397,7 @@ must not be used directly.  There are functions like,
 
 You should always use silc_calloc instead of silc_malloc because
 silc_calloc automatically zeroes the allocated memory area.  This is
-imporant especially with structures because generally we want that all
+important especially with structures because generally we want that all
 fields, by default, are zero.
 
 So, instead of doing
@@ -411,13 +420,16 @@ by memset() before freeing the memory.  Common way to do is,
        memset(ptr, 'F', sizeof(*ptr));
        silc_free(ptr);
 
-Where 'F' indicates free'd memory if you ever check it with debugger.
+Where 'F' indicates free'd memory if you'd ever check it with debugger.
 Other choice is to use 0 instead of 'F'.  The pointer after freeing 
 should be set to NULL if appropriate, ptr = NULL.
 
 Note that some functions in the SILC library handles the zeroing of
 the memory area automatically, like for example, silc_buffer_free.
 
+Also note that all allocation routines assert()'s if the memory allocation
+fails, ie. system does not have free memory.
+
 
 Callback Programming
 ====================
diff --git a/doc/FAQ b/doc/FAQ
index b6da03030d589fe692adfa199b12d37753c1d8a6..44d9056616ea846ee217ec0b40335a980a4c70da 100644 (file)
--- a/doc/FAQ
+++ b/doc/FAQ
@@ -4,25 +4,90 @@ Frequently Asked Questions
 Q: What is SILC?
 A: SILC (Secure Internet Live Conferencing) is a protocol which provides
    secure conferencing services in the Internet over insecure channel.
-   SILC is IRC like although internally they are very different.  Biggest
-   similiarity between SILC and IRC is that they both provide conferencing
-   services and that SILC has almost same commands as IRC.  Other than
-   that they are nothing alike.
+   SILC superficially resembles IRC although internally they are very
+   different.  Biggest similarity between SILC and IRC is that they both
+   provide conferencing services and that SILC has almost same commands
+   as IRC.  Other than that they are nothing alike.  Biggest differences
+   are that SILC is secure what IRC is not in any way.  The network model
+   is also entirely different compared to IRC.
 
-   Biggest differences are that SILC is secure what IRC is not in any
-   way.  The network model is also entirely different compared to IRC.
+
+Q: Why SILC in the first place?
+A: Simply for fun, nothing more.  An actually for need back then when
+   it was started.  SILC has been very interesting and educational
+   project.
+
+
+Q: When SILC will be completed?
+A: SILC still has a lot things to do.  The time of completion is much
+   related to how many interested people is willing to join the effort.
+   It will be ready when it is ready.  The reason for release of the
+   current development version is just to get it out and people aware
+   that something like this exist.
+
+
+Q: Why use SILC? Why not IRC with SSL?
+A: Sure, that is possible, although, does that secure the entire IRC
+   network? And does that increase or decrease the lags and splits in
+   the IRC network?  Does that provide user based security where some
+   specific private message are secured.? Does that provide security
+   where some specific channel messages are secured?  Security is not
+   just about applying encryption to traffic and SILC is not just about
+   `encrypting the traffic'.  You cannot make insecure protocol suddenly
+   secure just by encrypting the traffic.  SILC is not meant to be IRC
+   replacement.  IRC is good for some things, SILC is good for same and
+   some other things.
 
 
 Q: Can I use SILC with IRC client?  What about can I use IRC with SILC
    client?
 A: Answer for both question is no.  IRC client is in no way compatible
-   with SILC server.  SILC client cannot currenly use IRC but this may
+   with SILC server.  SILC client cannot currently use IRC but this may
    change in the future if IRC support is added to the SILC client.  
    After that one could use both SILC and IRC with the same client.
    Although, even then one cannot talk from SILC network to IRC network.
    That just is not possible.
 
 
+Q: Why client/server protocol is based on IRC? Would it be more
+   interesting to implement something extensible and more powerful?
+A: They are not, not the least.  Have you read the protocol
+   specification?  The client superficially resembles IRC client but
+   everything that happens under the hood is nothing alike IRC.  SILC
+   could *never* support IRC because the entire network toppology is
+   different (hopefully more scalable and powerful).  So no, SILC protocol
+   (client or server) is not based on IRC.  Instead, I've taken good
+   things from IRC and leaved all the bad things behind and not even tried
+   to burden myself with the IRC caveats that will burden IRC and future
+   IRC projects til the end.  SILC client resembles IRC client because it
+   is easier for new users to start using SILC when they already know all
+   the commands.
+
+
+Q: Why SILC? Why not IRC3?
+A: Question that is justified no doubt of that.  I didn't start doing SILC
+   to be replacement for IRC.  SILC was something that didn't exist in
+   1996 or even today except that SILC is now released.  However, I did
+   check out the IRC3 project in 1997 when I started coding and planning
+   the SILC protocol.
+
+   But, IRC3 is problematic. Why? Because it still doesn't exist.  The
+   project is at the same spot where it was in 1997 when I checked it out.
+   And it was old project back then as well.  Couple of months ago I 
+   checked it again and nothing were happening.  That's the problem of IRC3
+   project.  The same almost happened to SILC as well as I wasn't making
+   real progress over the years.  I talked to the original author of IRC,
+   Jarkko Oikarinen, in 1997 and he directed me to the IRC3 project, 
+   although he said that IRC3 is a lot of talking and not that much of 
+   anything else.  I am not trying to put down the IRC3 project but its
+   problem is that no one in the project is able to make a decision what
+   is the best way to go about making the IRC3 and I wasn't going to be
+   part of that.  The fact is that if I would've gone to IRC3 project,
+   nor IRC3 or SILC would exist today.  I think IRC3 could be something
+   really great if they just would get their act together and start
+   coding the thing.
+
+
 Q: How secure SILC really is?
 A: A good question which I don't have a answer.  SILC has been tried to
    make as secure as possible.  However, there is no security protocol
@@ -51,7 +116,7 @@ A: A good question which I don't have a answer.  SILC has been tried to
         the public keys used in the SILC are not verified to be trusted.
 
       o IP spoofing is ineffective (because of encryption and trusted 
-        server keys).
+        keys).
 
       o Attacks that change the contents of the data or add extra
         data to the packets are ineffective (because of encryption and
@@ -65,26 +130,4 @@ A: A good question which I don't have a answer.  SILC has been tried to
         by using the best cryptographic algorithms out there.
 
 
-Q: Why SILC? Why not IRC3?
-A: Question that is justified no doubt of that.  I didn't start doing SILC
-   to be replacement for IRC.  SILC was something that didn't exist in
-   1996 or even today except that SILC is now released.  However, I did
-   check out the IRC3 project in 1997 when I started coding and planning
-   the SILC protocol.
-
-   But, IRC3 is problematic. Why? Because it still doesn't exist.  The
-   project is at the same spot where it was in 1997 when I checked it out.
-   And it was old project back then as well.  Couple of months ago I 
-   checked it again and nothing were happening.  That's the problem of IRC3
-   project.  The same almost to happened to SILC as well as I wasn't making
-   real progress over the years.  I talked to the original author of IRC,
-   Jarkko Oikarinen, in 1997 and he directed me to the IRC3 project, 
-   although he said that IRC3 is a lot of talking and not that much of 
-   anything else.  I am not trying to put down the IRC3 project but its
-   problem is that no one in the project is able to make a decision what
-   is the best way to go about making the IRC3 and I wasn't going to be
-   part of that.  The fact is that if I would've gone to IRC3 project,
-   nor IRC3 or SILC would exist today.  I think IRC3 could be something
-   really great if they just would get their act together and start
-   coding the thing.  I hope that the release of SILC gives a boost to
-   the IRC3 project as well.
+More to come later...
index 7f6fea86104f263e89122d107e72af8270e24e13..04e3cc7542f73ddfa2be8cd1d3b36ef9ff2513f6 100644 (file)
 AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
 
 all:
-       touch draft-riikonen-silc-spec-00.txt
-       touch draft-riikonen-silc-pp-00.txt
-       touch draft-riikonen-silc-ke-auth-00.txt
+       touch draft-riikonen-silc-spec-01.txt
+       touch draft-riikonen-silc-pp-01.txt
+       touch draft-riikonen-silc-ke-auth-01.txt
        -cd ..
 
 dist-hook:
-       -rm -f draft-riikonen*.txt
-       ./makerfc draft-riikonen-silc-spec-00.nroff \
-               draft-riikonen-silc-spec-00.txt
-       ./makerfc draft-riikonen-silc-pp-00.nroff \
-               draft-riikonen-silc-pp-00.txt
-       ./makerfc draft-riikonen-silc-ke-auth-00.nroff \
-               draft-riikonen-silc-ke-auth-00.txt
+       touch draft-riikonen-silc-spec-01.txt
+       touch draft-riikonen-silc-pp-01.txt
+       touch draft-riikonen-silc-ke-auth-01.txt
+       ./makerfc draft-riikonen-silc-spec-01.nroff \
+               draft-riikonen-silc-spec-01.txt
+       ./makerfc draft-riikonen-silc-pp-01.nroff \
+               draft-riikonen-silc-pp-01.txt
+       ./makerfc draft-riikonen-silc-ke-auth-01.nroff \
+               draft-riikonen-silc-ke-auth-01.txt
 
 EXTRA_DIST = \
        CodingStyle \
+       FAQ \
        example_silcd.conf \
        example_silc.conf \
        draft-riikonen*.txt
diff --git a/doc/Makefile.in b/doc/Makefile.in
deleted file mode 100644 (file)
index ed43946..0000000
+++ /dev/null
@@ -1,203 +0,0 @@
-# Makefile.in generated automatically by automake 1.3 from Makefile.am
-
-# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
-# This Makefile.in is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
-# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE.
-
-#
-#  Makefile.am
-#
-#  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
-#
-#  Copyright (C) 2000 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
-#  GNU General Public License for more details.
-#
-
-
-SHELL = /bin/sh
-
-srcdir = @srcdir@
-top_srcdir = @top_srcdir@
-VPATH = @srcdir@
-prefix = @prefix@
-exec_prefix = @exec_prefix@
-
-bindir = @bindir@
-sbindir = @sbindir@
-libexecdir = @libexecdir@
-datadir = @datadir@
-sysconfdir = @sysconfdir@
-sharedstatedir = @sharedstatedir@
-localstatedir = @localstatedir@
-libdir = @libdir@
-infodir = @infodir@
-mandir = @mandir@
-includedir = @includedir@
-oldincludedir = /usr/include
-
-DISTDIR =
-
-pkgdatadir = $(datadir)/@PACKAGE@
-pkglibdir = $(libdir)/@PACKAGE@
-pkgincludedir = $(includedir)/@PACKAGE@
-
-top_builddir = ..
-
-ACLOCAL = @ACLOCAL@
-AUTOCONF = @AUTOCONF@
-AUTOMAKE = @AUTOMAKE@
-AUTOHEADER = @AUTOHEADER@
-
-INSTALL = @INSTALL@
-INSTALL_PROGRAM = @INSTALL_PROGRAM@
-INSTALL_DATA = @INSTALL_DATA@
-INSTALL_SCRIPT = @INSTALL_SCRIPT@
-transform = @program_transform_name@
-
-NORMAL_INSTALL = :
-PRE_INSTALL = :
-POST_INSTALL = :
-NORMAL_UNINSTALL = :
-PRE_UNINSTALL = :
-POST_UNINSTALL = :
-build_alias = @build_alias@
-build_triplet = @build@
-host_alias = @host_alias@
-host_triplet = @host@
-target_alias = @target_alias@
-target_triplet = @target@
-CC = @CC@
-LN_S = @LN_S@
-MAKEINFO = @MAKEINFO@
-PACKAGE = @PACKAGE@
-RANLIB = @RANLIB@
-VERSION = @VERSION@
-
-AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
-
-EXTRA_DIST = \
-       CodingStyle \
-       example_silcd.conf \
-       example_silc.conf \
-       draft-riikonen*.txt
-mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
-CONFIG_HEADER = ../includes/silcdefs.h
-CONFIG_CLEAN_FILES = 
-DIST_COMMON =  Makefile.am Makefile.in
-
-
-DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
-
-TAR = tar
-GZIP = --best
-all: Makefile
-
-.SUFFIXES:
-$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
-       cd $(top_srcdir) && $(AUTOMAKE) --foreign doc/Makefile
-
-Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
-       cd $(top_builddir) \
-         && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
-
-tags: TAGS
-TAGS:
-
-
-distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
-
-subdir = doc
-
-distdir: $(DISTFILES)
-       @for file in $(DISTFILES); do \
-         d=$(srcdir); \
-         test -f $(distdir)/$$file \
-         || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
-         || cp -p $$d/$$file $(distdir)/$$file; \
-       done
-       $(MAKE) top_distdir="$(top_distdir)" distdir="$(distdir)" dist-hook
-info:
-dvi:
-check: all
-       $(MAKE)
-installcheck:
-install-exec: 
-       @$(NORMAL_INSTALL)
-
-install-data: 
-       @$(NORMAL_INSTALL)
-
-install: install-exec install-data all
-       @:
-
-uninstall: 
-
-install-strip:
-       $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install
-installdirs:
-
-
-mostlyclean-generic:
-       -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
-
-clean-generic:
-       -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
-
-distclean-generic:
-       -rm -f Makefile $(DISTCLEANFILES)
-       -rm -f config.cache config.log stamp-h stamp-h[0-9]*
-       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-
-maintainer-clean-generic:
-       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
-       -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
-mostlyclean:  mostlyclean-generic
-
-clean:  clean-generic mostlyclean
-
-distclean:  distclean-generic clean
-       -rm -f config.status
-
-maintainer-clean:  maintainer-clean-generic distclean
-       @echo "This command is intended for maintainers to use;"
-       @echo "it deletes files that may require special tools to rebuild."
-
-.PHONY: tags distdir info dvi installcheck install-exec install-data \
-install uninstall all installdirs mostlyclean-generic distclean-generic \
-clean-generic maintainer-clean-generic clean mostlyclean distclean \
-maintainer-clean
-
-
-all:
-       touch draft-riikonen-silc-spec-00.txt
-       touch draft-riikonen-silc-pp-00.txt
-       touch draft-riikonen-silc-ke-auth-00.txt
-       -cd ..
-
-dist-hook:
-       -rm -f draft-riikonen*.txt
-       ./makerfc draft-riikonen-silc-spec-00.nroff \
-               draft-riikonen-silc-spec-00.txt
-       ./makerfc draft-riikonen-silc-pp-00.nroff \
-               draft-riikonen-silc-pp-00.txt
-       ./makerfc draft-riikonen-silc-ke-auth-00.nroff \
-               draft-riikonen-silc-ke-auth-00.txt
-
-# Tell versions [3.59,3.63) of GNU make to not export all variables.
-# Otherwise a system limit (for SysV at least) may be exceeded.
-.NOEXPORT:
diff --git a/doc/development/lib_reference.sgml b/doc/development/lib_reference.sgml
new file mode 100644 (file)
index 0000000..3f1ad78
--- /dev/null
@@ -0,0 +1,335 @@
+<!doctype linuxdoc system>
+
+<!--
+#
+#  SILC Library Reference Manual SGML source code
+#
+#  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+#  Copyright (C) 2000 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
+#  GNU General Public License for more details.
+#
+
+-->
+
+<article>
+
+<!-- Title information -->
+
+<title>SILC Library Reference Manual
+<author>Pekka Riikonen <tt>priikone@poseidon.pspt.fi</tt>
+<date>Last updated: $Id$
+<abstract>
+This document describes the SILC Library functions and programming
+application interfaces.  The SILC Library is pretty much generic purpose
+library in many ways.  It includes routines for basic things like buffer
+management, network connection management, scheduling and task management.
+However, it includes a lot routines that are related only to SILC.  This
+document does not describe the implementation of the SILC client and SILC
+server.  They and their API's will be described in separate documents.
+</abstract>
+
+<!-- Table of contents -->
+<toc>
+
+<!-- Begin the document -->
+
+<sect>Overview
+
+<p>
+This document describes the SILC Library functions and programming
+application interfaces.  The SILC Library is pretty much generic purpose
+library in many ways.  It includes routines for basic things like buffer
+management, network connection management, scheduling and task management.
+However, it includes a lot routines that are related only to SILC.  This
+document does not describe the implementation of the SILC client and SILC
+server.  They and their API's will be described in separate documents.
+
+<sect><tt>lib/</tt> directory
+
+<p>
+This section describes the libraries implemented in the SILC Library
+as a whole.  The SILC package and the SILC library includes other libraries
+that are out of scope of this document.  Those libraries are mentioned
+separately and reference to the corresponding library manual is given.
+
+<sect1><tt>silccore</tt>
+
+<p>
+This directory includes the core library of the SILC.  It includes all the
+basic and common routines used by SILC client and server applications.
+This includes buffer management, file management, network connection
+mangement, task management and scheduling.
+
+<sect1><tt>silccrypt</tt>
+
+<p>
+This directory includes the crypto library.  It includes implementations
+of various cryptographic algrotihms, hash functions and public key
+cryptosystems.  It also includes cryptographically strong random number
+generator.  Most of the implementations of the algorithms are copied
+from other crypto libraries.
+
+<sect1><tt>silcmath</tt>
+
+<p>
+This directory includes math library.  It includes GNU MP library and
+some other routines.  The math library is tightly related to the crypto
+library and specificly public key cryptosystems.
+
+<sect2><tt>silcmath/gmp-3.0.1</tt>
+
+<p>
+This directory includes the GNU MP library.  The description of this
+library is out of scope of this document.  See 
+<url url="http://www.swox.com/gmp/"> for more detailed information.
+
+<sect1><tt>silcsim</tt>
+
+<p>
+This directory includes the SILC Module (SIM) library.  SIM's are dynamically
+loadable shared objects.
+
+<sect1><tt>silcske</tt>
+
+<p>
+This directory includes implementation of the SILC Key Exchange (SKE)
+protocol.  SKE protocol is used to perform key exchange between two
+connecting entities such as client and server.  The SKE protocol
+specification is described in the Internet Draft
+<tt>draft-riikonen-silc-ke-auth-00.txt</tt> document available from
+<url url="http://www.ietf.org">.
+
+<sect>Basic programming with SILC library
+
+<p>
+
+
+<sect>Core Library
+
+<p>
+SILC Core library includes all the basic and common routines used by
+SILC client and server applications.  This includes buffer management, 
+file management, network connection mangement, task management and scheduling.
+It also includes core components related to the actual SILC protocol
+implementation such as ID routines, ID cache system and SILC packet management.
+
+<p>
+This section lists all the public header files of the core library thus
+all the public application programming interfaces of the core library.
+
+<sect1>lib/silccore/id.h
+
+<p>
+   These are important ID types used in SILC. SILC server creates these
+   but SILC client has to handle these as well since these are used in
+   packet sending and reception. However, client never creates these
+   but it receives the correct ID's from server. Clients, servers and
+   channels are identified by the these ID's. Note that these are currently
+   IPv4 specific, although adding IPv6 support is not a bad task and SILC
+   protocol already supports IPv6.
+
+<sect2>Includes
+
+<p>
+<tt>#include "id.h"</tt>
+
+<sect2>Definitions
+
+<p>
+<verb>typedef unsigned char SilcIdType;</verb>
+<descrip><quote>
+Type definition for all ID types.
+</quote></descrip>
+
+<p>
+<verb>
+#define SILC_ID_SERVER_LEN
+#define SILC_ID_CLIENT_LEN
+#define SILC_ID_CHANNEL_LEN
+</verb>
+<descrip><quote>
+Length of the ID's.
+</quote></descrip>
+
+<p>
+<verb>
+#define SILC_ID_NONE
+#define SILC_ID_SERVER
+#define SILC_ID_CLIENT
+#define SILC_ID_CHANNEL
+</verb>
+<descrip><quote>
+All types of the ID's.
+</quote></descrip>
+
+<p>
+<verb>
+typedef struct {
+  struct in_addr ip;                           /* 32 bit IP */
+  unsigned short port;                         /* 16 bit port */
+  unsigned short rnd;                          /* 16 bit random number */
+} SilcServerID;
+</verb>
+<descrip><quote>
+Defines the Server ID structure.  This is used to distinguish a server in
+SILC network.
+</quote></descrip>
+
+<p>
+<verb>
+typedef struct {
+  struct in_addr ip;                           /* 32 bit IP */
+  unsigned char rnd;                           /* 8 bit random number */
+  unsigned char hash[CLIENTID_HASH_LEN];       /* 88 bit MD5 hash */
+} SilcClientID;
+</verb>
+<descrip><quote>
+Defines the Client ID structure.  This is used to distinguish a client in
+SILC network.
+</quote></descrip>
+
+<p>
+<verb>
+typedef struct {
+  struct in_addr ip;                           /* 32 bit IP */
+  unsigned short port;                         /* 16 bit port */
+  unsigned short rnd;                          /* 16 bit random number */
+} SilcChannelID;
+</verb>
+<descrip><quote>
+Defines the Channel ID structure.  This is used to distinguish a channel in
+SILC network.
+</quote></descrip>
+
+<sect2>Public Interface
+
+<p>
+<verb>
+unsigned char *silc_id_id2str(void *id, SilcIdType type);
+</verb>
+<descrip><quote>
+Converts ID to unsigned char string. First argument is a pointer of the
+ID to be converted, second argument is the of the ID. Returns the converted
+ID.
+</quote></descrip>
+
+<p>
+<verb>
+void *silc_id_str2id(unsigned char *id, SilcIdType type);
+</verb>
+<descrip><quote>
+Converts string to ID. First argument is the string ID seconf is the type
+of the ID. Returns the converted ID.
+</quote></descrip>
+
+<p>
+<verb>
+unsigned int silc_id_get_len(SilcIdType type);
+</verb>
+<descrip><quote>
+Returns length of a type of an ID.
+</quote></descrip>
+
+
+<sect1>lib/silccore/idcache.h
+<sect1>lib/silccore/silcbuffer.h
+<sect1>lib/silccore/silcbuffmt.h
+<sect1>lib/silccore/silcbufutil.h
+<sect1>lib/silccore/silcchannel.h
+<sect1>lib/silccore/silccommand.h
+<sect1>lib/silccore/silcconfig.h
+<sect1>lib/silccore/silclog.h
+<sect1>lib/silccore/silcmemory.h
+<sect1>lib/silccore/silcnet.h
+<sect1>lib/silccore/silcpacket.h
+<sect1>lib/silccore/silcprotocol.h
+<sect1>lib/silccore/silcschedule.h
+<sect1>lib/silccore/silcsockconn.h
+<sect1>lib/silccore/silctask.h
+<sect1>lib/silccore/silcutil.h
+
+
+<sect>Crypto Library
+
+<sect>Math Library
+
+<sect>SIM Library
+
+<sect>SKE library
+
+<p>
+All right, so you're typing along, and you want to show some example code,
+or example I/O with a program, whatever. Use the <tt/code/ or <tt/verb/
+``environments'' for this, wrapped in a <tt/tscreen/ environment, as so:
+<tscreen><verb>
+This is an example verb environment.
+</verb></tscreen>
+As well as:
+<tscreen><code>
+This is an example code environment.
+</code></tscreen>
+The <tt/tscreen/ environment just sets the font to small type and 
+indents it nicely. It's not required for using <tt/verb/ or <tt/code/,
+but I suggest that you do. 
+
+The <em/Linuxdoc-SGML User's Guide/ explains what special characters you
+can and can't use in the <tt/verb/ and <tt/code/ environments. 
+
+<sect1><heading><label id="test-ref">Cross references</>
+
+<p>
+What about cross-references? This section has been marked with the
+<tt>label</> command; using <tt>ref</> will provide a cross reference,
+as in ``See Section <ref id="test-ref">'' for more. 
+
+Right now cross-references don't work in the <tt/groff/ translation for 
+plain ASCII.  They do work when generating LaTeX or HTML output.
+
+<sect1>Using fonts
+
+<p>
+You want fonts, we got fonts. Of course these won't show up in the
+plain ASCII text, but they all map into the various output formats:
+<bf/boldface/, <em/emphasis/, <sf/sans serif/, <sl/slanted/,
+<tt/typewriter/, and <it/italics/.
+
+<sect1>Lists
+
+<p>
+Lists are easy as well. Just use the <tt/itemize/ element with the
+<tt/item/ commands, seen here:
+<itemize>
+<item> This is a list.
+<item> Nothing exciting about that.
+       <itemize> 
+       <item> Multiple levels are supported as well.
+       <item> Again, that's no surprise.
+       </itemize>
+       <enum>
+       <item> Enumerated lists using <tt>enum</> also work.
+       <item> Description environments using <tt>descrip</> along
+             with <tt>tag</> are also available, as seen here.
+       </enum>
+       <descrip>
+       <tag/First item./ Here's one item.
+       <tag/Second item./ Here's another.
+       <tag/Third item./ Can we go for three?
+       </descrip>
+<item> A final item to top it all off.
+</itemize>
+
+This is just about everything that you need to get started with
+writing SGML docs using the <tt/linuxdoc-sgml/ DTD. Please let me know
+if you think something should be changed or added to this document.
+
+</article>
index e4be714352a498e70e1c1109fe4de750647d63ec..18d604b32e6890695d407114ce0c4b8fac886983 100644 (file)
@@ -7,42 +7,43 @@
 .ds LF Riikonen
 .ds RF FORMFEED[Page %]
 .ds CF
-.ds LH Internet Draft
-.ds RH 27 June 2000
-.ds CH Key Exchange and Authentication
+.ds LH INTERNET-DRAFT
+.ds RH 13 September 2000
+.ds CH
 .na
 .hy 0
 .in 0
 .nf
 Network Working Group                                      P. Riikonen
-Internet-Draft
-draft-riikonen-silc-ke-auth-00.txt                        27 June 2000
-Expires: 27 Jan 2001
+INTERNET-DRAFT
+draft-riikonen-silc-ke-auth-00.txt                   13 September 2000
+Expires: 13 May 2001
 
 .in 3
 
-.ce
+.ce 2
 SILC Key Exchange and Authentication Protocols
+<draft-riikonen-silc-ke-auth-00.txt>
 
 .ti 0
 Status of this Memo
 
-This document is an Internet-Draft.  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
 
-To learn the current status of any Internet-Draft, please check the
-``1id-abstracts.txt'' listing contained in the Internet-Drafts
-Shadow Directories on ftp.is.co.za (Africa), nic.nordu.net (Europe),
-munnari.oz.au (Pacific Rim), ds.internic.net (US East Coast), or
-ftp.isi.edu (US West Coast).
+The list of Internet-Draft Shadow Directories can be accessed at
+http://www.ietf.org/shadow.html
 
 The distribution of this memo is unlimited.
 
@@ -241,6 +242,12 @@ not include spaces (` ').
 +                                                               +
 |                                                               |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|     Version String Length     |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                         Version String                        ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |   Key Exchange Grp Length     |                               |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
 |                                                               |
@@ -307,38 +314,47 @@ o Flags (1 byte) - Indicates flags to be used in the key
        must not be set.
 
 o Payload Length (2 bytes) - Length of the entire Key Exchange
-  Start payload.
+  Start payload, not including any other field.
 
 o Cookie (16 bytes) - Cookie that uniforms this payload so
   that each of the party cannot determine the payload before
   hand.
 
+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 of the version
+  string format.
+
 o Key Exchange Grp Length (2 bytes) - The length of the
-  key exchange group list, including this field as well.
+  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.1.2 SILC Key Exchange
   Groups for definitions of these groups.
 
 o PKCS Alg Length (2 bytes) - The length of the PKCS algorithms
-  list, including this field as well.
+  list, not including any other field.
 
 o PKCS Algorithms (variable length) - The list of PKCS 
   algorithms.
 
 o Encryption Alg Length (2 bytes) - The length of the encryption
-  algorithms list, including this field as well.
+  algorithms list, not including any other field.
 
 o Encryption Algorithms (variable length) - The list of
   encryption algorithms.
 
 o Hash Alg Length (2 bytes) - The length of the Hash algorithms
-  list, including this field as well.
+  list, not including any other field.
 
 o Hash Algorithms (variable length) - The list of Hash algorithms.
 
 o Compression Alg Length (2 bytes) - The length of the
-  compression algorithms list, including this field as well.
+  compression algorithms list, not including any other field.
 
 o Compression Algorithms (variable length) - The list of 
   compression algorithms.
@@ -401,9 +417,8 @@ Figure 2:  Key Exchange 1 Payload
 
 
 .in 6
-o Public Key Length (2 bytes) - The length of the public key
-  (or certificate), including this field and public key type
-  field as well.
+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 
@@ -425,8 +440,8 @@ o Public Key Type (2 bytes) - The public key (or certificate)
   sending SILC_PACKET_FAILURE message.
 
 o Public Data Length (2 bytes) - The length of the public
-  data computed by the responder, including this field
-  as well.
+  data computed by the responder, not including any other
+  field.
 
 o Public Data (variable length) - The public data to be
   sent to the responder.  See section 2.2 Key Exchange 
@@ -479,9 +494,8 @@ Figure 3:  Key Exchange 2 Payload
 
 
 .in 6
-o Public Key Length (2 bytes) - The length of the public key
-  (or certificate), including this field and public key type
-  field as well.
+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 
@@ -494,8 +508,8 @@ o Public Key of the host (variable length) - The public
   is indicated by previous Public Key Type field.
 
 o Public Data Length (2 bytes) - The length of the public
-  data computed by the responder, including this field
-  as well.
+  data computed by the responder, not including any other
+  field.
 
 o Public Data (variable length) - The public data computed
   by the responder.  See section 2.2 Key Exchange Procedure
@@ -503,7 +517,7 @@ o Public Data (variable length) - The public data computed
   value is binary encoded.
 
 o Signature Length (2 bytes) - The length of the signature,
-  including the length of this field as well.
+  not including any other field.
 
 o Signature Data (variable length) - The signature signed
   by the responder.  The receiver of this signature must
@@ -1036,3 +1050,6 @@ Kasarmikatu 11 A4
 Finland
 
 EMail: priikone@poseidon.pspt.fi
+
+This Internet-Draft expires 13 May 2001 
+
diff --git a/doc/draft-riikonen-silc-ke-auth-01.nroff b/doc/draft-riikonen-silc-ke-auth-01.nroff
new file mode 100644 (file)
index 0000000..8f71edc
--- /dev/null
@@ -0,0 +1,1057 @@
+.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 6 October 2000
+.ds CH
+.na
+.hy 0
+.in 0
+.nf
+Network Working Group                                      P. Riikonen
+Internet-Draft
+draft-riikonen-silc-ke-auth-01.txt                      6 October 2000
+Expires: 6 Jun 2001
+
+.in 3
+
+.ce 2
+SILC Key Exchange and Authentication Protocols
+<draft-riikonen-silc-ke-auth-01.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 internet-draft [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.  SKE uses best parts
+of the SSH2 Key Exchange protocol, Station-To-Station (STS) protocol
+and the OAKLEY Key Determination protocol [OAKLEY].
+
+The 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 user with, for example, passphrase
+(pre-shared- secret) or public key (and certificate).
+
+
+
+.ti 0
+Table of Contents
+
+.nf
+1 Introduction ..................................................  2
+2 SILC Key Exchange Protocol ....................................  3
+  2.1 Key Exchange Payloads .....................................  3
+      2.1.1 Key Exchange Start Payload ..........................  4
+      2.1.2 Key Exchange 1 Payload ..............................  7
+      2.1.3 Key Exchange 2 Payload ..............................  9
+  2.2 Key Exchange Procedure .................................... 10
+  2.3 Processing the Key Material ............................... 12
+  2.4 SILC Key Exchange Groups .................................. 13
+      2.4.1 diffie-hellman-group1 ............................... 13
+      2.4.2 diffie-hellman-group2 ............................... 14
+  2.5 Key Exchange Status Types ................................. 14
+3 SILC Connection Authentication Protocol ....................... 16
+  3.1 Connection Auth Payload ................................... 17
+  3.2 Connection Authentication Types ........................... 18
+      3.2.1 Passphrase Authentication ........................... 18
+      3.2.2 Public Key Authentication ........................... 18
+  3.3 Connection Authentication Status Types .................... 19
+4 Security Considerations ....................................... 19
+5 References .................................................... 19
+6 Author's Address .............................................. 20
+
+
+.ti 0
+List of Figures
+
+.nf
+Figure 1:  Key Exchange Start Payload
+Figure 2:  Key Exchange 1 Payload
+Figure 3:  Key Exchange 2 Payload
+Figure 4:  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 Internet-Draft [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.  SKE uses best parts
+of the SSH2 Key Exchange protocol, Station-To-Station (STS) protocol
+and the OAKLEY Key Determination protocol.
+
+The 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 user with, for example, passphrase
+(pre-shared- secret) or public key (and certificate).
+
+The basis of secure SILC session requires strong and secure key exchange
+protocol and authentication.  The authentication protocol is entirely
+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 refers constantly to other SILC protocol specification
+Internet Drafts that are a must read for those who wants to understand
+the function of these protocols.  The most important references are
+the Secure Internet Live Conferencing, Protocol Specification [SILC1]
+and SILC Packet Protocol [SILC2] Internet Drafts.
+
+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
+2 SILC Key Exchange Protocol
+
+SILC Key Exchange Protocol (SKE) is used to exchange shared secret
+between connecting entities.  The result of this protocol is a key
+material used to secure the communication channel.  The protocol uses
+Diffie-Hellman key exchange algorithm and its functionality is derived
+from several key exchange protocols.  SKE uses best parts of the SSH2
+Key Exchange protocol, Station-To-Station (STS) protocol and the OAKLEY
+Key Determination protocol.  The protocol does not claim any conformance
+to any of these protocols, they were merely used as a reference when
+designing this protocol.
+
+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 like commands, command replies and other
+communication between two entities.  If connection is server to server
+connection, the keys are used to protect all traffic between those
+servers.  In client connections usually all the packets are protected
+with this key except channel messages; channels has their own keys and 
+they are not exchanged with this protocol.
+
+
+.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, the same is done with these payloads as well.  All fields in
+all payloads are always in MSB (most significant byte first) order.
+Following descriptions of these payloads.
+
+
+.ti 0
+2.1.1 Key Exchange Start Payload
+
+Key exchange between two entities always begins with a
+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 responders 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 Key Exchange Start Payload is used to tell connecting entities what
+security properties and algorithms should be used in the communication.
+If perfect forward secrecy (PFS) is not desired (PFS is undefined by
+default) Key Exchange Start Payload is sent only once per session, thus,
+for example, re-keying will not cause sending of a new payload.  If PFS
+is desired, re-keying will always cause new key exchange thus causes
+sending of a new Key Exchange Start Payload.
+
+When performing first key exchange this payload is never encrypted, as
+there are no existing keys to encrypt it with.  If performing re-keying
+(PFS was selected) this payload is encrypted with the existing key and
+encryption algorithm.
+
+A cookie is also sent in this payload.  A cookie is used to uniform the
+payload so that none of the key exchange parties can determine this
+payload before hand.  The cookie must be returned to the original sender
+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 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                        ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|    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
+  zeroes (0).
+
+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.  Following flags are reserved for this field.
+
+     No flags              0x00
+
+       In this case the field is ignored.
+
+     No Reply              0x01
+
+       If set the receiver of the payload does not reply to 
+       the packet.
+
+     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.  When PFS is used, 
+       re-keying and creating new keys for any particular 
+       purpose will cause new key exchange.
+
+       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 uniforms this payload so
+  that each of the party cannot determine the payload before
+  hand.
+
+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 of the version
+  string format.
+
+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.1.2 SILC Key Exchange
+  Groups for definitions of these groups.
+
+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.
+
+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.
+
+o Hash Alg Length (2 bytes) - The length of the Hash algorithms
+  list, not including any other field.
+
+o Hash Algorithms (variable length) - The list of Hash algorithms.
+
+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.
+.in 3
+
+
+.ti 0
+2.1.2 Key Exchange 1 Payload
+
+Key Exchange 1 Payload is used to deliver computed public data from 
+initiator to responder.  This data is used to compute the shared secret,
+later by all parties.  Key Exchange 1 Payload is only sent after the 
+SILC_PACKET_KEY_EXCHANGE packet and the Key Exchange Start Payload has
+been processed by all the parties.
+
+This payload sends the initiator's public key to the responder.  Responder
+may need the public key in which case it should be checked to be trusted
+by the responder.
+The payload may only be sent with SILC_PACKET_KEY_EXCHANGE_1 packet.
+It must not be sent in any other packet type.  Following diagram 
+represent the Key Exchange 1 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 Host (or certificate)            ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|      Public Data Length       |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                 Public Data (e = g ^ x mod p)                 ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 2:  Key Exchange 1 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
+  SSH 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.
+
+o Public Data Length (2 bytes) - The length of the public
+  data computed by the responder, not including any other
+  field.
+
+o Public Data (variable length) - The public data to be
+  sent to the responder.  See section 2.2 Key Exchange 
+  Procedure for detailed description how this field is
+  computed.  This value is binary encoded.
+.in 3
+
+
+.ti 0
+2.1.3 Key Exchange 2 Payload
+
+Key Exchange 2 Payload is used to deliver public key, computed public
+data and signature from responder to initiator.  Initiator uses these
+public parts of the key exchange protocol to compute the shared secret.
+
+The payload may only be sent with SILC_PACKET_KEY_EXCHANGE_2 packet.
+It must not be sent in any other packet type.  Following diagram 
+represent the Key Exchange 2 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 Host (or certificate)            ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Public Data Length      |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                 Public Data (f = g ^ y mod p)                 ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Signature Length       |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                        Signature Data                         ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 3:  Key Exchange 2 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 previous sections for defined public key
+  types.
+
+o Public Key of the host (variable length) - The public
+  key of the sender (or its certificate).  This is verified
+  by the receiver of the packet.  The type of this field
+  is indicated by previous Public Key Type field.
+
+o Public Data Length (2 bytes) - The length of the public
+  data computed by the responder, not including any other
+  field.
+
+o Public Data (variable length) - The public data computed
+  by the responder.  See section 2.2 Key Exchange Procedure
+  for detailed description how this field is computed.  This
+  value is binary encoded.
+
+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 responder.  The receiver of this signature must
+  verify it.  The verification is done using the public
+  key received in this same payload.  See section 2.2
+  Key Exchange Procedure for detailed description how
+  to produce the signature.
+
+
+.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 1 Payload and sent
+        to the responder.
+
+
+    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(Key Exchange Start Payload data | Host 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 2 Payload and sends it to the 
+        initiator.
+
+
+    3.  Initiator verifies that the public key provided in
+        the payload is authentic, or if certificates are used
+        it verifies the certificate.  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 SILC_PACKET_FAILURE is sent to
+indicate that the key exchange protocol failed.  Any other packets must
+not be sent or accepted during the key exchange except the
+SILC_PACKET_KEY_EXCHANGE_*, SILC_PACKET_DISCONNECT, SILC_PACKET_FAILURE
+and/or 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.
+
+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 will 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.  This is used in the key
+deriving process as a session identifier.
+
+Keys are derived from the key material as follows:
+
+.in 6
+Sending Initial Vector (IV)     = hash(0 | KEY | HASH)
+Receiving Initial Vector (IV)   = hash(1 | KEY | HASH)
+Sending Encryption Key          = hash(2 | KEY | HASH)
+Receiving Encryption Key        = hash(3 | KEY | HASH)
+HMAC Key                        = hash(4 | 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 is
+produced in following manner:
+
+.in 6
+K1 = hash(2 | KEY | HASH)
+K2 = hash(KEY | K1)
+K3 = hash(KEY | K1 | K2)  ...
+
+Sending Encryption Key = K1 | K2 | K3 ...
+
+
+K1 = hash(3 | KEY | HASH)
+K2 = hash(KEY | K1)
+K3 = hash(KEY | 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 sending).
+
+The HMAC key is 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.
+
+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.
+
+
+.ti 0
+2.4 SILC Key Exchange Groups
+
+Following groups may be used in the SILC Key Exchange protocol.  The 
+first group diffie-hellman-group1 is mandatory, other groups maybe 
+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 on the list).
+
+
+.ti 0
+2.4.1 diffie-hellman-group1
+
+The length of this group is 1024 bits.  This is mandatory group.
+The prime is 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 }.
+
+Its decimal value is
+
+.in 6
+179769313486231590770839156793787453197860296048756011706444
+423684197180216158519368947833795864925541502180565485980503
+646440548199239100050792877003355816639229553136239076508735
+759914822574862575007425302077447712589550957937778424442426
+617334727629299387668709205606050270810842907692932019128194
+467627007
+.in 3
+
+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 the OAKLEY specification.
+
+
+.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 decimal value is
+
+.in 6
+241031242692103258855207602219756607485695054850245994265411
+694195810883168261222889009385826134161467322714147790401219
+650364895705058263194273070680500922306273474534107340669624
+601458936165977404102716924945320037872943417032584377865919
+814376319377685986952408894019557734611984354530154704374720
+774996976375008430892633929555996888245787241299381012913029
+459299994792636526405928464720973038494721168143446471443848
+8520940127459844288859336526896320919633919
+.in 3
+
+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 the OAKLEY specification.
+
+
+.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). Following status types are 
+defined:
+
+.in 6
+0   SILC_SKE_STATUS_OK
+
+    Protocol were executed successfully.
+
+
+1   SILC_SKE_STATUS_ERROR
+
+    Unknown error occured.  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_PUBLIC_KEY
+
+    Provided public key type is not supported.
+
+
+8   SILC_SKE_STATUS_INCORRECT_SIGNATURE
+
+    Provided signature was incorrect.
+
+
+9   SILC_SKE_STATUS_BAD_VERSION
+
+    Provided version string was not acceptable.
+.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 server as well.  Its other purpose is to provide
+information for the server about which type of connection this is.
+The type defines whether this is client, server or router connection.
+Server uses this information to create the ID for the connection.  After
+the authentication protocol has been successfully completed 
+SILC_PACKET_NEW_ID must be sent to the connecting party by the server.
+See section New ID Payload in [SILC2] for detailed description for this
+packet's payload.
+
+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 everything checks out fine 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 is started by the connecting party by sending
+SILC_PACKET_CONNECTION_AUTH packet with Connection Auth Payload,
+described in the next section.  This payload must include the
+authentication data.  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 must
+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 at all.  However, in this case the protocol still must be
+executed; the authentication data just is empty indicating no
+authentication is required.
+
+If authentication method is passphrase the authentication data is
+plaintext passphrase.  As the payload is entirely encrypted it is safe
+to have plaintext passphrase.  3.2.1 Passphrase Authentication for
+more information.
+
+
+If authentication method is public key authentication the authentication
+data is signature of the hash value HASH plus Key Exchange Start Payload,
+established by the SILC Key Exchange protocol.  This signature must then
+be verified by the server.  See section 3.2.2 Public Key Authentication
+for more information.
+
+The connecting party of this protocol must wait after successful execution
+of this protocol for the SILC_PACKET_NEW_ID packet where it will receive
+the ID it will be using in the SILC network.  Connecting party cannot
+start normal SILC session (sending messages or commands) until it has
+received its ID.  The ID's are always created by the server except
+for server to server connection where servers create their own ID's.
+
+
+
+.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.  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 4:  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 or public key based authentication.
+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 base 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.
+
+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.
+
+
+.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
+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.
+The server must verify the data, thus it must keep the HASH and the
+Key Exchange Start Payload saved during SKE and authentication protocols.
+
+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). 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.
+
+
+.ti 0
+5 References
+
+[SILC1]      Riikonen, P., "Secure Internet Live Conferencing (SILC),
+             Protocol Specification", Internet Draft, June 2000.
+
+[SILC2]      Riikonen, P., "SILC Packet Protocol", Internet Draft,
+             June 2000.
+
+[IRC]        Oikarinen, J., and Reed D., "Internet Relay Chat Protocol",
+             RFC 1459, May 1993.
+
+[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.
+
+
+.ti 0
+6 Author's Address
+
+.nf
+Pekka Riikonen
+Kasarmikatu 11 A4
+70110 Kuopio
+Finland
+
+EMail: priikone@poseidon.pspt.fi
+
+This Internet-Draft expires 6 Jun 2001 
+
index 7f907438a7c05785d7ac793be51376c7cfd65963..6aca37fb1339f1dc64b4acc5f4dfc47c4caf9cbc 100644 (file)
@@ -8,43 +8,44 @@
 .ds RF FORMFEED[Page %]
 .ds CF
 .ds LH Internet Draft
-.ds RH 27 June 2000
-.ds CH SILC Packet Protocol
+.ds RH 13 September 2000
+.ds CH
 .na
 .hy 0
 .in 0
 .nf
 Network Working Group                                      P. Riikonen
 Internet-Draft
-draft-riikonen-silc-pp-00.txt                             27 June 2000
-Expires: 27 Jan 2001
+draft-riikonen-silc-pp-00.txt                        13 September 2000
+Expires: 13 May 2001
 
 .in 3
 
-.ce
+.ce 2
 SILC Packet Protocol
+<draft-riikonen-silc-pp-00.txt>
 
 .ti 0
 Status of this Memo
 
-This document is an Internet-Draft.  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   
 
-To learn the current status of any Internet-Draft, please check the
-``1id-abstracts.txt'' listing contained in the Internet-Drafts
-Shadow Directories on ftp.is.co.za (Africa), nic.nordu.net (Europe),
-munnari.oz.au (Pacific Rim), ds.internic.net (US East Coast), or
-ftp.isi.edu (US West Coast).
+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
@@ -110,9 +111,10 @@ Table of Contents
   2.8 Packet Compression ........................................ 40
   2.9 Packet Sending ............................................ 40
   2.10 Packet Reception ......................................... 41
-  2.11 Packet Broadcasting ...................................... 41
-  2.12 Packet Routing ........................................... 42
-  2.13 Packet Tunneling ......................................... 42
+  2.11 Packet Routing ........................................... 42
+  2.12 Packet Forwarding ........................................
+  2.13 Packet Broadcasting ...................................... 41
+  2.14 Packet Tunneling ......................................... 42
 3 Security Considerations ....................................... 43
 4 References .................................................... 43
 5 Author's Address .............................................. 44
@@ -143,6 +145,7 @@ Figure 19:  New Channel Payload
 Figure 20:  New Channel User Payload
 Figure 21:  Replace ID Payload
 Figure 22:  Remove ID Payload
+Figure 23:  Remove Channel User Payload
 
 
 .ti 0
@@ -296,7 +299,16 @@ o Flags (1 byte) - Indicates flags to be used in packet
        Encryption And Decryption for more information.
 
 
-     Broadcast                 0x02
+     Forwarded                 0x02
+  
+       Marks the packet to be forwarded.  Some specific
+       packet types may be forwarded.  Receiver of packet
+       with this flag set must not forward the packet any
+       further.  See section 2.12 Packet Forwarding for
+       desribtion of packet forwarding.
+
+
+     Broadcast                 0x04
 
        Marks the packet to be broadcasted.  Client cannot
        send broadcast packet and normal server cannot send
@@ -305,16 +317,16 @@ o Flags (1 byte) - Indicates flags to be used in packet
        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.11 Packet Broadcasting for description of 
+       section 2.13 Packet Broadcasting for description of 
        packet broadcasting.
 
 
-     Tunneled                  0x04
+     Tunneled                  0x08
 
        Marks that the packet is tunneled.  Tunneling means
        that extra SILC Packet Header has been applied to the
        original packet.  The outer header has this flag
-       set.  See section 2.13 Packet Tunneling for more
+       set.  See section 2.14 Packet Tunneling for more
        information.
 .in 3
 
@@ -437,7 +449,8 @@ List of SILC Packet types are defined as follows.
           This packet is sent when an error occurs.  Server may
           send this packet.  Client never sends this packet.  The
           client may entirely ignore the packet, however, server is
-          most likely to take action anyway.
+          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.7 Error Payload.
 
@@ -709,7 +722,18 @@ List of SILC Packet types are defined as follows.
           Payload of the packet:  See section 2.3.24 Remove ID Payload
 
 
-     28   SILC_PACKET_REKEY
+     28   SILC_PACKET_REMOVE_CHANNEL_USER
+
+          This packet is used to remove user from a channel.  This is
+          used by router to notify other routers in the network that a
+          client has leaved a channel.  This packet maybe sent to entity
+          that is indirectly connected to the sender.
+
+          Payload of the packet:  See section 2.3.25 Remove Channel User
+                                  Payload
+
+
+     29   SILC_PACKET_REKEY
 
           This packet is used to indicate that re-key must be performed
           for session keys.  See section Session Key Regeneration in
@@ -717,9 +741,7 @@ List of SILC Packet types are defined as follows.
           a payload.
 
 
-
-
-     29   SILC_PACKET_REKEY_DONE
+     30   SILC_PACKET_REKEY_DONE
 
           This packet is used to indicate that re-key is performed and
           new keys must be used hereafter.  This is sent only if re-key
@@ -728,7 +750,7 @@ List of SILC Packet types are defined as follows.
           not have a payload.
 
 
-     30 - 254
+     31 - 254
 
          Currently undefined commands.
 
@@ -833,6 +855,7 @@ o Success Indication (variable length) - Indication of
 This is opposite of Success Payload.  Indication of failure of
 some protocol is sent in the payload.
 
+
 .in 5
 .nf
                      1                   2                   3
@@ -892,6 +915,9 @@ o Reject Indication (variable length) - Indication of
 .in 3
 
 
+
+
+
 .ti 0
 2.3.6 Notify Payload
 
@@ -905,15 +931,13 @@ The payload may only be sent with SILC_PACKET_NOTIFY packet.  It must
 not be sent in any other packet type.  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          |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
 |                                                               |
 ~                        Notify Message                         ~
 |                                                               |
@@ -925,6 +949,9 @@ Figure 7:  Notify Payload
 
 
 .in 6
+o Notify Type (2 bytes) - Indicates the type of the notify
+  message.
+
 o Notify Message (variable length) - Human readable notify
   message.
 .in 3
@@ -981,7 +1008,7 @@ 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.  Hence, the actual packet and padding to be
+with that key.  Thus, the actual packet and padding to be
 encrypted with the session key is SILC Header plus padding to it
 to make it multiple by eight (8) or multiple by the block size
 of the cipher, which ever is larger.
@@ -990,12 +1017,12 @@ 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 who client sent
+the source ID from the header which tells the client who sent
 the message.
 
 The payload may only be sent with SILC_PACKET_CHANNEL_MESSAGE packet.
 It  must not be sent in any other packet type.  Following diagram 
-represents the Notify Payload.
+represents the Channel Message Payload.
 
 (*) indicates that the field is not encrypted.
 
@@ -1265,7 +1292,7 @@ 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.  Following 
-diagram represents the Private Message Payload.
+diagram represents the Private Message Key Payload.
 
 
 .in 5
@@ -1301,8 +1328,9 @@ o Private Message Key (variable length) - The actual private
 .ti 0
 2.3.12 Command Payload
 
-Command Payload is used to send SILC commands from client to server.  
-Following diagram represents the Command Payload.
+Command Payload is used to send SILC commands from client to server.
+Also server may send commands to other servers.  Following diagram
+represents the Command Payload.
 
 
 .in 5
@@ -1310,8 +1338,10 @@ Following diagram represents the Command Payload.
                      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
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-| SILC Command  | Arguments Num |         Payload Length        |
+|         Payload Length        | SILC Command  | Arguments Num |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Command Unifier        |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 .in 3
 
 .ce
@@ -1319,6 +1349,10 @@ Figure 13:  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) - SILC Command identifier.  This must 
   be set to non-zero value.  If zero (0) value is found in this 
   field the packet must be discarded.
@@ -1328,9 +1362,14 @@ o Arguments Num (1 byte) - Indicates the number of arguments
   field is set to zero (0).  The arguments must follow the 
   command payload.
 
-o Payload Length (2 bytes) - Length of the entire command 
-  payload including any command argument payloads associated 
-  with this payload.
+o Command Unifier (2 bytes) - Unifies this command at the
+  sender's end.  The entity who 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 [SILC1] for detailed description of different SILC commands,
@@ -1394,11 +1433,15 @@ o Argument Data (variable length) - Argument data.
 .ti 0
 2.3.13 Command Reply Payload
 
-Command Reply Payload is used to send replies to the commands sent
-by the client.  The Command Reply Payload is identical to the
-Command Payload hence see the upper sections for Command Payload
-and for Command Argument Payload specifications.  Command Reply
-message uses the Command Argument Payload as well.
+Command Reply Payload is used to send replies to the commands.  The
+Command Reply Payload is identical to the Command Payload thus see the
+upper sections for Command Payload and for Command Argument Payload
+specifications.  Command Reply message uses the Command Argument Payload
+as well.
+
+The entity who sends the reply packet must set the Command Unifier
+field in the reply packet's Command Payload to the value it received
+in the original command packet.
 
 See SILC Commands in [SILC1] for detailed description of different
 SILC commands, their arguments and their reply messages.
@@ -1676,7 +1719,7 @@ 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 sends JOIN command
+in this case server acts as router.  Normal server forwards JOIN command
 to the router (after it has received JOIN command from client) which
 then processes the command and creates the channel.  Client never sends
 this packet.
@@ -1912,13 +1955,65 @@ o ID Type (2 bytes) - Indicates the type of the ID to be
   removed.  See section 2.4 SILC ID Types for list of defined
   ID types.
 
-o ID Length (2 bytes) - Length of the D Data area not including
+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 to be removed.
 .in 3
 
 
+.ti 0
+2.3.25 Remove Channel User Payload
+
+Remove Channel User payload is used to remove a user from a channel network
+wide.  This is used by routers to notify other routers that a user has
+leaved a channel.  As routers keep information about users on channels a
+user leaving channel must be removed from all routers.  Normal server may
+send this payload as well.  Client must not send this payload.
+
+The payload may only be sent with SILC_PACKET_REMOVE_CHANNEL USER packet.
+It must not be sent in any other packet type.  Following diagram
+represents the Remove Payload 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 Data                         ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|      Channel ID Length        |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                        Channel ID Data                        ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 23:  Remove Channel User Payload
+
+
+.in 6
+o Client ID Length (2 bytes) - Length of the Client ID Data area
+  not including the length of any other fields in the payload.
+
+o Client ID Data (variable length) - The Client ID of the user
+  that has left the channel.
+
+o Channel ID Length (2 bytes) - Length of the Channel ID Data area
+  not including the length of any other fields in the payload.
+
+o Channel ID Data (variable length) - The Channel ID of the channel
+  the user has left.
+.in 3
+
+
 .ti 0
 2.4 SILC ID Types
 
@@ -2141,10 +2236,10 @@ server or router en route must not decompress the packet.
 
 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.  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.
+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
@@ -2177,34 +2272,7 @@ special packet types and their parsing.
 
 
 .ti 0
-2.11 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 may
-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
-2.12 Packet Routing
+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
@@ -2236,7 +2304,62 @@ directly connected to the server.
 
 
 .ti 0
-2.13 Packet Tunneling
+2.12 Packet Forwarding
+
+Currently SILC command packets may be forwarded from one entity to another.
+Any other packet currently cannot be forwarded but support for more packet
+types may be added if needed.  Forwarding is usually used by server to
+forward some command request coming from client to the router as the server
+may be incapable to handle the request.  Forwarding may be only one hop
+long; the receiver of the packet with Forwarded flag set in the SILC   
+Packet header must not forward the packet any further.
+
+The normal scenario is that client sends JOIN command to the server which
+is not able to create the channel as there are no local clients on the
+channel.  Channels are created always by the router of the cell thus the
+packet must be forwarded to the router.  The server forwards the original
+packet coming from client to the router after it has set the Forwarded
+flag to the SILC Packet header.
+
+Router receiving the packet knows that the packet has to be processed
+specially by checking the flags and the Forwarded flag in the SILC Packet
+header.  After router has joined the client to the channel (and perhaps
+created a new channel) it sends normal command reply packet to the
+client.  However, as the router doesn't have direct connection to the
+client the packet is sent through the server.  Server detects that 
+the command reply packet is destined to the client and sends it to
+the client.
+
+
+.ti 0
+2.13 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 may
+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
+2.14 Packet Tunneling
 
 Tunneling is a feature that is available in SILC protocol.  Tunneling
 means that extra SILC Packet Header is applied to the original packet
@@ -2315,3 +2438,5 @@ Kasarmikatu 11 A4
 Finland
 
 EMail: priikone@poseidon.pspt.fi
+
+This Internet-Draft expires 13 May 2001
diff --git a/doc/draft-riikonen-silc-pp-01.nroff b/doc/draft-riikonen-silc-pp-01.nroff
new file mode 100644 (file)
index 0000000..2e3527f
--- /dev/null
@@ -0,0 +1,2557 @@
+.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 6 October 2000
+.ds CH
+.na
+.hy 0
+.in 0
+.nf
+Network Working Group                                      P. Riikonen
+Internet-Draft
+draft-riikonen-silc-pp-01.txt                           6 October 2000
+Expires: 6 Jun 2001
+
+.in 3
+
+.ce 2
+SILC Packet Protocol
+<draft-riikonen-silc-pp-01.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 Internet Draft [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
+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 .................................... 16
+            2.3.2.1 ID Payload .................................. 16
+            2.3.2.2 Argument Payload ............................ 16
+      2.3.3 Disconnect Payload .................................. 17
+      2.3.4 Success Payload ..................................... 18
+      2.3.5 Failure Payload ..................................... 18
+      2.3.6 Reject Payload ...................................... 19
+      2.3.7 Notify Payload ...................................... 20
+      2.3.8 Error Payload ....................................... 21
+      2.3.9 Channel Message Payload ............................. 22
+      2.3.10 Channel Key Payload ................................ 24
+      2.3.11 Private Message Payload ............................ 26
+      2.3.12 Private Message Key Payload ........................ 27
+      2.3.13 Command Payload .................................... 28
+      2.3.14 Command Reply Payload .............................. 29
+      2.3.15 Connection Auth Request Payload .................... 29
+      2.3.16 New ID Payload ..................................... 30
+      2.3.17 New ID List Payload ................................ 31
+      2.3.18 New Client Payload ................................. 31
+      2.3.19 New Server Payload ................................. 32
+      2.3.20 New Channel Payload ................................ 33
+      2.3.21 New Channel User Payload ........................... 34
+      2.3.22 New Channel List Payload ........................... 35
+      2.3.23 New Channel User List Payload ...................... 36
+      2.3.24 Replace ID Payload ................................. 36
+      2.3.25 Remove ID Payload .................................. 37
+      2.3.26 Remove Channel User Payload ........................ 38
+  2.4 SILC ID Types ............................................. 39
+  2.5 Packet Encryption And Decryption .......................... 39
+      2.5.1 Normal Packet Encryption And Decryption ............. 39
+      2.5.2 Channel Message Encryption And Decryption ........... 40
+      2.5.3 Private Message Encryption And Decryption ........... 41
+  2.6 Packet MAC Generation ..................................... 41
+  2.7 Packet Padding Generation ................................. 42
+  2.8 Packet Compression ........................................ 42
+  2.9 Packet Sending ............................................ 43
+  2.10 Packet Reception ......................................... 43
+  2.11 Packet Routing ........................................... 44
+  2.12 Packet Forwarding ........................................ 44
+  2.13 Packet Broadcasting ...................................... 45
+  2.14 Packet Tunneling ......................................... 45
+3 Security Considerations ....................................... 46
+4 References .................................................... 46
+5 Author's Address .............................................. 47
+
+.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:   Disconnect Payload
+Figure 6:   Success Payload
+Figure 7:   Failure Payload
+Figure 8:   Reject Payload
+Figure 9:   Notify Payload
+Figure 10:  Error Payload
+Figure 11:  Channel Message Payload
+Figure 12:  Channel Key Payload
+Figure 13:  Private Message Payload
+Figure 14:  Private Message Key Payload
+Figure 15:  Command Payload
+Figure 16:  Connection Auth Request Payload
+Figure 17:  New Client Payload
+Figure 18:  New Server Payload
+Figure 19:  New Channel Payload
+Figure 20:  New Channel User Payload
+Figure 21:  Replace ID Payload
+Figure 22:  Remove Channel User 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 Internet Draft [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 basis of SILC protocol relies in the SILC packets and it is with
+out a doubt the most important part of the protocol.  It is also probably
+the most complicated part of the protocol.  Packets are used all the
+time in the SILC network to send messages, commands and other information.
+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 of the packet and destination of the
+packet.
+
+
+.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 and first two (2) bytes of the
+header (thus first two bytes of the packet) are not encrypted.  The
+first two (2) bytes are the length of the packet which is not encrypted.
+See 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 16 bytes.  The padding is always
+encrypted.
+
+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.  The MAC is always computed from the packet
+before the encryption is applied to the packet.  If compression is used
+in the packet the MAC is computed after the compression has been
+applied.  The compression, on the other hand, 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 default 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.
+
+Following diagram represents the default SILC header format.
+(*) indicates that this field is never encrypted.  Other fields are
+always 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
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Payload Length *       |     Flags     |  Packet Type  |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Source ID Length       |     Destination ID Length     |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|  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) - Is the length of the packet
+  not including the padding of the packet.  This field must
+  not be encrypted but must always be authenticated.
+
+o Flags (1 byte) - Indicates flags to be used in packet
+  processing.  Several flags may be set by ORing the flags
+  together.
+
+  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 must include private
+       message that is encrypted using private key set by
+       client.  Servers does not know anything about this
+       key and this causes that the private message is
+       not handled by the server at all, it is just
+       passed along.  See section 2.5.3 Private Message
+       Encryption And Decryption for more information.
+
+
+     Forwarded                 0x02
+  
+       Marks the packet to be forwarded.  Some specific
+       packet types may be forwarded.  Receiver of packet
+       with this flag set must not forward the packet any
+       further.  See section 2.12 Packet Forwarding for
+       description of packet forwarding.
+
+
+     Broadcast                 0x04
+
+       Marks the packet to be broadcasted.  Client cannot
+       send broadcast packet and normal server cannot send
+       broadcast packet.  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.13 Packet Broadcasting for description of 
+       packet broadcasting.
+
+
+     Tunneled                  0x08
+
+       Marks that the packet is tunneled.  Tunneling means
+       that extra SILC Packet Header has been applied to the
+       original packet.  The outer header has this flag
+       set.  See section 2.14 Packet Tunneling for more
+       information.
+.in 3
+
+
+
+o Packet Type (1 byte) - Is 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 Source ID Length (2 bytes) - Indicates the length of the
+  Source ID field in the header, not including this or any
+  other fields.
+
+o Destination ID Length (2 bytes) - 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 who 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 source ID that
+  indicates who 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, as a one
+byte, 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 of these packet
+types.
+
+The below list of the SILC Packet types includes reference to the packet
+payload as well.  Packet payloads are the actual packet, that is, the data
+that the packet consists of.  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
+router to send 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 has not 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 mentioned separately in the packet
+description (unless it is obvious as in private and channel message
+packets).  Other packets must not be sent or accepted, if sent, to
+indirectly connected entities.
+
+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.  Client
+          usually does not send this packet.
+
+          Payload of the packet:  See section 2.3.3 Disconnect Payload
+
+
+     2    SILC_PACKET_SUCCESS
+
+          This packet is sent upon successful execution of some protocol.
+          The status of the success is sent in the packet.
+
+          Payload of the packet:  See section 2.3.4 Success Payload
+
+
+     3    SILC_PACKET_FAILURE
+
+          This packet is sent upon failure of some protocol.  The status
+          of the failure is sent in the packet.
+
+          Payload of the packet:  See section 2.3.5 Failure Payload
+
+
+     4    SILC_PACKET_REJECT
+
+          This packet may be sent upon rejection of some protocol.
+          The status of the rejection is sent in the packet.
+
+          Payload of the packet:  See section 2.3.6 Reject Payload
+
+
+     5    SILC_PACKET_NOTIFY
+
+          This packet is used to send notify message, usually from
+          server to client, although it may be sent from server to another
+          server as well.  Client never sends this packet.  Server may
+          send this packet to channel as well when the packet is 
+          distributed to all clients on the channel.
+
+          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 never sends 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.  Channel Keys are distributed by
+          SILC_PACKET_CHANNEL_KEY packet.
+
+          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.  Each channel has their own independent keys that
+          is used to protect the traffic on the channel.  Only server
+          may 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.  SILC_PACKET_PRIVATE_MESSAGE_KEY packet is used to 
+          agree the key with the remote client.  Pre-shared key may be 
+          used as well if both of the client knows it, however, it needs 
+          to be agreed outside SILC.  See more of this in [SILC1].
+
+          Payload of the packet:  See section 2.3.11 Private Message
+                                  Payload
+
+
+     10   SILC_PACKET_PRIVATE_MESSAGE_KEY
+
+          This packet is used to agree about a key to be used to protect
+          the private messages between two clients.  If this is not sent
+          the normal session key is used to protect the private messages
+          inside SILC network.  Agreeing to use specific key to protect
+          private messages adds security, as no server between the two
+          clients will be able to decrypt the private message.  However,
+          servers inside SILC network are considered to be trusted, thus
+          using normal session key to protect private messages does not
+          degree security.  Whether to agree to use specific keys by
+          default or to use normal session keys by default, is 
+          implementation specific issue.  See more of this in [SILC1].
+
+          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 [SILC1].  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 send as reply to the SILC_PACKET_COMMAND packet.
+          The contents of this packet is command specific.  This packet
+          maybe sent to entity that is indirectly connected to the sender.
+
+          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 the 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 is used to determine it.
+
+          The party receiving this payload must 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 ID's from server to
+          router and from router to all routers in the SILC network.
+          This is used when for example new client is registered to
+          SILC network.  The newly created ID's of these operations are
+          distributed by this packet.  Only server may send this packet,
+          however, client must be able to receive this packet.
+
+          Payload of the packet:  See section 2.3.16 New ID Payload
+
+
+     19   SILC_PACKET_NEW_ID_LIST
+
+          This packet is used to distribute list of new ID's from
+          server to routers.  This is equivalent to previous packet
+          type except that it may include several ID's.  Client must
+          not send this packet.
+
+          Payload of the packet:  See section 2.3.17 New ID List 
+                                  Payload
+
+
+     20   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.
+
+          Payload of the packet:  See section 2.3.18 New Client Payload
+
+
+     21   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.
+          Client must not send or receive this packet.
+
+          Payload of the packet:  See section 2.3.19 New Server Payload
+
+
+     22   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 maybe sent to entity that is indirectly
+          connected to the sender.
+
+          Payload of the packet:  See section 2.3.20 New Channel Payload
+
+
+     23   SILC_PACKET_NEW_CHANNEL_USER
+
+          This packet is used to notify routers about new user on channel.
+          The packet is sent after user has joined to the channel.  Server
+          may send this packet to its router and router may send this to
+          its primary router.  Client must not send this packet.  This
+          packet maybe sent to entity that is indirectly connected to
+          the sender.
+
+          When received, the server or router must distribute
+          SILC_NOTIFY_TYPE_JOIN to local clients on the channel.
+
+          Payload of the packet:  See section 2.3.21 New Channel User
+                                  Payload
+
+
+     24   SILC_PACKET_NEW_CHANNEL_LIST
+
+          This packet is used to distribute list of created channels
+          from server to routers.  This is equivalent to the packet
+          SILC_PACKET_NEW_CHANNEL except that it may include several
+          payloads. Client must not send this packet.
+
+          Payload of the packet:  See section 2.3.22 New Channel List
+                                  Payload
+
+
+     25   SILC_PACKET_NEW_CHANNEL_USER_LIST
+
+          This packet is used to distribute list of users on specific
+          channel from server to routers.  This is equivalent to the
+          packet SILC_PACKET_NEW_CHANNEL_USER except that it may
+          include several payloads.  Client must not send this packet.
+
+          When received, the server or router must distribute
+          SILC_NOTIFY_TYPE_JOIN to local clients on the channel.
+
+          Payload of the packet:  See section 2.3.23 New Channel User
+                                  List Payload
+
+
+     26   SILC_PACKET_REPLACE_ID
+
+          This packet is used to replace old ID with new ID sent in
+          the packet payload.  For example, when client changes its
+          nickname new ID is created and this packet can be used to
+          distribute the new ID and the old ID is removed when it is
+          send in the packet.  Client cannot send or receive this
+          packet.  This packet maybe sent to entity that is indirectly
+          connected to the sender.
+
+          When received and the replaced ID is Client ID the server or
+          router must distribute SILC_NOTIFY_TYPE_NICK_CHANGE to the
+          local clients on the channels (if any) of the client whose
+          ID was changed.  However, the notify type must be sent only
+          once per client.
+
+          Payload of the packet:  See section 2.3.24 Replace ID Payload
+
+
+     27   SILC_PACKET_REMOVE_ID
+
+          This packet is used to removed ID.  For example, when client
+          exits SILC network its ID is removed.  Client must not send
+          this packet.  This packet maybe sent to entity that is
+          indirectly connected to the sender.
+
+          When received and the replaced ID is Client ID the server or
+          router must distribute SILC_NOTIFY_TYPE_SIGNOFF to the
+          local clients on the channels (if any) of the client whose
+          ID was changed.  However, the notify type must be sent only
+          once per client.
+
+          Payload of the packet:  See section 2.3.25 Remove ID Payload
+
+
+     28   SILC_PACKET_REMOVE_CHANNEL_USER
+
+          This packet is used to remove user from a channel.  This is
+          used by router to notify other routers in the network that a
+          client has left a channel.  This packet maybe sent to entity
+          that is indirectly connected to the sender.
+
+          When received, the server or router must distribute
+          SILC_NOTIFY_TYPE_LEAVEW to local clients on the channel.
+
+          Payload of the packet:  See section 2.3.26 Remove Channel User
+                                  Payload
+
+
+     29   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.
+
+
+     30   SILC_PACKET_REKEY_DONE
+
+          This packet is used to indicate that re-key is performed and
+          new keys must be used hereafter.  This is sent only if re-key
+          was done without PFS option.  If PFS is set, this is not sent
+          as SILC Key Exchange protocol is executed.  This packet does
+          not have a payload.
+
+
+     31 - 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 
+         is not 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 default
+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.
+
+Payloads described in this section are common payloads that must be
+accepted anytime during SILC session.  Most of the payloads may only
+be sent with specific packet type which is defined in the description
+of the payload.
+
+There are a lot of other payloads in the 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] and [SILC3].
+
+
+.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 payloads.
+
+
+.ti 0
+2.3.2.1 ID Payload
+
+This payload can be used to send an ID.  ID's are variable length thus
+this payload provides a way to send variable length ID's.
+
+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.
+.in 3
+
+
+.ti 0
+2.3.2.2 Argument Payload
+
+Argument Payload is used to set arguments for any packet payload that
+needs and supports arguments, such as commands.  Number of arguments
+associated with a packet must be indicated by the packet payload who
+needs 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.  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 payload data 
+  area not including the length of any other fields in the 
+  payload.
+
+o Argument Type (1 byte) - Indicates the type of the argument.  
+  Every argument may have a specific type that must be defined
+  by the packet payload needing the argument.  For example
+  every command specify a number for each argument that maybe 
+  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).
+
+o Argument Data (variable length) - Argument data.
+.in 3
+
+
+.ti 0
+2.3.3 Disconnect Payload
+
+Disconnect payload is sent upon disconnection.  The payload is simple;
+reason of disconnection is sent to the disconnected party.
+
+The payload may only be sent with SILC_PACKET_DISCONNECT packet.  It
+must not be sent in any other packet type.  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
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                      Disconnect Message                       ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 5:  Disconnect Payload
+
+
+
+
+.in 6
+o Disconnect Message (variable length) - Human readable
+  reason of the disconnection.
+.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 maybe any data, including binary or human readable data.
+
+.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 6:  Success Payload
+
+
+.in 6
+o Success Indication (variable length) - Indication of
+  the success.  This maybe 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 7:  Failure Payload
+
+
+.in 6
+o Failure Indication (variable length) - Indication of
+  the failure.  This maybe 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.
+
+
+.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 8:  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, however, server may send it to another
+server as well.  This payload may also be sent to a channel.  Client must
+not send this payload.  The receiver of this payload may totally ignore the
+contents of the payload, however, notify message should be noted and
+possibly logged.
+
+The payload may only be sent with SILC_PACKET_NOTIFY packet.  It must
+not be sent in any other packet type.  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 9:  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 (2 bytes) - Indicates the number of Argument
+  Payloads associated to this payload.  Notify types may define
+  arguments to be send along the notify message.
+.in 3
+
+Following list of currently defined notify types.  The format for notify
+arguments is same as in SILC commands described in [SILC1].  Also, all
+ID's sent in arguments are sent inside ID Payload.
+
+.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 text string.  Receiver
+      may ignore this message.
+
+
+1     SILC_NOTIFY_TYPE_INVITE
+
+      Sent when receiver has been invited to a channel.  This type must be
+      sent directly to the invited client.
+
+      Max Arguments:  2
+          Arguments:  (1) <Client ID>  (2) <Channel ID>
+
+      The <Client ID> is the client who invites the receiver of this type 
+      to channel indicated by <Channel ID>.
+
+
+2     SILC_NOTIFY_TYPE_JOIN
+
+      Sent when client has joined to a channel.  The server must distribute
+      this type only to the local clients on the channel and then send
+      SILC_PACKET_NEW_CHANNEL_USER packet to its primary route.  The router
+      or server receiving the packet distributes this type to the local
+      clients on the channel.  See description of SILC_PACKET_NEW_CHANNEL_USER
+      packet for more information.
+
+      Max Arguments:  1
+          Arguments:  (1) <Client ID>
+
+      The <Client ID> is the client that joined to the channel.
+
+
+3     SILC_NOTIFY_TYPE_LEAVE
+
+      Sent when client has left a channel.  The server must distribute
+      this type only to the local clients on the channel and then send
+      SILC_PACKET_REMOVE_CHANNEL_USER packet to its primary route.  The
+      router or server receiving the packet distributes this type to the
+      local clients on the channel.  See description of 
+      SILC_PACKET_REMOVE_CHANNEL_USER packet for more information.
+
+      Max Arguments:  1
+          Arguments:  (1) <Client ID>
+
+      The <Client ID> is the client who left the channel.
+
+
+4     SILC_NOTIFY_TYPE_SIGNOFF
+
+      Sent when client signoffs from SILC network.  This type is sent only
+      if the client was joined to any channel.  This type is sent by server
+      or router when SILC_PACKET_REMOVE_ID packet has been received.  See
+      detailed information from description of SILC_PACKET_REMOVE_ID packet.
+
+      Max Arguments:  1
+          Arguments:  (1) <Client ID>
+
+      The <Client ID> is the client who left SILC network.
+
+
+5     SILC_NOTIFY_TYPE_TOPIC_SET
+
+      Sent when topic is set/changed on a channel.  This type must be sent
+      only to the clients who is joined on the channel whose topic was
+      set or changed.
+
+      Max Arguments:  2
+          Arguments:  (1) <Client ID>  (2) <topic>
+
+      The <Client ID> is the client who set or changed the <topic>.
+
+
+6     SILC_NOTIFY_TYPE_NICK_CHANGE
+
+      Sent when client changes nick on a channel.  This type is sent only if
+      the client has joined to any channel.  This type is sent by server or
+      router when SILC_PACKET_REPLACE_ID packet has been received.  See 
+      detailed information from description of SILC_PACKET_REPLACE_ID packet.
+
+      Max Arguments:  2
+          Arguments:  (1) <Old Client ID>  (2) <New Client ID>
+
+      The <Old Client ID> is the old ID of the client who changed the 
+      nickname.  The <New Client ID> is the new ID generated by the change
+      of the nickname.
+
+
+7     SILC_NOTIFY_TYPE_CMODE_CHANGE
+
+      Sent when channel mode has changed.  This type must be sent only to
+      the clients who is joined on the channel whose mode was changed.
+
+      Max Arguments:  2
+          Arguments:  (1) <Client ID>  (2) <mode mask>
+
+      The <Client ID> is the client who changed the mode.  The <mode mask>
+      is the new mode mask of the channel.
+
+
+8     SILC_NOTIFY_TYPE_CUMODE_CHANGE
+
+      Sent when user mode on channel has changed.  This type must be sent
+      only to the clients who is joined on the channel where the target 
+      client is on.
+
+      Max Arguments: 3
+          Arguments:  (1) <Client ID>  (2) <mode mask>
+                      (3) <Target Client ID>
+
+      The <Client ID> is the client who changed the mode.  The <mode mask>
+      is the new mode mask of the channel.  The <Target Client ID> is the
+      client whose mode was changed.
+
+
+9     SILC_NOTIFY_TYPE_MOTD
+
+      Sent when Message of the Day (motd) is sent to client.
+
+      Max Arguments:  1
+          Arguments:  (1) <motd>
+
+      The <motd> is the Message of the Day.
+.in 3
+
+Notify types starting from 16384 are reserved for private notify
+message types.
+
+
+.ti 0
+2.3.8 Error Payload
+
+Error payload is sent upon error.  Error may occur in various
+conditions when server sends this packet.  Client may not send this
+payload but must be able to accept it.  However, client may
+totally 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 10:  Error Payload
+
+
+.in 6
+o Error Message (variable length) - Human readable error
+  message.
+.in 3
+
+
+.ti 0
+2.3.9 Channel Message Payload
+
+Channel messages are the most common messages sent in the SILC.
+Channel Message Payload is used to send message to channels.  These
+messages can only be sent if client has joined to some channel.
+Even though this packet is the most 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 padding should be random data.  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
+to make it multiple by eight (8) or multiple by the block size
+of the cipher, which ever is larger.
+
+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 who sent
+the message.
+
+The payload may only be sent with SILC_PACKET_CHANNEL_MESSAGE packet.
+It  must not be sent in any other packet type.  Following diagram 
+represents the Channel 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 Length        |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                         Message Data                          ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Padding Length         |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                            Padding                            ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                       Initial Vector *                        ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 11:  Channel Message Payload
+
+
+.in 6
+o Message Length (2 bytes) - Indicates the length of the
+  the Message Data field in the payload, not including any 
+  other field.
+
+o Message Data (variable length) - The actual message to
+  the channel.
+
+o Padding Length (2 bytes) - Indicates the length of the
+  Padding field in the payload, not including any other
+  field.
+
+o Padding (variable length) - The padding that must be
+  applied because this payload is encrypted separately from
+  other parts of the packet.
+
+o Initial Vector (variable length) - The initial vector
+  that has been used in packet encryption.  It needs to be
+  used in the packet decryption as well.  What this field
+  includes is implementation issue.  However, it is 
+  recommended that it would be random data or, perhaps,
+  a timestamp.  It is not recommended to use zero (0) as
+  initial vector.  This field is not encrypted.  This field
+  is not included into the padding calculation.  Length
+  of this field equals the cipher's block size.  This field
+  is, however, authenticated.
+.in 3
+
+
+.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 starts using the key received
+in this payload to protect the traffic on the channel.
+
+Channel keys are cell specific thus every router in 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.
+
+The payload may only be sent with SILC_PACKET_CHANNEL_KEY packet.
+It must not be sent in any other packet type.  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 12:  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 this key is meant for.
+
+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.  This key is used as such as key material for
+  encryption function.
+.in 3
+
+
+.ti 0
+2.3.11 Private Message Payload
+
+Private Message Payload is used to send private message between
+two clients (or users for that matter).  The messages are sent only
+to the specified user and no other user inside SILC network is
+able to see the message.  The message is protected by the session 
+key established by the SILC Key Exchange Protocol.  However,
+it is also possible to agree to use specific keys to protect
+just the private messages.  See section 2.3.11 Private Message
+Key Payload for detailed description of how to agree to use
+specific key.
+
+If normal session key is used to protect the message, every
+server between the sender client and the receiving client needs
+to 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 specific key is used to protect the message, servers between 
+the sender and the receiver needs not to decrypt/re-encrypt the 
+packet.  Section 4.8.2 Client To Client in [SILC1] gives example of
+this scheme as well.
+
+The payload may only be sent with SILC_PACKET_PRIVATE_MESSAGE 
+packet.  It must not be sent in any other packet type.  Following 
+diagram represents the Private Message 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
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Nickname Length        |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                            Nickname                           ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                          Message Data                         ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 13:  Private Message Payload
+
+
+.in 6
+o Nickname Length (2 bytes) - Indicates the length of the
+  Nickname field, not including any other field.
+
+o Nickname (variable length) - Nickname of the sender of the 
+  private message.  This should not be trusted as a definite 
+  sender of the private message.  The SILC Packet Header in 
+  the packet indicates the true sender of the packet and 
+  client should verify that the nickname sent here belongs 
+  to the Client ID in the SILC Packet Header.  This nickname 
+  is merely provided to be displayed by the client.
+
+o Message Data (variable length) - The actual message to
+  the client.  Rest of the packet is reserved for the message
+  data.
+.in 3
+
+
+.ti 0
+2.3.12 Private Message Key Payload
+
+This payload is used to send key from client to another client that
+is going to be used to protect the private messages between these
+two clients.  If this payload is not sent normal session key 
+established by the SILC Key Exchange Protocol is used to protect
+the private messages.
+
+This payload may only be sent by client to another client.  Server
+must not send this payload at any time.  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.  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                      ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 14:  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.  This key is used as such as key material 
+  for encryption function.
+.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.  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 Unifier        |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 15:  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) - SILC Command identifier.  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 Unifier (2 bytes) - Unifies this command at the
+  sender's end.  The entity who 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 [SILC1] 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
+upper sections for Command Payload and for Command Argument Payload
+specifications.  Command Reply message uses the Command Argument Payload
+as well.
+
+The entity who sends the reply packet must set the Command Unifier
+field in the reply packet's Command Payload to the value it received
+in the original command packet.
+
+See SILC Commands in [SILC1] 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 must 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.  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 16:  Connection Auth Request Payload
+
+
+.in 6
+o Connection Type (2 bytes) - Indicates the type of the ID.
+  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.  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.  Similary 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 uses 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.
+
+Hence, this payload is very important and used every time when some
+new entity is registered to the SILC network.  Client never sends this
+payload.  Both client and server (and router) may receive this payload.
+
+The packet uses generic ID Payload as New ID Payload.  See section
+2.3.2.1 for generic ID Payload.
+
+
+.ti 0
+2.3.17 New ID List Payload
+
+New ID List Payload is used to distribute list of ID's usually from 
+server to router but also from router to other routers in the network.
+This payload is used, for example, when server is connected to router
+and the server wants to distribute all of its locally connected clients
+and locally created channels to the router.  It is convenient in this
+case to use this payload instead of sending all the information one
+by one using New ID Payload.
+
+There is no specific payload for this packet type.  The packet type
+uses same payload as described in previous section.  To form a list
+several payloads is put in the packet each after each.  The payload
+is variable in length but can be calculated by calculating the ID
+Type field, Length field and the ID Data fields together.  This forms
+one New ID Payload in the list.
+
+The list of payloads may only be sent with SILC_PACKET_NEW_ID_LIST
+packet.  They must not be sent in any other packet type.
+
+
+.ti 0
+2.3.18 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.  Clients 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 username sent in this payload.
+However, client should call NICK command after sending this payload to
+set the real nickname of the user which is then used to create new 
+client ID.
+
+The payload may only be sent with SILC_PACKET_NEW_CLIENT packet.  It
+must not be sent in any other packet type.  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 17:  New Client Payload
+
+
+.in 6
+o Username Length (2 bytes) - Length of the username.
+
+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.
+
+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.19 New Server Payload
+
+This payload is sent by server when it has completed successfully both
+key exchange and connection authentication protocols.  The server
+uses this payload to register itself to the SILC network.  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.  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 18:  New Server Payload
+
+
+.in 6
+o Server ID Length (2 bytes) - Length of the ID Data area not 
+  including the length of any other fields in the payload.
+
+o Server ID Data (variable length) - The actual Server ID
+   data.
+
+o Server Name Length (2 bytes) - Length of the server name.
+
+o Server Name (variable length) - The server name.
+.in 3
+
+
+.ti 0
+2.3.20 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 forwards JOIN command
+to the router (after it has received JOIN command from client) which
+then processes the command and creates the channel.  Client never sends
+this packet.
+
+The payload may only be sent with SILC_PACKET_NEW_CHANNEL packet.
+It must not be sent in any other packet type.  Following diagram
+represents the New 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                           ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 19:  New Channel Payload
+
+
+
+.in 6
+o Channel Name Length (2 bytes) - Length of the channel name.
+
+o Channel Name (variable length) - The name of the created
+  channel.
+
+o Channel ID Length (2 bytes) - Length of the Channel ID.
+
+o Channel ID (variable length) - The created Channel ID.
+.in 3
+
+
+.ti 0
+2.3.21 New Channel User Payload
+
+When client (user) joins to a channel, server must notify routers
+about the new user on the channel.  Normal server sends this packet
+payload to its router which then broadcasts the packet further.
+Router sends this packet always to its primary router.  Client must
+not send this packet payload.  The mode of the user is NONE after 
+user has joined to the channel.
+
+The payload may only be sent with SILC_PACKET_NEW_CHANNEL_USER 
+packet.  It must not be sent in any other packet type.  Following 
+diagram represents the New Channel User 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                           ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|       Client ID Length        |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                           Client ID                           ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 20:  New Channel User Payload
+
+
+.in 6
+o Channel ID Length (2 bytes) - Length of the Channel ID.
+
+o Channel ID (variable length) - The Channel ID of the channel
+  to which the client has joined.
+
+o Client ID Length (2 bytes) - Length of the Client ID.
+
+o Client ID (variable length) - The Client ID of the client
+  who has joined the channel.
+.in 3
+
+
+.ti 0
+2.3.22 New Channel List Payload
+
+This payload is used to distribute list of new channels from server
+to routers.  It might convenient to send list of new channels when
+existing server connects to router, instead of sending them one
+by one.
+
+There is no specific payload for this packet type.  The packet type
+uses same payload as described in 2.3.19 New Channel Payload.  To form
+a list several payloads is put in the packet each after each.  The
+payload is variable in length but can be calculated by calculating
+the length of the fields together.  This forms one New Channel Payload
+in the list.
+
+The list of payloads may only be sent with SILC_PACKET_NEW_CHANNEL_LIST
+packet.  They must not be sent in any other packet type.
+
+
+.ti 0
+2.3.23 New Channel User List Payload
+
+This payload is used to distribute list of channel users on specific
+channel from server to routers.  It might convenient to send list of
+channel users when existing server connects to router, instead of
+sending them one by one.
+
+There is no specific payload for this packet type.  The packet type
+uses same payload as described in 2.3.20 New Channel User Payload.
+To form a list several payloads is put in the packet each after each.
+The payload is variable in length but can be calculated by calculating
+the length of the fields together.  This forms one New Channel User
+Payload in the list.
+
+The list of payloads may only be sent with packet
+SILC_PACKET_NEW_CHANNEL_USER_LIST. They must not be sent in any other
+packet type.
+
+
+.ti 0
+2.3.24 Replace ID Payload
+
+This payload is used to replace old ID with new ID sent in the payload.
+When ID changes for some entity and the new ID is wanted to replace the
+old one this payload must be used.  Client cannot send or receive this
+payload.  Normal server and router server may send and receive this
+payload.  After this packet has been sent the old ID must not be used
+anymore.
+
+The payload may only be sent with SILC_PACKET_REPLACE_ID packet.  It must
+not be sent in any other packet type.  Following diagram represents the 
+Replace Payload 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
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|          Old ID Type          |         Old ID Length         |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                         Old ID Data                           ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|          New ID Type          |         New ID Length         |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                                                               |
+~                         New ID Data                           ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 21:  Replace ID Payload
+
+
+.in 6
+o Old ID Type (2 bytes) - Indicates the type of the old ID.  See 
+  section 2.4 SILC ID Types for list of defined ID types.
+
+o Old ID Length (2 bytes) - Length of the old ID Data area not 
+  including the length of any other fields in the payload.
+
+o Old ID Data (variable length) - The actual old ID data.
+
+o New ID Type (2 bytes) - Indicates the type of the new ID.  See 
+  section 2.4 SILC ID Types for list of defined ID types.
+
+o New ID Length (2 bytes) - Length of the new ID Data area not 
+  including the length of any other fields in the payload.
+
+o New ID Data (variable length) - The actual new ID data.
+.in 3
+
+
+.ti 0
+2.3.25 Remove ID Payload
+
+Remove ID payload is used to remove ID from SILC network.  This is used
+for example when client exits SILC network.  The server must in this
+case send this payload to notify that this ID is not valid anymore.
+After this has been send the old ID must not be used anymore.  Client
+must not send this payload.
+
+The packet uses generic ID Payload as New ID Payload.  See section
+2.3.2.1 for generic ID Payload.
+
+
+.ti 0
+2.3.26 Remove Channel User Payload
+
+Remove Channel User payload is used to remove a user from a channel network
+wide.  This is used by routers to notify other routers that a user has
+left a channel.  As routers keep information about users on channels a
+user leaving channel must be removed from all routers.  Normal server may
+send this payload as well.  Client must not send this payload.
+
+The payload may only be sent with SILC_PACKET_REMOVE_CHANNEL USER packet.
+It must not be sent in any other packet type.  Following diagram
+represents the Remove Payload 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 Data                         ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|      Channel ID Length        |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                                                               |
+~                        Channel ID Data                        ~
+|                                                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 22:  Remove Channel User Payload
+
+
+.in 6
+o Client ID Length (2 bytes) - Length of the Client ID Data area
+  not including the length of any other fields in the payload.
+
+o Client ID Data (variable length) - The Client ID of the user
+  that has left the channel.
+
+o Channel ID Length (2 bytes) - Length of the Channel ID Data area
+  not including the length of any other fields in the payload.
+
+o Channel ID Data (variable length) - The Channel ID of the channel
+  the user has left.
+.in 3
+
+
+
+.ti 0
+2.4 SILC ID Types
+
+ID's are extensively used in the SILC network to associate different
+entities.  Following ID's has been defined to be used in the SILC
+network.
+
+.in 6
+0    No ID
+
+   When ever specific ID cannot be used this is used.
+
+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
+
+
+.ti 0
+2.5 Packet Encryption And Decryption
+
+SILC packets are encrypted almost entirely.  Only small part of SILC
+header is not encrypted as described in section 5.2 SILC Packet Header.
+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 also 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 following sections the packet
+decryption is special.  If the packet type is not among those special
+packet types rest of the packet may be decrypted with the same key.
+
+Also, note that two bytes of the SILC Packet header are not encrypted
+thus it must be noticed in the decryption process by starting the
+decryption from the second byte of the header.  This sets some rules
+to padding generation as well, see the section 2.7 Packet Padding
+Generation.
+
+With out a doubt, this sort of decryption processing causes some
+overhead to packet decryption, but never the less, is required.
+
+
+.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, who ever that might
+be.  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 even 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 hence 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 who is routing the
+message to another router then it must decrypt the Channel Message
+payload.  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, is 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 above.  This
+different processing of channel messages with router to router
+connection is because channel keys are cell specific.  All cells has
+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.
+
+
+.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 can 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.
+
+The true receiver of the private message, client, that is, 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, and from the original contents of the packet.  The MAC is
+always computed before the packet is encrypted, although after it is
+compressed if compression is used.
+
+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.
+
+If the packet is special packet MAC is computed from the entire packet
+but part of the packet may be encrypted before the MAC is computed.
+This is case, for example, with channel messages where the message data
+is encrypted with key that server may not now.  In this case the MAC
+has been computed from the encrypted data.
+
+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
+must always be multiple by eight (8) or multiple by the size of the
+cipher's block size, 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
+are calculated as follows:
+
+.in 6
+padding length = 16 - ((packet length - 2) % 16)
+.in 3
+
+The 16 is the maximum padding allowed in SILC packet.  Two (2) is 
+subtracted from the true length of the packet because two (2) bytes
+is not encrypted in SILC Packet Header, see section 2.2 SILC Packet
+Header.  Those two bytes that are not encrypted must not be calculated
+to the padding length.
+
+For special packets the padding calculation may be 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.  In this case, as well, two (2) is subtracted from the
+length.
+
+The padding must be random data, preferably, generated by 
+cryptographically strong random number generator.
+
+
+.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 must 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 compute the MAC of the packet.
+
+Then sender encrypts the packet as has been described in above
+sections according whether the packet is normal packet or special
+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, server 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).
+
+For server who 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 some
+server cannot send, for example, disconnect packet to client that is not
+directly connected to the server.
+
+
+.ti 0
+2.12 Packet Forwarding
+
+Currently SILC command packets may be forwarded from one entity to another.
+Any other packet currently cannot be forwarded but support for more packet
+types may be added if needed.  Forwarding is usually used by server to
+forward some command request coming from client to the router as the server
+may be incapable to handle the request.  Forwarding may be only one hop
+long; the receiver of the packet with Forwarded flag set in the SILC   
+Packet header must not forward the packet any further.
+
+The normal scenario is that client sends JOIN command to the server which
+is not able to create the channel as there are no local clients on the
+channel.  Channels are created always by the router of the cell thus the
+packet must be forwarded to the router.  The server forwards the original
+packet coming from client to the router after it has set the Forwarded
+flag to the SILC Packet header.
+
+Router receiving the packet knows that the packet has to be processed
+specially by checking the flags and the Forwarded flag in the SILC Packet
+header.  After router has joined the client to the channel (and perhaps
+created a new channel) it sends normal command reply packet to the
+client.  However, as the router doesn't have direct connection to the
+client the packet is sent through the server.  Server detects that 
+the command reply packet is destined to the client and sends it to
+the client.
+
+
+.ti 0
+2.13 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 may
+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
+2.14 Packet Tunneling
+
+Tunneling is a feature that is available in SILC protocol.  Tunneling
+means that extra SILC Packet Header is applied to the original packet
+and thus hiding the original packet entirely.  There can be some
+interesting applications using tunneling, such as, using ID's based on
+private network IP addresses inside in the tunneled packet.  This can
+open many interesting features relating to connecting to private network
+from the Internet with SILC and many more.  However, this feature is
+optional currently in SILC as there does not exist thorough analysis of
+this feature.  It is with out a doubt that there will be many more
+applications that has not yet been discovered.  Thus, it is left
+to Internet Community to investigate the use of tunneling in SILC
+protocol.  This document is updated according those investigations
+and additional documents on the issue may be written.
+
+
+.ti 0
+3 Security Considerations
+
+Security is central to the design of this protocol, and these security
+considerations permeate the specification.
+
+
+.ti 0
+4 References
+
+[SILC1]      Riikonen, P., "Secure Internet Live Conferencing (SILC),
+             Protocol Specification", Internet Draft, June 2000.
+
+[SILC3]      Riikonen, P., "SILC Key Exchange and Authentication 
+             Protocols", Internet Draft, June 2000.
+
+[IRC]        Oikarinen, J., and Reed D., "Internet Relay Chat Protocol",
+             RFC 1459, May 1993.
+
+[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.
+
+
+
+
+
+
+.ti 0
+5 Author's Address
+
+.nf
+Pekka Riikonen
+Kasarmikatu 11 A4
+70110 Kuopio
+Finland
+
+EMail: priikone@poseidon.pspt.fi
+
+This Internet-Draft expires 6 Jun 2001
index a37c0a5181e7fe681a09f20867b8d3ec5fbb9d5a..5bd3c04c3b9950932db90f4925fd166d02ea460c 100644 (file)
@@ -8,44 +8,45 @@
 .ds RF FORMFEED[Page %]
 .ds CF
 .ds LH Internet Draft
-.ds RH 27 June 2000
-.ds CH Secure Internet Live Conferencing
+.ds RH 13 September 2000
+.ds CH
 .na
 .hy 0
 .in 0
 .nf
 Network Working Group                                      P. Riikonen
 Internet-Draft
-draft-riikonen-silc-spec-00.txt                           27 June 2000
-Expires: 27 Jan 2001
+draft-riikonen-silc-spec-00.txt                      13 September 2000
+Expires: 13 May 2001
 
 .in 3
 
-.ce 2
+.ce 3
 Secure Internet Live Conferencing (SILC),
 Protocol Specification
+<draft-riikonen-silc-spec-00.txt>
 
 .ti 0
 Status of this Memo
 
-This document is an Internet-Draft.  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."   
 
-To learn the current status of any Internet-Draft, please check the
-``1id-abstracts.txt'' listing contained in the Internet-Drafts
-Shadow Directories on ftp.is.co.za (Africa), nic.nordu.net (Europe),
-munnari.oz.au (Pacific Rim), ds.internic.net (US East Coast), or
-ftp.isi.edu (US West Coast).
+The list of current Internet-Drafts can be accessed at   
+http://www.ietf.org/ietf/1id-abstracts.txt   
 
-The distribution of this memo is unlimited.
+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
@@ -80,50 +81,51 @@ Table of Contents
 3 SILC Specification ............................................  7
   3.1 Client ....................................................  7
       3.1.1 Client ID ...........................................  8
-  3.2 Server ....................................................  8
+  3.2 Server ....................................................  9
       3.2.1 Server's Local ID List ..............................  9
       3.2.2 Server ID ........................................... 10
-      3.2.3 SILC Server Ports ................................... 10
+      3.2.3 SILC Server Ports ................................... 11
   3.3 Router .................................................... 11
       3.3.1 Router's Local ID List .............................. 11
       3.3.2 Router's Global ID List ............................. 12
-      3.3.3 Router's Server ID .................................. 12
-  3.4 Channels .................................................. 12
-      3.4.1 Channel ID .......................................... 13
+      3.3.3 Router's Server ID .................................. 13
+  3.4 Channels .................................................. 13
+      3.4.1 Channel ID .......................................... 14
   3.5 Operators ................................................. 14
-  3.6 SILC Commands ............................................. 14
+  3.6 SILC Commands ............................................. 15
   3.7 SILC Packets .............................................. 15
-  3.8 Packet Encryption ......................................... 15
+  3.8 Packet Encryption ......................................... 16
       3.8.1 Determination of the Source and the Destination ..... 16
-      3.8.2 Client To Client .................................... 16
-      3.8.3 Client To Channel ................................... 17
-      3.8.4 Server To Server .................................... 18
-  3.9 Key Exchange And Authentication ........................... 18
+      3.8.2 Client To Client .................................... 17
+      3.8.3 Client To Channel ................................... 18
+      3.8.4 Server To Server .................................... 19
+  3.9 Key Exchange And Authentication ........................... 19
   3.10 Algorithms ............................................... 19
       3.10.1 Ciphers ............................................ 19
       3.10.2 Public Key Algorithms .............................. 20
       3.10.3 MAC Algorithms ..................................... 20
-      3.10.4 Compression Algorithms ............................. 20
+      3.10.4 Compression Algorithms ............................. 21
   3.11 SILC Public Key .......................................... 21
-4 SILC Procedures ............................................... 23
-  4.1 Creating Client Connection ................................ 23
-  4.2 Creating Server Connection ................................ 24
-  4.3 Joining to a Channel ...................................... 25
-  4.4 Channel Key Generation .................................... 26
+  3.12 SILC Version Detection ................................... 24
+4 SILC Procedures ............................................... 24
+  4.1 Creating Client Connection ................................ 24
+  4.2 Creating Server Connection ................................ 25
+  4.3 Joining to a Channel ...................................... 26
+  4.4 Channel Key Generation .................................... 27
   4.5 Private Message Sending and Reception ..................... 27
-  4.6 Private Message Key Generation ............................ 27
-  4.7 Channel Message Sending and Reception ..................... 28
-  4.8 Session Key Regeneration .................................. 28
+  4.6 Private Message Key Generation ............................ 28
+  4.7 Channel Message Sending and Reception ..................... 29
+  4.8 Session Key Regeneration .................................. 29
   4.9 Command Sending and Reception ............................. 29
-5 SILC Commands ................................................. 29
-  5.1 SILC Commands Syntax ...................................... 29
-  5.2 SILC Commands List ........................................ 31
+5 SILC Commands ................................................. 30
+  5.1 SILC Commands Syntax ...................................... 30
+  5.2 SILC Commands List ........................................ 32
   5.3 SILC Command Status Types ................................. 53
       5.3.1 SILC Command Status Payload ......................... 53
       5.3.2 SILC Command Status List ............................ 54
-6 Security Considerations ....................................... 58
-7 References .................................................... 58
-8 Author's Address .............................................. 59
+6 Security Considerations ....................................... 59
+7 References .................................................... 59
+8 Author's Address .............................................. 60
 
 
 .ti 0
@@ -143,11 +145,12 @@ Figure 5:  SILC Command Status Payload
 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.  Strong cryptographic
-methods are used to protect SILC packets inside SILC network.  Two
-other Internet Drafts relates very closely to this memo;  SILC Packet
-Protocol [SILC2] and SILC Key Exchange and Authentication Protocols
-[SILC3].
+not equivalent to IRC and does not support IRC.
+
+Strong cryptographic methods are used to protect SILC packets inside
+SILC network.  Two other Internet Drafts relates very closely to this
+memo; SILC Packet Protocol [SILC2] and SILC Key Exchange and
+Authentication Protocols [SILC3].
 
 The protocol uses extensively packets as conferencing protocol 
 requires message and command sending.  The SILC Packet Protocol is
@@ -189,7 +192,8 @@ clear.
 SILC network is a cellular network as opposed to tree style network 
 topology.  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.  
+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 
@@ -199,9 +203,25 @@ keep global information up to date at all time.
 
 This, on the other hand, leads to cellular like network, where routers 
 are in the centrum on the cell and servers are connected to the router.
+
 Following diagram represents SILC network topology.
 
 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 .in 8
 .nf
   ---- ---- ----         ---- ---- ----
@@ -326,9 +346,6 @@ when clients are connected directly to the routers and the messages
 are delivered from one router to the other router.
 
 
-
-
-
 .ti 0 
 2.4 Channel Communication
 
@@ -402,7 +419,7 @@ 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.
 
-o Random number - Random number to further unify the
+o Random number - Random number to further randomize the
   Client ID.  This makes it possible to have 2^8 same
   nicknames from the same server IP address.
 
@@ -462,6 +479,13 @@ of creating the Client ID's for their clients.
 Normal server also keeps information about locally created channels and
 their Channel ID's.
 
+
+
+
+
+
+
+
 Hence, local list for normal server includes:
 
 .in 6
@@ -481,8 +505,6 @@ client list        - All clients in server
    o Sending key
    o Receiving key
 
-
-
 channel list       - All channels in server
    o Channel name
    o Channel ID
@@ -513,7 +535,7 @@ o IP address of the server - This is the real IP address of
 
 o Port - This is the port the server is binded to.
 
-o Random number - This is used to further unify the Server ID.
+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
@@ -524,13 +546,15 @@ distributing it to the router.
 .ti 0
 3.2.3 SILC Server Ports
 
-SILC uses currently TCP port 334 on SILC network.  However, this is not
-official port assigned for SILC.  Official port has been requested by 
-the IANA.
+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.  Most convenience case
-would be to assign port numbers upwards from 334.
+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.
@@ -565,6 +589,10 @@ information about user's nickname, username and hostname and real name
 since these are not needed by the router.  Router keeps only information
 that it needs.
 
+
+
+
+
 Hence, local list for router includes:
 
 .in 6
@@ -616,6 +644,7 @@ server list        - All servers in SILC
    o Server ID
    o Router's Server ID
 
+
 client list        - All clients in SILC
    o Client ID
 
@@ -707,7 +736,7 @@ o Router's Server ID IP address - Indicates the IP address of
 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 unify the Channel ID.  This makes
+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.
 .in 3
@@ -738,7 +767,10 @@ 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.  However, server may not send command
-to client and there are some commands that server must not send.
+to client and there are some commands that server must not send.  Server
+is also able to send the forwarded command packets.  For example, 
+SILC_COMMAND_JOIN is always forwarded packet.  See [SILC2] for more
+about packet forwarding.
 
 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
@@ -770,6 +802,8 @@ in [SILC2].  This document does not define or describe details of
 SILC packets.
 
 
+
+
 .ti 0
 3.8 Packet Encryption
 
@@ -968,6 +1002,11 @@ in the SILC packets.  See [SILC2] of 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.
 
+
+
+
+
+
 Following ciphers are defined in SILC protocol:
 
 .in 6
@@ -993,10 +1032,6 @@ Additional ciphers may be defined to be used in SILC by using the
 same name format as above.
 
 
-
-
-
-
 .ti 0
 3.10.2 Public Key Algorithms
 
@@ -1023,6 +1058,10 @@ Data integrity is protected by computing a message authentication code
 (MAC) of the packet data.  See [SILC2] for details how to compute the
 MAC.
 
+
+
+
+
 Following MAC algorithms are defined in SILC protocol:
 
 .in 6
@@ -1074,6 +1113,11 @@ 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
@@ -1176,6 +1220,39 @@ All fields in the public key are in MSB (most significant byte first)
 order.
 
 
+.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 intiator and responder.  The
+version identifier is of following format:
+
+.in 6
+SILC-<protocol version>-<software version>
+.in 3
+
+The version strings are of following format:
+
+.in 6
+protocol version = <major>.<minor>
+software version = <major>[.<minor>[.<build>]]
+.in 3
+
+Protocol version may provide both major and minor version.  Currently
+implementations must set the protocol version and accept the protocol
+version as SILC-1.0-<sotware version>. 
+
+Software version may provide major, minor and build version.  The
+software version may be freely set and accepted.
+
+Thus, the version string could be, for example:
+
+.in 6
+SILC-1.0-1.2
+.in 3
+
+
 .ti 0
 4 SILC Procedures
 
@@ -1298,7 +1375,7 @@ newly joined channel is sent to the router.  The new channel key is
 also distributed to the router and to all clients on the channel.
 
 If the channel does not exist in the local list the command must be
-sent to the router which will then perform the actual joining
+fowarded 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 distributed to the client who sent the command
 originally.  Server will also receive the channel key from the server
@@ -1421,6 +1498,8 @@ case by default in SILC, the private messages are secured by using
 normal session keys established by SILC Key Exchange protocol.
 
 
+
+
 .ti 0
 4.7 Channel Message Sending and Reception
 
@@ -1519,6 +1598,10 @@ 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
@@ -1570,6 +1653,8 @@ 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
@@ -1600,19 +1685,23 @@ List of all defined commands in SILC follows.
         None.  This is reserved command and must not be sent.
 
 
-   2    SILC_COMMAND_WHOIS
+   1    SILC_COMMAND_WHOIS
 
-        Max Arguments:  2
-            Arguments:  (1) <nickname>[@<server>]  (2) [<count>]
+        Max Arguments:  3
+            Arguments:  (1) <nickname>[@<server>]  (2) [<Client ID>]
+                        (3) [<count>]
+
+        Whois command is used to query various information about specific
+        user.  The user maybe 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 maybe 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.
 
-        Whois.  Whois command is used to query various information about
-        specific user.  The user maybe 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
-        maybe 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.
+        It is also possible to search the user by Client ID.  If <Client ID>
+        is provided server must use it as the search value instead of
+        the <nickname>.
 
         To prevent miss-use of this service wildcards in the nickname
         or in the servername are not permitted.  It is not allowed
@@ -1658,7 +1747,7 @@ List of all defined commands in SILC follows.
             SILC_STATUS_ERR_TOO_MANY_PARAMS
 
 
-   3    SILC_COMMAND_WHOWAS
+   2    SILC_COMMAND_WHOWAS
 
         Max Arguments:  2
             Arguments:  (1) <nickname>[@<server>]  (2) [<count>]
@@ -1707,7 +1796,7 @@ List of all defined commands in SILC follows.
             SILC_STATUS_ERR_TOO_MANY_PARAMS
 
 
-   4    SILC_COMMAND_IDENTIFY
+   3    SILC_COMMAND_IDENTIFY
 
         Max Arguments:  2
             Arguments:  (1) <nickname>[@<server>]  (2) [<count>]
@@ -1730,7 +1819,7 @@ List of all defined commands in SILC follows.
         be based on specific nickname request.
 
         Implementations may not want to give interface access to this
-        commands as it is hardly a command that would be used a end user.
+        command as it is hardly a command that would be used a end user.
         However, it must be implemented as it is used with private message
         sending.
 
@@ -1766,7 +1855,7 @@ List of all defined commands in SILC follows.
             SILC_STATUS_ERR_TOO_MANY_PARAMS
 
 
-   5    SILC_COMMAND_NICK
+   4    SILC_COMMAND_NICK
 
         Max Arguments:  1
             Arguments:  (1) <nickname>
@@ -1800,7 +1889,7 @@ List of all defined commands in SILC follows.
             SILC_STATUS_ERR_TOO_MANY_PARAMS
 
 
-   6    SILC_COMMAND_LIST
+   5    SILC_COMMAND_LIST
 
         Max Arguments:  2
             Arguments:  (1) [<Channel ID>] [<server>]
@@ -1817,9 +1906,9 @@ List of all defined commands in SILC follows.
 
         Reply messages to the command:
 
-        Max Arguments:  3
-            Arguments:  (1) <Status Payload>  (2) <channel>
-                        (3) <topic>
+        Max Arguments:  4
+            Arguments:  (1) <Status Payload>  (2) <Channel ID>
+                        (3) <channel>         (4) <topic>
 
         This command may reply with several command reply messages to form
         a list of results.  In this case the status payload will include
@@ -1827,7 +1916,7 @@ List of all defined commands in SILC follows.
         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 name and the topic of the
+        This command replies with Channel ID, name and the topic of the
         channel.  If the channel is private channel the <topic> includes
         "*private*" string.
 
@@ -1844,7 +1933,7 @@ List of all defined commands in SILC follows.
             SILC_STATUS_ERR_NO_SUCH_SERVER
 
 
-   7    SILC_COMMAND_TOPIC
+   6    SILC_COMMAND_TOPIC
 
         Max Arguments:  2
             Arguments:  (1) <Channel ID>  (2) [<server>]]
@@ -1878,16 +1967,19 @@ List of all defined commands in SILC follows.
             SILC_STATUS_ERR_NO_CHANNEL_PRIV
 
 
-   8    SILC_COMMAND_INVITE
+   7    SILC_COMMAND_INVITE
 
         Max Arguments:  2
-            Arguments:  (1) <Client ID>  (2) <channel>
+            Arguments:  (1) <Client ID>  (2) <Channel ID>
 
         This command is used to invite other clients to join to the
-        channel.  There is no requirement that the channel the target
-        client is being invited to must exist or be a valid channel.
-        The <Client ID> argument is the target client's ID that is being
-        invited.
+        channel.  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.  This command must fail if the requested channel does
+        not exist, the requested client 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.
 
         Reply messages to the command:
 
@@ -1899,18 +1991,18 @@ List of all defined commands in SILC follows.
         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_CLIENT_ID
             SILC_STATUS_ERR_TOO_MANY_PARAMS
-            SILC_STATUS_ERR_NO_RECIPIENT
-            SILC_STATUS_ERR_USER_ON_CHANNEL
+            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
 
 
-   9    SILC_COMMAND_QUIT
+   8    SILC_COMMAND_QUIT
 
         Max Arguments:  1
             Arguments:  (1) [<quit message>]
@@ -1925,7 +2017,7 @@ List of all defined commands in SILC follows.
         This command does not reply anything.
 
 
-   10   SILC_COMMAND_KILL
+    9   SILC_COMMAND_KILL
 
         Max Arguments:  2
             Arguments:  (1) <Client ID>  (2) [<comment>]
@@ -1955,7 +2047,10 @@ List of all defined commands in SILC follows.
             SILC_STATUS_ERR_NO_CLIENT_ID
 
 
-   11   SILC_COMMAND_INFO
+
+
+
+   10   SILC_COMMAND_INFO
 
         Max Arguments:  1
             Arguments:  (1) [<server>]
@@ -1978,14 +2073,12 @@ List of all defined commands in SILC follows.
             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_ID
             SILC_STATUS_ERR_NO_SUCH_SERVER
 
 
-
-
-   12   SILC_COMMAND_CONNECT
+   11   SILC_COMMAND_CONNECT
 
         Max Arguments:  2
             Arguments:  (1) <Server ID>  
@@ -2004,6 +2097,8 @@ List of all defined commands in SILC follows.
 
         This command replies only with Status Payload.
 
+
+
         Status messages:
 
             SILC_STATUS_OK
@@ -2016,15 +2111,15 @@ List of all defined commands in SILC follows.
             SILC_STATUS_ERR_NO_ROUTER_PRIV
 
 
-   13   SILC_COMMAND_PING
+   12   SILC_COMMAND_PING
 
         Max Arguments:  1
             Arguments:  (1) <Server ID>
 
-        This command is used by clients to test the communication
-        channel to its server if client suspects that the communication
-        is not working correctly.  The <Server ID> is the ID of the
-        server the client is connected to.
+        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:
 
@@ -2039,11 +2134,12 @@ List of all defined commands in SILC follows.
             SILC_STATUS_OK
             SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
             SILC_STATUS_ERR_TOO_MANY_PARAMS
-            SILC_STATUS_ERR_NO_SUCH_SERVER_ID
+            SILC_STATUS_ERR_NO_SERVER_ID
+            SILC_STATUS_ERR_NO_SUCH_SERVER
             SILC_STATUS_ERR_NOT_REGISTERED
 
 
-   14   SILC_COMMAND_OPER
+   13   SILC_COMMAND_OPER
 
         Max Arguments:  2
             Arguments:  (1) <username>  (2) <authentication data>
@@ -2078,7 +2174,7 @@ List of all defined commands in SILC follows.
             SILC_STATUS_ERR_AUTH_FAILED
 
 
-   15   SILC_COMMAND_JOIN
+   14   SILC_COMMAND_JOIN
 
         Max Arguments:  3
             Arguments:  (1) <channel>  (2) [<passphrase>] 
@@ -2086,9 +2182,10 @@ List of all defined commands in SILC follows.
 
         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 on the server receiving the join request.  The channel 
-        may be protected with passphrase.  If this is the case the 
-        passphrase must be sent along the join command.
+        created.  If server is normal server this command must be forwarded
+        to router who 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.
@@ -2148,7 +2245,7 @@ List of all defined commands in SILC follows.
             SILC_STATUS_ERR_USER_ON_CHANNEL
 
 
-   16   SILC_COMMAND_MOTD
+   15   SILC_COMMAND_MOTD
 
         Max Arguments:  1
             Arguments:  (1) <server>
@@ -2171,7 +2268,7 @@ List of all defined commands in SILC follows.
             SILC_STATUS_ERR_NO_SUCH_SERVER
 
 
-   17   SILC_COMMAND_UMODE
+   16   SILC_COMMAND_UMODE
 
         Max Arguments:  2
             Arguments:  (1) <Client ID>  (2) <client mode mask>
@@ -2218,6 +2315,7 @@ List of all defined commands in SILC follows.
         This command replies with the changed client mode mask that
         the client is required to keep locally.
 
+
         Status messages:
 
             SILC_STATUS_OK
@@ -2232,12 +2330,13 @@ List of all defined commands in SILC follows.
             SILC_STATUS_ERR_NO_CLIENT_ID
 
 
-   18   SILC_COMMAND_CMODE
+   17   SILC_COMMAND_CMODE
 
-        Max Arguments:  6
+        Max Arguments:  8
             Arguments:  (1) <Channel ID>    (2) <channel mode mask>
                         (3) [<user limit>]  (4) [<passphrase>]
-                        (5) [<Client ID>]   (6) [<cipher>[:<key len>]]
+                        (5) [<ban mask>]    (6) [<invite list>]
+                        (7) [<Client ID>]   (8) [<cipher>[:<key len>]]
 
         This command is used by client to set or change channel flags on
         a channel.  Channel has several modes that set various properties
@@ -2375,8 +2474,22 @@ List of all defined commands in SILC follows.
               Typical implementation would use [+|-]b on user interface
               to set/unset this mode.
 
+
+           0x0100    SILC_CMODE_INVITE
+
+              Invite list has been set to the channel.  The invite list
+              can be used to mark the clients that is able to join
+              channel without being invited when the channel is set to
+              be invite-only channel.  The <invite list> argument is the
+              set invite mask.  When unsetting entry from the invite list
+              the entry must be provided as argument.  Channel founder and
+              channel operator may set/unset this mode.
+
+              Typical implementation would use [+|-]I on user interface
+              to set/unset this mode.
+
         
-           0x0100    SILC_CMODE_OPERATOR
+           0x0200    SILC_CMODE_OPERATOR
 
               Sets channel operator privileges on the channel for a
               client on the channel.  The <Client ID> argument is the
@@ -2388,7 +2501,7 @@ List of all defined commands in SILC follows.
               to set/unset this mode.
 
 
-           0x0200    SILC_CMODE_CIPHER
+           0x0400    SILC_CMODE_CIPHER
 
               Sets specific cipher to be used to protect channel
               traffic.  The <cipher> argument is the requested cipher.
@@ -2409,6 +2522,7 @@ List of all defined commands in SILC follows.
         all clients on the channel by sending SILC_COMMAND_CMODE command
         reply packet.
 
+
         Reply messages to the command:
 
         Max Arguments:  2
@@ -2434,7 +2548,9 @@ List of all defined commands in SILC follows.
             SILC_STATUS_ERR_NO_CLIENT_ID
 
 
-   19   SILC_COMMAND_KICK
+
+
+   18   SILC_COMMAND_KICK
 
         Max Arguments:  3
             Arguments:  (1) <channel>  (2) <Client ID>  
@@ -2465,7 +2581,7 @@ List of all defined commands in SILC follows.
             SILC_STATUS_ERR_NO_CLIENT_ID
 
 
-   20   SILC_COMMAND_RESTART
+   19   SILC_COMMAND_RESTART
 
         Max Arguments:  0
             Arguments:  None
@@ -2480,6 +2596,8 @@ List of all defined commands in SILC follows.
 
         This command replies only with Status Payload.
 
+
+
         Status messages:
 
             SILC_STATUS_OK
@@ -2487,7 +2605,7 @@ List of all defined commands in SILC follows.
             SILC_STATUS_ERR_NO_SERVER_PRIV
 
 
-   21   SILC_COMMAND_CLOSE
+   20   SILC_COMMAND_CLOSE
 
         Max Arguments:  1
             Arguments:  (1) <Server ID>
@@ -2503,6 +2621,8 @@ List of all defined commands in SILC follows.
 
         This command replies only with Status Payload.
 
+
+
         Status messages:
 
             SILC_STATUS_OK
@@ -2514,7 +2634,7 @@ List of all defined commands in SILC follows.
             SILC_STATUS_ERR_NO_SUCH_SERVER_ID
 
 
-   22   SILC_COMMAND_DIE
+   21   SILC_COMMAND_DIE
 
         Max Arguments:  0
             Arguments:  None
@@ -2525,6 +2645,8 @@ List of all defined commands in SILC follows.
 
         Reply messages to the command:
 
+
+
         Max Arguments:  1
             Arguments:  (1) <Status Payload>
 
@@ -2537,7 +2659,7 @@ List of all defined commands in SILC follows.
             SILC_STATUS_ERR_NO_SERVER_PRIV
 
 
-   23   SILC_COMMAND_SILCOPER
+   22   SILC_COMMAND_SILCOPER
 
         Max Arguments:  2
             Arguments:  (1) <username>  (2) <authentication data>
@@ -2577,7 +2699,7 @@ List of all defined commands in SILC follows.
             SILC_STATUS_ERR_AUTH_FAILED
 
 
-   24   SILC_COMMAND_LEAVE
+   23   SILC_COMMAND_LEAVE
 
         Max Arguments:  1
             Arguments:  (1) <Channel ID>
@@ -2605,7 +2727,7 @@ List of all defined commands in SILC follows.
             SILC_STATUS_ERR_NO_CHANNEL_ID
 
 
-   25   SILC_COMMAND_NAMES
+   24   SILC_COMMAND_NAMES
 
         Max Arguments:  1
             Arguments:  (1) <Channel ID>
@@ -2624,11 +2746,17 @@ List of all defined commands in SILC follows.
 
         Reply messages to the command:
 
-        Max Arguments:  2
-            Arguments:  (1) <Status Payload>  (2) <name list>
+        Max Arguments:  3
+            Arguments:  (1) <Status Payload>  (2) <Channel ID>
+                        (3) <name list>       (4) <Client ID list>
 
-        This command replies with the comma separated list of users on
-        the channel.
+        This command replies with the Channel ID of the requested channel,
+        comma separated list of users on the channel and Client ID list
+        of the users on the list.  The Client ID list has Client ID's
+        of all users in the list.  First Client ID in the list must be
+        the Client ID of the first user in <name list>.  The Client ID
+        List is formed by adding Client ID's each after each.  Note that
+        the Client ID list is binary data.
 
         Status messages:
 
@@ -2642,7 +2770,7 @@ List of all defined commands in SILC follows.
             SILC_STATUS_ERR_NOT_ON_CHANNEL
 
 
-   26 - 254
+   25 - 254
 
         Currently undefined commands.
 
@@ -2767,125 +2895,129 @@ List of all defined command status messages following.
         "No Channel ID given".  Channel ID were expected as command
         parameter but were not found.
 
-   19   SILC_STATUS_ERR_BAD_CLIENT_ID
+   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.
 
-   20   SILC_STATUS_ERR_BAD_CHANNEL_ID
+   21   SILC_STATUS_ERR_BAD_CHANNEL_ID
 
         "Bad Channel ID".  Channel ID provided were erroneous.
 
-   21   SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+   22   SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
 
         "No such Client ID".  Client ID provided does not exist.
 
 
-
-   22   SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+   23   SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
 
         "No such Channel ID".  Channel ID provided does not exist.
 
-   23   SILC_STATUS_ERR_NICKNAME_IN_USE
+   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.
 
-   24   SILC_STATUS_ERR_NOT_ON_CHANNEL
+   25   SILC_STATUS_ERR_NOT_ON_CHANNEL
 
         "You are not on that channel".  The command were specified for
         client user is not currently on.
 
-   25   SILC_STATUS_ERR_USER_ON_CHANNEL
+   26   SILC_STATUS_ERR_USER_ON_CHANNEL
 
         "User already on channel".  User were invited on channel they
         already are on.
 
-   26   SILC_STATUS_ERR_NOT_REGISTERED
+   27   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.
 
-   27   SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+   28   SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
 
         "Not enough parameters".  Command requires more parameters
         than provided.
 
-   28   SILC_STATUS_ERR_TOO_MANY_PARAMS
+   29   SILC_STATUS_ERR_TOO_MANY_PARAMS
 
         "Too many parameters".  Too many parameters were provided
         for the command.
 
-   29   SILC_STATUS_ERR_PERM_DENIED
+   30   SILC_STATUS_ERR_PERM_DENIED
 
         "Your host is not among the privileged".  The client tried to
         register on server that does not allow this host to connect.
 
-   30   SILC_STATUS_ERR_BANNED_FROM_SERVER
+   31   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.
 
 
 
-   31   SILC_STATUS_ERR_BAD_PASSWORD
+   32   SILC_STATUS_ERR_BAD_PASSWORD
 
         "Cannot join channel. Incorrect password".  Password provided for 
         channel were not accepted.
 
-   32   SILC_STATUS_ERR_CHANNEL_IS_FULL
+   33   SILC_STATUS_ERR_CHANNEL_IS_FULL
 
         "Cannot join channel. Channel is full".  The channel is full
         and client cannot be joined to it.
 
-   33   SILC_STATUS_ERR_NOT_INVITED
+   34   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.
 
-   34   SILC_STATUS_ERR_BANNED_FROM_CHANNEL
+   35   SILC_STATUS_ERR_BANNED_FROM_CHANNEL
 
         "Cannot join channel. You have been banned".  The client has
         been banned from the channel.
 
-   35   SILC_STATUS_ERR_UNKNOWN_MODE
+   36   SILC_STATUS_ERR_UNKNOWN_MODE
 
         "Unknown mode".  Mode provided by the client were unknown to
         the server.
 
-   36   SILC_STATUS_ERR_NOT_YOU
+   37   SILC_STATUS_ERR_NOT_YOU
 
         "Cannot change mode for other users".  User tried to change
         someone else's mode.
 
-   37   SILC_STATUS_ERR_NO_CHANNEL_PRIV
+   38   SILC_STATUS_ERR_NO_CHANNEL_PRIV
 
         "Permission denied. You are not channel operator".  Command may 
         be executed only by channel operator.
 
-   38   SILC_STATUS_ERR_NO_SERVER_PRIV
+   39   SILC_STATUS_ERR_NO_SERVER_PRIV
 
         "Permission denied. You are not server operator".  Command may
         be executed only by server operator.
 
-   39   SILC_STATUS_ERR_NO_ROUTER_PRIV
+   40   SILC_STATUS_ERR_NO_ROUTER_PRIV
 
         "Permission denied. You are not SILC operator".  Command may be
         executed only by router (SILC) operator.
 
-   40   SILC_STATUS_ERR_BAD_NICKNAME
+   41   SILC_STATUS_ERR_BAD_NICKNAME
 
         "Bad nickname".  Nickname requested contained illegal characters
         or were malformed.
 
-   41   SILC_STATUS_ERR_BAD_CHANNEL
+   42   SILC_STATUS_ERR_BAD_CHANNEL
 
         "Bad channel name".  Channel requested contained illegal characters
         or were malformed.
 
-   42   SILC_STATUS_ERR_AUTH_FAILED
+   43   SILC_STATUS_ERR_AUTH_FAILED
 
         "Authentication failed".  The authentication data sent as 
         argument were wrong and thus authentication failed.
@@ -2899,6 +3031,9 @@ Security is central to the design of this protocol, and these security
 considerations permeate the specification.
 
 
+
+
+
 .ti 0
 7 References
 
@@ -2944,6 +3079,7 @@ considerations permeate the specification.
              Authentication", RFC 2104, February 1997.
 
 
+
 .ti 0
 8 Author's Address
 
@@ -2954,3 +3090,5 @@ Kasarmikatu 11 A4
 Finland
 
 EMail: priikone@poseidon.pspt.fi
+
+This Internet-Draft expires 13 May 2001 
diff --git a/doc/draft-riikonen-silc-spec-01.nroff b/doc/draft-riikonen-silc-spec-01.nroff
new file mode 100644 (file)
index 0000000..33555f1
--- /dev/null
@@ -0,0 +1,3228 @@
+.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 6 October 2000
+.ds CH
+.na
+.hy 0
+.in 0
+.nf
+Network Working Group                                      P. Riikonen
+Internet-Draft
+draft-riikonen-silc-spec-01.txt                         6 October 2000
+Expires: 6 Jun 2001
+
+.in 3
+
+.ce 3
+Secure Internet Live Conferencing (SILC),
+Protocol Specification
+<draft-riikonen-silc-spec-01.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 is IRC [IRC] like protocol, however, it is 
+not equivalent to IRC and does not support IRC.  Strong cryptographic
+methods are used to protect SILC packets inside SILC network.  Two
+other Internet Drafts relates very closely to this memo;  SILC Packet
+Protocol [SILC2] and SILC Key Exchange and Authentication Protocols
+[SILC3].
+
+
+
+
+
+
+
+
+.ti 0
+Table of Contents
+
+.nf
+1 Introduction ..................................................  3
+2 SILC Concepts .................................................  3
+  2.1 SILC Network Topology .....................................  4
+  2.2 Communication Inside a Cell ...............................  5
+  2.3 Communication in the Network ..............................  6
+  2.4 Channel Communication .....................................  7
+  2.5 Router Connections ........................................  7
+3 SILC Specification ............................................  8
+  3.1 Client ....................................................  8
+      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.3 SILC Server Ports ................................... 11
+  3.3 Router .................................................... 12
+      3.3.1 Router's Local ID List .............................. 12
+      3.3.2 Router's Global ID List ............................. 13
+      3.3.3 Router's Server ID .................................. 13
+  3.4 Channels .................................................. 14
+      3.4.1 Channel ID .......................................... 15
+  3.5 Operators ................................................. 15
+  3.6 SILC Commands ............................................. 15
+  3.7 SILC Packets .............................................. 16
+  3.8 Packet Encryption ......................................... 16
+      3.8.1 Determination of the Source and the Destination ..... 17
+      3.8.2 Client To Client .................................... 17
+      3.8.3 Client To Channel ................................... 19
+      3.8.4 Server To Server .................................... 19
+  3.9 Key Exchange And Authentication ........................... 20
+  3.10 Algorithms ............................................... 20
+      3.10.1 Ciphers ............................................ 20
+      3.10.2 Public Key Algorithms .............................. 21
+      3.10.3 MAC Algorithms ..................................... 21
+      3.10.4 Compression Algorithms ............................. 22
+  3.11 SILC Public Key .......................................... 22
+  3.12 SILC Version Detection ................................... 24
+4 SILC Procedures ............................................... 25
+  4.1 Creating Client Connection ................................ 25
+  4.2 Creating Server Connection ................................ 26
+  4.3 Joining to a Channel ...................................... 27
+  4.4 Channel Key Generation .................................... 28
+  4.5 Private Message Sending and Reception ..................... 29
+  4.6 Private Message Key Generation ............................ 29
+  4.7 Channel Message Sending and Reception ..................... 30
+  4.8 Session Key Regeneration .................................. 30
+  4.9 Command Sending and Reception ............................. 30
+5 SILC Commands ................................................. 31
+  5.1 SILC Commands Syntax ...................................... 31
+  5.2 SILC Commands List ........................................ 33
+  5.3 SILC Command Status Types ................................. 56
+      5.3.1 SILC Command Status Payload ......................... 56
+      5.3.2 SILC Command Status List ............................ 57
+6 Security Considerations ....................................... 61
+7 References .................................................... 61
+8 Author's Address .............................................. 62
+
+
+.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:  SILC Command Status Payload
+
+
+.ti 0
+1. Introduction
+
+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.
+
+Strong cryptographic methods are used to protect SILC packets inside
+SILC network.  Two other Internet Drafts relates very closely to this
+memo; SILC Packet Protocol [SILC2] and SILC Key Exchange and
+Authentication Protocols [SILC3].
+
+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 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 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
+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 is a cellular network as opposed to tree style network 
+topology.  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 cellular like network, where routers 
+are in the center of the cell and servers are connected to the router.
+
+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 normal SILC 
+server; clients may connect to it the same way as to normal SILC 
+servers.  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.
+
+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 will 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.  Client who 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.
+
+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. message sent 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 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 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 there is no direct connection to the destination router, the local
+router routes the message to its primary route.  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. message sent
+          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 client point of view is
+when clients are connected directly to the routers and the messages
+are delivered from one router to the other router.
+
+
+.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 who are 
+joined to the channel.  Also, router 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 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 circular.
+
+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.
+
+
+.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 nickname selected by the user.  User uses logical nicknames
+in communication which are then mapped to the corresponding Client ID.
+Client ID's are low level identifications and must 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 hostname 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 causes the server names to be used along
+with the nicknames 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.  Another difference is that there are no limit of the length
+of the nickname in the SILC.
+
+
+.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.
+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  ServerID IP address (bits 1-32)
+ 8 bit  Random number
+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 to the client has connected.
+
+o Random number - Random number to further randomize the
+  Client ID.  This makes it possible to have 2^8 same
+  nicknames from the same server IP address.
+
+o MD5 hash - MD5 hash value of the 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.
+
+.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 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 may 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 may not connect to other
+cell's router except in situations where its cell's router is unavailable.
+
+Servers and routers in the SILC network are considered to be trusted.
+With out a doubt, servers that are set to work on ports above 1023 are
+not considered to be trusted.  Also, the service provider acts important
+role in the server's trustworthy.
+
+
+.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 ID's, nicknames, usernames and hostnames 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.
+
+Normal server also keeps information about locally created channels and
+their Channel ID's.
+
+
+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
+
+channel list       - All channels in server
+   o Channel name
+   o Channel ID
+   o Client ID's 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.
+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 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
+
+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
+
+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 about everything in the SILC.
+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.
+
+
+.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 keep
+information about user's nickname, username and hostname and real name
+since these are not needed by the router.  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 ID's 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.
+
+
+.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 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
+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 hostnames or user's real names.  Router does not 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 ID's on channel
+   o Client ID modes on channel
+.in 3
+
+
+.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.  Server ID's for routers are always
+created by the remote router where the router is connected to.
+
+
+.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 name of the channel.
+
+Channel names are unique although the real uniqueness comes from 64 bit
+Channel ID that unifies each channel.  However, channel names are still
+unique and no two global channels with same name may exist.  Channel name
+is a string which begins with `#' character.  There is no limit on the
+length of the channel name.  Channel names may not contain any spaces
+(`  '), any non-printable ASCII characters, commas (`,') and wildcard
+characters.
+
+Channels can have operators that can administrate the channel and
+operate all of its modes.  Following operators on channel exist on 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.  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 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 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
+
+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 - 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.
+.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
+channel, to gain access to the contents of a 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
+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.  However, server may not send command
+to client and there are some commands that server must not send.  Server
+is also able to send the forwarded command packets.  For example, 
+SILC_COMMAND_JOIN is always forwarded packet.  See [SILC2] for more
+about packet forwarding.
+
+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,
+however, choose ignore the command reply, but should not.
+
+It is expected that some of the commands may be miss-used 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.  This should be sufficient to prevent the miss-use
+of commands.
+
+SILC commands are described in section 5 SILC Commands.
+
+
+.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.  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
+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].
+
+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 has their own 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 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 knows the key for 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
+from router to other router, including packets for channels, are
+encrypted with the shared session key.  Every router connection has
+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 is always 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
+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
+tell to where the packet needs to be sent and where it is coming from.
+
+The header in the packet does 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 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 case, for example, with command packets.
+
+
+.ti 0
+3.8.2 Client To Client
+
+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 has established 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 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 Router determines the destination of the packet and sends the
+  packet to the server.
+
+o Server determines the client to which the packet is destined
+  to and sends the packet to the client.
+
+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 
+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.
+
+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 the packet.
+
+
+.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 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
+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, Usually clients are accepted
+to connect to server without explicit authentication.  Servers are
+required use authentication protocol when connecting.  The authentication
+may be based on passphrase (pre-shared-secret) or public key.  The
+connection authentication protocol is described in detail in [SILC3].
+
+
+.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] of 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.
+
+Following ciphers are defined in SILC protocol:
+
+.in 6
+aes-cbc         AES in CBC mode       (mandatory)
+twofish-cbc     Twofish in CBC mode   (optional)
+blowfish-cbc    Blowfish in CBC mode  (optional)
+rc6-cbc         RC6 in CBC mode       (optional)
+rc5-cbc         RC5 in CBC mode       (optional)
+mars-cbc        Mars in CBC mode      (optional)
+none            No encryption         (optional)
+.in 3
+
+
+All algorithms must use minimum of 128 bit key, by default.  Several
+algorithms, however, supports longer keys and it is recommended to use
+longer keys if they are available.
+
+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 algorithms except in special
+debugging mode.
+
+Additional ciphers may be defined to be used in SILC by using the
+same name format as above.
+
+
+.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].
+
+Following public key algorithms are defined in SILC protocol:
+
+.in 6
+rsa        RSA  (mandatory)
+dss        DSS  (optional)
+.in 3
+
+Both of the algorithms are described in [Scheneir] and [Menezes].
+
+Additional public key algorithms may be defined to be used in SILC.
+
+
+.ti 0
+3.10.3 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.
+
+Following MAC algorithms are defined in SILC protocol:
+
+.in 6
+hmac-sha1        HMAC-SHA1, length = 20  (mandatory)
+hmac-md5         HMAC-MD5, length = 16   (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] and hash algorithms that
+are used as part of the HMACs are described in [Scheneir] and in
+[Menezes]
+
+Additional MAC algorithms may be defined to be used in SILC.
+
+
+.ti 0
+3.10.4 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.
+
+Following compression algorithms are defined:
+
+.in 6
+none        No compression               (mandatory)
+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 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 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 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 written as `\\,',
+  for example, `O=Company XYZ\\, Inc.'.
+
+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.
+
+
+.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 following format:
+
+.in 6
+SILC-<protocol version>-<software version>
+.in 3
+
+The version strings are of following format:
+
+.in 6
+protocol version = <major>.<minor>
+software version = <major>[.<minor>[.<build>]]
+.in 3
+
+Protocol version may provide both major and minor version.  Currently
+implementations must set the protocol version and accept the protocol
+version as SILC-1.0-<sotware version>. 
+
+Software version may provide major, minor and build version.  The
+software version may be freely set and accepted.
+
+
+Thus, the version string could be, for example:
+
+.in 6
+SILC-1.0-1.2
+.in 3
+
+
+.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 section describes the procedures only generally as details
+are described in [SILC2] and [SILC3].
+
+
+.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 must have 
+both valid IP address and fully qualified domain name (FQDN).
+
+After that 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.  Reason for
+this is that if the host is not allowed to connect to the server there
+is no reason to perform a key exchange protocol.
+
+After successful key exchange protocol the client and server performs
+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
+registers 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
+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 those
+informations rather than what it received from client.  This is 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.
+
+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].
+
+
+.ti 0
+4.2 Creating Server Connection
+
+This section descibres 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.
+
+One difference is that server must perform connection authentication
+protocol with proper authentication.  Proper authentication is based
+on passphrase or public key authentication.
+
+After server and router has successfully performed the key exchange
+and connection authentication protocol, the server 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.
+
+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].
+
+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.  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.
+
+If the server has already connected clients and locally created
+channels the server must distribute these informations to the router.
+The distribution is done by sending packet SILC_PACKET_NEW_CHANNEL.
+See [SILC2] for more information on this.
+
+
+.ti 0
+4.3 Joining to a Channel
+
+This section describes the procedure when client joins to a channel.
+Client may join 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
+joined to the client, new channel key is created and information about
+newly joined channel is sent to the router.  The new channel key is
+also distributed to the router and to all clients on the channel.
+
+If the channel does not exist in the local list the command must be
+forwarded 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 distributed to the client who sent the command
+originally.  Server will also receive the channel key from the server
+that it must distribute to the client who 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 who 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.
+
+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 is set for the client.
+
+When the router joins the client to the channel it must send 
+information about newly joined client to all routers in the SILC 
+network.  Also, if the channel was created in the process, information
+about newly created channel must also be distributed to all routers.
+The distribution of newly created channel is done by sending packet
+SILC_PACKET_NEW_CHANNEL.
+
+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 who receives the reply to
+the join command must start using the received Channel ID in the channel
+message communication thereafter.  However, client must not start
+communicating on the channel before it has received the packet
+SILC_PACKET_CHANNEL_KEY.
+
+If client wants to know the other clients currently on the channel
+the client must send SILC_COMMAND_NAMES command to receive a list of
+channel users.  Server implementation, however, may send command reply
+packet to SILC_COMMAND_NAMES command after client has joined to the
+channel even if the client has not sent the command.  Server should also
+send SILC_NOTIFY_TYPE_JOIN to all clients on the channel about a new
+client on the channel.
+
+
+.ti 0
+4.4 Channel Key Generation
+
+Channel keys are created by router who 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, who 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
+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
+how channel messages must be encrypted and decrypted when router is
+processing them.
+
+
+.ti 0
+4.5 Private Message Sending and Reception
+
+Private messages are sent point to point.  Client explicitly destines
+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.
+
+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.
+
+Receiver of a private message should not explicitly trust the nickname
+that it receives in the Private Message Payload, described in [SILC2].
+Implementations could resolve the nickname from server, as described
+previously, and compare the received Client ID and the SILC Packet
+Header's Client ID.  The nickname in the payload is merely provided
+to be displayed for end user.
+
+See [SILC2] for description of private message encryption and decryption
+process.
+
+
+.ti 0
+4.6 Private Message Key Generation
+
+Private message may be protected by key generated by 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.
+See more information about how this works technically in [SILC2].
+
+Other choice is to entirely use keys that are not sent through
+the SILC network at all.  This significantly adds security.  This key
+would be pre-shared-key that is known by both of the clients.  Both
+agree about using the key and starts sending packets that indicate
+that the private message is secured using private message key.  This
+is the technical aspect mentioned previously that is described
+in [SILC2].
+
+If the private message keys are not set to be used, which is the
+case by default in SILC, the private messages are secured by using
+normal session keys established by SILC Key Exchange protocol.
+
+
+
+
+.ti 0
+4.7 Channel Message Sending and Reception
+
+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 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.
+
+See [SILC2] for description of channel message encryption and decryption
+process.
+
+
+.ti 0
+4.8 Session Key Regeneration
+
+Session keys should 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.
+
+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 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
+hashing the old key with hash function selected earlier in the SKE
+protocol.  If the digest length of the hash function is too short for the
+key, then the key is distributed as described in section Processing the
+Key Material in [SILC3].  After both parties has regenerated the session
+key, both send SILC_PACKET_REKEY_DONE packet to each other.  These packets
+are still secured with the old key.  After these packets, following
+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.
+
+However, if the server is not able to process the command, it is usually
+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
+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
+to further to receive the exact information about the requested client.
+The WHOIS command travels all the way to the server who owns the client
+and it replies with command reply packet.  Finally, the server who
+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
+must not accept command reply packet originated from anyone else but
+from its own server.
+
+
+.ti 0
+5 SILC Commands
+
+.ti 0
+5.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 occured 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_TOO_MANY_TARGETS
+    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 5.3 SILC Command Status Types.
+
+.in 3
+Every command that has some kind of 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.
+
+
+.ti 0
+5.2 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:  3
+            Arguments:  (1) [<nickname>[@<server>]]  (2) [<Client ID>]
+                        (3) [<count>]
+
+        Whois command is used to query various information about specific
+        user.  The user maybe 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 maybe 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.
+
+        It is also possible to search the user by Client ID.  If <Client ID>
+        is provided server must use it as the search value instead of
+        the <nickname>.
+
+        To prevent miss-use of this service wildcards in the nickname
+        or in the servername are not permitted.  It is not allowed
+        to request all users on some server.  The WHOIS requests must 
+        be based on specific nickname request.
+
+        The WHOIS request must be always forwarded to router by server
+        so that all users are searched.  However, the server still must
+        search its locally connected clients.  The server must send
+        this command to the server who owns the requested client.  That
+        server must reply to the command.
+
+        Reply messages to the command:
+
+        Max Arguments:  7
+            Arguments:  (1) <Status Payload>       (2) <Client ID> 
+                        (3) <nickname>[@<server>]  (4) <username@host> 
+                        (5) <real name>            (6) [<channel list>] 
+                        (7) [<idle time>]
+
+        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 include the Client ID of the nickname,
+        nickname and servername, username and hostname and users 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.
+
+        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
+
+
+
+
+   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 maybe 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 maybe
+        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.
+
+        To prevent miss-use of this service wildcards in the nickname
+        or in the servername are not permitted.  The WHOWAS requests must 
+        be based on specific nickname request.
+
+        The WHOWAS request must be always forwarded to 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:  3
+            Arguments:  (1) <Status Payload>  (2) <nickname>[@<server>]
+                        (3) <username@host>
+
+        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 username and hostname.
+        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:  2
+            Arguments:  (1) [<nickname>[@<server>]]  (2) [<Client ID>]
+                        (3) [<count>]
+
+        Identify.  Identify command is almost analogous to WHOIS command,
+        except that it does not return as much information.  Only relevant
+        information such as Client ID is returned.  This is usually used
+        to get the Client ID of a client used in the communication with
+        the client.
+
+        The query may find multiple matching users as there are no unique 
+        nicknames in the SILC.  The <count> option maybe 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.
+
+        It is also possible to search the user by Client ID.  If <Client ID>
+        is provided server must use it as the search value instead of
+        the <nickname>.
+
+        To prevent miss-use of this service wildcards in the nickname
+        or in the servername are not permitted.  It is not allowed
+        to request all users on some server.  The IDENTIFY requests must 
+        be based on specific nickname request.
+
+        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 used with private message
+        sending.
+
+        The IDENTIFY must be always forwarded to 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) <Client ID>
+                        (3) [<nickname>[@<server>]]  (4) [<username@host>]
+
+        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 Client ID of the nickname and if more
+        information is available it may reply with nickname and username
+        and hostname.  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_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.  There is no limit of the length of the nickname in SILC.
+        Nickname must not include any spaces (` '), non-printable
+        characters, commas (`,') and any wildcard characters.  Note:
+        nicknames in SILC are case-sensitive which must be taken into
+        account when searching clients by nickname.
+
+        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_PACKET_REPLACE_ID to its primary route to replace the old
+        Client ID with the new one.
+
+        Reply messages to the command:
+
+        Max Arguments:  2
+            Arguments:  (1) <Status Payload>  (2) <New ID Payload>
+
+        This command is replied 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].
+
+        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:  2
+            Arguments:  (1) [<Channel ID>] [<server>]
+
+        The list command is used to list channels and their topics on
+        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.
+
+        If the <server> argument is specified the specified server's
+        channels are listed.  In this case the command must be sent to
+        the server who owns the channel that was requested.
+
+        Reply messages to the command:
+
+        Max Arguments:  4
+            Arguments:  (1) <Status Payload>  (2) <Channel ID>
+                        (3) <channel>         (4) <topic>
+
+        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> includes
+        "*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
+            SILC_STATUS_ERR_NO_SUCH_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.
+
+        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:  2
+            Arguments:  (1) <Client ID>  (2) <Channel ID>
+
+        This command is used to invite other clients to join to the
+        channel.  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.  This command must fail if the requested channel does
+        not exist, the requested client 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.
+
+        Reply messages to the command:
+
+        Max Arguments:  2
+            Arguments:  (1) <Status Payload>
+
+        This command replies only with Status 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_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
+
+
+   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:  2
+            Arguments:  (1) <Client ID>  (2) [<comment>]
+
+        This command is used by SILC operators to remove a client from
+        SILC network.  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.
+
+        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
+
+
+   10   SILC_COMMAND_INFO
+
+        Max Arguments:  1
+            Arguments:  (1) [<server>]
+
+        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.
+
+        Reply messages to the command:
+
+        Max Arguments:  3
+            Arguments:  (1) <Status Payload>  (2) <Server ID>
+                        (3) <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
+
+
+   11   SILC_COMMAND_CONNECT
+
+        Max Arguments:  2
+            Arguments:  (1) <Server ID>  
+                        (2) [<remote server/router>[ <port>]]
+
+        This command is used by operators to force a server to try to
+        establish a new connection to another router (if the connecting
+        server is normal server) or server (if the connecting server is
+        router server).  Operator may specify the server/router to be
+        connected by setting <remote server> argument.  The separator
+        between <remote server address> and <port> is whitespace (` ').
+
+        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_SERVER_ID
+            SILC_STATUS_ERR_NO_SERVER_PRIV
+            SILC_STATUS_ERR_NO_ROUTER_PRIV
+
+
+   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 data>
+
+        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 data> 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 data (data signed with private key), or 
+        certificate.
+
+        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_BAD_PASSWORD
+            SILC_STATUS_ERR_AUTH_FAILED
+
+
+   14   SILC_COMMAND_JOIN
+
+        Max Arguments:  3
+            Arguments:  (1) <channel>  (2) [<passphrase>] 
+                        (3) [<cipher>]
+
+        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 forwarded
+        to router who 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.
+
+        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 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/hostname must not match
+               any active bans.
+
+            o  The correct passphrase must be provided if passphrase 
+               is set to the channel.
+
+            o  The user count limit, if set, must not be reached.
+
+        Reply messages to the command:
+
+        Max Arguments:  6
+            Arguments:  (1) <Status Payload>  (2) <channel> 
+                        (3) <Channel ID>      (4) <channel mode mask>
+                        (5) [<ban mask>]      (6) [<invite list>]
+                        (6) [<topic>]
+
+        This command replies with the channel name requested by the
+        client, channel ID of the channel and topic of the channel
+        if it exists.  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).  If ban mask
+        and/or invite list is set they are sent as well.
+
+        Client must not start transmitting to the channel even after
+        server has replied to this command.  Client is permitted to 
+        start transmitting on channel after server has sent packet 
+        SILC_PACKET_CHANNEL_KEY to the client.
+
+        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:  2
+            Arguments:  (1) <Status Payload>  (2) [<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 may 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.
+
+        Following client modes are defined:
+
+           0x0000    SILC_UMODE_NONE
+
+              No specific mode for client.  This is the initial
+              setting when new client is created.  The client is
+              normal client now.
+
+
+           0x0001    SILC_UMODE_SERVER_OPERATOR
+
+              Marks the user as server operator.  Client cannot
+              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.
+
+
+           0x0002    SILC_UMODE_ROUTER_OPERATOR
+
+              Marks the user as router (SILC) operator.  Client
+              cannot 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.
+
+        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 is required 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_UNKNOWN_MODE
+            SILC_STATUS_ERR_NO_RECIPIENT
+            SILC_STATUS_ERR_NO_CLIENT_ID
+
+
+   17   SILC_COMMAND_CMODE
+
+        Max Arguments:  7
+            Arguments:  (1) <Channel ID>    (2) <channel mode mask>
+                        (3) [<user limit>]  (4) [<passphrase>]
+                        (5) [<ban mask>]    (6) [<invite list>]
+                        (7) [<cipher>[:<key len>]]
+
+        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 poses sufficient privileges to be able to
+        change the mode.
+
+        When the mode is changed SILC_NOTIFY_TYPE_CMODE_CHANGE notify
+        type is distributed to the channel.
+
+        Following channel modes are defined:
+
+           0x0000    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.
+
+
+           0x0001    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.
+
+              Typical implementation would use [+|-]p on user interface
+              to set/unset this mode.
+
+
+           0x0002    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.
+
+              Typical implementation would use [+|-]s on user interface
+              to set/unset this mode.
+
+
+           0x0004    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).  This specification does not define how the private
+              channel key is set as it is entirely local setting on
+              client end.
+
+              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.
+
+              Typical implementation would use [+|-]k on user interface
+              to set/unset this mode.
+
+
+           0x0008    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.
+
+              Typical implementation would use [+|-]i on user interface
+              to set/unset this mode.
+
+
+           0x0010    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.
+
+              Typical implementation would use [+|-]t on user interface
+              to set/unset this mode.
+
+
+           0x0020    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.
+
+              Typical implementation would use [+|-]l on user interface
+              to set/unset this mode.
+
+
+           0x0040    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.
+
+              Typical implementation would use [+|-]a on user interface
+              to set/unset this mode.
+
+
+           0x0080    SILC_CMODE_BAN
+
+              Ban mask has been set to the channel.  The ban mask
+              may be used to ban specific clients to join the channel.
+              The <ban mask> argument is the set ban mask.  When
+              unsetting a ban mask the mask must be provided as
+              argument.  Channel founder and channel operator may
+              set/unset this mode.  Channel founder may not be
+              added to the ban list.  <ban mask> is comma (`,') separated
+              list of banned clients in following format:
+
+                [<nickname>!][<username>]@[<hostname>]
+
+              Wildcards maybe used when banning clients.
+
+              Typical implementation would use [+|-]b on user interface
+              to set/unset this mode.
+
+
+           0x0100    SILC_CMODE_INVITE_LIST
+
+              Invite list has been set to the channel.  The invite list
+              can be used to mark the clients that is able to join
+              channel without being invited when the channel is set to
+              be invite-only channel.  The <invite list> argument is the
+              set invite mask.  When unsetting entry from the invite list
+              the entry must be provided as argument.  Channel founder and
+              channel operator may set/unset this mode.  The <invite list>
+              is command (`,') separated list of invited clients in following
+              format:
+
+                [<nickname>!][<username>]@[<hostname>]
+
+              Wildcards maybe used when setting the invite list.
+
+              Typical implementation would use [+|-]I on user interface
+              to set/unset this mode.
+
+        
+           0x0200    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.  If <key len> argument is specified with
+              <cipher> argument the new key is generated of <key len>
+              length in bits.  Only channel founder may set the cipher of 
+              the channel.  When unset the new key is generated using
+              default cipher for the channel.
+
+              Typical implementation would use [+|-]c on user interface
+              to set/unset this mode.
+
+
+        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 distributes the changed channel mode mask to
+        all clients on the channel by sending SILC_COMMAND_CMODE command
+        reply packet.
+
+
+        Reply messages to the command:
+
+        Max Arguments:  2
+            Arguments:  (1) <Status Payload>  (2) <channel mode mask>
+
+        This command replies with the changed channel mode mask that
+        client is required 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_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_UNKNOWN_MODE
+            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+
+
+   19   SILC_COMMAND_CUMODE
+
+        Max Arguments:  3
+            Arguments:  (1) <Channel ID>  (2) <mode mask>
+                        (3) <Client ID>
+
+        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 poses 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.
+
+        Following channel modes are defined:
+
+           0x0000    SILC_CUMODE_NONE
+
+              No specific mode.  This is the normal situation for client.
+              Also, this is the mode set when removing all modes from client.
+
+
+           0x0001    SILC_CUMODE_FOUNDER
+
+              The client is channel founder of the channel.  This mode
+              cannot be set by other client, it is set by the server when
+              the channel was founded (created).  The mode is provided 
+              because client may remove the founder rights from itself.
+
+
+           0x0002    SILC_CUMODE_OPERATOR
+
+              Sets channel operator privileges on the channel for a
+              client on the channel.  Channel founder and channel operator
+              may set/unset (promote/demote) this mode.
+
+
+        Reply messages to the command:
+
+        Max Arguments:  3
+            Arguments:  (1) <Status Payload>  (2) <channel user mode mask>
+                        (3) <Client ID>
+
+        This command replies with the changed channel user mode mask that
+        client is required to keep locally.  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_UNKNOWN_MODE
+            SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+
+
+   19   SILC_COMMAND_KICK
+
+        Max Arguments:  3
+            Arguments:  (1) <channel>  (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.
+
+        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_RESTART
+
+        Max Arguments:  0
+            Arguments:  None
+
+        This command may only be used by server operator to force a
+        server to restart itself.
+
+        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_REGISTERED
+            SILC_STATUS_ERR_NO_SERVER_PRIV
+
+
+
+
+
+   21   SILC_COMMAND_CLOSE
+
+        Max Arguments:  1
+            Arguments:  (1) <Server ID>
+
+        This command is used only by operator to close connection to a
+        remote site.  The <Server ID> argument is the ID of the remote
+        site and must be valid.
+
+        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_SERVER
+            SILC_STATUS_ERR_NO_SERVER_PRIV
+            SILC_STATUS_ERR_NO_SUCH_SERVER_ID
+
+
+   22   SILC_COMMAND_DIE
+
+        Max Arguments:  0
+            Arguments:  None
+
+        This command is used only by operator to shutdown the server.
+        All connections to the server will be closed and the server is
+        shutdown.
+
+        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_REGISTERED
+            SILC_STATUS_ERR_NO_SERVER_PRIV
+
+
+   23   SILC_COMMAND_SILCOPER
+
+        Max Arguments:  2
+            Arguments:  (1) <username>  (2) <authentication data>
+
+        This command is used by normal client to obtain router operator
+        privileges (also known as SILC operator) on some router.  Note
+        that router operator has router privileges that supersedes the
+        server operator privileges.
+
+        The <username> is the username set in the server configurations
+        as operator.  The <authentication data> 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 data (data signed with private key), or 
+        certificate.
+
+        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.
+
+        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_BAD_PASSWORD
+            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.  After a client has leaved the channel the server
+        must create new key for the channel and distribute to all clients
+        still currently on the channel.
+
+        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_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_NAMES
+
+        Max Arguments:  1
+            Arguments:  (1) <Channel ID>
+
+        This command is used to list user names currently on the requested
+        channel; argument <Channel ID>.  The server must resolve the
+        user names and send a comma (`,') separated list of user names
+        on the channel.  Server or router may resolve the names by sending
+        SILC_COMMAND_WHOIS commands.
+
+        If the requested channel is a private or secret channel, this
+        command must not send the list of users, as private and secret
+        channels cannot be seen by outside.  In this case the returned
+        name list may include a indication that the server could not 
+        resolve the names of the users on the channel.  Also, in this case
+        Client ID's or client modes are not sent either.
+
+        Reply messages to the command:
+
+        Max Arguments:  5
+            Arguments:  (1) <Status Payload>  (2) <Channel ID>
+                        (3) <name list>       (4) <Client ID list>
+                        (5) <client mode list>
+
+        This command replies with the Channel ID of the requested channel,
+        comma separated list of users on the channel and Client ID list
+        of the users on the list.  The Client ID list has Client ID's
+        of all users in the list.  First Client ID in the list must be
+        the Client ID of the first user in <name list>.  The <Client ID
+        list> is formed by adding Client ID's each after each.  Note that
+        the Client ID list is binary data and the length of each ID must
+        be snooped from the data.  The <client mode list> is formed by
+        adding client's user modes on the channel each after each (4 bytes 
+        each).
+
+        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 - 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
+5.3 SILC Command Status Types
+
+.ti 0
+5.3.1 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 of length.  Following diagram
+represents the Command Status Payload (field is always in MSB order).
+
+
+
+
+
+.in 21
+.nf
+                     1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        Status Message         |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+.in 3
+
+.ce
+Figure 6:  SILC Command Status Payload
+
+
+.in 6
+o Status Message (2 bytes) - Indicates the status message.
+  All Status messages are described in the next section.
+.in 3
+
+
+.ti 0
+5.3.2 SILC Command Status List
+
+Command Status messages are returned in the command reply messages
+to indicate whether the command were executed without errors.  If error
+has occured the status tells which error occured.  Status payload only
+sends numeric reply about the status.  Receiver of the payload must
+convert the numeric values into human readable error messages.  The
+list of status messages below has an example human readable error
+messages that client may display for the user.
+
+List of all defined command status messages following.
+
+.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.
+
+   3 - 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_TOO_MANY_TARGETS
+
+        "Duplicate recipients. No message delivered".  Message were
+        tried to be sent to recipient which has several occurrences in 
+        the recipient list.
+
+   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.
+
+   23   SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+
+        "No such Channel ID".  Channel ID provided does not exist.
+
+   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
+
+        "Your host is not among the privileged".  The client tried to
+        register on server that does not allow this host to connect.
+
+   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_SERVER_PRIV
+
+        "Permission denied. You are not server operator".  Command may
+        be executed only by server operator.
+
+   41   SILC_STATUS_ERR_NO_ROUTER_PRIV
+
+        "Permission denied. You are not SILC operator".  Command may be
+        executed only by router (SILC) operator.
+
+   42   SILC_STATUS_ERR_BAD_NICKNAME
+
+        "Bad nickname".  Nickname requested contained illegal characters
+        or were malformed.
+
+   43   SILC_STATUS_ERR_BAD_CHANNEL
+
+        "Bad channel name".  Channel requested contained illegal characters
+        or were malformed.
+
+   44   SILC_STATUS_ERR_AUTH_FAILED
+
+        "Authentication failed".  The authentication data sent as 
+        argument were wrong and thus authentication failed.
+.in 3
+
+
+.ti 0
+6 Security Considerations
+
+Security is central to the design of this protocol, and these security
+considerations permeate the specification.
+
+
+.ti 0
+7 References
+
+[SILC2]      Riikonen, P., "SILC Packet Protocol", Internet Draft,
+             June 2000.
+
+[SILC3]      Riikonen, P., "SILC Key Exchange and Authentication 
+             Protocols", Internet Draft, June 2000.
+
+[IRC]        Oikarinen, J., and Reed D., "Internet Relay Chat Protocol",
+             RFC 1459, May 1993.
+
+[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.
+
+
+
+.ti 0
+8 Author's Address
+
+.nf
+Pekka Riikonen
+Kasarmikatu 11 A4
+70110 Kuopio
+Finland
+
+EMail: priikone@poseidon.pspt.fi
+
+This Internet-Draft expires 6 Jun 2001 
index 64574a939901f8b53df840bf15ac574e4e737289..8dbe7ef97d0f005500431d46fee0b68cf349e386 100644 (file)
@@ -6,10 +6,10 @@
 # If the cipher is builtin the <module path> maybe omitted.
 #
 [cipher]
-twofish-cbc:/home/priikone/silc/lib/silcsim/modules/twofish.sim.so:16:16
-rc6-cbc:/home/priikone/silc/lib/silcsim/modules/rc6.sim.so:16:16
-mars-cbc:/home/priikone/silc/lib/silcsim/modules/mars.sim.so:16:16
-none:/home/priikone/silc/lib/silcsim/modules/none.sim.so:0:0
+twofish:../lib/silcsim/modules/twofish.sim.so:16:16
+rc6:../lib/silcsim/modules/rc6.sim.so:16:16
+mars:../lib/silcsim/modules/mars.sim.so:16:16
+none:../lib/silcsim/modules/none.sim.so:0:0
 
 #
 # Configured hash functions.
@@ -41,7 +41,7 @@ sha1::64:20
 # <auth type> maybe `passwd' or `pubkey'.
 #
 [connection]
-#lassi.kuo.fi.ssh.com:passwd::1333
+#lassi.kuo.fi.ssh.com:passwd::706
 
 #
 # Commands.  These are executed when SILC client is run.  Normal
index fd67a4c83190203c7ac5b6b869524544f7a747c1..18499cc4319bcd0a49e65bfdef4fd49f62e93143 100644 (file)
@@ -5,11 +5,11 @@
 #
 # If the cipher is builtin the <module path> maybe omitted.
 #
-[cipher]
-twofish-cbc:/home/priikone/silc/lib/silcsim/modules/twofish.sim.so:16:16
-rc6-cbc:/home/priikone/silc/lib/silcsim/modules/rc6.sim.so:16:16
-mars-cbc:/home/priikone/silc/lib/silcsim/modules/mars.sim.so:16:16
-none:/home/priikone/silc/lib/silcsim/modules/none.sim.so:0:0
+[Cipher]
+twofish:../lib/silcsim/modules/twofish.sim.so:16:16
+rc6:../lib/silcsim/modules/rc6.sim.so:16:16
+mars:../lib/silcsim/modules/mars.sim.so:16:16
+none:../lib/silcsim/modules/none.sim.so:0:0
 
 #
 # Configured hash functions.
@@ -18,7 +18,7 @@ none:/home/priikone/silc/lib/silcsim/modules/none.sim.so:0:0
 #
 # If the hash function is builtin the <module path> maybe omitted.
 #
-[hash]
+[HashFunction]
 md5::64:16
 sha1::64:20
 
@@ -29,7 +29,7 @@ sha1::64:20
 #
 # NOTE: <module path> must be omitted as PKCS cannot be modules currently.
 #
-#[pkcs]
+#[PKCS]
 #rsa::1024
 #dss::1024
 
@@ -47,7 +47,7 @@ Kuopio, Finland:Test Server:Pekka Riikonen:priikone@poseidon.pspt.fi
 # Format: +<server FQDN>:<server IP>:<geographic location>:<port>
 #
 [ServerInfo]
-lassi.kuo.fi.ssh.com:10.2.1.6:Kuopio, Finland:1333
+lassi.kuo.fi.ssh.com:10.2.1.6:Kuopio, Finland:706
 
 #
 # Listenning ports.
@@ -55,7 +55,7 @@ lassi.kuo.fi.ssh.com:10.2.1.6:Kuopio, Finland:1333
 # Format: <local IP/UNIX socket path>:<remote IP>:<port>
 #
 [ListenPort]
-10.2.1.6:10.2.1.6:1333
+10.2.1.6:10.2.1.6:706
 
 #
 # Log files.
@@ -115,7 +115,7 @@ infologfile:silcd.log:10000
 # Format: <remote host>:<auth method>:<auth data>:<port>:<version ID>:<vlass>
 #
 [ServerConnection]
-10.2.1.7:passwd:veryscret:1333:1:1
+10.2.1.7:passwd:veryscret:706:1:1
 
 #
 # Configured router connections.
@@ -128,7 +128,7 @@ infologfile:silcd.log:10000
 # Format: <remote host>:<auth method>:<auth data>:<port>:<version ID>:<class>
 #
 [RouterConnection]
-10.2.1.100:passwd:veryverysecret:1333:1:1
+#10.2.1.100:passwd:veryverysecret:706:1:1
 
 #
 # Denied connections.
diff --git a/includes/Makefile.in b/includes/Makefile.in
deleted file mode 100644 (file)
index 0b8bc33..0000000
+++ /dev/null
@@ -1,209 +0,0 @@
-# Makefile.in generated automatically by automake 1.3 from Makefile.am
-
-# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
-# This Makefile.in is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
-# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE.
-
-#
-#  Makefile.am
-#
-#  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
-#
-#  Copyright (C) 2000 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
-#  GNU General Public License for more details.
-#
-
-
-SHELL = /bin/sh
-
-srcdir = @srcdir@
-top_srcdir = @top_srcdir@
-VPATH = @srcdir@
-prefix = @prefix@
-exec_prefix = @exec_prefix@
-
-bindir = @bindir@
-sbindir = @sbindir@
-libexecdir = @libexecdir@
-datadir = @datadir@
-sysconfdir = @sysconfdir@
-sharedstatedir = @sharedstatedir@
-localstatedir = @localstatedir@
-libdir = @libdir@
-infodir = @infodir@
-mandir = @mandir@
-includedir = @includedir@
-oldincludedir = /usr/include
-
-DISTDIR =
-
-pkgdatadir = $(datadir)/@PACKAGE@
-pkglibdir = $(libdir)/@PACKAGE@
-pkgincludedir = $(includedir)/@PACKAGE@
-
-top_builddir = ..
-
-ACLOCAL = @ACLOCAL@
-AUTOCONF = @AUTOCONF@
-AUTOMAKE = @AUTOMAKE@
-AUTOHEADER = @AUTOHEADER@
-
-INSTALL = @INSTALL@
-INSTALL_PROGRAM = @INSTALL_PROGRAM@
-INSTALL_DATA = @INSTALL_DATA@
-INSTALL_SCRIPT = @INSTALL_SCRIPT@
-transform = @program_transform_name@
-
-NORMAL_INSTALL = :
-PRE_INSTALL = :
-POST_INSTALL = :
-NORMAL_UNINSTALL = :
-PRE_UNINSTALL = :
-POST_UNINSTALL = :
-build_alias = @build_alias@
-build_triplet = @build@
-host_alias = @host_alias@
-host_triplet = @host@
-target_alias = @target_alias@
-target_triplet = @target@
-CC = @CC@
-LN_S = @LN_S@
-MAKEINFO = @MAKEINFO@
-PACKAGE = @PACKAGE@
-RANLIB = @RANLIB@
-VERSION = @VERSION@
-
-AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
-
-EXTRA_DIST = *.h
-mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
-CONFIG_HEADER = silcdefs.h
-CONFIG_CLEAN_FILES = 
-DIST_COMMON =  Makefile.am Makefile.in silcdefs.h.in stamp-h.in
-
-
-DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
-
-TAR = tar
-GZIP = --best
-all: Makefile silcdefs.h
-
-.SUFFIXES:
-$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
-       cd $(top_srcdir) && $(AUTOMAKE) --foreign includes/Makefile
-
-Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
-       cd $(top_builddir) \
-         && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
-
-
-silcdefs.h: stamp-h
-       @:
-stamp-h: $(srcdir)/silcdefs.h.in $(top_builddir)/config.status
-       cd $(top_builddir) \
-         && CONFIG_FILES= CONFIG_HEADERS=includes/silcdefs.h \
-            $(SHELL) ./config.status
-       @echo timestamp > stamp-h
-$(srcdir)/silcdefs.h.in: $(srcdir)/stamp-h.in
-$(srcdir)/stamp-h.in: $(top_srcdir)/configure.in $(ACLOCAL_M4) 
-       cd $(top_srcdir) && $(AUTOHEADER)
-       @echo timestamp > $(srcdir)/stamp-h.in
-
-mostlyclean-hdr:
-
-clean-hdr:
-
-distclean-hdr:
-       -rm -f silcdefs.h
-
-maintainer-clean-hdr:
-tags: TAGS
-TAGS:
-
-
-distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
-
-subdir = includes
-
-distdir: $(DISTFILES)
-       @for file in $(DISTFILES); do \
-         d=$(srcdir); \
-         test -f $(distdir)/$$file \
-         || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
-         || cp -p $$d/$$file $(distdir)/$$file; \
-       done
-info:
-dvi:
-check: all
-       $(MAKE)
-installcheck:
-install-exec: 
-       @$(NORMAL_INSTALL)
-
-install-data: 
-       @$(NORMAL_INSTALL)
-
-install: install-exec install-data all
-       @:
-
-uninstall: 
-
-install-strip:
-       $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install
-installdirs:
-
-
-mostlyclean-generic:
-       -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
-
-clean-generic:
-       -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
-
-distclean-generic:
-       -rm -f Makefile $(DISTCLEANFILES)
-       -rm -f config.cache config.log stamp-h stamp-h[0-9]*
-       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-
-maintainer-clean-generic:
-       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
-       -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
-mostlyclean:  mostlyclean-hdr mostlyclean-generic
-
-clean:  clean-hdr clean-generic mostlyclean
-
-distclean:  distclean-hdr distclean-generic clean
-       -rm -f config.status
-
-maintainer-clean:  maintainer-clean-hdr maintainer-clean-generic \
-               distclean
-       @echo "This command is intended for maintainers to use;"
-       @echo "it deletes files that may require special tools to rebuild."
-
-.PHONY: mostlyclean-hdr distclean-hdr clean-hdr maintainer-clean-hdr \
-tags distdir info dvi installcheck install-exec install-data install \
-uninstall all installdirs mostlyclean-generic distclean-generic \
-clean-generic maintainer-clean-generic clean mostlyclean distclean \
-maintainer-clean
-
-
-all:
-       -cd ..
-
-# Tell versions [3.59,3.63) of GNU make to not export all variables.
-# Otherwise a system limit (for SysV at least) may be exceeded.
-.NOEXPORT:
index 479c000732249771b22daefaca7770e2cc3e44f5..d579b1276c8d304ad96dc2566454b10626802567 100644 (file)
 #ifndef CLIENTINCLUDES_H
 #define CLIENTINCLUDES_H
 
+#include "silcdefs.h"
+
 #include <curses.h>
-#include <paths.h>
 #include <sys/param.h>
 #include <pwd.h>
 
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+
 /* Generic includes */
 #include "silcincludes.h"
+#include "clientlibincludes.h"
 
 /* SILC Client includes */
-#include "idlist.h"
 #include "screen.h"
 #include "clientconfig.h"
-#include "client.h"
+#include "local_command.h"
 #include "clientutil.h"
-#include "protocol.h"
-#include "command.h"
-#include "command_reply.h"
 #include "silc.h"
+#include "client_ops.h"
 
 #endif
similarity index 62%
rename from lib/silccrypt/e2_internal.h
rename to includes/clientlibincludes.h
index 446b0a1bf21008142cde87aa587ee7efe9af770c..d0c3c9593a5f6f74fef57fe2a0f347817fc054af 100644 (file)
@@ -1,6 +1,6 @@
 /*
 
-  e2_internal.h
+  clientlibincludes.h
 
   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
 
 
 */
 
-#ifndef E2_INTERNAL_H
-#define E2_INTERNAL_H
+#ifndef CLIENTLIBINCLUDES_H
+#define CLIENTLIBINCLUDES_H
 
-typedef struct {
-  u4byte l_key[72];
-} E2Context;
+#include "silcdefs.h"
 
-/* Prototypes */
-u4byte *e2_set_key(E2Context *ctx,
-                  const u4byte in_key[], const u4byte key_len);
-void e2_encrypt(E2Context *ctx, const u4byte in_blk[4], u4byte out_blk[4]);
-void e2_decrypt(E2Context *ctx, const u4byte in_blk[4], u4byte out_blk[4]);
+/* Generic includes */
+#include "silcincludes.h"
+
+/* SILC Client includes */
+#include "client.h"
+#include "command.h"
+#include "command_reply.h"
+#include "idlist.h"
+#include "protocol.h"
+#include "ops.h"
 
 #endif
index 3c8eedf3b39f6d1c4bbb2c004ca4472e17dd9c07..988e83629866479a78a1db330ace4a2cdb486c64 100644 (file)
 
 /* SILC Server includes */
 #include "idlist.h"
-#include "route.h"
 #include "serverid.h"
 #include "serverconfig.h"
 #include "server.h"
+#include "route.h"
 #include "protocol.h"
 #include "command.h"
 #include "command_reply.h"
diff --git a/includes/silcdefs.h.in b/includes/silcdefs.h.in
deleted file mode 100644 (file)
index 61be749..0000000
+++ /dev/null
@@ -1,231 +0,0 @@
-/* includes/silcdefs.h.in.  Generated automatically from configure.in by autoheader.  */
-
-/* Define to empty if the keyword does not work.  */
-#undef const
-
-/* Define to `int' if <sys/types.h> doesn't define.  */
-#undef gid_t
-
-/* Define as __inline if that's what the C compiler calls it.  */
-#undef inline
-
-/* Define to `int' if <sys/types.h> doesn't define.  */
-#undef mode_t
-
-/* Define to `int' if <sys/types.h> doesn't define.  */
-#undef pid_t
-
-/* Define as the return type of signal handlers (int or void).  */
-#undef RETSIGTYPE
-
-/* Define to `unsigned' if <sys/types.h> doesn't define.  */
-#undef size_t
-
-/* Define if the `S_IS*' macros in <sys/stat.h> do not work properly.  */
-#undef STAT_MACROS_BROKEN
-
-/* Define if you have the ANSI C header files.  */
-#undef STDC_HEADERS
-
-/* Define if you can safely include both <sys/time.h> and <time.h>.  */
-#undef TIME_WITH_SYS_TIME
-
-/* Define to `int' if <sys/types.h> doesn't define.  */
-#undef uid_t
-
-/* Name of the package. */
-#undef PACKAGE
-
-/* Version of the package. */
-#undef VERSION
-
-/* Debugging */
-#undef SILC_DEBUG
-
-/* Default configuration file */
-#undef SILC_SERVER_CONFIG_FILE
-
-/* SIM (SILC Module) support */
-#undef SILC_SIM
-#undef HAVE_RTLD_NOW
-#undef HAVE_RTLD_LAZY
-
-/* Define if you have the bind function.  */
-#undef HAVE_BIND
-
-/* Define if you have the chmod function.  */
-#undef HAVE_CHMOD
-
-/* Define if you have the close function.  */
-#undef HAVE_CLOSE
-
-/* Define if you have the connect function.  */
-#undef HAVE_CONNECT
-
-/* Define if you have the ctime function.  */
-#undef HAVE_CTIME
-
-/* Define if you have the fcntl function.  */
-#undef HAVE_FCNTL
-
-/* Define if you have the fstat function.  */
-#undef HAVE_FSTAT
-
-/* Define if you have the getenv function.  */
-#undef HAVE_GETENV
-
-/* Define if you have the getgid function.  */
-#undef HAVE_GETGID
-
-/* Define if you have the gethostbyaddr function.  */
-#undef HAVE_GETHOSTBYADDR
-
-/* Define if you have the gethostbyname function.  */
-#undef HAVE_GETHOSTBYNAME
-
-/* Define if you have the gethostname function.  */
-#undef HAVE_GETHOSTNAME
-
-/* Define if you have the getopt_long function.  */
-#undef HAVE_GETOPT_LONG
-
-/* Define if you have the getpgid function.  */
-#undef HAVE_GETPGID
-
-/* Define if you have the getpgrp function.  */
-#undef HAVE_GETPGRP
-
-/* Define if you have the getpid function.  */
-#undef HAVE_GETPID
-
-/* Define if you have the getservbyname function.  */
-#undef HAVE_GETSERVBYNAME
-
-/* Define if you have the getservbyport function.  */
-#undef HAVE_GETSERVBYPORT
-
-/* Define if you have the getsid function.  */
-#undef HAVE_GETSID
-
-/* Define if you have the gettimeofday function.  */
-#undef HAVE_GETTIMEOFDAY
-
-/* Define if you have the getuid function.  */
-#undef HAVE_GETUID
-
-/* Define if you have the listen function.  */
-#undef HAVE_LISTEN
-
-/* Define if you have the memcpy function.  */
-#undef HAVE_MEMCPY
-
-/* Define if you have the memmove function.  */
-#undef HAVE_MEMMOVE
-
-/* Define if you have the memset function.  */
-#undef HAVE_MEMSET
-
-/* Define if you have the mlock function.  */
-#undef HAVE_MLOCK
-
-/* Define if you have the munlock function.  */
-#undef HAVE_MUNLOCK
-
-/* Define if you have the putenv function.  */
-#undef HAVE_PUTENV
-
-/* Define if you have the select function.  */
-#undef HAVE_SELECT
-
-/* Define if you have the setsockopt function.  */
-#undef HAVE_SETSOCKOPT
-
-/* Define if you have the shutdown function.  */
-#undef HAVE_SHUTDOWN
-
-/* Define if you have the socket function.  */
-#undef HAVE_SOCKET
-
-/* Define if you have the stat function.  */
-#undef HAVE_STAT
-
-/* Define if you have the strchr function.  */
-#undef HAVE_STRCHR
-
-/* Define if you have the strcpy function.  */
-#undef HAVE_STRCPY
-
-/* Define if you have the strerror function.  */
-#undef HAVE_STRERROR
-
-/* Define if you have the strncpy function.  */
-#undef HAVE_STRNCPY
-
-/* Define if you have the strstr function.  */
-#undef HAVE_STRSTR
-
-/* Define if you have the time function.  */
-#undef HAVE_TIME
-
-/* Define if you have the <arpa/inet.h> header file.  */
-#undef HAVE_ARPA_INET_H
-
-/* Define if you have the <assert.h> header file.  */
-#undef HAVE_ASSERT_H
-
-/* Define if you have the <ctype.h> header file.  */
-#undef HAVE_CTYPE_H
-
-/* Define if you have the <dlfcn.h> header file.  */
-#undef HAVE_DLFCN_H
-
-/* Define if you have the <errno.h> header file.  */
-#undef HAVE_ERRNO_H
-
-/* Define if you have the <fcntl.h> header file.  */
-#undef HAVE_FCNTL_H
-
-/* Define if you have the <getopt.h> header file.  */
-#undef HAVE_GETOPT_H
-
-/* Define if you have the <grp.h> header file.  */
-#undef HAVE_GRP_H
-
-/* Define if you have the <ncurses.h> header file.  */
-#undef HAVE_NCURSES_H
-
-/* Define if you have the <netdb.h> header file.  */
-#undef HAVE_NETDB_H
-
-/* Define if you have the <netinet/in.h> header file.  */
-#undef HAVE_NETINET_IN_H
-
-/* Define if you have the <netinet/tcp.h> header file.  */
-#undef HAVE_NETINET_TCP_H
-
-/* Define if you have the <pwd.h> header file.  */
-#undef HAVE_PWD_H
-
-/* Define if you have the <signal.h> header file.  */
-#undef HAVE_SIGNAL_H
-
-/* Define if you have the <string.h> header file.  */
-#undef HAVE_STRING_H
-
-/* Define if you have the <sys/mman.h> header file.  */
-#undef HAVE_SYS_MMAN_H
-
-/* Define if you have the <sys/stat.h> header file.  */
-#undef HAVE_SYS_STAT_H
-
-/* Define if you have the <sys/time.h> header file.  */
-#undef HAVE_SYS_TIME_H
-
-/* Define if you have the <sys/types.h> header file.  */
-#undef HAVE_SYS_TYPES_H
-
-/* Define if you have the <termcap.h> header file.  */
-#undef HAVE_TERMCAP_H
-
-/* Define if you have the <unistd.h> header file.  */
-#undef HAVE_UNISTD_H
index abb8b3f87a31e49af30b0f5d22d875a2b50e6381..92ba83273be470f11e85a6dbbb98ca8c1adfbc24 100644 (file)
 #include <sys/time.h>
 #include <sys/times.h>
 
+#ifdef SOCKS5
+#include "socks.h"
+#endif
+
 #ifdef HAVE_GETOPT_H
 #include <getopt.h>
-#else
-#error getopt.h not found in the system
 #endif
 
 #ifdef HAVE_SIGNAL_H
+#undef __USE_GNU
 #include <signal.h>
+#define __USE_GNU 1
 #else
 #error signal.h not found in the system
 #endif
 #include <dlfcn.h>
 #endif
 
+#ifndef HAVE_GETOPT_LONG
+#include "../lib/contrib/getopt.h"
+#endif
+
 #ifndef TRUE
 #define TRUE 1
 #endif
 /* Math library includes */
 #include "silcmp.h"
 #include "modinv.h"
+#include "mpbin.h"
 #include "silcprimegen.h"
 
 /* Crypto library includes */
 #include "silcrng.h"
 #include "silcpkcs.h"
 
-/* SILC core library includes */
+/* SILC util library includes */
 #include "silclog.h"
 #include "silcmemory.h"
 #include "silcbuffer.h"
 #include "silcnet.h"
 #include "silcutil.h"
 #include "silcconfig.h"
-#include "id.h"
-#include "idcache.h"
-#include "silcpacket.h"
 #include "silctask.h"
 #include "silcschedule.h"
+
+/* SILC core library includes */
+#include "id.h"
+#include "idcache.h"
 #include "silcprotocol.h"
+#include "silcsockconn.h"
+#include "silcpayload.h"
 #include "silccommand.h"
 #include "silcchannel.h"
-#include "silcsockconn.h"
+#include "silcpacket.h"
+#include "silcnotify.h"
+
+/* TRQ (SilcList API and SilcDList API) */
+#include "silclist.h"
+#include "silcdlist.h"
 
 #ifdef SILC_SIM
 /* SILC Module library includes */
 #include "groups.h"
 
 #endif
+
index e225709c4b79eef7b12b33f1980789411b19209a..a878e25df893552ac9e8997d8462d4090924a22b 100644 (file)
@@ -21,6 +21,8 @@
 #ifndef VERSION_H
 #define VERSION_H
 
+#include "version_internal.h"
+
 /* Version type definition */
 typedef unsigned char SilcVersion;
 
@@ -33,7 +35,8 @@ typedef unsigned char SilcVersion;
 #define SILC_VERSION_1 '\1'
 
 /* SILC version string */
-const char *silc_version = "27062000";
+const char *silc_version = SILC_VERSION_STRING;
+const char *silc_version_string = SILC_PROTOCOL_VERSION_STRING;
 const char *silc_name = "SILC";
 const char *silc_fullname = "Secure Internet Live Conferencing";
 
index 66c6682a79b4e42dcdce880775223b23cd5310c5..b755b781fb57cb60e74565ca916154c28320677c 100644 (file)
 AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
 
 SUBDIRS = \
+       contrib \
        silccore \
        silccrypt \
        silcsim \
        silcmath \
-       silcske
+       silcske \
+       silcutil \
+       silcclient \
+       trq
 #        zlib
 
-CLEANFILES = libsilc.a
-DISTCLEANFILES = libsilc.a
+# SILC Library dirs
+SILCLIB_DIRS = \
+       contrib \
+       silccore \
+       silccrypt \
+       silcsim \
+       silcmath \
+       silcske \
+       silcutil \
+       trq
+
+# SILC Client Library dirs
+SILCCLIENTLIB_DIRS = \
+       silcclient
 
-all:   libsilc.a
+CLEANFILES = libsilc.a libsilcclient.a
+DISTCLEANFILES = libsilc.a libsilcclient.a
+
+all:  remove libsilc.a libsilcclient.a
+
+remove:
+       -rm -rf libsilc.a
+       -rm -rf libsilcclient.a
 
 libsilc.a:
-       find . -type f -name *.o | xargs $(AR) cru libsilc.a
+       find $(SILCLIB_DIRS) -type f -name *.o | xargs $(AR) cru libsilc.a
        ranlib libsilc.a
+
+libsilcclient.a:
+       find $(SILCCLIENTLIB_DIRS) -type f -name *.o | xargs $(AR) cru libsilcclient.a
+       ranlib libsilcclient.a
+
diff --git a/lib/contrib/Makefile.am b/lib/contrib/Makefile.am
new file mode 100644 (file)
index 0000000..516e97b
--- /dev/null
@@ -0,0 +1,31 @@
+#
+#  Makefile.am
+#
+#  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+#  Copyright (C) 2000 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
+#  GNU General Public License for more details.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+noinst_LIBRARIES = libcontrib.a
+
+libcontrib_a_SOURCES = \
+       getopt.c \
+       getopt1.c
+
+EXTRA_DIST = *.h
+
+INCLUDES = -I. -I.. -I../silccrypt -I../silcmath -I../silcske \
+       -I../silcsim -I../.. -I../../includes -I../silccore -I../silcutil \
+       -I../silcmath/gmp -I../trq
diff --git a/lib/contrib/getopt.c b/lib/contrib/getopt.c
new file mode 100644 (file)
index 0000000..1378a22
--- /dev/null
@@ -0,0 +1,747 @@
+/* Getopt for GNU.
+   NOTE: getopt is now part of the C library, so if you don't know what
+   "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
+   before changing it!
+
+   Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+       Free Software Foundation, Inc.
+
+   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, or (at your option) any
+   later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+\f
+
+#ifndef __STDC__
+/* This is a separate conditional since some stdc systems
+   reject `defined (const)'.  */
+#ifndef const
+#define const
+#endif
+#endif
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.  */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef __GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+   contain conflicting prototypes for getopt.  */
+#include <stdlib.h>
+#endif /* GNU C library.  */
+
+/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
+   long-named option.  Because this is not POSIX.2 compliant, it is
+   being phased out.  */
+/* #define GETOPT_COMPAT */
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+   but it behaves differently for the user, since it allows the user
+   to intersperse the options with the other arguments.
+
+   As `getopt' works, it permutes the elements of ARGV so that,
+   when it is done, all the options precede everything else.  Thus
+   all application programs are extended to handle flexible argument order.
+
+   Setting the environment variable POSIXLY_CORRECT disables permutation.
+   Then the behavior is completely standard.
+
+   GNU application programs can use a third alternative mode in which
+   they can distinguish the relative order of options and other arguments.  */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+char *optarg = 0;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns EOF, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+/* XXX 1003.2 says this must be 1 before any call.  */
+int optind = 0;
+
+/* The next char to be scanned in the option-element
+   in which the last option character we returned was found.
+   This allows us to pick up the scan where we left off.
+
+   If this is zero, or a null string, it means resume the scan
+   by advancing to the next ARGV-element.  */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+   for unrecognized options.  */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+   This must be initialized on some systems to avoid linking in the
+   system's own getopt implementation.  */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+   If the caller did not specify anything,
+   the default is REQUIRE_ORDER if the environment variable
+   POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+   REQUIRE_ORDER means don't recognize them as options;
+   stop option processing when the first non-option is seen.
+   This is what Unix does.
+   This mode of operation is selected by either setting the environment
+   variable POSIXLY_CORRECT, or using `+' as the first character
+   of the list of option characters.
+
+   PERMUTE is the default.  We permute the contents of ARGV as we scan,
+   so that eventually all the non-options are at the end.  This allows options
+   to be given in any order, even with programs that were not written to
+   expect this.
+
+   RETURN_IN_ORDER is an option available to programs that were written
+   to expect options and other ARGV-elements in any order and that care about
+   the ordering of the two.  We describe each non-option ARGV-element
+   as if it were the argument of an option with character code 1.
+   Using `-' as the first character of the list of option characters
+   selects this mode of operation.
+
+   The special argument `--' forces an end of option-scanning regardless
+   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
+   `--' can cause `getopt' to return EOF with `optind' != ARGC.  */
+
+static enum
+{
+  REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+\f
+#ifdef __GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+   because there are many ways it can cause trouble.
+   On some systems, it contains special magic macros that don't work
+   in GCC.  */
+#include <string.h>
+#define        my_index        strchr
+#else
+
+/* Avoid depending on library functions or files
+   whose names are inconsistent.  */
+
+char *getenv ();
+
+static char *
+my_index (str, chr)
+     const char *str;
+     int chr;
+{
+  while (*str)
+    {
+      if (*str == chr)
+       return (char *) str;
+      str++;
+    }
+  return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+   If not using GCC, it is ok not to declare it.
+   (Supposedly there are some machines where it might get a warning,
+   but changing this conditional to __STDC__ is too risky.)  */
+#ifdef __GNUC__
+#ifdef IN_GCC
+#include "gstddef.h"
+#else
+#include <stddef.h>
+#endif
+extern size_t strlen (const char *);
+#endif
+
+#endif                         /* GNU C library.  */
+\f
+/* Handle permutation of arguments.  */
+
+/* Describe the part of ARGV that contains non-options that have
+   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
+   `last_nonopt' is the index after the last of them.  */
+
+static int first_nonopt;
+static int last_nonopt;
+
+/* Exchange two adjacent subsequences of ARGV.
+   One subsequence is elements [first_nonopt,last_nonopt)
+   which contains all the non-options that have been skipped so far.
+   The other is elements [last_nonopt,optind), which contains all
+   the options processed since those non-options were skipped.
+
+   `first_nonopt' and `last_nonopt' are relocated so that they describe
+   the new indices of the non-options in ARGV after they are moved.  */
+
+static void
+exchange (argv)
+     char **argv;
+{
+  int bottom = first_nonopt;
+  int middle = last_nonopt;
+  int top = optind;
+  char *tem;
+
+  /* Exchange the shorter segment with the far end of the longer segment.
+     That puts the shorter segment into the right place.
+     It leaves the longer segment in the right place overall,
+     but it consists of two parts that need to be swapped next.  */
+
+  while (top > middle && middle > bottom)
+    {
+      if (top - middle > middle - bottom)
+       {
+         /* Bottom segment is the short one.  */
+         int len = middle - bottom;
+         register int i;
+
+         /* Swap it with the top part of the top segment.  */
+         for (i = 0; i < len; i++)
+           {
+             tem = argv[bottom + i];
+             argv[bottom + i] = argv[top - (middle - bottom) + i];
+             argv[top - (middle - bottom) + i] = tem;
+           }
+         /* Exclude the moved bottom segment from further swapping.  */
+         top -= len;
+       }
+      else
+       {
+         /* Top segment is the short one.  */
+         int len = top - middle;
+         register int i;
+
+         /* Swap it with the bottom part of the bottom segment.  */
+         for (i = 0; i < len; i++)
+           {
+             tem = argv[bottom + i];
+             argv[bottom + i] = argv[middle + i];
+             argv[middle + i] = tem;
+           }
+         /* Exclude the moved top segment from further swapping.  */
+         bottom += len;
+       }
+    }
+
+  /* Update records for the slots the non-options now occupy.  */
+
+  first_nonopt += (optind - last_nonopt);
+  last_nonopt = optind;
+}
+\f
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+   given in OPTSTRING.
+
+   If an element of ARGV starts with '-', and is not exactly "-" or "--",
+   then it is an option element.  The characters of this element
+   (aside from the initial '-') are option characters.  If `getopt'
+   is called repeatedly, it returns successively each of the option characters
+   from each of the option elements.
+
+   If `getopt' finds another option character, it returns that character,
+   updating `optind' and `nextchar' so that the next call to `getopt' can
+   resume the scan with the following option character or ARGV-element.
+
+   If there are no more option characters, `getopt' returns `EOF'.
+   Then `optind' is the index in ARGV of the first ARGV-element
+   that is not an option.  (The ARGV-elements have been permuted
+   so that those that are not options now come last.)
+
+   OPTSTRING is a string containing the legitimate option characters.
+   If an option character is seen that is not listed in OPTSTRING,
+   return '?' after printing an error message.  If you set `opterr' to
+   zero, the error message is suppressed but we still return '?'.
+
+   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+   so the following text in the same ARGV-element, or the text of the following
+   ARGV-element, is returned in `optarg'.  Two colons mean an option that
+   wants an optional arg; if there is text in the current ARGV-element,
+   it is returned in `optarg', otherwise `optarg' is set to zero.
+
+   If OPTSTRING starts with `-' or `+', it requests different methods of
+   handling the non-option ARGV-elements.
+   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+   Long-named options begin with `--' instead of `-'.
+   Their names may be abbreviated as long as the abbreviation is unique
+   or is an exact match for some defined option.  If they have an
+   argument, it follows the option name in the same ARGV-element, separated
+   from the option name by a `=', or else the in next ARGV-element.
+   When `getopt' finds a long-named option, it returns 0 if that option's
+   `flag' field is nonzero, the value of the option's `val' field
+   if the `flag' field is zero.
+
+   The elements of ARGV aren't really const, because we permute them.
+   But we pretend they're const in the prototype to be compatible
+   with other systems.
+
+   LONGOPTS is a vector of `struct option' terminated by an
+   element containing a name which is zero.
+
+   LONGIND returns the index in LONGOPT of the long-named option found.
+   It is only valid when a long-named option has been found by the most
+   recent call.
+
+   If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+   long-named options.  */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+     const struct option *longopts;
+     int *longind;
+     int long_only;
+{
+  int option_index;
+
+  optarg = 0;
+
+  /* Initialize the internal data when the first call is made.
+     Start processing options with ARGV-element 1 (since ARGV-element 0
+     is the program name); the sequence of previously skipped
+     non-option ARGV-elements is empty.  */
+
+  if (optind == 0)
+    {
+      first_nonopt = last_nonopt = optind = 1;
+
+      nextchar = NULL;
+
+      /* Determine how to handle the ordering of options and nonoptions.  */
+
+      if (optstring[0] == '-')
+       {
+         ordering = RETURN_IN_ORDER;
+         ++optstring;
+       }
+      else if (optstring[0] == '+')
+       {
+         ordering = REQUIRE_ORDER;
+         ++optstring;
+       }
+      else if (getenv ("POSIXLY_CORRECT") != NULL)
+       ordering = REQUIRE_ORDER;
+      else
+       ordering = PERMUTE;
+    }
+
+  if (nextchar == NULL || *nextchar == '\0')
+    {
+      if (ordering == PERMUTE)
+       {
+         /* If we have just processed some options following some non-options,
+            exchange them so that the options come first.  */
+
+         if (first_nonopt != last_nonopt && last_nonopt != optind)
+           exchange ((char **) argv);
+         else if (last_nonopt != optind)
+           first_nonopt = optind;
+
+         /* Now skip any additional non-options
+            and extend the range of non-options previously skipped.  */
+
+         while (optind < argc
+                && (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+                && (longopts == NULL
+                    || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif                         /* GETOPT_COMPAT */
+                )
+           optind++;
+         last_nonopt = optind;
+       }
+
+      /* Special ARGV-element `--' means premature end of options.
+        Skip it like a null option,
+        then exchange with previous non-options as if it were an option,
+        then skip everything else like a non-option.  */
+
+      if (optind != argc && !strcmp (argv[optind], "--"))
+       {
+         optind++;
+
+         if (first_nonopt != last_nonopt && last_nonopt != optind)
+           exchange ((char **) argv);
+         else if (first_nonopt == last_nonopt)
+           first_nonopt = optind;
+         last_nonopt = argc;
+
+         optind = argc;
+       }
+
+      /* If we have done all the ARGV-elements, stop the scan
+        and back over any non-options that we skipped and permuted.  */
+
+      if (optind == argc)
+       {
+         /* Set the next-arg-index to point at the non-options
+            that we previously skipped, so the caller will digest them.  */
+         if (first_nonopt != last_nonopt)
+           optind = first_nonopt;
+         return EOF;
+       }
+
+      /* If we have come to a non-option and did not permute it,
+        either stop the scan or describe it to the caller and pass it by.  */
+
+      if ((argv[optind][0] != '-' || argv[optind][1] == '\0')
+#ifdef GETOPT_COMPAT
+         && (longopts == NULL
+             || argv[optind][0] != '+' || argv[optind][1] == '\0')
+#endif                         /* GETOPT_COMPAT */
+         )
+       {
+         if (ordering == REQUIRE_ORDER)
+           return EOF;
+         optarg = argv[optind++];
+         return 1;
+       }
+
+      /* We have found another option-ARGV-element.
+        Start decoding its characters.  */
+
+      nextchar = (argv[optind] + 1
+                 + (longopts != NULL && argv[optind][1] == '-'));
+    }
+
+  if (longopts != NULL
+      && ((argv[optind][0] == '-'
+          && (argv[optind][1] == '-' || long_only))
+#ifdef GETOPT_COMPAT
+         || argv[optind][0] == '+'
+#endif                         /* GETOPT_COMPAT */
+         ))
+    {
+      const struct option *p;
+      char *s = nextchar;
+      int exact = 0;
+      int ambig = 0;
+      const struct option *pfound = NULL;
+      int indfound;
+
+      while (*s && *s != '=')
+       s++;
+
+      /* Test all options for either exact match or abbreviated matches.  */
+      for (p = longopts, option_index = 0; p->name;
+          p++, option_index++)
+       if (!strncmp (p->name, nextchar, s - nextchar))
+         {
+           if (s - nextchar == strlen (p->name))
+             {
+               /* Exact match found.  */
+               pfound = p;
+               indfound = option_index;
+               exact = 1;
+               break;
+             }
+           else if (pfound == NULL)
+             {
+               /* First nonexact match found.  */
+               pfound = p;
+               indfound = option_index;
+             }
+           else
+             /* Second nonexact match found.  */
+             ambig = 1;
+         }
+
+      if (ambig && !exact)
+       {
+         if (opterr)
+           fprintf (stderr, "%s: option `%s' is ambiguous\n",
+                    argv[0], argv[optind]);
+         nextchar += strlen (nextchar);
+         optind++;
+         return '?';
+       }
+
+      if (pfound != NULL)
+       {
+         option_index = indfound;
+         optind++;
+         if (*s)
+           {
+             /* Don't test has_arg with >, because some C compilers don't
+                allow it to be used on enums.  */
+             if (pfound->has_arg)
+               optarg = s + 1;
+             else
+               {
+                 if (opterr)
+                   {
+                     if (argv[optind - 1][1] == '-')
+                       /* --option */
+                       fprintf (stderr,
+                                "%s: option `--%s' doesn't allow an argument\n",
+                                argv[0], pfound->name);
+                     else
+                       /* +option or -option */
+                       fprintf (stderr,
+                            "%s: option `%c%s' doesn't allow an argument\n",
+                            argv[0], argv[optind - 1][0], pfound->name);
+                   }
+                 nextchar += strlen (nextchar);
+                 return '?';
+               }
+           }
+         else if (pfound->has_arg == 1)
+           {
+             if (optind < argc)
+               optarg = argv[optind++];
+             else
+               {
+                 if (opterr)
+                   fprintf (stderr, "%s: option `%s' requires an argument\n",
+                            argv[0], argv[optind - 1]);
+                 nextchar += strlen (nextchar);
+                 return optstring[0] == ':' ? ':' : '?';
+               }
+           }
+         nextchar += strlen (nextchar);
+         if (longind != NULL)
+           *longind = option_index;
+         if (pfound->flag)
+           {
+             *(pfound->flag) = pfound->val;
+             return 0;
+           }
+         return pfound->val;
+       }
+      /* Can't find it as a long option.  If this is not getopt_long_only,
+        or the option starts with '--' or is not a valid short
+        option, then it's an error.
+        Otherwise interpret it as a short option.  */
+      if (!long_only || argv[optind][1] == '-'
+#ifdef GETOPT_COMPAT
+         || argv[optind][0] == '+'
+#endif                         /* GETOPT_COMPAT */
+         || my_index (optstring, *nextchar) == NULL)
+       {
+         if (opterr)
+           {
+             if (argv[optind][1] == '-')
+               /* --option */
+               fprintf (stderr, "%s: unrecognized option `--%s'\n",
+                        argv[0], nextchar);
+             else
+               /* +option or -option */
+               fprintf (stderr, "%s: unrecognized option `%c%s'\n",
+                        argv[0], argv[optind][0], nextchar);
+           }
+         nextchar = (char *) "";
+         optind++;
+         return '?';
+       }
+    }
+
+  /* Look at and handle the next option-character.  */
+
+  {
+    char c = *nextchar++;
+    char *temp = my_index (optstring, c);
+
+    /* Increment `optind' when we start to process its last character.  */
+    if (*nextchar == '\0')
+      ++optind;
+
+    if (temp == NULL || c == ':')
+      {
+       if (opterr)
+         {
+#if 0
+           if (c < 040 || c >= 0177)
+             fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
+                      argv[0], c);
+           else
+             fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
+#else
+           /* 1003.2 specifies the format of this message.  */
+           fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
+#endif
+         }
+       optopt = c;
+       return '?';
+      }
+    if (temp[1] == ':')
+      {
+       if (temp[2] == ':')
+         {
+           /* This is an option that accepts an argument optionally.  */
+           if (*nextchar != '\0')
+             {
+               optarg = nextchar;
+               optind++;
+             }
+           else
+             optarg = 0;
+           nextchar = NULL;
+         }
+       else
+         {
+           /* This is an option that requires an argument.  */
+           if (*nextchar != '\0')
+             {
+               optarg = nextchar;
+               /* If we end this ARGV-element by taking the rest as an arg,
+                  we must advance to the next element now.  */
+               optind++;
+             }
+           else if (optind == argc)
+             {
+               if (opterr)
+                 {
+#if 0
+                   fprintf (stderr, "%s: option `-%c' requires an argument\n",
+                            argv[0], c);
+#else
+                   /* 1003.2 specifies the format of this message.  */
+                   fprintf (stderr, "%s: option requires an argument -- %c\n",
+                            argv[0], c);
+#endif
+                 }
+               optopt = c;
+               if (optstring[0] == ':')
+                 c = ':';
+               else
+                 c = '?';
+             }
+           else
+             /* We already incremented `optind' once;
+                increment it again when taking next ARGV-elt as argument.  */
+             optarg = argv[optind++];
+           nextchar = NULL;
+         }
+      }
+    return c;
+  }
+}
+
+int
+getopt (argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+  return _getopt_internal (argc, argv, optstring,
+                          (const struct option *) 0,
+                          (int *) 0,
+                          0);
+}
+
+#endif /* _LIBC or not __GNU_LIBRARY__.  */
+\f
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+   the above definition of `getopt'.  */
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = optind ? optind : 1;
+
+      c = getopt (argc, argv, "abc:d:0123456789");
+      if (c == EOF)
+       break;
+
+      switch (c)
+       {
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+         if (digit_optind != 0 && digit_optind != this_option_optind)
+           printf ("digits occur in two different argv-elements.\n");
+         digit_optind = this_option_optind;
+         printf ("option %c\n", c);
+         break;
+
+       case 'a':
+         printf ("option a\n");
+         break;
+
+       case 'b':
+         printf ("option b\n");
+         break;
+
+       case 'c':
+         printf ("option c with value `%s'\n", optarg);
+         break;
+
+       case '?':
+         break;
+
+       default:
+         printf ("?? getopt returned character code 0%o ??\n", c);
+       }
+    }
+
+  if (optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (optind < argc)
+       printf ("%s ", argv[optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
diff --git a/lib/contrib/getopt.h b/lib/contrib/getopt.h
new file mode 100644 (file)
index 0000000..45541f5
--- /dev/null
@@ -0,0 +1,129 @@
+/* Declarations for getopt.
+   Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+   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, or (at your option) any
+   later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns EOF, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+   for unrecognized options.  */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized.  */
+
+extern int optopt;
+
+/* Describe the long-named options requested by the application.
+   The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+   of `struct option' terminated by an element containing a name which is
+   zero.
+
+   The field `has_arg' is:
+   no_argument         (or 0) if the option does not take an argument,
+   required_argument   (or 1) if the option requires an argument,
+   optional_argument   (or 2) if the option takes an optional argument.
+
+   If the field `flag' is not NULL, it points to a variable that is set
+   to the value given in the field `val' when the option is found, but
+   left unchanged if the option is not found.
+
+   To have a long-named option do something other than set an `int' to
+   a compiled-in constant, such as set a value from `optarg', set the
+   option's `flag' field to zero and its `val' field to a nonzero
+   value (the equivalent single-letter option character, if there is
+   one).  For long options that have a zero `flag' field, `getopt'
+   returns the contents of the `val' field.  */
+
+struct option
+{
+#if    __STDC__
+  const char *name;
+#else
+  char *name;
+#endif
+  /* has_arg can't be an enum because some compilers complain about
+     type mismatches in all the code that assumes it is an int.  */
+  int has_arg;
+  int *flag;
+  int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'.  */
+
+#define        no_argument             0
+#define required_argument      1
+#define optional_argument      2
+
+#if __STDC__
+#if defined(__GNU_LIBRARY__)
+/* Many other libraries have conflicting prototypes for getopt, with
+   differences in the consts, in stdlib.h.  To avoid compilation
+   errors, only prototype getopt for the GNU C library.  */
+extern int getopt (int argc, char *const *argv, const char *shortopts);
+#else /* not __GNU_LIBRARY__ */
+extern int getopt ();
+#endif /* not __GNU_LIBRARY__ */
+extern int getopt_long (int argc, char *const *argv, const char *shortopts,
+                       const struct option *longopts, int *longind);
+extern int getopt_long_only (int argc, char *const *argv,
+                            const char *shortopts,
+                            const struct option *longopts, int *longind);
+
+/* Internal only.  Users should not call this directly.  */
+extern int _getopt_internal (int argc, char *const *argv,
+                            const char *shortopts,
+                            const struct option *longopts, int *longind,
+                            int long_only);
+#else /* not __STDC__ */
+extern int getopt ();
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+#endif /* not __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GETOPT_H */
diff --git a/lib/contrib/getopt1.c b/lib/contrib/getopt1.c
new file mode 100644 (file)
index 0000000..fe6bdd9
--- /dev/null
@@ -0,0 +1,177 @@
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+   Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
+       Free Software Foundation, Inc.
+
+   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, or (at your option) any
+   later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+\f
+
+#include "getopt.h"
+
+#ifndef __STDC__
+/* This is a separate conditional since some stdc systems
+   reject `defined (const)'.  */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef __GNU_LIBRARY__
+#include <stdlib.h>
+#else
+char *getenv ();
+#endif
+
+#ifndef        NULL
+#define NULL 0
+#endif
+
+int
+getopt_long (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+  return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+   If an option that starts with '-' (not '--') doesn't match a long option,
+   but does match a short option, it is parsed as a short option
+   instead.  */
+
+int
+getopt_long_only (argc, argv, options, long_options, opt_index)
+     int argc;
+     char *const *argv;
+     const char *options;
+     const struct option *long_options;
+     int *opt_index;
+{
+  return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+
+#endif /* _LIBC or not __GNU_LIBRARY__.  */
+\f
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = optind ? optind : 1;
+      int option_index = 0;
+      static struct option long_options[] =
+      {
+       {"add", 1, 0, 0},
+       {"append", 0, 0, 0},
+       {"delete", 1, 0, 0},
+       {"verbose", 0, 0, 0},
+       {"create", 0, 0, 0},
+       {"file", 1, 0, 0},
+       {0, 0, 0, 0}
+      };
+
+      c = getopt_long (argc, argv, "abc:d:0123456789",
+                      long_options, &option_index);
+      if (c == EOF)
+       break;
+
+      switch (c)
+       {
+       case 0:
+         printf ("option %s", long_options[option_index].name);
+         if (optarg)
+           printf (" with arg %s", optarg);
+         printf ("\n");
+         break;
+
+       case '0':
+       case '1':
+       case '2':
+       case '3':
+       case '4':
+       case '5':
+       case '6':
+       case '7':
+       case '8':
+       case '9':
+         if (digit_optind != 0 && digit_optind != this_option_optind)
+           printf ("digits occur in two different argv-elements.\n");
+         digit_optind = this_option_optind;
+         printf ("option %c\n", c);
+         break;
+
+       case 'a':
+         printf ("option a\n");
+         break;
+
+       case 'b':
+         printf ("option b\n");
+         break;
+
+       case 'c':
+         printf ("option c with value `%s'\n", optarg);
+         break;
+
+       case 'd':
+         printf ("option d with value `%s'\n", optarg);
+         break;
+
+       case '?':
+         break;
+
+       default:
+         printf ("?? getopt returned character code 0%o ??\n", c);
+       }
+    }
+
+  if (optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (optind < argc)
+       printf ("%s ", argv[optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
diff --git a/lib/silcclient/Makefile.am b/lib/silcclient/Makefile.am
new file mode 100644 (file)
index 0000000..07df388
--- /dev/null
@@ -0,0 +1,35 @@
+#
+#  Makefile.am
+#
+#  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+#  Copyright (C) 2000 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
+#  GNU General Public License for more details.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+noinst_LIBRARIES = libsilcclient.a
+
+libsilcclient_a_SOURCES = \
+       client.c \
+       command.c \
+       command_reply.c \
+       idlist.c \
+       protocol.c
+
+EXTRA_DIST = *.h
+
+INCLUDES = -I. -I.. -I../silccore -I../silccrypt -I../silcutil \
+       -I../silcmath -I../silcske -I../silcsim \
+       -I../../includes \
+       -I../silcmath/gmp -I../trq
diff --git a/lib/silcclient/README b/lib/silcclient/README
new file mode 100644 (file)
index 0000000..cdd1011
--- /dev/null
@@ -0,0 +1,141 @@
+SILC Client Library
+===================
+
+This directory includes the SILC Client implementation.  The library uses
+common and core components of SILC protocol from lib/silccore library and
+normal utility routines from lib/silcutil library.  The library has been
+designed to be complete SILC Client implementation without actual user
+interface.  The library provides API for the application which can use
+it to implement generally what ever user interface it wants.
+
+The `ops.h' file defines the function prototypes that application must
+implement in order to be able to create the user interface with the
+library.  The idea is that the application can implement what ever user
+interface routines in the functions and display the data what ever way
+it wants.  The library is entirely transparent to the user interface and
+it does not include any user interface specific issues such as window
+handling or item handling on the screen etc.  These does not interest
+the library.
+
+
+
+Creating Client
+===============
+
+The client is context or entity based (which ever) thus several client
+entitites can be created in the application if needed.  However, it should
+be noted that they are completely independent from each other and can
+be seen as different applications.  Usually only one client entity is
+needed per application.
+
+The client object is SilcClient which is usually allocated in following
+manner:
+
+       SilcClient client = silc_client_alloc(&ops, context);
+
+`ops' is the static structure of client operations that library will call.
+`context' can be some application specific context that will be saved into
+the SilcClient object.  It is up to the caller to free this context.
+SilcClient is always passed to the application thus the application specific
+context can be retrieved from the SilcClient object.  See `client.h' file
+for detailed definition of SilcClient object.
+
+`ops' can be defined for example as follows:
+
+SilcClientOperations ops = {
+  say:                  silc_say,
+  channel_message:      silc_channel_message,
+  private_message:      silc_private_message,
+  notify:               silc_notify,
+  command:              silc_command,
+  command_reply:        silc_command_reply,
+  connect:              silc_connect,
+  disconnect:           silc_disconnect,
+  get_auth_method:      silc_get_auth_method,
+  verify_server_key:    silc_verify_server_key,
+  ask_passphrase:       silc_ask_passphrase,
+};
+
+
+Initializing the Client
+=======================
+
+The client must be initialized before running.  However, there are also
+some other tasks that must be done before initializing the client.  Following
+pointers must be set before calling the initializing function:
+
+       client->username
+       client->hostname
+       client->realname
+       client->pkcs
+       client->public_key
+       client->private_key
+
+After setting the pointers one must call:
+
+       silc_client_init(client);
+
+which then initializes the client library for the `client'.  If the pointers
+mentioned above are not initialized the silc_client_init will fail.
+
+
+Running the Client
+==================
+
+The client is run by calling silc_client_run.  The function will call
+the scheduler from utility library that will be run until the program is
+ended.  When silc_client_run returns the application is ended.  Thus,
+to run the client, call:
+
+       silc_client_run(client);
+
+Usually application may do some other initializations before calling
+this function.  For example before calling this function application should
+initialize the user interface.
+
+
+Creating Connection to Server
+=============================
+
+Connection to remote SILC server is done by calling:
+
+       silc_client_connect_to_server(client, port, hostname, context);
+
+The function will create the connection asynchronously to the server, ie.
+the function will return before the actual connection is created.  After
+the connection is created the client->ops->connect operation is called.
+
+Generally speaking the connections are associated with windows' on the
+screen.  IRC is usually implemented this way, however it is not the necessary
+way to associate the client's connections.  SilcClientConnection object
+is provided by the library (and is always passed to the application) that
+can be used in the application to associate the connection from the library.
+Application specific context can be saved to the SilcClientConnection object
+which then can be retrieved in the application, thus perhaps associate
+the connection with what ever object in the application (window or something
+else).
+
+
+Using Own Connecting
+====================
+
+Application might not want to use silc_client_connect_to_server function
+if it wants to perform its own connecting for some reason.  In this case
+application must call function silc_client_start_key_exchange after it
+has created the connection by itself.  This function starts key exhange
+protocol between the client and server and the library takes care of
+everything after that.
+
+After connection has been created application must call:
+
+       SilcClientConnection conn;
+
+       /* Add new connection to client */
+       conn = silc_client_add_connection(client, hostname, port, context);
+
+       /* Start key exchange and let the library handle everything
+          after this point on. */
+       silc_client_start_key_exchange(client, conn, sock);
+
+These calls are performed only and only if application did not call
+silc_client_connect_to_server function.
diff --git a/lib/silcclient/client.c b/lib/silcclient/client.c
new file mode 100644 (file)
index 0000000..44659ad
--- /dev/null
@@ -0,0 +1,2158 @@
+/*
+
+  client.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 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
+  GNU General Public License for more details.
+
+*/
+/* $Id$ */
+
+#include "clientlibincludes.h"
+
+/* Static task callback prototypes */
+SILC_TASK_CALLBACK(silc_client_connect_to_server_start);
+SILC_TASK_CALLBACK(silc_client_connect_to_server_second);
+SILC_TASK_CALLBACK(silc_client_connect_to_server_final);
+SILC_TASK_CALLBACK(silc_client_packet_process);
+SILC_TASK_CALLBACK(silc_client_packet_parse_real);
+
+static void silc_client_packet_parse(SilcPacketParserContext *parser_context);
+static void silc_client_packet_parse_type(SilcClient client, 
+                                         SilcSocketConnection sock,
+                                         SilcPacketContext *packet);
+
+/* Allocates new client object. This has to be done before client may
+   work. After calling this one must call silc_client_init to initialize
+   the client. The `application' is application specific user data pointer
+   and caller must free it. */
+
+SilcClient silc_client_alloc(SilcClientOperations *ops, void *application)
+{
+  SilcClient new_client;
+
+  new_client = silc_calloc(1, sizeof(*new_client));
+  new_client->application = application;
+  new_client->ops = ops;
+
+  return new_client;
+}
+
+/* Free's client object */
+
+void silc_client_free(SilcClient client)
+{
+  if (client) {
+    silc_free(client);
+  }
+}
+
+/* Initializes the client. This makes all the necessary steps to make
+   the client ready to be run. One must call silc_client_run to run the
+   client. */
+
+int silc_client_init(SilcClient client)
+{
+  SILC_LOG_DEBUG(("Initializing client"));
+
+  /* Initialize hash functions for client to use */
+  silc_hash_alloc("md5", &client->md5hash);
+  silc_hash_alloc("sha1", &client->sha1hash);
+
+  /* Initialize none cipher */
+  silc_cipher_alloc("none", &client->none_cipher);
+
+  /* Initialize random number generator */
+  client->rng = silc_rng_alloc();
+  silc_rng_init(client->rng);
+  silc_math_primegen_init(); /* XXX */
+
+  /* Register protocols */
+  silc_client_protocols_register();
+
+  /* Initialize the scheduler */
+  silc_schedule_init(&client->io_queue, &client->timeout_queue, 
+                    &client->generic_queue, 5000);
+
+  return TRUE;
+}
+
+/* Stops the client. This is called to stop the client and thus to stop
+   the program. */
+
+void silc_client_stop(SilcClient client)
+{
+  SILC_LOG_DEBUG(("Stopping client"));
+
+  /* Stop the scheduler, although it might be already stopped. This
+     doesn't hurt anyone. This removes all the tasks and task queues,
+     as well. */
+  silc_schedule_stop();
+  silc_schedule_uninit();
+
+  silc_client_protocols_unregister();
+
+  SILC_LOG_DEBUG(("Client stopped"));
+}
+
+/* Runs the client. */
+
+void silc_client_run(SilcClient client)
+{
+  SILC_LOG_DEBUG(("Running client"));
+
+  /* Start the scheduler, the heart of the SILC client. When this returns
+     the program will be terminated. */
+  silc_schedule();
+}
+
+/* Allocates and adds new connection to the client. This adds the allocated
+   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. */
+
+SilcClientConnection silc_client_add_connection(SilcClient client,
+                                               char *hostname,
+                                               int port,
+                                               void *context)
+{
+  SilcClientConnection conn;
+  int i;
+
+  conn = silc_calloc(1, sizeof(*conn));
+
+  /* Initialize ID caches */
+  conn->client_cache = silc_idcache_alloc(0);
+  conn->channel_cache = silc_idcache_alloc(0);
+  conn->server_cache = silc_idcache_alloc(0);
+  conn->client = client;
+  conn->remote_host = strdup(hostname);
+  conn->remote_port = port;
+  conn->context = context;
+
+  /* Add the connection to connections table */
+  for (i = 0; i < client->conns_count; i++)
+    if (client->conns && !client->conns[i]) {
+      client->conns[i] = conn;
+      return conn;
+    }
+
+  client->conns = silc_realloc(client->conns, sizeof(*client->conns)
+                              * (client->conns_count + 1));
+  client->conns[client->conns_count] = conn;
+  client->conns_count++;
+
+  return conn;
+}
+
+/* Removes connection from client. */
+
+void silc_client_del_connection(SilcClient client, SilcClientConnection conn)
+{
+  int i;
+
+  for (i = 0; i < client->conns_count; i++)
+    if (client->conns[i] == conn) {
+      silc_free(conn);
+      client->conns[i] = NULL;
+    }
+}
+
+/* Internal context for connection process. This is needed as we
+   doing asynchronous connecting. */
+typedef struct {
+  SilcClient client;
+  SilcClientConnection conn;
+  SilcTask task;
+  int sock;
+  char *host;
+  int port;
+  int tries;
+} SilcClientInternalConnectContext;
+
+static int 
+silc_client_connect_to_server_internal(SilcClientInternalConnectContext *ctx)
+{
+  int sock;
+
+  /* XXX In the future we should give up this non-blocking connect all
+     together and use threads instead. */
+  /* Create connection to server asynchronously */
+  sock = silc_net_create_connection_async(ctx->port, ctx->host);
+  if (sock < 0)
+    return -1;
+
+  /* Register task that will receive the async connect and will
+     read the result. */
+  ctx->task = silc_task_register(ctx->client->io_queue, sock, 
+                                silc_client_connect_to_server_start,
+                                (void *)ctx, 0, 0, 
+                                SILC_TASK_FD,
+                                SILC_TASK_PRI_NORMAL);
+  silc_task_reset_iotype(ctx->task, SILC_TASK_WRITE);
+  silc_schedule_set_listen_fd(sock, ctx->task->iomask);
+
+  ctx->sock = sock;
+
+  return sock;
+}
+
+/* Connects to remote server. This is the main routine used to connect
+   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. */
+
+int silc_client_connect_to_server(SilcClient client, int port,
+                                 char *host, void *context)
+{
+  SilcClientInternalConnectContext *ctx;
+  SilcClientConnection conn;
+  int sock;
+
+  SILC_LOG_DEBUG(("Connecting to port %d of server %s",
+                 port, host));
+
+  conn = silc_client_add_connection(client, host, port, context);
+
+  client->ops->say(client, conn, 
+                  "Connecting to port %d of server %s", port, host);
+
+  /* Allocate internal context for connection process. This is
+     needed as we are doing async connecting. */
+  ctx = silc_calloc(1, sizeof(*ctx));
+  ctx->client = client;
+  ctx->conn = conn;
+  ctx->host = strdup(host);
+  ctx->port = port;
+  ctx->tries = 0;
+
+  /* Do the actual connecting process */
+  sock = silc_client_connect_to_server_internal(ctx);
+  if (sock == -1)
+    silc_client_del_connection(client, conn);
+  return sock;
+}
+
+/* Start SILC Key Exchange (SKE) protocol to negotiate shared secret
+   key material between client and server.  This function can be called
+   directly if application is performing its own connecting and does not
+   use the connecting provided by this library. */
+
+int silc_client_start_key_exchange(SilcClient client,
+                                  SilcClientConnection conn,
+                                   int fd)
+{
+  SilcProtocol protocol;
+  SilcClientKEInternalContext *proto_ctx;
+  void *context;
+
+  /* Allocate new socket connection object */
+  silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER, (void *)conn, &conn->sock);
+  if (conn->sock == NULL) {
+    client->ops->say(client, conn, 
+                    "Error: Could not allocate connection socket");
+    return FALSE;
+  }
+
+  conn->nickname = strdup(client->username);
+  conn->sock->hostname = conn->remote_host;
+  conn->sock->port = conn->remote_port;
+
+  /* Allocate internal Key Exchange context. This is sent to the
+     protocol as context. */
+  proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+  proto_ctx->client = (void *)client;
+  proto_ctx->sock = conn->sock;
+  proto_ctx->rng = client->rng;
+  proto_ctx->responder = FALSE;
+
+  /* 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, 
+                     &protocol, (void *)proto_ctx,
+                     silc_client_connect_to_server_second);
+  if (!protocol) {
+    client->ops->say(client, conn, 
+                    "Error: Could not start authentication protocol");
+    return FALSE;
+  }
+  conn->sock->protocol = protocol;
+
+  /* Register the connection for network input and output. This sets
+     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 
+     be set separately by calling SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT,
+     later when outgoing data is available. */
+  context = (void *)client;
+  SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(fd);
+
+  /* Execute the protocol */
+  protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
+  return TRUE;
+}
+
+/* Start of the connection to the remote server. This is called after
+   succesful TCP/IP connection has been established to the remote host. */
+
+SILC_TASK_CALLBACK(silc_client_connect_to_server_start)
+{
+  SilcClientInternalConnectContext *ctx =
+    (SilcClientInternalConnectContext *)context;
+  SilcClient client = ctx->client;
+  SilcClientConnection conn = ctx->conn;
+  int opt, opt_len = sizeof(opt);
+
+  SILC_LOG_DEBUG(("Start"));
+
+  /* Check the socket status as it might be in error */
+  getsockopt(fd, SOL_SOCKET, SO_ERROR, &opt, &opt_len);
+  if (opt != 0) {
+    if (ctx->tries < 2) {
+      /* Connection failed but lets try again */
+      client->ops->say(client, conn, "Could not connect to server %s: %s",
+                      ctx->host, strerror(opt));
+      client->ops->say(client, conn, 
+                      "Connecting to port %d of server %s resumed", 
+                      ctx->port, ctx->host);
+
+      /* Unregister old connection try */
+      silc_schedule_unset_listen_fd(fd);
+      silc_net_close_connection(fd);
+      silc_task_unregister(client->io_queue, ctx->task);
+
+      /* Try again */
+      silc_client_connect_to_server_internal(ctx);
+      ctx->tries++;
+    } else {
+      /* Connection failed and we won't try anymore */
+      client->ops->say(client, conn, "Could not connect to server %s: %s",
+                      ctx->host, strerror(opt));
+      silc_schedule_unset_listen_fd(fd);
+      silc_net_close_connection(fd);
+      silc_task_unregister(client->io_queue, ctx->task);
+      silc_free(ctx);
+
+      /* Notify application of failure */
+      client->ops->connect(client, conn, FALSE);
+      silc_client_del_connection(client, conn);
+    }
+    return;
+  }
+
+  silc_schedule_unset_listen_fd(fd);
+  silc_task_unregister(client->io_queue, ctx->task);
+  silc_free(ctx);
+
+  if (!silc_client_start_key_exchange(client, conn, fd)) {
+    silc_net_close_connection(fd);
+    client->ops->connect(client, conn, FALSE);
+  }
+}
+
+/* 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 *)protocol->context;
+  SilcClient client = (SilcClient)ctx->client;
+  SilcSocketConnection sock = NULL;
+  SilcClientConnAuthInternalContext *proto_ctx;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  if (protocol->state == SILC_PROTOCOL_STATE_ERROR) {
+    /* Error occured during protocol */
+    SILC_LOG_DEBUG(("Error during KE protocol"));
+    silc_protocol_free(protocol);
+    if (ctx->ske)
+      silc_ske_free(ctx->ske);
+    if (ctx->dest_id)
+      silc_free(ctx->dest_id);
+    ctx->sock->protocol = NULL;
+
+    /* Notify application of failure */
+    client->ops->connect(client, ctx->sock->user_data, FALSE);
+    silc_free(ctx);
+    return;
+  }
+
+  /* Allocate internal context for the authentication protocol. This
+     is sent as context for the protocol. */
+  proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+  proto_ctx->client = (void *)client;
+  proto_ctx->sock = sock = ctx->sock;
+  proto_ctx->ske = ctx->ske;   /* Save SKE object from previous protocol */
+  proto_ctx->dest_id_type = ctx->dest_id_type;
+  proto_ctx->dest_id = ctx->dest_id;
+
+  /* Resolve the authentication method to be used in this connection */
+  if (!client->ops->get_auth_method(client, sock->user_data, sock->hostname,
+                                   sock->port, &proto_ctx->auth_meth,
+                                   &proto_ctx->auth_data, 
+                                   &proto_ctx->auth_data_len))
+    {
+      /* XXX do AUTH_REQUEST resolcing with server */
+      proto_ctx->auth_meth = SILC_PROTOCOL_CONN_AUTH_NONE;
+    }
+
+  /* Free old protocol as it is finished now */
+  silc_protocol_free(protocol);
+  if (ctx->packet)
+    silc_buffer_free(ctx->packet);
+  silc_free(ctx);
+  /* silc_free(ctx->keymat....); */
+  sock->protocol = NULL;
+
+  /* Allocate the authentication protocol. This is allocated here
+     but we won't start it yet. We will be receiving party of this
+     protocol thus we will wait that connecting party will make
+     their first move. */
+  silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH, 
+                     &sock->protocol, (void *)proto_ctx, 
+                     silc_client_connect_to_server_final);
+
+  /* Execute the protocol */
+  sock->protocol->execute(client->timeout_queue, 0, sock->protocol, fd, 0, 0);
+}
+
+/* Finalizes the connection to the remote SILC server. This is called
+   after authentication protocol has been completed. This send our
+   user information to the server to receive our client ID from
+   server. */
+
+SILC_TASK_CALLBACK(silc_client_connect_to_server_final)
+{
+  SilcProtocol protocol = (SilcProtocol)context;
+  SilcClientConnAuthInternalContext *ctx = 
+    (SilcClientConnAuthInternalContext *)protocol->context;
+  SilcClient client = (SilcClient)ctx->client;
+  SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data;
+  SilcBuffer packet;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  if (protocol->state == SILC_PROTOCOL_STATE_ERROR) {
+    /* Error occured during protocol */
+    SILC_LOG_DEBUG(("Error during authentication protocol"));
+    silc_protocol_free(protocol);
+    if (ctx->auth_data)
+      silc_free(ctx->auth_data);
+    if (ctx->ske)
+      silc_ske_free(ctx->ske);
+    if (ctx->dest_id)
+      silc_free(ctx->dest_id);
+    conn->sock->protocol = NULL;
+
+    /* Notify application of failure */
+    client->ops->connect(client, ctx->sock->user_data, FALSE);
+    silc_free(ctx);
+    return;
+  }
+
+  /* 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) + 
+                            strlen(client->realname));
+  silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+  silc_buffer_format(packet,
+                    SILC_STR_UI_SHORT(strlen(client->username)),
+                    SILC_STR_UI_XNSTRING(client->username,
+                                         strlen(client->username)),
+                    SILC_STR_UI_SHORT(strlen(client->realname)),
+                    SILC_STR_UI_XNSTRING(client->realname,
+                                         strlen(client->realname)),
+                    SILC_STR_END);
+
+  /* Send the packet */
+  silc_client_packet_send(client, ctx->sock, SILC_PACKET_NEW_CLIENT,
+                         NULL, 0, NULL, NULL, 
+                         packet->data, packet->len, TRUE);
+  silc_buffer_free(packet);
+
+  /* Save remote ID. */
+  conn->remote_id = ctx->dest_id;
+  conn->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_SERVER);
+  conn->remote_id_data_len = SILC_ID_SERVER_LEN;
+
+  /* Notify application of successful connection */
+  client->ops->connect(client, conn, TRUE);
+
+  silc_protocol_free(protocol);
+  if (ctx->auth_data)
+    silc_free(ctx->auth_data);
+  if (ctx->ske)
+    silc_ske_free(ctx->ske);
+  if (ctx->dest_id)
+    silc_free(ctx->dest_id);
+  silc_free(ctx);
+  conn->sock->protocol = NULL;
+}
+
+/* Internal routine that sends packet or marks packet to be sent. This
+   is used directly only in special cases. Normal cases should use
+   silc_server_packet_send. Returns < 0 on error. */
+
+static int silc_client_packet_send_real(SilcClient client,
+                                       SilcSocketConnection sock,
+                                       int force_send)
+{
+  int ret;
+
+  /* Send the packet */
+  ret = silc_packet_send(sock, force_send);
+  if (ret != -2)
+    return ret;
+
+  /* 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). 
+     Actual data sending is performed by silc_client_packet_process. */
+  SILC_CLIENT_SET_CONNECTION_FOR_OUTPUT(sock->sock);
+
+  /* Mark to socket that data is pending in outgoing buffer. This flag
+     is needed if new data is added to the buffer before the earlier
+     put data is sent to the network. */
+  SILC_SET_OUTBUF_PENDING(sock);
+
+  return 0;
+}
+
+/* Packet processing callback. This is used to send and receive packets
+   from network. This is generic task. */
+
+SILC_TASK_CALLBACK(silc_client_packet_process)
+{
+  SilcClient client = (SilcClient)context;
+  SilcSocketConnection sock = NULL;
+  SilcClientConnection conn;
+  int ret;
+
+  SILC_LOG_DEBUG(("Processing packet"));
+
+  SILC_CLIENT_GET_SOCK(client, fd, sock);
+  if (sock == NULL)
+    return;
+
+  conn = (SilcClientConnection)sock->user_data;
+
+  /* Packet sending */
+  if (type == SILC_TASK_WRITE) {
+    SILC_LOG_DEBUG(("Writing data to connection"));
+
+    if (sock->outbuf->data - sock->outbuf->head)
+      silc_buffer_push(sock->outbuf, 
+                      sock->outbuf->data - sock->outbuf->head);
+
+    ret = silc_client_packet_send_real(client, sock, TRUE);
+
+    /* If returned -2 could not write to connection now, will do
+       it later. */
+    if (ret == -2)
+      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. 
+       This call clears the output setting and sets it only for input. */
+    SILC_CLIENT_SET_CONNECTION_FOR_INPUT(fd);
+    SILC_UNSET_OUTBUF_PENDING(sock);
+
+    silc_buffer_clear(sock->outbuf);
+    return;
+  }
+
+  /* Packet receiving */
+  if (type == SILC_TASK_READ) {
+    SILC_LOG_DEBUG(("Reading data from connection"));
+
+    /* Read data from network */
+    ret = silc_packet_receive(sock);
+    if (ret < 0)
+      return;
+    
+    /* EOF */
+    if (ret == 0) {
+      SILC_LOG_DEBUG(("Read EOF"));
+
+      /* If connection is disconnecting already we will finally
+        close the connection */
+      if (SILC_IS_DISCONNECTING(sock)) {
+       client->ops->disconnect(client, conn);
+       silc_client_close_connection(client, sock);
+       return;
+      }
+      
+      client->ops->say(client, conn, "Connection closed: premature EOF");
+      SILC_LOG_DEBUG(("Premature EOF from connection %d", sock->sock));
+      client->ops->disconnect(client, conn);
+      silc_client_close_connection(client, sock);
+      return;
+    }
+
+    /* Process the packet. This will call the parser that will then
+       decrypt and parse the packet. */
+    silc_packet_receive_process(sock, conn->receive_key, conn->hmac,
+                               silc_client_packet_parse, client);
+  }
+}
+
+/* Parses whole packet, received earlier. */
+
+SILC_TASK_CALLBACK(silc_client_packet_parse_real)
+{
+  SilcPacketParserContext *parse_ctx = (SilcPacketParserContext *)context;
+  SilcClient client = (SilcClient)parse_ctx->context;
+  SilcPacketContext *packet = parse_ctx->packet;
+  SilcBuffer buffer = packet->buffer;
+  SilcSocketConnection sock = parse_ctx->sock;
+  SilcClientConnection conn = (SilcClientConnection)sock->user_data;
+  int ret;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  /* Decrypt the received packet */
+  ret = silc_packet_decrypt(conn->receive_key, conn->hmac, buffer, packet);
+  if (ret < 0)
+    goto out;
+
+  if (ret == 0) {
+    /* Parse the packet. Packet type is returned. */
+    ret = silc_packet_parse(packet);
+  } else {
+    /* Parse the packet header in special way as this is "special"
+       packet type. */
+    ret = silc_packet_parse_special(packet);
+  }
+
+  if (ret == SILC_PACKET_NONE)
+    goto out;
+
+  /* Parse the incoming packet type */
+  silc_client_packet_parse_type(client, sock, packet);
+
+ out:
+  silc_buffer_clear(buffer);
+  if (packet->src_id)
+    silc_free(packet->src_id);
+  if (packet->dst_id)
+    silc_free(packet->dst_id);
+  silc_free(packet);
+  silc_free(parse_ctx);
+}
+
+/* Parser callback called by silc_packet_receive_process. Thie merely
+   registers timeout that will handle the actual parsing when appropriate. */
+
+void silc_client_packet_parse(SilcPacketParserContext *parser_context)
+{
+  SilcClient client = (SilcClient)parser_context->context;
+
+  /* Parse the packet */
+  silc_task_register(client->timeout_queue, parser_context->sock->sock, 
+                    silc_client_packet_parse_real,
+                    (void *)parser_context, 0, 1, 
+                    SILC_TASK_TIMEOUT,
+                    SILC_TASK_PRI_NORMAL);
+}
+  
+/* 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, 
+                                  SilcSocketConnection sock,
+                                  SilcPacketContext *packet)
+{
+  SilcBuffer buffer = packet->buffer;
+  SilcPacketType type = packet->type;
+
+  SILC_LOG_DEBUG(("Parsing packet type %d", type));
+
+  /* Parse the packet type */
+  switch(type) {
+  case SILC_PACKET_DISCONNECT:
+    silc_client_disconnected_by_server(client, sock, buffer);
+    break;
+  case SILC_PACKET_SUCCESS:
+    /*
+     * Success received for something. For now we can have only
+     * one protocol for connection executing at once hence this
+     * success message is for whatever protocol is executing currently.
+     */
+    if (sock->protocol) {
+      sock->protocol->execute(client->timeout_queue, 0,
+                             sock->protocol, sock->sock, 0, 0);
+    }
+    break;
+  case SILC_PACKET_FAILURE:
+    /*
+     * 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.
+     */
+    if (sock->protocol) {
+      sock->protocol->state = SILC_PROTOCOL_STATE_FAILURE;
+      sock->protocol->execute(client->timeout_queue, 0,
+                             sock->protocol, sock->sock, 0, 0);
+
+      /* XXX We have only two protocols currently thus we know what this
+        failure indication is. */
+      if (buffer->len >= 4) {
+       unsigned int failure;
+
+       SILC_GET32_MSB(failure, buffer->data);
+
+       /* Notify application */
+       client->ops->failure(client, sock->user_data, sock->protocol,
+                            (void *)failure);
+      }
+    }
+    break;
+  case SILC_PACKET_REJECT:
+    break;
+
+  case SILC_PACKET_NOTIFY:
+    /*
+     * Received notify message 
+     */
+    silc_client_notify_by_server(client, sock, packet);
+    break;
+
+  case SILC_PACKET_ERROR:
+    /*
+     * Received error message
+     */
+    silc_client_error_by_server(client, sock, buffer);
+    break;
+
+  case SILC_PACKET_CHANNEL_MESSAGE:
+    /*
+     * Received message to (from, actually) a channel
+     */
+    silc_client_channel_message(client, sock, packet);
+    break;
+  case SILC_PACKET_CHANNEL_KEY:
+    /*
+     * Received key for a channel. By receiving this key the client will be
+     * able to talk to the channel it has just joined. This can also be
+     * a new key for existing channel as keys expire peridiocally.
+     */
+    silc_client_receive_channel_key(client, sock, buffer);
+    break;
+
+  case SILC_PACKET_PRIVATE_MESSAGE:
+    /*
+     * Received private message
+     */
+    silc_client_private_message(client, sock, packet);
+    break;
+  case SILC_PACKET_PRIVATE_MESSAGE_KEY:
+    /*
+     * Received private message key
+     */
+    break;
+
+  case SILC_PACKET_COMMAND_REPLY:
+    /*
+     * Recived reply for a command
+     */
+    silc_client_command_reply_process(client, sock, packet);
+    break;
+
+  case SILC_PACKET_KEY_EXCHANGE:
+    if (sock->protocol) {
+      SilcClientKEInternalContext *proto_ctx = 
+       (SilcClientKEInternalContext *)sock->protocol->context;
+
+      proto_ctx->packet = buffer;
+      proto_ctx->dest_id_type = packet->src_id_type;
+      proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_type);
+
+      /* Let the protocol handle the packet */
+      sock->protocol->execute(client->timeout_queue, 0,
+                             sock->protocol, sock->sock, 0, 0);
+    } else {
+      SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
+                     "protocol active, packet dropped."));
+
+      /* XXX Trigger KE protocol?? Rekey actually! */
+    }
+    break;
+
+  case SILC_PACKET_KEY_EXCHANGE_1:
+    if (sock->protocol) {
+
+    } else {
+      SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
+                     "protocol active, packet dropped."));
+    }
+    break;
+  case SILC_PACKET_KEY_EXCHANGE_2:
+    if (sock->protocol) {
+      SilcClientKEInternalContext *proto_ctx = 
+       (SilcClientKEInternalContext *)sock->protocol->context;
+
+      if (proto_ctx->packet)
+       silc_buffer_free(proto_ctx->packet);
+
+      proto_ctx->packet = buffer;
+      proto_ctx->dest_id_type = packet->src_id_type;
+      proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_type);
+
+      /* Let the protocol handle the packet */
+      sock->protocol->execute(client->timeout_queue, 0,
+                             sock->protocol, sock->sock, 0, 0);
+    } else {
+      SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
+                     "protocol active, packet dropped."));
+    }
+    break;
+
+  case SILC_PACKET_NEW_ID:
+    {
+      /*
+       * Received new ID from server. This packet is received at
+       * 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.
+       */
+      SilcIDPayload idp;
+
+      idp = silc_id_payload_parse(buffer);
+      if (silc_id_payload_get_type(idp) != SILC_ID_CLIENT)
+       break;
+
+      silc_client_receive_new_id(client, sock, idp);
+      silc_id_payload_free(idp);
+      break;
+    }
+
+  default:
+    SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
+    break;
+  }
+}
+
+/* Sends packet. This doesn't actually send the packet instead it assembles
+   it and marks it to be sent. However, if force_send is TRUE the packet
+   is sent immediately. if dst_id, cipher and hmac are NULL those parameters
+   will be derived from sock argument. Otherwise the valid arguments sent
+   are used. */
+
+void silc_client_packet_send(SilcClient client, 
+                            SilcSocketConnection sock,
+                            SilcPacketType type, 
+                            void *dst_id,
+                            SilcIdType dst_id_type,
+                            SilcCipher cipher,
+                            SilcHmac hmac,
+                            unsigned char *data, 
+                            unsigned int data_len, 
+                            int force_send)
+{
+  SilcPacketContext packetdata;
+
+  SILC_LOG_DEBUG(("Sending packet, type %d", type));
+
+  /* Get data used in the packet sending, keys and stuff */
+  if ((!cipher || !hmac || !dst_id) && sock->user_data) {
+    if (!cipher && ((SilcClientConnection)sock->user_data)->send_key)
+      cipher = ((SilcClientConnection)sock->user_data)->send_key;
+
+    if (!hmac && ((SilcClientConnection)sock->user_data)->hmac)
+      hmac = ((SilcClientConnection)sock->user_data)->hmac;
+
+    if (!dst_id && ((SilcClientConnection)sock->user_data)->remote_id) {
+      dst_id = ((SilcClientConnection)sock->user_data)->remote_id;
+      dst_id_type = SILC_ID_SERVER;
+    }
+  }
+
+  /* Set the packet context pointers */
+  packetdata.flags = 0;
+  packetdata.type = type;
+  if (((SilcClientConnection)sock->user_data)->local_id_data)
+    packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data;
+  else 
+    packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
+  packetdata.src_id_len = SILC_ID_CLIENT_LEN;
+  packetdata.src_id_type = SILC_ID_CLIENT;
+  if (dst_id) {
+    packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
+    packetdata.dst_id_len = silc_id_get_len(dst_id_type);
+    packetdata.dst_id_type = dst_id_type;
+  } else {
+    packetdata.dst_id = NULL;
+    packetdata.dst_id_len = 0;
+    packetdata.dst_id_type = SILC_ID_NONE;
+  }
+  packetdata.rng = client->rng;
+  packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN + 
+    packetdata.src_id_len + packetdata.dst_id_len;
+  packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
+
+  /* Prepare outgoing data buffer for packet sending */
+  silc_packet_send_prepare(sock, 
+                          SILC_PACKET_HEADER_LEN +
+                          packetdata.src_id_len + 
+                          packetdata.dst_id_len,
+                          packetdata.padlen,
+                          data_len);
+
+  SILC_LOG_DEBUG(("Putting data to outgoing buffer, len %d", data_len));
+
+  packetdata.buffer = sock->outbuf;
+
+  /* Put the data to the buffer */
+  if (data && data_len)
+    silc_buffer_put(sock->outbuf, data, data_len);
+
+  /* Create the outgoing packet */
+  silc_packet_assemble(&packetdata);
+
+  /* Encrypt the packet */
+  if (cipher)
+    silc_packet_encrypt(cipher, hmac, sock->outbuf, sock->outbuf->len);
+
+  SILC_LOG_HEXDUMP(("Packet, len %d", sock->outbuf->len),
+                  sock->outbuf->data, sock->outbuf->len);
+
+  /* Now actually send the packet */
+  silc_client_packet_send_real(client, sock, force_send);
+}
+
+/* Sends packet to a channel. Packet to channel is always encrypted
+   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. */
+
+void silc_client_packet_send_to_channel(SilcClient client, 
+                                       SilcSocketConnection sock,
+                                       SilcChannelEntry channel,
+                                       unsigned char *data, 
+                                       unsigned int data_len, 
+                                       int force_send)
+{
+  int i;
+  SilcClientConnection conn = (SilcClientConnection)sock->user_data;
+  SilcBuffer payload;
+  SilcPacketContext packetdata;
+  SilcCipher cipher;
+  SilcHmac hmac;
+  unsigned char *id_string;
+
+  SILC_LOG_DEBUG(("Sending packet to channel"));
+
+  if (!channel || !channel->key) {
+    client->ops->say(client, conn, 
+                    "Cannot talk to channel: key does not exist");
+    return;
+  }
+
+  /* Generate IV */
+  if (!channel->iv)
+    for (i = 0; i < 16; i++)
+      channel->iv[i] = silc_rng_get_byte(client->rng);
+  else
+    silc_hash_make(client->md5hash, channel->iv, 16, channel->iv);
+
+  /* Encode the channel payload */
+  payload = silc_channel_payload_encode(data_len, data, 16, channel->iv, 
+                                       client->rng);
+  if (!payload) {
+    client->ops->say(client, conn, 
+                    "Error: Could not create packet to be sent to channel");
+    return;
+  }
+
+  /* Get data used in packet header encryption, keys and stuff. Rest
+     of the packet (the payload) is, however, encrypted with the 
+     specified channel key. */
+  cipher = conn->send_key;
+  hmac = conn->hmac;
+  id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+
+  /* Set the packet context pointers. The destination ID is always
+     the Channel ID of the channel. Server and router will handle the
+     distribution of the packet. */
+  packetdata.flags = 0;
+  packetdata.type = SILC_PACKET_CHANNEL_MESSAGE;
+  packetdata.src_id = conn->local_id_data;
+  packetdata.src_id_len = SILC_ID_CLIENT_LEN;
+  packetdata.src_id_type = SILC_ID_CLIENT;
+  packetdata.dst_id = id_string;
+  packetdata.dst_id_len = SILC_ID_CHANNEL_LEN;
+  packetdata.dst_id_type = SILC_ID_CHANNEL;
+  packetdata.rng = client->rng;
+  packetdata.truelen = payload->len + SILC_PACKET_HEADER_LEN + 
+    packetdata.src_id_len + packetdata.dst_id_len;
+  packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
+                                         packetdata.src_id_len +
+                                         packetdata.dst_id_len));
+
+  /* Prepare outgoing data buffer for packet sending */
+  silc_packet_send_prepare(sock, 
+                          SILC_PACKET_HEADER_LEN +
+                          packetdata.src_id_len + 
+                          packetdata.dst_id_len,
+                          packetdata.padlen,
+                          payload->len);
+
+  packetdata.buffer = sock->outbuf;
+
+  /* Encrypt payload of the packet. This is encrypted with the channel key. */
+  channel->channel_key->cipher->encrypt(channel->channel_key->context,
+                                       payload->data, payload->data,
+                                       payload->len - 16, /* -IV_LEN */
+                                       channel->iv);
+
+  /* Put the actual encrypted payload data into the buffer. */
+  silc_buffer_put(sock->outbuf, payload->data, payload->len);
+
+  /* Create the outgoing packet */
+  silc_packet_assemble(&packetdata);
+
+  /* Encrypt the header and padding of the packet. This is encrypted 
+     with normal session key shared with our server. */
+  silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN + 
+                     packetdata.src_id_len + packetdata.dst_id_len +
+                     packetdata.padlen);
+
+  SILC_LOG_HEXDUMP(("Packet to channel, len %d", sock->outbuf->len),
+                  sock->outbuf->data, sock->outbuf->len);
+
+  /* Now actually send the packet */
+  silc_client_packet_send_real(client, sock, force_send);
+  silc_buffer_free(payload);
+  silc_free(id_string);
+}
+
+/* Sends private message to remote client. If private message key has
+   not been set with this client then the message will be encrypted using
+   normal session keys. Private messages are special packets in SILC
+   network hence we need this own function for them. This is similiar
+   to silc_client_packet_send_to_channel except that we send private
+   message. */
+
+void silc_client_packet_send_private_message(SilcClient client,
+                                            SilcSocketConnection sock,
+                                            SilcClientEntry client_entry,
+                                            unsigned char *data, 
+                                            unsigned int data_len, 
+                                            int force_send)
+{
+  SilcClientConnection conn = (SilcClientConnection)sock->user_data;
+  SilcBuffer buffer;
+  SilcPacketContext packetdata;
+  unsigned int nick_len;
+  SilcCipher cipher;
+  SilcHmac hmac;
+
+  SILC_LOG_DEBUG(("Sending private message"));
+
+  /* Create private message payload */
+  nick_len = strlen(conn->nickname);
+  buffer = silc_buffer_alloc(2 + nick_len + data_len);
+  silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
+  silc_buffer_format(buffer,
+                    SILC_STR_UI_SHORT(nick_len),
+                    SILC_STR_UI_XNSTRING(conn->nickname,
+                                         nick_len),
+                    SILC_STR_UI_XNSTRING(data, data_len),
+                    SILC_STR_END);
+
+  /* If we don't have private message specific key then private messages
+     are just as any normal packet thus call normal packet sending.  If
+     the key exist then the encryption process is a bit different and
+     will be done in the rest of this function. */
+  if (!client_entry->send_key) {
+    silc_client_packet_send(client, sock, SILC_PACKET_PRIVATE_MESSAGE,
+                           client_entry->id, SILC_ID_CLIENT, NULL, NULL,
+                           buffer->data, buffer->len, force_send);
+    goto out;
+  }
+
+  /* We have private message specific key */
+
+  /* Get data used in the encryption */
+  cipher = client_entry->send_key;
+  hmac = conn->hmac;
+
+  /* Set the packet context pointers. */
+  packetdata.flags = 0;
+  packetdata.type = SILC_PACKET_PRIVATE_MESSAGE;
+  packetdata.src_id = conn->local_id_data;
+  packetdata.src_id_len = SILC_ID_CLIENT_LEN;
+  packetdata.src_id_type = SILC_ID_CLIENT;
+  if (client_entry)
+    packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
+  else
+    packetdata.dst_id = conn->local_id_data;
+  packetdata.dst_id_len = SILC_ID_CLIENT_LEN;
+  packetdata.dst_id_type = SILC_ID_CLIENT;
+  packetdata.rng = client->rng;
+  packetdata.truelen = buffer->len + SILC_PACKET_HEADER_LEN + 
+    packetdata.src_id_len + packetdata.dst_id_len;
+  packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
+                                         packetdata.src_id_len +
+                                         packetdata.dst_id_len));
+
+  /* Prepare outgoing data buffer for packet sending */
+  silc_packet_send_prepare(sock, 
+                          SILC_PACKET_HEADER_LEN +
+                          packetdata.src_id_len + 
+                          packetdata.dst_id_len,
+                          packetdata.padlen,
+                          buffer->len);
+  
+  packetdata.buffer = sock->outbuf;
+
+  /* Encrypt payload of the packet. Encrypt with private message specific
+     key if it exist, otherwise with session key. */
+  cipher->cipher->encrypt(cipher->context, buffer->data, buffer->data,
+                         buffer->len, cipher->iv);
+      
+  /* Put the actual encrypted payload data into the buffer. */
+  silc_buffer_put(sock->outbuf, buffer->data, buffer->len);
+
+  /* Create the outgoing packet */
+  silc_packet_assemble(&packetdata);
+
+  /* Encrypt the header and padding of the packet. */
+  silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN + 
+                     packetdata.src_id_len + packetdata.dst_id_len +
+                     packetdata.padlen);
+
+  SILC_LOG_HEXDUMP(("Private message packet, len %d", sock->outbuf->len),
+                  sock->outbuf->data, sock->outbuf->len);
+
+  /* Now actually send the packet */
+  silc_client_packet_send_real(client, sock, force_send);
+  silc_free(packetdata.dst_id);
+
+ out:
+  silc_free(buffer);
+}     
+
+/* Closes connection to remote end. Free's all allocated data except
+   for some information such as nickname etc. that are valid at all time. */
+
+void silc_client_close_connection(SilcClient client,
+                                 SilcSocketConnection sock)
+{
+  SilcClientConnection conn;
+
+  /* We won't listen for this connection anymore */
+  silc_schedule_unset_listen_fd(sock->sock);
+
+  /* Unregister all tasks */
+  silc_task_unregister_by_fd(client->io_queue, sock->sock);
+  silc_task_unregister_by_fd(client->timeout_queue, sock->sock);
+
+  /* Close the actual connection */
+  silc_net_close_connection(sock->sock);
+
+  client->ops->say(client, sock->user_data,
+                  "Closed connection to host %s", sock->hostname ?
+                  sock->hostname : sock->ip);
+
+  /* Free everything */
+  if (sock->user_data) {
+    conn = (SilcClientConnection)sock->user_data;
+
+    /* XXX Free all client entries and channel entries. */
+
+    /* Clear ID caches */
+    silc_idcache_del_all(conn->client_cache);
+    silc_idcache_del_all(conn->channel_cache);
+
+    /* Free data */
+    if (conn->remote_host)
+      silc_free(conn->remote_host);
+    if (conn->local_id)
+      silc_free(conn->local_id);
+    if (conn->local_id_data)
+      silc_free(conn->local_id_data);
+    if (conn->send_key)
+      silc_cipher_free(conn->send_key);
+    if (conn->receive_key)
+      silc_cipher_free(conn->receive_key);
+    if (conn->hmac)
+      silc_hmac_free(conn->hmac);
+    if (conn->hmac_key) {
+      memset(conn->hmac_key, 0, conn->hmac_key_len);
+      silc_free(conn->hmac_key);
+    }
+
+    conn->sock = NULL;
+    conn->remote_port = 0;
+    conn->remote_type = 0;
+    conn->send_key = NULL;
+    conn->receive_key = NULL;
+    conn->hmac = NULL;
+    conn->hmac_key = NULL;
+    conn->hmac_key_len = 0;
+    conn->local_id = NULL;
+    conn->local_id_data = NULL;
+    conn->remote_host = NULL;
+    conn->current_channel = NULL;
+
+    silc_client_del_connection(client, conn);
+  }
+
+  if (sock->protocol) {
+    silc_protocol_free(sock->protocol);
+    sock->protocol = NULL;
+  }
+  silc_socket_free(sock);
+}
+
+/* Called when we receive disconnection packet from server. This 
+   closes our end properly and displays the reason of the disconnection
+   on the screen. */
+
+void silc_client_disconnected_by_server(SilcClient client,
+                                       SilcSocketConnection sock,
+                                       SilcBuffer message)
+{
+  char *msg;
+
+  SILC_LOG_DEBUG(("Server disconnected us, sock %d", sock->sock));
+
+  msg = silc_calloc(message->len + 1, sizeof(char));
+  memcpy(msg, message->data, message->len);
+  client->ops->say(client, sock->user_data, msg);
+  silc_free(msg);
+
+  SILC_SET_DISCONNECTED(sock);
+  silc_client_close_connection(client, sock);
+}
+
+/* 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,
+                                SilcSocketConnection sock,
+                                SilcBuffer message)
+{
+  char *msg;
+
+  msg = silc_calloc(message->len + 1, sizeof(char));
+  memcpy(msg, message->data, message->len);
+  client->ops->say(client, sock->user_data, msg);
+  silc_free(msg);
+}
+
+/* Called when notify is received and some async operation (such as command)
+   is required before processing the notify message. This calls again the
+   silc_client_notify_by_server and reprocesses the original notify packet. */
+
+static void silc_client_notify_by_server_pending(void *context)
+{
+  SilcPacketContext *p = (SilcPacketContext *)context;
+  silc_client_notify_by_server(p->context, p->sock, p);
+  if (p->src_id)
+    silc_free(p->src_id);
+  if (p->dst_id)
+    silc_free(p->dst_id);
+  silc_buffer_free(p->buffer);
+  silc_free(p);
+}
+
+/* Received notify message from server */
+
+void silc_client_notify_by_server(SilcClient client,
+                                 SilcSocketConnection sock,
+                                 SilcPacketContext *packet)
+{
+  SilcBuffer buffer = packet->buffer;
+  SilcClientConnection conn = (SilcClientConnection)sock->user_data;
+  SilcNotifyPayload payload;
+  SilcNotifyType type;
+  SilcArgumentPayload args;
+  int i;
+
+  SilcClientID *client_id = NULL;
+  SilcChannelID *channel_id = NULL;
+  SilcClientEntry client_entry;
+  SilcClientEntry client_entry2;
+  SilcChannelEntry channel;
+  SilcIDCacheEntry id_cache = NULL;
+  unsigned char *tmp;
+  unsigned int tmp_len, mode;
+
+  payload = silc_notify_payload_parse(buffer);
+  type = silc_notify_get_type(payload);
+  args = silc_notify_get_args(payload);
+  if (!args)
+    goto out;
+
+  switch(type) {
+  case SILC_NOTIFY_TYPE_NONE:
+    /* Notify application */
+    client->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.
+     */
+    
+    /* Get Client ID */
+    tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+    if (!tmp)
+      goto out;
+
+    client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+    /* Find Client entry and if not found query it */
+    client_entry = silc_idlist_get_client_by_id(client, conn, client_id, TRUE);
+    if (!client_entry) {
+      SilcPacketContext *p = silc_packet_context_dup(packet);
+      p->context = (void *)client;
+      p->sock = sock;
+      silc_client_command_pending(SILC_COMMAND_WHOIS, 
+                                 silc_client_notify_by_server_pending, p);
+      goto out;
+    }
+
+    /* 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);
+
+    /* XXX Will ALWAYS fail because currently we don't have way to resolve
+       channel information for channel that we're not joined to. */
+    /* XXX ways to fix: use (extended) LIST command, or define the channel
+       name to the notfy type when name resolving is not mandatory. */
+    /* Find channel entry */
+    if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
+                                    SILC_ID_CHANNEL, &id_cache))
+      goto out;
+
+    channel = (SilcChannelEntry)id_cache->context;
+
+    /* Notify application */
+    client->ops->notify(client, conn, type, client_entry, channel);
+    break;
+
+  case SILC_NOTIFY_TYPE_JOIN:
+    /*
+     * Someone has joined to a channel. Get their ID and nickname and
+     * cache them for later use.
+     */
+
+    /* Get Client ID */
+    tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+    if (!tmp)
+      goto out;
+
+    client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+    /* Find Client entry and if not found query it */
+    client_entry = silc_idlist_get_client_by_id(client, conn, client_id, TRUE);
+    if (!client_entry) {
+      SilcPacketContext *p = silc_packet_context_dup(packet);
+      p->context = (void *)client;
+      p->sock = sock;
+      silc_client_command_pending(SILC_COMMAND_WHOIS, 
+                                 silc_client_notify_by_server_pending, p);
+      goto out;
+    }
+
+    /* Get channel entry */
+    channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
+    if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
+                                    SILC_ID_CHANNEL, &id_cache))
+      break;
+
+    channel = (SilcChannelEntry)id_cache->context;
+
+    /* Add client to channel */
+    for (i = 0; i < channel->clients_count; i++) {
+      if (channel->clients[i].client == NULL) {
+       channel->clients[channel->clients_count].client = client_entry;
+       channel->clients_count++;
+       break;
+      }
+    }
+
+    if (i == channel->clients_count) {
+      channel->clients = silc_realloc(channel->clients, 
+                                     sizeof(*channel->clients) * 
+                                     (channel->clients_count + 1));
+      channel->clients[channel->clients_count].client = client_entry;
+      channel->clients[channel->clients_count].mode = 0;
+      channel->clients_count++;
+    }
+
+    /* XXX add support for multiple same nicks on same channel. Check
+       for them here */
+
+    /* 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->ops->notify(client, conn, type, client_entry, channel);
+    break;
+
+  case SILC_NOTIFY_TYPE_LEAVE:
+    /*
+     * 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.
+     */
+    
+    /* Get Client ID */
+    tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+    if (!tmp)
+      goto out;
+
+    client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+    /* Find Client entry */
+    client_entry = 
+      silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
+    if (!client_entry)
+      goto out;
+
+    /* Get channel entry */
+    channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
+    if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
+                                    SILC_ID_CHANNEL, &id_cache))
+      break;
+
+    channel = (SilcChannelEntry)id_cache->context;
+
+    /* Remove client from channel */
+    for (i = 0; i < channel->clients_count; i++) {
+      if (channel->clients[i].client == client_entry) {
+       channel->clients[i].client = NULL;
+       channel->clients_count--;
+       break;
+      }
+    }
+
+    /* 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->ops->notify(client, conn, type, client_entry, channel);
+    break;
+
+  case SILC_NOTIFY_TYPE_SIGNOFF:
+    /*
+     * Someone left SILC. We'll remove it from all channels and from cache.
+     */
+
+    /* Get Client ID */
+    tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+    if (!tmp)
+      goto out;
+
+    client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+    /* Find Client entry */
+    client_entry = 
+      silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
+    if (!client_entry)
+      goto out;
+
+    /* Remove from all channels */
+    silc_client_remove_from_channels(client, conn, client_entry);
+
+    /* Remove from cache */
+    silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, 
+                          client_entry->id);
+
+    /* Notify application */
+    client->ops->notify(client, conn, type, client_entry);
+
+    /* Free data */
+    if (client_entry->nickname)
+      silc_free(client_entry->nickname);
+    if (client_entry->server)
+      silc_free(client_entry->server);
+    if (client_entry->id)
+      silc_free(client_entry->id);
+    if (client_entry->send_key)
+      silc_cipher_free(client_entry->send_key);
+    if (client_entry->receive_key)
+      silc_cipher_free(client_entry->receive_key);
+    break;
+
+  case SILC_NOTIFY_TYPE_TOPIC_SET:
+    /*
+     * Someone set the topic on a channel.
+     */
+
+    /* Get Client ID */
+    tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+    if (!tmp)
+      goto out;
+
+    client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+    /* Find Client entry */
+    client_entry = 
+      silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
+    if (!client_entry)
+      goto out;
+
+    /* Get topic */
+    tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+    if (!tmp)
+      goto out;
+
+    /* Get channel entry */
+    channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
+    if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
+                                    SILC_ID_CHANNEL, &id_cache))
+      break;
+
+    channel = (SilcChannelEntry)id_cache->context;
+
+    /* 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->ops->notify(client, conn, type, client_entry, tmp, channel);
+    break;
+
+  case SILC_NOTIFY_TYPE_NICK_CHANGE:
+    /*
+     * 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 
+     * application.
+     */
+
+    /* Get new Client ID */
+    tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+    if (!tmp)
+      goto out;
+
+    client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+    /* Ignore my ID */
+    if (!SILC_ID_CLIENT_COMPARE(client_id, conn->local_id))
+      break;
+
+    /* Find Client entry and if not found query it */
+    client_entry2 = 
+      silc_idlist_get_client_by_id(client, conn, client_id, TRUE);
+    if (!client_entry2) {
+      SilcPacketContext *p = silc_packet_context_dup(packet);
+      p->context = (void *)client;
+      p->sock = sock;
+      silc_client_command_pending(SILC_COMMAND_WHOIS, 
+                                 silc_client_notify_by_server_pending, p);
+      goto out;
+    }
+
+    /* Get old Client ID */
+    tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+    if (!tmp)
+      goto out;
+
+    client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+    /* Find old Client entry */
+    client_entry = 
+      silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
+    if (!client_entry)
+      goto out;
+
+    /* Remove the old from cache */
+    silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, 
+                          client_entry->id);
+
+    /* Replace old ID entry with new one on all channels. */
+    silc_client_replace_from_channels(client, conn, client_entry,
+                                     client_entry2);
+
+    /* Notify application */
+    client->ops->notify(client, conn, type, client_entry, client_entry2);
+
+    /* Free data */
+    if (client_entry->nickname)
+      silc_free(client_entry->nickname);
+    if (client_entry->server)
+      silc_free(client_entry->server);
+    if (client_entry->id)
+      silc_free(client_entry->id);
+    if (client_entry->send_key)
+      silc_cipher_free(client_entry->send_key);
+    if (client_entry->receive_key)
+      silc_cipher_free(client_entry->receive_key);
+    break;
+
+  case SILC_NOTIFY_TYPE_CMODE_CHANGE:
+    /*
+     * Someone changed a channel mode
+     */
+
+    /* Get Client ID */
+    tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+    if (!tmp)
+      goto out;
+
+    client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+    /* Find Client entry */
+    client_entry = 
+      silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
+    if (!client_entry)
+      goto out;
+
+    /* Get the mode */
+    tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+    if (!tmp)
+      goto out;
+
+    SILC_GET32_MSB(mode, tmp);
+
+    /* Get channel entry */
+    channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
+    if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
+                                    SILC_ID_CHANNEL, &id_cache))
+      break;
+
+    channel = (SilcChannelEntry)id_cache->context;
+
+    /* Save the new mode */
+    channel->mode = mode;
+
+    /* 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->ops->notify(client, conn, type, client_entry, mode, channel);
+    break;
+
+  case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
+    /*
+     * Someone changed user's mode on a channel
+     */
+
+    /* Get Client ID */
+    tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+    if (!tmp)
+      goto out;
+
+    client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+    /* Find Client entry */
+    client_entry = 
+      silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
+    if (!client_entry)
+      goto out;
+
+    /* Get the mode */
+    tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+    if (!tmp)
+      goto out;
+
+    SILC_GET32_MSB(mode, tmp);
+
+    /* Get target Client ID */
+    tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
+    if (!tmp)
+      goto out;
+
+    silc_free(client_id);
+    client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+    /* Find target Client entry */
+    client_entry2 = 
+      silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
+    if (!client_entry2)
+      goto out;
+
+    /* Get channel entry */
+    channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
+    if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
+                                    SILC_ID_CHANNEL, &id_cache))
+      break;
+
+    channel = (SilcChannelEntry)id_cache->context;
+
+    /* Save the mode */
+    for (i = 0; i < channel->clients_count; i++) {
+      if (channel->clients[i].client == client_entry2) {
+       channel->clients[i].mode = mode;
+       break;
+      }
+    }
+
+    /* 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->ops->notify(client, conn, type, client_entry, mode, 
+                       client_entry2, channel);
+    break;
+
+  case SILC_NOTIFY_TYPE_MOTD:
+    /*
+     * Received Message of the day
+     */
+
+    /* Get motd */
+    tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+    if (!tmp)
+      goto out;
+    
+    /* Notify application */
+    client->ops->notify(client, conn, type, tmp);
+    break;
+    
+  default:
+    break;
+  }
+
+ out:
+  silc_notify_payload_free(payload);
+  if (client_id)
+    silc_free(client_id);
+  if (channel_id)
+    silc_free(channel_id);
+}
+
+/* Processes the received new Client ID from server. Old Client ID is
+   deleted from cache and new one is added. */
+
+void silc_client_receive_new_id(SilcClient client,
+                               SilcSocketConnection sock,
+                               SilcIDPayload idp)
+{
+  SilcClientConnection conn = (SilcClientConnection)sock->user_data;
+
+  /* Delete old ID from ID cache */
+  silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, conn->local_id);
+  
+  /* Save the new ID */
+  if (conn->local_id)
+    silc_free(conn->local_id);
+  if (conn->local_id_data)
+    silc_free(conn->local_id_data);
+
+  conn->local_id = silc_id_payload_get_id(idp);
+  conn->local_id_data = silc_id_payload_get_data(idp);
+  conn->local_id_data_len = silc_id_payload_get_len(idp);;
+
+  if (!conn->local_entry)
+    conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
+
+  conn->local_entry->nickname = conn->nickname;
+  if (!conn->local_entry->username) {
+    conn->local_entry->username = 
+      silc_calloc(strlen(client->username) + strlen(client->hostname) + 1,
+                 sizeof(conn->local_entry->username));
+    sprintf(conn->local_entry->username, "%s@%s", client->username,
+           client->hostname);
+  }
+  conn->local_entry->id = conn->local_id;
+  
+  /* Put it to the ID cache */
+  silc_idcache_add(conn->client_cache, conn->nickname, SILC_ID_CLIENT,
+                  conn->local_id, (void *)conn->local_entry, TRUE);
+}
+
+/* Processed received Channel ID for a channel. This is called when client
+   joins to channel and server replies with channel ID. The ID is cached. */
+
+void silc_client_new_channel_id(SilcClient client,
+                               SilcSocketConnection sock,
+                               char *channel_name,
+                               unsigned int mode, SilcIDPayload idp)
+{
+  SilcClientConnection conn = (SilcClientConnection)sock->user_data;
+  SilcChannelEntry channel;
+
+  SILC_LOG_DEBUG(("New channel ID"));
+
+  channel = silc_calloc(1, sizeof(*channel));
+  channel->channel_name = channel_name;
+  channel->id = silc_id_payload_get_id(idp);
+  channel->mode = mode;
+  conn->current_channel = channel;
+
+  /* Put it to the ID cache */
+  silc_idcache_add(conn->channel_cache, channel_name, SILC_ID_CHANNEL,
+                  (void *)channel->id, (void *)channel, TRUE);
+}
+
+/* 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. 
+   This is the key that server has generated, this is not the channel
+   private key, it is entirely local setting. */
+
+void silc_client_receive_channel_key(SilcClient client,
+                                    SilcSocketConnection sock,
+                                    SilcBuffer packet)
+{
+  unsigned char *id_string, *key, *cipher;
+  unsigned int tmp_len;
+  SilcClientConnection conn = (SilcClientConnection)sock->user_data;
+  SilcChannelID *id;
+  SilcIDCacheEntry id_cache = NULL;
+  SilcChannelEntry channel;
+  SilcChannelKeyPayload payload;
+
+  SILC_LOG_DEBUG(("Received key for channel"));
+  
+  payload = silc_channel_key_payload_parse(packet);
+  if (!payload)
+    return;
+
+  id_string = silc_channel_key_get_id(payload, &tmp_len);
+  if (!id_string) {
+    silc_channel_key_payload_free(payload);
+    return;
+  }
+  id = silc_id_payload_parse_id(id_string, tmp_len);
+
+  /* Find channel. */
+  if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)id,
+                                  SILC_ID_CHANNEL, &id_cache))
+    goto out;
+    
+  /* Save the key */
+  key = silc_channel_key_get_key(payload, &tmp_len);
+  cipher = silc_channel_key_get_cipher(payload, NULL);
+
+  channel = (SilcChannelEntry)id_cache->context;
+  channel->key_len = tmp_len;
+  channel->key = silc_calloc(tmp_len, sizeof(*channel->key));
+  memcpy(channel->key, key, tmp_len);
+
+  if (!silc_cipher_alloc(cipher, &channel->channel_key)) {
+    client->ops->say(client, conn,
+                    "Cannot talk to channel: unsupported cipher %s", cipher);
+    goto out;
+  }
+  channel->channel_key->cipher->set_key(channel->channel_key->context, 
+                                       key, tmp_len);
+
+  /* Client is now joined to the channel */
+  channel->on_channel = TRUE;
+
+ out:
+  silc_free(id);
+  silc_channel_key_payload_free(payload);
+}
+
+/* Process received message to a channel (or from a channel, really). This
+   decrypts the channel message with channel specific key and parses the
+   channel payload. Finally it displays the message on the screen. */
+
+void silc_client_channel_message(SilcClient client, 
+                                SilcSocketConnection sock, 
+                                SilcPacketContext *packet)
+{
+  SilcClientConnection conn = (SilcClientConnection)sock->user_data;
+  SilcBuffer buffer = packet->buffer;
+  SilcChannelPayload payload = NULL;
+  SilcChannelID *id = NULL;
+  SilcChannelEntry channel;
+  SilcIDCacheEntry id_cache = NULL;
+  SilcClientID *client_id = NULL;
+  int i;
+  char *nickname;
+
+  /* Sanity checks */
+  if (packet->dst_id_type != SILC_ID_CHANNEL)
+    goto out;
+
+  client_id = silc_id_str2id(packet->src_id, SILC_ID_CLIENT);
+  id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
+
+  /* Find the channel entry from channels on this connection */
+  if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)id,
+                                  SILC_ID_CHANNEL, &id_cache))
+    goto out;
+
+  channel = (SilcChannelEntry)id_cache->context;
+
+  /* Decrypt the channel message payload. Push the IV out of the way,
+     since it is not encrypted (after pushing buffer->tail has the IV). */
+  silc_buffer_push_tail(buffer, 16);
+  channel->channel_key->cipher->decrypt(channel->channel_key->context,
+                                       buffer->data, buffer->data,
+                                       buffer->len, buffer->tail);
+  silc_buffer_pull_tail(buffer, 16);
+
+  /* Parse the channel message payload */
+  payload = silc_channel_payload_parse(buffer);
+  if (!payload)
+    goto out;
+
+  /* Find nickname */
+  nickname = "[unknown]";
+  for (i = 0; i < channel->clients_count; i++) {
+    if (channel->clients[i].client && 
+       !SILC_ID_CLIENT_COMPARE(channel->clients[i].client->id, client_id))
+      nickname = channel->clients[i].client->nickname;
+  }
+
+  /* Pass the message to application */
+  client->ops->channel_message(client, conn, nickname,
+                              channel->channel_name,
+                              silc_channel_get_data(payload, NULL));
+
+ out:
+  if (id)
+    silc_free(id);
+  if (client_id)
+    silc_free(client_id);
+  if (payload)
+    silc_channel_payload_free(payload);
+}
+
+/* Private message received. This processes the private message and
+   finally displays it on the screen. */
+
+void silc_client_private_message(SilcClient client, 
+                                SilcSocketConnection sock, 
+                                SilcPacketContext *packet)
+{
+  SilcClientConnection conn = (SilcClientConnection)sock->user_data;
+  SilcBuffer buffer = packet->buffer;
+  unsigned short nick_len;
+  unsigned char *nickname, *message;
+
+  /* Get nickname */
+  silc_buffer_unformat(buffer, 
+                      SILC_STR_UI16_NSTRING_ALLOC(&nickname, &nick_len),
+                      SILC_STR_END);
+  silc_buffer_pull(buffer, 2 + nick_len);
+     
+  message = silc_calloc(buffer->len + 1, sizeof(char));
+  memcpy(message, buffer->data, buffer->len);
+
+  /* Pass the private message to application */
+  client->ops->private_message(client, conn, nickname, message);
+
+  /* See if we are away (gone). If we are away we will reply to the
+     sender with the set away message. */
+  if (conn->away && conn->away->away) {
+    SilcClientID *remote_id;
+    SilcClientEntry remote_client;
+    SilcIDCacheEntry id_cache;
+
+    if (packet->src_id_type != SILC_ID_CLIENT)
+      goto out;
+
+    remote_id = silc_id_str2id(packet->src_id, SILC_ID_CLIENT);
+    if (!remote_id)
+      goto out;
+
+    /* If it's me, ignore */
+    if (!SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
+      goto out;
+
+    /* Check whether we know this client already */
+    if (!silc_idcache_find_by_id_one(conn->client_cache, remote_id,
+                                    SILC_ID_CLIENT, &id_cache))
+      {
+       /* Allocate client entry */
+       remote_client = silc_calloc(1, sizeof(*remote_client));
+       remote_client->id = remote_id;
+       silc_parse_nickname(nickname, &remote_client->nickname, 
+                           &remote_client->server, &remote_client->num);
+
+       /* Save the client to cache */
+       silc_idcache_add(conn->client_cache, remote_client->nickname,
+                        SILC_ID_CLIENT, remote_client->id, remote_client, 
+                        TRUE);
+      } else {
+       silc_free(remote_id);
+       remote_client = (SilcClientEntry)id_cache->context;
+      }
+
+    /* Send the away message */
+    silc_client_packet_send_private_message(client, sock, remote_client,
+                                           conn->away->away,
+                                           strlen(conn->away->away), TRUE);
+  }
+
+ out:
+  memset(message, 0, buffer->len);
+  silc_free(message);
+  silc_free(nickname);
+}
+
+/* Removes a client entry from all channel it has joined. This really is
+   a performance killer (client_entry should have pointers to channel 
+   entry list). */
+
+void silc_client_remove_from_channels(SilcClient client,
+                                     SilcClientConnection conn,
+                                     SilcClientEntry client_entry)
+{
+  SilcIDCacheEntry id_cache;
+  SilcIDCacheList list;
+  SilcChannelEntry channel;
+  int i;
+
+  if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
+                              SILC_ID_CHANNEL, &list))
+    return;
+
+  silc_idcache_list_first(list, &id_cache);
+  channel = (SilcChannelEntry)id_cache->context;
+  
+  while (channel) {
+    
+    /* Remove client from channel */
+    for (i = 0; i < channel->clients_count; i++) {
+      if (channel->clients[i].client == client_entry) {
+       channel->clients[i].client = NULL;
+       channel->clients_count--;
+       break;
+      }
+    }
+
+    if (!silc_idcache_list_next(list, &id_cache))
+      break;
+    
+    channel = (SilcChannelEntry)id_cache->context;
+  }
+
+  silc_idcache_list_free(list);
+}
+
+/* Replaces `old' client entries from all channels to `new' client entry.
+   This can be called for example when nickname changes and old ID entry
+   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, 
+                                      SilcClientConnection conn,
+                                      SilcClientEntry old,
+                                      SilcClientEntry new)
+{
+  SilcIDCacheEntry id_cache;
+  SilcIDCacheList list;
+  SilcChannelEntry channel;
+  int i;
+
+  if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
+                              SILC_ID_CHANNEL, &list))
+    return;
+
+  silc_idcache_list_first(list, &id_cache);
+  channel = (SilcChannelEntry)id_cache->context;
+  
+  while (channel) {
+    
+    /* Remove client from channel */
+    for (i = 0; i < channel->clients_count; i++) {
+      if (channel->clients[i].client == old) {
+       channel->clients[i].client = new;
+       break;
+      }
+    }
+
+    if (!silc_idcache_list_next(list, &id_cache))
+      break;
+    
+    channel = (SilcChannelEntry)id_cache->context;
+  }
+
+  silc_idcache_list_free(list);
+}
+
+/* Parses mode mask and returns the mode as string. */
+
+char *silc_client_chmode(unsigned int mode)
+{
+  char string[20];
+
+  if (!mode)
+    return NULL;
+
+  memset(string, 0, sizeof(string));
+
+  if (mode & SILC_CHANNEL_MODE_PRIVATE)
+    strncat(string, "p", 1);
+
+  if (mode & SILC_CHANNEL_MODE_SECRET)
+    strncat(string, "s", 1);
+
+  if (mode & SILC_CHANNEL_MODE_PRIVKEY)
+    strncat(string, "k", 1);
+
+  if (mode & SILC_CHANNEL_MODE_INVITE)
+    strncat(string, "i", 1);
+
+  if (mode & SILC_CHANNEL_MODE_TOPIC)
+    strncat(string, "t", 1);
+
+  if (mode & SILC_CHANNEL_MODE_ULIMIT)
+    strncat(string, "l", 1);
+
+  if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
+    strncat(string, "a", 1);
+
+  /* Rest of mode is ignored */
+
+  return strdup(string);
+}
+
+/* Parses channel user mode mask and returns te mode as string */
+
+char *silc_client_chumode(unsigned int mode)
+{
+  char string[4];
+
+  if (!mode)
+    return NULL;
+
+  memset(string, 0, sizeof(string));
+
+  if (mode & SILC_CHANNEL_UMODE_CHANFO)
+    strncat(string, "f", 1);
+
+  if (mode & SILC_CHANNEL_UMODE_CHANOP)
+    strncat(string, "o", 1);
+
+  return strdup(string);
+}
+
+/* Parses channel user mode and returns it as special mode character. */
+
+char *silc_client_chumode_char(unsigned int mode)
+{
+  char string[4];
+
+  if (!mode)
+    return NULL;
+
+  memset(string, 0, sizeof(string));
+
+  if (mode & SILC_CHANNEL_UMODE_CHANFO)
+    strncat(string, "*", 1);
+
+  if (mode & SILC_CHANNEL_UMODE_CHANOP)
+    strncat(string, "@", 1);
+
+  return strdup(string);
+}
similarity index 55%
rename from apps/silc/client.h
rename to lib/silcclient/client.h
index 661bd83a481604aad891dc11bc2d0263043af5ca..fdff610eee9e0ae4bcafa828d3540eeeafe0e81a 100644 (file)
 #ifndef CLIENT_H
 #define CLIENT_H
 
-/* Window structure used in client to associate all the important
-   connection (window) specific data to this structure. How the window
-   actually appears on the screen in handeled by the silc_screen*
-   routines in screen.c. */
-typedef struct {
+/* Forward declaration for client */
+typedef struct SilcClientObject *SilcClient;
+
+/* Forward declaration for client connection */
+typedef struct SilcClientConnectionObject *SilcClientConnection;
+
+#include "idlist.h"
+#include "command.h"
+#include "ops.h"
+
+/* 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. */
+typedef struct SilcClientPingStruct {
+  time_t start_time;
+  void *dest_id;
+  char *dest_name;
+} SilcClientPing;
+
+/* 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 
+   be set in one connection. */
+typedef struct SilcClientAwayStruct {
+  char *away;
+  struct SilcClientAwayStruct *next;
+} SilcClientAway;
+
+/* Connection structure used in client to associate all the important
+   connection specific data to this structure. */
+struct SilcClientConnectionObject {
   /*
    * Local data 
    */
@@ -48,11 +74,12 @@ typedef struct {
   char *remote_host;
   int remote_port;
   int remote_type;
+  char *remote_info;
 
-  /* Remote client ID for this connection */
-  SilcClientID *remote_id;
+  /* Remote server ID for this connection */
+  SilcServerID *remote_id;
 
-  /* Remote local ID so that the above defined ID would not have
+  /* Decoded remote ID so that the above defined ID would not have
      to be decoded for every packet. */
   unsigned char *remote_id_data;
   unsigned int remote_id_data_len;
@@ -63,7 +90,6 @@ typedef struct {
   /* Keys */
   SilcCipher send_key;
   SilcCipher receive_key;
-  SilcPKCS public_key;
   SilcHmac hmac;
   unsigned char *hmac_key;
   unsigned int hmac_key_len;
@@ -71,14 +97,11 @@ typedef struct {
   /* Client ID and Channel ID cache. Messages transmitted in SILC network
      are done using different unique ID's. These are the cache for
      thoses ID's used in the communication. */
-  SilcIDCache *client_id_cache[96];
-  unsigned int client_id_cache_count[96];
-  SilcIDCache *channel_id_cache[96];
-  unsigned int channel_id_cache_count[96];
-  SilcIDCache *server_id_cache;
-  unsigned int server_id_cache_count;
-
-  /* Current channel on window. All channel's are saved (allocated) into
+  SilcIDCache client_cache;
+  SilcIDCache channel_cache;
+  SilcIDCache server_cache;
+
+  /* Current channel on window. All channels are saved (allocated) into
      the cache entries. */
   SilcChannelEntry current_channel;
 
@@ -87,64 +110,74 @@ typedef struct {
      referencing (sock->user_data). */
   SilcSocketConnection sock;
 
-  /* The actual physical screen. This data is handled by the
-     screen handling routines. */
-  void *screen;
-} *SilcClientWindow;
+  /* Requested pings. */
+  SilcClientPing *ping;
+  unsigned int ping_count;
+
+  /* Set away message */
+  SilcClientAway *away;
+
+  /* Pointer back to the SilcClient. This object is passed to the application
+     and the actual client object is accesible through this pointer. */
+  SilcClient client;
+
+  /* User data context. Library does not touch this. */
+  void *context;
+};
+
+/* Main client structure. */
+struct SilcClientObject {
+  /*
+   * Public data. All the following pointers must be set by the allocator
+   * of this structure.
+   */
 
-typedef struct {
+  /* Users's username, hostname and realname. */
   char *username;
+  char *hostname;
   char *realname;
 
+  /* Private and public key of the user. */
+  SilcPKCS pkcs;
+  SilcPublicKey public_key;
+  SilcPrivateKey private_key;
+
+  /* Application specific user data pointer. Client library does not
+     touch this. */
+  void *application;
+
+  /*
+   * Private data. Following pointers are used internally by the client
+   * library and should be considered read-only fields.
+   */
+
+  /* All client operations that are implemented in the application. */
+  SilcClientOperations *ops;
+
   /* SILC client task queues */
   SilcTaskQueue io_queue;
   SilcTaskQueue timeout_queue;
   SilcTaskQueue generic_queue;
 
-  /* Input buffer that holds the characters user types. This is
-     used only to store the typed chars for a while. */
-  SilcBuffer input_buffer;
-
-  /* Table of windows in client. All the data, including connection
-     specific data, is saved in here. */
-  SilcClientWindow *windows;
-  unsigned int windows_count;
+  /* Table of connections in client. All the connection data is saved here. */
+  SilcClientConnection *conns;
+  unsigned int conns_count;
 
-  /* Currently active window. This is pointer to the window table 
-     defined above. This must never be free'd directly. */
-  SilcClientWindow current_win;
-
-  /* The SILC client screen object */
-  SilcScreen screen;
-
-  /* Generic cipher and hash objects */
+  /* Generic cipher and hash objects. These can be used and referenced
+     by the application as well. */
   SilcCipher none_cipher;
   SilcHash md5hash;
   SilcHash sha1hash;
   SilcHmac md5hmac;
   SilcHmac sha1hmac;
 
-  /* Configuration object */
-  SilcClientConfig config;
-
-  /* Random Number Generator */
+  /* Random Number Generator. Application should use this as its primary
+     random number generator. */
   SilcRng rng;
-
-#ifdef SILC_SIM
-  /* SIM (SILC Module) table */
-  SilcSimContext **sim;
-  unsigned int sim_count;
-#endif
-} SilcClientObject;
-
-typedef SilcClientObject *SilcClient;
+};
 
 /* Macros */
 
-#ifndef CTRL
-#define CTRL(x) ((x) & 0x1f)   /* Ctrl+x */
-#endif
-
 /* Registers generic task for file descriptor for reading from network and
    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. */
@@ -174,32 +207,31 @@ do {                                                              \
 do {                                                   \
   int __i;                                             \
                                                        \
-  for (__i = 0; __i < (__x)->windows_count; __i++)     \
-    if ((__x)->windows[__i]->sock->sock == (__fd))     \
+  for (__i = 0; __i < (__x)->conns_count; __i++)       \
+    if ((__x)->conns[__i]->sock->sock == (__fd))       \
       break;                                           \
                                                        \
-  if (__i >= (__x)->windows_count)                     \
+  if (__i >= (__x)->conns_count)                       \
     (__sock) = NULL;                                   \
- (__sock) = (__x)->windows[__i]->sock;                 \
+ (__sock) = (__x)->conns[__i]->sock;                   \
 } while(0)
 
-/* Returns TRUE if windows is currently active window */
-#define SILC_CLIENT_IS_CURRENT_WIN(__x, __win) ((__x)->current_win == (__win))
-
 /* Prototypes */
-int silc_client_alloc(SilcClient *new_client);
+
+SilcClient silc_client_alloc(SilcClientOperations *ops, void *application);
 void silc_client_free(SilcClient client);
 int silc_client_init(SilcClient client);
 void silc_client_stop(SilcClient client);
 void silc_client_run(SilcClient client);
-void silc_client_parse_command_line(unsigned char *buffer, 
-                                   unsigned char ***parsed,
-                                   unsigned int **parsed_lens,
-                                   unsigned int **parsed_types,
-                                   unsigned int *parsed_num,
-                                   unsigned int max_args);
+SilcClientConnection silc_client_add_connection(SilcClient client,
+                                               char *hostname,
+                                               int port,
+                                               void *context);
 int silc_client_connect_to_server(SilcClient client, int port,
-                                 char *host);
+                                 char *host, void *context);
+int silc_client_start_key_exchange(SilcClient client,
+                                  SilcClientConnection conn,
+                                   int fd);
 void silc_client_packet_send(SilcClient client, 
                             SilcSocketConnection sock,
                             SilcPacketType type, 
@@ -232,18 +264,32 @@ void silc_client_error_by_server(SilcClient client,
                                 SilcBuffer message);
 void silc_client_notify_by_server(SilcClient client,
                                  SilcSocketConnection sock,
-                                 SilcBuffer message);
+                                 SilcPacketContext *packet);
 void silc_client_receive_new_id(SilcClient client,
                                SilcSocketConnection sock,
-                               unsigned char *id_string);
+                               SilcIDPayload idp);
 void silc_client_new_channel_id(SilcClient client,
                                SilcSocketConnection sock,
                                char *channel_name,
-                               unsigned char *id_string);
+                               unsigned int mode, SilcIDPayload idp);
 void silc_client_receive_channel_key(SilcClient client,
                                     SilcSocketConnection sock,
                                     SilcBuffer packet);
 void silc_client_channel_message(SilcClient client, 
                                 SilcSocketConnection sock, 
                                 SilcPacketContext *packet);
+void silc_client_private_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, 
+                                      SilcClientConnection conn,
+                                      SilcClientEntry old,
+                                      SilcClientEntry new);
+char *silc_client_chmode(unsigned int mode);
+char *silc_client_chumode(unsigned int mode);
+char *silc_client_chumode_char(unsigned int mode);
+
 #endif
diff --git a/lib/silcclient/command.c b/lib/silcclient/command.c
new file mode 100644 (file)
index 0000000..1d21505
--- /dev/null
@@ -0,0 +1,1221 @@
+/*
+
+  command.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 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
+  GNU General Public License for more details.
+
+*/
+/* $Id$ */
+
+#include "clientlibincludes.h"
+
+/* Client command list. */
+SilcClientCommand silc_command_list[] =
+{
+  SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", SILC_CF_LAG | SILC_CF_REG, 3),
+  SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", SILC_CF_LAG | SILC_CF_REG, 3),
+  SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 
+                 SILC_CF_LAG | SILC_CF_REG, 3),
+  SILC_CLIENT_CMD(nick, NICK, "NICK", SILC_CF_LAG | SILC_CF_REG, 2),
+  SILC_CLIENT_CMD(list, LIST, "LIST", SILC_CF_LAG | SILC_CF_REG, 2),
+  SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", SILC_CF_LAG | SILC_CF_REG, 3),
+  SILC_CLIENT_CMD(invite, INVITE, "INVITE", SILC_CF_LAG | SILC_CF_REG, 3),
+  SILC_CLIENT_CMD(quit, QUIT, "QUIT", SILC_CF_LAG | SILC_CF_REG, 1),
+  SILC_CLIENT_CMD(kill, KILL, "KILL", 
+                 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
+  SILC_CLIENT_CMD(info, INFO, "INFO", SILC_CF_LAG | SILC_CF_REG, 2),
+  SILC_CLIENT_CMD(connect, CONNECT, "CONNECT",
+                 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
+  SILC_CLIENT_CMD(ping, PING, "PING", SILC_CF_LAG | SILC_CF_REG, 2),
+  SILC_CLIENT_CMD(oper, OPER, "OPER",
+                 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
+  SILC_CLIENT_CMD(join, JOIN, "JOIN", SILC_CF_LAG | SILC_CF_REG, 4),
+  SILC_CLIENT_CMD(motd, MOTD, "MOTD", SILC_CF_LAG | SILC_CF_REG, 2),
+  SILC_CLIENT_CMD(umode, UMODE, "UMODE", SILC_CF_LAG | SILC_CF_REG, 2),
+  SILC_CLIENT_CMD(cmode, CMODE, "CMODE", SILC_CF_LAG | SILC_CF_REG, 4),
+  SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", SILC_CF_LAG | SILC_CF_REG, 5),
+  SILC_CLIENT_CMD(kick, KICK, "KICK", SILC_CF_LAG | SILC_CF_REG, 2),
+  SILC_CLIENT_CMD(restart, RESTART, "RESTART",
+                 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
+  SILC_CLIENT_CMD(close, CLOSE, "CLOSE",
+                 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
+  SILC_CLIENT_CMD(die, DIE, "DIE",
+                 SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
+  SILC_CLIENT_CMD(silcoper, SILCOPER, "SILOPER",
+                 SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER, 2),
+  SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", SILC_CF_LAG | SILC_CF_REG, 2),
+  SILC_CLIENT_CMD(names, NAMES, "NAMES", SILC_CF_LAG | SILC_CF_REG, 2),
+
+  { NULL, 0, NULL, 0, 0 },
+};
+
+#define SILC_NOT_CONNECTED(x, c) \
+  x->ops->say((x), (c), \
+          "You are not connected to a server, use /SERVER to connect");
+
+/* Command operation that is called at the end of all commands. 
+   Usage: COMMAND; */
+#define COMMAND cmd->client->ops->command(cmd->client, cmd->conn, \
+  cmd, TRUE, cmd->command->cmd)
+
+/* Error to application. Usage: COMMAND_ERROR; */
+#define COMMAND_ERROR cmd->client->ops->command(cmd->client, cmd->conn, \
+  cmd, FALSE, cmd->command->cmd)
+
+/* List of pending commands. */
+SilcClientCommandPending *silc_command_pending = NULL;
+
+/* Generic function to send any command. The arguments must be sent already
+   encoded into correct form in correct order. */
+
+void silc_client_send_command(SilcClient client, SilcClientConnection conn,
+                             SilcCommand command, unsigned int argc, ...)
+{
+  SilcBuffer packet;
+  va_list ap;
+
+  va_start(ap, argc);
+
+  packet = silc_command_payload_encode_vap(command, 0, argc, ap);
+  silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND, 
+                         NULL, 0, NULL, NULL, packet->data, 
+                         packet->len, TRUE);
+  silc_buffer_free(packet);
+}
+
+/* Finds and returns a pointer to the command list. Return NULL if the
+   command is not found. */
+
+SilcClientCommand *silc_client_command_find(const char *name)
+{
+  SilcClientCommand *cmd;
+
+  for (cmd = silc_command_list; cmd->name; cmd++) {
+    if (!strcmp(cmd->name, name))
+      return cmd;
+  }
+
+  return NULL;
+}
+
+/* Add new pending command to the list of pending commands. Currently
+   pending commands are executed from command replies, thus we can
+   execute any command after receiving some specific command reply.
+
+   The argument `reply_cmd' is the command reply from where the callback
+   function is to be called, thus, it IS NOT the command to be executed.
+
+   XXX: If needed in the future this support may be extended for
+   commands as well, when any command could be executed after executing
+   some specific command. */
+
+void silc_client_command_pending(SilcCommand reply_cmd,
+                                SilcClientCommandCallback callback,
+                                void *context)
+{
+  SilcClientCommandPending *reply, *r;
+
+  reply = silc_calloc(1, sizeof(*reply));
+  reply->reply_cmd = reply_cmd;
+  reply->context = context;
+  reply->callback = callback;
+
+  if (silc_command_pending == NULL) {
+    silc_command_pending = reply;
+    return;
+  }
+
+  for (r = silc_command_pending; r; r = r->next) {
+    if (r->next == NULL) {
+      r->next = reply;
+      break;
+    }
+  }
+}
+
+/* Deletes pending command by reply command type. */
+
+void silc_client_command_pending_del(SilcCommand reply_cmd)
+{
+  SilcClientCommandPending *r, *tmp;
+  
+  if (silc_command_pending) {
+    if (silc_command_pending->reply_cmd == reply_cmd) {
+      silc_free(silc_command_pending);
+      silc_command_pending = NULL;
+      return;
+    }
+
+    for (r = silc_command_pending; r; r = r->next) {
+      if (r->next && r->next->reply_cmd == reply_cmd) {
+       tmp = r->next;
+       r->next = r->next->next;
+       silc_free(tmp);
+       break;
+      }
+    }
+  }
+}
+
+/* Free command context and its internals */
+
+void silc_client_command_free(SilcClientCommandContext cmd)
+{
+  int i;
+
+  if (cmd) {
+    for (i = 0; i < cmd->argc; i++)
+      silc_free(cmd->argv[i]);
+    silc_free(cmd);
+  }
+}
+
+/* Command WHOIS. This command is used to query information about 
+   specific user. */
+
+SILC_CLIENT_CMD_FUNC(whois)
+{
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClientConnection conn = cmd->conn;
+  SilcBuffer buffer;
+
+  if (!cmd->conn) {
+    SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  if (cmd->argc < 2 || cmd->argc > 3) {
+    cmd->client->ops->say(cmd->client, conn, 
+            "Usage: /WHOIS <nickname>[@<server>] [<count>]");
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  buffer = silc_command_payload_encode(SILC_COMMAND_WHOIS,
+                                      cmd->argc - 1, ++cmd->argv,
+                                      ++cmd->argv_lens, ++cmd->argv_types,
+                                      0);
+  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);
+  cmd->argv--;
+  cmd->argv_lens--;
+  cmd->argv_types--;
+
+  /* Notify application */
+  COMMAND;
+
+ out:
+  silc_client_command_free(cmd);
+}
+
+SILC_CLIENT_CMD_FUNC(whowas)
+{
+}
+
+/* Command IDENTIFY. This command is used to query information about 
+   specific user, especially ID's. */
+
+SILC_CLIENT_CMD_FUNC(identify)
+{
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClientConnection conn = cmd->conn;
+  SilcBuffer buffer;
+
+  if (!cmd->conn) {
+    SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  if (cmd->argc < 2 || cmd->argc > 3) {
+    cmd->client->ops->say(cmd->client, conn,
+            "Usage: /IDENTIFY <nickname>[@<server>] [<count>]");
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  buffer = silc_command_payload_encode(SILC_COMMAND_IDENTIFY,
+                                      cmd->argc - 1, ++cmd->argv,
+                                      ++cmd->argv_lens, ++cmd->argv_types,
+                                      0);
+  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);
+  cmd->argv--;
+  cmd->argv_lens--;
+  cmd->argv_types--;
+
+  /* Notify application */
+  COMMAND;
+
+ out:
+  silc_client_command_free(cmd);
+}
+
+/* Command NICK. Shows current nickname/sets new nickname on current
+   window. */
+
+SILC_CLIENT_CMD_FUNC(nick)
+{
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClientConnection conn = cmd->conn;
+  SilcBuffer buffer;
+
+  if (!cmd->conn) {
+    SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  if (!strncmp(conn->nickname, cmd->argv[1], cmd->argv_lens[1]))
+    goto out;
+
+  /* Show current nickname */
+  if (cmd->argc < 2) {
+    if (cmd->conn) {
+      cmd->client->ops->say(cmd->client, conn, 
+                           "Your nickname is %s on server %s", 
+                           conn->nickname, conn->remote_host);
+    } else {
+      cmd->client->ops->say(cmd->client, conn, 
+                           "Your nickname is %s", conn->nickname);
+    }
+
+    /* XXX Notify application */
+    COMMAND;
+    goto out;
+  }
+
+  /* Set new nickname */
+  buffer = silc_command_payload_encode(SILC_COMMAND_NICK,
+                                      cmd->argc - 1, ++cmd->argv,
+                                      ++cmd->argv_lens, ++cmd->argv_types,
+                                      0);
+  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);
+  cmd->argv--;
+  cmd->argv_lens--;
+  cmd->argv_types--;
+  if (conn->nickname)
+    silc_free(conn->nickname);
+  conn->nickname = strdup(cmd->argv[1]);
+
+  /* Notify application */
+  COMMAND;
+
+ out:
+  silc_client_command_free(cmd);
+}
+
+SILC_CLIENT_CMD_FUNC(list)
+{
+}
+
+/* Command TOPIC. Sets/shows topic on a channel. */
+
+SILC_CLIENT_CMD_FUNC(topic)
+{
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClientConnection conn = cmd->conn;
+  SilcIDCacheEntry id_cache = NULL;
+  SilcChannelEntry channel;
+  SilcBuffer buffer, idp;
+  char *name;
+
+  if (!cmd->conn) {
+    SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  if (cmd->argc < 2 || cmd->argc > 3) {
+    cmd->client->ops->say(cmd->client, conn,
+                         "Usage: /TOPIC <channel> [<topic>]");
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  if (cmd->argv[1][0] == '*') {
+    if (!conn->current_channel) {
+      cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
+      COMMAND_ERROR;
+      goto out;
+    }
+    name = conn->current_channel->channel_name;
+  } else {
+    name = cmd->argv[1];
+  }
+
+  if (!conn->current_channel) {
+    cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  /* Get the Channel ID of the channel */
+  if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
+    cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  channel = (SilcChannelEntry)id_cache->context;
+
+  /* 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, 0, 2, 
+                                           1, idp->data, idp->len,
+                                           2, cmd->argv[2], 
+                                           strlen(cmd->argv[2]));
+  else
+    buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC, 1, 
+                                           1, idp->data, idp->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);
+
+  /* Notify application */
+  COMMAND;
+
+ out:
+  silc_client_command_free(cmd);
+}
+
+/* Command INVITE. Invites specific client to join a channel. */
+
+SILC_CLIENT_CMD_FUNC(invite)
+{
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClient client = cmd->client;
+  SilcClientConnection conn = cmd->conn;
+  SilcClientEntry client_entry;
+  SilcChannelEntry channel_entry;
+  SilcBuffer buffer, clidp, chidp;
+  unsigned int num = 0;
+  char *nickname = NULL, *server = NULL;
+
+  if (!cmd->conn) {
+    SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  if (cmd->argc != 3) {
+    cmd->client->ops->say(cmd->client, conn,
+                         "Usage: /INVITE <nickname>[@<server>] <channel>");
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  /* Parse the typed nickname. */
+  if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
+    cmd->client->ops->say(cmd->client, conn, "Bad nickname");
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  /* Find client entry */
+  client_entry = silc_idlist_get_client(client, conn, nickname, server, num);
+  if (!client_entry) {
+    if (nickname)
+      silc_free(nickname);
+    if (server)
+      silc_free(server);
+
+    /* Client entry not found, it was requested thus mark this to be
+       pending command. */
+    silc_client_command_pending(SILC_COMMAND_IDENTIFY, 
+                               silc_client_command_invite, context);
+    return;
+  }
+
+  /* Find channel entry */
+  channel_entry = silc_idlist_get_channel(client, conn, cmd->argv[2]);
+  if (!channel_entry) {
+    cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  /* Send command */
+  clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
+  chidp = silc_id_payload_encode(channel_entry->id, SILC_ID_CHANNEL);
+  buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE, 0, 2,
+                                         1, clidp->data, clidp->len,
+                                         2, chidp->data, chidp->len);
+  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(clidp);
+  silc_buffer_free(chidp);
+
+  cmd->client->ops->say(cmd->client, conn, 
+                       "Inviting %s to channel %s", cmd->argv[1], 
+                       cmd->argv[2]);
+
+  /* Notify application */
+  COMMAND;
+
+ out:
+  silc_client_command_free(cmd);
+}
+
+/* Command QUIT. Closes connection with current server. */
+SILC_CLIENT_CMD_FUNC(quit)
+{
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcBuffer buffer;
+
+  if (!cmd->conn) {
+    SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1, 
+                                      ++cmd->argv, ++cmd->argv_lens,
+                                      ++cmd->argv_types, 0);
+  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);
+  cmd->argv--;
+  cmd->argv_lens--;
+  cmd->argv_types--;
+
+  /* Close connection */
+  silc_client_close_connection(cmd->client, cmd->conn->sock);
+  cmd->client->ops->disconnect(cmd->client, cmd->conn);
+
+  /* Notify application */
+  COMMAND;
+
+ out:
+  silc_client_command_free(cmd);
+}
+
+SILC_CLIENT_CMD_FUNC(kill)
+{
+}
+
+/* Command INFO. Request information about specific server. If specific
+   server is not provided the current server is used. */
+
+SILC_CLIENT_CMD_FUNC(info)
+{
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClientConnection conn = cmd->conn;
+  SilcBuffer buffer;
+  char *name;
+
+  if (!cmd->conn) {
+    SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  if (cmd->argc < 2)
+    name = strdup(conn->remote_host);
+  else
+    name = strdup(cmd->argv[1]);
+
+  /* Send the command */
+  buffer = silc_command_payload_encode_va(SILC_COMMAND_INFO, 0, 1, 
+                                         1, name, strlen(name));
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+                         0, NULL, NULL, buffer->data, buffer->len, TRUE);
+  silc_buffer_free(buffer);
+
+  /* Notify application */
+  COMMAND;
+
+ out:
+  silc_client_command_free(cmd);
+}
+
+SILC_CLIENT_CMD_FUNC(connect)
+{
+}
+
+/* Command PING. Sends ping to server. This is used to test the 
+   communication channel. */
+
+SILC_CLIENT_CMD_FUNC(ping)
+{
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClientConnection conn = cmd->conn;
+  SilcBuffer buffer;
+  void *id;
+  int i;
+  char *name = NULL;
+
+  if (!cmd->conn) {
+    SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  if (cmd->argc == 1 || !strcmp(cmd->argv[1], conn->remote_host))
+    name = strdup(conn->remote_host);
+
+  /* Send the command */
+  buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1, 
+                                         1, conn->remote_id_data, 
+                                         SILC_ID_SERVER_LEN);
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+                         0, NULL, NULL, buffer->data, buffer->len, TRUE);
+  silc_buffer_free(buffer);
+
+  id = silc_id_str2id(conn->remote_id_data, SILC_ID_SERVER);
+
+  /* Start counting time */
+  for (i = 0; i < conn->ping_count; i++) {
+    if (conn->ping[i].dest_id == NULL) {
+      conn->ping[i].start_time = time(NULL);
+      conn->ping[i].dest_id = id;
+      conn->ping[i].dest_name = name;
+      conn->ping_count++;
+      break;
+    }
+  }
+  if (i >= conn->ping_count) {
+    i = conn->ping_count;
+    conn->ping = silc_realloc(conn->ping, sizeof(*conn->ping) * (i + 1));
+    conn->ping[i].start_time = time(NULL);
+    conn->ping[i].dest_id = id;
+    conn->ping[i].dest_name = name;
+    conn->ping_count++;
+  }
+  
+  /* Notify application */
+  COMMAND;
+
+ out:
+  silc_client_command_free(cmd);
+}
+
+SILC_CLIENT_CMD_FUNC(oper)
+{
+}
+
+SILC_CLIENT_CMD_FUNC(trace)
+{
+}
+
+SILC_CLIENT_CMD_FUNC(notice)
+{
+}
+
+/* Command JOIN. Joins to a channel. */
+
+SILC_CLIENT_CMD_FUNC(join)
+{
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClientConnection conn = cmd->conn;
+  SilcIDCacheEntry id_cache = NULL;
+  SilcBuffer buffer;
+
+  if (!cmd->conn) {
+    SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  if (cmd->argc < 2) {
+    /* Show channels currently joined to */
+
+    goto out;
+  }
+
+  /* See if we have joined to the requested channel already */
+  if (silc_idcache_find_by_data_one(conn->channel_cache, cmd->argv[1],
+                                   &id_cache)) {
+    cmd->client->ops->say(cmd->client, conn, 
+                         "You are talking to channel %s", cmd->argv[1]);
+    conn->current_channel = (SilcChannelEntry)id_cache->context;
+#if 0
+    cmd->client->screen->bottom_line->channel = cmd->argv[1];
+    silc_screen_print_bottom_line(cmd->client->screen, 0);
+#endif
+    goto out;
+  }
+
+  /* Send JOIN command to the server */
+  if (cmd->argc == 2)
+    buffer = 
+      silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 1,
+                                    1, cmd->argv[1], cmd->argv_lens[1]);
+  else if (cmd->argc == 3)
+    /* XXX Buggy */
+    buffer = 
+      silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 2,
+                                    1, cmd->argv[1], cmd->argv_lens[1],
+                                    2, cmd->argv[2], cmd->argv_lens[2]);
+  else
+    buffer = 
+      silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 3,
+                                    1, cmd->argv[1], cmd->argv_lens[1],
+                                    2, cmd->argv[2], cmd->argv_lens[2],
+                                    3, cmd->argv[3], cmd->argv_lens[3]);
+
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+                         0, NULL, NULL, buffer->data, buffer->len, TRUE);
+  silc_buffer_free(buffer);
+
+  /* Notify application */
+  COMMAND;
+
+ out:
+  silc_client_command_free(cmd);
+}
+
+/* MOTD command. Requests motd from server. */
+
+SILC_CLIENT_CMD_FUNC(motd)
+{
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClientConnection conn = cmd->conn;
+  SilcBuffer buffer;
+
+  if (!cmd->conn) {
+    SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  if (cmd->argc < 1 || cmd->argc > 1) {
+    cmd->client->ops->say(cmd->client, conn,
+                         "Usage: /MOTD");
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  /* Send TOPIC command to the server */
+  buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1, 
+                                         2, conn->remote_host, 
+                                         strlen(conn->remote_host));
+  silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL, 
+                         0, NULL, NULL, buffer->data, buffer->len, TRUE);
+  silc_buffer_free(buffer);
+
+  /* Notify application */
+  COMMAND;
+
+ out:
+  silc_client_command_free(cmd);
+}
+
+/* UMODE. Set user mode in SILC. */
+
+SILC_CLIENT_CMD_FUNC(umode)
+{
+
+}
+
+/* CMODE command. Sets channel mode. Modes that does not require any arguments
+   can be set several at once. Those modes that require argument must be set
+   separately (unless set with modes that does not require arguments). */
+
+SILC_CLIENT_CMD_FUNC(cmode)
+{
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClientConnection conn = cmd->conn;
+  SilcChannelEntry channel;
+  SilcBuffer buffer, chidp;
+  unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
+  unsigned int mode, add, type, len, arg_len = 0;
+  int i;
+
+  if (!cmd->conn) {
+    SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  if (cmd->argc < 3) {
+    cmd->client->ops->say(cmd->client, conn, 
+                 "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  if (cmd->argv[1][0] == '*') {
+    if (!conn->current_channel) {
+      cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
+      COMMAND_ERROR;
+      goto out;
+    }
+
+    channel = conn->current_channel;
+  } else {
+    name = cmd->argv[1];
+
+    channel = silc_idlist_get_channel(cmd->client, conn, name);
+    if (!channel) {
+      cmd->client->ops->say(cmd->client, conn, "You are on that channel");
+      COMMAND_ERROR;
+      goto out;
+    }
+  }
+
+  mode = channel->mode;
+
+  /* Are we adding or removing mode */
+  if (cmd->argv[2][0] == '-')
+    add = FALSE;
+  else
+    add = TRUE;
+
+  /* Argument type to be sent to server */
+  type = 0;
+
+  /* Parse mode */
+  cp = cmd->argv[2] + 1;
+  len = strlen(cp);
+  for (i = 0; i < len; i++) {
+    switch(cp[i]) {
+    case 'p':
+      if (add)
+       mode |= SILC_CHANNEL_MODE_PRIVATE;
+      else
+       mode &= ~SILC_CHANNEL_MODE_PRIVATE;
+      break;
+    case 's':
+      if (add)
+       mode |= SILC_CHANNEL_MODE_SECRET;
+      else
+       mode &= ~SILC_CHANNEL_MODE_SECRET;
+      break;
+    case 'k':
+      if (add)
+       mode |= SILC_CHANNEL_MODE_PRIVKEY;
+      else
+       mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
+      break;
+    case 'i':
+      if (add)
+       mode |= SILC_CHANNEL_MODE_INVITE;
+      else
+       mode &= ~SILC_CHANNEL_MODE_INVITE;
+      break;
+    case 't':
+      if (add)
+       mode |= SILC_CHANNEL_MODE_TOPIC;
+      else
+       mode &= ~SILC_CHANNEL_MODE_TOPIC;
+      break;
+    case 'l':
+      if (add) {
+       int ll;
+       mode |= SILC_CHANNEL_MODE_ULIMIT;
+       type = 3;
+       ll = atoi(cmd->argv[3]);
+       SILC_PUT32_MSB(ll, tmp);
+       arg = tmp;
+       arg_len = 4;
+      } else {
+       mode &= ~SILC_CHANNEL_MODE_ULIMIT;
+      }
+      break;
+    case 'a':
+      if (add) {
+       mode |= SILC_CHANNEL_MODE_PASSPHRASE;
+       type = 4;
+       arg = cmd->argv[3];
+       arg_len = cmd->argv_lens[3];
+      } else {
+       mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
+      }
+      break;
+    case 'b':
+      if (add) {
+       mode |= SILC_CHANNEL_MODE_BAN;
+       type = 5;
+       arg = cmd->argv[3];
+       arg_len = cmd->argv_lens[3];
+      } else {
+       mode &= ~SILC_CHANNEL_MODE_BAN;
+      }
+      break;
+    case 'I':
+      if (add) {
+       mode |= SILC_CHANNEL_MODE_INVITE_LIST;
+       type = 6;
+       arg = cmd->argv[3];
+       arg_len = cmd->argv_lens[3];
+      } else {
+       mode &= ~SILC_CHANNEL_MODE_INVITE_LIST;
+      }
+      break;
+    case 'c':
+      if (add) {
+       mode |= SILC_CHANNEL_MODE_CIPHER;
+       type = 8;
+       arg = cmd->argv[3];
+       arg_len = cmd->argv_lens[3];
+      } else {
+       mode &= ~SILC_CHANNEL_MODE_CIPHER;
+      }
+      break;
+    default:
+      COMMAND_ERROR;
+      goto out;
+      break;
+    }
+  }
+
+  if (type && cmd->argc < 3) {
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+  SILC_PUT32_MSB(mode, modebuf);
+
+  /* Send the command packet. We support sending only one mode at once
+     that requires an argument. */
+  if (type && arg) {
+    buffer = 
+      silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3, 
+                                    1, chidp->data, chidp->len, 
+                                    2, modebuf, sizeof(modebuf),
+                                    type, arg, arg_len);
+  } else {
+    buffer = 
+      silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2, 
+                                    1, chidp->data, chidp->len, 
+                                    2, modebuf, sizeof(modebuf));
+  }
+
+  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);
+
+  /* Notify application */
+  COMMAND;
+
+ out:
+  silc_client_command_free(cmd);
+}
+
+/* CUMODE command. Changes client's mode on a channel. */
+
+SILC_CLIENT_CMD_FUNC(cumode)
+{
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClientConnection conn = cmd->conn;
+  SilcChannelEntry channel;
+  SilcClientEntry client_entry;
+  SilcBuffer buffer, clidp, chidp;
+  unsigned char *name, *cp, modebuf[4];
+  unsigned int mode = 0, add, len;
+  char *nickname = NULL, *server = NULL;
+  unsigned int num = 0;
+  int i;
+
+  if (!cmd->conn) {
+    SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  if (cmd->argc < 4) {
+    cmd->client->ops->say(cmd->client, conn, 
+                 "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  if (cmd->argv[1][0] == '*') {
+    if (!conn->current_channel) {
+      cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
+      COMMAND_ERROR;
+      goto out;
+    }
+
+    channel = conn->current_channel;
+  } else {
+    name = cmd->argv[1];
+
+    channel = silc_idlist_get_channel(cmd->client, conn, name);
+    if (!channel) {
+      cmd->client->ops->say(cmd->client, conn, "You are on that channel");
+      COMMAND_ERROR;
+      goto out;
+    }
+  }
+
+  /* Parse the typed nickname. */
+  if (!silc_parse_nickname(cmd->argv[3], &nickname, &server, &num)) {
+    cmd->client->ops->say(cmd->client, conn, "Bad nickname");
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  /* Find client entry */
+  client_entry = silc_idlist_get_client(cmd->client, conn, 
+                                       nickname, server, num);
+  if (!client_entry) {
+    /* Client entry not found, it was requested thus mark this to be
+       pending command. */
+    silc_client_command_pending(SILC_COMMAND_CUMODE, 
+                               silc_client_command_cumode, context);
+    return;
+  }
+  
+  for (i = 0; i < channel->clients_count; i++)
+    if (channel->clients[i].client == client_entry) {
+      mode = channel->clients[i].mode;
+      break;
+    }
+
+  /* Are we adding or removing mode */
+  if (cmd->argv[2][0] == '-')
+    add = FALSE;
+  else
+    add = TRUE;
+
+  /* Parse mode */
+  cp = cmd->argv[2] + 1;
+  len = strlen(cp);
+  for (i = 0; i < len; i++) {
+    switch(cp[i]) {
+    case 'a':
+      if (add) {
+       mode |= SILC_CHANNEL_UMODE_CHANFO;
+       mode |= SILC_CHANNEL_UMODE_CHANOP;
+      } else {
+       mode = SILC_CHANNEL_UMODE_NONE;
+      }
+      break;
+    case 'f':
+      if (add)
+       mode |= SILC_CHANNEL_UMODE_CHANFO;
+      else
+       mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+      break;
+    case 'o':
+      if (add)
+       mode |= SILC_CHANNEL_UMODE_CHANOP;
+      else
+       mode &= ~SILC_CHANNEL_UMODE_CHANOP;
+      break;
+    default:
+      COMMAND_ERROR;
+      goto out;
+      break;
+    }
+  }
+
+  chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+  SILC_PUT32_MSB(mode, modebuf);
+  clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
+
+  /* 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, 3, 
+                                         1, chidp->data, chidp->len, 
+                                         2, modebuf, 4,
+                                         3, clidp->data, clidp->len);
+
+  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);
+  
+  /* Notify application */
+  COMMAND;
+
+ out:
+  silc_client_command_free(cmd);
+}
+
+/* KICK command. Kicks a client out of channel. */
+
+SILC_CLIENT_CMD_FUNC(kick)
+{
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClientConnection conn = cmd->conn;
+
+}
+
+SILC_CLIENT_CMD_FUNC(restart)
+{
+}
+SILC_CLIENT_CMD_FUNC(close)
+{
+}
+SILC_CLIENT_CMD_FUNC(die)
+{
+}
+SILC_CLIENT_CMD_FUNC(silcoper)
+{
+}
+
+/* LEAVE command. Leaves a channel. Client removes itself from a channel. */
+
+SILC_CLIENT_CMD_FUNC(leave)
+{
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClientConnection conn = cmd->conn;
+  SilcIDCacheEntry id_cache = NULL;
+  SilcChannelEntry channel;
+  SilcBuffer buffer, idp;
+  char *name;
+
+  if (!cmd->conn) {
+    SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  if (cmd->argc != 2) {
+    cmd->client->ops->say(cmd->client, conn, "Usage: /LEAVE <channel>");
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  if (cmd->argv[1][0] == '*') {
+    if (!conn->current_channel) {
+      cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
+      COMMAND_ERROR;
+      goto out;
+    }
+    name = conn->current_channel->channel_name;
+  } else {
+    name = cmd->argv[1];
+  }
+
+  if (!conn->current_channel) {
+    cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  /* Get the Channel ID of the channel */
+  if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
+    cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  channel = (SilcChannelEntry)id_cache->context;
+
+  /* Send LEAVE command to the server */
+  idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
+  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, 
+                         0, NULL, NULL, buffer->data, buffer->len, TRUE);
+  silc_buffer_free(buffer);
+  silc_buffer_free(idp);
+
+  /* We won't talk anymore on this channel */
+  cmd->client->ops->say(cmd->client, conn, "You have left channel %s", name);
+
+  conn->current_channel = NULL;
+
+  silc_idcache_del_by_id(conn->channel_cache, SILC_ID_CHANNEL, channel->id);
+  silc_free(channel->channel_name);
+  silc_free(channel->id);
+  silc_free(channel->key);
+  silc_cipher_free(channel->channel_key);
+  silc_free(channel);
+
+  /* Notify application */
+  COMMAND;
+
+ out:
+  silc_client_command_free(cmd);
+}
+
+/* Command NAMES. Requests the names of the clients joined on requested
+   channel. */
+
+SILC_CLIENT_CMD_FUNC(names)
+{
+  SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+  SilcClientConnection conn = cmd->conn;
+  SilcIDCacheEntry id_cache = NULL;
+  SilcBuffer buffer, idp;
+  char *name;
+
+  if (!cmd->conn) {
+    SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  if (cmd->argc != 2) {
+    cmd->client->ops->say(cmd->client, conn, "Usage: /NAMES <channel>");
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  if (cmd->argv[1][0] == '*')
+    name = conn->current_channel->channel_name;
+  else
+    name = cmd->argv[1];
+
+  /* Get the Channel ID of the channel */
+  if (!silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
+    /* XXX should resolve the channel ID; LIST command */
+    cmd->client->ops->say(cmd->client, conn, 
+                         "You are not on that channel", name);
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  /* Send NAMES command to the server */
+  idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
+  buffer = silc_command_payload_encode_va(SILC_COMMAND_NAMES, 0, 1, 
+                                         1, idp->data, idp->len);
+  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);
+
+  /* Register dummy pending command that will tell the reply command
+     that user called this command. Server may send reply to this command
+     even if user did not send this command thus we want to handle things
+     differently when user sent the command. This is dummy and won't be
+     executed. */
+  /* XXX this is kludge and should be removed after pending command reply 
+     support is added. Currently only commands may be pending not command
+     replies. */
+  silc_client_command_pending(SILC_COMMAND_NAMES, 
+                             silc_client_command_names, NULL);
+
+  /* Notify application */
+  COMMAND;
+
+ out:
+  silc_client_command_free(cmd);
+}
similarity index 92%
rename from apps/silc/command.h
rename to lib/silcclient/command.h
index 19db809b936484e47199e6a98002ca3dbce81cfb..11163ac4b2ba52220dcbf9ca31f89c4fa3803229 100644 (file)
@@ -66,7 +66,8 @@ typedef void (*SilcClientCommandCallback)(void *context);
 /* Context sent as argument to all commands */
 typedef struct {
   SilcClient client;
-  SilcSocketConnection sock;
+  SilcClientConnection conn;
+  SilcClientCommand *command;
   unsigned int argc;
   unsigned char **argv;
   unsigned int *argv_lens;
@@ -126,6 +127,10 @@ do {                                                       \
 } while(0)
 
 /* Prototypes */
+void silc_client_command_free(SilcClientCommandContext cmd);
+void silc_client_send_command(SilcClient client, SilcClientConnection conn,
+                             SilcCommand command, unsigned int argc, ...);
+SilcClientCommand *silc_client_command_find(const char *name);
 void silc_client_command_pending(SilcCommand reply_cmd,
                                 SilcClientCommandCallback callback,
                                 void *context);
@@ -134,7 +139,6 @@ SILC_CLIENT_CMD_FUNC(whois);
 SILC_CLIENT_CMD_FUNC(whowas);
 SILC_CLIENT_CMD_FUNC(identify);
 SILC_CLIENT_CMD_FUNC(nick);
-SILC_CLIENT_CMD_FUNC(server);
 SILC_CLIENT_CMD_FUNC(list);
 SILC_CLIENT_CMD_FUNC(topic);
 SILC_CLIENT_CMD_FUNC(invite);
@@ -148,6 +152,7 @@ SILC_CLIENT_CMD_FUNC(join);
 SILC_CLIENT_CMD_FUNC(motd);
 SILC_CLIENT_CMD_FUNC(umode);
 SILC_CLIENT_CMD_FUNC(cmode);
+SILC_CLIENT_CMD_FUNC(cumode);
 SILC_CLIENT_CMD_FUNC(kick);
 SILC_CLIENT_CMD_FUNC(restart);
 SILC_CLIENT_CMD_FUNC(close);
@@ -155,10 +160,5 @@ SILC_CLIENT_CMD_FUNC(die);
 SILC_CLIENT_CMD_FUNC(silcoper);
 SILC_CLIENT_CMD_FUNC(leave);
 SILC_CLIENT_CMD_FUNC(names);
-SILC_CLIENT_CMD_FUNC(help);
-SILC_CLIENT_CMD_FUNC(clear);
-SILC_CLIENT_CMD_FUNC(version);
-SILC_CLIENT_CMD_FUNC(msg);
-SILC_CLIENT_CMD_FUNC(away);
 
 #endif
diff --git a/lib/silcclient/command_reply.c b/lib/silcclient/command_reply.c
new file mode 100644 (file)
index 0000000..8b2f0c3
--- /dev/null
@@ -0,0 +1,1145 @@
+/*
+
+  command_reply.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 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
+  GNU General Public License for more details.
+
+*/
+/*
+ * Command reply functions are "the otherside" of the command functions.
+ * Reply to a command sent by server is handled by these functions.
+ *
+ * The arguments received from server are also passed to the calling
+ * 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 
+ * 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
+ * received but ID entry does not exist, NULL is sent.
+ */
+/* $Id$ */
+
+#include "clientlibincludes.h"
+
+/* Client command reply list. */
+SilcClientCommandReply silc_command_reply_list[] =
+{
+  SILC_CLIENT_CMD_REPLY(whois, WHOIS),
+  SILC_CLIENT_CMD_REPLY(whowas, WHOWAS),
+  SILC_CLIENT_CMD_REPLY(identify, IDENTIFY),
+  SILC_CLIENT_CMD_REPLY(nick, NICK),
+  SILC_CLIENT_CMD_REPLY(list, LIST),
+  SILC_CLIENT_CMD_REPLY(topic, TOPIC),
+  SILC_CLIENT_CMD_REPLY(invite, INVITE),
+  SILC_CLIENT_CMD_REPLY(quit, QUIT),
+  SILC_CLIENT_CMD_REPLY(kill, KILL),
+  SILC_CLIENT_CMD_REPLY(info, INFO),
+  SILC_CLIENT_CMD_REPLY(connect, CONNECT),
+  SILC_CLIENT_CMD_REPLY(ping, PING),
+  SILC_CLIENT_CMD_REPLY(oper, OPER),
+  SILC_CLIENT_CMD_REPLY(join, JOIN),
+  SILC_CLIENT_CMD_REPLY(motd, MOTD),
+  SILC_CLIENT_CMD_REPLY(umode, UMODE),
+  SILC_CLIENT_CMD_REPLY(cmode, CMODE),
+  SILC_CLIENT_CMD_REPLY(cumode, CUMODE),
+  SILC_CLIENT_CMD_REPLY(kick, KICK),
+  SILC_CLIENT_CMD_REPLY(restart, RESTART),
+  SILC_CLIENT_CMD_REPLY(close, CLOSE),
+  SILC_CLIENT_CMD_REPLY(die, DIE),
+  SILC_CLIENT_CMD_REPLY(silcoper, SILCOPER),
+  SILC_CLIENT_CMD_REPLY(leave, LEAVE),
+  SILC_CLIENT_CMD_REPLY(names, NAMES),
+
+  { NULL, 0 },
+};
+
+/* Status message structure. Messages are defined below. */
+typedef struct {
+  SilcCommandStatus status;
+  char *message;
+} SilcCommandStatusMessage;
+
+/* Status messages returned by the server */
+#define STAT(x) SILC_STATUS_ERR_##x
+const SilcCommandStatusMessage silc_command_status_messages[] = {
+
+  { STAT(NO_SUCH_NICK),      "No such nickname" },
+  { STAT(NO_SUCH_CHANNEL),   "No such channel" },
+  { STAT(NO_SUCH_SERVER),    "No such server" },
+  { STAT(TOO_MANY_TARGETS),  "Duplicate recipients. No message delivered" },
+  { STAT(NO_RECIPIENT),      "No recipient given" },
+  { STAT(UNKNOWN_COMMAND),   "Unknown command" },
+  { STAT(WILDCARDS),         "Unknown command" },
+  { STAT(NO_CLIENT_ID),      "No Client ID given" },
+  { STAT(NO_CHANNEL_ID),     "No Channel ID given" },
+  { STAT(NO_SERVER_ID),      "No Server ID given" },
+  { STAT(BAD_CLIENT_ID),     "Bad Client ID" },
+  { STAT(BAD_CHANNEL_ID),    "Bad Channel ID" },
+  { STAT(NO_SUCH_CLIENT_ID), "No such Client ID" },
+  { STAT(NO_SUCH_CHANNEL_ID),"No such Channel ID" },
+  { STAT(NICKNAME_IN_USE),   "Nickname already exists" },
+  { STAT(NOT_ON_CHANNEL),    "You are not on that channel" },
+  { STAT(USER_NOT_ON_CHANNEL),"They are not on the channel" },
+  { STAT(USER_ON_CHANNEL),   "User already on the channel" },
+  { STAT(NOT_REGISTERED),    "You have not registered" },
+  { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
+  { STAT(TOO_MANY_PARAMS),   "Too many parameters" },
+  { STAT(PERM_DENIED),       "Your host is not among the privileged" },
+  { STAT(BANNED_FROM_SERVER),"You are banned from this server" },
+  { STAT(BAD_PASSWORD),      "Cannot join channel. Incorrect password" },
+  { STAT(CHANNEL_IS_FULL),   "Cannot join channel. Channel is full" },
+  { STAT(NOT_INVITED),     "Cannot join channel. You have not been invited" },
+  { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
+  { STAT(UNKNOWN_MODE),    "Unknown mode" },
+  { STAT(NOT_YOU),         "Cannot change mode for other users" },
+  { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
+  { STAT(NO_SERVER_PRIV),  "Permission denied. You are not server operator" },
+  { STAT(NO_ROUTER_PRIV),  "Permission denied. You are not SILC operator" },
+  { STAT(BAD_NICKNAME),    "Bad nickname" },
+  { STAT(BAD_CHANNEL),     "Bad channel name" },
+  { STAT(AUTH_FAILED),     "Authentication failed" },
+
+  { 0, NULL }
+};
+
+/* 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->ops->command_reply args
+#define ARGS cmd->client, cmd->sock->user_data, \
+             cmd->payload, TRUE, silc_command_get(cmd->payload), status
+
+/* Error reply to application. Usage: COMMAND_REPLY_ERROR; */
+#define COMMAND_REPLY_ERROR cmd->client->ops->command_reply(cmd->client, \
+  cmd->sock->user_data, cmd->payload, FALSE, \
+  silc_command_get(cmd->payload), status)
+
+/* Process received command reply. */
+
+void silc_client_command_reply_process(SilcClient client,
+                                      SilcSocketConnection sock,
+                                      SilcPacketContext *packet)
+{
+  SilcBuffer buffer = packet->buffer;
+  SilcClientCommandReplyContext ctx;
+  SilcCommandPayload payload;
+
+  /* Get command reply payload from packet */
+  payload = silc_command_payload_parse(buffer);
+  if (!payload) {
+    /* Silently ignore bad reply packet */
+    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));
+  ctx->client = client;
+  ctx->sock = sock;
+  ctx->payload = payload;
+  ctx->args = silc_command_get_args(ctx->payload);
+  ctx->packet = packet;
+      
+  /* Check for pending commands and mark to be exeucted */
+  SILC_CLIENT_COMMAND_CHECK_PENDING(ctx);
+  
+  /* Execute command reply */
+  SILC_CLIENT_COMMAND_REPLY_EXEC(ctx);
+}
+
+/* Returns status message string */
+
+static char *
+silc_client_command_status_message(SilcCommandStatus status)
+{
+  int i;
+
+  for (i = 0; silc_command_status_messages[i].message; i++) {
+    if (silc_command_status_messages[i].status == status)
+      break;
+  }
+
+  if (silc_command_status_messages[i].message == NULL)
+    return NULL;
+
+  return silc_command_status_messages[i].message;
+}
+
+/* Free command reply context and its internals. */
+
+void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
+{
+  if (cmd) {
+    silc_command_free_payload(cmd->payload);
+    silc_free(cmd);
+  }
+}
+
+static void 
+silc_client_command_reply_whois_print(SilcClientCommandReplyContext cmd,
+                                     SilcCommandStatus status)
+{
+  char buf[256];
+  int argc, len;
+  unsigned char *id_data;
+  char *nickname = NULL, *username = NULL;
+  char *realname = NULL;
+  SilcClientID *client_id;
+  SilcIDCacheEntry id_cache = NULL;
+  SilcClientEntry client_entry = NULL;
+  SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+  
+  memset(buf, 0, sizeof(buf));
+  
+  argc = silc_argument_get_arg_num(cmd->args);
+
+  id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
+  if (!id_data) {
+    COMMAND_REPLY_ERROR;
+    return;
+  }
+  
+  client_id = silc_id_payload_parse_id(id_data, len);
+  
+  nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
+  if (nickname) {
+    strncat(buf, nickname, len);
+    strncat(buf, " is ", 4);
+  }
+  
+  username = silc_argument_get_arg_type(cmd->args, 4, &len);
+  if (username) {
+    strncat(buf, username, len);
+  }
+  
+  realname = silc_argument_get_arg_type(cmd->args, 5, &len);
+  if (realname) {
+    strncat(buf, " (", 2);
+    strncat(buf, realname, len);
+    strncat(buf, ")", 1);
+  }
+  
+  /* Check if we have this client cached already. */
+  if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
+                                  SILC_ID_CLIENT, &id_cache)) {
+    client_entry = silc_calloc(1, sizeof(*client_entry));
+    client_entry->id = client_id;
+    silc_parse_nickname(nickname, &client_entry->nickname, 
+                       &client_entry->server, &client_entry->num);
+    client_entry->username = strdup(username);
+    
+    /* Add client to cache */
+    silc_idcache_add(conn->client_cache, client_entry->nickname,
+                    SILC_ID_CLIENT, client_id, (void *)client_entry, TRUE);
+  } else {
+    client_entry = (SilcClientEntry)id_cache->context;
+    silc_free(client_id);
+  }
+
+  if (!cmd->callback)
+    cmd->client->ops->say(cmd->client, conn, "%s", buf);
+
+  /* Notify application */
+  COMMAND_REPLY((ARGS, client_entry, nickname, 
+                username, realname, NULL, NULL));
+}
+
+/* Received reply for WHOIS command. This maybe called several times
+   for one WHOIS command as server may reply with list of results. */
+
+SILC_CLIENT_CMD_REPLY_FUNC(whois)
+{
+  SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+  SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+  SilcCommandStatus status;
+  unsigned char *tmp;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+  SILC_GET16_MSB(status, tmp);
+  if (status != SILC_STATUS_OK && 
+      status != SILC_STATUS_LIST_START &&
+      status != SILC_STATUS_LIST_ITEM &&
+      status != SILC_STATUS_LIST_END) {
+    if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
+      /* Take nickname which may be provided */
+      tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
+      if (tmp)
+       cmd->client->ops->say(cmd->client, conn, "%s: %s", tmp,
+                silc_client_command_status_message(status));
+      else
+       cmd->client->ops->say(cmd->client, conn, "%s",
+                silc_client_command_status_message(status));
+      COMMAND_REPLY_ERROR;
+      goto out;
+    } else {
+      cmd->client->ops->say(cmd->client, conn,
+              "%s", silc_client_command_status_message(status));
+      COMMAND_REPLY_ERROR;
+      goto out;
+    }
+  }
+
+  /* Display one whois reply */
+  if (status == SILC_STATUS_OK) {
+    silc_client_command_reply_whois_print(cmd, status);
+  }
+
+  /* XXX list should not be displayed untill all items has been received. */
+  if (status == SILC_STATUS_LIST_START) {
+    silc_client_command_reply_whois_print(cmd, status);
+  }
+
+  if (status == SILC_STATUS_LIST_ITEM) {
+    silc_client_command_reply_whois_print(cmd, status);
+  }
+
+  if (status == SILC_STATUS_LIST_END) {
+    silc_client_command_reply_whois_print(cmd, status);
+  }
+
+  SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_WHOIS);
+
+ out:
+  silc_client_command_reply_free(cmd);
+}
+
+/* Received reply for WHOWAS command. */
+
+SILC_CLIENT_CMD_REPLY_FUNC(whowas)
+{
+
+}
+
+/* Received reply for IDENTIFY command. This maybe called several times
+   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)
+{
+  SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+  SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+  SilcClientEntry client_entry;
+  SilcCommandStatus status;
+  unsigned char *tmp;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+  SILC_GET16_MSB(status, tmp);
+  if (status != SILC_STATUS_OK) {
+    if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
+      /* Take nickname which may be provided */
+      tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
+      if (tmp)
+       cmd->client->ops->say(cmd->client, conn, "%s: %s", tmp,
+                silc_client_command_status_message(status));
+      else
+       cmd->client->ops->say(cmd->client, conn, "%s",
+                silc_client_command_status_message(status));
+      COMMAND_REPLY_ERROR;
+      goto out;
+    } else {
+      cmd->client->ops->say(cmd->client, conn,
+              "%s", silc_client_command_status_message(status));
+      COMMAND_REPLY_ERROR;
+      goto out;
+    }
+  }
+
+  /* Display one whois reply */
+  if (status == SILC_STATUS_OK) {
+    unsigned int len;
+    unsigned char *id_data;
+    char *nickname;
+    char *username;
+
+    id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
+    nickname = silc_argument_get_arg_type(cmd->args, 3, NULL);
+    username = silc_argument_get_arg_type(cmd->args, 4, NULL);
+
+    /* Allocate client entry */
+    client_entry = silc_calloc(1, sizeof(*client_entry));
+    client_entry->id = silc_id_payload_parse_id(id_data, len);
+    if (nickname)
+      silc_parse_nickname(nickname, &client_entry->nickname, 
+                         &client_entry->server, &client_entry->num);
+    if (username)
+      client_entry->username = strdup(username);
+
+    /* Save received Client ID to ID cache */
+    silc_idcache_add(conn->client_cache, client_entry->nickname,
+                    SILC_ID_CLIENT, client_entry->id, client_entry, TRUE);
+  }
+
+  if (status == SILC_STATUS_LIST_START) {
+
+  }
+
+  if (status == SILC_STATUS_LIST_END) {
+
+  }
+
+  SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_IDENTIFY);
+
+ out:
+  silc_client_command_reply_free(cmd);
+}
+
+/* Received reply for command NICK. If everything went without errors
+   we just received our new Client ID. */
+
+SILC_CLIENT_CMD_REPLY_FUNC(nick)
+{
+  SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+  SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+  SilcCommandStatus status;
+  SilcIDPayload idp;
+  unsigned char *tmp;
+  unsigned int argc, len;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
+  if (status != SILC_STATUS_OK) {
+    cmd->client->ops->say(cmd->client, conn, "Cannot set nickname: %s", 
+            silc_client_command_status_message(status));
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+
+  argc = silc_argument_get_arg_num(cmd->args);
+  if (argc < 2 || argc > 2) {
+    cmd->client->ops->say(cmd->client, conn, 
+                         "Cannot set nickname: bad reply to command");
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+
+  /* Take received Client ID */
+  tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+  idp = silc_id_payload_parse_data(tmp, len);
+  silc_client_receive_new_id(cmd->client, cmd->sock, idp);
+    
+  /* Notify application */
+  COMMAND_REPLY((ARGS, conn->local_entry));
+
+ out:
+  silc_client_command_reply_free(cmd);
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(list)
+{
+}
+
+/* Received reply to topic command. */
+
+SILC_CLIENT_CMD_REPLY_FUNC(topic)
+{
+  SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+  SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+  SilcCommandStatus status;
+  SilcChannelEntry channel;
+  SilcChannelID *channel_id = NULL;
+  SilcIDCacheEntry id_cache = NULL;
+  unsigned char *tmp;
+  char *topic;
+  unsigned int argc, len;
+
+  SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
+  if (status != SILC_STATUS_OK) {
+    cmd->client->ops->say(cmd->client, conn,
+            "%s", silc_client_command_status_message(status));
+    COMMAND_REPLY_ERROR;
+    silc_client_command_reply_free(cmd);
+    return;
+  }
+
+  argc = silc_argument_get_arg_num(cmd->args);
+  if (argc < 1 || argc > 3) {
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+
+  /* Take Channel ID */
+  tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+  if (!tmp)
+    goto out;
+
+  /* Take topic */
+  topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
+  if (!topic)
+    goto out;
+
+  channel_id = silc_id_payload_parse_id(tmp, len);
+
+  /* Get the channel name */
+  if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
+                                  SILC_ID_CHANNEL, &id_cache)) {
+    silc_free(channel_id);
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+  
+  channel = (SilcChannelEntry)id_cache->context;
+
+  cmd->client->ops->say(cmd->client, conn, 
+                       "Topic on channel %s: %s", channel->channel_name,
+                       topic);
+
+  /* Notify application */
+  COMMAND_REPLY((ARGS, channel, topic));
+
+ out:
+  silc_client_command_reply_free(cmd);
+}
+
+/* Received reply to invite command. */
+
+SILC_CLIENT_CMD_REPLY_FUNC(invite)
+{
+  SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+  SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+  SilcCommandStatus status;
+  unsigned char *tmp;
+
+  tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+  SILC_GET16_MSB(status, tmp);
+  if (status != SILC_STATUS_OK) {
+    cmd->client->ops->say(cmd->client, conn,
+            "%s", silc_client_command_status_message(status));
+    COMMAND_REPLY_ERROR;
+    silc_client_command_reply_free(cmd);
+    return;
+  }
+
+  /* Notify application */
+  COMMAND_REPLY((ARGS));
+
+  silc_client_command_reply_free(cmd);
+}
+SILC_CLIENT_CMD_REPLY_FUNC(quit)
+{
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(kill)
+{
+}
+
+/* Received reply to INFO command. We receive the server ID and some
+   information about the server user requested. */
+
+SILC_CLIENT_CMD_REPLY_FUNC(info)
+{
+  SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+  SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+  SilcClient client = cmd->client;
+  SilcCommandStatus status;
+  unsigned char *tmp;
+
+  tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+  SILC_GET16_MSB(status, tmp);
+  if (status != SILC_STATUS_OK) {
+    cmd->client->ops->say(cmd->client, conn,
+            "%s", silc_client_command_status_message(status));
+    COMMAND_REPLY_ERROR;
+    silc_client_command_reply_free(cmd);
+    return;
+  }
+
+  /* Get server ID */
+  tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
+  if (!tmp)
+    goto out;
+
+  /* XXX save server id */
+
+  /* Get server info */
+  tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
+  if (!tmp)
+    goto out;
+
+  client->ops->say(cmd->client, conn, "Info: %s", tmp);
+
+  /* Notify application */
+  COMMAND_REPLY((ARGS, NULL, (char *)tmp));
+
+ out:
+  silc_client_command_reply_free(cmd);
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(connect)
+{
+}
+
+/* Received reply to PING command. The reply time is shown to user. */
+
+SILC_CLIENT_CMD_REPLY_FUNC(ping)
+{
+  SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+  SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+  SilcCommandStatus status;
+  void *id;
+  int i;
+  time_t diff, curtime;
+
+  SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
+  if (status != SILC_STATUS_OK) {
+    cmd->client->ops->say(cmd->client, conn,
+            "%s", silc_client_command_status_message(status));
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+
+  curtime = time(NULL);
+  id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
+
+  for (i = 0; i < conn->ping_count; i++) {
+    if (!SILC_ID_SERVER_COMPARE(conn->ping[i].dest_id, id)) {
+      diff = curtime - conn->ping[i].start_time;
+      cmd->client->ops->say(cmd->client, conn, 
+                           "Ping reply from %s: %d second%s", 
+                           conn->ping[i].dest_name, diff, 
+                           diff == 1 ? "" : "s");
+
+      conn->ping[i].start_time = 0;
+      silc_free(conn->ping[i].dest_id);
+      conn->ping[i].dest_id = NULL;
+      silc_free(conn->ping[i].dest_name);
+      conn->ping[i].dest_name = NULL;
+
+      /* Notify application */
+      COMMAND_REPLY((ARGS));
+      break;
+    }
+  }
+
+  silc_free(id);
+
+ out:
+  silc_client_command_reply_free(cmd);
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(oper)
+{
+}
+
+/* Received reply for JOIN command. */
+
+SILC_CLIENT_CMD_REPLY_FUNC(join)
+{
+  SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+  SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+  SilcClient client = cmd->client;
+  SilcCommandStatus status;
+  SilcIDPayload idp;
+  unsigned int argc, mode, len;
+  char *topic, *tmp, *channel_name;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
+  if (status != SILC_STATUS_OK) {
+    cmd->client->ops->say(cmd->client, conn,
+            "%s", silc_client_command_status_message(status));
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+
+  argc = silc_argument_get_arg_num(cmd->args);
+  if (argc < 3 || argc > 5) {
+    cmd->client->ops->say(cmd->client, conn,
+            "Cannot join channel: Bad reply packet");
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+
+  /* Get channel name */
+  tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
+  if (!tmp) {
+    cmd->client->ops->say(cmd->client, conn, 
+                         "Cannot join channel: Bad reply packet");
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+  channel_name = strdup(tmp);
+
+  /* Get Channel ID */
+  tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
+  if (!tmp) {
+    cmd->client->ops->say(cmd->client, conn, 
+                         "Cannot join channel: Bad reply packet");
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+  idp = silc_id_payload_parse_data(tmp, len);
+
+  /* Get channel mode */
+  tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
+  if (tmp)
+    SILC_GET32_MSB(mode, tmp);
+  else
+    mode = 0;
+
+  /* Get topic */
+  topic = silc_argument_get_arg_type(cmd->args, 5, NULL);
+
+  /* Save received Channel ID */
+  silc_client_new_channel_id(cmd->client, cmd->sock, channel_name, 
+                            mode, idp);
+  silc_id_payload_free(idp);
+
+  if (topic)
+    client->ops->say(cmd->client, conn, 
+                    "Topic for %s: %s", channel_name, topic);
+
+  /* Notify application */
+  COMMAND_REPLY((ARGS, channel_name, conn->current_channel, mode,
+                NULL, NULL, topic));
+
+ out:
+  silc_client_command_reply_free(cmd);
+}
+
+/* Received reply for MOTD command */
+
+SILC_CLIENT_CMD_REPLY_FUNC(motd)
+{
+  SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+  SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+  SilcCommandStatus status;
+  unsigned int argc, i;
+  unsigned char *tmp;
+  char *motd = NULL, *cp, line[256];
+
+  tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+  SILC_GET16_MSB(status, tmp);
+  if (status != SILC_STATUS_OK) {
+    cmd->client->ops->say(cmd->client, conn,
+            "%s", silc_client_command_status_message(status));
+    COMMAND_REPLY_ERROR;
+    return;
+  }
+
+  argc = silc_argument_get_arg_num(cmd->args);
+  if (argc > 2) {
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+
+  if (argc == 2) {
+    motd = silc_argument_get_arg_type(cmd->args, 2, NULL);
+    if (!motd) {
+      COMMAND_REPLY_ERROR;
+      goto out;
+    }
+
+    i = 0;
+    cp = motd;
+    while(cp[i] != 0) {
+      if (cp[i++] == '\n') {
+       memset(line, 0, sizeof(line));
+       strncat(line, cp, i - 1);
+       cp += i;
+       
+       if (i == 2)
+         line[0] = ' ';
+       
+       cmd->client->ops->say(cmd->client, conn, "%s", line);
+       
+       if (!strlen(cp))
+         break;
+       i = 0;
+      }
+    }
+  }
+
+  /* Notify application */
+  COMMAND_REPLY((ARGS, motd));
+
+ out:
+  silc_client_command_reply_free(cmd);
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(umode)
+{
+}
+
+/* Received reply for CMODE command. */
+
+SILC_CLIENT_CMD_REPLY_FUNC(cmode)
+{
+  SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+  SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+  SilcCommandStatus status;
+  unsigned char *tmp;
+
+  SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
+  if (status != SILC_STATUS_OK) {
+    cmd->client->ops->say(cmd->client, conn,
+            "%s", silc_client_command_status_message(status));
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+
+  /* Get channel mode */
+  tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
+  if (!tmp) {
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+
+  /* Notify application */
+  COMMAND_REPLY((ARGS, tmp));
+
+ out:
+  silc_client_command_reply_free(cmd);
+}
+
+/* Received reply for CUMODE command */
+
+SILC_CLIENT_CMD_REPLY_FUNC(cumode)
+{
+  SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+  SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+  SilcCommandStatus status;
+  SilcIDCacheEntry id_cache = NULL;
+  SilcClientID *client_id;
+  unsigned char *tmp, *id;
+  unsigned int len;
+  
+  SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
+  if (status != SILC_STATUS_OK) {
+    cmd->client->ops->say(cmd->client, conn,
+            "%s", silc_client_command_status_message(status));
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+  
+  /* Get channel mode */
+  tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
+  if (!tmp) {
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+
+  /* Get Client ID */
+  id = silc_argument_get_arg_type(cmd->args, 3, &len);
+  if (!id) {
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+  client_id = silc_id_payload_parse_id(id, len);
+  
+  /* Get client entry */
+  if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
+                                  SILC_ID_CLIENT, &id_cache)) {
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+
+  /* Notify application */
+  COMMAND_REPLY((ARGS, tmp, (SilcClientEntry)id_cache->context));
+  silc_free(client_id);
+  
+ out:
+  silc_client_command_reply_free(cmd);
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(kick)
+{
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(restart)
+{
+}
+SILC_CLIENT_CMD_REPLY_FUNC(close)
+{
+}
+SILC_CLIENT_CMD_REPLY_FUNC(die)
+{
+}
+SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
+{
+}
+
+/* Reply to LEAVE command. */
+
+SILC_CLIENT_CMD_REPLY_FUNC(leave)
+{
+  SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+  SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+  SilcCommandStatus status;
+  unsigned char *tmp;
+
+  tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+  SILC_GET16_MSB(status, tmp);
+  if (status != SILC_STATUS_OK) {
+    cmd->client->ops->say(cmd->client, conn,
+            "%s", silc_client_command_status_message(status));
+    COMMAND_REPLY_ERROR;
+    return;
+  }
+
+  /* Notify application */
+  COMMAND_REPLY((ARGS));
+
+  silc_client_command_reply_free(cmd);
+}
+
+/* Reply to NAMES command. Received list of client names on the channel 
+   we requested. */
+
+SILC_CLIENT_CMD_REPLY_FUNC(names)
+{
+  SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+  SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+  SilcCommandStatus status;
+  SilcIDCacheEntry id_cache = NULL;
+  SilcChannelEntry channel;
+  SilcChannelID *channel_id = NULL;
+  SilcBuffer client_id_list;
+  SilcBuffer client_mode_list;
+  unsigned char *tmp;
+  char *name_list, *cp;
+  int i, k, len1, len2, list_count = 0;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+  SILC_GET16_MSB(status, tmp);
+  if (status != SILC_STATUS_OK) {
+    cmd->client->ops->say(cmd->client, conn,
+            "%s", silc_client_command_status_message(status));
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+
+  /* Get channel ID */
+  tmp = silc_argument_get_arg_type(cmd->args, 2, &len1);
+  if (!tmp) {
+    cmd->client->ops->say(cmd->client, conn, 
+                         "Cannot Channel ID: Bad reply packet");
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+  channel_id = silc_id_payload_parse_id(tmp, len1);
+
+  /* Get the name list of the channel */
+  name_list = silc_argument_get_arg_type(cmd->args, 3, &len1);
+  if (!name_list) {
+    cmd->client->ops->say(cmd->client, conn, 
+                         "Cannot get user list: Bad reply packet");
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+
+  /* Get Client ID list */
+  tmp = silc_argument_get_arg_type(cmd->args, 4, &len2);
+  if (!tmp) {
+    cmd->client->ops->say(cmd->client, conn, 
+                         "Cannot get user list: Bad reply packet");
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+
+  client_id_list = silc_buffer_alloc(len2);
+  silc_buffer_pull_tail(client_id_list, len2);
+  silc_buffer_put(client_id_list, tmp, len2);
+
+  /* Get client mode list */
+  tmp = silc_argument_get_arg_type(cmd->args, 5, &len2);
+  if (!tmp) {
+    cmd->client->ops->say(cmd->client, conn, 
+                         "Cannot get user list: Bad reply packet");
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+
+  client_mode_list = silc_buffer_alloc(len2);
+  silc_buffer_pull_tail(client_mode_list, len2);
+  silc_buffer_put(client_mode_list, tmp, len2);
+
+  /* Get the channel name */
+  if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
+                                  SILC_ID_CHANNEL, &id_cache)) {
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+  
+  channel = (SilcChannelEntry)id_cache->context;
+
+  /* If there is pending command we know that user has called this command
+     and we will handle the name list differently. */
+  if (cmd->callback) {
+    /* We will resolve all the necessary information about the people
+       on the channel. Only after that will we display the user list. */
+    for (i = 0; i < len1; i++) {
+      /* XXX */
+
+    }
+    silc_client_command_pending_del(SILC_COMMAND_NAMES);
+  } else {
+    /* there is no pending callback it means that this command reply
+       has been received without calling the command, ie. server has sent
+       the reply without getting the command from us first. This happens
+       with SILC servers that sends NAMES reply after joining to a channel. */
+
+    /* Remove commas from list */
+    for (i = 0; i < len1; i++)
+      if (name_list[i] == ',') {
+       name_list[i] = ' ';
+       list_count++;
+      }
+    list_count++;
+  }
+
+  /* Remove old client list from channel, if exists */
+  if (channel->clients) {
+    silc_free(channel->clients);
+    channel->clients = NULL;
+    channel->clients_count = 0;
+  }
+
+  /* Allocate room for clients in the channel */
+  channel->clients = silc_calloc(list_count, sizeof(*channel->clients));
+
+  /* Cache the received name list, client ID's and modes. This cache expires
+     whenever server sends notify message to channel. It means two things;
+     some user has joined or leaved the channel. */
+  cp = name_list;
+  for (i = 0; i < list_count; i++) {
+    int nick_len = strcspn(name_list, " ");
+    unsigned short idp_len;
+    unsigned int mode;
+    char *nickname = silc_calloc(nick_len + 1, sizeof(*nickname));
+    SilcClientID *client_id;
+    SilcClientEntry client;
+
+    memcpy(nickname, name_list, nick_len);
+    SILC_GET16_MSB(idp_len, client_id_list->data + 2);
+    idp_len += 4;
+    client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
+    silc_buffer_pull(client_id_list, idp_len);
+    
+    SILC_GET32_MSB(mode, client_mode_list->data);
+    silc_buffer_pull(client_mode_list, 4);
+
+    /* Check if we have this client cached already. */
+    if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
+                                    SILC_ID_CLIENT, &id_cache)) {
+      client = silc_calloc(1, sizeof(*client));
+      client->id = client_id;
+      silc_parse_nickname(nickname, &client->nickname, &client->server, 
+                         &client->num);
+      silc_free(nickname);
+
+      /* Add client to cache */
+      silc_idcache_add(conn->client_cache, client->nickname, SILC_ID_CLIENT,
+                      client_id, (void *)client, TRUE);
+    } else {
+      client = (SilcClientEntry)id_cache->context;
+      silc_free(client_id);
+      silc_free(nickname);
+      id_cache = NULL;
+    }
+
+    channel->clients[channel->clients_count].client = client;
+    channel->clients[channel->clients_count].mode = mode;
+    channel->clients_count++;
+
+    name_list += nick_len + 1;
+  }
+
+  name_list = cp;
+  for (i = 0; i < list_count; i++) {
+    int c;
+    int nick_len = strcspn(name_list, " ");
+    char *nickname = silc_calloc(nick_len + 1, sizeof(*nickname));
+    memcpy(nickname, name_list, nick_len);
+
+    for (c = 0, k = 0; k < channel->clients_count; k++) {
+      if (channel->clients[k].client && 
+         !strncmp(channel->clients[k].client->nickname, 
+                  nickname, strlen(channel->clients[k].client->nickname))) {
+       char t[8];
+       
+       if (!c) {
+         c++;
+         continue;
+       }
+       
+       memset(t, 0, sizeof(t));
+       channel->clients[k].client->nickname = 
+         silc_calloc(strlen(nickname) + 8, sizeof(*channel->clients[k].
+                                                  client->nickname));
+       snprintf(t, sizeof(t), "[%d]", c++);
+       strncat(channel->clients[k].client->nickname, t, strlen(t));
+       strncat(channel->clients[k].client->nickname, nickname, 
+               strlen(nickname));
+      }
+    }
+
+    silc_free(nickname);
+  }
+
+  name_list = NULL;
+  len1 = 0;
+  for (k = 0; k < channel->clients_count; k++) {
+    char *m, *n = channel->clients[k].client->nickname;
+    len2 = strlen(n);
+    len1 += len2;
+
+    name_list = silc_realloc(name_list, sizeof(*name_list) * (len1 + 3));
+
+    m = silc_client_chumode_char(channel->clients[k].mode);
+    if (m) {
+      memcpy(name_list + (len1 - len2), m, strlen(m));
+      len1 += strlen(m);
+      silc_free(m);
+    }
+
+    memcpy(name_list + (len1 - len2), n, len2);
+    name_list[len1] = 0;
+    
+    if (k == channel->clients_count - 1)
+      break;
+    memcpy(name_list + len1, " ", 1);
+    len1++;
+  }
+
+  cmd->client->ops->say(cmd->client, conn,
+                       "Users on %s: %s", channel->channel_name, name_list);
+
+  /* Notify application */
+  COMMAND_REPLY((ARGS, channel, name_list, client_id_list->head,
+                client_mode_list->head));
+
+  silc_free(name_list);
+  silc_buffer_free(client_id_list);
+  silc_buffer_free(client_mode_list);
+
+ out:
+  if (channel_id)
+    silc_free(channel_id);
+  silc_client_command_reply_free(cmd);
+}
similarity index 95%
rename from apps/silc/command_reply.h
rename to lib/silcclient/command_reply.h
index 36b312860733035d2df58f02f963c30bc38c93ad..76bddc1a0a8afa8c4fa0693189d8448d43e6baa1 100644 (file)
@@ -35,6 +35,8 @@ typedef struct {
   SilcClient client;
   SilcSocketConnection sock;
   SilcCommandPayload payload;
+  SilcArgumentPayload args;
+  SilcPacketContext *packet;
 
   /* If defined this executes the pending command. */
   void *context;
@@ -71,7 +73,7 @@ do {                                                  \
 /* Prototypes */
 void silc_client_command_reply_process(SilcClient client,
                                       SilcSocketConnection sock,
-                                      SilcBuffer buffer);
+                                      SilcPacketContext *packet);
 SILC_CLIENT_CMD_REPLY_FUNC(whois);
 SILC_CLIENT_CMD_REPLY_FUNC(whowas);
 SILC_CLIENT_CMD_REPLY_FUNC(identify);
@@ -85,7 +87,6 @@ SILC_CLIENT_CMD_REPLY_FUNC(info);
 SILC_CLIENT_CMD_REPLY_FUNC(links);
 SILC_CLIENT_CMD_REPLY_FUNC(stats);
 SILC_CLIENT_CMD_REPLY_FUNC(users);
-SILC_CLIENT_CMD_REPLY_FUNC(away);
 SILC_CLIENT_CMD_REPLY_FUNC(connect);
 SILC_CLIENT_CMD_REPLY_FUNC(ping);
 SILC_CLIENT_CMD_REPLY_FUNC(pong);
@@ -94,6 +95,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(join);
 SILC_CLIENT_CMD_REPLY_FUNC(motd);
 SILC_CLIENT_CMD_REPLY_FUNC(umode);
 SILC_CLIENT_CMD_REPLY_FUNC(cmode);
+SILC_CLIENT_CMD_REPLY_FUNC(cumode);
 SILC_CLIENT_CMD_REPLY_FUNC(kick);
 SILC_CLIENT_CMD_REPLY_FUNC(restart);
 SILC_CLIENT_CMD_REPLY_FUNC(close);
@@ -101,6 +103,5 @@ SILC_CLIENT_CMD_REPLY_FUNC(die);
 SILC_CLIENT_CMD_REPLY_FUNC(silcoper);
 SILC_CLIENT_CMD_REPLY_FUNC(leave);
 SILC_CLIENT_CMD_REPLY_FUNC(names);
-SILC_CLIENT_CMD_REPLY_FUNC(msg);
 
 #endif
diff --git a/lib/silcclient/idlist.c b/lib/silcclient/idlist.c
new file mode 100644 (file)
index 0000000..edd2df0
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+
+  idlist.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 2000 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
+  GNU General Public License for more details.
+
+*/
+/* $Id$ */
+
+#include "clientlibincludes.h"
+
+/* Finds client entry from cache by nickname. If the entry is not found
+   from the cache this function queries it from the server. If `server'
+   and `num' are defined as well thisk checks the match from multiple
+   cache entries thus providing support for multiple same nickname
+   handling. This also ignores case-sensitivity. */
+
+SilcClientEntry silc_idlist_get_client(SilcClient client,
+                                      SilcClientConnection conn,
+                                      char *nickname,
+                                      char *server,
+                                      unsigned int num)
+{
+  SilcIDCacheEntry id_cache;
+  SilcIDCacheList list = NULL;
+  SilcClientEntry entry = NULL;
+
+  /* Find ID from cache */
+  if (!silc_idcache_find_by_data_loose(conn->client_cache, nickname, &list)) {
+    SilcClientCommandContext ctx;
+    char ident[512];
+    
+  identify:
+
+    SILC_LOG_DEBUG(("Requesting Client ID from server"));
+
+    /* No ID found. Do query from the server. The query is done by 
+       sending simple IDENTIFY command to the server. */
+    ctx = silc_calloc(1, sizeof(*ctx));
+    ctx->client = client;
+    ctx->conn = conn;
+    ctx->command = silc_client_command_find("IDENTIFY");
+    memset(ident, 0, sizeof(ident));
+    snprintf(ident, sizeof(ident), "IDENTIFY %s", nickname);
+    silc_parse_command_line(ident, &ctx->argv, &ctx->argv_lens, 
+                           &ctx->argv_types, &ctx->argc, 2);
+    ctx->command->cb(ctx);
+
+    if (list)
+      silc_idcache_list_free(list);
+
+    return NULL;
+  }
+
+  if (!server && !num) {
+    /* Take first found cache entry */
+    if (!silc_idcache_list_first(list, &id_cache))
+      goto identify;
+
+    entry = (SilcClientEntry)id_cache->context;
+  } else {
+    /* Check multiple cache entries for match */
+    silc_idcache_list_first(list, &id_cache);
+    entry = (SilcClientEntry)id_cache->context;
+    
+    while (entry) {
+      if (server && entry->server && 
+         !strncasecmp(server, entry->server, strlen(server)))
+       break;
+      
+      if (num && entry->num == num)
+       break;
+
+      if (!silc_idcache_list_next(list, &id_cache)) {
+       entry = NULL;
+       break;
+      }
+
+      entry = (SilcClientEntry)id_cache->context;
+    }
+
+    /* If match weren't found, request it */
+    if (!entry)
+      goto identify;
+  }
+
+  if (list)
+    silc_idcache_list_free(list);
+
+  return entry;
+}
+
+/* Finds client entry from cache by Client ID. If the entry is not found
+   from the cache this function can query it from the server. */
+
+SilcClientEntry silc_idlist_get_client_by_id(SilcClient client,
+                                            SilcClientConnection conn,
+                                            SilcClientID *client_id,
+                                            int query)
+{
+  SilcIDCacheEntry id_cache;
+
+  /* Find ID from cache */
+  if (!silc_idcache_find_by_id_one(conn->client_cache, client_id, 
+                                  SILC_ID_CLIENT, &id_cache)) {
+    if (!query) {
+      return NULL;
+    } else {
+      SilcBuffer idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
+      silc_client_send_command(client, conn, SILC_COMMAND_WHOIS, 1,
+                              2, idp->data, idp->len);
+      return NULL;
+    }
+  }
+
+  return (SilcClientEntry)id_cache->context;
+}
+
+/* Finds channel entry from ID cache by channel name. */
+
+SilcChannelEntry silc_idlist_get_channel(SilcClient client,
+                                        SilcClientConnection conn,
+                                        char *channel)
+{
+  SilcIDCacheEntry id_cache;
+  SilcChannelEntry entry;
+
+  if (!silc_idcache_find_by_data_one(conn->channel_cache, channel, &id_cache))
+    return NULL;
+
+  entry = (SilcChannelEntry)id_cache->context;
+
+  return entry;
+}
similarity index 67%
rename from apps/silc/idlist.h
rename to lib/silcclient/idlist.h
index 9c769e9839578215407f626e2222903e590dcf30..b71a0fa13d3ceb47615d95ca1b060faadbe72e8c 100644 (file)
    client entry. This entry also includes the private message keys if
    they are used. */
 typedef struct SilcClientEntryStruct {
-  char *nickname;
+  char *nickname;             /* nickname[@server] */
+  char *username;            /* username[@host] */
+  char *server;                      /* SILC server name */
+  unsigned int num;
   SilcClientID *id;
 
   /* Keys, these are defined if private message key has been defined 
@@ -37,6 +40,12 @@ typedef struct SilcClientEntryStruct {
 
 typedef SilcClientEntryObject *SilcClientEntry;
 
+/* Client and its mode on a channel */
+typedef struct {
+  SilcClientEntry client;
+  unsigned int mode;
+} SilcChannelUsers;
+
 /* Channel entry context. This is allocate for every channel client has
    joined to. This includes for example the channel specific keys */
 /* XXX channel_key is the server generated key. Later this context must 
@@ -44,8 +53,12 @@ typedef SilcClientEntryObject *SilcClientEntry;
 typedef struct SilcChannelEntryStruct {
   char *channel_name;
   SilcChannelID *id;
+  unsigned int mode;
   int on_channel;
 
+  SilcChannelUsers *clients;
+  unsigned int clients_count;
+
   /* Channel keys */
   SilcCipher channel_key;
   unsigned char *key;
@@ -55,4 +68,19 @@ typedef struct SilcChannelEntryStruct {
 
 typedef SilcChannelEntryObject *SilcChannelEntry;
 
+/* Prototypes */
+
+SilcClientEntry silc_idlist_get_client(SilcClient client,
+                                      SilcClientConnection conn,
+                                      char *nickname,
+                                      char *server,
+                                      unsigned int num);
+SilcClientEntry silc_idlist_get_client_by_id(SilcClient client,
+                                            SilcClientConnection conn,
+                                            SilcClientID *client_id,
+                                            int query);
+SilcChannelEntry silc_idlist_get_channel(SilcClient client,
+                                        SilcClientConnection conn,
+                                        char *channel);
+
 #endif
diff --git a/lib/silcclient/ops.h b/lib/silcclient/ops.h
new file mode 100644 (file)
index 0000000..5c61919
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+
+  ops.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 2000 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
+  GNU General Public License for more details.
+
+*/
+
+#ifndef OPS_H
+#define OPS_H
+
+/*
+ * SILC Client Operations
+ *
+ * These functions must be implemented by the application calling the
+ * SILC client library. The client library can call these functions at
+ * any time.
+ *
+ * To use this structure: define a static SilcClientOperations variable,
+ * fill it and pass its pointer to silc_client_alloc function.
+ */
+typedef struct {
+  void (*say)(SilcClient client, SilcClientConnection conn, char *msg, ...);
+  void (*channel_message)(SilcClient client, SilcClientConnection conn, 
+                         char *sender, char *channel_name, char *msg);
+  void (*private_message)(SilcClient client, SilcClientConnection conn,
+                         char *sender, char *msg);
+  void (*notify)(SilcClient client, SilcClientConnection conn, 
+                SilcNotifyType type, ...);
+  void (*command)(SilcClient client, SilcClientConnection conn, 
+                 SilcClientCommandContext cmd_context, int success,
+                 SilcCommand command);
+  void (*command_reply)(SilcClient client, SilcClientConnection conn,
+                       SilcCommandPayload cmd_payload, int success,
+                       SilcCommand command, SilcCommandStatus status, ...);
+  void (*connect)(SilcClient client, SilcClientConnection conn, int success);
+  void (*disconnect)(SilcClient client, SilcClientConnection conn);
+  int (*get_auth_method)(SilcClient client, SilcClientConnection conn,
+                        char *hostname, unsigned short port,
+                        SilcProtocolAuthMeth *auth_meth,
+                        unsigned char **auth_data,
+                        unsigned int *auth_data_len);
+  int (*verify_server_key)(SilcClient client, SilcClientConnection conn,
+                          unsigned char *pk, unsigned int pk_len,
+                          SilcSKEPKType pk_type);
+  unsigned char *(*ask_passphrase)(SilcClient client, 
+                                  SilcClientConnection conn);
+  void (*failure)(SilcClient client, SilcClientConnection conn, 
+                 SilcProtocol protocol, void *failure);
+} SilcClientOperations;
+
+/* 
+   Descriptions of above operation functions:
+
+   void (*say)(SilcClient client, SilcClientConnection conn, char *msg, ...);
+
+   Message sent to the application by library. `conn' associates the
+   message to a specific connection.  `conn', however, may be NULL.
+
+
+   void (*channel_message)(client, SilcClientConnection conn, 
+                          char *sender, char *channel_name, char *msg);
+
+   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 (*private_message)(client, SilcClientConnection conn,
+                          char *sender, char *msg);
+
+   Private message to the client. The `sender' is the nickname of the
+   sender received in the packet.
+
+
+   void (*notify)(SilcClient client, SilcClientConnection conn, ...);
+
+   Notify message to the client. The notify 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 received
+   application receives SilcClientEntry.  Also, if the notify type is
+   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 (*command)(SilcClient client, SilcClientConnection conn, 
+                  SilcClientCommandContext cmd_context, int success,
+                  SilcCommand command);
+
+   Command handler. This function is called always in the command function.
+   If error occurs it will be called as well. `conn' is the associated
+   client connection. `cmd_context' is the command context that was
+   originally sent to the command. `success' is FALSE if error occured
+   during command. `command' is the command being processed. It must be
+   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_reply)(SilcClient client, SilcClientConnection conn,
+                        SilcCommandPayload cmd_payload, int success,
+                        SilcCommandStatus status, SilcCommand command, ...);
+
+   Command reply handler. This function is called always in the command reply
+   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. 
+
+   `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,
+   however, it must be noted that the data is parsed already by the library
+   thus the payload can be ignored. `success' is FALSE if error occured.
+   In this case arguments are not sent to the application. The `status' is
+   the command reply status server returned. The `command' is the command
+   reply being processed. The function has variable argument list and each
+   command defines the number and type of arguments it passes to the
+   application (on error they are not sent).
+
+
+   void (*connect)(SilcClient client, SilcClientConnection conn, int success);
+
+   Called to indicate that connection was either successfully established
+   or connecting failed.  This is also the first time application receives
+   the SilcClientConnection objecet which it should save somewhere.
+
+
+   void (*disconnect)(SilcClient client, SilcClientConnection conn);
+
+   Called to indicate that connection was disconnected to the server.
+
+
+   int (*get_auth_method)(SilcClient client, SilcClientConnection conn,
+                         char *hostname, unsigned short port,
+                         SilcProtocolAuthMeth *auth_meth,
+                         unsigned char **auth_data,
+                         unsigned int *auth_data_len);
+
+   Find authentication method and authentication data by hostname and
+   port. The hostname may be IP address as well. The found authentication
+   method and authentication data is returned to `auth_meth', `auth_data'
+   and `auth_data_len'. The function returns TRUE if authentication method
+   is found and FALSE if not. `conn' may be NULL.
+
+
+   int (*verify_server_key)(SilcClient client, SilcClientConnection conn,
+                           unsigned char *pk, unsigned int pk_len,
+                           SilcSKEPKType pk_type);
+
+   Verifies received public key. The public key has been received from
+   a server. If user decides to trust the key may be saved as trusted
+   server key for later use. If user does not trust the key this returns
+   FALSE. If everything is Ok this returns TRUE. 
+
+
+   unsigned char *(*ask_passphrase)(SilcClient client, 
+                                   SilcClientConnection conn);
+
+   Ask (interact, that is) a passphrase from user. Returns the passphrase
+   or NULL on error. 
+
+
+   void (*failure)(SilcClient client, SilcClientConnection conn, 
+                   SilcProtocol protocol, void *failure);
+
+   Notifies application that failure packet was received.  This is called
+   if there is some protocol active in the client.  The `protocol' is the
+   protocol context.  The `failure' is opaque pointer to the failure
+   indication.  Note, that the `failure' is protocol dependant and application
+   must explicitly cast it to correct type.  Usually `failure' is 32 bit
+   failure type (see protocol specs for all protocol failure types).
+
+*/
+
+#endif
similarity index 64%
rename from apps/silc/protocol.c
rename to lib/silcclient/protocol.c
index ba89d9dcf80a4fb47ddd4d9b24a98aeee608d0f3..33203777ca9172e94b6ebb2c2727d6da88cdee6b 100644 (file)
 /*
  * Client side of the protocols.
  */
-/*
- * $Id$
- * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:56  priikone
- *     Importet from internal CVS/Added Log headers.
- *
- *
- */
+/* $Id$ */
 
-#include "clientincludes.h"
+#include "clientlibincludes.h"
 
 SILC_TASK_CALLBACK(silc_client_protocol_connection_auth);
-SILC_TASK_CALLBACK(silc_client_protocol_channel_auth);
 SILC_TASK_CALLBACK(silc_client_protocol_key_exchange);
 
-/* SILC client protocol list */
-const SilcProtocolObject silc_protocol_list[] =
-{
-  { SILC_PROTOCOL_CLIENT_CONNECTION_AUTH, 
-    silc_client_protocol_connection_auth },
-  { SILC_PROTOCOL_CLIENT_CHANNEL_AUTH, 
-    silc_client_protocol_channel_auth },
-  { SILC_PROTOCOL_CLIENT_KEY_EXCHANGE, 
-    silc_client_protocol_key_exchange },
-
-  { SILC_PROTOCOL_CLIENT_NONE, NULL },
-};
+extern char *silc_version_string;
 
 /*
  * Key Exhange protocol functions
  */
 
+/* Function that is called when SKE protocol sends packets to network. */
+
 static void silc_client_protocol_ke_send_packet(SilcSKE ske,
                                                SilcBuffer packet,
                                                SilcPacketType type,
@@ -68,20 +51,15 @@ static void silc_client_protocol_ke_send_packet(SilcSKE ske,
 
 }
 
-static void silc_client_protocol_ke_phase1_cb(SilcSKE ske,
-                                             void *context)
-{
-  SilcProtocol protocol = (SilcProtocol)context;
-  SilcClientKEInternalContext *ctx = 
-    (SilcClientKEInternalContext *)protocol->context;
-  SilcClient client = (SilcClient)ctx->client;
+/* Callback that is called when we have received KE2 payload from
+   responder. We try to verify the public key now. */
 
-  SILC_LOG_DEBUG(("Start"));
-
-}
-
-static void silc_client_protocol_ke_finish_cb(SilcSKE ske,
-                                             void *context)
+static SilcSKEStatus 
+silc_client_protocol_ke_verify_key(SilcSKE ske,
+                                  unsigned char *pk_data,
+                                  unsigned int pk_len,
+                                  SilcSKEPKType pk_type,
+                                  void *context)
 {
   SilcProtocol protocol = (SilcProtocol)context;
   SilcClientKEInternalContext *ctx = 
@@ -90,6 +68,12 @@ static void silc_client_protocol_ke_finish_cb(SilcSKE ske,
 
   SILC_LOG_DEBUG(("Start"));
 
+  /* Verify server key from user. */
+  if (!client->ops->verify_server_key(client, ctx->sock->user_data, 
+                                     pk_data, pk_len, pk_type))
+    return SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
+
+  return SILC_SKE_STATUS_OK;
 }
 
 /* Sets the negotiated key material into use for particular connection. */
@@ -101,42 +85,46 @@ static void silc_client_protocol_ke_set_keys(SilcSKE ske,
                                             SilcPKCS pkcs,
                                             SilcHash hash)
 {
-  SilcClientWindow win = (SilcClientWindow)sock->user_data;
+  SilcClientConnection conn = (SilcClientConnection)sock->user_data;
   SilcHash nhash;
 
   SILC_LOG_DEBUG(("Setting new keys into use"));
 
   /* Allocate cipher to be used in the communication */
-  silc_cipher_alloc(cipher->cipher->name, &win->send_key);
-  silc_cipher_alloc(cipher->cipher->name, &win->receive_key);
+  silc_cipher_alloc(cipher->cipher->name, &conn->send_key);
+  silc_cipher_alloc(cipher->cipher->name, &conn->receive_key);
 
-  win->send_key->cipher->set_key(win->send_key->context, 
+  conn->send_key->cipher->set_key(conn->send_key->context, 
                                 keymat->send_enc_key, 
                                 keymat->enc_key_len);
-  win->send_key->set_iv(win->send_key, keymat->send_iv);
-  win->receive_key->cipher->set_key(win->receive_key->context, 
+  conn->send_key->set_iv(conn->send_key, keymat->send_iv);
+  conn->receive_key->cipher->set_key(conn->receive_key->context, 
                                    keymat->receive_enc_key, 
                                    keymat->enc_key_len);
-  win->receive_key->set_iv(win->receive_key, keymat->receive_iv);
+  conn->receive_key->set_iv(conn->receive_key, keymat->receive_iv);
 
   /* Allocate PKCS to be used */
 #if 0
   /* XXX Do we ever need to allocate PKCS for the connection??
      If yes, we need to change KE protocol to get the initiators
      public key. */
-  silc_pkcs_alloc(pkcs->pkcs->name, &win->public_Key);
-  silc_pkcs_set_public_key(win->public_key, ske->ke2_payload->pk_data, 
+  silc_pkcs_alloc(pkcs->pkcs->name, &conn->public_Key);
+  silc_pkcs_set_public_key(conn->public_key, ske->ke2_payload->pk_data, 
                           ske->ke2_payload->pk_len);
 #endif
 
   /* Save HMAC key to be used in the communication. */
   silc_hash_alloc(hash->hash->name, &nhash);
-  silc_hmac_alloc(nhash, &win->hmac);
-  win->hmac_key_len = keymat->hmac_key_len;
-  win->hmac_key = silc_calloc(win->hmac_key_len,
-                                   sizeof(unsigned char));
-  memcpy(win->hmac_key, keymat->hmac_key, keymat->hmac_key_len);
+  silc_hmac_alloc(nhash, &conn->hmac);
+  silc_hmac_set_key(conn->hmac, keymat->hmac_key, keymat->hmac_key_len);
+}
 
+/* XXX TODO */
+
+SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version,
+                                    unsigned int len)
+{
+  return SILC_SKE_STATUS_OK;
 }
 
 /* Performs key exchange protocol. This is used for both initiator
@@ -148,7 +136,8 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
   SilcClientKEInternalContext *ctx = 
     (SilcClientKEInternalContext *)protocol->context;
   SilcClient client = (SilcClient)ctx->client;
-  SilcSKEStatus status;
+  SilcClientConnection conn = ctx->sock->user_data;
+  SilcSKEStatus status = 0;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -166,6 +155,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
       /* Allocate Key Exchange object */
       ske = silc_ske_alloc();
       ctx->ske = ske;
+      ske->rng = client->rng;
       
       if (ctx->responder == TRUE) {
 #if 0
@@ -183,7 +173,9 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
        SilcSKEStartPayload *start_payload;
 
        /* Assemble security properties. */
-       silc_ske_assemble_security_properties(ske, &start_payload);
+       silc_ske_assemble_security_properties(ske, SILC_SKE_SP_FLAG_NONE, 
+                                             silc_version_string,
+                                             &start_payload);
 
        /* Start the key exchange by sending our security properties
           to the remote end. */
@@ -194,11 +186,14 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
       }
 
       if (status != SILC_SKE_STATUS_OK) {
-       switch(status) {
-         
-       default:
-         break;
-       }
+       SILC_LOG_WARNING(("Error (type %d) during Key Exchange protocol",
+                         status));
+       SILC_LOG_DEBUG(("Error (type %d) during Key Exchange protocol",
+                       status));
+
+       protocol->state = SILC_PROTOCOL_STATE_ERROR;
+       protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
+       return;
       }
 
       /* Advance the state of the protocol. */
@@ -223,16 +218,18 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
           paylaod reply we just got from the responder. The callback
           function will receive the processed payload where we will
           save it. */
-       status = 
-         silc_ske_initiator_phase_1(ctx->ske,
-                                    ctx->packet,
-                                    silc_client_protocol_ke_phase1_cb,
-                                    context);
+       status = silc_ske_initiator_phase_1(ctx->ske, ctx->packet, NULL, NULL);
       }
 
-      switch(status) {
-      default:
-       break;
+      if (status != SILC_SKE_STATUS_OK) {
+       SILC_LOG_WARNING(("Error (type %d) during Key Exchange protocol",
+                         status));
+       SILC_LOG_DEBUG(("Error (type %d) during Key Exchange protocol",
+                       status));
+
+       protocol->state = SILC_PROTOCOL_STATE_ERROR;
+       protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
+       return;
       }
 
       /* Advance the state of the protocol and call the next state. */
@@ -259,13 +256,20 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
           Key Exhange 1 Payload to the responder. */
        status = 
          silc_ske_initiator_phase_2(ctx->ske,
+                                    client->public_key,
                                     silc_client_protocol_ke_send_packet,
                                     context);
       }
 
-      switch(status) {
-      default:
-       break;
+      if (status != SILC_SKE_STATUS_OK) {
+       SILC_LOG_WARNING(("Error (type %d) during Key Exchange protocol",
+                         status));
+       SILC_LOG_DEBUG(("Error (type %d) during Key Exchange protocol",
+                       status));
+
+       protocol->state = SILC_PROTOCOL_STATE_ERROR;
+       protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
+       return;
       }
 
       /* Advance the state of the protocol. */
@@ -278,6 +282,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
        * Finish protocol
        */
       if (ctx->responder == TRUE) {
+       status = 0;
 #if 0
        status = 
          silc_ske_responder_phase_2(ctx->ske, 
@@ -288,16 +293,25 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
       } else {
        /* Finish the protocol. This verifies the Key Exchange 2 payload
           sent by responder. */
-       status = 
-         silc_ske_initiator_finish(ctx->ske,
-                                   ctx->packet,
-                                   silc_client_protocol_ke_finish_cb,
-                                   context);
+       status = silc_ske_initiator_finish(ctx->ske, ctx->packet,
+                                          silc_client_protocol_ke_verify_key,
+                                          context, NULL, NULL);
       }
 
-      switch(status) {
-      default:
-       break;
+      if (status != SILC_SKE_STATUS_OK) {
+
+        if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY) {
+          client->ops->say(client, conn, 
+                          "Received unsupported server %s public key",
+                          ctx->sock->hostname);
+        } else {
+          client->ops->say(client, conn,
+                          "Error during key exchange protocol with server %s",
+                          ctx->sock->hostname);
+        }
+       protocol->state = SILC_PROTOCOL_STATE_ERROR;
+       protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
+       return;
       }
       
       /* Send Ok to the other end. We will end the protocol as server
@@ -308,6 +322,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
       protocol->state = SILC_PROTOCOL_STATE_END;
     }
     break;
+
   case SILC_PROTOCOL_STATE_END:
     {
       /* 
@@ -332,10 +347,34 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
        silc_protocol_free(protocol);
     }
     break;
+
   case SILC_PROTOCOL_STATE_ERROR:
+    /*
+     * Error during protocol
+     */
     
+    /* Send abort notification */
+    silc_ske_abort(ctx->ske, ctx->ske->status, 
+                  silc_client_protocol_ke_send_packet,
+                  context);
+
+    /* On error the final callback is always called. */
+    if (protocol->final_callback)
+      protocol->execute_final(client->timeout_queue, 0, protocol, fd);
+    else
+      silc_protocol_free(protocol);
+    break;
+
+  case SILC_PROTOCOL_STATE_FAILURE:
+    /*
+     * Received failure from remote.
+     */
+
     /* On error the final callback is always called. */
-    /*    protocol->final_callback(pptr, context);*/
+    if (protocol->final_callback)
+      protocol->execute_final(client->timeout_queue, 0, protocol, fd);
+    else
+      silc_protocol_free(protocol);
     break;
   case SILC_PROTOCOL_STATE_UNKNOWN:
     break;
@@ -352,6 +391,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
   SilcClientConnAuthInternalContext *ctx = 
     (SilcClientConnAuthInternalContext *)protocol->context;
   SilcClient client = (SilcClient)ctx->client;
+  SilcClientConnection conn = ctx->sock->user_data;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -383,16 +423,15 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
          break;
        }
 
-       silc_say(client, "Password authentication required by server %s",
-                ctx->sock->hostname);
-       auth_data = silc_client_ask_passphrase(client);
+       client->ops->say(client, conn, 
+                        "Password authentication required by server %s",
+                        ctx->sock->hostname);
+       auth_data = client->ops->ask_passphrase(client, conn);
        auth_data_len = strlen(auth_data);
        break;
 
       case SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY:
-#if 0
-
-#endif
+       /* XXX */
        break;
       }
 
@@ -439,13 +478,16 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
   case SILC_PROTOCOL_STATE_ERROR:
     {
       /* 
-       * Error
+       * Error. Send notify to remote.
        */
+      unsigned char error[4];
+
+      SILC_PUT32_MSB(SILC_CONN_AUTH_FAILED, error);
 
       /* Error in protocol. Send FAILURE packet. Although I don't think
         this could ever happen on client side. */
       silc_client_packet_send(client, ctx->sock, SILC_PACKET_FAILURE,
-                             NULL, 0, NULL, NULL, NULL, 0, TRUE);
+                             NULL, 0, NULL, NULL, error, 4, TRUE);
 
       /* On error the final callback is always called. */
       if (protocol->final_callback)
@@ -453,12 +495,40 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
       else
        silc_protocol_free(protocol);
     }
+
+  case SILC_PROTOCOL_STATE_FAILURE:
+    /*
+     * Received failure from remote.
+     */
+
+    /* On error the final callback is always called. */
+    if (protocol->final_callback)
+      protocol->execute_final(client->timeout_queue, 0, protocol, fd);
+    else
+      silc_protocol_free(protocol);
     break;
+
   case SILC_PROTOCOL_STATE_UNKNOWN:
     break;
   }
 }
 
-SILC_TASK_CALLBACK(silc_client_protocol_channel_auth)
+/* Registers protocols used in client */
+
+void silc_client_protocols_register(void)
+{
+  silc_protocol_register(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
+                        silc_client_protocol_connection_auth);
+  silc_protocol_register(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
+                        silc_client_protocol_key_exchange);
+}
+
+/* Unregisters protocols */
+
+void silc_client_protocols_unregister(void)
 {
+  silc_protocol_unregister(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
+                          silc_client_protocol_connection_auth);
+  silc_protocol_unregister(SILC_PROTOCOL_CLIENT_KEY_EXCHANGE,
+                          silc_client_protocol_key_exchange);
 }
similarity index 72%
rename from apps/silc/protocol.h
rename to lib/silcclient/protocol.h
index 1c40ef382ab8e6c0f94ab6ff81cab71a9d9414cc..87c2573ad06230c76a31d335085248a3309a3ce2 100644 (file)
 #define PROTOCOL_H
 
 /* SILC client protocol types */
-#define SILC_PROTOCOL_CLIENT_NONE 0
-#define SILC_PROTOCOL_CLIENT_CONNECTION_AUTH 1
-#define SILC_PROTOCOL_CLIENT_CHANNEL_AUTH 2
-#define SILC_PROTOCOL_CLIENT_KEY_EXCHANGE 3
-/* #define SILC_PROTOCOL_CLIENT_MAX 255 */
+#define SILC_PROTOCOL_CLIENT_NONE               0
+#define SILC_PROTOCOL_CLIENT_CONNECTION_AUTH    1
+#define SILC_PROTOCOL_CLIENT_KEY_EXCHANGE       2
+/* #define SILC_PROTOCOL_CLIENT_MAX             255 */
 
 /* Internal context for key exchange protocol */
 typedef struct {
@@ -34,6 +33,12 @@ typedef struct {
   SilcSocketConnection sock;
   SilcRng rng;
   int responder;
+
+  /* Destinations ID taken from authenticataed packet so that we can
+     get the destinations ID. */
+  void *dest_id;
+  SilcIdType dest_id_type;
+
   SilcBuffer packet;
   SilcSKE ske;
 } SilcClientKEInternalContext;
@@ -48,7 +53,11 @@ typedef struct {
 
   /* Auth method that must be used. This is resolved before this
      connection authentication protocol is started. */
-  unsigned int auth_meth;
+  SilcProtocolAuthMeth auth_meth;
+
+  /* Destinations ID from KE protocol context */
+  void *dest_id;
+  SilcIdType dest_id_type;
 
   /* Authentication data if we alreay know it. This is filled before
      starting the protocol if we know the authentication data. Otherwise
@@ -60,5 +69,7 @@ typedef struct {
 } SilcClientConnAuthInternalContext;
 
 /* Prototypes */
+void silc_client_protocols_register(void);
+void silc_client_protocols_unregister(void);
 
 #endif
index 5811b56a5438b3b3cc0cae1f9feb90f67149ca7a..36036ce139bbbb851a175a56e49c2b515577bfe0 100644 (file)
@@ -23,24 +23,16 @@ noinst_LIBRARIES = libsilccore.a
 libsilccore_a_SOURCES = \
        id.c \
        idcache.c \
-       silcbuffer.c \
-       silcbuffmt.c \
-       silcbufutil.c \
        silcchannel.c \
        silccommand.c \
-       silcconfig.c \
-       silclog.c \
-       silcmemory.c \
-       silcnet.c \
        silcpacket.c \
        silcprotocol.c \
-       silcschedule.c \
        silcsockconn.c \
-       silctask.c \
-       silcutil.c
+       silcpayload.c \
+       silcnotify.c
 
 EXTRA_DIST = *.h
 
 INCLUDES = -I. -I.. -I../silccrypt -I../silcmath -I../silcske \
-       -I../silcsim -I../.. -I../../includes \
-       -I../silcmath/gmp-3.0.1
+       -I../silcsim -I../.. -I../silcutil -I../../includes \
+       -I../silcmath/gmp -I../trq
index 324c9cfe31b541881f854dffb4afbfc36d719b7f..ccfa04ca5752574f21240f7c814a90fab3becf0d 100644 (file)
 /*
  * $Id$
  * $Log$
+ * Revision 1.2  2000/07/05 06:06:35  priikone
+ *     Global cosmetic change.
+ *
  * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
- *     Importet from internal CVS/Added Log headers.
+ *     Imported from internal CVS/Added Log headers.
  *
  *
  */
index 56551c4ae02e2e236eb94209f536be183d76dc7c..9da7f87376c04510ceccb153cd96ab04f3e3647b 100644 (file)
@@ -42,7 +42,7 @@
 #define SILC_ID_CHANNEL 3
 
 /* Type definition for the ID types. */
-typedef unsigned char SilcIdType;
+typedef unsigned short SilcIdType;
 
 /* 
    64 bit SilcServerID structure:
index 6f9c13077a472d62e0b180e6133e650c4c4b651b..9dc176f3c84401806870adab7decc839a0427924 100644 (file)
   GNU General Public License for more details.
 
 */
-/* XXX: This ID cache system sucks and must be rewritten! */
-/*
- * $Id$
- * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
- *     Importet from internal CVS/Added Log headers.
- *
- *
- */
+/* $Id$ */
 
 #include "silcincludes.h"
+#include "idcache.h"
+
+/* Static prototypes */
+static int silc_idcache_sorter(const void *a, const void *b);
+static SilcIDCacheList silc_idcache_list_alloc();
+static void silc_idcache_list_add(SilcIDCacheList list, 
+                                 SilcIDCacheEntry cache);
+
+/*
+   SILC ID Cache object.
+
+   This is context for the ID cache system. This includes all the cache
+   entries and other internal data. This is read-only object and not
+   visible outside this cache system.
+
+   Fields are as follows:
+
+   SilcIDCacheEntry cache
+
+       Table of the cache entries allocated by silc_idcache_add function.
+       This table is reallocated when new entry is added into the cache.
+
+   unsigned int cache_count
+
+       Number of cache entries in the cache.
+
+   int sorted
+
+       Boolean value to indicate whether the cache is sorted or not. If
+       cache is not sorted the fast access (described next) cannot be used.
+       Sorting can be done by calling sorting function or when adding new
+       entries to the cache.
+
+   int fast_access[];
+
+       Table to provide fast access into the cache by index. When searching
+       by data this table is used to get the index to the first occurence
+       of that data (or part of the data) in the cache. Purpose of this
+       is to provide faster access to the cache when searching by data.
+       This is updated by silc_idcache_add and sorting functions.
+
+*/
+struct SilcIDCacheStruct {
+  SilcIDCacheEntry cache;
+  unsigned int cache_count;
+  int sorted;
+  int fast_access[256];
+};
+
+/* 
+   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. :)
+
+   By default the found cache entries are saved into the static cache
+   table to provide access without reallocation. However, if the static
+   table is full, rest of the cache entries are dynamically allocated
+   into `cache_dyn' table. Traversing functions automatically handles
+   these situations.
+
+*/
+struct SilcIDCacheListStruct {
+  SilcIDCacheEntry cache[64];
+  SilcIDCacheEntry *cache_dyn;
+  unsigned int cache_dyn_count;
+  unsigned int cache_count;
+  unsigned int pos;
+};
+
+/* 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. */
+
+SilcIDCache silc_idcache_alloc(unsigned int count)
+{
+  SilcIDCache cache;
+
+  SILC_LOG_DEBUG(("Allocating new cache"));
+
+  cache = silc_calloc(1, sizeof(*cache));
+  cache->cache = silc_calloc(count ? count : 5, sizeof(*cache->cache));
+  cache->cache_count = count ? count : 5;
+  memset(cache->fast_access, -1, sizeof(cache->fast_access));
+
+  return cache;
+}
+
+/* Free's ID cache object and cache entries */
+
+void silc_idcache_free(SilcIDCache cache)
+{
+  if (cache) {
+    silc_free(cache->cache);
+    silc_free(cache);
+  }
+}
 
 /* qsort() sorter function. */
 
 static int silc_idcache_sorter(const void *a, const void *b)
 {
-  SilcIDCache *a1, *b1;
-  
-  a1 = (SilcIDCache *)a;
-  b1 = (SilcIDCache *)b;
+  SilcIDCacheEntry a1, b1;
+
+  a1 = (SilcIDCacheEntry)a;
+  b1 = (SilcIDCacheEntry)b;
   
+  if (!a1->data && !b1->data)
+    return 0;
+
+  if (!a1->data)
+    return -1;
+
+  if (!b1->data)
+    return 1;
+
   return a1->data[0] - b1->data[0];
 }
 
-/* Sorts given cache by data */
+/* Sorts given cache by data. After sorting this updates the fast access
+   table that can be used to access the cache faster. */
 
-void silc_idcache_sort_by_data(SilcIDCache *cache, unsigned int count)
+void silc_idcache_sort_by_data(SilcIDCache cache)
 {
-  qsort(cache, count, sizeof(*cache), silc_idcache_sorter);
+  int i;
+
+  qsort(cache->cache, cache->cache_count, 
+       sizeof(*cache->cache), silc_idcache_sorter);
+
+  memset(cache->fast_access, -1, sizeof(cache->fast_access));
+
+  /* Update the fast access table (this of course takes its own time when
+     the cache is very large). */
+  for (i = 0; i < cache->cache_count; i++) {
+    if (cache->cache[i].data &&
+       cache->fast_access[(int)cache->cache[i].data[0]] == -1)
+      cache->fast_access[(int)cache->cache[i].data[0]] = i;
+  }
+
+  cache->sorted = TRUE;
 }
 
 /* Find ID Cache entry by data. The data maybe anything that must
-   match exactly. */
+   match exactly. Returns list of cache entries. */
 
-int silc_idcache_find_by_data(SilcIDCache *cache, unsigned int cache_count,
-                             char *data, SilcIDCache **ret)
+int silc_idcache_find_by_data(SilcIDCache cache, char *data, 
+                             SilcIDCacheList *ret)
 {
   int i;
+  SilcIDCacheList list;
+
+  if (!cache || !cache->cache || !data)
+    return FALSE;
+
+  list = silc_idcache_list_alloc();
+
+  if (cache->sorted)
+    i = cache->fast_access[(int)data[0]];
+  else
+    i = 0;
+
+  for (i = i; i < cache->cache_count; i++) {
+    if (cache->sorted && cache->cache[i].data &&
+       cache->cache[i].data[0] != data[0])
+      break;
+
+    if (cache->cache[i].data && 
+       !memcmp(cache->cache[i].data, data, strlen(cache->cache[i].data)))
+      silc_idcache_list_add(list, &(cache->cache[i]));
+  }
 
-  if (cache == NULL)
+  if (!silc_idcache_list_count(list))
     return FALSE;
 
-  if (data == NULL)
+  if (ret)
+    *ret = list;
+  else
+    silc_idcache_list_free(list);
+
+  return TRUE;
+}
+
+/* Find ID Cache entry by data. The data maybe anything that must
+   match exactly. Returns one cache entry. */
+
+int silc_idcache_find_by_data_one(SilcIDCache cache, char *data,
+                                 SilcIDCacheEntry *ret)
+{
+  int i;
+
+  if (!cache || !cache->cache || !data)
     return FALSE;
 
-  for (i = 0; i < cache_count; i++)
-    if (cache[i].data && !memcmp(cache[i].data, data, strlen(data))) {
+  if (cache->sorted)
+    i = cache->fast_access[(int)data[0]];
+  else
+    i = 0;
+
+  for (i = i; i < cache->cache_count; i++)
+    if (cache->cache[i].data && 
+       !memcmp(cache->cache[i].data, data, strlen(cache->cache[i].data))) {
       if (ret)
-       *ret = &(cache[i]);
+       *ret = &(cache->cache[i]);
       return TRUE;
     }
 
   return FALSE;
 }
 
-/* Find ID Cache entry by ID. */
+/* Find ID Cache entry by data, loosely. The data don't have to be 100%
+   match. This ignores data case-sensitivity when searching with this
+   function. Returns list of cache entries. */
+
+int silc_idcache_find_by_data_loose(SilcIDCache cache, char *data, 
+                                   SilcIDCacheList *ret)
+{
+  int i, c;
+  SilcIDCacheList list;
+
+  if (!cache || !cache->cache || !data)
+    return FALSE;
+
+  list = silc_idcache_list_alloc();
+
+  c = tolower((int)data[0]);
+
+  if (cache->sorted)
+    i = cache->fast_access[c];
+  else
+    i = 0;
+
+  for (i = i; i < cache->cache_count; i++) {
+    if (cache->sorted && cache->cache[i].data &&
+       cache->cache[i].data[0] != (char)c)
+      break;
+    
+    if (cache->cache[i].data && 
+       !strcasecmp(cache->cache[i].data, data))
+      silc_idcache_list_add(list, &(cache->cache[i]));
+  }
+
+  if (cache->sorted) {
+    c = toupper((int)data[0]);
+    i = cache->fast_access[c];
+
+    for (i = i; i < cache->cache_count; i++) {
+      if (cache->sorted && cache->cache[i].data &&
+         cache->cache[i].data[0] != (char)c)
+       break;
+
+      if (cache->cache[i].data && 
+         !strcasecmp(cache->cache[i].data, data))
+       silc_idcache_list_add(list, &(cache->cache[i]));
+    }
+  }
+    
+  if (!silc_idcache_list_count(list))
+    return FALSE;
+
+  if (ret)
+    *ret = list;
+  else
+    silc_idcache_list_free(list);
+
+  return TRUE;
+}
+
+/* Find ID Cache entry by ID. Returns list of cache entries. If `id' is
+   SILC_ID_CACHE_ANY this returns all ID's of type `type'. */
 
-int silc_idcache_find_by_id(SilcIDCache *cache, unsigned int cache_count, 
-                           void *id, SilcIdType type, SilcIDCache **ret)
+int silc_idcache_find_by_id(SilcIDCache cache, void *id, SilcIdType type,
+                           SilcIDCacheList *ret)
 {
   int i, id_len;
+  SilcIDCacheList list;
 
-  if (cache == NULL)
+  if (!cache || !cache->cache || !id)
     return FALSE;
 
-  if (id == NULL)
+  id_len = silc_id_get_len(type);
+
+  list = silc_idcache_list_alloc();
+
+  if (id != SILC_ID_CACHE_ANY) {
+    for (i = 0; i < cache->cache_count; i++)
+      if (cache->cache[i].id && !memcmp(cache->cache[i].id, id, id_len))
+       silc_idcache_list_add(list, &(cache->cache[i]));
+  } else {
+    for (i = 0; i < cache->cache_count; i++)
+      if (cache->cache[i].id && cache->cache[i].type == type)
+       silc_idcache_list_add(list, &(cache->cache[i]));
+  }
+
+  if (!silc_idcache_list_count(list))
+    return FALSE;
+
+  if (ret)
+    *ret = list;
+  else
+    silc_idcache_list_free(list);
+
+  return TRUE;
+}
+
+/* Find ID Cache entry by ID. Returns one cache entry. */
+
+int silc_idcache_find_by_id_one(SilcIDCache cache, void *id, SilcIdType type, 
+                               SilcIDCacheEntry *ret)
+{
+  int i, id_len;
+
+  if (!cache || !cache->cache || !id)
     return FALSE;
 
   id_len = silc_id_get_len(type);
 
-  for (i = 0; i < cache_count; i++)
-    if (cache[i].id && !memcmp(cache[i].id, id, id_len)) {
+  for (i = 0; i < cache->cache_count; i++)
+    if (cache->cache[i].id && !memcmp(cache->cache[i].id, id, id_len)) {
+      if (ret)
+       *ret = &(cache->cache[i]);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+/* Finds cache entry by context. */
+
+int silc_idcache_find_by_context(SilcIDCache cache, void *context, 
+                                SilcIDCacheEntry *ret)
+{
+  int i;
+
+  if (!cache || !cache->cache || !context)
+    return FALSE;
+
+  for (i = 0; i < cache->cache_count; i++)
+    if (cache->cache[i].context && cache->cache[i].context == context) {
       if (ret)
-       *ret = &(cache[i]);
+       *ret = &(cache->cache[i]);
       return TRUE;
     }
 
   return FALSE;
 }
 
-/* Add new entry to the cache. Returns number of allocated cache
-   entries in the cache. */
+/* Add new entry to the cache. Returns TRUE or FALSE. If `sort' is TRUE
+   then the cache is sorted after the new entry has been added. The
+   cache must be sorted in order for the fast access feature to work,
+   however, it is not mandatory. */
 
-int silc_idcache_add(SilcIDCache **cache, unsigned int cache_count,
-                    char *data, SilcIdType id_type, void *id, 
-                    void *context)
+int silc_idcache_add(SilcIDCache cache, char *data, SilcIdType id_type,
+                    void *id, void *context, int sort)
 {
-  SilcIDCache *c;
   int i;
+  unsigned int count;
   unsigned long curtime = time(NULL);
+  SilcIDCacheEntry c;
+
+  if (!cache || !cache->cache)
+    return FALSE;
 
   SILC_LOG_DEBUG(("Adding cache entry"));
 
-  c = *cache;
+  c = cache->cache;
+  count = cache->cache_count;
 
   if (c == NULL) {
     c = silc_calloc(5, sizeof(*c));
-    if (!c)
-      return 0;
-    cache_count = 5;
+    count = 5;
   }
 
   /* See if it exists already */
-  if (silc_idcache_find_by_id(c, cache_count, id, id_type, NULL) == TRUE)
-    return cache_count;
+  /* XXX this slows down this function. */
+  if (silc_idcache_find_by_id(cache, id, id_type, NULL))
+    return FALSE;
 
-  for (i = 0; i < cache_count; i++) {
-    if (c[i].data == NULL) {
+  for (i = 0; i < count; i++) {
+    if (c[i].data == NULL && c[i].id == NULL) {
       c[i].data = data;
       c[i].type = id_type;
       c[i].id = id;
@@ -134,31 +408,34 @@ int silc_idcache_add(SilcIDCache **cache, unsigned int cache_count,
     }
   }
 
-  if (i == cache_count) {
-    c = silc_realloc(c, sizeof(*c) * (cache_count + 5));
-    if (!c)
-      return cache_count;
-    for (i = cache_count; i < cache_count + 5; i++) {
+  if (i == count) {
+    c = silc_realloc(c, sizeof(*c) * (count + 5));
+    for (i = count; i < count + 5; i++) {
       c[i].data = NULL;
       c[i].id = NULL;
     }
-    c[cache_count].data = data;
-    c[cache_count].type = id_type;
-    c[cache_count].id = id;
-    c[cache_count].expire = curtime + SILC_ID_CACHE_EXPIRE;
-    c[cache_count].context = context;
-    cache_count += 5;
+    c[count].data = data;
+    c[count].type = id_type;
+    c[count].id = id;
+    c[count].expire = curtime + SILC_ID_CACHE_EXPIRE;
+    c[count].context = context;
+    count += 5;
   }
 
-  *cache = c;
+  cache->cache = c;
+  cache->cache_count = count;
+  cache->sorted = sort;
+
+  if (sort)
+    silc_idcache_sort_by_data(cache);
 
-  return cache_count;
+  return TRUE;
 }
 
 /* Delete cache entry from cache. */
 /* XXX */
 
-int silc_idcache_del(SilcIDCache *cache, SilcIDCache *old)
+int silc_idcache_del(SilcIDCache cache, SilcIDCacheEntry old)
 {
 
   return TRUE;
@@ -166,8 +443,7 @@ int silc_idcache_del(SilcIDCache *cache, SilcIDCache *old)
 
 /* XXX */
 
-int silc_idcache_del_by_data(SilcIDCache *cache, unsigned int cache_count,
-                            char *data)
+int silc_idcache_del_by_data(SilcIDCache cache, char *data)
 {
 
   return TRUE;
@@ -175,25 +451,21 @@ int silc_idcache_del_by_data(SilcIDCache *cache, unsigned int cache_count,
 
 /* Deletes ID cache entry by ID. */
 
-int silc_idcache_del_by_id(SilcIDCache *cache, unsigned int cache_count,
-                          SilcIdType type, void *id)
+int silc_idcache_del_by_id(SilcIDCache cache, SilcIdType type, void *id)
 {
   int i, id_len;
 
-  if (cache == NULL)
-    return FALSE;
-
-  if (id == NULL)
+  if (!cache || !cache->cache || !id)
     return FALSE;
 
   id_len = silc_id_get_len(type);
 
-  for (i = 0; i < cache_count; i++)
-    if (cache[i].id && !memcmp(cache[i].id, id, id_len)) {
-      cache[i].id = NULL;
-      cache[i].data = NULL;
-      cache[i].type = 0;
-      cache[i].context = NULL;
+  for (i = 0; i < cache->cache_count; i++)
+    if (cache->cache[i].id && !memcmp(cache->cache[i].id, id, id_len)) {
+      cache->cache[i].id = NULL;
+      cache->cache[i].data = NULL;
+      cache->cache[i].type = 0;
+      cache->cache[i].context = NULL;
       return TRUE;
     }
 
@@ -202,24 +474,14 @@ int silc_idcache_del_by_id(SilcIDCache *cache, unsigned int cache_count,
 
 /* Deletes all ID entries from cache. Free's memory as well. */
 
-int silc_idcache_del_all(SilcIDCache **cache, unsigned int cache_count)
+int silc_idcache_del_all(SilcIDCache cache)
 {
-  SilcIDCache *c = *cache;
-  int i;
-
-  if (c == NULL)
+  if (!cache || !cache->cache)
     return FALSE;
 
-  for (i = 0; i < cache_count; i++) {
-    c[i].id = NULL;
-    c[i].data = NULL;
-    c[i].type = 0;
-    c[i].expire = 0;
-    c[i].context = NULL;
-  }
-
-  silc_free(*cache);
-  *cache = NULL;
+  silc_free(cache->cache);
+  cache->cache = NULL;
+  cache->cache_count = 0;
 
   return TRUE;
 }
@@ -227,24 +489,146 @@ int silc_idcache_del_all(SilcIDCache **cache, unsigned int cache_count)
 /* Purges the cache by removing expired cache entires. This does not
    free any memory though. */
 
-int silc_idcache_purge(SilcIDCache *cache, unsigned int cache_count)
+int silc_idcache_purge(SilcIDCache cache)
 {
+  SilcIDCacheEntry c;
   unsigned long curtime = time(NULL);
   int i;
 
-  if (cache == NULL)
+  if (!cache || !cache->cache)
     return FALSE;
 
-  for (i = 0; i < cache_count; i++) {
-    if (cache[i].data && 
-       (cache[i].expire == 0 || cache[i].expire < curtime)) {
-      cache[i].id = NULL;
-      cache[i].data = NULL;
-      cache[i].type = 0;
-      cache[i].expire = 0;
-      cache[i].context = NULL;
+  c = cache->cache;
+
+  for (i = 0; i < cache->cache_count; i++) {
+    if (c[i].data && 
+       (c[i].expire == 0 || c[i].expire < curtime)) {
+      c[i].id = NULL;
+      c[i].data = NULL;
+      c[i].type = 0;
+      c[i].expire = 0;
+      c[i].context = NULL;
+    }
+  }
+
+  return TRUE;
+}
+
+/* Allocates ID cache list. */
+
+static SilcIDCacheList silc_idcache_list_alloc()
+{
+  SilcIDCacheList list;
+
+  list = silc_calloc(1, sizeof(*list));
+
+  return list;
+}
+
+/* Adds cache entry to the ID cache list. If needed reallocates memory
+   for the list. */
+
+static void silc_idcache_list_add(SilcIDCacheList list, SilcIDCacheEntry cache)
+{
+  int i;
+
+  /* Try to add to static cache */
+  if (!list->cache_dyn_count)
+    for (i = 0; i < sizeof(list->cache); i++) {
+      if (!list->cache[i]) {
+       list->cache[i] = cache;
+       list->cache_count++;
+       return;
+      }
     }
+
+  /* Static cache is full, allocate dynamic cache */
+  for (i = 0; i < list->cache_dyn_count; i++) {
+    if (!list->cache_dyn[i]) {
+      list->cache_dyn[i] = cache;
+      list->cache_count++;
+      break;
+    }
+  }
+
+  if (i >= list->cache_dyn_count) {
+    int k;
+
+    i += 5;
+    list->cache_dyn = silc_realloc(list->cache_dyn, 
+                                  sizeof(*list->cache) * (i));
+
+    /* NULL the reallocated area */
+    for (k = list->cache_dyn_count; k < i; k++)
+      list->cache_dyn[k] = NULL;
+
+    list->cache_dyn[list->cache_dyn_count] = cache;
+    list->cache_dyn_count = i;
+    list->cache_count++;
+  }
+}
+
+/* Returns number of cache entries in the ID cache list. */
+
+int silc_idcache_list_count(SilcIDCacheList list)
+{
+  return list->cache_count;
+}
+
+/* Returns first entry from the ID cache list. */
+
+int silc_idcache_list_first(SilcIDCacheList list, SilcIDCacheEntry *ret)
+{
+  list->pos = 0;
+
+  if (!list->cache[list->pos])
+    return FALSE;
+  
+  if (ret)
+    *ret = list->cache[list->pos];
+
+  return TRUE;
+}
+
+/* Returns next entry from the ID cache list. */
+
+int silc_idcache_list_next(SilcIDCacheList list, SilcIDCacheEntry *ret)
+{
+  int dyn = FALSE;
+  list->pos++;
+
+  if (list->pos >= sizeof(list->cache)) {
+    list->pos = 0;
+    dyn = TRUE;
   }
 
+  if (dyn && list->pos >= list->cache_dyn_count)
+    return FALSE;
+
+  if (!dyn && !list->cache[list->pos])
+    return FALSE;
+  
+  if (dyn && !list->cache_dyn[list->pos])
+    return FALSE;
+  
+  if (ret) {
+    if (!dyn)
+      *ret = list->cache[list->pos];
+    else
+      *ret = list->cache_dyn[list->pos];
+  }
+  
   return TRUE;
 }
+
+/* Free's ID cache list. User must free the list object returned by
+   any of the searching functions. */
+
+void silc_idcache_list_free(SilcIDCacheList list)
+{
+  if (list) {
+    if (list->cache_dyn)
+      silc_free(list->cache_dyn);
+    silc_free(list);
+  }
+}
index 074dc48ed000b5e0f25eb4eace78b1d7376da430..582019ceff79d3405458b68ddd73c75c3a4c4404 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
 
-  Copyright (C) 1997 - 2000 Pekka Riikonen
+  Copyright (C) 2000 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 IDCACHE_H
 
 /* 
-   SilcIDCache structure.
+   Silc ID Cache Entry object.
+
+   This is one entry in the SILC ID Cache system. Contents of this is
+   allocated outside the ID cache system, however, all the fields are 
+   filled with ID cache utility functions. The ID cache system does not
+   allocate any of these fields nor free them.
 
    char *data
 
@@ -55,25 +60,44 @@ typedef struct {
   void *id;
   unsigned long expire;
   void *context;
-} SilcIDCache;
+} *SilcIDCacheEntry;
+
+/* Forward declaration for SILC ID Cache object. */
+typedef struct SilcIDCacheStruct *SilcIDCache;
+
+/* Forward declaration for ID Cache List */
+typedef struct SilcIDCacheListStruct *SilcIDCacheList;
+
+#define SILC_ID_CACHE_ANY ((void *)1)
 
 #define SILC_ID_CACHE_EXPIRE 3600
 
 /* Prototypes */
-void silc_idcache_sort_by_data(SilcIDCache *cache, unsigned int count);
-int silc_idcache_find_by_data(SilcIDCache *cache, unsigned int cache_count,
-                             char *data, SilcIDCache **ret);
-int silc_idcache_find_by_id(SilcIDCache *cache, unsigned int cache_count, 
-                           void *id, SilcIdType type, SilcIDCache **ret);
-int silc_idcache_add(SilcIDCache **cache, unsigned int cache_count,
-                    char *data, SilcIdType id_type, void *id, 
-                    void *context);
-int silc_idcache_del(SilcIDCache *cache, SilcIDCache *old);
-int silc_idcache_del_by_data(SilcIDCache *cache, unsigned int cache_count,
-                            char *data);
-int silc_idcache_del_by_id(SilcIDCache *cache, unsigned int cache_count,
-                          SilcIdType type, void *id);
-int silc_idcache_del_all(SilcIDCache **cache, unsigned int cache_count);
-int silc_idcache_purge(SilcIDCache *cache, unsigned int cache_count);
+SilcIDCache silc_idcache_alloc(unsigned int count);
+void silc_idcache_free(SilcIDCache cache);
+void silc_idcache_sort_by_data(SilcIDCache cache);
+int silc_idcache_find_by_data(SilcIDCache cache, char *data, 
+                             SilcIDCacheList *ret);
+int silc_idcache_find_by_data_one(SilcIDCache cache, char *data,
+                                 SilcIDCacheEntry *ret);
+int silc_idcache_find_by_data_loose(SilcIDCache cache, char *data, 
+                                   SilcIDCacheList *ret);
+int silc_idcache_find_by_id(SilcIDCache cache, void *id, SilcIdType type,
+                           SilcIDCacheList *ret);
+int silc_idcache_find_by_id_one(SilcIDCache cache, void *id, SilcIdType type, 
+                               SilcIDCacheEntry *ret);
+int silc_idcache_find_by_context(SilcIDCache cache, void *context, 
+                                SilcIDCacheEntry *ret);
+int silc_idcache_add(SilcIDCache cache, char *data, SilcIdType id_type,
+                    void *id, void *context, int sort);
+int silc_idcache_del(SilcIDCache cache, SilcIDCacheEntry old);
+int silc_idcache_del_by_data(SilcIDCache cache, char *data);
+int silc_idcache_del_by_id(SilcIDCache cache, SilcIdType type, void *id);
+int silc_idcache_del_all(SilcIDCache cache);
+int silc_idcache_purge(SilcIDCache cache);
+int silc_idcache_list_count(SilcIDCacheList list);
+int silc_idcache_list_first(SilcIDCacheList list, SilcIDCacheEntry *ret);
+int silc_idcache_list_next(SilcIDCacheList list, SilcIDCacheEntry *ret);
+void silc_idcache_list_free(SilcIDCacheList list);
 
 #endif
index bb183cb0870499fccf7ce9661d1be44305821885..c2226da4439c056d0deadd753eb8ed61ed1c2b3e 100644 (file)
   GNU General Public License for more details.
 
 */
-/*
- * $Id$
- * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
- *     Importet from internal CVS/Added Log headers.
- *
- *
- */
+/* Channel Payload and Channel Key Payload implementations. */
+/* $Id$ */
 
 #include "silcincludes.h"
 #include "silcchannel.h"
 
+/******************************************************************************
+
+                              Channel Payload
+
+******************************************************************************/
+
 /* Channel Payload structure. Contents of this structure is parsed
    from SILC packets. */
 struct SilcChannelPayloadStruct {
-  unsigned short nick_len;
-  unsigned char *nick;
   unsigned short data_len;
   unsigned char *data;
   unsigned short iv_len;
   unsigned char *iv;
 };
 
-/* Channel Key Payload structrue. Channel keys are parsed from SILC
-   packets into this structure. */
-struct SilcChannelKeyPayloadStruct {
-  unsigned short id_len;
-  unsigned char *id;
-  unsigned short cipher_len;
-  unsigned char *cipher;
-  unsigned short key_len;
-  unsigned char *key;
-};
-
 /* Parses channel payload returning new channel payload structure */
 
-SilcChannelPayload silc_channel_parse_payload(SilcBuffer buffer)
+SilcChannelPayload silc_channel_payload_parse(SilcBuffer buffer)
 {
   SilcChannelPayload new;
 
   SILC_LOG_DEBUG(("Parsing channel payload"));
 
   new = silc_calloc(1, sizeof(*new));
-  if (!new) {
-    SILC_LOG_ERROR(("Could not allocate new channel payload"));
-    return NULL;
-  }
 
   /* Parse the Channel Payload. Ignore padding and IV, we don't need
      them. */
   silc_buffer_unformat(buffer,
-                      SILC_STR_UI16_NSTRING_ALLOC(&new->nick, &new->nick_len),
                       SILC_STR_UI16_NSTRING_ALLOC(&new->data, &new->data_len),
                       SILC_STR_UI16_NSTRING_ALLOC(NULL, NULL),
                       SILC_STR_END);
 
-  if (new->data_len < 1) {
+  if (new->data_len < 1 || new->data_len > buffer->len) {
     SILC_LOG_ERROR(("Incorrect channel payload in packet, packet dropped"));
     goto err;
   }
@@ -81,8 +63,6 @@ SilcChannelPayload silc_channel_parse_payload(SilcBuffer buffer)
   return new;
 
  err:
-  if (new->nick)
-    silc_free(new->nick);
   if (new->data)
     silc_free(new->data);
   if (new->iv)
@@ -96,9 +76,7 @@ SilcChannelPayload silc_channel_parse_payload(SilcBuffer buffer)
    encrypted separately from other parts of the packet padding must
    be applied to the payload. */
 
-SilcBuffer silc_channel_encode_payload(unsigned short nick_len,
-                                      unsigned char *nick,
-                                      unsigned short data_len,
+SilcBuffer silc_channel_payload_encode(unsigned short data_len,
                                       unsigned char *data,
                                       unsigned short iv_len,
                                       unsigned char *iv,
@@ -113,14 +91,12 @@ SilcBuffer silc_channel_encode_payload(unsigned short nick_len,
 
   /* Calculate length of padding. IV is not included into the calculation
      since it is not encrypted. */
-  len = 2 + nick_len + 2 + data_len + 2;
+  len = 2 + data_len + 2;
   pad_len = SILC_PACKET_PADLEN((len + 2));
 
   /* Allocate channel payload buffer */
   len += pad_len;
   buffer = silc_buffer_alloc(len + iv_len);
-  if (!buffer)
-    return NULL;
 
   /* Generate padding */
   for (i = 0; i < pad_len; i++)
@@ -130,8 +106,6 @@ SilcBuffer silc_channel_encode_payload(unsigned short nick_len,
 
   /* Encode the Channel Payload */
   silc_buffer_format(buffer, 
-                    SILC_STR_UI_SHORT(nick_len),
-                    SILC_STR_UI_XNSTRING(nick, nick_len),
                     SILC_STR_UI_SHORT(data_len),
                     SILC_STR_UI_XNSTRING(data, data_len),
                     SILC_STR_UI_SHORT(pad_len),
@@ -145,7 +119,7 @@ SilcBuffer silc_channel_encode_payload(unsigned short nick_len,
 
 /* Free's Channel Payload */
 
-void silc_channel_free_payload(SilcChannelPayload payload)
+void silc_channel_payload_free(SilcChannelPayload payload)
 {
   if (payload) {
     if (payload->data)
@@ -156,17 +130,6 @@ void silc_channel_free_payload(SilcChannelPayload payload)
   }
 }
 
-/* Return nickname */
-
-unsigned char *silc_channel_get_nickname(SilcChannelPayload payload,
-                                        unsigned int *nick_len)
-{
-  if (nick_len)
-    *nick_len = payload->nick_len;
-
-  return payload->nick;
-}
-
 /* Return data */
 
 unsigned char *silc_channel_get_data(SilcChannelPayload payload,
@@ -189,19 +152,32 @@ unsigned char *silc_channel_get_iv(SilcChannelPayload payload,
   return payload->iv;
 }
 
+/******************************************************************************
+
+                             Channel Key Payload
+
+******************************************************************************/
+
+/* Channel Key Payload structrue. Channel keys are parsed from SILC
+   packets into this structure. */
+struct SilcChannelKeyPayloadStruct {
+  unsigned short id_len;
+  unsigned char *id;
+  unsigned short cipher_len;
+  unsigned char *cipher;
+  unsigned short key_len;
+  unsigned char *key;
+};
+
 /* Parses channel key payload returning new channel key payload structure */
 
-SilcChannelKeyPayload silc_channel_key_parse_payload(SilcBuffer buffer)
+SilcChannelKeyPayload silc_channel_key_payload_parse(SilcBuffer buffer)
 {
   SilcChannelKeyPayload new;
 
   SILC_LOG_DEBUG(("Parsing channel key payload"));
 
   new = silc_calloc(1, sizeof(*new));
-  if (!new) {
-    SILC_LOG_ERROR(("Could not allocate new channel key payload"));
-    return NULL;
-  }
 
   /* Parse the Channel Key Payload */
   silc_buffer_unformat(buffer,
@@ -232,7 +208,7 @@ SilcChannelKeyPayload silc_channel_key_parse_payload(SilcBuffer buffer)
 /* Encodes channel key payload into a buffer and returns it. This is used 
    to add channel key payload into a packet. */
 
-SilcBuffer silc_channel_key_encode_payload(unsigned short id_len,
+SilcBuffer silc_channel_key_payload_encode(unsigned short id_len,
                                           unsigned char *id,
                                           unsigned short cipher_len,
                                           unsigned char *cipher,
@@ -252,8 +228,6 @@ SilcBuffer silc_channel_key_encode_payload(unsigned short id_len,
      2 + cipher */
   len = 2 + id_len + 2 + key_len + 2 + cipher_len;
   buffer = silc_buffer_alloc(len);
-  if (!buffer)
-    return NULL;
 
   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
 
@@ -272,7 +246,7 @@ SilcBuffer silc_channel_key_encode_payload(unsigned short id_len,
 
 /* Free's Channel Key Payload */
 
-void silc_channel_key_free_payload(SilcChannelKeyPayload payload)
+void silc_channel_key_payload_free(SilcChannelKeyPayload payload)
 {
   if (payload) {
     if (payload->id)
index b39045fa9d80472de3d9fe40780515767e49f558..e3382e7b8361db8b04184811835942f59a0a964a 100644 (file)
@@ -30,41 +30,43 @@ typedef struct SilcChannelPayloadStruct *SilcChannelPayload;
 typedef struct SilcChannelKeyPayloadStruct *SilcChannelKeyPayload;
 
 /* Channel modes */
-#define SILC_CHANNEL_MODE_NONE       0x0000
-#define SILC_CHANNEL_MODE_PRIVATE    0x0001 /* private channel */
-#define SILC_CHANNEL_MODE_SECRET     0x0002 /* secret channel */
-#define SILC_CHANNEL_MODE_PRIVKEY    0x0004 /* channel has private key */
-#define SILC_CHANNEL_MODE_INVITE     0x0008 /* invite only channel */
+#define SILC_CHANNEL_MODE_NONE        0x0000
+#define SILC_CHANNEL_MODE_PRIVATE     0x0001 /* private channel */
+#define SILC_CHANNEL_MODE_SECRET      0x0002 /* secret channel */
+#define SILC_CHANNEL_MODE_PRIVKEY     0x0004 /* channel has private key */
+#define SILC_CHANNEL_MODE_INVITE      0x0008 /* invite only channel */
+#define SILC_CHANNEL_MODE_TOPIC       0x0010 /* topic setting by operator */
+#define SILC_CHANNEL_MODE_ULIMIT      0x0020 /* user limit set */
+#define SILC_CHANNEL_MODE_PASSPHRASE  0x0040 /* passphrase set */
+#define SILC_CHANNEL_MODE_BAN         0x0080 /* ban list set */
+#define SILC_CHANNEL_MODE_INVITE_LIST 0x0100 /* invite list set */
+#define SILC_CHANNEL_MODE_CIPHER      0x0200 /* sets cipher of channel */
 
 /* User modes on channel */
-#define SILC_CHANNEL_UMODE_NONE      0x0000
-#define SILC_CHANNEL_UMODE_CHANFO    0x0001 /* channel founder */
-#define SILC_CHANNEL_UMODE_CHANOP    0x0002 /* channel operator */
+#define SILC_CHANNEL_UMODE_NONE       0x0000 /* Normal user */
+#define SILC_CHANNEL_UMODE_CHANFO     0x0001 /* channel founder */
+#define SILC_CHANNEL_UMODE_CHANOP     0x0002 /* channel operator */
 
 /* Prototypes */
-SilcChannelPayload silc_channel_parse_payload(SilcBuffer buffer);
-SilcBuffer silc_channel_encode_payload(unsigned short nick_len,
-                                      unsigned char *nick,
-                                      unsigned short data_len,
+SilcChannelPayload silc_channel_payload_parse(SilcBuffer buffer);
+SilcBuffer silc_channel_payload_encode(unsigned short data_len,
                                       unsigned char *data,
                                       unsigned short iv_len,
                                       unsigned char *iv,
                                       SilcRng rng);
-void silc_channel_free_payload(SilcChannelPayload payload);
-unsigned char *silc_channel_get_nickname(SilcChannelPayload payload,
-                                        unsigned int *nick_len);
+void silc_channel_payload_free(SilcChannelPayload payload);
 unsigned char *silc_channel_get_data(SilcChannelPayload payload,
                                     unsigned int *data_len);
 unsigned char *silc_channel_get_iv(SilcChannelPayload payload,
                                   unsigned int *iv_len);
-SilcChannelKeyPayload silc_channel_key_parse_payload(SilcBuffer buffer);
-SilcBuffer silc_channel_key_encode_payload(unsigned short id_len,
+SilcChannelKeyPayload silc_channel_key_payload_parse(SilcBuffer buffer);
+SilcBuffer silc_channel_key_payload_encode(unsigned short id_len,
                                           unsigned char *id,
                                           unsigned short cipher_len,
                                           unsigned char *cipher,
                                           unsigned short key_len,
                                           unsigned char *key);
-void silc_channel_key_free_payload(SilcChannelKeyPayload payload);
+void silc_channel_key_payload_free(SilcChannelKeyPayload payload);
 unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload, 
                                       unsigned int *id_len);
 unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload,
index cab272faf32ea705d514bc445da92930758832fc..6c45cdb87535ad3908406e2b1f10b1c12935f9fa 100644 (file)
   GNU General Public License for more details.
 
 */
-/*
- * $Id$
- * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
- *     Importet from internal CVS/Added Log headers.
- *
- *
- */
+/* $Id$ */
 
 #include "silcincludes.h"
 #include "silccommand.h"
 
+/******************************************************************************
+
+                              Command Payload
+
+******************************************************************************/
+
 /* Command Payload structure. Contents of this structure is parsed
    from SILC packets. */
 struct SilcCommandPayloadStruct {
   SilcCommand cmd;
-  unsigned int argc;
-  unsigned char **argv;
-  unsigned int *argv_lens;
-  unsigned int *argv_types;
-  unsigned int pos;
+  unsigned short ident;
+  SilcArgumentPayload args;
 };
 
 /* Length of the command payload */
-#define SILC_COMMAND_PAYLOAD_LEN 4
+#define SILC_COMMAND_PAYLOAD_LEN 6
 
 /* Parses command payload returning new command payload structure */
 
-SilcCommandPayload silc_command_parse_payload(SilcBuffer buffer)
+SilcCommandPayload silc_command_payload_parse(SilcBuffer buffer)
 {
   SilcCommandPayload new;
-  unsigned short payload_len = 0;
-  unsigned char args_num = 0;
-  unsigned char arg_num = 0;
-  unsigned int arg_type = 0;
-  unsigned int pull_len = 0;
-  int i = 0;
+  unsigned char args_num;
+  unsigned short payload_len;
 
   SILC_LOG_DEBUG(("Parsing command payload"));
 
   new = silc_calloc(1, sizeof(*new));
-  if (!new) {
-    SILC_LOG_ERROR(("Could not allocate new command payload"));
-    return NULL;
-  }
 
   /* Parse the Command Payload */
   silc_buffer_unformat(buffer, 
+                      SILC_STR_UI_SHORT(&payload_len),
                       SILC_STR_UI_CHAR(&new->cmd),
                       SILC_STR_UI_CHAR(&args_num),
-                      SILC_STR_UI_SHORT(&payload_len),
+                      SILC_STR_UI_SHORT(&new->ident),
                       SILC_STR_END);
 
   if (payload_len != buffer->len) {
     SILC_LOG_ERROR(("Incorrect command payload in packet, packet dropped"));
+    silc_free(new);
     return NULL;
   }
 
-  if (new->cmd == 0)
+  if (new->cmd == 0) {
+    silc_free(new);
     return NULL;
-
-  if (args_num && payload_len) {
-
-    new->argv = silc_calloc(args_num, sizeof(unsigned char *));
-    new->argv_lens = silc_calloc(args_num, sizeof(unsigned int));
-    new->argv_types = silc_calloc(args_num, sizeof(unsigned int));
-
-    silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN);
-    pull_len += SILC_COMMAND_PAYLOAD_LEN;
-
-    /* Parse Command Argument Payloads */
-    arg_num = 1;
-    while(arg_num) {
-      silc_buffer_unformat(buffer,
-                          SILC_STR_UI_CHAR(&arg_num),
-                          SILC_STR_UI_CHAR(&arg_type),
-                          SILC_STR_UI_SHORT(&payload_len),
-                          SILC_STR_END);
-
-      /* Check that argument number is correct */
-      if (arg_num != i + 1)
-       goto err;
-
-      new->argv_lens[i] = payload_len;
-      new->argv_types[i] = arg_type;
-
-      /* Get argument data */
-      silc_buffer_pull(buffer, 4);
-      silc_buffer_unformat(buffer,
-                          SILC_STR_UI_XNSTRING_ALLOC(&new->argv[i], 
-                                                     payload_len),
-                          SILC_STR_END);
-      silc_buffer_pull(buffer, payload_len);
-      pull_len += 4 + payload_len;
-
-      i++;
-
-      if (i == args_num)
-       break;
-    }
-
-    /* Check the number of arguments */
-    if (arg_num != args_num)
-      goto err;
-  }
-
-  new->argc = i;
-  new->pos = 0;
-
-  silc_buffer_push(buffer, pull_len);
-
-  return new;
-
- err:
-  if (i) {
-    int k;
-
-    for (k = 0; k < i; k++)
-      silc_free(new->argv[k]);
   }
 
-  silc_free(new->argv);
-  silc_free(new->argv_lens);
-  silc_free(new->argv_types);
-
-  if (new)
+  silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN);
+  new->args = silc_argument_payload_parse(buffer, args_num);
+  if (!new->args) {
     silc_free(new);
+    return NULL;
+  }
+  silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN);
 
-  return NULL;
+  return new;
 }
 
 /* Encodes Command Payload returning it to SilcBuffer. */
 
-SilcBuffer silc_command_encode_payload(SilcCommand cmd,
+SilcBuffer silc_command_payload_encode(SilcCommand cmd,
                                       unsigned int argc,
                                       unsigned char **argv,
                                       unsigned int *argv_lens,
-                                      unsigned int *argv_types)
+                                      unsigned int *argv_types,
+                                      unsigned short ident)
 {
   SilcBuffer buffer;
-  unsigned int len;
-  int i;
+  SilcBuffer args = NULL;
+  unsigned int len = 0;
 
   SILC_LOG_DEBUG(("Encoding command payload"));
 
-  len = 1 + 1 + 2;
-  for (i = 0; i < argc; i++)
-    len += 1 + 1 + 2 + argv_lens[i];
+  if (argc) {
+    args = silc_argument_payload_encode(argc, argv, argv_lens, argv_types);
+    len = args->len;
+  }
 
+  len += SILC_COMMAND_PAYLOAD_LEN;
   buffer = silc_buffer_alloc(len);
   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
 
   /* Create Command payload */
   silc_buffer_format(buffer,
+                    SILC_STR_UI_SHORT(len),
                     SILC_STR_UI_CHAR(cmd),
                     SILC_STR_UI_CHAR(argc),
-                    SILC_STR_UI_SHORT(len),
+                    SILC_STR_UI_SHORT(ident),
                     SILC_STR_END);
 
-  /* Put arguments */
+  /* Add arguments */
   if (argc) {
-    silc_buffer_pull(buffer, 4);
-   
-    for (i = 0; i < argc; i++) {
-      silc_buffer_format(buffer,
-                        SILC_STR_UI_CHAR(i + 1),
-                        SILC_STR_UI_CHAR(argv_types[i]),
-                        SILC_STR_UI_SHORT(argv_lens[i]),
-                        SILC_STR_UI_XNSTRING(argv[i], argv_lens[i]),
-                        SILC_STR_END);
-      silc_buffer_pull(buffer, 4 + argv_lens[i]);
-    }
-
-    silc_buffer_push(buffer, len);
+    silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN);
+    silc_buffer_format(buffer,
+                      SILC_STR_UI_XNSTRING(args->data, args->len),
+                      SILC_STR_END);
+    silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN);
+    silc_free(args);
   }
 
   return buffer;
 }
 
 /* Encodes Command payload with variable argument list. The arguments
-   must be: unsigned char *, unsigned int, ... One unsigned char *
-   and unsigned int forms one argument, hence `argc' in case when
-   sending one unsigned char * and unsigned int 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. */
-
-SilcBuffer silc_command_encode_payload_va(SilcCommand cmd, 
+   must be: unsigned int, unsigned char *, unsigned int, ... One 
+   {unsigned int, unsigned char * and unsigned int} forms one argument, 
+   thus `argc' in case when sending one {unsigned int, unsigned char * 
+   and unsigned int} 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, 
+                                         unsigned short ident, 
                                          unsigned int argc, ...)
 {
   va_list ap;
@@ -211,6 +143,7 @@ SilcBuffer silc_command_encode_payload_va(SilcCommand cmd,
   unsigned int *argv_lens = NULL, *argv_types = NULL;
   unsigned char *x;
   unsigned int x_len;
+  unsigned int x_type;
   SilcBuffer buffer;
   int i;
 
@@ -221,17 +154,18 @@ SilcBuffer silc_command_encode_payload_va(SilcCommand cmd,
   argv_types = silc_calloc(argc, sizeof(unsigned int));
 
   for (i = 0; i < argc; i++) {
+    x_type = va_arg(ap, unsigned int);
     x = va_arg(ap, unsigned char *);
     x_len = va_arg(ap, unsigned int);
 
     argv[i] = silc_calloc(x_len + 1, sizeof(unsigned char));
     memcpy(argv[i], x, x_len);
     argv_lens[i] = x_len;
-    argv_types[i] = i + 1;
+    argv_types[i] = x_type;
   }
 
-  buffer = silc_command_encode_payload(cmd, argc, argv, 
-                                      argv_lens, argv_types);
+  buffer = silc_command_payload_encode(cmd, argc, argv, 
+                                      argv_lens, argv_types, ident);
 
   for (i = 0; i < argc; i++)
     silc_free(argv[i]);
@@ -242,99 +176,131 @@ SilcBuffer silc_command_encode_payload_va(SilcCommand cmd,
   return buffer;
 }
 
-/* Free's Command Payload */
+/* Same as above but with va_list. */
 
-void silc_command_free_payload(SilcCommandPayload payload)
+SilcBuffer silc_command_payload_encode_vap(SilcCommand cmd, 
+                                          unsigned short ident, 
+                                          unsigned int argc, va_list ap)
 {
+  unsigned char **argv;
+  unsigned int *argv_lens = NULL, *argv_types = NULL;
+  unsigned char *x;
+  unsigned int x_len;
+  unsigned int x_type;
+  SilcBuffer buffer;
   int i;
 
-  if (payload) {
-    for (i = 0; i < payload->argc; i++)
-      silc_free(payload->argv[i]);
+  argv = silc_calloc(argc, sizeof(unsigned char *));
+  argv_lens = silc_calloc(argc, sizeof(unsigned int));
+  argv_types = silc_calloc(argc, sizeof(unsigned int));
 
-    silc_free(payload->argv);
-    silc_free(payload);
+  for (i = 0; i < argc; i++) {
+    x_type = va_arg(ap, unsigned int);
+    x = va_arg(ap, unsigned char *);
+    x_len = va_arg(ap, unsigned int);
+
+    argv[i] = silc_calloc(x_len + 1, sizeof(unsigned char));
+    memcpy(argv[i], x, x_len);
+    argv_lens[i] = x_len;
+    argv_types[i] = x_type;
   }
-}
 
-/* Returns the command type in payload */
+  buffer = silc_command_payload_encode(cmd, argc, argv, 
+                                      argv_lens, argv_types, ident);
 
-SilcCommand silc_command_get(SilcCommandPayload payload)
-{
-  return payload->cmd;
+  for (i = 0; i < argc; i++)
+    silc_free(argv[i]);
+  silc_free(argv);
+  silc_free(argv_lens);
+  silc_free(argv_types);
+
+  return buffer;
 }
 
-/* Returns number of arguments in payload */
+/* Same as above except that this is used to encode strictly command
+   reply packets. The command status message to be returned is sent as
+   extra argument to this function. The `argc' must not count `status'
+   as on argument. */
 
-unsigned int silc_command_get_arg_num(SilcCommandPayload payload)
+SilcBuffer 
+silc_command_reply_payload_encode_va(SilcCommand cmd, 
+                                    SilcCommandStatus status,
+                                    unsigned short ident,
+                                    unsigned int argc, ...)
 {
-  return payload->argc;
-}
+  va_list ap;
+  unsigned char **argv;
+  unsigned int *argv_lens = NULL, *argv_types = NULL;
+  unsigned char status_data[2];
+  unsigned char *x;
+  unsigned int x_len;
+  unsigned int x_type;
+  SilcBuffer buffer;
+  int i;
 
-/* Returns first argument from payload. */
+  va_start(ap, argc);
 
-unsigned char *silc_command_get_first_arg(SilcCommandPayload payload,
-                                         unsigned int *ret_len)
-{
-  payload->pos = 0;
+  argc++;
+  argv = silc_calloc(argc, sizeof(unsigned char *));
+  argv_lens = silc_calloc(argc, sizeof(unsigned int));
+  argv_types = silc_calloc(argc, sizeof(unsigned int));
 
-  if (ret_len)
-    *ret_len = payload->argv_lens[payload->pos];
+  SILC_PUT16_MSB(status, status_data);
+  argv[0] = silc_calloc(sizeof(status_data) + 1, sizeof(unsigned char));
+  memcpy(argv[0], status_data, sizeof(status_data));
+  argv_lens[0] = sizeof(status_data);
+  argv_types[0] = 1;
 
-  return payload->argv[payload->pos++];
-}
+  for (i = 1; i < argc; i++) {
+    x_type = va_arg(ap, unsigned int);
+    x = va_arg(ap, unsigned char *);
+    x_len = va_arg(ap, unsigned int);
 
-/* Returns next argument from payload or NULL if no more arguments. */
+    argv[i] = silc_calloc(x_len + 1, sizeof(unsigned char));
+    memcpy(argv[i], x, x_len);
+    argv_lens[i] = x_len;
+    argv_types[i] = x_type;
+  }
 
-unsigned char *silc_command_get_next_arg(SilcCommandPayload payload,
-                                        unsigned int *ret_len)
-{
-  if (payload->pos >= payload->argc)
-    return NULL;
+  buffer = silc_command_payload_encode(cmd, argc, argv, 
+                                      argv_lens, argv_types, ident);
 
-  if (ret_len)
-    *ret_len = payload->argv_lens[payload->pos];
+  for (i = 0; i < argc; i++)
+    silc_free(argv[i]);
+  silc_free(argv);
+  silc_free(argv_lens);
+  silc_free(argv_types);
 
-  return payload->argv[payload->pos++];
+  return buffer;
 }
 
-/* Returns argument which type is `type'. */
+/* Free's Command Payload */
 
-unsigned char *silc_command_get_arg_type(SilcCommandPayload payload,
-                                        unsigned int type,
-                                        unsigned int *ret_len)
+void silc_command_free_payload(SilcCommandPayload payload)
 {
-  int i;
-
-  for (i = 0; i < payload->argc; i++)
-    if (payload->argv_types[i] == type)
-      break;
-
-  if (i >= payload->argc)
-    return NULL;
+  if (payload) {
+    silc_argument_payload_free(payload->args);
+    silc_free(payload);
+  }
+}
 
-  if (ret_len)
-    *ret_len = payload->argv_lens[i];
+/* Returns command */
 
-  return payload->argv[i];
+SilcCommand silc_command_get(SilcCommandPayload payload)
+{
+  return payload->cmd;
 }
 
-/* Encodes command status payload. Status payload is sent as one reply
-   argument. The returned payload still has to be saved into the 
-   Command Argument payload. */
+/* Retuns arguments payload */
 
-SilcBuffer silc_command_encode_status_payload(SilcCommandStatus status,
-                                             unsigned char *data,
-                                             unsigned int len)
+SilcArgumentPayload silc_command_get_args(SilcCommandPayload payload)
 {
-  SilcBuffer sp;
+  return payload->args;
+}
 
-  sp = silc_buffer_alloc(len + 2);
-  silc_buffer_pull_tail(sp, SILC_BUFFER_END(sp));
-  silc_buffer_format(sp,
-                    SILC_STR_UI_SHORT(status),
-                    SILC_STR_UI_XNSTRING(data, len),
-                    SILC_STR_END);
+/* Returns identifier */
 
-  return sp;
+unsigned short silc_command_get_ident(SilcCommandPayload payload)
+{
+  return payload->ident;
 }
index 80c7ece9f804ac91f6baf51cadd5c93e696ce2a9..bdca206b0dfa84b029fa69dc8bb4eb4a37193a6d 100644 (file)
@@ -34,44 +34,45 @@ typedef struct SilcCommandPayloadStruct *SilcCommandPayload;
 /* Command flags. These set how the commands behave on different
    situations. These can be OR'ed together to set multiple flags. */
 typedef enum {
-  SILC_CF_NONE = 0,
+  SILC_CF_NONE           = 0,
 
   /* Command may only be used once per (about) 2 seconds */
-  SILC_CF_LAG = (1L << 1),
+  SILC_CF_LAG            = (1L << 1),
 
   /* Command is available for registered connections (connections
      whose ID has been created. */
-  SILC_CF_REG = (1L << 2),
+  SILC_CF_REG            = (1L << 2),
 
   /* Command is available only for server operators */
-  SILC_CF_OPER = (1L << 3),
+  SILC_CF_OPER           = (1L << 3),
 
   /* 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 << 4),
+  SILC_CF_SILC_OPER      = (1L << 4),
 
 } SilcCommandFlag;
 
 /* All SILC commands. These are commands that have client and server
    counterparts. These are pretty much the same as in IRC. */
 #define SILC_COMMAND_NONE               0
-#define SILC_COMMAND_WHOIS             2
-#define SILC_COMMAND_WHOWAS            3
-#define SILC_COMMAND_IDENTIFY           4
-#define SILC_COMMAND_NICK              5
-#define SILC_COMMAND_LIST              6
-#define SILC_COMMAND_TOPIC             7
-#define SILC_COMMAND_INVITE            8
-#define SILC_COMMAND_QUIT              9
-#define SILC_COMMAND_KILL              10
-#define SILC_COMMAND_INFO              11
-#define SILC_COMMAND_CONNECT           12
-#define SILC_COMMAND_PING              13
-#define SILC_COMMAND_OPER              14
-#define SILC_COMMAND_JOIN              15
-#define SILC_COMMAND_MOTD              16
-#define SILC_COMMAND_UMODE             17
-#define SILC_COMMAND_CMODE             18
+#define SILC_COMMAND_WHOIS             1
+#define SILC_COMMAND_WHOWAS            2
+#define SILC_COMMAND_IDENTIFY           3
+#define SILC_COMMAND_NICK              4
+#define SILC_COMMAND_LIST              5
+#define SILC_COMMAND_TOPIC             6
+#define SILC_COMMAND_INVITE            7
+#define SILC_COMMAND_QUIT              8
+#define SILC_COMMAND_KILL              9
+#define SILC_COMMAND_INFO              10
+#define SILC_COMMAND_CONNECT           11
+#define SILC_COMMAND_PING              12
+#define SILC_COMMAND_OPER              13
+#define SILC_COMMAND_JOIN              14
+#define SILC_COMMAND_MOTD              15
+#define SILC_COMMAND_UMODE             16
+#define SILC_COMMAND_CMODE             17
+#define SILC_COMMAND_CUMODE            18
 #define SILC_COMMAND_KICK              19
 #define        SILC_COMMAND_RESTART            20
 #define        SILC_COMMAND_CLOSE              21
@@ -80,16 +81,6 @@ typedef enum {
 #define SILC_COMMAND_LEAVE             24
 #define SILC_COMMAND_NAMES             25
 
-/* Local commands. Local commands are unofficial commands and
-   are implementation specific commands. These are used only by the
-   SILC client to extend user commands. */
-#define SILC_COMMAND_HELP              100
-#define SILC_COMMAND_CLEAR             101
-#define SILC_COMMAND_VERSION           102
-#define SILC_COMMAND_SERVER             103
-#define SILC_COMMAND_MSG               104
-#define SILC_COMMAND_AWAY              105
-
 /* Reserved */
 #define SILC_COMMAND_RESERVED           255
 
@@ -99,7 +90,8 @@ typedef unsigned short SilcCommandStatus;
 /* Command Status messages */
 #define SILC_STATUS_OK                      0
 #define SILC_STATUS_LIST_START              1
-#define SILC_STATUS_LIST_END                2
+#define SILC_STATUS_LIST_ITEM               2
+#define SILC_STATUS_LIST_END                3
 #define SILC_STATUS_ERR_NO_SUCH_NICK        10
 #define SILC_STATUS_ERR_NO_SUCH_CHANNEL     11
 #define SILC_STATUS_ERR_NO_SUCH_SERVER      12
@@ -109,52 +101,55 @@ typedef unsigned short SilcCommandStatus;
 #define SILC_STATUS_ERR_WILDCARDS           16
 #define SILC_STATUS_ERR_NO_CLIENT_ID        17
 #define SILC_STATUS_ERR_NO_CHANNEL_ID       18
-#define SILC_STATUS_ERR_BAD_CLIENT_ID       19
-#define SILC_STATUS_ERR_BAD_CHANNEL_ID      20
-#define SILC_STATUS_ERR_NO_SUCH_CLIENT_ID   21
-#define SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID  22
-#define SILC_STATUS_ERR_NICKNAME_IN_USE     23
-#define SILC_STATUS_ERR_NOT_ON_CHANNEL      24
-#define SILC_STATUS_ERR_USER_ON_CHANNEL     25
-#define SILC_STATUS_ERR_NOT_REGISTERED      26
-#define SILC_STATUS_ERR_NOT_ENOUGH_PARAMS   27
-#define SILC_STATUS_ERR_TOO_MANY_PARAMS     28
-#define SILC_STATUS_ERR_PERM_DENIED         29
-#define SILC_STATUS_ERR_BANNED_FROM_SERVER  30
-#define SILC_STATUS_ERR_BAD_PASSWORD        31
-#define SILC_STATUS_ERR_CHANNEL_IS_FULL     32
-#define SILC_STATUS_ERR_NOT_INVITED         33
-#define SILC_STATUS_ERR_BANNED_FROM_CHANNEL 34
-#define SILC_STATUS_ERR_UNKNOWN_MODE        35
-#define SILC_STATUS_ERR_NOT_YOU             36
-#define SILC_STATUS_ERR_NO_CHANNEL_PRIV     37
-#define SILC_STATUS_ERR_NO_SERVER_PRIV      38
-#define SILC_STATUS_ERR_NO_ROUTER_PRIV      39
-#define SILC_STATUS_ERR_BAD_NICKNAME        40
-#define SILC_STATUS_ERR_BAD_CHANNEL         41
-#define SILC_STATUS_ERR_AUTH_FAILED         42
+#define SILC_STATUS_ERR_NO_SERVER_ID        19
+#define SILC_STATUS_ERR_BAD_CLIENT_ID       20
+#define SILC_STATUS_ERR_BAD_CHANNEL_ID      21
+#define SILC_STATUS_ERR_NO_SUCH_CLIENT_ID   22
+#define SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID  23
+#define SILC_STATUS_ERR_NICKNAME_IN_USE     24
+#define SILC_STATUS_ERR_NOT_ON_CHANNEL      25
+#define SILC_STATUS_ERR_USER_NOT_ON_CHANNEL 26
+#define SILC_STATUS_ERR_USER_ON_CHANNEL     27
+#define SILC_STATUS_ERR_NOT_REGISTERED      28
+#define SILC_STATUS_ERR_NOT_ENOUGH_PARAMS   29
+#define SILC_STATUS_ERR_TOO_MANY_PARAMS     30
+#define SILC_STATUS_ERR_PERM_DENIED         31
+#define SILC_STATUS_ERR_BANNED_FROM_SERVER  32
+#define SILC_STATUS_ERR_BAD_PASSWORD        33
+#define SILC_STATUS_ERR_CHANNEL_IS_FULL     34
+#define SILC_STATUS_ERR_NOT_INVITED         35
+#define SILC_STATUS_ERR_BANNED_FROM_CHANNEL 36
+#define SILC_STATUS_ERR_UNKNOWN_MODE        37
+#define SILC_STATUS_ERR_NOT_YOU             38
+#define SILC_STATUS_ERR_NO_CHANNEL_PRIV     39
+#define SILC_STATUS_ERR_NO_SERVER_PRIV      40
+#define SILC_STATUS_ERR_NO_ROUTER_PRIV      41
+#define SILC_STATUS_ERR_BAD_NICKNAME        42
+#define SILC_STATUS_ERR_BAD_CHANNEL         43
+#define SILC_STATUS_ERR_AUTH_FAILED         44
 
 /* Prototypes */
-SilcCommandPayload silc_command_parse_payload(SilcBuffer buffer);
-SilcBuffer silc_command_encode_payload(SilcCommand cmd,
+SilcCommandPayload silc_command_payload_parse(SilcBuffer buffer);
+SilcBuffer silc_command_payload_encode(SilcCommand cmd,
                                       unsigned int argc,
                                       unsigned char **argv,
                                       unsigned int *argv_lens,
-                                      unsigned int *argv_types);
-SilcBuffer silc_command_encode_payload_va(SilcCommand cmd, 
+                                      unsigned int *argv_types,
+                                      unsigned short ident);
+SilcBuffer silc_command_payload_encode_va(SilcCommand cmd, 
+                                         unsigned short ident, 
                                          unsigned int argc, ...);
+SilcBuffer silc_command_payload_encode_vap(SilcCommand cmd, 
+                                          unsigned short ident, 
+                                          unsigned int argc, va_list ap);
+SilcBuffer 
+silc_command_reply_payload_encode_va(SilcCommand cmd, 
+                                    SilcCommandStatus status,
+                                    unsigned short ident,
+                                    unsigned int argc, ...);
 void silc_command_free_payload(SilcCommandPayload payload);
 SilcCommand silc_command_get(SilcCommandPayload payload);
-unsigned int silc_command_get_arg_num(SilcCommandPayload payload);
-unsigned char *silc_command_get_first_arg(SilcCommandPayload payload,
-                                         unsigned int *ret_len);
-unsigned char *silc_command_get_next_arg(SilcCommandPayload payload,
-                                        unsigned int *ret_len);
-unsigned char *silc_command_get_arg_type(SilcCommandPayload payload,
-                                        unsigned int type,
-                                        unsigned int *ret_len);
-SilcBuffer silc_command_encode_status_payload(SilcCommandStatus status,
-                                             unsigned char *data,
-                                             unsigned int len);
+SilcArgumentPayload silc_command_get_args(SilcCommandPayload payload);
+unsigned short silc_command_get_ident(SilcCommandPayload payload);
 
 #endif
diff --git a/lib/silccore/silcnotify.c b/lib/silccore/silcnotify.c
new file mode 100644 (file)
index 0000000..b76d675
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+
+  silcnotify.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 2000 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
+  GNU General Public License for more details.
+
+*/
+/* $Id$ */
+
+#include "silcincludes.h"
+#include "silcnotify.h"
+
+/******************************************************************************
+
+                               Notify Payload
+
+******************************************************************************/
+
+struct SilcNotifyPayloadStruct {
+  SilcNotifyType type;
+  unsigned int argc;
+  SilcArgumentPayload args;
+};
+
+/* Parse notify payload buffer and return data into payload structure */
+
+SilcNotifyPayload silc_notify_payload_parse(SilcBuffer buffer)
+{
+  SilcNotifyPayload new;
+  unsigned short len;
+
+  SILC_LOG_DEBUG(("Parsing Notify payload"));
+
+  new = silc_calloc(1, sizeof(*new));
+
+  silc_buffer_unformat(buffer,
+                      SILC_STR_UI_SHORT(&new->type),
+                      SILC_STR_UI_SHORT(&len),
+                      SILC_STR_UI_CHAR(&new->argc),
+                      SILC_STR_END);
+
+  if (len > buffer->len)
+    goto err;
+
+  if (new->argc) {
+    silc_buffer_pull(buffer, 5);
+    new->args = silc_argument_payload_parse(buffer, new->argc);
+    silc_buffer_push(buffer, 5);
+  }
+
+  return new;
+
+ err:
+  silc_free(new);
+  return NULL;
+}
+
+/* Encode notify payload with variable argument list. If `argc' is > 0
+   argument payloads will be associated to the notify payload. Variable
+   arguments must be {usigned char *, unsigned int (len)}. */
+
+SilcBuffer silc_notify_payload_encode(SilcNotifyType type, unsigned int argc, 
+                                     va_list ap)
+{
+  SilcBuffer buffer;
+  SilcBuffer args = NULL;
+  unsigned char **argv;
+  unsigned int *argv_lens = NULL, *argv_types = NULL;
+  unsigned char *x;
+  unsigned int x_len;
+  int i, len = 0;
+
+  if (argc) {
+    argv = silc_calloc(argc, sizeof(unsigned char *));
+    argv_lens = silc_calloc(argc, sizeof(unsigned int));
+    argv_types = silc_calloc(argc, sizeof(unsigned int));
+    
+    for (i = 0; i < argc; i++) {
+      x = va_arg(ap, unsigned char *);
+      x_len = va_arg(ap, unsigned int);
+      
+      argv[i] = silc_calloc(x_len + 1, sizeof(unsigned char));
+      memcpy(argv[i], x, x_len);
+      argv_lens[i] = x_len;
+      argv_types[i] = i + 1;
+    }
+
+    args = silc_argument_payload_encode(argc, argv, argv_lens, argv_types);
+    len = args->len;
+
+    for (i = 0; i < argc; i++)
+      silc_free(argv[i]);
+    silc_free(argv);
+    silc_free(argv_lens);
+    silc_free(argv_types);
+  }
+
+  len += 5;
+  buffer = silc_buffer_alloc(len);
+  silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
+  silc_buffer_format(buffer,
+                    SILC_STR_UI_SHORT(type),
+                    SILC_STR_UI_SHORT(len),
+                    SILC_STR_UI_CHAR(argc),
+                    SILC_STR_END);
+
+  if (argc) {
+    silc_buffer_pull(buffer, 5);
+    silc_buffer_format(buffer,
+                      SILC_STR_UI_XNSTRING(args->data, args->len),
+                      SILC_STR_END);
+    silc_buffer_push(buffer, 5);
+    silc_buffer_free(args);
+  }
+
+  return buffer;
+}
+
+/* Free's notify payload */
+
+void silc_notify_payload_free(SilcNotifyPayload payload)
+{
+  if (payload) {
+    silc_argument_payload_free(payload->args);
+    silc_free(payload);
+  }
+}
+
+/* Return notify type */
+
+SilcNotifyType silc_notify_get_type(SilcNotifyPayload payload)
+{
+  return payload->type;
+}
+
+/* Return argument nums */
+
+unsigned int silc_notify_get_arg_num(SilcNotifyPayload payload)
+{
+  return payload->argc;
+}
+
+/* Return argument payload */
+
+SilcArgumentPayload silc_notify_get_args(SilcNotifyPayload payload)
+{
+  return payload->args;
+}
diff --git a/lib/silccore/silcnotify.h b/lib/silccore/silcnotify.h
new file mode 100644 (file)
index 0000000..3362d7f
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+
+  silcnotify.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 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
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SILCNOTIFY_H
+#define SILCNOTIFY_H
+
+/* Forward declarations */
+typedef struct SilcNotifyPayloadStruct *SilcNotifyPayload;
+
+/* Type definition of notify type */
+typedef unsigned short SilcNotifyType;
+
+/* SILC notify types. Server may send these notify types to client to
+   notify of some action. Server also sends human readable notify message
+   to the client which client may ignore. */
+#define SILC_NOTIFY_TYPE_NONE            0 /* no specific type */
+#define SILC_NOTIFY_TYPE_INVITE          1 /* "invites you to channel" */
+#define SILC_NOTIFY_TYPE_JOIN            2 /* "has joined channel" */
+#define SILC_NOTIFY_TYPE_LEAVE           3 /* "has left channel" */
+#define SILC_NOTIFY_TYPE_SIGNOFF         4 /* "signoff" */
+#define SILC_NOTIFY_TYPE_TOPIC_SET       5 /* "topic has been changed" */
+#define SILC_NOTIFY_TYPE_NICK_CHANGE     6 /* "has changed nickname" */
+#define SILC_NOTIFY_TYPE_CMODE_CHANGE    7 /* "has changed channel mode" */
+#define SILC_NOTIFY_TYPE_CUMODE_CHANGE   8 /* "has change mode" */
+#define SILC_NOTIFY_TYPE_MOTD            9 /* message of the day */
+
+/* Prototypes */
+SilcNotifyPayload silc_notify_payload_parse(SilcBuffer buffer);
+SilcBuffer silc_notify_payload_encode(SilcNotifyType type, unsigned int argc, 
+                                     va_list ap);
+void silc_notify_payload_free(SilcNotifyPayload payload);
+SilcNotifyType silc_notify_get_type(SilcNotifyPayload payload);
+unsigned int silc_notify_get_arg_num(SilcNotifyPayload payload);
+SilcArgumentPayload silc_notify_get_args(SilcNotifyPayload payload);
+
+#endif
index 26c7cbefa9e686236e9b7075af09a087928f0a3b..f2800597b08fd21c4509127d4715ada63b758674 100644 (file)
 /*
  * Created: Fri Jul 25 18:52:14 1997
  */
-/*
- * $Id$
- * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
- *     Importet from internal CVS/Added Log headers.
- *
- *
- */
+/* $Id$ */
 
 #include "silcincludes.h"
 
+/******************************************************************************
+
+                          Packet Sending Routines
+
+******************************************************************************/
+
 /* Writes data from encrypted buffer to the socket connection. If the
    data cannot be written at once, it will be written later with a timeout. 
    The data is written from the data section of the buffer, not from head
@@ -62,6 +61,228 @@ int silc_packet_write(int sock, SilcBuffer src)
   return ret;
 }
 
+/* Actually sends the packet. This flushes the connections outgoing data
+   buffer. If data is sent directly to the network this returns the bytes
+   written, if error occured this returns -1 and if the data could not
+   be written directly to the network at this time this returns -2, in
+   which case the data should be queued by the caller and sent at some
+   later time. If `force_send' is TRUE this attempts to write the data
+   directly to the network, if FALSE, this returns -2. */
+
+int silc_packet_send(SilcSocketConnection sock, int force_send)
+{
+  /* Send now if forced to do so */
+  if (force_send == TRUE) {
+    int ret;
+
+    SILC_LOG_DEBUG(("Forcing packet send, packet sent immediately"));
+
+    /* Write to network */
+    ret = silc_packet_write(sock->sock, sock->outbuf);
+
+    if (ret == -1) {
+      SILC_LOG_ERROR(("Error sending packet, dropped"));
+    }
+    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 
+   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
+   other process of HMAC computing and encryption is needed this function
+   cannot be used. */
+
+void silc_packet_encrypt(SilcCipher cipher, SilcHmac hmac, 
+                        SilcBuffer buffer, unsigned int len)
+{
+  unsigned char mac[32];
+
+  if (cipher) {
+    SILC_LOG_DEBUG(("Encrypting packet, cipher %s, len %d (%d)", 
+                   cipher->cipher->name, len, len - 2));
+  }
+
+  /* Compute HMAC. This assumes that HMAC is created from the entire
+     data area thus this uses the length found in buffer, not the length
+     sent as argument. */
+  if (hmac) {
+    silc_hmac_make(hmac, buffer->data, buffer->len, mac);
+    silc_buffer_put_tail(buffer, mac, hmac->hash->hash->hash_len);
+    memset(mac, 0, sizeof(mac));
+  }
+
+  /* Encrypt the data area of the packet. 2 bytes of the packet
+     are not encrypted. */
+  if (cipher)
+    cipher->cipher->encrypt(cipher->context, buffer->data + 2, 
+                           buffer->data + 2, len - 2, cipher->iv);
+
+  /* Pull the HMAC into the visible data area in the buffer */
+  if (hmac)
+    silc_buffer_pull_tail(buffer, hmac->hash->hash->hash_len);
+}
+
+/* Assembles a new packet to be ready for send out. The buffer sent as
+   argument must include the data to be sent and it must not be encrypted. 
+   The packet also must have enough free space so that the SILC header
+   and padding maybe added to the packet. The packet is encrypted after 
+   this function has returned.
+
+   The buffer sent as argument should be something like following:
+
+   --------------------------------------------
+   | head             | data           | tail |
+   --------------------------------------------
+   ^                  ^
+   58 bytes           x bytes
+
+   So that the SILC header and 1 - 16 bytes of padding can fit to
+   the buffer. After assembly the buffer might look like this:
+
+   --------------------------------------------
+   | data                              |      |
+   --------------------------------------------
+   ^                                   ^
+   Start of assembled packet
+
+   Packet construct is as follows (* = won't be encrypted):
+
+   x bytes       SILC Header
+      2 bytes     Payload length  (*)
+      1 byte      Flags
+      1 byte      Packet type
+      1 byte      Source ID Type
+      2 bytes     Source ID Length
+      x bytes     Source ID
+      1 byte      Destination ID Type
+      2 bytes     Destination ID Length
+      x bytes     Destination ID
+
+   1 - 16 bytes    Padding
+
+   x bytes        Data payload
+
+   All fields in the packet will be authenticated by MAC. The MAC is
+   not computed here, it must be computed differently before encrypting
+   the packet.
+
+*/
+
+void silc_packet_assemble(SilcPacketContext *ctx)
+{
+  unsigned char tmppad[SILC_PACKET_MAX_PADLEN];
+  int i;
+
+  SILC_LOG_DEBUG(("Assembling outgoing packet"));
+  
+  /* Get the true length of the packet. This is saved as payload length
+     into the packet header. This does not include the length of the
+     padding. */
+  if (!ctx->truelen)
+    ctx->truelen = ctx->buffer->len + SILC_PACKET_HEADER_LEN + 
+      ctx->src_id_len + ctx->dst_id_len;
+
+  /* Calculate the length of the padding. The padding is calculated from
+     the data that will be encrypted. As protocol states 3 first bytes
+     of the packet are not encrypted they are not included in the
+     padding calculation. */
+  if (!ctx->padlen)
+    ctx->padlen = SILC_PACKET_PADLEN(ctx->truelen);
+
+  /* Put the start of the data section to the right place. */
+  silc_buffer_push(ctx->buffer, SILC_PACKET_HEADER_LEN + 
+                  ctx->src_id_len + ctx->dst_id_len + ctx->padlen);
+
+  /* Get random padding */
+#if 1
+  for (i = 0; i < ctx->padlen; i++)
+    tmppad[i] = silc_rng_get_byte(ctx->rng);
+#else
+  /* XXX: For testing - to be removed */
+  memset(tmppad, 65, sizeof(tmppad));
+#endif
+
+  /* Create the packet. This creates the SILC header and adds padding,
+     rest of the buffer remains as it is. */
+  silc_buffer_format(ctx->buffer, 
+                    SILC_STR_UI_SHORT(ctx->truelen),
+                    SILC_STR_UI_CHAR(ctx->flags),
+                    SILC_STR_UI_CHAR(ctx->type),
+                    SILC_STR_UI_SHORT(ctx->src_id_len),
+                    SILC_STR_UI_SHORT(ctx->dst_id_len),
+                    SILC_STR_UI_CHAR(ctx->src_id_type),
+                    SILC_STR_UI_XNSTRING(ctx->src_id, ctx->src_id_len),
+                    SILC_STR_UI_CHAR(ctx->dst_id_type),
+                    SILC_STR_UI_XNSTRING(ctx->dst_id, ctx->dst_id_len),
+                    SILC_STR_UI_XNSTRING(tmppad, ctx->padlen),
+                    SILC_STR_END);
+
+  SILC_LOG_HEXDUMP(("Assembled packet, len %d", ctx->buffer->len), 
+                  ctx->buffer->data, ctx->buffer->len);
+
+  SILC_LOG_DEBUG(("Outgoing packet assembled"));
+}
+
+/* Prepare outgoing data buffer for packet sending. This moves the data
+   area so that new packet may be added into it. If needed this allocates
+   more space to the buffer. This handles directly the connection's
+   outgoing buffer in SilcSocketConnection object. */
+
+void silc_packet_send_prepare(SilcSocketConnection sock,
+                             unsigned int header_len,
+                             unsigned int padlen,
+                             unsigned int data_len)
+{
+  int totlen, oldlen;
+
+  totlen = header_len + padlen + data_len;
+
+  /* Prepare the outgoing buffer for packet sending. */
+  if (!sock->outbuf) {
+    /* Allocate new buffer. This is done only once per connection. */
+    SILC_LOG_DEBUG(("Allocating outgoing data buffer"));
+    
+    sock->outbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE);
+    silc_buffer_pull_tail(sock->outbuf, totlen);
+    silc_buffer_pull(sock->outbuf, header_len + padlen);
+  } else {
+    if (SILC_IS_OUTBUF_PENDING(sock)) {
+      /* There is some pending data in the buffer. */
+
+      /* Allocate more space if needed */
+      if ((sock->outbuf->end - sock->outbuf->tail) < data_len) {
+       SILC_LOG_DEBUG(("Reallocating outgoing data buffer"));
+       sock->outbuf = silc_buffer_realloc(sock->outbuf, 
+                                          sock->outbuf->truelen + totlen);
+      }
+
+      oldlen = sock->outbuf->len;
+      silc_buffer_pull_tail(sock->outbuf, totlen);
+      silc_buffer_pull(sock->outbuf, header_len + padlen + oldlen);
+    } else {
+      /* Buffer is free for use */
+      silc_buffer_clear(sock->outbuf);
+      silc_buffer_pull_tail(sock->outbuf, totlen);
+      silc_buffer_pull(sock->outbuf, header_len + padlen);
+    }
+  }
+}
+
+/******************************************************************************
+
+                         Packet Reception Routines
+
+******************************************************************************/
+
 /* Reads data from the socket connection into the incoming data buffer.
    However, this does not parse the packet, it only reads some amount from
    the network. If there are more data available that can be read at a time
@@ -86,7 +307,7 @@ int silc_packet_read(int sock, SilcBuffer dest)
   /* Read the data from the socket. */
   len = read(sock, buf, sizeof(buf));
   if (len < 0) {
-    if (errno == EAGAIN) {
+    if (errno == EAGAIN || errno == EINTR) {
       SILC_LOG_DEBUG(("Could not read immediately, will do it later"));
       return -2;
     }
@@ -98,8 +319,9 @@ int silc_packet_read(int sock, SilcBuffer dest)
     return 0;
 
   /* Insert the data to the buffer. If the data doesn't fit to the 
-     buffer space is allocated for the buffer.  
-     XXX: I don't like this. -Pekka */
+     buffer space is allocated for the buffer. */
+  /* XXX: This may actually be bad thing as if there is pending data in
+     the buffer they will be lost! */
   if (dest) {
 
     /* If the data doesn't fit we just have to allocate a whole new 
@@ -131,34 +353,259 @@ int silc_packet_read(int sock, SilcBuffer dest)
   return len;
 }
 
-/* Encrypts a packet. */
+/* Processes the received data. This checks the received data and 
+   calls parser callback that handles the actual packet decryption
+   and parsing. 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 `context'
+   sent to this function. */
+
+void silc_packet_receive_process(SilcSocketConnection sock,
+                                SilcCipher cipher, SilcHmac hmac,
+                                SilcPacketParserCallback parser,
+                                void *context)
+{
+  SilcPacketParserContext *parse_ctx;
+  int packetlen, paddedlen, count, mac_len = 0;
+
+  /* We need at least 2 bytes of data to be able to start processing
+     the packet. */
+  if (sock->inbuf->len < 2)
+    return;
+
+  if (hmac)
+    mac_len = hmac->hash->hash->hash_len;
+
+  /* Parse the packets from the data */
+  count = 0;
+  while (sock->inbuf->len > 0) {
+    SILC_PACKET_LENGTH(sock->inbuf, packetlen, paddedlen);
+    paddedlen += 2;
+    count++;
+
+    if (packetlen < SILC_PACKET_MIN_LEN) {
+      SILC_LOG_DEBUG(("Received invalid packet, dropped"));
+      return;
+    }
+
+    if (sock->inbuf->len < paddedlen + mac_len) {
+      SILC_LOG_DEBUG(("Received partial packet, waiting for the rest"));
+      return;
+    }
+
+    parse_ctx = silc_calloc(1, sizeof(*parse_ctx));
+    parse_ctx->packet = silc_calloc(1, sizeof(*parse_ctx->packet));
+    parse_ctx->packet->buffer = silc_buffer_alloc(paddedlen + mac_len);
+    parse_ctx->sock = sock;
+    parse_ctx->cipher = cipher;
+    parse_ctx->hmac = hmac;
+    parse_ctx->context = context;
+
+    silc_buffer_pull_tail(parse_ctx->packet->buffer, 
+                         SILC_BUFFER_END(parse_ctx->packet->buffer));
+    silc_buffer_put(parse_ctx->packet->buffer, sock->inbuf->data, 
+                   paddedlen + mac_len);
+
+    SILC_LOG_HEXDUMP(("Incoming packet, len %d", 
+                     parse_ctx->packet->buffer->len),
+                    parse_ctx->packet->buffer->data, 
+                    parse_ctx->packet->buffer->len);
+
+    /* Call the parser */
+    if (parser)
+      (*parser)(parse_ctx);
+
+    /* Pull the packet from inbuf thus we'll get the next one
+       in the inbuf. */
+    silc_buffer_pull(sock->inbuf, paddedlen);
+    if (hmac)
+      silc_buffer_pull(sock->inbuf, mac_len);
+  }
+
+  silc_buffer_clear(sock->inbuf);
+}
+
+/* Receives packet from network and reads the data into connection's
+   incoming data buffer. If the data was read directly this returns the
+   read bytes, if error occured this returns -1, if the data could not
+   be read directly at this time this returns -2 in which case the data
+   should be read again at some later time, or If EOF occured this returns
+   0. */
 
-void silc_packet_encrypt(SilcCipher cipher, SilcBuffer buffer,
-                        unsigned int len)
+int silc_packet_receive(SilcSocketConnection sock)
 {
-  SILC_LOG_DEBUG(("Encrypting packet, cipher %s, len %d (%d)", 
-                 cipher->cipher->name, len, len - 2));
+  int ret;
 
-  /* Encrypt the data area of the packet. 3 bytes of the packet
-     are not encrypted. */
-  cipher->cipher->encrypt(cipher->context, buffer->data + 2, 
-                         buffer->data + 2, len - 2, cipher->iv);
+  /* Allocate the incoming data buffer if not done already. */
+  if (!sock->inbuf)
+    sock->inbuf = silc_buffer_alloc(SILC_PACKET_DEFAULT_SIZE);
+  
+  /* Read some data from connection */
+  ret = silc_packet_read(sock->sock, sock->inbuf);
+
+  /* Error */
+  if (ret == -1) {
+    SILC_LOG_ERROR(("Error reading packet, dropped"));
+  }
+
+  return ret;
+}
+
+/* Checks MAC in the packet. Returns TRUE if MAC is Ok. This is called
+   after packet has been totally decrypted and parsed. */
+
+static int silc_packet_check_mac(SilcHmac hmac, SilcBuffer buffer)
+{
+  /* Check MAC */
+  if (hmac) {
+    unsigned char mac[32];
+    
+    SILC_LOG_DEBUG(("Verifying MAC"));
+
+    /* Compute HMAC of packet */
+    memset(mac, 0, sizeof(mac));
+    silc_hmac_make(hmac, buffer->data, buffer->len, mac);
+
+    /* Compare the HMAC's (buffer->tail has the packet's HMAC) */
+    if (memcmp(mac, buffer->tail, hmac->hash->hash->hash_len)) {
+      SILC_LOG_DEBUG(("MAC failed"));
+      return FALSE;
+    }
+    
+    SILC_LOG_DEBUG(("MAC is Ok"));
+    memset(mac, 0, sizeof(mac));
+  }
+  
+  return TRUE;
+}
+
+/* Decrypts rest of the packet (after decrypting just the SILC header).
+   After calling this function the packet is ready to be parsed by calling 
+   silc_packet_parse. If everything goes without errors this returns TRUE,
+   if packet is malformed this returns FALSE. */
+
+static int silc_packet_decrypt_rest(SilcCipher cipher, SilcHmac hmac,
+                                   SilcBuffer buffer)
+{
+  if (cipher) {
+
+    /* Pull MAC from packet before decryption */
+    if (hmac) {
+      if ((buffer->len - hmac->hash->hash->hash_len) > SILC_PACKET_MIN_LEN) {
+       silc_buffer_push_tail(buffer, hmac->hash->hash->hash_len);
+      } else {
+       SILC_LOG_DEBUG(("Bad MAC length in packet, packet dropped"));
+       return FALSE;
+      }
+    }
+
+    SILC_LOG_DEBUG(("Decrypting rest of the packet"));
 
+    /* Decrypt rest of the packet */
+    silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
+    cipher->cipher->decrypt(cipher->context, buffer->data + 2,
+                           buffer->data + 2, buffer->len - 2,
+                           cipher->iv);
+    silc_buffer_push(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
+
+    SILC_LOG_HEXDUMP(("Fully decrypted packet, len %d", buffer->len),
+                    buffer->data, buffer->len);
+  }
+
+  return TRUE;
 }
 
-/* Decrypts a packet. */
+/* Decrypts rest of the SILC Packet header that has been decrypted partly
+   already. This decrypts the padding of the packet also. After calling 
+   this function the packet is ready to be parsed by calling function 
+   silc_packet_parse. This is used in special packet reception (protocol
+   defines the way of decrypting special packets). */
 
-void silc_packet_decrypt(SilcCipher cipher, SilcBuffer buffer, 
-                        unsigned int len)
+static int silc_packet_decrypt_rest_special(SilcCipher cipher,
+                                           SilcHmac hmac,
+                                           SilcBuffer buffer)
 {
+  /* Decrypt rest of the header plus padding */
+  if (cipher) {
+    unsigned short truelen, len1, len2, padlen;
+
+    /* Pull MAC from packet before decryption */
+    if (hmac) {
+      if ((buffer->len - hmac->hash->hash->hash_len) > SILC_PACKET_MIN_LEN) {
+       silc_buffer_push_tail(buffer, hmac->hash->hash->hash_len);
+      } else {
+       SILC_LOG_DEBUG(("Bad MAC length in packet, packet dropped"));
+       return FALSE;
+      }
+    }
+  
+    SILC_LOG_DEBUG(("Decrypting rest of the header"));
+
+    SILC_GET16_MSB(len1, &buffer->data[4]);
+    SILC_GET16_MSB(len2, &buffer->data[6]);
+
+    truelen = SILC_PACKET_HEADER_LEN + len1 + len2;
+    padlen = SILC_PACKET_PADLEN(truelen);
+    len1 = (truelen + padlen) - (SILC_PACKET_MIN_HEADER_LEN - 2);
+
+    silc_buffer_pull(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
+    cipher->cipher->decrypt(cipher->context, buffer->data + 2,
+                           buffer->data + 2, len1 - 2,
+                           cipher->iv);
+    silc_buffer_push(buffer, SILC_PACKET_MIN_HEADER_LEN - 2);
+  }
+
+  return TRUE;
+}
+
+/* Decrypts a packet. This assumes that typical SILC packet is the
+   packet to be decrypted and thus checks for normal and special SILC
+   packets and can handle both of them. This also computes and checks
+   the HMAC of the packet. If any other special or customized decryption
+   processing is required this function cannot be used. This returns
+   -1 on error, 0 when packet is normal packet and 1 when the packet
+   is special and requires special processing. */
+
+int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
+                       SilcBuffer buffer, SilcPacketContext *packet)
+{
+#if 0
   SILC_LOG_DEBUG(("Decrypting packet, cipher %s, len %d (%d)", 
                  cipher->cipher->name, len, len - 2));
+#endif
+
+  /* Decrypt start of the packet header */
+  if (cipher)
+    cipher->cipher->decrypt(cipher->context, buffer->data + 2,
+                           buffer->data + 2, SILC_PACKET_MIN_HEADER_LEN - 2,
+                           cipher->iv);
+
+  /* If the packet type is not any special type lets decrypt rest
+     of the packet here. */
+  if ((buffer->data[3] == SILC_PACKET_PRIVATE_MESSAGE &&
+      !(buffer->data[2] & SILC_PACKET_FLAG_PRIVMSG_KEY)) ||
+      buffer->data[3] != SILC_PACKET_CHANNEL_MESSAGE) {
 
-  /* Decrypt the data area of the packet. 2 bytes of the packet
-     are not decrypted (they are not encrypted). */
-  cipher->cipher->decrypt(cipher->context, buffer->data + 2, 
-                         buffer->data + 2, len - 2, cipher->iv);
+    /* Normal packet, decrypt rest of the packet */
+    if (!silc_packet_decrypt_rest(cipher, hmac, buffer))
+      return -1;
+
+    /* Check MAC */
+    if (!silc_packet_check_mac(hmac, buffer))
+      return FALSE;
+
+    return 0;
+  } else {
+    /* Packet requires special handling, decrypt rest of the header.
+       This only decrypts. */
+    silc_packet_decrypt_rest_special(cipher, hmac, buffer);
+
+    /* Check MAC */
+    if (!silc_packet_check_mac(hmac, buffer))
+      return FALSE;
 
+    return 1;
+  }
 }
 
 /* Parses the packet. This is called when a whole packet is ready to be
@@ -286,103 +733,34 @@ SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx)
   return ctx->type;
 }
 
-/* Assembles a new packet to be ready for send out. The buffer sent as
-   argument must include the data to be sent and it must not be encrypted. 
-   The packet also must have enough free space so that the SILC header
-   and padding maybe added to the packet. The packet is encrypted after 
-   this function has returned.
+/* Duplicates packet context. Duplicates the entire context and its
+   contents. */
 
-   The buffer sent as argument should be something like following:
-
-   --------------------------------------------
-   | head             | data           | tail |
-   --------------------------------------------
-   ^                  ^
-   58 bytes           x bytes
-
-   So that the SILC header and 1 - 16 bytes of padding can fit to
-   the buffer. After assembly the buffer might look like this:
-
-   --------------------------------------------
-   | data                              |      |
-   --------------------------------------------
-   ^                                   ^
-   Start of assembled packet
-
-   Packet construct is as follows (* = won't be encrypted):
-
-   x bytes       SILC Header
-      2 bytes     Payload length  (*)
-      1 byte      Flags           (*)
-      1 byte      Packet type
-      1 byte      Source ID Type
-      2 bytes     Source ID Length
-      x bytes     Source ID
-      1 byte      Destination ID Type
-      2 bytes     Destination ID Length
-      x bytes     Destination ID
-
-   1 - 16 bytes    Padding
-
-   x bytes        Data payload
-
-   All fields in the packet will be authenticated by MAC. The MAC is
-   not computed here, it must be computed differently before encrypting
-   the packet.
-
-*/
-
-void silc_packet_assemble(SilcPacketContext *ctx)
+SilcPacketContext *silc_packet_context_dup(SilcPacketContext *ctx)
 {
-  unsigned char tmppad[SILC_PACKET_MAX_PADLEN];
-  int i;
-
-  SILC_LOG_DEBUG(("Assembling outgoing packet"));
-  
-  /* Get the true length of the packet. This is saved as payload length
-     into the packet header. This does not include the length of the
-     padding. */
-  if (!ctx->truelen)
-    ctx->truelen = ctx->buffer->len + SILC_PACKET_HEADER_LEN + 
-      ctx->src_id_len + ctx->dst_id_len;
+  SilcPacketContext *new;
 
-  /* Calculate the length of the padding. The padding is calculated from
-     the data that will be encrypted. As protocol states 3 first bytes
-     of the packet are not encrypted they are not included in the
-     padding calculation. */
-  if (!ctx->padlen)
-    ctx->padlen = SILC_PACKET_PADLEN(ctx->truelen);
+  new = silc_calloc(1, sizeof(*new));
+  new->buffer = silc_buffer_copy(ctx->buffer);
+  new->type = ctx->type;
+  new->flags = ctx->flags;
 
-  /* Put the start of the data section to the right place. */
-  silc_buffer_push(ctx->buffer, SILC_PACKET_HEADER_LEN + 
-                  ctx->src_id_len + ctx->dst_id_len + ctx->padlen);
+  new->src_id = silc_calloc(ctx->src_id_len, sizeof(*new->src_id));
+  memcpy(new->src_id, ctx->src_id, ctx->src_id_len);
+  new->src_id_len = ctx->src_id_len;
+  new->src_id_type = ctx->src_id_type;
 
-  /* Get random padding */
-#if 1
-  for (i = 0; i < ctx->padlen; i++)
-    tmppad[i] = silc_rng_get_byte(ctx->rng);
-#else
-  /* XXX: For testing - to be removed */
-  memset(tmppad, 65, sizeof(tmppad));
-#endif
+  new->dst_id = silc_calloc(ctx->dst_id_len, sizeof(*new->dst_id));
+  memcpy(new->dst_id, ctx->dst_id, ctx->dst_id_len);
+  new->dst_id_len = ctx->dst_id_len;
+  new->dst_id_type = ctx->dst_id_type;
 
-  /* Create the packet. This creates the SILC header and adds padding,
-     rest of the buffer remains as it is. */
-  silc_buffer_format(ctx->buffer, 
-                    SILC_STR_UI_SHORT(ctx->truelen),
-                    SILC_STR_UI_CHAR(ctx->flags),
-                    SILC_STR_UI_CHAR(ctx->type),
-                    SILC_STR_UI_SHORT(ctx->src_id_len),
-                    SILC_STR_UI_SHORT(ctx->dst_id_len),
-                    SILC_STR_UI_CHAR(ctx->src_id_type),
-                    SILC_STR_UI_XNSTRING(ctx->src_id, ctx->src_id_len),
-                    SILC_STR_UI_CHAR(ctx->dst_id_type),
-                    SILC_STR_UI_XNSTRING(ctx->dst_id, ctx->dst_id_len),
-                    SILC_STR_UI_XNSTRING(tmppad, ctx->padlen),
-                    SILC_STR_END);
+  new->truelen = ctx->truelen;
+  new->padlen = ctx->padlen;
 
-  SILC_LOG_HEXDUMP(("Assembled packet, len %d", ctx->buffer->len), 
-                  ctx->buffer->data, ctx->buffer->len);
+  new->rng = ctx->rng;
+  new->context = ctx->context;
+  new->sock = ctx->sock;
 
-  SILC_LOG_DEBUG(("Outgoing packet assembled"));
+  return new;
 }
index a26447900093483f8190fc9ee56c3a1399b18497..14b1c678fa07d3793a69db3617d85cf7521dbc11 100644 (file)
@@ -59,10 +59,10 @@ typedef unsigned char SilcPacketFlags;
 /* All defined packet flags */
 #define SILC_PACKET_FLAG_NONE             0x00
 #define SILC_PACKET_FLAG_PRIVMSG_KEY      0x01
-#define SILC_PACKET_FLAG_FORWARDED        0x02 /* XXX deprecated 26062000 */
+#define SILC_PACKET_FLAG_FORWARDED        0x02
 #define SILC_PACKET_FLAG_BROADCAST        0x04
+#define SILC_PACKET_FLAG_TUNNELED         0x08
 /* Rest of flags still available
-#define SILC_PACKET_FLAG_XXX              0x08
 #define SILC_PACKET_FLAG_XXX              0x10
 #define SILC_PACKET_FLAG_XXX              0x20
 #define SILC_PACKET_FLAG_XXX              0x40
@@ -94,12 +94,19 @@ typedef unsigned char SilcPacketFlags;
        Packet flags. Flags are defined above.
 
    unsigned char *src_id
-   unsigned int src_id_len
-   SilcIdType src_id_type
+   unsigned short src_id_len
+   unsigned char src_id_type
 
        Source ID, its length and type. On packet reception retuned ID's
        are always the hash values of the ID's from the packet.
 
+  unsigned char *dst_id;
+  unsigned short dst_id_len;
+  unsigned char src_id_type;
+
+       Destination ID, its length and type. On packet reception retuned
+       ID's are always the hash values of the ID's from the packet.
+
    SilcHash hash
 
        Pointer to allocated hash object. This must be MD5 hash object.
@@ -112,20 +119,73 @@ typedef struct {
   SilcPacketFlags flags;
 
   unsigned char *src_id;
-  unsigned int src_id_len;
-  SilcIdType src_id_type;
+  unsigned short src_id_len;
+  unsigned char src_id_type;
 
   unsigned char *dst_id;
-  unsigned int dst_id_len;
-  SilcIdType dst_id_type;
+  unsigned short dst_id_len;
+  unsigned char dst_id_type;
 
-  unsigned int truelen;
-  unsigned int padlen;
+  unsigned short truelen;
+  unsigned short padlen;
 
   /* For padding generation */
   SilcRng rng;
+
+  /* Back pointers */
+  void *context;
+  SilcSocketConnection sock;
 } SilcPacketContext;
 
+/* 
+   Silc Packet Parser context.
+
+   This context is used in packet reception when silc_packet_receive_process
+   function calls parser callback that performs the actual packet decryption
+   and parsing. This context is sent as argument to the parser function.
+   This context must be free'd by the parser callback function.
+
+   Following description of the fields:
+
+   SilcPacketContext *packet
+
+       The actual packet received from the network. In this phase the
+       context is not parsed, only the packet->buffer is allocated and
+       it includes the raw packet data, which is encrypted.
+
+   SilcSocketConnection sock
+
+       The associated connection.
+
+   SilcCipher cipher
+
+       The cipher to be used in the decryption.
+
+   SilcHmac hmac
+
+       The HMAC to be used in the decryption.
+
+   void *context
+
+       User context that is sent to the silc_packet_receive_process
+       function. This usually includes application and connection specific
+       data.
+
+*/
+
+typedef struct {
+  SilcPacketContext *packet;
+  SilcSocketConnection sock;
+  SilcCipher cipher;
+  SilcHmac hmac;
+  void *context;
+} SilcPacketParserContext;
+
+/* The parser callback function. */
+typedef void (*SilcPacketParserCallback)(SilcPacketParserContext 
+                                        *parse_context);
+
+
 /* SILC Packet types. */
 #define SILC_PACKET_NONE                0       /* NULL, never sent */
 #define SILC_PACKET_DISCONNECT          1       /* Disconnection */
@@ -155,6 +215,9 @@ typedef struct {
 #define SILC_PACKET_NEW_CHANNEL_USER_LIST 25     /* List of users on "" */
 #define SILC_PACKET_REPLACE_ID           26      /* To replace old ID */
 #define SILC_PACKET_REMOVE_ID            27      /* To remove ID */
+#define SILC_PACKET_REMOVE_CHANNEL_USER  28      /* Remove user from channel */
+#define SILC_PACKET_REKEY                29
+#define SILC_PACKET_REKEY_DONE           30
 /* #define SILC_PACKET_MAX               255 */
 
 /* Macros */
@@ -173,13 +236,24 @@ do {                                                                           \
 
 /* Prototypes */
 int silc_packet_write(int sock, SilcBuffer src);
+int silc_packet_send(SilcSocketConnection sock, int force_send);
+void silc_packet_encrypt(SilcCipher cipher, SilcHmac hmac, 
+                        SilcBuffer buffer, unsigned int len);
+void silc_packet_assemble(SilcPacketContext *ctx);
+void silc_packet_send_prepare(SilcSocketConnection sock,
+                             unsigned int header_len,
+                             unsigned int padlen,
+                             unsigned int data_len);
 int silc_packet_read(int sock, SilcBuffer dest);
-void silc_packet_encrypt(SilcCipher cipher, SilcBuffer buffer,
-                        unsigned int len);
-void silc_packet_decrypt(SilcCipher cipher, SilcBuffer buffer, 
-                        unsigned int len);
+int silc_packet_receive(SilcSocketConnection sock);
+int silc_packet_decrypt(SilcCipher cipher, SilcHmac hmac,
+                       SilcBuffer buffer, SilcPacketContext *packet);
+void silc_packet_receive_process(SilcSocketConnection sock,
+                                SilcCipher cipher, SilcHmac hmac,
+                                SilcPacketParserCallback parser,
+                                void *context);
 SilcPacketType silc_packet_parse(SilcPacketContext *ctx);
 SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx);
-void silc_packet_assemble(SilcPacketContext *ctx);
+SilcPacketContext *silc_packet_context_dup(SilcPacketContext *ctx);
 
 #endif
diff --git a/lib/silccore/silcpayload.c b/lib/silccore/silcpayload.c
new file mode 100644 (file)
index 0000000..add747c
--- /dev/null
@@ -0,0 +1,449 @@
+/*
+
+  silcpayload.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 2000 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
+  GNU General Public License for more details.
+
+*/
+/* Implementation of generic payloads described in the protocol 
+   specification drafts. */
+/* $Id$ */
+
+#include "silcincludes.h"
+#include "silcpayload.h"
+
+/******************************************************************************
+
+                                ID Payload
+
+******************************************************************************/
+
+struct SilcIDPayloadStruct {
+  SilcIdType type;
+  unsigned short len;
+  unsigned char *id;
+};
+
+/* Parses buffer and return ID payload into payload structure */
+
+SilcIDPayload silc_id_payload_parse(SilcBuffer buffer)
+{
+  SilcIDPayload new;
+
+  SILC_LOG_DEBUG(("Parsing ID payload"));
+
+  new = silc_calloc(1, sizeof(*new));
+
+  silc_buffer_unformat(buffer,
+                      SILC_STR_UI_SHORT(&new->type),
+                      SILC_STR_UI_SHORT(&new->len),
+                      SILC_STR_END);
+
+  silc_buffer_pull(buffer, 4);
+
+  if (new->len > buffer->len)
+    goto err;
+
+  silc_buffer_unformat(buffer,
+                      SILC_STR_UI_XNSTRING_ALLOC(&new->id, new->len),
+                      SILC_STR_END);
+  silc_buffer_push(buffer, 4);
+
+  return new;
+
+ err:
+  silc_free(new);
+  return NULL;
+}
+
+/* Parses data and return ID payload into payload structure. */
+
+SilcIDPayload silc_id_payload_parse_data(unsigned char *data, 
+                                        unsigned int len)
+{
+  SilcIDPayload new;
+  SilcBuffer buffer;
+
+  SILC_LOG_DEBUG(("Parsing ID payload"));
+
+  buffer = silc_buffer_alloc(len);
+  silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
+  silc_buffer_put(buffer, data, len);
+
+  new = silc_calloc(1, sizeof(*new));
+
+  silc_buffer_unformat(buffer,
+                      SILC_STR_UI_SHORT(&new->type),
+                      SILC_STR_UI_SHORT(&new->len),
+                      SILC_STR_END);
+
+  silc_buffer_pull(buffer, 4);
+
+  if (new->len > buffer->len)
+    goto err;
+
+  silc_buffer_unformat(buffer,
+                      SILC_STR_UI_XNSTRING_ALLOC(&new->id, new->len),
+                      SILC_STR_END);
+
+  silc_buffer_free(buffer);
+  return new;
+
+ err:
+  silc_buffer_free(buffer);
+  silc_free(new);
+  return NULL;
+}
+
+/* Return the ID directly from the raw payload data. */
+
+void *silc_id_payload_parse_id(unsigned char *data, unsigned int len)
+{
+  SilcBuffer buffer;
+  SilcIdType type;
+  unsigned short idlen;
+  unsigned char *id;
+
+  buffer = silc_buffer_alloc(len);
+  silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
+  silc_buffer_put(buffer, data, len);
+
+  silc_buffer_unformat(buffer,
+                      SILC_STR_UI_SHORT(&type),
+                      SILC_STR_UI_SHORT(&idlen),
+                      SILC_STR_END);
+
+  silc_buffer_pull(buffer, 4);
+
+  if (idlen > buffer->len)
+    goto err;
+
+  silc_buffer_unformat(buffer,
+                      SILC_STR_UI_XNSTRING_ALLOC(&id, idlen),
+                      SILC_STR_END);
+
+  silc_buffer_free(buffer);
+
+  return silc_id_str2id(id, type);
+
+ err:
+  silc_buffer_free(buffer);
+  return NULL;
+}
+
+/* Encodes ID Payload */
+
+SilcBuffer silc_id_payload_encode(void *id, SilcIdType type)
+{
+  SilcBuffer buffer;
+  unsigned char *id_data;
+  unsigned int len;
+
+  SILC_LOG_DEBUG(("Parsing ID payload"));
+
+  id_data = silc_id_id2str(id, type);
+  len = silc_id_get_len(type);
+
+  buffer = silc_buffer_alloc(4 + len);
+  silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
+  silc_buffer_format(buffer,
+                    SILC_STR_UI_SHORT(type),
+                    SILC_STR_UI_SHORT(len),
+                    SILC_STR_UI_XNSTRING(id_data, len),
+                    SILC_STR_END);
+  silc_free(id_data);
+
+  return buffer;
+}
+
+/* Free ID Payload */
+
+void silc_id_payload_free(SilcIDPayload payload)
+{
+  if (payload) {
+    silc_free(payload->id);
+  }
+}
+
+/* Get ID type */
+
+SilcIdType silc_id_payload_get_type(SilcIDPayload payload)
+{
+  return payload->type;
+}
+
+/* Get ID */
+
+void *silc_id_payload_get_id(SilcIDPayload payload)
+{
+  return silc_id_str2id(payload->id, payload->type);
+}
+
+/* Get raw ID data. Data is duplicated. */
+
+unsigned char *silc_id_payload_get_data(SilcIDPayload payload)
+{
+  unsigned char *ret = silc_calloc(payload->len, sizeof(*ret));
+  memcpy(ret, payload->id, payload->len);
+  return ret;
+}
+
+/* Get length of ID */
+
+unsigned int silc_id_payload_get_len(SilcIDPayload payload)
+{
+  return payload->len;
+}
+
+/******************************************************************************
+
+                             Argument Payload
+
+******************************************************************************/
+
+struct SilcArgumentPayloadStruct {
+  unsigned int argc;
+  unsigned char **argv;
+  unsigned int *argv_lens;
+  unsigned int *argv_types;
+  unsigned int pos;
+};
+
+/* Parses arguments and returns them into Argument Payload structure. */
+
+SilcArgumentPayload silc_argument_payload_parse(SilcBuffer buffer,
+                                               unsigned int argc)
+{
+  SilcArgumentPayload new;
+  unsigned short payload_len = 0;
+  unsigned char arg_num = 0;
+  unsigned int arg_type = 0;
+  unsigned int pull_len = 0;
+  int i = 0;
+
+  SILC_LOG_DEBUG(("Parsing argument payload"));
+
+  new = silc_calloc(1, sizeof(*new));
+  new->argv = silc_calloc(argc, sizeof(unsigned char *));
+  new->argv_lens = silc_calloc(argc, sizeof(unsigned int));
+  new->argv_types = silc_calloc(argc, sizeof(unsigned int));
+    
+  /* Get arguments */
+  arg_num = 1;
+  for (i = 0; i < argc; i++) {
+    silc_buffer_unformat(buffer,
+                        SILC_STR_UI_SHORT(&payload_len),
+                        SILC_STR_UI_CHAR(&arg_type),
+                        SILC_STR_END);
+    
+    new->argv_lens[i] = payload_len;
+    new->argv_types[i] = arg_type;
+
+    if (payload_len > buffer->len)
+      break;
+    
+    /* Get argument data */
+    silc_buffer_pull(buffer, 3);
+    silc_buffer_unformat(buffer,
+                        SILC_STR_UI_XNSTRING_ALLOC(&new->argv[i], 
+                                                   payload_len),
+                        SILC_STR_END);
+
+    silc_buffer_pull(buffer, payload_len);
+    pull_len += 3 + payload_len;
+  }
+
+  if (buffer->len != 0)
+    goto err;
+
+  new->argc = argc;
+  new->pos = 0;
+
+  silc_buffer_push(buffer, pull_len);
+
+  return new;
+
+ err:
+  if (i) {
+    int k;
+
+    for (k = 0; k < i; k++)
+      silc_free(new->argv[k]);
+  }
+
+  silc_free(new->argv);
+  silc_free(new->argv_lens);
+  silc_free(new->argv_types);
+
+  if (new)
+    silc_free(new);
+
+  return NULL;
+}
+
+/* Encodes arguments in to Argument Paylods returning them to SilcBuffer. */
+
+SilcBuffer silc_argument_payload_encode(unsigned int argc,
+                                       unsigned char **argv,
+                                       unsigned int *argv_lens,
+                                       unsigned int *argv_types)
+{
+  SilcBuffer buffer;
+  unsigned int len;
+  int i;
+
+  SILC_LOG_DEBUG(("Encoding Argument payload"));
+
+  len = 0;
+  for (i = 0; i < argc; i++)
+    len += 3 + argv_lens[i];
+
+  buffer = silc_buffer_alloc(len);
+  silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
+
+  /* Put arguments */
+  for (i = 0; i < argc; i++) {
+    silc_buffer_format(buffer,
+                      SILC_STR_UI_SHORT(argv_lens[i]),
+                      SILC_STR_UI_CHAR(argv_types[i]),
+                      SILC_STR_UI_XNSTRING(argv[i], argv_lens[i]),
+                      SILC_STR_END);
+    silc_buffer_pull(buffer, 3 + argv_lens[i]);
+  }
+
+  silc_buffer_push(buffer, len);
+
+  return buffer;
+}
+
+#if 0
+/* Encodes Argument payload with variable argument list. The arguments
+   must be: unsigned int, unsigned char *, unsigned int, ... One 
+   {unsigned int, unsigned char * and unsigned int} forms one argument, 
+   thus `argc' in case when sending one {unsigned int, unsigned char * 
+   and unsigned int} 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_encode_payload_va(unsigned int argc, ...)
+{
+  va_list ap;
+  unsigned char **argv;
+  unsigned int *argv_lens = NULL, *argv_types = NULL;
+  unsigned char *x;
+  unsigned int x_len;
+  unsigned int x_type;
+  SilcBuffer buffer;
+  int i;
+
+  va_start(ap, argc);
+
+  argv = silc_calloc(argc, sizeof(unsigned char *));
+  argv_lens = silc_calloc(argc, sizeof(unsigned int));
+  argv_types = silc_calloc(argc, sizeof(unsigned int));
+
+  for (i = 0; i < argc; i++) {
+    x_type = va_arg(ap, unsigned int);
+    x = va_arg(ap, unsigned char *);
+    x_len = va_arg(ap, unsigned int);
+
+    argv[i] = silc_calloc(x_len + 1, sizeof(unsigned char));
+    memcpy(argv[i], x, x_len);
+    argv_lens[i] = x_len;
+    argv_types[i] = x_type;
+  }
+
+  buffer = silc_argument_payload_encode(argc, argv, 
+                                       argv_lens, argv_types);
+
+  for (i = 0; i < argc; i++)
+    silc_free(argv[i]);
+  silc_free(argv);
+  silc_free(argv_lens);
+  silc_free(argv_types);
+
+  return buffer;
+}
+#endif
+
+/* Free's Command Payload */
+
+void silc_argument_payload_free(SilcArgumentPayload payload)
+{
+  int i;
+
+  if (payload) {
+    for (i = 0; i < payload->argc; i++)
+      silc_free(payload->argv[i]);
+
+    silc_free(payload->argv);
+    silc_free(payload);
+  }
+}
+
+/* Returns number of arguments in payload */
+
+unsigned int silc_argument_get_arg_num(SilcArgumentPayload payload)
+{
+  return payload->argc;
+}
+
+/* Returns first argument from payload. */
+
+unsigned char *silc_argument_get_first_arg(SilcArgumentPayload payload,
+                                          unsigned int *ret_len)
+{
+  payload->pos = 0;
+
+  if (ret_len)
+    *ret_len = payload->argv_lens[payload->pos];
+
+  return payload->argv[payload->pos++];
+}
+
+/* Returns next argument from payload or NULL if no more arguments. */
+
+unsigned char *silc_argument_get_next_arg(SilcArgumentPayload payload,
+                                         unsigned int *ret_len)
+{
+  if (payload->pos >= payload->argc)
+    return NULL;
+
+  if (ret_len)
+    *ret_len = payload->argv_lens[payload->pos];
+
+  return payload->argv[payload->pos++];
+}
+
+/* Returns argument which type is `type'. */
+
+unsigned char *silc_argument_get_arg_type(SilcArgumentPayload payload,
+                                         unsigned int type,
+                                         unsigned int *ret_len)
+{
+  int i;
+
+  for (i = 0; i < payload->argc; i++)
+    if (payload->argv_types[i] == type)
+      break;
+
+  if (i >= payload->argc)
+    return NULL;
+
+  if (ret_len)
+    *ret_len = payload->argv_lens[i];
+
+  return payload->argv[i];
+}
diff --git a/lib/silccore/silcpayload.h b/lib/silccore/silcpayload.h
new file mode 100644 (file)
index 0000000..e58171e
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+
+  silcpayload.h
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 2000 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
+  GNU General Public License for more details.
+
+*/
+
+#ifndef SILCPAYLOAD_H
+#define SILCPAYLOAD_H
+
+/* Forward declarations */
+typedef struct SilcIDPayloadStruct *SilcIDPayload;
+typedef struct SilcArgumentPayloadStruct *SilcArgumentPayload;
+
+/* Prototypes */
+SilcIDPayload silc_id_payload_parse(SilcBuffer buffer);
+SilcArgumentPayload silc_argument_payload_parse(SilcBuffer buffer,
+                                               unsigned int argc);
+SilcIDPayload silc_id_payload_parse_data(unsigned char *data, 
+                                        unsigned int len);
+void *silc_id_payload_parse_id(unsigned char *data, unsigned int len);
+SilcBuffer silc_id_payload_encode(void *id, SilcIdType type);
+void silc_id_payload_free(SilcIDPayload payload);
+SilcIdType silc_id_payload_get_type(SilcIDPayload payload);
+void *silc_id_payload_get_id(SilcIDPayload payload);
+unsigned char *silc_id_payload_get_data(SilcIDPayload payload);
+unsigned int silc_id_payload_get_len(SilcIDPayload payload);
+SilcBuffer silc_argument_payload_encode(unsigned int argc,
+                                       unsigned char **argv,
+                                       unsigned int *argv_lens,
+                                       unsigned int *argv_types);
+void silc_argument_payload_free(SilcArgumentPayload payload);
+unsigned int silc_argument_get_arg_num(SilcArgumentPayload payload);
+unsigned char *silc_argument_get_first_arg(SilcArgumentPayload payload,
+                                          unsigned int *ret_len);
+unsigned char *silc_argument_get_next_arg(SilcArgumentPayload payload,
+                                         unsigned int *ret_len);
+unsigned char *silc_argument_get_arg_type(SilcArgumentPayload payload,
+                                         unsigned int type,
+                                         unsigned int *ret_len);
+
+#endif
index dfdf0321af317e18190fc7c3ce263f1520ada964..7c33c1afbfd3d6191ebc1543378b1e34bf8e221f 100644 (file)
 /*
  * $Id$
  * $Log$
+ * Revision 1.3  2000/07/20 10:17:25  priikone
+ *     Added dynamic protocol registering/unregistering support.  The
+ *     patch was provided by cras.
+ *
+ * Revision 1.2  2000/07/05 06:06:35  priikone
+ *     Global cosmetic change.
+ *
  * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
- *     Importet from internal CVS/Added Log headers.
+ *     Imported from internal CVS/Added Log headers.
  *
  *
  */
 #include "silcincludes.h"
 #include "silcprotocol.h"
 
+/* Dynamically registered protocols */
+SilcProtocolObject *silc_protocol_list = NULL;
+
+/* Dynamically registers new protocol. The protocol is added into protocol
+   list and can be unregistered with silc_protocol_unregister. */
+
+void silc_protocol_register(SilcProtocolType type,
+                           SilcProtocolCallback callback)
+{
+  SilcProtocolObject *new;
+
+  new = silc_calloc(1, sizeof(*new));
+  new->type = type;
+  new->callback = callback;
+
+  if (!silc_protocol_list)
+    silc_protocol_list = new;
+  else {
+    new->next = silc_protocol_list;
+    silc_protocol_list = new;
+  }
+}
+
+/* Unregisters protocol. The unregistering is done by both protocol type
+   and the protocol callback. */
+
+void silc_protocol_unregister(SilcProtocolType type,
+                              SilcProtocolCallback callback)
+{
+  SilcProtocolObject *protocol, *prev;
+
+  protocol = silc_protocol_list;
+  prev = NULL;
+  while (protocol && (protocol->type != type && 
+                      protocol->callback != callback)) {
+    prev = protocol;
+    protocol = protocol->next;
+  }
+
+  if (protocol) {
+    if (prev)
+      prev->next = protocol->next;
+    else
+      silc_protocol_list = protocol->next;
+
+    silc_free(protocol);
+  }
+}
+
 /* Allocates a new protocol object. The new allocated and initialized 
    protocol is returned to the new_protocol argument. The argument context
    is the context to be sent as argument for the protocol. The callback
 void silc_protocol_alloc(SilcProtocolType type, SilcProtocol *new_protocol,
                         void *context, SilcProtocolFinalCallback callback)
 {
-  int i;
+  SilcProtocolObject *protocol;
 
   SILC_LOG_DEBUG(("Allocating new protocol type %d", type));
 
-  for (i = 0; silc_protocol_list[i].callback; i++)
-    if (silc_protocol_list[i].type == type)
-      break;
+  protocol = silc_protocol_list;
+  while (protocol && protocol->type != type)
+    protocol = protocol->next;
 
-  if (!silc_protocol_list[i].callback) {
+  if (!protocol) {
     SILC_LOG_ERROR(("Requested protocol does not exists"));
     return;
   }
 
   *new_protocol = silc_calloc(1, sizeof(**new_protocol));
-  if (*new_protocol == NULL) {
-    SILC_LOG_ERROR(("Cannot allocate new protocol object"));
-    return;
-  }
-
-  (*new_protocol)->protocol = (SilcProtocolObject *)&silc_protocol_list[i];
+  (*new_protocol)->protocol = protocol;
   (*new_protocol)->state = SILC_PROTOCOL_STATE_UNKNOWN;
   (*new_protocol)->context = context;
   (*new_protocol)->execute = silc_protocol_execute;
index f04ffd794f843a0ffd37fe4d9895df392ee5ac2c..6d5ef0b529d89455536b9fea1c5bf02ab06feb4c 100644 (file)
@@ -31,14 +31,23 @@ typedef unsigned char SilcProtocolState;
    the START state or you break every protocol. */
 #define SILC_PROTOCOL_STATE_UNKNOWN 0
 #define SILC_PROTOCOL_STATE_START 1
-#define SILC_PROTOCOL_STATE_END 253
-#define SILC_PROTOCOL_STATE_ERROR 254
+#define SILC_PROTOCOL_STATE_END 252
+#define SILC_PROTOCOL_STATE_FAILURE 253         /* Received failure from remote */
+#define SILC_PROTOCOL_STATE_ERROR 254    /* Local error at our end */
 
 /* Connection Authentication protocols' authentication methods */
 #define SILC_PROTOCOL_CONN_AUTH_NONE 0
 #define SILC_PROTOCOL_CONN_AUTH_PASSWORD 1
 #define SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY 2
 
+/* XXX These don't belong here really! */
+/* Connection authentication protocol status message */
+#define SILC_CONN_AUTH_OK 0
+#define SILC_CONN_AUTH_FAILED 1
+
+/* Type definition for above auth methods */
+typedef unsigned char SilcProtocolAuthMeth;
+
 /* 
    SILC Protocol Object.
 
@@ -91,15 +100,17 @@ typedef unsigned char SilcProtocolState;
 */
 typedef SilcTaskCallback SilcProtocolCallback;
 
-typedef struct {
+typedef struct SilcProtocolObjectStruct {
   SilcProtocolType type;
   SilcProtocolCallback callback;
+
+  struct SilcProtocolObjectStruct *next;
 } SilcProtocolObject;
 
 typedef SilcTaskCallback SilcProtocolFinalCallback;
 typedef SilcTaskCallback SilcProtocolExecute;
 
-typedef struct SilcProtocolObjectStruct {
+typedef struct SilcProtocolStruct {
   SilcProtocolObject *protocol;
   SilcProtocolState state;
   void *context;
@@ -110,12 +121,11 @@ typedef struct SilcProtocolObjectStruct {
   SilcProtocolFinalCallback final_callback;
 } *SilcProtocol;
 
-/* Definition for SILC protocol list. This list includes all the
-   protocols in the SILC. SILC server and client defined own list of
-   protocols. */
-extern const SilcProtocolObject silc_protocol_list[];
-
 /* Prototypes */
+void silc_protocol_register(SilcProtocolType type,
+                           SilcProtocolCallback callback);
+void silc_protocol_unregister(SilcProtocolType type,
+                              SilcProtocolCallback callback);
 void silc_protocol_alloc(SilcProtocolType type, SilcProtocol *new_protocol,
                         void *context, SilcProtocolFinalCallback callback);
 void silc_protocol_free(SilcProtocol protocol);
index 7025205ea9adaa5c5206c91abf6abf23fdf7e06c..79ea3f84a676929fe1d9d8426e1aad25f8fcccd8 100644 (file)
 /*
  * $Id$
  * $Log$
+ * Revision 1.2  2000/07/05 06:06:35  priikone
+ *     Global cosmetic change.
+ *
  * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
- *     Importet from internal CVS/Added Log headers.
+ *     Imported from internal CVS/Added Log headers.
  *
  *
  */
@@ -36,14 +39,9 @@ void silc_socket_alloc(int sock, SilcSocketType type, void *user_data,
 {
   SILC_LOG_DEBUG(("Allocating new socket connection object"));
 
-  *new_socket = silc_calloc(1, sizeof(**new_socket));
-  if (*new_socket == NULL) {
-    SILC_LOG_ERROR(("Could not allocate new socket connection object"));
-    return;
-  }
-
   /* Set the pointers. Incoming and outgoing data buffers
      are allocated by the server when they are first used. */
+  *new_socket = silc_calloc(1, sizeof(**new_socket));
   (*new_socket)->sock = sock;
   (*new_socket)->type = type;
   (*new_socket)->user_data = user_data;
index 5706b682ab3ca11f6f0cb819105df099a1806215..291a5a46e798546d964f12d42421446cc8bb98e5 100644 (file)
@@ -76,6 +76,13 @@ typedef enum {
        indicate several different status that can affect the use of the
        socket object.
 
+   char *hostname
+   char *ip
+   unsigned short port
+
+       Resolved hostname, IP address and port of the connection who owns
+       this object.
+
    SilcBuffer inbuf
    SilcBuffer outbuf
 
diff --git a/lib/silccore/silcutil.c b/lib/silccore/silcutil.c
deleted file mode 100644 (file)
index 23d2440..0000000
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
-
-  silcutil.c
-
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
-
-  Copyright (C) 1997 - 2000 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
-  GNU General Public License for more details.
-
-*/
-/*
- * These are general utility functions that doesn't belong to any specific
- * group of routines.
- */
-/*
- * $Id$
- * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
- *     Importet from internal CVS/Added Log headers.
- *
- *
- */
-
-#include "silcincludes.h"
-
-/* Reads a file to a buffer. The allocated buffer is returned. Length of
-   the file read is returned to the return_len argument. */
-
-char *silc_file_read(const char *filename, int *return_len)
-{
-  int fd;
-  char *buffer;
-  int filelen;
-
-  fd = open(filename, O_RDONLY);
-  if (fd < 0) {
-    SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno)));
-    return NULL;
-  }
-
-  filelen = lseek(fd, (off_t)0L, SEEK_END);
-  lseek(fd, (off_t)0L, SEEK_SET);  
-
-  if (filelen < 0) {
-    SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno)));
-    return NULL;
-  }
-  
-  buffer = silc_calloc(filelen + 1, sizeof(char));
-  
-  if ((read(fd, buffer, filelen)) == -1) {
-    memset(buffer, 0, sizeof(buffer));
-    close(fd);
-    SILC_LOG_ERROR(("Cannot read from file %s: %s", filename,
-                    strerror(errno)));
-    return NULL;
-  }
-
-  close(fd);
-  buffer[filelen] = EOF;
-  
-  *return_len = filelen;
-  return buffer;
-}
-
-/* Writes a buffer to the file. */
-
-int silc_file_write(const char *filename, const char *buffer, int len)
-{
-  int fd;
-        
-  if ((fd = creat(filename, 0644)) == -1) {
-    SILC_LOG_ERROR(("Cannot open file %s for writing: %s", strerror(errno)));
-    return -1;
-  }
-  
-  if ((write(fd, buffer, len)) == -1) {
-    SILC_LOG_ERROR(("Cannot write to file %s: %s", strerror(errno)));
-    return -1;
-  }
-
-  close(fd);
-  
-  return 0;
-}
-
-/* Gets line from a buffer. Stops reading when a newline or EOF occurs.
-   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)
-{
-  static int start = 0;
-  int i;
-  
-  memset(dest, 0, destlen);
-  
-  if (begin != start)
-    start = 0;
-  
-  i = 0;
-  for ( ; start <= srclen; i++, start++) {
-    if (i > destlen)
-      return -1;
-    
-    dest[i] = src[start];
-    
-    if (dest[i] == EOF) 
-      return EOF;
-    
-    if (dest[i] == '\n') 
-      break;
-  }
-  start++;
-  
-  return start;
-}
-
-/* Checks line for illegal characters. Return -1 when illegal character
-   were found. This is used to check for bad lines when reading data from
-   for example a configuration file. */
-
-int silc_check_line(char *buf) 
-{
-  /* Illegal characters in line */
-  if (strchr(buf, '#')) return -1;
-  if (strchr(buf, '\'')) return -1;
-  if (strchr(buf, '\\')) return -1;
-  if (strchr(buf, '\r')) return -1;
-  if (strchr(buf, '\a')) return -1;
-  if (strchr(buf, '\b')) return -1;
-  if (strchr(buf, '\f')) return -1;
-  
-  /* Empty line */
-  if (buf[0] == '\n')
-    return -1;
-  
-  return 0;
-}
-
-/* Returns current time as string. */
-
-char *silc_get_time()
-{
-  time_t curtime;
-  char *return_time;
-
-  curtime = time(NULL);
-  return_time = ctime(&curtime);
-  return_time[strlen(return_time) - 1] = '\0';
-
-  return return_time;
-}
-
-/* Converts string to capital characters */
-
-char *silc_to_upper(char *string)
-{
-  int i;
-  char *ret = silc_calloc(strlen(string) + 1, sizeof(char));
-
-  for (i = 0; i < strlen(string); i++)
-    ret[i] = toupper(string[i]);
-
-  return ret;
-}
-
-/* Compares two strings. Strings may include wildcards * and ?.
-   Returns TRUE if strings match. */
-
-int silc_string_compare(char *string1, char *string2)
-{
-  int i;
-  int slen1 = strlen(string1);
-  int slen2 = strlen(string2);
-  char *tmpstr1, *tmpstr2;
-
-  if (!string1 || !string2)
-    return FALSE;
-
-  /* See if they are same already */
-  if (!strncmp(string1, string2, strlen(string2)))
-    return TRUE;
-
-  if (slen2 < slen1)
-    if (!strchr(string1, '*'))
-      return FALSE;
-  
-  /* Take copies of the original strings as we will change them */
-  tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
-  memcpy(tmpstr1, string1, slen1);
-  tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
-  memcpy(tmpstr2, string2, slen2);
-  
-  for (i = 0; i < slen2; i++) {
-    
-    /* * wildcard. Only one * wildcard is possible. */
-    if (tmpstr1[i] == '*')
-      if (!strncmp(tmpstr1, tmpstr2, i)) {
-       memset(tmpstr2, 0, slen2);
-       strncpy(tmpstr2, tmpstr1, i);
-       break;
-      }
-    
-    /* ? wildcard */
-    if (tmpstr1[i] == '?') {
-      if (!strncmp(tmpstr1, tmpstr2, i)) {
-       if (!(slen1 < i + 1))
-         if (tmpstr1[i + 1] != '?' &&
-             tmpstr1[i + 1] != tmpstr2[i + 1])
-           continue;
-       
-       if (!(slen1 < slen2))
-         tmpstr2[i] = '?';
-      }
-#if 0
-    } else {
-      if (strncmp(tmpstr1, tmpstr2, i))
-       strncpy(tmpstr2, string2, slen2);
-#endif
-    }
-  }
-  
-  /* if using *, remove it */
-  if (strchr(tmpstr1, '*'))
-    *strchr(tmpstr1, '*') = 0;
-  
-  if (!strcmp(tmpstr1, tmpstr2)) {
-    memset(tmpstr1, 0, slen1);
-    memset(tmpstr2, 0, slen2);
-    silc_free(tmpstr1);
-    silc_free(tmpstr2);
-    return TRUE;
-  }
-  
-  memset(tmpstr1, 0, slen1);
-  memset(tmpstr2, 0, slen2);
-  silc_free(tmpstr1);
-  silc_free(tmpstr2);
-  return FALSE;
-}
index b0d7d8185ab09bc745be1f5f546dc98ee91071a6..a1441d19e464be92c185adf7edf7308e1791190b 100644 (file)
@@ -40,5 +40,5 @@ libsilccrypt_a_SOURCES = \
 EXTRA_DIST = *.h
 
 INCLUDES = -I. -I.. -I../silccore -I../silcmath -I../silcske \
-       -I../silcsim -I../.. -I../../includes \
-       -I../silcmath/gmp-3.0.1
+       -I../silcsim -I../.. -I../silcutil -I../../includes \
+       -I../silcmath/gmp -I../trq
index 05034a6620be3fc02281d7e742fffac717371c81..a19924766400178472fbc1daea7d3638e03c9d59 100644 (file)
@@ -20,8 +20,8 @@
 /*
  * $Id$
  * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:54  priikone
- *     Importet from internal CVS/Added Log headers.
+ * Revision 1.1  2000/06/27 11:36:54  priikone
+ * Initial revision
  *
  *
  */
index a83c06e5a9d9399b684c63dec175f3756f10c74d..59581400d44caf432bb24d0c4af48226a6119364 100644 (file)
@@ -20,8 +20,8 @@
 /*
  * $Id$
  * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:54  priikone
- *     Importet from internal CVS/Added Log headers.
+ * Revision 1.1  2000/06/27 11:36:54  priikone
+ * Initial revision
  *
  *
  */
index a7b8ece9db549bc0f4e59efefd0d44a9bbd26a35..b7f83fc76253bebf9c37402d3eb929ee07b0192d 100644 (file)
@@ -25,5 +25,6 @@
 #include "mars.h"
 #include "rc6.h"
 #include "twofish.h"
+#include "rijndael.h"
 
 #endif
diff --git a/lib/silccrypt/crypton.c b/lib/silccrypt/crypton.c
deleted file mode 100644 (file)
index dae0221..0000000
+++ /dev/null
@@ -1,298 +0,0 @@
-/* Modified for SILC. -Pekka */\r
-\r
-/* This is an independent implementation of the encryption algorithm:   */\r
-/*                                                                      */\r
-/*         CRYPTON by Chae Hoon Lim of Future Systms Inc                */\r
-/*                                                                      */\r
-/* which is a candidate algorithm in the Advanced Encryption Standard   */\r
-/* programme of the US National Institute of Standards and Technology.  */\r
-/*                                                                      */\r
-/* Copyright in this implementation is held by Dr B R Gladman but I     */\r
-/* hereby give permission for its free direct or derivative use subject */\r
-/* to acknowledgment of its origin and compliance with any conditions   */\r
-/* that the originators of the algorithm place on its exploitation.     */\r
-/*                                                                      */\r
-/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999     */\r
-\r
-/* Timing data for CRYPTON (crypton.c)\r
-\r
-128 bit key:\r
-Key Setup:    531/1369 cycles (encrypt/decrypt)\r
-Encrypt:       474 cycles =    54.0 mbits/sec\r
-Decrypt:       474 cycles =    54.0 mbits/sec\r
-Mean:          474 cycles =    54.0 mbits/sec\r
-\r
-192 bit key:\r
-Key Setup:    539/1381 cycles (encrypt/decrypt)\r
-Encrypt:       473 cycles =    54.1 mbits/sec\r
-Decrypt:       470 cycles =    54.5 mbits/sec\r
-Mean:          472 cycles =    54.3 mbits/sec\r
-\r
-256 bit key:\r
-Key Setup:    552/1392 cycles (encrypt/decrypt)\r
-Encrypt:       469 cycles =    54.6 mbits/sec\r
-Decrypt:       483 cycles =    53.0 mbits/sec\r
-Mean:          476 cycles =    53.8 mbits/sec\r
-\r
-*/\r
-\r
-#include "silcincludes.h"\r
-#include "crypton.h"\r
-\r
-#define gamma_tau(x,b,m,p,q) \\r
-    (x) = (((u4byte)s_box[p][byte(b[0],m)]      ) | \\r
-           ((u4byte)s_box[q][byte(b[1],m)] <<  8) | \\r
-           ((u4byte)s_box[p][byte(b[2],m)] << 16) | \\r
-           ((u4byte)s_box[q][byte(b[3],m)] << 24))\r
-\r
-#define ma_0    0x3fcff3fc\r
-#define ma_1    0xfc3fcff3\r
-#define ma_2    0xf3fc3fcf\r
-#define ma_3    0xcff3fc3f\r
-\r
-#define mb_0    0xcffccffc\r
-#define mb_1    0xf33ff33f\r
-#define mb_2    0xfccffccf\r
-#define mb_3    0x3ff33ff3\r
-\r
-#define pi(b,n0,n1,n2,n3)       \\r
-    (((b)[0] & ma_##n0) ^       \\r
-     ((b)[1] & ma_##n1) ^       \\r
-     ((b)[2] & ma_##n2) ^       \\r
-     ((b)[3] & ma_##n3))\r
-\r
-#define phi_n(x,n0,n1,n2,n3)    \\r
-    (     (x)      & mb_##n0) ^ \\r
-    (rotl((x),  8) & mb_##n1) ^ \\r
-    (rotl((x), 16) & mb_##n2) ^ \\r
-    (rotl((x), 24) & mb_##n3)\r
-\r
-#define phi_00(x)   phi_n(x,0,1,2,3)\r
-#define phi_01(x)   phi_n(x,3,0,1,2)\r
-#define phi_02(x)   phi_n(x,2,3,0,1)\r
-#define phi_03(x)   phi_n(x,1,2,3,0)\r
-\r
-#define phi_10(x)   phi_n(x,3,0,1,2)\r
-#define phi_11(x)   phi_n(x,2,3,0,1)\r
-#define phi_12(x)   phi_n(x,1,2,3,0)\r
-#define phi_13(x)   phi_n(x,0,1,2,3)\r
-\r
-#define phi0(x,y)               \\r
-    (y)[0] = phi_00((x)[0]);    \\r
-    (y)[1] = phi_01((x)[1]);    \\r
-    (y)[2] = phi_02((x)[2]);    \\r
-    (y)[3] = phi_03((x)[3])\r
-\r
-#define phi1(x,y)               \\r
-    (y)[0] = phi_10((x)[0]);    \\r
-    (y)[1] = phi_11((x)[1]);    \\r
-    (y)[2] = phi_12((x)[2]);    \\r
-    (y)[3] = phi_13((x)[3])\r
-\r
-u1byte p_box[3][16] = \r
-{   { 15,  9,  6,  8,  9,  9,  4, 12,  6,  2,  6, 10,  1,  3,  5, 15 },\r
-    { 10, 15,  4,  7,  5,  2, 14,  6,  9,  3, 12,  8, 13,  1, 11,  0 },\r
-    {  0,  4,  8,  4,  2, 15,  8, 13,  1,  1, 15,  7,  2, 11, 14, 15 }\r
-};\r
-\r
-u4byte  tab_gen = 0;\r
-u1byte  s_box[2][256];\r
-u4byte  s_tab[4][256];\r
-\r
-void gen_tab(void)\r
-{   u4byte  i, xl, xr, yl, yr;\r
-\r
-    for(i = 0; i < 256; ++i)\r
-    {\r
-        xl = (i & 0xf0) >> 4; xr = i & 15;\r
-\r
-        yr = xr ^ p_box[1][xl ^ p_box[0][xr]];\r
-        yl = xl ^ p_box[0][xr] ^ p_box[2][yr];\r
-\r
-        yr |= (yl << 4); s_box[0][i] = (u1byte)yr; s_box[1][yr] = (u1byte)i;\r
-\r
-        xr = yr * 0x01010101; xl = i * 0x01010101;\r
-\r
-        s_tab[0][ i] = xr & 0x3fcff3fc;\r
-        s_tab[1][yr] = xl & 0xfc3fcff3;\r
-        s_tab[2][ i] = xr & 0xf3fc3fcf;\r
-        s_tab[3][yr] = xl & 0xcff3fc3f;\r
-    }\r
-};\r
-\r
-/* initialise the key schedule from the user supplied key   */\r
-\r
-u4byte  kp[4] = { 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f };\r
-u4byte  kq[4] = { 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, 0xcbbb9d5d };\r
-\r
-#define h0_block(n,r0,r1)                           \\r
-    e_key[4 * n +  8] = rotl(e_key[4 * n + 0], r0); \\r
-    e_key[4 * n +  9] = rc ^ e_key[4 * n + 1];      \\r
-    e_key[4 * n + 10] = rotl(e_key[4 * n + 2], r1); \\r
-    e_key[4 * n + 11] = rc ^ e_key[4 * n + 3]\r
-\r
-#define h1_block(n,r0,r1)                           \\r
-    e_key[4 * n +  8] = rc ^ e_key[4 * n + 0];      \\r
-    e_key[4 * n +  9] = rotl(e_key[4 * n + 1], r0); \\r
-    e_key[4 * n + 10] = rc ^ e_key[4 * n + 2];      \\r
-    e_key[4 * n + 11] = rotl(e_key[4 * n + 3], r1)\r
-\r
-u4byte *crypton_set_key(CryptonContext *ctx,\r
-                       const u4byte in_key[], const u4byte key_len)\r
-{   \r
-    u4byte  i, rc, t0, t1, tmp[4];\r
-    u4byte *e_key = ctx->l_key + 52;\r
-    u4byte *d_key = ctx->l_key;\r
-\r
-    if(!tab_gen)\r
-    {\r
-        gen_tab(); tab_gen = 1;\r
-    }\r
-\r
-    e_key[2] = e_key[3] = e_key[6] = e_key[7] = 0;\r
-\r
-    switch((key_len + 63) / 64)\r
-    {\r
-    case 4: e_key[3] = in_key[6]; e_key[7] = in_key[7];\r
-    case 3: e_key[2] = in_key[4]; e_key[6] = in_key[5];\r
-    case 2: e_key[0] = in_key[0]; e_key[4] = in_key[1];\r
-            e_key[1] = in_key[2]; e_key[5] = in_key[3];\r
-    }\r
-\r
-    tmp[0] = pi(e_key, 0, 1, 2, 3) ^ kp[0];\r
-    tmp[1] = pi(e_key, 1, 2, 3, 0) ^ kp[1];\r
-    tmp[2] = pi(e_key, 2, 3, 0, 1) ^ kp[2];\r
-    tmp[3] = pi(e_key, 3, 0, 1, 2) ^ kp[3];\r
-    \r
-    gamma_tau(e_key[0], tmp, 0, 0, 1); \r
-    gamma_tau(e_key[1], tmp, 1, 1, 0);\r
-    gamma_tau(e_key[2], tmp, 2, 0, 1); \r
-    gamma_tau(e_key[3], tmp, 3, 1, 0);\r
-\r
-    tmp[0] = pi(e_key + 4, 1, 2, 3, 0) ^ kq[0]; \r
-    tmp[1] = pi(e_key + 4, 2, 3, 0, 1) ^ kq[1];\r
-    tmp[2] = pi(e_key + 4, 3, 0, 1, 2) ^ kq[2]; \r
-    tmp[3] = pi(e_key + 4, 0, 1, 2, 3) ^ kq[3];\r
-\r
-    gamma_tau(e_key[4], tmp, 0, 1, 0); \r
-    gamma_tau(e_key[5], tmp, 1, 0, 1);\r
-    gamma_tau(e_key[6], tmp, 2, 1, 0); \r
-    gamma_tau(e_key[7], tmp, 3, 0, 1);\r
-\r
-    t0 = e_key[0] ^ e_key[1] ^ e_key[2] ^ e_key[3];\r
-    t1 = e_key[4] ^ e_key[5] ^ e_key[6] ^ e_key[7];\r
-    \r
-    e_key[0] ^= t1; e_key[1] ^= t1;\r
-    e_key[2] ^= t1; e_key[3] ^= t1;\r
-    e_key[4] ^= t0; e_key[5] ^= t0;\r
-    e_key[6] ^= t0; e_key[7] ^= t0;\r
-\r
-    rc = 0x01010101; \r
-    h0_block( 0,  8, 16); h1_block(1, 16, 24); rc <<= 1;\r
-    h1_block( 2, 24,  8); h0_block(3,  8, 16); rc <<= 1;\r
-    h0_block( 4, 16, 24); h1_block(5, 24,  8); rc <<= 1;\r
-    h1_block( 6,  8, 16); h0_block(7, 16, 24); rc <<= 1;\r
-    h0_block( 8, 24,  8); h1_block(9,  8, 16); rc <<= 1;\r
-    h1_block(10, 16, 24);\r
-\r
-    for(i = 0; i < 13; ++i)\r
-    {\r
-        if(i & 1)\r
-        {\r
-            phi0(e_key + 4 * i, d_key + 48 - 4 * i);\r
-        }\r
-        else\r
-        {\r
-            phi1(e_key + 4 * i, d_key + 48 - 4 * i);\r
-        }\r
-    }\r
-\r
-    phi1(d_key + 48, d_key + 48);\r
-    phi1(e_key + 48, e_key + 48);\r
-\r
-    return l_key;\r
-};\r
-\r
-/* encrypt a block of text  */\r
-\r
-#define fr0(i,k)                                    \\r
-    b1[i] = s_tab[ (i)         ][byte(b0[0],i)] ^   \\r
-            s_tab[((i) + 1) & 3][byte(b0[1],i)] ^   \\r
-            s_tab[((i) + 2) & 3][byte(b0[2],i)] ^   \\r
-            s_tab[((i) + 3) & 3][byte(b0[3],i)] ^ (k)\r
-\r
-#define fr1(i,k)                                    \\r
-    b0[i] = s_tab[((i) + 1) & 3][byte(b1[0],i)] ^   \\r
-            s_tab[((i) + 2) & 3][byte(b1[1],i)] ^   \\r
-            s_tab[((i) + 3) & 3][byte(b1[2],i)] ^   \\r
-            s_tab[(i)          ][byte(b1[3],i)] ^ (k)\r
-\r
-#define f0_rnd(kp)                  \\r
-    fr0(0,(kp)[0]); fr0(1,(kp)[1]); \\r
-    fr0(2,(kp)[2]); fr0(3,(kp)[3])\r
-\r
-#define f1_rnd(kp)                  \\r
-    fr1(0,(kp)[0]); fr1(1,(kp)[1]); \\r
-    fr1(2,(kp)[2]); fr1(3,(kp)[3])\r
-\r
-void crypton_encrypt(CryptonContext *ctx,\r
-                    const u4byte in_blk[4], u4byte out_blk[4])\r
-{   \r
-    u4byte  b0[4], b1[4];\r
-    u4byte *e_key = ctx->l_key + 52;\r
-    u4byte *d_key = ctx->l_key;\r
-\r
-    b0[0] = in_blk[0] ^ e_key[0];\r
-    b0[1] = in_blk[1] ^ e_key[1];\r
-    b0[2] = in_blk[2] ^ e_key[2];\r
-    b0[3] = in_blk[3] ^ e_key[3];\r
-\r
-    f0_rnd(e_key +  4); f1_rnd(e_key +  8);\r
-    f0_rnd(e_key + 12); f1_rnd(e_key + 16);\r
-    f0_rnd(e_key + 20); f1_rnd(e_key + 24);\r
-    f0_rnd(e_key + 28); f1_rnd(e_key + 32);\r
-    f0_rnd(e_key + 36); f1_rnd(e_key + 40);\r
-    f0_rnd(e_key + 44);\r
-\r
-    gamma_tau(b0[0], b1, 0, 1, 0); \r
-    gamma_tau(b0[1], b1, 1, 0, 1); \r
-    gamma_tau(b0[2], b1, 2, 1, 0); \r
-    gamma_tau(b0[3], b1, 3, 0, 1);\r
-\r
-    out_blk[0] = b0[0] ^ e_key[48]; \r
-    out_blk[1] = b0[1] ^ e_key[49];\r
-    out_blk[2] = b0[2] ^ e_key[50]; \r
-    out_blk[3] = b0[3] ^ e_key[51];\r
-};\r
-\r
-/* decrypt a block of text  */\r
-\r
-void crypton_decrypt(CryptonContext *ctx,\r
-                    const u4byte in_blk[4], u4byte out_blk[4])\r
-{   \r
-    u4byte  b0[4], b1[4];\r
-    u4byte *e_key = ctx->l_key + 52;\r
-    u4byte *d_key = ctx->l_key;\r
-\r
-    b0[0] = in_blk[0] ^ d_key[0];\r
-    b0[1] = in_blk[1] ^ d_key[1];\r
-    b0[2] = in_blk[2] ^ d_key[2];\r
-    b0[3] = in_blk[3] ^ d_key[3];\r
-\r
-    f0_rnd(d_key +  4); f1_rnd(d_key +  8);\r
-    f0_rnd(d_key + 12); f1_rnd(d_key + 16);\r
-    f0_rnd(d_key + 20); f1_rnd(d_key + 24);\r
-    f0_rnd(d_key + 28); f1_rnd(d_key + 32);\r
-    f0_rnd(d_key + 36); f1_rnd(d_key + 40);\r
-    f0_rnd(d_key + 44);\r
-\r
-    gamma_tau(b0[0], b1, 0, 1, 0); \r
-    gamma_tau(b0[1], b1, 1, 0, 1); \r
-    gamma_tau(b0[2], b1, 2, 1, 0); \r
-    gamma_tau(b0[3], b1, 3, 0, 1);\r
-    \r
-    out_blk[0] = b0[0] ^ d_key[48]; \r
-    out_blk[1] = b0[1] ^ d_key[49];\r
-    out_blk[2] = b0[2] ^ d_key[50]; \r
-    out_blk[3] = b0[3] ^ d_key[51];\r
-};\r
diff --git a/lib/silccrypt/crypton.h b/lib/silccrypt/crypton.h
deleted file mode 100644 (file)
index 22c79b9..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
-
-  crypton.h
-
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
-
-  Copyright (C) 1999 - 2000 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
-  GNU General Public License for more details.
-
-*/
-/*
- * $Id$
- * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:54  priikone
- *     Importet from internal CVS/Added Log headers.
- *
- *
- */
-
-#ifndef CRYPTON_H
-#define CRYPTON_H
-
-#include "crypton_internal.h"
-
-/* 
- * SILC Crypto API for Crypton
- */
-
-/* Sets the key for the cipher. */
-
-SILC_CIPHER_API_SET_KEY(crypton)
-{
-  crypton_set_key((CryptonContext *)context, (unsigned int *)key, keylen);
-  return TRUE;
-}
-
-/* Sets the string as a new key for the cipher. The string is first
-   hashed and then used as a new key. */
-
-SILC_CIPHER_API_SET_KEY_WITH_STRING(crypton)
-{
-  SilcHash hash;
-  unsigned char key[16];
-
-  silc_hash_alloc("md5", &hash);
-  hash->make_hash(hash, string, stringlen, key);
-
-  crypton_set_key((CryptonContext *)context, key, sizeof(key));
-
-  silc_hash_free(hash);
-  memset(&key, 'F', sizeof(key));
-
-  return TRUE;
-}
-
-/* Returns the size of the cipher context. */
-
-SILC_CIPHER_API_CONTEXT_LEN(crypton)
-{
-  return sizeof(CryptonContext);
-}
-
-/* Encrypts with the cipher in CBC mode. */
-
-SILC_CIPHER_API_ENCRYPT_CBC(crypton)
-{
-  unsigned int *in, *out, *tiv;
-  unsigned int tmp[4];
-  int i;
-
-  in = (unsigned int *)src;
-  out = (unsigned int *)dst;
-  tiv = (unsigned int *)iv;
-
-  tmp[0] = in[0] ^ tiv[0];
-  tmp[1] = in[1] ^ tiv[1];
-  tmp[2] = in[2] ^ tiv[2];
-  tmp[3] = in[3] ^ tiv[3];
-  crypton_encrypt((CryptonContext *)context, tmp, out);
-  in += 4;
-  out += 4;
-
-  for (i = 16; i < len; i += 16) {
-    tmp[0] = in[0] ^ out[0 - 4];
-    tmp[1] = in[1] ^ out[1 - 4];
-    tmp[2] = in[2] ^ out[2 - 4];
-    tmp[3] = in[3] ^ out[3 - 4];
-    crypton_encrypt((CryptonContext *)context, tmp, out);
-    in += 4;
-    out += 4;
-  }
-
-  return TRUE;
-}
-
-/* Decrypts with the cipher in CBC mode. */
-
-SILC_CIPHER_API_DECRYPT_CBC(crypton)
-{
-  unsigned int *in, *out, *tiv;
-  int i;
-
-  in = (unsigned int *)src;
-  out = (unsigned int *)dst;
-  tiv = (unsigned int *)iv;
-
-  crypton_decrypt((CryptonContext *)context, in, out);
-  out[0] ^= tiv[0];
-  out[1] ^= tiv[1];
-  out[2] ^= tiv[2];
-  out[3] ^= tiv[3];
-  in += 4;
-  out += 4;
-
-  for (i = 16; i < len; i += 16) {
-    crypton_decrypt((CryptonContext *)context, in, out);
-    out[0] ^= in[0 - 4];
-    out[1] ^= in[1 - 4];
-    out[2] ^= in[2 - 4];
-    out[3] ^= in[3 - 4];
-    in += 4;
-    out += 4;
-  }
-
-  return TRUE;
-}
-
-#endif
diff --git a/lib/silccrypt/crypton_internal.h b/lib/silccrypt/crypton_internal.h
deleted file mode 100644 (file)
index 3dd7976..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
-
-  crypton_internal.h
-
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
-
-  Copyright (C) 1999 - 2000 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
-  GNU General Public License for more details.
-
-*/
-
-#ifndef CRYPTON_INTERNAL_H
-#define CRYPTON_INTERNAL_H
-
-#include "ciphers_def.h"
-
-/* Cipher's context */
-typedef struct {
-  u4byte l_key[104];
-} CryptonContext;
-
-/* Prototypes */
-u4byte *crypton_set_key(CryptonContext *ctx,
-                       const u4byte in_key[], const u4byte key_len);
-void crypton_encrypt(CryptonContext *ctx,
-                    const u4byte in_blk[4], u4byte out_blk[4]);
-void crypton_decrypt(CryptonContext *ctx,
-                    const u4byte in_blk[4], u4byte out_blk[4]);
-
-#endif
diff --git a/lib/silccrypt/dfc.c b/lib/silccrypt/dfc.c
deleted file mode 100644 (file)
index ba1449c..0000000
+++ /dev/null
@@ -1,410 +0,0 @@
-/* Modified for SILC. -Pekka */\r
-\r
-/* This is an independent implementation of the encryption algorithm:   */\r
-/*                                                                      */\r
-/*         DFC designed by a team at CNRS and France Telecom            */\r
-/*                                                                      */\r
-/* which is a candidate algorithm in the Advanced Encryption Standard   */\r
-/* programme of the US National Institute of Standards and Technology.  */\r
-/*                                                                      */\r
-/* Copyright in this implementation is held by Dr B R Gladman but I     */\r
-/* hereby give permission for its free direct or derivative use subject */\r
-/* to acknowledgment of its origin and compliance with any conditions   */\r
-/* that the originators of the algorithm place on its exploitation.     */\r
-/*                                                                      */\r
-/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999     */\r
-/*                                                                      */\r
-/* My thanks go to Serge Vaudenay of the Ecole Normale Superieure       */\r
-/* for providing test vectors. This implementation has also been        */\r
-/* tested with an independent implementation by Dr Russell Bradford     */\r
-/* (Department of Mathematical Sciences, University of Bath, Bath,      */\r
-/* UK) and checks out.   My thanks go to Russell for his help in        */\r
-/* comparing our implementations and finding bugs (and for help in      */\r
-/* resolving 'endian' issues before test vectors became available).     */\r
-\r
-/* Timing data for DFC (dfc.c)\r
-\r
-Core timing without I/O endian conversion:\r
-\r
-Algorithm: dfc (dfc.c)\r
-\r
-128 bit key:\r
-Key Setup:    5222 cycles\r
-Encrypt:      1203 cycles =    21.3 mbits/sec\r
-Decrypt:      1244 cycles =    20.6 mbits/sec\r
-Mean:         1224 cycles =    20.9 mbits/sec\r
-\r
-192 bit key:\r
-Key Setup:    5203 cycles\r
-Encrypt:      1288 cycles =    19.9 mbits/sec\r
-Decrypt:      1235 cycles =    20.7 mbits/sec\r
-Mean:         1262 cycles =    20.3 mbits/sec\r
-\r
-256 bit key:\r
-Key Setup:    5177 cycles\r
-Encrypt:      1178 cycles =    21.7 mbits/sec\r
-Decrypt:      1226 cycles =    20.9 mbits/sec\r
-Mean:         1202 cycles =    21.3 mbits/sec\r
-\r
-Full timing with I/O endian conversion:\r
-\r
-128 bit key:\r
-Key Setup:    5227 cycles\r
-Encrypt:      1247 cycles =    20.5 mbits/sec\r
-Decrypt:      1222 cycles =    20.9 mbits/sec\r
-Mean:         1235 cycles =    20.7 mbits/sec\r
-\r
-192 bit key:\r
-Key Setup:    5252 cycles\r
-Encrypt:      1215 cycles =    21.1 mbits/sec\r
-Decrypt:      1265 cycles =    20.2 mbits/sec\r
-Mean:         1240 cycles =    20.6 mbits/sec\r
-\r
-256 bit key:\r
-Key Setup:    5174 cycles\r
-Encrypt:      1247 cycles =    20.5 mbits/sec\r
-Decrypt:      1206 cycles =    21.2 mbits/sec\r
-Mean:         1227 cycles =    20.9 mbits/sec\r
-\r
-*/\r
-\r
-/* The EES string is as follows (the abstract contains an error in \r
-   the last line of this sequence which changes KC and KD):\r
-\r
-    0xb7e15162, 0x8aed2a6a, 0xbf715880, 0x9cf4f3c7, \r
-    0x62e7160f, 0x38b4da56, 0xa784d904, 0x5190cfef, \r
-    0x324e7738, 0x926cfbe5, 0xf4bf8d8d, 0x8c31d763,\r
-    0xda06c80a, 0xbb1185eb, 0x4f7c7b57, 0x57f59584, \r
-\r
-    0x90cfd47d, 0x7c19bb42, 0x158d9554, 0xf7b46bce, \r
-    0xd55c4d79, 0xfd5f24d6, 0x613c31c3, 0x839a2ddf,\r
-    0x8a9a276b, 0xcfbfa1c8, 0x77c56284, 0xdab79cd4, \r
-    0xc2b3293d, 0x20e9e5ea, 0xf02ac60a, 0xcc93ed87, \r
-\r
-    0x4422a52e, 0xcb238fee, 0xe5ab6add, 0x835fd1a0,\r
-    0x753d0a8f, 0x78e537d2, 0xb95bb79d, 0x8dcaec64, \r
-    0x2c1e9f23, 0xb829b5c2, 0x780bf387, 0x37df8bb3, \r
-    0x00d01334, 0xa0d0bd86, 0x45cbfa73, 0xa6160ffe,\r
-\r
-    0x393c48cb, 0xbbca060f, 0x0ff8ec6d, 0x31beb5cc, \r
-    0xeed7f2f0, 0xbb088017, 0x163bc60d, 0xf45a0ecb, \r
-    0x1bcd289b, 0x06cbbfea, 0x21ad08e1, 0x847f3f73,\r
-    0x78d56ced, 0x94640d6e, 0xf0d3d37b, 0xe67008e1, \r
-    \r
-    0x86d1bf27, 0x5b9b241d, 0xeb64749a, 0x47dfdfb9, \r
-\r
-    Where:\r
-\r
-    EES = RT(0) | RT(1) | ... | RT(63) | KD | KC\r
-\r
-    Note that the abstract describing DFC is written \r
-    in big endian notation with the most significant \r
-    digits of a sequence of digits placed at the low\r
-    index positions in arrays. This format is used\r
-    here and is only converted to machine format at\r
-    the point that maths is done on any numbers in \r
-    the round function.\r
-    \r
-    The key input is thus treated as an array of 32 \r
-    bit words numbered from 0..3, 0..5 or 0..7 \r
-    depending on key length.  The first (leftmost) \r
-    bit of this key string as defined in the DFC \r
-    abstract is the most significant bit of word 0 \r
-    and the rightmost bit of this string is the least \r
-    signicant bit of the highest numbered key word.\r
-\r
-    The input and output blocks for the cipher are \r
-    also treated as arrays of 32 bit words numbered\r
-    from 0..3.  The most significant bit of word 0 is\r
-    the 1st (leftmost) bit of the 128 bit input string \r
-    and the least significant bit of word 3 is the \r
-    last (rightmost) bit.\r
-    \r
-    Note that the inputs, the output and the key are\r
-    in Intel little endian format when BYTE_SWAP is \r
-    defined\r
-*/\r
-\r
-#include <stdio.h>\r
-#include <sys/types.h>\r
-#include "dfc_internal.h"\r
-\r
-/* The following arrays are all stored in big endian    */\r
-/* format with 32 bit words at lower array positions    */\r
-/* being more significant in multi-word values          */\r
-\r
-u4byte rt64[64] = \r
-{\r
-    0xb7e15162, 0x8aed2a6a, 0xbf715880, 0x9cf4f3c7, \r
-    0x62e7160f, 0x38b4da56, 0xa784d904, 0x5190cfef, \r
-    0x324e7738, 0x926cfbe5, 0xf4bf8d8d, 0x8c31d763,\r
-    0xda06c80a, 0xbb1185eb, 0x4f7c7b57, 0x57f59584, \r
-\r
-    0x90cfd47d, 0x7c19bb42, 0x158d9554, 0xf7b46bce, \r
-    0xd55c4d79, 0xfd5f24d6, 0x613c31c3, 0x839a2ddf,\r
-    0x8a9a276b, 0xcfbfa1c8, 0x77c56284, 0xdab79cd4, \r
-    0xc2b3293d, 0x20e9e5ea, 0xf02ac60a, 0xcc93ed87, \r
-\r
-    0x4422a52e, 0xcb238fee, 0xe5ab6add, 0x835fd1a0,\r
-    0x753d0a8f, 0x78e537d2, 0xb95bb79d, 0x8dcaec64, \r
-    0x2c1e9f23, 0xb829b5c2, 0x780bf387, 0x37df8bb3, \r
-    0x00d01334, 0xa0d0bd86, 0x45cbfa73, 0xa6160ffe,\r
-\r
-    0x393c48cb, 0xbbca060f, 0x0ff8ec6d, 0x31beb5cc, \r
-    0xeed7f2f0, 0xbb088017, 0x163bc60d, 0xf45a0ecb, \r
-    0x1bcd289b, 0x06cbbfea, 0x21ad08e1, 0x847f3f73,\r
-    0x78d56ced, 0x94640d6e, 0xf0d3d37b, 0xe67008e1, \r
-};\r
-\r
-u4byte  kc = 0xeb64749a;\r
-\r
-u4byte  kd2[2] = \r
-{\r
-    0x86d1bf27, 0x5b9b241d  \r
-};\r
-\r
-u4byte  ka2[6] = \r
-{\r
-    0xb7e15162, 0x8aed2a6a, \r
-    0xbf715880, 0x9cf4f3c7, \r
-    0x62e7160f, 0x38b4da56, \r
-};\r
-\r
-u4byte  kb2[6] =\r
-{\r
-    0xa784d904, 0x5190cfef, \r
-    0x324e7738, 0x926cfbe5, \r
-    0xf4bf8d8d, 0x8c31d763,\r
-};\r
-\r
-u4byte  ks8[8] = \r
-{   0xda06c80a, 0xbb1185eb, 0x4f7c7b57, 0x57f59584, \r
-    0x90cfd47d, 0x7c19bb42, 0x158d9554, 0xf7b46bce,\r
-};\r
-\r
-#define lo(x)   ((x) & 0x0000ffff)\r
-#define hi(x)   ((x) >> 16)\r
-\r
-#define mult_64(r,x,y)                                          \\r
-    x0 = lo(x[1]); x1 = hi(x[1]); x2 = lo(x[0]); x3 = hi(x[0]); \\r
-    y0 = lo(y[1]); y1 = hi(y[1]); y2 = lo(y[0]); y3 = hi(y[0]); \\r
-    t0 = x0 * y0; r[0] = lo(t0); c = hi(t0);                    \\r
-    t0 = x0 * y1; t1 = x1 * y0; c += lo(t0) + lo(t1);           \\r
-    r[0] += (c << 16); c = hi(c) + hi(t0) + hi(t1);             \\r
-    t0 = x0 * y2; t1 = x1 * y1; t2 = x2 * y0;                   \\r
-    c += lo(t0) + lo(t1) + lo(t2); r[1] = lo(c);                \\r
-    c = hi(c) + hi(t0) + hi(t1) + hi(t2);                       \\r
-    t0 = x0 * y3; t1 = x1 * y2; t2 = x2 * y1; t3 = x3 * y0;     \\r
-    c += lo(t0) + lo(t1) + lo(t2) + lo(t3); r[1] += (c << 16);  \\r
-    c = hi(c) + hi(t0) + hi(t1) + hi(t2) + hi(t3);              \\r
-    t0 = x1 * y3; t1 = x2 * y2; t2 = x3 * y1;                   \\r
-    c += lo(t0) + lo(t1) + lo(t2); r[2] = lo(c);                \\r
-    c = hi(c) + hi(t0) + hi(t1) + hi(t2);                       \\r
-    t0 = x2 * y3; t1 = x3 * y2; c += lo(t0) + lo(t1);           \\r
-    r[2] += (c << 16); c = hi(c) + hi(t0) + hi(t1);             \\r
-    r[3] = c + x3 * y3\r
-\r
-#define add_64(r,hi,lo)     \\r
-    if((r[0] += lo) < lo)   \\r
-        if(!++r[1])         \\r
-            if(!++r[2])     \\r
-                ++r[3];     \\r
-    if((r[1] += hi) < hi)   \\r
-        if(!++r[2])         \\r
-            ++r[3]\r
-    \r
-#define mult_13(r)                  \\r
-    c = 13 * lo((r)[0]);            \\r
-    d = hi((r)[0]);                 \\r
-    (r)[0] = lo(c);                 \\r
-    c = hi(c) + 13 * d;             \\r
-    (r)[0] += (c << 16);            \\r
-    c = hi(c) + 13 * lo((r)[1]);    \\r
-    d = hi((r)[1]);                 \\r
-    (r)[1] = lo(c);                 \\r
-    c = hi(c) + 13 * d;             \\r
-    (r)[1] += (c << 16);            \\r
-    (r)[2] = hi(c)\r
-\r
-/* Where necessary this is where conversion from big endian to  */\r
-/* little endian format is performed.  Since all the maths is   */\r
-/* little endian care is needed when 64 bit blocks are being    */\r
-/* used to get them in the right order by reversing the order   */\r
-/* in which these are stored. This applies to the key array     */\r
-/* which gives the two values A and B and to the constant KD.   */\r
-/* Since the input and output blocks are big endian we also     */\r
-/* have to invert the order of the 32 bit words in the 64 bit   */\r
-/* blocks being processed.                                      */ \r
-\r
-void r_fun(u4byte outp[2], const u4byte inp[2], const u4byte key[4])\r
-{   u4byte  acc[5], x0, x1, x2, x3, y0, y1, y2, y3, t0, t1, t2, t3, c, d;\r
-\r
-    mult_64(acc, inp, key);  add_64(acc, key[2], key[3]);\r
-\r
-    /* we need the value in the accumulator mod 2^64 + 13 so if */\r
-    /* the accumulator value is hi * 2^64 + lo we need to find  */\r
-    /* a k value such that r = hi * 2^64 + lo - k * (2^64 + 13) */\r
-    /* is 0 <= r < 2^64 + 13.  We can see that k will be close  */\r
-    /* to hi in value - it may equal hi but will not be greater */\r
-    /* and we can let k = hi - e with e >= 0 so that r is given */\r
-    /* by r = e * (2^64 + 13) + lo - 13 * hi. If we compute the */\r
-    /* lo - 13 * hi value, the overflow into the top 64 bits of */\r
-    /* the accumulator has to be 'zeroed' by the e * (2^64 + 13)*/\r
-    /* term and this sets the e value (in fact such an overlow  */\r
-    /* is only removed when the lower word is higher than 12).  */\r
-\r
-    mult_13(acc + 2);   /* multiply top of accumulator by 13    */\r
-\r
-    /* calculate lo - 13 * hi in acc[0] and acc[1] with any     */\r
-    /* overflow into top 64 bits in c                           */\r
-\r
-    d = acc[0]; acc[0] -= acc[2]; c = (acc[0] > d ? 1 : 0);\r
-\r
-    d = acc[1]; acc[1] -= acc[3] + c;\r
-    c = (acc[1] > d ? 1 : (acc[1] == d ? c : 0));\r
-\r
-    c = 13 * (acc[4] + c);  /* overflow into top 64 bits of acc */\r
-\r
-    if(((acc[0] += c) < c) && !(++acc[1]))\r
-    {\r
-        if(acc[0] > 12)\r
-\r
-            acc[0] -= 13;\r
-    }\r
-\r
-    /* do the confusion permutation */\r
-\r
-    d = acc[1] ^ kc; c = acc[0] ^ rt64[acc[1] >> 26];  \r
-    \r
-    c += kd2[0] + ((d += kd2[1]) < kd2[1] ? 1 : 0);\r
-\r
-    outp[0] ^= c; outp[1] ^= d; \r
-};\r
-\r
-u4byte *dfc_set_key(DfcContext *ctx,\r
-                   const u4byte in_key[], const u4byte key_len)\r
-{   \r
-    u4byte  i, lk[32], rk[4];\r
-    u4byte *l_key = ctx->l_key;\r
-\r
-    for(i = 0; i < key_len / 32; ++i)\r
-\r
-        lk[i] = io_swap(in_key[i]);\r
-\r
-    /* pad the key with the KS array            */\r
-\r
-    for(i = 0; i < 8 - key_len / 32; ++i)    /* K|KS */\r
-\r
-        lk[i + key_len / 32] = ks8[i];\r
-\r
-    /* do the reordering of the key parameters  */\r
-    /* the OAP[1]|OBP[1]|OAP[2]... sequence is  */\r
-    /* at lk[0]... and the other at lk[16]...   */\r
-    \r
-    lk[18] = lk[5]; lk[19] = lk[2]; /* EBP */ \r
-    lk[16] = lk[1]; lk[17] = lk[6]; /* EAP */\r
-    lk[ 2] = lk[4]; lk[ 3] = lk[3]; /* OBP */\r
-    lk[ 0] = lk[0]; lk[ 1] = lk[7]; /* OAP */\r
-\r
-    /* create other elements using KA and KB    */\r
-\r
-    for(i = 0; i < 6; i += 2)\r
-    {\r
-        lk[i + i +   4] = lk[ 0] ^ ka2[i];      /* OAP[i] ms */\r
-        lk[i + i +   5] = lk[ 1] ^ ka2[i + 1];  /* OAP[i] ls */\r
-        lk[i + i +   6] = lk[ 2] ^ kb2[i];      /* OBP[i] ms */\r
-        lk[i + i +   7] = lk[ 3] ^ kb2[i + 1];  /* OBP[i] ls */\r
-        lk[i + i +  20] = lk[16] ^ ka2[i];      /* EAP[i] ms */\r
-        lk[i + i +  21] = lk[17] ^ ka2[i + 1];  /* EAP[i] ls */\r
-        lk[i + i +  22] = lk[18] ^ kb2[i];      /* EBP[i] ms */\r
-        lk[i + i +  23] = lk[19] ^ kb2[i + 1];  /* EBP[i] ls */\r
-    }\r
-\r
-    rk[0] = rk[1] = rk[2] = rk[3] = 0;\r
-\r
-    /* do the 4 round key mixing encryption     */\r
-\r
-    for(i = 0; i < 32; i += 8)\r
-    {\r
-        r_fun(rk, rk + 2, lk);      /*  R2|R1   */\r
-        r_fun(rk + 2, rk, lk +  4); /*  R2|R3   */\r
-        r_fun(rk, rk + 2, lk +  8); /*  R4|R3   */\r
-        r_fun(rk + 2, rk, lk + 12); /*  R4|R5   */\r
-\r
-        /* keep key in big endian format with   */\r
-        /* the most significant 32 bit words    */\r
-        /* first (lowest) in the key schedule   */\r
-        /* - note that the upper and lower 64   */\r
-        /* bit blocks are in inverse order at   */\r
-        /* this point in the loop               */\r
-\r
-        l_key[i + 0] = rk[2]; l_key[i + 1] = rk[3]; \r
-        l_key[i + 2] = rk[0]; l_key[i + 3] = rk[1]; \r
-\r
-        r_fun(rk + 2, rk, lk + 16); /*  R1|R2   */\r
-        r_fun(rk, rk + 2, lk + 20); /*  R3|R2   */\r
-        r_fun(rk + 2, rk, lk + 24); /*  R3|R4   */  \r
-        r_fun(rk, rk + 2, lk + 28); /*  R5|R4   */\r
-\r
-        l_key[i + 4] = rk[0]; l_key[i + 5] = rk[1]; \r
-        l_key[i + 6] = rk[2]; l_key[i + 7] = rk[3];\r
-    }\r
-    \r
-    return l_key;\r
-};\r
-\r
-void dfc_encrypt(DfcContext *ctx,\r
-                const u4byte in_blk[4], u4byte out_blk[4])\r
-{   \r
-    u4byte  blk[4];\r
-    u4byte *l_key = ctx->l_key;\r
-\r
-    /* the input/output format is big endian -  */\r
-    /* any reversals needed are performed when  */\r
-    /* maths is done in the round function      */\r
-\r
-    blk[0] = io_swap(in_blk[0]); blk[1] = io_swap(in_blk[1]);\r
-    blk[2] = io_swap(in_blk[2]); blk[3] = io_swap(in_blk[3]);\r
-\r
-    r_fun(blk, blk + 2, l_key +  0); /*  R2|R1  */ \r
-    r_fun(blk + 2, blk, l_key +  4); /*  R2|R3  */\r
-    r_fun(blk, blk + 2, l_key +  8); /*  R4|R3  */\r
-    r_fun(blk + 2, blk, l_key + 12); /*  R4|R5  */\r
-    r_fun(blk, blk + 2, l_key + 16); /*  R6|R5  */\r
-    r_fun(blk + 2, blk, l_key + 20); /*  R6|R7  */\r
-    r_fun(blk, blk + 2, l_key + 24); /*  R8|R7  */\r
-    r_fun(blk + 2, blk, l_key + 28); /*  R8|R9  */\r
-\r
-    /* swap order to obtain the result R9|R8    */\r
-\r
-    out_blk[0] = io_swap(blk[2]); out_blk[1] = io_swap(blk[3]);\r
-    out_blk[2] = io_swap(blk[0]); out_blk[3] = io_swap(blk[1]);\r
-};\r
-\r
-void dfc_decrypt(DfcContext *ctx,\r
-                const u4byte in_blk[4], u4byte out_blk[4])\r
-{   \r
-    u4byte  blk[4];\r
-    u4byte *l_key = ctx->l_key;\r
-\r
-    /* the input/output format is big endian -  */\r
-    /* any reversals needed are performed when  */\r
-    /* maths is done in the round function      */\r
-\r
-    blk[0] = io_swap(in_blk[0]); blk[1] = io_swap(in_blk[1]);\r
-    blk[2] = io_swap(in_blk[2]); blk[3] = io_swap(in_blk[3]);\r
-\r
-    r_fun(blk, blk + 2, l_key + 28); /*  R7|R8  */\r
-    r_fun(blk + 2, blk, l_key + 24); /*  R7|R6  */\r
-    r_fun(blk, blk + 2, l_key + 20); /*  R5|R6  */\r
-    r_fun(blk + 2, blk, l_key + 16); /*  R5|R4  */\r
-    r_fun(blk, blk + 2, l_key + 12); /*  R3|R4  */\r
-    r_fun(blk + 2, blk, l_key +  8); /*  R3|R2  */\r
-    r_fun(blk, blk + 2, l_key +  4); /*  R1|R2  */\r
-    r_fun(blk + 2, blk, l_key     ); /*  R1|R0  */ \r
-\r
-    /* swap order to obtain the result R1|R0    */\r
-\r
-    out_blk[0] = io_swap(blk[2]); out_blk[1] = io_swap(blk[3]);\r
-    out_blk[2] = io_swap(blk[0]); out_blk[3] = io_swap(blk[1]);   \r
-};\r
diff --git a/lib/silccrypt/dfc.h b/lib/silccrypt/dfc.h
deleted file mode 100644 (file)
index 15be620..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
-
-  dfc.h
-
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
-
-  Copyright (C) 1997 - 2000 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
-  GNU General Public License for more details.
-
-*/
-/*
- * $Id$
- * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:54  priikone
- *     Importet from internal CVS/Added Log headers.
- *
- *
- */
-
-#ifndef DFC_H
-#define DFC_H
-
-#include "dfc_internal.h"
-
-/* 
- * SILC Crypto API for DFC
- */
-
-/* Sets the key for the cipher. */
-
-inline int silc_dfc_init(void *context, 
-                        const unsigned char *key, 
-                        unsigned int keylen)
-{
-  dfc_set_key((DfcContext *)context, (unsigned int *)key, keylen);
-  return 1;
-}
-
-/* Sets the string as a new key for the cipher. The string is first
-   hashed and then used as a new key. */
-
-inline int silc_dfc_set_string_as_key(void *context, 
-                                     const unsigned char *string,
-                                     unsigned int keylen)
-{
-  /*  SilcHash hash;
-  unsigned char key[16];
-
-  silc_hash_alloc("md5", &hash);
-  hash->make_hash(hash, string, stringlen, key);
-
-  dfc_set_key((DfcContext *)context, key, sizeof(key));
-
-  silc_hash_free(hash);
-  memset(&key, 'F', sizeof(key));
-  */
-  return TRUE;
-}
-
-/* Returns the size of the cipher context. */
-
-inline unsigned int silc_dfc_context_len()
-{
-  return sizeof(DfcContext);
-}
-
-/* Encrypts with the cipher in CBC mode. */
-
-inline int silc_dfc_encrypt_cbc(void *context,
-                               const unsigned char *src,
-                               unsigned char *dst,
-                               unsigned int len,
-                               unsigned char *iv)
-{
-  unsigned int *in, *out, *tiv;
-  unsigned int tmp[4];
-  int i;
-
-  in = (unsigned int *)src;
-  out = (unsigned int *)dst;
-  tiv = (unsigned int *)iv;
-
-  tmp[0] = in[0] ^ tiv[0];
-  tmp[1] = in[1] ^ tiv[1];
-  tmp[2] = in[2] ^ tiv[2];
-  tmp[3] = in[3] ^ tiv[3];
-  dfc_encrypt((DfcContext *)context, tmp, out);
-  in += 4;
-  out += 4;
-
-  for (i = 16; i < len; i += 16) {
-    tmp[0] = in[0] ^ out[0 - 4];
-    tmp[1] = in[1] ^ out[1 - 4];
-    tmp[2] = in[2] ^ out[2 - 4];
-    tmp[3] = in[3] ^ out[3 - 4];
-    dfc_encrypt((DfcContext *)context, tmp, out);
-    in += 4;
-    out += 4;
-  }
-
-  return 1;
-}
-
-/* Decrypts with the cipher in CBC mode. */
-
-inline int silc_dfc_decrypt_cbc(void *context,
-                               const unsigned char *src,
-                               unsigned char *dst,
-                               unsigned int len,
-                               unsigned char *iv)
-{
-  unsigned int *in, *out, *tiv;
-  int i;
-
-  in = (unsigned int *)src;
-  out = (unsigned int *)dst;
-  tiv = (unsigned int *)iv;
-
-  dfc_decrypt((DfcContext *)context, in, out);
-  out[0] ^= tiv[0];
-  out[1] ^= tiv[1];
-  out[2] ^= tiv[2];
-  out[3] ^= tiv[3];
-  in += 4;
-  out += 4;
-
-  for (i = 16; i < len; i += 16) {
-    dfc_decrypt((DfcContext *)context, in, out);
-    out[0] ^= in[0 - 4];
-    out[1] ^= in[1 - 4];
-    out[2] ^= in[2 - 4];
-    out[3] ^= in[3 - 4];
-    in += 4;
-    out += 4;
-  }
-
-  return 1;
-}
-
-#endif
diff --git a/lib/silccrypt/e2.c b/lib/silccrypt/e2.c
deleted file mode 100644 (file)
index 8cc8acd..0000000
+++ /dev/null
@@ -1,378 +0,0 @@
-/* Modified for SILC. -Pekka */\r
-\r
-/* This is an independent implementation of the encryption algorithm:   */\r
-/*                                                                      */\r
-/*         E2 by Nippon Telegraph and Telephone (NTT) Japan             */\r
-/*                                                                      */\r
-/* which is a candidate algorithm in the Advanced Encryption Standard   */\r
-/* programme of the US National Institute of Standards and Technology.  */\r
-/*                                                                      */\r
-/* Copyright in this implementation is held by Dr B R Gladman but I     */\r
-/* hereby give permission for its free direct or derivative use subject */\r
-/* to acknowledgment of its origin and compliance with any conditions   */\r
-/* that the originators of the algorithm place on its exploitation.     */\r
-/*                                                                      */\r
-/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999     */\r
-/*                                                                      */\r
-/* In accordance with the wishes of NTT this implementation is made     */\r
-/* available for academic and study purposes only.   I gratefully       */\r
-/* acknowledge the contributions made by Kazumaro Aoki of NTT Japan     */\r
-/* for ways to increase the speed of this implementation.               */\r
-\r
-/* Timing data for E2 (e28.c)\r
-\r
-Core timing without I/O endian conversion:\r
-\r
-128 bit key:\r
-Key Setup:    9473 cycles\r
-Encrypt:       687 cycles =    37.3 mbits/sec\r
-Decrypt:       691 cycles =    37.0 mbits/sec\r
-Mean:          689 cycles =    37.2 mbits/sec\r
-\r
-192 bit key:\r
-Key Setup:    9540 cycles\r
-Encrypt:       696 cycles =    36.8 mbits/sec\r
-Decrypt:       693 cycles =    36.9 mbits/sec\r
-Mean:          695 cycles =    36.9 mbits/sec\r
-\r
-256 bit key:\r
-Key Setup:    9913 cycles\r
-Encrypt:       691 cycles =    37.0 mbits/sec\r
-Decrypt:       706 cycles =    36.3 mbits/sec\r
-Mean:          699 cycles =    36.6 mbits/sec\r
-\r
-Full timing with I/O endian conversion:\r
-\r
-128 bit key:\r
-Key Setup:    9598 cycles\r
-Encrypt:       730 cycles =    35.1 mbits/sec\r
-Decrypt:       723 cycles =    35.4 mbits/sec\r
-Mean:          727 cycles =    35.2 mbits/sec\r
-\r
-192 bit key:\r
-Key Setup:    9393 cycles\r
-Encrypt:       730 cycles =    35.1 mbits/sec\r
-Decrypt:       720 cycles =    35.6 mbits/sec\r
-Mean:          725 cycles =    35.3 mbits/sec\r
-\r
-256 bit key:\r
-Key Setup:    9720 cycles\r
-Encrypt:       727 cycles =    35.2 mbits/sec\r
-Decrypt:       721 cycles =    35.5 mbits/sec\r
-Mean:          724 cycles =    35.4 mbits/sec\r
-\r
-*/\r
-\r
-#include <stdio.h>\r
-#include <sys/types.h>\r
-#include "e2_internal.h"\r
-\r
-u1byte  s_box[] =\r
-{\r
- 0xe1, 0x42, 0x3e, 0x81, 0x4e, 0x17, 0x9e, 0xfd, 0xb4, 0x3f, 0x2c, 0xda,\r
- 0x31, 0x1e, 0xe0, 0x41, 0xcc, 0xf3, 0x82, 0x7d, 0x7c, 0x12, 0x8e, 0xbb,\r
- 0xe4, 0x58, 0x15, 0xd5, 0x6f, 0xe9, 0x4c, 0x4b, 0x35, 0x7b, 0x5a, 0x9a,\r
- 0x90, 0x45, 0xbc, 0xf8, 0x79, 0xd6, 0x1b, 0x88, 0x02, 0xab, 0xcf, 0x64,\r
- 0x09, 0x0c, 0xf0, 0x01, 0xa4, 0xb0, 0xf6, 0x93, 0x43, 0x63, 0x86, 0xdc,\r
- 0x11, 0xa5, 0x83, 0x8b, 0xc9, 0xd0, 0x19, 0x95, 0x6a, 0xa1, 0x5c, 0x24,\r
- 0x6e, 0x50, 0x21, 0x80, 0x2f, 0xe7, 0x53, 0x0f, 0x91, 0x22, 0x04, 0xed,\r
- 0xa6, 0x48, 0x49, 0x67, 0xec, 0xf7, 0xc0, 0x39, 0xce, 0xf2, 0x2d, 0xbe,\r
- 0x5d, 0x1c, 0xe3, 0x87, 0x07, 0x0d, 0x7a, 0xf4, 0xfb, 0x32, 0xf5, 0x8c,\r
- 0xdb, 0x8f, 0x25, 0x96, 0xa8, 0xea, 0xcd, 0x33, 0x65, 0x54, 0x06, 0x8d,\r
- 0x89, 0x0a, 0x5e, 0xd9, 0x16, 0x0e, 0x71, 0x6c, 0x0b, 0xff, 0x60, 0xd2,\r
- 0x2e, 0xd3, 0xc8, 0x55, 0xc2, 0x23, 0xb7, 0x74, 0xe2, 0x9b, 0xdf, 0x77,\r
- 0x2b, 0xb9, 0x3c, 0x62, 0x13, 0xe5, 0x94, 0x34, 0xb1, 0x27, 0x84, 0x9f,\r
- 0xd7, 0x51, 0x00, 0x61, 0xad, 0x85, 0x73, 0x03, 0x08, 0x40, 0xef, 0x68,\r
- 0xfe, 0x97, 0x1f, 0xde, 0xaf, 0x66, 0xe8, 0xb8, 0xae, 0xbd, 0xb3, 0xeb,\r
- 0xc6, 0x6b, 0x47, 0xa9, 0xd8, 0xa7, 0x72, 0xee, 0x1d, 0x7e, 0xaa, 0xb6,\r
- 0x75, 0xcb, 0xd4, 0x30, 0x69, 0x20, 0x7f, 0x37, 0x5b, 0x9d, 0x78, 0xa3,\r
- 0xf1, 0x76, 0xfa, 0x05, 0x3d, 0x3a, 0x44, 0x57, 0x3b, 0xca, 0xc7, 0x8a,\r
- 0x18, 0x46, 0x9c, 0xbf, 0xba, 0x38, 0x56, 0x1a, 0x92, 0x4d, 0x26, 0x29,\r
- 0xa2, 0x98, 0x10, 0x99, 0x70, 0xa0, 0xc5, 0x28, 0xc1, 0x6d, 0x14, 0xac,\r
- 0xf9, 0x5f, 0x4f, 0xc4, 0xc3, 0xd1, 0xfc, 0xdd, 0xb2, 0x59, 0xe6, 0xb5,\r
- 0x36, 0x52, 0x4a, 0x2a\r
-};\r
-\r
-u4byte  l_box[4][256];\r
-u4byte  lb_init = 0;\r
-\r
-#define v_0     0x67452301\r
-#define v_1     0xefcdab89\r
-\r
-/* s_fun(s_fun(s_fun(v)))           */\r
-\r
-#define k2_0    0x30d32e58\r
-#define k2_1    0xb89e4984\r
-\r
-/* s_fun(s_fun(s_fun(s_fun(v))))    */\r
-\r
-#define k3_0    0x0957cfec\r
-#define k3_1    0xd800502e\r
-\r
-#define bp_fun(a,b,c,d,e,f,g,h)     \\r
-    u = (e ^ g) & 0x00ffff00;       \\r
-    v = (f ^ h) & 0x0000ffff;       \\r
-    a = e ^ u; c = g ^ u;           \\r
-    b = f ^ v; d = h ^ v\r
-\r
-#define ibp_fun(a,b,c,d,e,f,g,h)    \\r
-    u = (e ^ g) & 0xff0000ff;       \\r
-    v = (f ^ h) & 0xffff0000;       \\r
-    a = e ^ u; c = g ^ u;           \\r
-    b = f ^ v; d = h ^ v\r
-\r
-#define bp2_fun(x,y)                \\r
-    w = (x ^ y) & 0x00ff00ff;       \\r
-    x ^= w; y ^= w;                 \\r
-\r
-#define s_fun(x,y)          \\r
-    p = x; q = x >> 8;      \\r
-    r = y; s = y >> 8;      \\r
-    x  = l_box[0][r & 255]; \\r
-    y  = l_box[0][p & 255]; \\r
-    p >>=  16; r >>=  16;   \\r
-    x |= l_box[1][q & 255]; \\r
-    y |= l_box[1][s & 255]; \\r
-    x |= l_box[2][r & 255]; \\r
-    y |= l_box[2][p & 255]; \\r
-    x |= l_box[3][p >> 8];  \\r
-    y |= l_box[3][r >> 8]\r
-\r
-#define sx_fun(x,y)         \\r
-    p = x >>  8;            \\r
-    q = x >> 16;            \\r
-    x  = l_box[0][x & 255]; \\r
-    x |= l_box[1][p & 255]; \\r
-    x |= l_box[2][q & 255]; \\r
-    x |= l_box[3][q >> 8];  \\r
-    p = y >>  8;            \\r
-    q = y >> 16;            \\r
-    y  = l_box[0][y & 255]; \\r
-    y |= l_box[1][p & 255]; \\r
-    y |= l_box[2][q & 255]; \\r
-    y |= l_box[3][q >> 8]\r
-\r
-#define spx_fun(x,y)        \\r
-    sx_fun(x,y);            \\r
-    y ^= x;                 \\r
-    x ^= rotr(y, 16);       \\r
-    y ^= rotr(x, 8);        \\r
-    x ^= y\r
-\r
-#define sp_fun(x,y)         \\r
-    s_fun(x,y);             \\r
-    y ^= x;                 \\r
-    x ^= rotr(y, 16);       \\r
-    y ^= rotr(x, 8);        \\r
-    x ^= y\r
-\r
-#define sr_fun(x,y)         \\r
-    p = x; q = x >> 8;      \\r
-    r = y; s = y >> 8;      \\r
-    y  = l_box[1][p & 255]; \\r
-    x  = l_box[1][r & 255]; \\r
-    p >>= 16; r >>= 16;     \\r
-    x |= l_box[2][q & 255]; \\r
-    y |= l_box[2][s & 255]; \\r
-    y |= l_box[3][p & 255]; \\r
-    x |= l_box[3][r & 255]; \\r
-    x |= l_box[0][r >>  8]; \\r
-    y |= l_box[0][p >>  8]\r
-\r
-#define f_fun(a,b,c,d,k)            \\r
-    u = c ^ *(k); v = d ^ *(k + 1); \\r
-    sp_fun(u, v);                   \\r
-    u ^= *(k + 2); v ^= *(k + 3);   \\r
-    sr_fun(u, v);                   \\r
-    a ^= v;                         \\r
-    b ^= u\r
-\r
-#define byte_adr(x,n)   *(((u1byte*)&x)+n)\r
-\r
-u4byte  mod_inv(u4byte x)\r
-{   u4byte  y1, y2, a, b, q;\r
-\r
-    y1 = ~((-x) / x); y2 = 1;\r
-\r
-    a = x; b = y1 * x;\r
-\r
-    for(;;)\r
-    {\r
-        q = a / b; \r
-        \r
-        if((a -= q * b) == 0)\r
-\r
-            return (x * y1 == 1 ? y1 : -y1);\r
-        \r
-        y2 -= q * y1;\r
-\r
-        q = b / a; \r
-        \r
-        if((b -= q * a) == 0)\r
-        \r
-            return (x * y2 == 1 ? y2 : -y2);\r
-\r
-        y1 -= q * y2;\r
-    }\r
-};\r
-\r
-void g_fun(u4byte y[8], u4byte l[8], u4byte v[2])\r
-{   u4byte  p,q;\r
-\r
-    spx_fun(y[0], y[1]); spx_fun(v[0], v[1]); \r
-    l[0] = v[0] ^= y[0]; l[1] = v[1] ^= y[1];\r
-\r
-    spx_fun(y[2], y[3]); spx_fun(v[0], v[1]); \r
-    l[2] = v[0] ^= y[2]; l[3] = v[1] ^= y[3];\r
-\r
-    spx_fun(y[4], y[5]); spx_fun(v[0], v[1]);  \r
-    l[4] = v[0] ^= y[4]; l[5] = v[1] ^= y[5];\r
-\r
-    spx_fun(y[6], y[7]); spx_fun(v[0], v[1]); \r
-    l[6] = v[0] ^= y[6]; l[7] = v[1] ^= y[7];\r
-};\r
-\r
-u4byte *e2_set_key(E2Context *ctx,\r
-                  const u4byte in_key[], const u4byte key_len)\r
-{   \r
-    u4byte  lk[8], v[2], lout[8];\r
-    u4byte  i, j, k, w;\r
-    u4byte *l_key = ctx->l_key;\r
-\r
-    if(!lb_init)\r
-    {\r
-        for(i = 0; i < 256; ++i)\r
-        {\r
-            l_box[0][i] = ((u4byte)(s_box[i]));\r
-            l_box[1][i] = ((u4byte)(s_box[i])) <<  8;\r
-            l_box[2][i] = ((u4byte)(s_box[i])) << 16;\r
-            l_box[3][i] = ((u4byte)(s_box[i])) << 24;\r
-        }\r
-\r
-        lb_init = 1;\r
-    }\r
-\r
-    v[0] = bswap(v_0); v[1] = bswap(v_1);\r
-\r
-    lk[0] = io_swap(in_key[0]); lk[1] = io_swap(in_key[1]);\r
-    lk[2] = io_swap(in_key[2]); lk[3] = io_swap(in_key[3]);\r
-\r
-    lk[4] = io_swap(key_len > 128 ? in_key[4] : k2_0);\r
-    lk[5] = io_swap(key_len > 128 ? in_key[5] : k2_1);\r
-\r
-    lk[6] = io_swap(key_len > 192 ? in_key[6] : k3_0);\r
-    lk[7] = io_swap(key_len > 192 ? in_key[7] : k3_1);\r
-\r
-    g_fun(lk, lout, v);\r
-\r
-    for(i = 0; i < 8; ++i)\r
-    {\r
-        g_fun(lk, lout, v);\r
-\r
-        for(j = 0; j < 4; ++j)\r
-        {\r
-            // this is complex because of a byte swap in each 32 bit output word\r
-\r
-            k = 2 * (48 - 16 * j + 2 * (i / 2) - i % 2);\r
-\r
-            ((u1byte*)l_key)[k + 3]   = ((u1byte*)lout)[j];\r
-            ((u1byte*)l_key)[k + 2]   = ((u1byte*)lout)[j + 16];\r
-\r
-            ((u1byte*)l_key)[k + 19]  = ((u1byte*)lout)[j +  8];\r
-            ((u1byte*)l_key)[k + 18]  = ((u1byte*)lout)[j + 24];\r
-\r
-            ((u1byte*)l_key)[k + 131] = ((u1byte*)lout)[j +  4];\r
-            ((u1byte*)l_key)[k + 130] = ((u1byte*)lout)[j + 20];\r
-\r
-            ((u1byte*)l_key)[k + 147] = ((u1byte*)lout)[j + 12];\r
-            ((u1byte*)l_key)[k + 146] = ((u1byte*)lout)[j + 28];\r
-        }\r
-    }\r
-\r
-    for(i = 52; i < 60; ++i)\r
-    {\r
-        l_key[i] |= 1; l_key[i + 12] = mod_inv(l_key[i]);\r
-    }\r
-\r
-    for(i = 0; i < 48; i += 4)\r
-    {\r
-        bp2_fun(l_key[i], l_key[i + 1]);\r
-    }\r
-\r
-    return (u4byte*)&l_key;\r
-};\r
-\r
-void e2_encrypt(E2Context *ctx, const u4byte in_blk[4], u4byte out_blk[4])\r
-{   \r
-    u4byte      a,b,c,d,p,q,r,s,u,v;\r
-    u4byte *l_key = ctx->l_key;\r
-\r
-    p = io_swap(in_blk[0]); q = io_swap(in_blk[1]); \r
-    r = io_swap(in_blk[2]); s = io_swap(in_blk[3]);\r
-    \r
-    p ^= l_key[48]; q ^= l_key[49]; r ^= l_key[50]; s ^= l_key[51]; \r
-    p *= l_key[52]; q *= l_key[53]; r *= l_key[54]; s *= l_key[55];\r
-\r
-    bp_fun(a, b, c, d, p, q, r, s);\r
-\r
-    f_fun(a, b, c, d, l_key);\r
-    f_fun(c, d, a, b, l_key +  4);\r
-    f_fun(a, b, c, d, l_key +  8);\r
-    f_fun(c, d, a, b, l_key + 12);\r
-    f_fun(a, b, c, d, l_key + 16);\r
-    f_fun(c, d, a, b, l_key + 20);\r
-    f_fun(a, b, c, d, l_key + 24);\r
-    f_fun(c, d, a, b, l_key + 28);\r
-    f_fun(a, b, c, d, l_key + 32);\r
-    f_fun(c, d, a, b, l_key + 36);\r
-    f_fun(a, b, c, d, l_key + 40);\r
-    f_fun(c, d, a, b, l_key + 44);\r
-\r
-    ibp_fun(p, q, r, s, a, b, c, d);        \r
-    \r
-    p *= l_key[68]; q *= l_key[69]; r *= l_key[70]; s *= l_key[71]; \r
-    p ^= l_key[60]; q ^= l_key[61]; r ^= l_key[62]; s ^= l_key[63];\r
-    \r
-    out_blk[0] = io_swap(p); out_blk[1] = io_swap(q);\r
-    out_blk[2] = io_swap(r); out_blk[3] = io_swap(s);\r
-};\r
-\r
-void e2_decrypt(E2Context *ctx, const u4byte in_blk[4], u4byte out_blk[4])\r
-{   \r
-    u4byte      a,b,c,d,p,q,r,s,u,v;\r
-    u4byte *l_key = ctx->l_key;\r
-\r
-    p = io_swap(in_blk[0]); q = io_swap(in_blk[1]); \r
-    r = io_swap(in_blk[2]); s = io_swap(in_blk[3]);\r
-\r
-    p ^= l_key[60]; q ^= l_key[61]; r ^= l_key[62]; s ^= l_key[63];\r
-    p *= l_key[56]; q *= l_key[57]; r *= l_key[58]; s *= l_key[59];\r
-\r
-    bp_fun(a, b, c, d, p, q, r, s);\r
-\r
-    f_fun(a, b, c, d, l_key + 44);\r
-    f_fun(c, d, a, b, l_key + 40);\r
-\r
-    f_fun(a, b, c, d, l_key + 36);\r
-    f_fun(c, d, a, b, l_key + 32);\r
-\r
-    f_fun(a, b, c, d, l_key + 28);\r
-    f_fun(c, d, a, b, l_key + 24);\r
-    \r
-    f_fun(a, b, c, d, l_key + 20);\r
-    f_fun(c, d, a, b, l_key + 16);\r
-\r
-    f_fun(a, b, c, d, l_key + 12);\r
-    f_fun(c, d, a, b, l_key +  8);\r
-    \r
-    f_fun(a, b, c, d, l_key +  4);\r
-    f_fun(c, d, a, b, l_key);\r
-\r
-    ibp_fun(p, q, r, s, a, b, c, d);        \r
-    \r
-    p *= l_key[64]; q *= l_key[65]; r *= l_key[66]; s *= l_key[67]; \r
-    p ^= l_key[48]; q ^= l_key[49]; r ^= l_key[50]; s ^= l_key[51];\r
-\r
-    out_blk[0] = io_swap(p); out_blk[1] = io_swap(q); \r
-    out_blk[2] = io_swap(r); out_blk[3] = io_swap(s);\r
-};\r
diff --git a/lib/silccrypt/e2.h b/lib/silccrypt/e2.h
deleted file mode 100644 (file)
index 600fafe..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
-
-  e2.h
-
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
-
-  Copyright (C) 1997 - 2000 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
-  GNU General Public License for more details.
-
-*/
-/*
- * $Id$
- * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:54  priikone
- *     Importet from internal CVS/Added Log headers.
- *
- *
- */
-
-#ifndef E2_H
-#define E2_H
-
-#include "e2_internal.h"
-
-/* 
- * SILC Crypto API for E2
- */
-
-/* Sets the key for the cipher. */
-
-inline int silc_e2_init(void *context, 
-                       const unsigned char *key, 
-                       size_t keylen)
-{
-  e2_set_key((E2Context *)context, (unsigned int *)key, keylen);
-  return 1;
-}
-
-/* Sets the string as a new key for the cipher. The string is first
-   hashed and then used as a new key. */
-
-inline int silc_e2_set_string_as_key(void *context, 
-                                    const unsigned char *string,
-                                    size_t keylen)
-{
-  /*  unsigned char key[md5_hash_len];
-  SilcMarsContext *ctx = (SilcMarsContext *)context;
-
-  make_md5_hash(string, &key);
-  memcpy(&ctx->key, mars_set_key(&key, keylen), keylen);
-  memset(&key, 'F', sizeoof(key));
-  */
-
-  return 1;
-}
-
-/* Returns the size of the cipher context. */
-
-inline size_t silc_e2_context_len()
-{
-  return sizeof(E2Context);
-}
-
-/* Encrypts with the cipher in CBC mode. */
-
-inline int silc_e2_encrypt_cbc(void *context,
-                              const unsigned char *src,
-                              unsigned char *dst,
-                              size_t len,
-                              unsigned char *iv)
-{
-  unsigned int *in, *out, *tiv;
-  unsigned int tmp[4];
-  int i;
-
-  in = (unsigned int *)src;
-  out = (unsigned int *)dst;
-  tiv = (unsigned int *)iv;
-
-  tmp[0] = in[0] ^ tiv[0];
-  tmp[1] = in[1] ^ tiv[1];
-  tmp[2] = in[2] ^ tiv[2];
-  tmp[3] = in[3] ^ tiv[3];
-  e2_encrypt((E2Context *)context, tmp, out);
-  in += 4;
-  out += 4;
-
-  for (i = 16; i < len; i += 16) {
-    tmp[0] = in[0] ^ out[0 - 4];
-    tmp[1] = in[1] ^ out[1 - 4];
-    tmp[2] = in[2] ^ out[2 - 4];
-    tmp[3] = in[3] ^ out[3 - 4];
-    e2_encrypt((E2Context *)context, tmp, out);
-    in += 4;
-    out += 4;
-  }
-
-  return 1;
-}
-
-/* Decrypts with the cipher in CBC mode. */
-
-inline int silc_e2_decrypt_cbc(void *context,
-                              const unsigned char *src,
-                              unsigned char *dst,
-                              size_t len,
-                              unsigned char *iv)
-{
-  unsigned int *in, *out, *tiv;
-  int i;
-
-  in = (unsigned int *)src;
-  out = (unsigned int *)dst;
-  tiv = (unsigned int *)iv;
-
-  e2_decrypt((E2Context *)context, in, out);
-  out[0] ^= tiv[0];
-  out[1] ^= tiv[1];
-  out[2] ^= tiv[2];
-  out[3] ^= tiv[3];
-  in += 4;
-  out += 4;
-
-  for (i = 16; i < len; i += 16) {
-    e2_decrypt((E2Context *)context, in, out);
-    out[0] ^= in[0 - 4];
-    out[1] ^= in[1 - 4];
-    out[2] ^= in[2 - 4];
-    out[3] ^= in[3 - 4];
-    in += 4;
-    out += 4;
-  }
-
-  return 1;
-}
-
-#endif
diff --git a/lib/silccrypt/loki.c b/lib/silccrypt/loki.c
deleted file mode 100644 (file)
index c326f27..0000000
+++ /dev/null
@@ -1,287 +0,0 @@
-/* Modified for SILC. -Pekka */\r
-\r
-/* This is an independent implementation of the encryption algorithm:   */\r
-/*                                                                      */\r
-/*         LOKI97 by Brown and Pieprzyk                                 */\r
-/*                                                                      */\r
-/* which is a candidate algorithm in the Advanced Encryption Standard   */\r
-/* programme of the US National Institute of Standards and Technology.  */\r
-/*                                                                      */\r
-/* Copyright in this implementation is held by Dr B R Gladman but I     */\r
-/* hereby give permission for its free direct or derivative use subject */\r
-/* to acknowledgment of its origin and compliance with any conditions   */\r
-/* that the originators of the algorithm place on its exploitation.     */\r
-/*                                                                      */\r
-/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999     */\r
-\r
-/* Timing data for LOKI97 (loki.c)\r
-\r
-Core timing without I/O endian conversion:\r
-\r
-128 bit key:\r
-Key Setup:    7430 cycles\r
-Encrypt:      2134 cycles =    12.0 mbits/sec\r
-Decrypt:      2192 cycles =    11.7 mbits/sec\r
-Mean:         2163 cycles =    11.8 mbits/sec\r
-\r
-192 bit key:\r
-Key Setup:    7303 cycles\r
-Encrypt:      2138 cycles =    12.0 mbits/sec\r
-Decrypt:      2189 cycles =    11.7 mbits/sec\r
-Mean:         2164 cycles =    11.8 mbits/sec\r
-\r
-256 bit key:\r
-Key Setup:    7166 cycles\r
-Encrypt:      2131 cycles =    12.0 mbits/sec\r
-Decrypt:      2184 cycles =    11.7 mbits/sec\r
-Mean:         2158 cycles =    11.9 mbits/sec\r
-\r
-Full timing with I/O endian conversion:\r
-\r
-128 bit key:\r
-Key Setup:    7582 cycles\r
-Encrypt:      2174 cycles =    11.8 mbits/sec\r
-Decrypt:      2235 cycles =    11.5 mbits/sec\r
-Mean:         2205 cycles =    11.6 mbits/sec\r
-\r
-192 bit key:\r
-Key Setup:    7477 cycles\r
-Encrypt:      2167 cycles =    11.8 mbits/sec\r
-Decrypt:      2223 cycles =    11.5 mbits/sec\r
-Mean:         2195 cycles =    11.7 mbits/sec\r
-\r
-256 bit key:\r
-Key Setup:    7365 cycles\r
-Encrypt:      2177 cycles =    11.8 mbits/sec\r
-Decrypt:      2194 cycles =    11.7 mbits/sec\r
-Mean:         2186 cycles =    11.7 mbits/sec\r
-\r
-*/\r
-\r
-#include <stdio.h>\r
-#include <sys/types.h>\r
-#include "loki_internal.h"\r
-\r
-#define S1_SIZE     13\r
-#define S1_LEN      (1 << S1_SIZE)\r
-#define S1_MASK     (S1_LEN - 1)\r
-#define S1_HMASK    (S1_MASK & ~0xff)\r
-#define S1_POLY     0x2911\r
-\r
-#define S2_SIZE     11\r
-#define S2_LEN      (1 << S2_SIZE)\r
-#define S2_MASK     (S2_LEN - 1)\r
-#define S2_HMASK    (S2_MASK & ~0xff)\r
-#define S2_POLY     0x0aa7\r
-\r
-#define io_swap(x)  ((x))\r
-\r
-u4byte  delta[2] = { 0x7f4a7c15, 0x9e3779b9 };\r
-\r
-u1byte  sb1[S1_LEN];    // GF(2^11) S box\r
-u1byte  sb2[S2_LEN];    // GF(2^11) S box\r
-u4byte  prm[256][2];\r
-u4byte  init_done = 0;\r
-\r
-#define add_eq(x,y)    (x)[1] += (y)[1] + (((x)[0] += (y)[0]) < (y)[0] ? 1 : x)\r
-#define sub_eq(x,y)    xs = (x)[0]; (x)[1] -= (y)[1] + (((x)[0] -= (y)[0]) > xs ? 1 : 0)   \r
-\r
-u4byte ff_mult(u4byte a, u4byte b, u4byte tpow, u4byte mpol)\r
-{   u4byte  r, s, m;\r
-\r
-    r = s = 0; m = (1 << tpow); \r
-\r
-    while(b)\r
-    {\r
-        if(b & 1)\r
-        \r
-            s ^= a;\r
-            \r
-        b >>= 1; a <<= 1;\r
-        \r
-        if(a & m)\r
-        \r
-            a ^= mpol;\r
-    }\r
-\r
-    return s;\r
-};\r
-\r
-void init_tables(void)\r
-{   u4byte  i, j, v;\r
-\r
-    // initialise S box 1\r
-\r
-    for(i = 0; i < S1_LEN; ++i)\r
-    {\r
-        j = v = i ^ S1_MASK; v = ff_mult(v, j, S1_SIZE, S1_POLY);\r
-        sb1[i] = (u1byte)ff_mult(v, j, S1_SIZE, S1_POLY);\r
-    } \r
-    // initialise S box 2\r
-\r
-    for(i = 0; i < S2_LEN; ++i)\r
-    {\r
-        j = v = i ^ S2_MASK; v = ff_mult(v, j, S2_SIZE, S2_POLY);\r
-        sb2[i] = (u1byte)ff_mult(v, j, S2_SIZE, S2_POLY);\r
-    }\r
-\r
-    // initialise permutation table\r
-\r
-    for(i = 0; i < 256; ++i)\r
-    {\r
-        prm[i][0] = ((i &  1) << 7) | ((i &  2) << 14) | ((i &  4) << 21) | ((i &   8) << 28);\r
-        prm[i][1] = ((i & 16) << 3) | ((i & 32) << 10) | ((i & 64) << 17) | ((i & 128) << 24);\r
-    }\r
-};\r
-\r
-void f_fun(u4byte res[2], const u4byte in[2], const u4byte key[2])\r
-{   u4byte  i, tt[2], pp[2];\r
-\r
-    tt[0] = (in[0] & ~key[0]) | (in[1] & key[0]);\r
-    tt[1] = (in[1] & ~key[0]) | (in[0] & key[0]);\r
-\r
-    i = sb1[((tt[1] >> 24) | (tt[0] << 8)) & S1_MASK];\r
-    pp[0]  = prm[i][0] >> 7; pp[1]  = prm[i][1] >> 7;\r
-    i = sb2[(tt[1] >> 16) & S2_MASK];\r
-    pp[0] |= prm[i][0] >> 6; pp[1] |= prm[i][1] >> 6;\r
-    i = sb1[(tt[1] >>  8) & S1_MASK];\r
-    pp[0] |= prm[i][0] >> 5; pp[1] |= prm[i][1] >> 5;\r
-    i = sb2[tt[1] & S2_MASK]; \r
-    pp[0] |= prm[i][0] >> 4; pp[1] |= prm[i][1] >> 4;\r
-    i = sb2[((tt[0] >> 24) | (tt[1] << 8)) & S2_MASK];\r
-    pp[0] |= prm[i][0] >> 3; pp[1] |= prm[i][1] >> 3;\r
-    i = sb1[(tt[0] >> 16) & S1_MASK]; \r
-    pp[0] |= prm[i][0] >> 2; pp[1] |= prm[i][1] >> 2;\r
-    i = sb2[(tt[0] >>  8) & S2_MASK];      \r
-    pp[0] |= prm[i][0] >> 1; pp[1] |= prm[i][1] >> 1;\r
-    i = sb1[tt[0] & S1_MASK];          \r
-    pp[0] |= prm[i][0];      pp[1] |= prm[i][1];\r
-\r
-    res[0] ^=  sb1[byte(pp[0], 0) | (key[1] <<  8) & S1_HMASK]\r
-            | (sb1[byte(pp[0], 1) | (key[1] <<  3) & S1_HMASK] << 8)\r
-            | (sb2[byte(pp[0], 2) | (key[1] >>  2) & S2_HMASK] << 16)\r
-            | (sb2[byte(pp[0], 3) | (key[1] >>  5) & S2_HMASK] << 24);\r
-    res[1] ^=  sb1[byte(pp[1], 0) | (key[1] >>  8) & S1_HMASK]\r
-            | (sb1[byte(pp[1], 1) | (key[1] >> 13) & S1_HMASK] << 8)\r
-            | (sb2[byte(pp[1], 2) | (key[1] >> 18) & S2_HMASK] << 16)\r
-            | (sb2[byte(pp[1], 3) | (key[1] >> 21) & S2_HMASK] << 24);\r
-};\r
-\r
-u4byte *loki_set_key(LokiContext *ctx,\r
-                    const u4byte in_key[], const u4byte key_len)\r
-{   \r
-    u4byte  i, k1[2], k2[2], k3[2], k4[2], del[2], tt[2], sk[2];\r
-    u4byte *l_key = ctx->l_key;\r
-\r
-    if(!init_done)\r
-    {\r
-        init_tables(); init_done = 1;\r
-    }\r
-\r
-    k4[0] = io_swap(in_key[1]); k4[1] = io_swap(in_key[0]);\r
-    k3[0] = io_swap(in_key[3]); k3[1] = io_swap(in_key[2]);\r
-\r
-    switch ((key_len + 63) / 64)\r
-    {\r
-    case 2:\r
-        k2[0] = 0; k2[1] = 0; f_fun(k2, k3, k4);\r
-        k1[0] = 0; k1[1] = 0; f_fun(k1, k4, k3);\r
-        break;\r
-    case 3:\r
-       k2[0] = io_swap(in_key[5]); k2[1] = io_swap(in_key[4]);\r
-        k1[0] = 0; k1[1] = 0; f_fun(k1, k4, k3);\r
-        break;\r
-    case 4: \r
-        k2[0] = in_key[5]; k2[1] = in_key[4];\r
-        k1[0] = in_key[7]; k1[1] = in_key[6];\r
-       k2[0] = io_swap(in_key[5]); k2[1] = io_swap(in_key[4]);\r
-       k1[0] = io_swap(in_key[7]); k1[1] = io_swap(in_key[6]);\r
-    }\r
-\r
-    del[0] = delta[0]; del[1] = delta[1];\r
-\r
-    for(i = 0; i < 48; ++i)\r
-    {\r
-        tt[0] = k1[0]; tt[1] = k1[1]; \r
-        add_eq(tt, k3); add_eq(tt, del); add_eq(del, delta);\r
-        sk[0] = k4[0]; sk[1] = k4[1];\r
-        k4[0] = k3[0]; k4[1] = k3[1];\r
-        k3[0] = k2[0]; k3[1] = k2[1];\r
-        k2[0] = k1[0]; k2[1] = k1[1];\r
-        k1[0] = sk[0]; k1[1] = sk[1];\r
-        f_fun(k1, tt, k3);\r
-        l_key[i + i] = k1[0]; l_key[i + i + 1] = k1[1];\r
-    }\r
-\r
-    return l_key;\r
-};\r
-\r
-#define r_fun(l,r,k)        \\r
-    add_eq((l),(k));        \\r
-    f_fun((r),(l),(k) + 2); \\r
-    add_eq((l), (k) + 4)\r
-\r
-void loki_encrypt(LokiContext *ctx,\r
-                 const u4byte in_blk[4], u4byte out_blk[4])\r
-{   \r
-    u4byte  blk[4];\r
-    u4byte *l_key = ctx->l_key;\r
-\r
-    blk[3] = io_swap(in_blk[0]); blk[2] = io_swap(in_blk[1]);\r
-    blk[1] = io_swap(in_blk[2]); blk[0] = io_swap(in_blk[3]);\r
-\r
-    r_fun(blk, blk + 2, l_key +  0);\r
-    r_fun(blk + 2, blk, l_key +  6);\r
-    r_fun(blk, blk + 2, l_key + 12);\r
-    r_fun(blk + 2, blk, l_key + 18);\r
-    r_fun(blk, blk + 2, l_key + 24);\r
-    r_fun(blk + 2, blk, l_key + 30);\r
-    r_fun(blk, blk + 2, l_key + 36);\r
-    r_fun(blk + 2, blk, l_key + 42);\r
-    r_fun(blk, blk + 2, l_key + 48);\r
-    r_fun(blk + 2, blk, l_key + 54);\r
-    r_fun(blk, blk + 2, l_key + 60);\r
-    r_fun(blk + 2, blk, l_key + 66);\r
-    r_fun(blk, blk + 2, l_key + 72);\r
-    r_fun(blk + 2, blk, l_key + 78);\r
-    r_fun(blk, blk + 2, l_key + 84);\r
-    r_fun(blk + 2, blk, l_key + 90);\r
-\r
-    out_blk[3] = io_swap(blk[2]); out_blk[2] = io_swap(blk[3]);\r
-    out_blk[1] = io_swap(blk[0]); out_blk[0] = io_swap(blk[1]);\r
-};\r
-\r
-#define ir_fun(l,r,k)       \\r
-    sub_eq((l),(k) + 4);    \\r
-    f_fun((r),(l),(k) + 2); \\r
-    sub_eq((l),(k))\r
-\r
-void loki_decrypt(LokiContext *ctx,\r
-                 const u4byte in_blk[4], u4byte out_blk[4])\r
-{   \r
-    u4byte  blk[4], xs;\r
-    u4byte *l_key = ctx->l_key;\r
-\r
-    blk[3] = io_swap(in_blk[0]); blk[2] = io_swap(in_blk[1]);\r
-    blk[1] = io_swap(in_blk[2]); blk[0] = io_swap(in_blk[3]);\r
-\r
-    ir_fun(blk, blk + 2, l_key + 90); \r
-    ir_fun(blk + 2, blk, l_key + 84);\r
-    ir_fun(blk, blk + 2, l_key + 78); \r
-    ir_fun(blk + 2, blk, l_key + 72);\r
-    ir_fun(blk, blk + 2, l_key + 66); \r
-    ir_fun(blk + 2, blk, l_key + 60);\r
-    ir_fun(blk, blk + 2, l_key + 54); \r
-    ir_fun(blk + 2, blk, l_key + 48);\r
-    ir_fun(blk, blk + 2, l_key + 42); \r
-    ir_fun(blk + 2, blk, l_key + 36);\r
-    ir_fun(blk, blk + 2, l_key + 30); \r
-    ir_fun(blk + 2, blk, l_key + 24);\r
-    ir_fun(blk, blk + 2, l_key + 18); \r
-    ir_fun(blk + 2, blk, l_key + 12);\r
-    ir_fun(blk, blk + 2, l_key +  6); \r
-    ir_fun(blk + 2, blk, l_key);\r
-\r
-    out_blk[3] = io_swap(blk[2]); out_blk[2] = io_swap(blk[3]);\r
-    out_blk[1] = io_swap(blk[0]); out_blk[0] = io_swap(blk[1]);   \r
-};\r
diff --git a/lib/silccrypt/loki.h b/lib/silccrypt/loki.h
deleted file mode 100644 (file)
index 0f3bc51..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
-
-  loki.h
-
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
-
-  Copyright (C) 1997 - 2000 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
-  GNU General Public License for more details.
-
-*/
-/*
- * $Id$
- * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:54  priikone
- *     Importet from internal CVS/Added Log headers.
- *
- *
- */
-
-#ifndef LOKI_H
-#define LOKI_H
-
-#include "loki_internal.h"
-
-/* 
- * SILC Crypto API for Loki
- */
-
-/* Sets the key for the cipher. */
-
-inline int silc_loki_init(void *context, 
-                         const unsigned char *key, 
-                         size_t keylen)
-{
-  loki_set_key((LokiContext *)context, (unsigned int *)key, keylen);
-  return 1;
-}
-
-/* Sets the string as a new key for the cipher. The string
-   is first hashed and then used as a new key. */
-
-inline int silc_loki_set_string_as_key(void *context, 
-                                      const unsigned char *string,
-                                      size_t keylen)
-{
-  /*  unsigned char key[md5_hash_len];
-  SilcMarsContext *ctx = (SilcMarsContext *)context;
-
-  make_md5_hash(string, &key);
-  memcpy(&ctx->key, mars_set_key(&key, keylen), keylen);
-  memset(&key, 'F', sizeoof(key));
-  */
-
-  return 1;
-}
-
-/* Returns the size of the cipher context. */
-
-inline size_t silc_loki_context_len()
-{
-  return sizeof(LokiContext);
-}
-
-/* Encrypts with the cipher in CBC mode. */
-
-inline int silc_loki_encrypt_cbc(void *context,
-                                const unsigned char *src,
-                                unsigned char *dst,
-                                size_t len,
-                                unsigned char *iv)
-{
-  unsigned int *in, *out, *tiv;
-  unsigned int tmp[4];
-  int i;
-
-  in = (unsigned int *)src;
-  out = (unsigned int *)dst;
-  tiv = (unsigned int *)iv;
-
-  tmp[0] = in[0] ^ tiv[0];
-  tmp[1] = in[1] ^ tiv[1];
-  tmp[2] = in[2] ^ tiv[2];
-  tmp[3] = in[3] ^ tiv[3];
-  loki_encrypt((LokiContext *)context, tmp, out);
-  in += 4;
-  out += 4;
-
-  for (i = 16; i < len; i += 16) {
-    tmp[0] = in[0] ^ out[0 - 4];
-    tmp[1] = in[1] ^ out[1 - 4];
-    tmp[2] = in[2] ^ out[2 - 4];
-    tmp[3] = in[3] ^ out[3 - 4];
-    loki_encrypt((LokiContext *)context, tmp, out);
-    in += 4;
-    out += 4;
-  }
-
-  return 1;
-}
-
-/* Decrypts with the cipher in CBC mode. */
-
-inline int silc_loki_decrypt_cbc(void *context,
-                                const unsigned char *src,
-                                unsigned char *dst,
-                                size_t len,
-                                unsigned char *iv)
-{
-  unsigned int *in, *out, *tiv;
-  int i;
-
-  in = (unsigned int *)src;
-  out = (unsigned int *)dst;
-  tiv = (unsigned int *)iv;
-
-  loki_decrypt((LokiContext *)context, in, out);
-  out[0] ^= tiv[0];
-  out[1] ^= tiv[1];
-  out[2] ^= tiv[2];
-  out[3] ^= tiv[3];
-  in += 4;
-  out += 4;
-
-  for (i = 16; i < len; i += 16) {
-    loki_decrypt((LokiContext *)context, in, out);
-    out[0] ^= in[0 - 4];
-    out[1] ^= in[1 - 4];
-    out[2] ^= in[2 - 4];
-    out[3] ^= in[3 - 4];
-    in += 4;
-    out += 4;
-  }
-
-  return 1;
-}
-
-#endif
diff --git a/lib/silccrypt/loki_internal.h b/lib/silccrypt/loki_internal.h
deleted file mode 100644 (file)
index 650f6b4..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
-
-  loki_internal.h
-
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
-
-  Copyright (C) 1997 - 2000 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
-  GNU General Public License for more details.
-
-*/
-
-#ifndef LOKI_INTERNAL_H
-#define LOKI_INTERNAL_H
-
-/* Cipher's context */
-typedef struct {
-  u4byte l_key[96];
-} LokiContext;
-
-/* Prototypes */
-u4byte *loki_set_key(LokiContext *ctx,
-                    const u4byte in_key[], const u4byte key_len);
-void loki_encrypt(LokiContext *ctx,
-                 const u4byte in_blk[4], u4byte out_blk[4]);
-void loki_decrypt(LokiContext *ctx,
-                 const u4byte in_blk[4], u4byte out_blk[4]);
-
-#endif
index 5ab5938b97a6c5f5551f8a6aabaa56f2915bb204..33dd82649eddd072f7364385f064cafebebdb4ef 100644 (file)
@@ -20,8 +20,8 @@
 /*
  * $Id$
  * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:54  priikone
- *     Importet from internal CVS/Added Log headers.
+ * Revision 1.1  2000/06/27 11:36:54  priikone
+ * Initial revision
  *
  *
  */
index c6c2e3b56394972d92496c7e9813ffa3ebd69fc7..c80f4a326f619180179e40a25de24ae006c624b9 100644 (file)
@@ -20,8 +20,8 @@
 /*
  * $Id$
  * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
- *     Importet from internal CVS/Added Log headers.
+ * Revision 1.1  2000/06/27 11:36:55  priikone
+ * Initial revision
  *
  *
  */
index 3bba1a02c59ce777e737d10ff700ca2e5cafcc4c..239be9106e4251a88f6d68c77c8e83e5ac1f0653 100644 (file)
@@ -20,8 +20,8 @@
 /*
  * $Id$
  * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
- *     Importet from internal CVS/Added Log headers.
+ * Revision 1.1  2000/06/27 11:36:55  priikone
+ * Initial revision
  *
  *
  */
index 3043de15360a0da76785109f8b72593c70e0032f..316ea8784130bd71534dfcd20babddaad2a6f436 100644 (file)
@@ -20,8 +20,8 @@
 /*
  * $Id$
  * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:54  priikone
- *     Importet from internal CVS/Added Log headers.
+ * Revision 1.1  2000/06/27 11:36:54  priikone
+ * Initial revision
  *
  *
  */
index 23186dce881ad63210914b72c7dced267293477c..7d5a23ed14dedf76bd38e693fdf4ea16686bb860 100644 (file)
@@ -20,8 +20,8 @@
 /*
  * $Id$
  * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:54  priikone
- *     Importet from internal CVS/Added Log headers.
+ * Revision 1.1  2000/06/27 11:36:54  priikone
+ * Initial revision
  *
  *
  */
index 6ca50da2ae02952a69b64c344089a92bc807bf8f..ee85979539606b7fd135d6778a282d901d7ad159 100644 (file)
@@ -20,8 +20,8 @@
 /*
  * $Id$
  * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:54  priikone
- *     Importet from internal CVS/Added Log headers.
+ * Revision 1.1  2000/06/27 11:36:54  priikone
+ * Initial revision
  *
  *
  */
index f6d5b1de390289124c73457bde42f332f0bcf6cb..1f7cadadcd13f3320bc627190b472bc9f2433b58 100644 (file)
@@ -1,4 +1,5 @@
 /* Modified for SILC. -Pekka */
+/* The AES */
 
 /* This is an independent implementation of the encryption algorithm:   */
 /*                                                                      */
@@ -41,6 +42,131 @@ Mean:          500 cycles =    51.2 mbits/sec
 #include "silcincludes.h"
 #include "rijndael.h"
 
+/* 
+ * SILC Crypto API for Rijndael
+ */
+
+/* Sets the key for the cipher. */
+
+SILC_CIPHER_API_SET_KEY(rijndael)
+{
+  rijndael_set_key((RijndaelContext *)context, (unsigned int *)key, keylen);
+  return 1;
+}
+
+/* Sets the string as a new key for the cipher. The string is first
+   hashed and then used as a new key. */
+
+SILC_CIPHER_API_SET_KEY_WITH_STRING(rijndael)
+{
+  /*  unsigned char key[md5_hash_len];
+  SilcMarsContext *ctx = (SilcMarsContext *)context;
+
+  make_md5_hash(string, &key);
+  memcpy(&ctx->key, mars_set_key(&key, keylen), keylen);
+  memset(&key, 'F', sizeoof(key));
+  */
+
+  return 1;
+}
+
+/* Returns the size of the cipher context. */
+
+SILC_CIPHER_API_CONTEXT_LEN(rijndael)
+{
+  return sizeof(RijndaelContext);
+}
+
+/* Encrypts with the cipher in CBC mode. Source and destination buffers
+   maybe one and same. */
+
+SILC_CIPHER_API_ENCRYPT_CBC(rijndael)
+{
+  unsigned int *in, *out, *tiv;
+  unsigned int tmp[4];
+  int i;
+
+  in = (unsigned int *)src;
+  out = (unsigned int *)dst;
+  tiv = (unsigned int *)iv;
+
+  tmp[0] = in[0] ^ tiv[0];
+  tmp[1] = in[1] ^ tiv[1];
+  tmp[2] = in[2] ^ tiv[2];
+  tmp[3] = in[3] ^ tiv[3];
+  rijndael_encrypt((RijndaelContext *)context, tmp, out);
+  in += 4;
+  out += 4;
+
+  for (i = 16; i < len; i += 16) {
+    tmp[0] = in[0] ^ out[0 - 4];
+    tmp[1] = in[1] ^ out[1 - 4];
+    tmp[2] = in[2] ^ out[2 - 4];
+    tmp[3] = in[3] ^ out[3 - 4];
+    rijndael_encrypt((RijndaelContext *)context, tmp, out);
+    in += 4;
+    out += 4;
+  }
+
+  tiv[0] = out[0 - 4];
+  tiv[1] = out[1 - 4];
+  tiv[2] = out[2 - 4];
+  tiv[3] = out[3 - 4];
+
+  return TRUE;
+}
+
+/* Decrypts with the cipher in CBC mode. Source and destination buffers
+   maybe one and same. */
+
+SILC_CIPHER_API_DECRYPT_CBC(rijndael)
+{
+  unsigned int *tiv, *in, *out;
+  unsigned int tmp[4], tmp2[4];
+  int i;
+
+  in = (unsigned int *)src;
+  out = (unsigned int *)dst;
+  tiv = (unsigned int *)iv;
+
+  tmp[0] = in[0];
+  tmp[1] = in[1];
+  tmp[2] = in[2];
+  tmp[3] = in[3];
+  rijndael_decrypt((RijndaelContext *)context, in, out);
+  out[0] ^= tiv[0];
+  out[1] ^= tiv[1];
+  out[2] ^= tiv[2];
+  out[3] ^= tiv[3];
+  in += 4;
+  out += 4;
+
+  for (i = 16; i < len; i += 16) {
+    tmp2[0] = tmp[0];
+    tmp2[1] = tmp[1];
+    tmp2[2] = tmp[2];
+    tmp2[3] = tmp[3];
+    tmp[0] = in[0];
+    tmp[1] = in[1];
+    tmp[2] = in[2];
+    tmp[3] = in[3];
+    rijndael_decrypt((RijndaelContext *)context, in, out);
+    out[0] ^= tmp2[0];
+    out[1] ^= tmp2[1];
+    out[2] ^= tmp2[2];
+    out[3] ^= tmp2[3];
+    in += 4;
+    out += 4;
+  }
+
+  tiv[0] = tmp[0];
+  tiv[1] = tmp[1];
+  tiv[2] = tmp[2];
+  tiv[3] = tmp[3];
+
+  return TRUE;
+}
+
 #define LARGE_TABLES
 
 u1byte  pow_tab[256];
index d53a11d174279f697be1ac11e194933e9bd593ab..15fc3c8f8a9a30f4aa0407877692ef66dbd4571b 100644 (file)
@@ -20,6 +20,9 @@
 /*
  * $Id$
  * $Log$
+ * Revision 1.2  2000/10/02 18:31:46  priikone
+ *     Added rijndael (AES) to cipher list.
+ *
  * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
  *     Importet from internal CVS/Added Log headers.
  *
  * SILC Crypto API for Rijndael
  */
 
-/* Sets the key for the cipher. */
-
-SILC_CIPHER_API_SET_KEY(rijndael)
-{
-  rijndael_set_key((RijndaelContext *)context, (unsigned int *)key, keylen);
-  return TRUE;
-}
-
-/* Sets the string as a new key for the cipher. The string is first
-   hashed and then used as a new key. */
-
-SILC_CIPHER_API_SET_KEY_WITH_STRING(rijndael)
-{
-  /*  unsigned char key[md5_hash_len];
-  SilcMarsContext *ctx = (SilcMarsContext *)context;
-
-  make_md5_hash(string, &key);
-  memcpy(&ctx->key, mars_set_key(&key, keylen), keylen);
-  memset(&key, 'F', sizeoof(key));
-  */
-
-  return TRUE;
-}
-
-/* Returns the size of the cipher context. */
-
-SILC_CIPHER_API_CONTEXT_LEN(rijnadel)
-{
-  return sizeof(RijndaelContext);
-}
-
-/* Encrypts with the cipher in CBC mode. Source and destination buffers
-   maybe one and same. */
-
-SILC_CIPHER_API_ENCRYPT_CBC(rijndael)
-{
-  unsigned int *in, *out, *tiv;
-  unsigned int tmp[4];
-  int i;
-
-  in = (unsigned int *)src;
-  out = (unsigned int *)dst;
-  tiv = (unsigned int *)iv;
-
-  tmp[0] = in[0] ^ tiv[0];
-  tmp[1] = in[1] ^ tiv[1];
-  tmp[2] = in[2] ^ tiv[2];
-  tmp[3] = in[3] ^ tiv[3];
-  rijndael_encrypt((RijndaelContext *)context, tmp, out);
-  in += 4;
-  out += 4;
-
-  for (i = 16; i < len; i += 16) {
-    tmp[0] = in[0] ^ out[0 - 4];
-    tmp[1] = in[1] ^ out[1 - 4];
-    tmp[2] = in[2] ^ out[2 - 4];
-    tmp[3] = in[3] ^ out[3 - 4];
-    rijndael_encrypt((RijndaelContext *)context, tmp, out);
-    in += 4;
-    out += 4;
-  }
-
-  return TRUE;
-}
-
-/* Decrypts with the cipher in CBC mode. Source and destination buffers
-   maybe one and same. */
-
-SILC_CIPHER_API_DECRYPT_CBC(rijndael)
-{
-  unsigned int *in, *out, *tiv;
-  unsigned int tmp[4], tmp2[4];
-  int i;
-
-  in = (unsigned int *)src;
-  out = (unsigned int *)dst;
-  tiv = (unsigned int *)iv;
-
-  tmp[0] = in[0];
-  tmp[1] = in[1];
-  tmp[2] = in[2];
-  tmp[3] = in[3];
-  rijndael_decrypt((RijndaelContext *)context, in, out);
-  out[0] ^= tiv[0];
-  out[1] ^= tiv[1];
-  out[2] ^= tiv[2];
-  out[3] ^= tiv[3];
-  in += 4;
-  out += 4;
-
-  for (i = 16; i < len; i += 16) {
-    tmp2[0] = tmp[0];
-    tmp2[1] = tmp[1];
-    tmp2[2] = tmp[2];
-    tmp2[3] = tmp[3];
-    tmp[0] = in[0];
-    tmp[1] = in[1];
-    tmp[2] = in[2];
-    tmp[3] = in[3];
-    rijndael_decrypt((RijndaelContext *)context, in, out);
-    out[0] ^= tmp2[0];
-    out[1] ^= tmp2[1];
-    out[2] ^= tmp2[2];
-    out[3] ^= tmp2[3];
-    in += 4;
-    out += 4;
-  }
+SILC_CIPHER_API_SET_KEY(rijndael);
+SILC_CIPHER_API_SET_KEY_WITH_STRING(rijndael);
+SILC_CIPHER_API_CONTEXT_LEN(rijndael);
+SILC_CIPHER_API_ENCRYPT_CBC(rijndael);
+SILC_CIPHER_API_DECRYPT_CBC(rijndael);
 
-  return TRUE;
-}
 
 #endif
index c185adb97f799f0c5057e0ff2ee1888d6add7f51..ec85853a2f3dc9d90d310bb141d27272013a240c 100644 (file)
@@ -43,6 +43,7 @@
  * everything else too about cryptography.
  *
  */
+/* $Id$ */
 
 #include "silcincludes.h"
 #include "rsa.h"
@@ -111,33 +112,27 @@ SILC_PKCS_API_GET_PUBLIC_KEY(rsa)
   RsaKey *key = (RsaKey *)context;
   unsigned char *e, *n, *ret;
   unsigned int e_len, n_len;
-  unsigned char tmp[2];
+  unsigned char tmp[4];
 
-  e_len = silc_mp_sizeinbase(&key->e, 16);
-  n_len = silc_mp_sizeinbase(&key->n, 16);
-  e = silc_calloc(e_len + 1, sizeof(unsigned char));
-  n = silc_calloc(n_len + 1, sizeof(unsigned char));
-  silc_mp_get_str(e, 16, &key->e);
-  silc_mp_get_str(n, 16, &key->n);
+  e = silc_mp_mp2bin(&key->e, &e_len);
+  n = silc_mp_mp2bin(&key->n, &n_len);
 
-  *ret_len = e_len + 2 + n_len + 2;
+  *ret_len = e_len + 4 + n_len + 4;
   ret = silc_calloc(*ret_len, sizeof(unsigned char));
 
   /* Put the length of the e. */
-  tmp[0] = e_len >> 8;
-  tmp[1] = e_len;
-  memcpy(ret, tmp, 2);
+  SILC_PUT32_MSB(e_len, tmp);
+  memcpy(ret, tmp, 4);
 
   /* Put the e. */
-  memcpy(ret + 2, e, e_len);
+  memcpy(ret + 4, e, e_len);
 
   /* Put the length of the n. */
-  tmp[0] = n_len >> 8;
-  tmp[1] = n_len;
-  memcpy(ret + 2 + e_len, tmp, 2);
+  SILC_PUT32_MSB(n_len, tmp);
+  memcpy(ret + 4 + e_len, tmp, 4);
 
   /* Put the n. */
-  memcpy(ret + 2 + e_len + 2, n, n_len);
+  memcpy(ret + 4 + e_len + 4, n, n_len);
 
   memset(e, 0, e_len);
   memset(n, 0, n_len);
@@ -156,44 +151,35 @@ SILC_PKCS_API_GET_PRIVATE_KEY(rsa)
   RsaKey *key = (RsaKey *)context;
   unsigned char *e, *n, *d, *ret;
   unsigned int e_len, n_len, d_len;
-  unsigned char tmp[2];
-
-  e_len = silc_mp_sizeinbase(&key->e, 16);
-  n_len = silc_mp_sizeinbase(&key->n, 16);
-  d_len = silc_mp_sizeinbase(&key->d, 16);
-  e = silc_calloc(e_len + 1, sizeof(unsigned char));
-  n = silc_calloc(n_len + 1, sizeof(unsigned char));
-  d = silc_calloc(d_len + 1, sizeof(unsigned char));
-  silc_mp_get_str(e, 16, &key->e);
-  silc_mp_get_str(n, 16, &key->n);
-  silc_mp_get_str(d, 16, &key->d);
-
-  *ret_len = e_len + 2 + n_len + 2 + d_len + 2;
+  unsigned char tmp[4];
+
+  e = silc_mp_mp2bin(&key->e, &e_len);
+  n = silc_mp_mp2bin(&key->n, &n_len);
+  d = silc_mp_mp2bin(&key->d, &d_len);
+
+  *ret_len = e_len + 4 + n_len + 4 + d_len + 4;
   ret = silc_calloc(*ret_len, sizeof(unsigned char));
 
   /* Put the length of the e. */
-  tmp[0] = e_len >> 8;
-  tmp[1] = e_len;
-  memcpy(ret, tmp, 2);
+  SILC_PUT32_MSB(e_len, tmp);
+  memcpy(ret, tmp, 4);
 
   /* Put the e. */
-  memcpy(ret + 2, e, e_len);
+  memcpy(ret + 4, e, e_len);
 
   /* Put the length of the n. */
-  tmp[0] = n_len >> 8;
-  tmp[1] = n_len;
-  memcpy(ret + 2 + e_len, tmp, 2);
+  SILC_PUT32_MSB(n_len, tmp);
+  memcpy(ret + 4 + e_len, tmp, 4);
 
   /* Put the n. */
-  memcpy(ret + 2 + e_len + 2, n, n_len);
+  memcpy(ret + 4 + e_len + 4, n, n_len);
 
   /* Put the length of the d. */
-  tmp[0] = d_len >> 8;
-  tmp[1] = d_len;
-  memcpy(ret + 2 + e_len + 2 + n_len, tmp, 2);
+  SILC_PUT32_MSB(d_len, tmp);
+  memcpy(ret + 4 + e_len + 4 + n_len, tmp, 4);
 
   /* Put the n. */
-  memcpy(ret + 2 + e_len + 2 + n_len + 2, d, d_len);
+  memcpy(ret + 4 + e_len + 4 + n_len + 4, d, d_len);
 
   memset(e, 0, e_len);
   memset(n, 0, n_len);
@@ -210,30 +196,31 @@ SILC_PKCS_API_GET_PRIVATE_KEY(rsa)
 SILC_PKCS_API_SET_PUBLIC_KEY(rsa)
 {
   RsaKey *key = (RsaKey *)context;
-  unsigned char *e, *n, tmp[2];
+  unsigned char tmp[4];
   unsigned int e_len, n_len;
 
   silc_mp_init(&key->e);
   silc_mp_init(&key->n);
 
-  memcpy(tmp, key_data, 2);
-  e_len = ((unsigned int)tmp[0] << 8) | ((unsigned int)tmp[1]);
+  memcpy(tmp, key_data, 4);
+  SILC_GET32_MSB(e_len, tmp);
+  if (e_len > key_len) {
+    silc_mp_clear(&key->e);
+    silc_mp_clear(&key->n);
+    return FALSE;
+  }
 
-  e = silc_calloc(e_len + 1, sizeof(unsigned char));
-  memcpy(e, key_data + 2, e_len);
-  silc_mp_set_str(&key->e, e, 16);
+  silc_mp_bin2mp(key_data + 4, e_len, &key->e);
   
-  memcpy(tmp, key_data + 2 + e_len, 2);
-  n_len = ((unsigned int)tmp[0] << 8) | ((unsigned int)tmp[1]);
-
-  n = silc_calloc(n_len + 1, sizeof(unsigned char));
-  memcpy(n, key_data + 2 + e_len + 2, n_len);
-  silc_mp_set_str(&key->n, n, 16);
+  memcpy(tmp, key_data + 4 + e_len, 4);
+  SILC_GET32_MSB(n_len, tmp);
+  if (e_len + n_len > key_len) {
+    silc_mp_clear(&key->e);
+    silc_mp_clear(&key->n);
+    return FALSE;
+  }
 
-  memset(e, 0, e_len);
-  memset(n, 0, n_len);
-  silc_free(e);
-  silc_free(n);
+  silc_mp_bin2mp(key_data + 4 + e_len + 4, n_len, &key->n);
 
   return TRUE;
 }
@@ -245,40 +232,42 @@ SILC_PKCS_API_SET_PUBLIC_KEY(rsa)
 SILC_PKCS_API_SET_PRIVATE_KEY(rsa)
 {
   RsaKey *key = (RsaKey *)context;
-  unsigned char *e, *n, *d, tmp[2];
+  unsigned char tmp[4];
   unsigned int e_len, n_len, d_len;
 
   silc_mp_init(&key->e);
   silc_mp_init(&key->n);
   silc_mp_init(&key->d);
 
-  memcpy(tmp, key_data, 2);
-  e_len = ((unsigned int)tmp[0] << 8) | ((unsigned int)tmp[1]);
+  memcpy(tmp, key_data, 4);
+  SILC_GET32_MSB(e_len, tmp);
+  if (e_len > key_len) {
+    silc_mp_clear(&key->e);
+    silc_mp_clear(&key->n);
+    return FALSE;
+  }
 
-  e = silc_calloc(e_len + 1, sizeof(unsigned char));
-  memcpy(e, key_data + 2, e_len);
-  silc_mp_set_str(&key->e, e, 16);
+  silc_mp_bin2mp(key_data + 4, e_len, &key->e);
   
-  memcpy(tmp, key_data + 2 + e_len, 2);
-  n_len = ((unsigned int)tmp[0] << 8) | ((unsigned int)tmp[1]);
-
-  n = silc_calloc(n_len + 1, sizeof(unsigned char));
-  memcpy(n, key_data + 2 + e_len + 2, n_len);
-  silc_mp_set_str(&key->n, n, 16);
+  memcpy(tmp, key_data + 4 + e_len, 4);
+  SILC_GET32_MSB(n_len, tmp);
+  if (e_len + n_len > key_len) {
+    silc_mp_clear(&key->e);
+    silc_mp_clear(&key->n);
+    return FALSE;
+  }
 
-  memcpy(tmp, key_data + 2 + e_len + 2 + n_len, 2);
-  d_len = ((unsigned int)tmp[0] << 8) | ((unsigned int)tmp[1]);
+  silc_mp_bin2mp(key_data + 4 + e_len + 4, n_len, &key->n);
 
-  d = silc_calloc(d_len + 1, sizeof(unsigned char));
-  memcpy(d, key_data + 2 + e_len + 2 + n_len + 2, d_len);
-  silc_mp_set_str(&key->d, d, 16);
+  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) {
+    silc_mp_clear(&key->e);
+    silc_mp_clear(&key->n);
+    return FALSE;
+  }
 
-  memset(e, 0, e_len);
-  memset(n, 0, n_len);
-  memset(d, 0, d_len);
-  silc_free(e);
-  silc_free(n);
-  silc_free(d);
+  silc_mp_bin2mp(key_data + 4 + e_len + 4 + n_len + 4, d_len, &key->d);
 
   return TRUE;
 }
diff --git a/lib/silccrypt/safer.c b/lib/silccrypt/safer.c
deleted file mode 100644 (file)
index bb0a3bc..0000000
+++ /dev/null
@@ -1,379 +0,0 @@
-\r
-/* This is an independent implementation of the encryption algorithm:   */\r
-/*                                                                      */\r
-/*         SAFER+ by Cylink                                             */\r
-/*                                                                      */\r
-/* which is a candidate algorithm in the Advanced Encryption Standard   */\r
-/* programme of the US National Institute of Standards and Technology.  */\r
-/*                                                                      */\r
-/* Copyright in this implementation is held by Dr B R Gladman but I     */\r
-/* hereby give permission for its free direct or derivative use subject */\r
-/* to acknowledgment of its origin and compliance with any conditions   */\r
-/* that the originators of the algorithm place on its exploitation.     */\r
-/*                                                                      */\r
-/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999     */\r
-\r
-/* Timing data for SAFER+ (safer.c)\r
-\r
-Core timing without I/O endian conversion:\r
-\r
-128 bit key:\r
-Key Setup:    4278 cycles\r
-Encrypt:      1722 cycles =    14.9 mbits/sec\r
-Decrypt:      1709 cycles =    15.0 mbits/sec\r
-Mean:         1716 cycles =    14.9 mbits/sec\r
-\r
-192 bit key:\r
-Key Setup:    7426 cycles\r
-Encrypt:      2555 cycles =    10.0 mbits/sec\r
-Decrypt:      2530 cycles =    10.1 mbits/sec\r
-Mean:         2543 cycles =    10.1 mbits/sec\r
-\r
-256 bit key:\r
-Key Setup:   11313 cycles\r
-Encrypt:      3391 cycles =     7.5 mbits/sec\r
-Decrypt:      3338 cycles =     7.7 mbits/sec\r
-Mean:         3365 cycles =     7.6 mbits/sec\r
-\r
-Full timing with I/O endian conversion:\r
-\r
-128 bit key:\r
-Key Setup:    3977 cycles\r
-Encrypt:      1751 cycles =    14.6 mbits/sec\r
-Decrypt:      1734 cycles =    14.8 mbits/sec\r
-Mean:         1743 cycles =    14.7 mbits/sec\r
-\r
-192 bit key:\r
-Key Setup:    6490 cycles\r
-Encrypt:      2574 cycles =     9.9 mbits/sec\r
-Decrypt:      2549 cycles =    10.0 mbits/sec\r
-Mean:         2562 cycles =    10.0 mbits/sec\r
-\r
-256 bit key:\r
-Key Setup:    9487 cycles\r
-Encrypt:      3412 cycles =     7.5 mbits/sec\r
-Decrypt:      3372 cycles =     7.6 mbits/sec\r
-Mean:         3392 cycles =     7.5 mbits/sec\r
-\r
-*/\r
-\r
-#include <stdio.h>\r
-#include <sys/types.h>\r
-#include "safer_internal.h"\r
-\r
-u1byte  expf[256] =\r
-{     1,  45, 226, 147, 190,  69,  21, 174, 120,   3, 135, 164, 184,  56, 207,  63, \r
-      8, 103,   9, 148, 235,  38, 168, 107, 189,  24,  52,  27, 187, 191, 114, 247, \r
-     64,  53,  72, 156,  81,  47,  59,  85, 227, 192, 159, 216, 211, 243, 141, 177, \r
-    255, 167,  62, 220, 134, 119, 215, 166,  17, 251, 244, 186, 146, 145, 100, 131, \r
-    241,  51, 239, 218,  44, 181, 178,  43, 136, 209, 153, 203, 140, 132,  29,  20, \r
-    129, 151, 113, 202,  95, 163, 139,  87,  60, 130, 196,  82,  92,  28, 232, 160, \r
-      4, 180, 133,  74, 246,  19,  84, 182, 223,  12,  26, 142, 222, 224,  57, 252, \r
-     32, 155,  36,  78, 169, 152, 158, 171, 242,  96, 208, 108, 234, 250, 199, 217, \r
-      0, 212,  31, 110,  67, 188, 236,  83, 137, 254, 122,  93,  73, 201,  50, 194, \r
-    249, 154, 248, 109,  22, 219,  89, 150,  68, 233, 205, 230,  70,  66, 143,  10, \r
-    193, 204, 185, 101, 176, 210, 198, 172,  30,  65,  98,  41,  46,  14, 116,  80, \r
-      2,  90, 195,  37, 123, 138,  42,  91, 240,   6,  13,  71, 111, 112, 157, 126, \r
-     16, 206,  18,  39, 213,  76,  79, 214, 121,  48, 104,  54, 117, 125, 228, 237, \r
-    128, 106, 144,  55, 162,  94, 118, 170, 197, 127,  61, 175, 165, 229,  25,  97, \r
-    253,  77, 124, 183,  11, 238, 173,  75,  34, 245, 231, 115,  35,  33, 200,   5, \r
-    225, 102, 221, 179,  88, 105,  99,  86,  15, 161,  49, 149,  23,   7,  58,  40 \r
-};\r
-\r
-u1byte logf[512] = \r
-{\r
-    128,   0, 176,   9,  96, 239, 185, 253,  16,  18, 159, 228, 105, 186, 173, 248, \r
-    192,  56, 194, 101,  79,   6, 148, 252,  25, 222, 106,  27,  93,  78, 168, 130, \r
-    112, 237, 232, 236, 114, 179,  21, 195, 255, 171, 182,  71,  68,   1, 172,  37, \r
-    201, 250, 142,  65,  26,  33, 203, 211,  13, 110, 254,  38,  88, 218,  50,  15, \r
-     32, 169, 157, 132, 152,   5, 156, 187,  34, 140,  99, 231, 197, 225, 115, 198, \r
-    175,  36,  91, 135, 102,  39, 247,  87, 244, 150, 177, 183,  92, 139, 213,  84, \r
-    121, 223, 170, 246,  62, 163, 241,  17, 202, 245, 209,  23, 123, 147, 131, 188, \r
-    189,  82,  30, 235, 174, 204, 214,  53,   8, 200, 138, 180, 226, 205, 191, 217, \r
-    208,  80,  89,  63,  77,  98,  52,  10,  72, 136, 181,  86,  76,  46, 107, 158, \r
-    210,  61,  60,   3,  19, 251, 151,  81, 117,  74, 145, 113,  35, 190, 118,  42, \r
-     95, 249, 212,  85,  11, 220,  55,  49,  22, 116, 215, 119, 167, 230,   7, 219, \r
-    164,  47,  70, 243,  97,  69, 103, 227,  12, 162,  59,  28, 133,  24,   4,  29, \r
-     41, 160, 143, 178,  90, 216, 166, 126, 238, 141,  83,  75, 161, 154, 193,  14, \r
-    122,  73, 165,  44, 129, 196, 199,  54,  43, 127,  67, 149,  51, 242, 108, 104, \r
-    109, 240,   2,  40, 206, 221, 155, 234,  94, 153, 124,  20, 134, 207, 229,  66, \r
-    184,  64, 120,  45,  58, 233, 100,  31, 146, 144, 125,  57, 111, 224, 137,  48,\r
-\r
-    128,   0, 176,   9,  96, 239, 185, 253,  16,  18, 159, 228, 105, 186, 173, 248, \r
-    192,  56, 194, 101,  79,   6, 148, 252,  25, 222, 106,  27,  93,  78, 168, 130, \r
-    112, 237, 232, 236, 114, 179,  21, 195, 255, 171, 182,  71,  68,   1, 172,  37, \r
-    201, 250, 142,  65,  26,  33, 203, 211,  13, 110, 254,  38,  88, 218,  50,  15, \r
-     32, 169, 157, 132, 152,   5, 156, 187,  34, 140,  99, 231, 197, 225, 115, 198, \r
-    175,  36,  91, 135, 102,  39, 247,  87, 244, 150, 177, 183,  92, 139, 213,  84, \r
-    121, 223, 170, 246,  62, 163, 241,  17, 202, 245, 209,  23, 123, 147, 131, 188, \r
-    189,  82,  30, 235, 174, 204, 214,  53,   8, 200, 138, 180, 226, 205, 191, 217, \r
-    208,  80,  89,  63,  77,  98,  52,  10,  72, 136, 181,  86,  76,  46, 107, 158, \r
-    210,  61,  60,   3,  19, 251, 151,  81, 117,  74, 145, 113,  35, 190, 118,  42, \r
-     95, 249, 212,  85,  11, 220,  55,  49,  22, 116, 215, 119, 167, 230,   7, 219, \r
-    164,  47,  70, 243,  97,  69, 103, 227,  12, 162,  59,  28, 133,  24,   4,  29, \r
-     41, 160, 143, 178,  90, 216, 166, 126, 238, 141,  83,  75, 161, 154, 193,  14, \r
-    122,  73, 165,  44, 129, 196, 199,  54,  43, 127,  67, 149,  51, 242, 108, 104, \r
-    109, 240,   2,  40, 206, 221, 155, 234,  94, 153, 124,  20, 134, 207, 229,  66, \r
-    184,  64, 120,  45,  58, 233, 100,  31, 146, 144, 125,  57, 111, 224, 137,  48\r
-};\r
-\r
-u4byte *safer_set_key(SaferContext *ctx,\r
-                     const u4byte in_key[], const u4byte key_len)\r
-{   \r
-    u1byte  by, lk[33];\r
-    u4byte  i, j, k, l, m;\r
-    u1byte *l_key = ctx->l_key;\r
-\r
-    get_key(lk, key_len);\r
-\r
-    ctx->k_bytes = k_bytes = key_len / 8; lk[k_bytes] = 0;\r
-\r
-    for(i = 0; i < k_bytes; ++i)\r
-    {\r
-        lk[k_bytes] ^= lk[i]; l_key[i] = lk[i];\r
-    }\r
-\r
-    for(i = 0; i < k_bytes; ++i)\r
-    {\r
-        for(j = 0; j <= k_bytes; ++j)\r
-        {\r
-            by = lk[j]; lk[j] = by << 3 | by >> 5;\r
-        }\r
-\r
-        k = 17 * i + 35; l = 16 * i + 16; m = i + 1;\r
-\r
-        if(i < 16)\r
-        {\r
-            for(j = 0; j < 16; ++j)\r
-            {\r
-                l_key[l + j] = lk[m] + expf[expf[(k + j) & 255]];\r
-\r
-                m = (m == k_bytes ? 0 : m + 1);\r
-            }\r
-        }\r
-        else\r
-        {\r
-            for(j = 0; j < 16; ++j)\r
-            {\r
-                l_key[l + j] = lk[m] + expf[(k + j) & 255];\r
-\r
-                m = (m == k_bytes ? 0 : m + 1);\r
-            }\r
-        }\r
-    }\r
-    return (u4byte*)l_key;\r
-};\r
-\r
-void do_fr(u1byte x[16], u1byte *kp)\r
-{   u1byte  t;\r
-\r
-    x[ 0] = expf[x[ 0] ^ kp[ 0]] + kp[16];\r
-    x[ 1] = logf[x[ 1] + kp[ 1]] ^ kp[17]; \r
-    x[ 2] = logf[x[ 2] + kp[ 2]] ^ kp[18]; \r
-    x[ 3] = expf[x[ 3] ^ kp[ 3]] + kp[19];\r
-\r
-    x[ 4] = expf[x[ 4] ^ kp[ 4]] + kp[20];\r
-    x[ 5] = logf[x[ 5] + kp[ 5]] ^ kp[21]; \r
-    x[ 6] = logf[x[ 6] + kp[ 6]] ^ kp[22]; \r
-    x[ 7] = expf[x[ 7] ^ kp[ 7]] + kp[23];\r
\r
-    x[ 8] = expf[x[ 8] ^ kp[ 8]] + kp[24];\r
-    x[ 9] = logf[x[ 9] + kp[ 9]] ^ kp[25]; \r
-    x[10] = logf[x[10] + kp[10]] ^ kp[26]; \r
-    x[11] = expf[x[11] ^ kp[11]] + kp[27];\r
-\r
-    x[12] = expf[x[12] ^ kp[12]] + kp[28];\r
-    x[13] = logf[x[13] + kp[13]] ^ kp[29]; \r
-    x[14] = logf[x[14] + kp[14]] ^ kp[30]; \r
-    x[15] = expf[x[15] ^ kp[15]] + kp[31];\r
-\r
-    x[ 1] += x[ 0]; x[ 0] += x[ 1];\r
-    x[ 3] += x[ 2]; x[ 2] += x[ 3];\r
-    x[ 5] += x[ 4]; x[ 4] += x[ 5];\r
-    x[ 7] += x[ 6]; x[ 6] += x[ 7];\r
-    x[ 9] += x[ 8]; x[ 8] += x[ 9];\r
-    x[11] += x[10]; x[10] += x[11];\r
-    x[13] += x[12]; x[12] += x[13];\r
-    x[15] += x[14]; x[14] += x[15];\r
-\r
-    x[ 7] += x[ 0]; x[ 0] += x[ 7];\r
-    x[ 1] += x[ 2]; x[ 2] += x[ 1];\r
-    x[ 3] += x[ 4]; x[ 4] += x[ 3];\r
-    x[ 5] += x[ 6]; x[ 6] += x[ 5];\r
-    x[11] += x[ 8]; x[ 8] += x[11];\r
-    x[ 9] += x[10]; x[10] += x[ 9];\r
-    x[15] += x[12]; x[12] += x[15];\r
-    x[13] += x[14]; x[14] += x[13];\r
-\r
-    x[ 3] += x[ 0]; x[ 0] += x[ 3];\r
-    x[15] += x[ 2]; x[ 2] += x[15];\r
-    x[ 7] += x[ 4]; x[ 4] += x[ 7];\r
-    x[ 1] += x[ 6]; x[ 6] += x[ 1];\r
-    x[ 5] += x[ 8]; x[ 8] += x[ 5];\r
-    x[13] += x[10]; x[10] += x[13];\r
-    x[11] += x[12]; x[12] += x[11];\r
-    x[ 9] += x[14]; x[14] += x[ 9];\r
-\r
-    x[13] += x[ 0]; x[ 0] += x[13];\r
-    x[ 5] += x[ 2]; x[ 2] += x[ 5];\r
-    x[ 9] += x[ 4]; x[ 4] += x[ 9];\r
-    x[11] += x[ 6]; x[ 6] += x[11];\r
-    x[15] += x[ 8]; x[ 8] += x[15];\r
-    x[ 1] += x[10]; x[10] += x[ 1];\r
-    x[ 3] += x[12]; x[12] += x[ 3];\r
-    x[ 7] += x[14]; x[14] += x[ 7];\r
-\r
-    t = x[0]; x[0] = x[14]; x[14] = x[12]; x[12] = x[10]; x[10] = x[2]; \r
-    x[2] = x[8]; x[8] = x[4]; x[4] = t;\r
-\r
-    t = x[1]; x[1] = x[7]; x[7] = x[11]; x[11] = x[5]; x[5] = x[13]; x[13] = t; \r
-    \r
-    t = x[15]; x[15] = x[3]; x[3] = t;\r
-};\r
-\r
-void do_ir(u1byte x[16], u1byte *kp)\r
-{   u1byte  t;\r
-\r
-    t = x[3]; x[3] = x[15]; x[15] = t; \r
-\r
-    t = x[13]; x[13] = x[5]; x[5] = x[11]; x[11] = x[7]; x[7] = x[1]; x[1] = t; \r
-\r
-    t = x[4]; x[4] = x[8]; x[8] = x[2]; x[2] = x[10]; \r
-    x[10] = x[12]; x[12] = x[14]; x[14] = x[0]; x[0] = t; \r
-\r
-    x[14] -= x[ 7]; x[ 7] -= x[14]; \r
-    x[12] -= x[ 3]; x[ 3] -= x[12];\r
-    x[10] -= x[ 1]; x[ 1] -= x[10];\r
-    x[ 8] -= x[15]; x[15] -= x[ 8];\r
-    x[ 6] -= x[11]; x[11] -= x[ 6]; \r
-    x[ 4] -= x[ 9]; x[ 9] -= x[ 4];\r
-    x[ 2] -= x[ 5]; x[ 5] -= x[ 2]; \r
-    x[ 0] -= x[13]; x[13] -= x[ 0]; \r
-\r
-    x[14] -= x[ 9]; x[ 9] -= x[14]; \r
-    x[12] -= x[11]; x[11] -= x[12]; \r
-    x[10] -= x[13]; x[13] -= x[10]; \r
-    x[ 8] -= x[ 5]; x[ 5] -= x[ 8]; \r
-    x[ 6] -= x[ 1]; x[ 1] -= x[ 6]; \r
-    x[ 4] -= x[ 7]; x[ 7] -= x[ 4]; \r
-    x[ 2] -= x[15]; x[15] -= x[ 2]; \r
-    x[ 0] -= x[ 3]; x[ 3] -= x[ 0]; \r
-\r
-    x[14] -= x[13]; x[13] -= x[14]; \r
-    x[12] -= x[15]; x[15] -= x[12]; \r
-    x[10] -= x[ 9]; x[ 9] -= x[10]; \r
-    x[ 8] -= x[11]; x[11] -= x[ 8];     \r
-    x[ 6] -= x[ 5]; x[ 5] -= x[ 6]; \r
-    x[ 4] -= x[ 3]; x[ 3] -= x[ 4]; \r
-    x[ 2] -= x[ 1]; x[ 1] -= x[ 2]; \r
-    x[ 0] -= x[ 7]; x[ 7] -= x[ 0]; \r
-\r
-    x[14] -= x[15]; x[15] -= x[14]; \r
-    x[12] -= x[13]; x[13] -= x[12];\r
-    x[10] -= x[11]; x[11] -= x[10]; \r
-    x[ 8] -= x[ 9]; x[ 9] -= x[ 8]; \r
-    x[ 6] -= x[ 7]; x[ 7] -= x[ 6];\r
-    x[ 4] -= x[ 5]; x[ 5] -= x[ 4]; \r
-    x[ 2] -= x[ 3]; x[ 3] -= x[ 2]; \r
-    x[ 0] -= x[ 1]; x[ 1] -= x[ 0]; \r
-    \r
-    x[ 0] = logf[x[ 0] - kp[16] + 256] ^ kp[ 0];\r
-    x[ 1] = expf[x[ 1] ^ kp[17]] - kp[ 1];\r
-    x[ 2] = expf[x[ 2] ^ kp[18]] - kp[ 2];\r
-    x[ 3] = logf[x[ 3] - kp[19] + 256] ^ kp[ 3];\r
-\r
-    x[ 4] = logf[x[ 4] - kp[20] + 256] ^ kp[ 4];\r
-    x[ 5] = expf[x[ 5] ^ kp[21]] - kp[ 5];\r
-    x[ 6] = expf[x[ 6] ^ kp[22]] - kp[ 6];\r
-    x[ 7] = logf[x[ 7] - kp[23] + 256] ^ kp[ 7];\r
-\r
-    x[ 8] = logf[x[ 8] - kp[24] + 256] ^ kp[ 8];\r
-    x[ 9] = expf[x[ 9] ^ kp[25]] - kp[ 9];\r
-    x[10] = expf[x[10] ^ kp[26]] - kp[10];\r
-    x[11] = logf[x[11] - kp[27] + 256] ^ kp[11];\r
-\r
-    x[12] = logf[x[12] - kp[28] + 256] ^ kp[12];\r
-    x[13] = expf[x[13] ^ kp[29]] - kp[13];\r
-    x[14] = expf[x[14] ^ kp[30]] - kp[14];\r
-    x[15] = logf[x[15] - kp[31] + 256] ^ kp[15];\r
-};\r
-\r
-void safer_encrypt(SaferContext *ctx,\r
-                  const u4byte in_blk[4], u4byte out_blk[4])\r
-{   \r
-    u1byte  blk[16], *kp;\r
-    u1byte *l_key = ctx->l_key;\r
-    u4byte k_bytes = ctx->k_bytes;\r
-\r
-    get_block(blk);\r
-\r
-    do_fr(blk, l_key);       do_fr(blk, l_key +  32); \r
-    do_fr(blk, l_key +  64); do_fr(blk, l_key +  96);\r
-    do_fr(blk, l_key + 128); do_fr(blk, l_key + 160);\r
-    do_fr(blk, l_key + 192); do_fr(blk, l_key + 224);\r
-    \r
-    if(k_bytes > 16)\r
-    {\r
-        do_fr(blk, l_key + 256); do_fr(blk, l_key + 288); \r
-        do_fr(blk, l_key + 320); do_fr(blk, l_key + 352);\r
-    }\r
-\r
-    if(k_bytes > 24)\r
-    {\r
-        do_fr(blk, l_key + 384); do_fr(blk, l_key + 416); \r
-        do_fr(blk, l_key + 448); do_fr(blk, l_key + 480);\r
-    }\r
-\r
-    kp = l_key + 16 * k_bytes;\r
-\r
-    blk[ 0] ^= kp[ 0]; blk[ 1] += kp[ 1];\r
-    blk[ 2] += kp[ 2]; blk[ 3] ^= kp[ 3]; \r
-    blk[ 4] ^= kp[ 4]; blk[ 5] += kp[ 5];\r
-    blk[ 6] += kp[ 6]; blk[ 7] ^= kp[ 7]; \r
-    blk[ 8] ^= kp[ 8]; blk[ 9] += kp[ 9];\r
-    blk[10] += kp[10]; blk[11] ^= kp[11]; \r
-    blk[12] ^= kp[12]; blk[13] += kp[13];\r
-    blk[14] += kp[14]; blk[15] ^= kp[15]; \r
-\r
-    put_block(blk);\r
-};\r
-\r
-void safer_decrypt(SaferContext *ctx,\r
-                  const u4byte in_blk[4], u4byte out_blk[4])\r
-{   \r
-    u1byte  blk[16], *kp;\r
-    u1byte *l_key = ctx->l_key;\r
-    u4byte k_bytes = ctx->k_bytes;\r
-\r
-    get_block(blk);\r
-\r
-    kp = l_key + 16 * k_bytes;\r
-\r
-    blk[ 0] ^= kp[ 0]; blk[ 1] -= kp[ 1];\r
-    blk[ 2] -= kp[ 2]; blk[ 3] ^= kp[ 3];\r
-    blk[ 4] ^= kp[ 4]; blk[ 5] -= kp[ 5];\r
-    blk[ 6] -= kp[ 6]; blk[ 7] ^= kp[ 7];\r
-    blk[ 8] ^= kp[ 8]; blk[ 9] -= kp[ 9];\r
-    blk[10] -= kp[10]; blk[11] ^= kp[11];\r
-    blk[12] ^= kp[12]; blk[13] -= kp[13];\r
-    blk[14] -= kp[14]; blk[15] ^= kp[15];\r
-\r
-    if(k_bytes > 24)\r
-    {\r
-        do_ir(blk, l_key + 480); do_ir(blk, l_key + 448); \r
-        do_ir(blk, l_key + 416); do_ir(blk, l_key + 384);\r
-    }\r
-\r
-    if(k_bytes > 16)\r
-    {\r
-        do_ir(blk, l_key + 352); do_ir(blk, l_key + 320); \r
-        do_ir(blk, l_key + 288); do_ir(blk, l_key + 256);\r
-    }\r
-\r
-    do_ir(blk, l_key + 224); do_ir(blk, l_key + 192); \r
-    do_ir(blk, l_key + 160); do_ir(blk, l_key + 128);\r
-    do_ir(blk, l_key +  96); do_ir(blk, l_key +  64); \r
-    do_ir(blk, l_key +  32); do_ir(blk, l_key);\r
-\r
-    put_block(blk);\r
-};\r
diff --git a/lib/silccrypt/safer.h b/lib/silccrypt/safer.h
deleted file mode 100644 (file)
index 106b4ea..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
-
-  safer.h
-
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
-
-  Copyright (C) 1997 - 2000 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
-  GNU General Public License for more details.
-
-*/
-/*
- * $Id$
- * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
- *     Importet from internal CVS/Added Log headers.
- *
- *
- */
-
-#ifndef SAFER_H
-#define SAFER_H
-
-#include "safer_internal.h"
-
-/* 
- * SILC Crypto API for Safer
- */
-
-/* Sets the key for the cipher. */
-
-inline int silc_safer_init(void *context, 
-                          const unsigned char *key, 
-                          size_t keylen)
-{
-  safer_set_key((SaferContext *)context, (unsigned int *)key, keylen);
-  return 1;
-}
-
-/* Sets the string as a new key for the cipher. The string is first
-   hashed and then used as a new key. */
-
-inline int silc_safer_set_string_as_key(void *context, 
-                                       const unsigned char *string,
-                                       size_t keylen)
-{
-  /*  unsigned char key[md5_hash_len];
-  SilcMarsContext *ctx = (SilcMarsContext *)context;
-
-  make_md5_hash(string, &key);
-  memcpy(&ctx->key, mars_set_key(&key, keylen), keylen);
-  memset(&key, 'F', sizeoof(key));
-  */
-
-  return 1;
-}
-
-/* Returns the size of the cipher context. */
-
-inline size_t silc_safer_context_len()
-{
-  return sizeof(SaferContext);
-}
-
-/* Encrypts with the cipher in CBC mode. */
-
-inline int silc_safer_encrypt_cbc(void *context,
-                                 const unsigned char *src,
-                                 unsigned char *dst,
-                                 size_t len,
-                                 unsigned char *iv)
-{
-  unsigned int *in, *out, *tiv;
-  unsigned int tmp[4];
-  int i;
-
-  in = (unsigned int *)src;
-  out = (unsigned int *)dst;
-  tiv = (unsigned int *)iv;
-
-  tmp[0] = in[0] ^ tiv[0];
-  tmp[1] = in[1] ^ tiv[1];
-  tmp[2] = in[2] ^ tiv[2];
-  tmp[3] = in[3] ^ tiv[3];
-  safer_encrypt((SaferContext *)context, tmp, out);
-  in += 4;
-  out += 4;
-
-  for (i = 16; i < len; i += 16) {
-    tmp[0] = in[0] ^ out[0 - 4];
-    tmp[1] = in[1] ^ out[1 - 4];
-    tmp[2] = in[2] ^ out[2 - 4];
-    tmp[3] = in[3] ^ out[3 - 4];
-    safer_encrypt((SaferContext *)context, tmp, out);
-    in += 4;
-    out += 4;
-  }
-
-  return 1;
-}
-
-/* Decrypts with the cipher in CBC mode. */
-
-inline int silc_safer_decrypt_cbc(void *context,
-                                 const unsigned char *src,
-                                 unsigned char *dst,
-                                 size_t len,
-                                 unsigned char *iv)
-{
-  unsigned int *in, *out, *tiv;
-  int i;
-
-  in = (unsigned int *)src;
-  out = (unsigned int *)dst;
-  tiv = (unsigned int *)iv;
-
-  safer_decrypt((SaferContext *)context, in, out);
-  out[0] ^= tiv[0];
-  out[1] ^= tiv[1];
-  out[2] ^= tiv[2];
-  out[3] ^= tiv[3];
-  in += 4;
-  out += 4;
-
-  for (i = 16; i < len; i += 16) {
-    safer_decrypt((SaferContext *)context, in, out);
-    out[0] ^= in[0 - 4];
-    out[1] ^= in[1 - 4];
-    out[2] ^= in[2 - 4];
-    out[3] ^= in[3 - 4];
-    in += 4;
-    out += 4;
-  }
-
-  return 1;
-}
-
-#endif
diff --git a/lib/silccrypt/safer_internal.h b/lib/silccrypt/safer_internal.h
deleted file mode 100644 (file)
index ee3bb1b..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
-
-  safer_internal.h
-
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
-
-  Copyright (C) 1997 - 2000 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
-  GNU General Public License for more details.
-
-*/
-
-#ifndef SAFER_INTERNAL_H
-#define SAFER_INTERNAL_H
-
-/* Cipher's context */
-typedef struct {
-  u1byte l_key[33 * 16];
-  u4byte k_bytes;
-} SaferContext;
-
-/* Prototypes */
-u4byte *safer_set_key(SaferContext *ctx,
-                     const u4byte in_key[], const u4byte key_len);
-void safer_encrypt(SaferContext *ctx,
-                  const u4byte in_blk[4], u4byte out_blk[4]);
-void safer_decrypt(SaferContext *ctx,
-                  const u4byte in_blk[4], u4byte out_blk[4]);
-
-#endif
diff --git a/lib/silccrypt/serpent.c b/lib/silccrypt/serpent.c
deleted file mode 100644 (file)
index 63640c8..0000000
+++ /dev/null
@@ -1,657 +0,0 @@
-/* Modified for SILC. -Pekka */x\r
-\r
-/* This is an independent implementation of the encryption algorithm:   */\r
-/*                                                                      */\r
-/*         Serpent by Ross Anderson, Eli Biham and Lars Knudsen         */\r
-/*                                                                      */\r
-/* which is a candidate algorithm in the Advanced Encryption Standard   */\r
-/* programme of the US National Institute of Standards and Technology.  */\r
-/*                                                                      */\r
-/* Copyright in this implementation is held by Dr B R Gladman but I     */\r
-/* hereby give permission for its free direct or derivative use subject */\r
-/* to acknowledgment of its origin and compliance with any conditions   */\r
-/* that the originators of the algorithm place on its exploitation.     */\r
-/*                                                                      */\r
-/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999     */\r
-\r
-/* Timing data for Serpent (serpent.c)\r
-\r
-Core timing without I/O endian conversion:\r
-\r
-128 bit key:\r
-Key Setup:    2402 cycles\r
-Encrypt:       952 cycles =    26.9 mbits/sec\r
-Decrypt:       914 cycles =    28.0 mbits/sec\r
-Mean:          933 cycles =    27.4 mbits/sec\r
-\r
-192 bit key:\r
-Key Setup:    2449 cycles\r
-Encrypt:       952 cycles =    26.9 mbits/sec\r
-Decrypt:       914 cycles =    28.0 mbits/sec\r
-Mean:          933 cycles =    27.4 mbits/sec\r
-\r
-256 bit key:\r
-Key Setup:    2349 cycles\r
-Encrypt:       952 cycles =    26.9 mbits/sec\r
-Decrypt:       914 cycles =    28.0 mbits/sec\r
-Mean:          933 cycles =    27.4 mbits/sec\r
-\r
-Full timing with I/O endian conversion:\r
-\r
-128 bit key:\r
-Key Setup:    2415 cycles\r
-Encrypt:       985 cycles =    26.0 mbits/sec\r
-Decrypt:       954 cycles =    26.8 mbits/sec\r
-Mean:          970 cycles =    26.4 mbits/sec\r
-\r
-192 bit key:\r
-Key Setup:    2438 cycles\r
-Encrypt:       985 cycles =    26.0 mbits/sec\r
-Decrypt:       954 cycles =    26.8 mbits/sec\r
-Mean:          970 cycles =    26.4 mbits/sec\r
-\r
-256 bit key:\r
-Key Setup:    2463 cycles\r
-Encrypt:       985 cycles =    26.0 mbits/sec\r
-Decrypt:       954 cycles =    26.8 mbits/sec\r
-Mean:          970 cycles =    26.4 mbits/sec\r
-\r
-*/\r
-\r
-#include <stdio.h>\r
-#include <sys/types.h>\r
-#include "serpent_internal.h"\r
-\r
-/* Partially optimised Serpent S Box boolean functions derived  */\r
-/* using a recursive descent analyser but without a full search */\r
-/* of all subtrees. This set of S boxes is the result of work   */\r
-/* by Sam Simpson and Brian Gladman using the spare time on a   */\r
-/* cluster of high capacity servers to search for S boxes with  */\r
-/* this customised search engine.                               */\r
-/*                                                              */\r
-/* Copyright:   Dr B. R Gladman (gladman@seven77.demon.co.uk)   */\r
-/*              and Sam Simpson (s.simpson@mia.co.uk)           */ \r
-/*              17th December 1998                              */\r
-/*                                                              */\r
-/* We hereby give permission for information in this file to be */\r
-/* used freely subject only to acknowledgement of its origin    */\r
-\r
-/* 15 terms */\r
-\r
-#define sb0(a,b,c,d,e,f,g,h)    \\r
-    t1 = a ^ d;     \\r
-    t2 = a & d;     \\r
-    t3 = c ^ t1;    \\r
-    t6 = b & t1;    \\r
-    t4 = b ^ t3;    \\r
-    t10 = ~t3;      \\r
-    h = t2 ^ t4;    \\r
-    t7 = a ^ t6;    \\r
-    t14 = ~t7;      \\r
-    t8 = c | t7;    \\r
-    t11 = t3 ^ t7;  \\r
-    g = t4 ^ t8;    \\r
-    t12 = h & t11;  \\r
-    f = t10 ^ t12;  \\r
-    e = t12 ^ t14\r
-\r
-/* 15 terms */\r
-\r
-#define ib0(a,b,c,d,e,f,g,h)    \\r
-    t1 = ~a;        \\r
-    t2 = a ^ b;     \\r
-    t3 = t1 | t2;   \\r
-    t4 = d ^ t3;    \\r
-    t7 = d & t2;    \\r
-    t5 = c ^ t4;    \\r
-    t8 = t1 ^ t7;   \\r
-    g = t2 ^ t5;    \\r
-    t11 = a & t4;   \\r
-    t9 = g & t8;    \\r
-    t14 = t5 ^ t8;  \\r
-    f = t4 ^ t9;    \\r
-    t12 = t5 | f;   \\r
-    h = t11 ^ t12;  \\r
-    e = h ^ t14\r
-\r
-/* 14 terms!  */\r
-\r
-#define sb1(a,b,c,d,e,f,g,h)    \\r
-    t1 = ~a;        \\r
-    t2 = b ^ t1;    \\r
-    t3 = a | t2;    \\r
-    t4 = d | t2;    \\r
-    t5 = c ^ t3;    \\r
-    g = d ^ t5;     \\r
-    t7 = b ^ t4;    \\r
-    t8 = t2 ^ g;    \\r
-    t9 = t5 & t7;   \\r
-    h = t8 ^ t9;    \\r
-    t11 = t5 ^ t7;  \\r
-    f = h ^ t11;    \\r
-    t13 = t8 & t11; \\r
-    e = t5 ^ t13\r
-\r
-/* 17 terms */\r
-\r
-#define ib1(a,b,c,d,e,f,g,h)    \\r
-    t1 = a ^ d;     \\r
-    t2 = a & b;     \\r
-    t3 = b ^ c;     \\r
-    t4 = a ^ t3;    \\r
-    t5 = b | d;     \\r
-    t7 = c | t1;    \\r
-    h = t4 ^ t5;    \\r
-    t8 = b ^ t7;    \\r
-    t11 = ~t2;      \\r
-    t9 = t4 & t8;   \\r
-    f = t1 ^ t9;    \\r
-    t13 = t9 ^ t11; \\r
-    t12 = h & f;    \\r
-    g = t12 ^ t13;  \\r
-    t15 = a & d;    \\r
-    t16 = c ^ t13;  \\r
-    e = t15 ^ t16\r
-\r
-/* 16 terms */\r
-\r
-#define sb2(a,b,c,d,e,f,g,h)    \\r
-    t1 = ~a;        \\r
-    t2 = b ^ d;     \\r
-    t3 = c & t1;    \\r
-    t13 = d | t1;   \\r
-    e = t2 ^ t3;    \\r
-    t5 = c ^ t1;    \\r
-    t6 = c ^ e;     \\r
-    t7 = b & t6;    \\r
-    t10 = e | t5;   \\r
-    h = t5 ^ t7;    \\r
-    t9 = d | t7;    \\r
-    t11 = t9 & t10; \\r
-    t14 = t2 ^ h;   \\r
-    g = a ^ t11;    \\r
-    t15 = g ^ t13;  \\r
-    f = t14 ^ t15\r
-\r
-/* 16 terms */\r
-\r
-#define ib2(a,b,c,d,e,f,g,h)    \\r
-    t1 = b ^ d;     \\r
-    t2 = ~t1;       \\r
-    t3 = a ^ c;     \\r
-    t4 = c ^ t1;    \\r
-    t7 = a | t2;    \\r
-    t5 = b & t4;    \\r
-    t8 = d ^ t7;    \\r
-    t11 = ~t4;      \\r
-    e = t3 ^ t5;    \\r
-    t9 = t3 | t8;   \\r
-    t14 = d & t11;  \\r
-    h = t1 ^ t9;    \\r
-    t12 = e | h;    \\r
-    f = t11 ^ t12;  \\r
-    t15 = t3 ^ t12; \\r
-    g = t14 ^ t15\r
-\r
-/* 17 terms */\r
-\r
-#define sb3(a,b,c,d,e,f,g,h)    \\r
-    t1 = a ^ c;     \\r
-    t2 = d ^ t1;    \\r
-    t3 = a & t2;    \\r
-    t4 = d ^ t3;    \\r
-    t5 = b & t4;    \\r
-    g = t2 ^ t5;    \\r
-    t7 = a | g;     \\r
-    t8 = b | d;     \\r
-    t11 = a | d;    \\r
-    t9 = t4 & t7;   \\r
-    f = t8 ^ t9;    \\r
-    t12 = b ^ t11;  \\r
-    t13 = g ^ t9;   \\r
-    t15 = t3 ^ t8;  \\r
-    h = t12 ^ t13;  \\r
-    t16 = c & t15;  \\r
-    e = t12 ^ t16\r
-\r
-/* 16 term solution that performs less well than 17 term one\r
-   in my environment (PPro/PII)                                  \r
-\r
-#define sb3(a,b,c,d,e,f,g,h)    \\r
-    t1 = a ^ b;     \\r
-    t2 = a & c;     \\r
-    t3 = a | d;     \\r
-    t4 = c ^ d;     \\r
-    t5 = t1 & t3;   \\r
-    t6 = t2 | t5;   \\r
-    g = t4 ^ t6;    \\r
-    t8 = b ^ t3;    \\r
-    t9 = t6 ^ t8;   \\r
-    t10 = t4 & t9;  \\r
-    e = t1 ^ t10;   \\r
-    t12 = g & e;    \\r
-    f = t9 ^ t12;   \\r
-    t14 = b | d;    \\r
-    t15 = t4 ^ t12; \\r
-    h = t14 ^ t15\r
-*/\r
-\r
-/* 17 terms */\r
-\r
-#define ib3(a,b,c,d,e,f,g,h)    \\r
-    t1 = b ^ c;     \\r
-    t2 = b | c;     \\r
-    t3 = a ^ c;     \\r
-    t7 = a ^ d;     \\r
-    t4 = t2 ^ t3;   \\r
-    t5 = d | t4;    \\r
-    t9 = t2 ^ t7;   \\r
-    e = t1 ^ t5;    \\r
-    t8 = t1 | t5;   \\r
-    t11 = a & t4;   \\r
-    g = t8 ^ t9;    \\r
-    t12 = e | t9;   \\r
-    f = t11 ^ t12;  \\r
-    t14 = a & g;    \\r
-    t15 = t2 ^ t14; \\r
-    t16 = e & t15;  \\r
-    h = t4 ^ t16\r
-\r
-/* 15 terms */\r
-\r
-#define sb4(a,b,c,d,e,f,g,h)    \\r
-    t1 = a ^ d;     \\r
-    t2 = d & t1;    \\r
-    t3 = c ^ t2;    \\r
-    t4 = b | t3;    \\r
-    h = t1 ^ t4;    \\r
-    t6 = ~b;        \\r
-    t7 = t1 | t6;   \\r
-    e = t3 ^ t7;    \\r
-    t9 = a & e;     \\r
-    t10 = t1 ^ t6;  \\r
-    t11 = t4 & t10; \\r
-    g = t9 ^ t11;   \\r
-    t13 = a ^ t3;   \\r
-    t14 = t10 & g;  \\r
-    f = t13 ^ t14\r
-\r
-/* 17 terms */\r
-\r
-#define ib4(a,b,c,d,e,f,g,h)    \\r
-    t1 = c ^ d;     \\r
-    t2 = c | d;     \\r
-    t3 = b ^ t2;    \\r
-    t4 = a & t3;    \\r
-    f = t1 ^ t4;    \\r
-    t6 = a ^ d;     \\r
-    t7 = b | d;     \\r
-    t8 = t6 & t7;   \\r
-    h = t3 ^ t8;    \\r
-    t10 = ~a;       \\r
-    t11 = c ^ h;    \\r
-    t12 = t10 | t11;\\r
-    e = t3 ^ t12;   \\r
-    t14 = c | t4;   \\r
-    t15 = t7 ^ t14; \\r
-    t16 = h | t10;  \\r
-    g = t15 ^ t16\r
-\r
-/* 16 terms */\r
-\r
-#define sb5(a,b,c,d,e,f,g,h)    \\r
-    t1 = ~a;        \\r
-    t2 = a ^ b;     \\r
-    t3 = a ^ d;     \\r
-    t4 = c ^ t1;    \\r
-    t5 = t2 | t3;   \\r
-    e = t4 ^ t5;    \\r
-    t7 = d & e;     \\r
-    t8 = t2 ^ e;    \\r
-    t10 = t1 | e;   \\r
-    f = t7 ^ t8;    \\r
-    t11 = t2 | t7;  \\r
-    t12 = t3 ^ t10; \\r
-    t14 = b ^ t7;   \\r
-    g = t11 ^ t12;  \\r
-    t15 = f & t12;  \\r
-    h = t14 ^ t15\r
-\r
-/* 16 terms */\r
-\r
-#define ib5(a,b,c,d,e,f,g,h)    \\r
-    t1 = ~c;        \\r
-    t2 = b & t1;    \\r
-    t3 = d ^ t2;    \\r
-    t4 = a & t3;    \\r
-    t5 = b ^ t1;    \\r
-    h = t4 ^ t5;    \\r
-    t7 = b | h;     \\r
-    t8 = a & t7;    \\r
-    f = t3 ^ t8;    \\r
-    t10 = a | d;    \\r
-    t11 = t1 ^ t7;  \\r
-    e = t10 ^ t11;  \\r
-    t13 = a ^ c;    \\r
-    t14 = b & t10;  \\r
-    t15 = t4 | t13; \\r
-    g = t14 ^ t15\r
-\r
-/* 15 terms */\r
-\r
-#define sb6(a,b,c,d,e,f,g,h)    \\r
-    t1 = ~a;        \\r
-    t2 = a ^ d;     \\r
-    t3 = b ^ t2;    \\r
-    t4 = t1 | t2;   \\r
-    t5 = c ^ t4;    \\r
-    f = b ^ t5;     \\r
-    t13 = ~t5;      \\r
-    t7 = t2 | f;    \\r
-    t8 = d ^ t7;    \\r
-    t9 = t5 & t8;   \\r
-    g = t3 ^ t9;    \\r
-    t11 = t5 ^ t8;  \\r
-    e = g ^ t11;    \\r
-    t14 = t3 & t11; \\r
-    h = t13 ^ t14\r
-\r
-/* 15 terms */\r
-\r
-#define ib6(a,b,c,d,e,f,g,h)    \\r
-    t1 = ~a;        \\r
-    t2 = a ^ b;     \\r
-    t3 = c ^ t2;    \\r
-    t4 = c | t1;    \\r
-    t5 = d ^ t4;    \\r
-    t13 = d & t1;   \\r
-    f = t3 ^ t5;    \\r
-    t7 = t3 & t5;   \\r
-    t8 = t2 ^ t7;   \\r
-    t9 = b | t8;    \\r
-    h = t5 ^ t9;    \\r
-    t11 = b | h;    \\r
-    e = t8 ^ t11;   \\r
-    t14 = t3 ^ t11; \\r
-    g = t13 ^ t14\r
-\r
-/* 17 terms */\r
-\r
-#define sb7(a,b,c,d,e,f,g,h)    \\r
-    t1 = ~c;        \\r
-    t2 = b ^ c;     \\r
-    t3 = b | t1;    \\r
-    t4 = d ^ t3;    \\r
-    t5 = a & t4;    \\r
-    t7 = a ^ d;     \\r
-    h = t2 ^ t5;    \\r
-    t8 = b ^ t5;    \\r
-    t9 = t2 | t8;   \\r
-    t11 = d & t3;   \\r
-    f = t7 ^ t9;    \\r
-    t12 = t5 ^ f;   \\r
-    t15 = t1 | t4;  \\r
-    t13 = h & t12;  \\r
-    g = t11 ^ t13;  \\r
-    t16 = t12 ^ g;  \\r
-    e = t15 ^ t16\r
-\r
-/* 17 terms */\r
-\r
-#define ib7(a,b,c,d,e,f,g,h)    \\r
-    t1 = a & b;     \\r
-    t2 = a | b;     \\r
-    t3 = c | t1;    \\r
-    t4 = d & t2;    \\r
-    h = t3 ^ t4;    \\r
-    t6 = ~d;        \\r
-    t7 = b ^ t4;    \\r
-    t8 = h ^ t6;    \\r
-    t11 = c ^ t7;   \\r
-    t9 = t7 | t8;   \\r
-    f = a ^ t9;     \\r
-    t12 = d | f;    \\r
-    e = t11 ^ t12;  \\r
-    t14 = a & h;    \\r
-    t15 = t3 ^ f;   \\r
-    t16 = e ^ t14;  \\r
-    g = t15 ^ t16\r
-\r
-#define k_xor(r,a,b,c,d)    \\r
-    a ^= l_key[4 * r +  8]; \\r
-    b ^= l_key[4 * r +  9]; \\r
-    c ^= l_key[4 * r + 10]; \\r
-    d ^= l_key[4 * r + 11]\r
-\r
-#define k_set(r,a,b,c,d)    \\r
-    a = l_key[4 * r +  8];  \\r
-    b = l_key[4 * r +  9];  \\r
-    c = l_key[4 * r + 10];  \\r
-    d = l_key[4 * r + 11]\r
-\r
-#define k_get(r,a,b,c,d)    \\r
-    l_key[4 * r +  8] = a;  \\r
-    l_key[4 * r +  9] = b;  \\r
-    l_key[4 * r + 10] = c;  \\r
-    l_key[4 * r + 11] = d\r
-\r
-/* the linear transformation and its inverse    */\r
-\r
-#define rot(a,b,c,d)    \\r
-    a = rotl(a, 13);    \\r
-    c = rotl(c, 3);     \\r
-    d ^= c ^ (a << 3);  \\r
-    b ^= a ^ c;         \\r
-    d = rotl(d, 7);     \\r
-    b = rotl(b, 1);     \\r
-    a ^= b ^ d;         \\r
-    c ^= d ^ (b << 7);  \\r
-    a = rotl(a, 5);     \\r
-    c = rotl(c, 22)\r
-\r
-#define irot(a,b,c,d)   \\r
-    c = rotr(c, 22);    \\r
-    a = rotr(a, 5);     \\r
-    c ^= d ^ (b << 7);  \\r
-    a ^= b ^ d;         \\r
-    d = rotr(d, 7);     \\r
-    b = rotr(b, 1);     \\r
-    d ^= c ^ (a << 3);  \\r
-    b ^= a ^ c;         \\r
-    c = rotr(c, 3);     \\r
-    a = rotr(a, 13)\r
-\r
-/* initialise the key schedule from the user supplied key   */\r
-\r
-u4byte *serpent_set_key(SerpentContext *ctx,\r
-                       const u4byte in_key[], const u4byte key_len)\r
-{   \r
-    u4byte  i,lk,a,b,c,d,e,f,g,h;\r
-    u4byte  t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16;\r
-    u4byte *l_key = ctx->l_key;\r
-\r
-    if(key_len < 0 || key_len > 256)\r
-\r
-        return (u4byte*)0;\r
-\r
-    i = 0; lk = (key_len + 31) / 32;\r
-    \r
-    while(i < lk)\r
-    {\r
-#ifdef  BLOCK_SWAP\r
-        l_key[i] = io_swap(in_key[lk - i - 1]);\r
-#else\r
-        l_key[i] = in_key[i];\r
-#endif  \r
-        i++;\r
-    }\r
-\r
-    if(key_len < 256)\r
-    {\r
-        while(i < 8)\r
-\r
-            l_key[i++] = 0;\r
-\r
-        i = key_len / 32; lk = 1 << key_len % 32; \r
-\r
-        l_key[i] = l_key[i] & (lk - 1) | lk;\r
-    }\r
-\r
-    for(i = 0; i < 132; ++i)\r
-    {\r
-        lk = l_key[i] ^ l_key[i + 3] ^ l_key[i + 5] \r
-                                ^ l_key[i + 7] ^ 0x9e3779b9 ^ i;\r
-\r
-        l_key[i + 8] = (lk << 11) | (lk >> 21); \r
-    }\r
-\r
-    k_set( 0,a,b,c,d);sb3(a,b,c,d,e,f,g,h);k_get( 0,e,f,g,h);\r
-    k_set( 1,a,b,c,d);sb2(a,b,c,d,e,f,g,h);k_get( 1,e,f,g,h);\r
-    k_set( 2,a,b,c,d);sb1(a,b,c,d,e,f,g,h);k_get( 2,e,f,g,h);\r
-    k_set( 3,a,b,c,d);sb0(a,b,c,d,e,f,g,h);k_get( 3,e,f,g,h);\r
-    k_set( 4,a,b,c,d);sb7(a,b,c,d,e,f,g,h);k_get( 4,e,f,g,h);\r
-    k_set( 5,a,b,c,d);sb6(a,b,c,d,e,f,g,h);k_get( 5,e,f,g,h);\r
-    k_set( 6,a,b,c,d);sb5(a,b,c,d,e,f,g,h);k_get( 6,e,f,g,h);\r
-    k_set( 7,a,b,c,d);sb4(a,b,c,d,e,f,g,h);k_get( 7,e,f,g,h);\r
-    k_set( 8,a,b,c,d);sb3(a,b,c,d,e,f,g,h);k_get( 8,e,f,g,h);\r
-    k_set( 9,a,b,c,d);sb2(a,b,c,d,e,f,g,h);k_get( 9,e,f,g,h);\r
-    k_set(10,a,b,c,d);sb1(a,b,c,d,e,f,g,h);k_get(10,e,f,g,h);\r
-    k_set(11,a,b,c,d);sb0(a,b,c,d,e,f,g,h);k_get(11,e,f,g,h);\r
-    k_set(12,a,b,c,d);sb7(a,b,c,d,e,f,g,h);k_get(12,e,f,g,h);\r
-    k_set(13,a,b,c,d);sb6(a,b,c,d,e,f,g,h);k_get(13,e,f,g,h);\r
-    k_set(14,a,b,c,d);sb5(a,b,c,d,e,f,g,h);k_get(14,e,f,g,h);\r
-    k_set(15,a,b,c,d);sb4(a,b,c,d,e,f,g,h);k_get(15,e,f,g,h);\r
-    k_set(16,a,b,c,d);sb3(a,b,c,d,e,f,g,h);k_get(16,e,f,g,h);\r
-    k_set(17,a,b,c,d);sb2(a,b,c,d,e,f,g,h);k_get(17,e,f,g,h);\r
-    k_set(18,a,b,c,d);sb1(a,b,c,d,e,f,g,h);k_get(18,e,f,g,h);\r
-    k_set(19,a,b,c,d);sb0(a,b,c,d,e,f,g,h);k_get(19,e,f,g,h);\r
-    k_set(20,a,b,c,d);sb7(a,b,c,d,e,f,g,h);k_get(20,e,f,g,h);\r
-    k_set(21,a,b,c,d);sb6(a,b,c,d,e,f,g,h);k_get(21,e,f,g,h);\r
-    k_set(22,a,b,c,d);sb5(a,b,c,d,e,f,g,h);k_get(22,e,f,g,h);\r
-    k_set(23,a,b,c,d);sb4(a,b,c,d,e,f,g,h);k_get(23,e,f,g,h);\r
-    k_set(24,a,b,c,d);sb3(a,b,c,d,e,f,g,h);k_get(24,e,f,g,h);\r
-    k_set(25,a,b,c,d);sb2(a,b,c,d,e,f,g,h);k_get(25,e,f,g,h);\r
-    k_set(26,a,b,c,d);sb1(a,b,c,d,e,f,g,h);k_get(26,e,f,g,h);\r
-    k_set(27,a,b,c,d);sb0(a,b,c,d,e,f,g,h);k_get(27,e,f,g,h);\r
-    k_set(28,a,b,c,d);sb7(a,b,c,d,e,f,g,h);k_get(28,e,f,g,h);\r
-    k_set(29,a,b,c,d);sb6(a,b,c,d,e,f,g,h);k_get(29,e,f,g,h);\r
-    k_set(30,a,b,c,d);sb5(a,b,c,d,e,f,g,h);k_get(30,e,f,g,h);\r
-    k_set(31,a,b,c,d);sb4(a,b,c,d,e,f,g,h);k_get(31,e,f,g,h);\r
-    k_set(32,a,b,c,d);sb3(a,b,c,d,e,f,g,h);k_get(32,e,f,g,h);\r
-\r
-    return l_key;\r
-};\r
-\r
-/* encrypt a block of text  */\r
-\r
-void serpent_encrypt(SerpentContext *ctx,\r
-                    const u4byte in_blk[4], u4byte out_blk[])\r
-{   \r
-    u4byte  a,b,c,d,e,f,g,h;\r
-    u4byte  t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16;\r
-    u4byte *l_key = ctx->l_key;\r
-\r
-#ifdef  BLOCK_SWAP\r
-    a = io_swap(in_blk[3]); b = io_swap(in_blk[2]); \r
-    c = io_swap(in_blk[1]); d = io_swap(in_blk[0]);\r
-#else\r
-    a = in_blk[0]; b = in_blk[1]; c = in_blk[2]; d = in_blk[3];\r
-#endif\r
-\r
-    k_xor( 0,a,b,c,d); sb0(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
-    k_xor( 1,e,f,g,h); sb1(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
-    k_xor( 2,a,b,c,d); sb2(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
-    k_xor( 3,e,f,g,h); sb3(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
-    k_xor( 4,a,b,c,d); sb4(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
-    k_xor( 5,e,f,g,h); sb5(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
-    k_xor( 6,a,b,c,d); sb6(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
-    k_xor( 7,e,f,g,h); sb7(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
-    k_xor( 8,a,b,c,d); sb0(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
-    k_xor( 9,e,f,g,h); sb1(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
-    k_xor(10,a,b,c,d); sb2(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
-    k_xor(11,e,f,g,h); sb3(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
-    k_xor(12,a,b,c,d); sb4(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
-    k_xor(13,e,f,g,h); sb5(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
-    k_xor(14,a,b,c,d); sb6(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
-    k_xor(15,e,f,g,h); sb7(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
-    k_xor(16,a,b,c,d); sb0(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
-    k_xor(17,e,f,g,h); sb1(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
-    k_xor(18,a,b,c,d); sb2(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
-    k_xor(19,e,f,g,h); sb3(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
-    k_xor(20,a,b,c,d); sb4(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
-    k_xor(21,e,f,g,h); sb5(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
-    k_xor(22,a,b,c,d); sb6(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
-    k_xor(23,e,f,g,h); sb7(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
-    k_xor(24,a,b,c,d); sb0(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
-    k_xor(25,e,f,g,h); sb1(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
-    k_xor(26,a,b,c,d); sb2(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
-    k_xor(27,e,f,g,h); sb3(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
-    k_xor(28,a,b,c,d); sb4(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
-    k_xor(29,e,f,g,h); sb5(e,f,g,h,a,b,c,d); rot(a,b,c,d); \r
-    k_xor(30,a,b,c,d); sb6(a,b,c,d,e,f,g,h); rot(e,f,g,h); \r
-    k_xor(31,e,f,g,h); sb7(e,f,g,h,a,b,c,d); k_xor(32,a,b,c,d); \r
-    \r
-#ifdef  BLOCK_SWAP\r
-    out_blk[3] = io_swap(a); out_blk[2] = io_swap(b); \r
-    out_blk[1] = io_swap(c); out_blk[0] = io_swap(d);\r
-#else\r
-    out_blk[0] = a; out_blk[1] = b; out_blk[2] = c; out_blk[3] = d;\r
-#endif\r
-};\r
-\r
-/* decrypt a block of text  */\r
-\r
-void serpent_decrypt(SerpentContext *ctx,\r
-                    const u4byte in_blk[4], u4byte out_blk[4])\r
-{   \r
-    u4byte  a,b,c,d,e,f,g,h;\r
-    u4byte  t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16;\r
-    u4byte *l_key = ctx->l_key;\r
-    \r
-#ifdef  BLOCK_SWAP\r
-    a = io_swap(in_blk[3]); b = io_swap(in_blk[2]); \r
-    c = io_swap(in_blk[1]); d = io_swap(in_blk[0]);\r
-#else\r
-    a = in_blk[0]; b = in_blk[1]; c = in_blk[2]; d = in_blk[3];\r
-#endif\r
-\r
-    k_xor(32,a,b,c,d); ib7(a,b,c,d,e,f,g,h); k_xor(31,e,f,g,h);\r
-    irot(e,f,g,h); ib6(e,f,g,h,a,b,c,d); k_xor(30,a,b,c,d);\r
-    irot(a,b,c,d); ib5(a,b,c,d,e,f,g,h); k_xor(29,e,f,g,h);\r
-    irot(e,f,g,h); ib4(e,f,g,h,a,b,c,d); k_xor(28,a,b,c,d);\r
-    irot(a,b,c,d); ib3(a,b,c,d,e,f,g,h); k_xor(27,e,f,g,h);\r
-    irot(e,f,g,h); ib2(e,f,g,h,a,b,c,d); k_xor(26,a,b,c,d);\r
-    irot(a,b,c,d); ib1(a,b,c,d,e,f,g,h); k_xor(25,e,f,g,h);\r
-    irot(e,f,g,h); ib0(e,f,g,h,a,b,c,d); k_xor(24,a,b,c,d);\r
-    irot(a,b,c,d); ib7(a,b,c,d,e,f,g,h); k_xor(23,e,f,g,h);\r
-    irot(e,f,g,h); ib6(e,f,g,h,a,b,c,d); k_xor(22,a,b,c,d);\r
-    irot(a,b,c,d); ib5(a,b,c,d,e,f,g,h); k_xor(21,e,f,g,h);\r
-    irot(e,f,g,h); ib4(e,f,g,h,a,b,c,d); k_xor(20,a,b,c,d);\r
-    irot(a,b,c,d); ib3(a,b,c,d,e,f,g,h); k_xor(19,e,f,g,h);\r
-    irot(e,f,g,h); ib2(e,f,g,h,a,b,c,d); k_xor(18,a,b,c,d);\r
-    irot(a,b,c,d); ib1(a,b,c,d,e,f,g,h); k_xor(17,e,f,g,h);\r
-    irot(e,f,g,h); ib0(e,f,g,h,a,b,c,d); k_xor(16,a,b,c,d);\r
-    irot(a,b,c,d); ib7(a,b,c,d,e,f,g,h); k_xor(15,e,f,g,h);\r
-    irot(e,f,g,h); ib6(e,f,g,h,a,b,c,d); k_xor(14,a,b,c,d);\r
-    irot(a,b,c,d); ib5(a,b,c,d,e,f,g,h); k_xor(13,e,f,g,h);\r
-    irot(e,f,g,h); ib4(e,f,g,h,a,b,c,d); k_xor(12,a,b,c,d);\r
-    irot(a,b,c,d); ib3(a,b,c,d,e,f,g,h); k_xor(11,e,f,g,h);\r
-    irot(e,f,g,h); ib2(e,f,g,h,a,b,c,d); k_xor(10,a,b,c,d);\r
-    irot(a,b,c,d); ib1(a,b,c,d,e,f,g,h); k_xor( 9,e,f,g,h);\r
-    irot(e,f,g,h); ib0(e,f,g,h,a,b,c,d); k_xor( 8,a,b,c,d);\r
-    irot(a,b,c,d); ib7(a,b,c,d,e,f,g,h); k_xor( 7,e,f,g,h);\r
-    irot(e,f,g,h); ib6(e,f,g,h,a,b,c,d); k_xor( 6,a,b,c,d);\r
-    irot(a,b,c,d); ib5(a,b,c,d,e,f,g,h); k_xor( 5,e,f,g,h);\r
-    irot(e,f,g,h); ib4(e,f,g,h,a,b,c,d); k_xor( 4,a,b,c,d);\r
-    irot(a,b,c,d); ib3(a,b,c,d,e,f,g,h); k_xor( 3,e,f,g,h);\r
-    irot(e,f,g,h); ib2(e,f,g,h,a,b,c,d); k_xor( 2,a,b,c,d);\r
-    irot(a,b,c,d); ib1(a,b,c,d,e,f,g,h); k_xor( 1,e,f,g,h);\r
-    irot(e,f,g,h); ib0(e,f,g,h,a,b,c,d); k_xor( 0,a,b,c,d);\r
-    \r
-#ifdef  BLOCK_SWAP\r
-    out_blk[3] = io_swap(a); out_blk[2] = io_swap(b); \r
-    out_blk[1] = io_swap(c); out_blk[0] = io_swap(d);\r
-#else\r
-    out_blk[0] = a; out_blk[1] = b; out_blk[2] = c; out_blk[3] = d;\r
-#endif\r
-};\r
diff --git a/lib/silccrypt/serpent.h b/lib/silccrypt/serpent.h
deleted file mode 100644 (file)
index f00798d..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
-
-  serpent.h
-
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
-
-  Copyright (C) 1997 - 2000 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
-  GNU General Public License for more details.
-
-*/
-/*
- * $Id$
- * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
- *     Importet from internal CVS/Added Log headers.
- *
- *
- */
-
-#ifndef SERPENT_H
-#define SERPENT_H
-
-#include "serpent_internal.h"
-
-/* 
- * SILC Crypto API for Serpent
- */
-
-/* Sets the key for the cipher. */
-
-inline int silc_serpent_init(void *context, 
-                            const unsigned char *key, 
-                            size_t keylen)
-{
-  serpent_set_key((SerpentContext *)context, (unsigned int *)key, keylen);
-  return 1;
-}
-
-/* Sets the string as a new key for the cipher. The string is first
-   hashed and then used as a new key. */
-
-inline int silc_serpent_set_string_as_key(void *context, 
-                                         const unsigned char *string,
-                                         size_t keylen)
-{
-  /*  unsigned char key[md5_hash_len];
-  SilcMarsContext *ctx = (SilcMarsContext *)context;
-
-  make_md5_hash(string, &key);
-  memcpy(&ctx->key, mars_set_key(&key, keylen), keylen);
-  memset(&key, 'F', sizeoof(key));
-  */
-
-  return 1;
-}
-
-/* Returns the size of the cipher context. */
-
-inline size_t silc_serpent_context_len()
-{
-  return sizeof(SerpentContext);
-}
-
-/* Encrypts with the cipher in CBC mode. */
-
-inline int silc_serpent_encrypt_cbc(void *context,
-                                   const unsigned char *src,
-                                   unsigned char *dst,
-                                   size_t len,
-                                   unsigned char *iv)
-{
-  unsigned int *in, *out, *tiv;
-  unsigned int tmp[4];
-  int i;
-
-  in = (unsigned int *)src;
-  out = (unsigned int *)dst;
-  tiv = (unsigned int *)iv;
-
-  tmp[0] = in[0] ^ tiv[0];
-  tmp[1] = in[1] ^ tiv[1];
-  tmp[2] = in[2] ^ tiv[2];
-  tmp[3] = in[3] ^ tiv[3];
-  serpent_encrypt((SerpentContext *)context, tmp, out);
-  in += 4;
-  out += 4;
-
-  for (i = 16; i < len; i += 16) {
-    tmp[0] = in[0] ^ out[0 - 4];
-    tmp[1] = in[1] ^ out[1 - 4];
-    tmp[2] = in[2] ^ out[2 - 4];
-    tmp[3] = in[3] ^ out[3 - 4];
-    serpent_encrypt((SerpentContext *)context, tmp, out);
-    in += 4;
-    out += 4;
-  }
-
-  return 1;
-}
-
-/* Decrypts with the cipher in CBC mode. */
-
-inline int silc_serpent_decrypt_cbc(void *context,
-                                   const unsigned char *src,
-                                   unsigned char *dst,
-                                   size_t len,
-                                   unsigned char *iv)
-{
-  unsigned int *in, *out, *tiv;
-  int i;
-
-  in = (unsigned int *)src;
-  out = (unsigned int *)dst;
-  tiv = (unsigned int *)iv;
-
-  serpent_decrypt((SerpentContext *)context, in, out);
-  out[0] ^= tiv[0];
-  out[1] ^= tiv[1];
-  out[2] ^= tiv[2];
-  out[3] ^= tiv[3];
-  in += 4;
-  out += 4;
-
-  for (i = 16; i < len; i += 16) {
-    serpent_decrypt((SerpentContext *)context, in, out);
-    out[0] ^= in[0 - 4];
-    out[1] ^= in[1 - 4];
-    out[2] ^= in[2 - 4];
-    out[3] ^= in[3 - 4];
-    in += 4;
-    out += 4;
-  }
-
-  return 1;
-}
-
-#endif
diff --git a/lib/silccrypt/serpent_internal.h b/lib/silccrypt/serpent_internal.h
deleted file mode 100644 (file)
index c777ed0..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
-
-  serpent_internal.h
-
-  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
-
-  Copyright (C) 1997 - 2000 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
-  GNU General Public License for more details.
-
-*/
-
-#ifndef SERPENT_INTERNAL_H
-#define SERPENT_INTERNAL_H
-
-/* Cipher's context */
-typedef struct {
-  u4byte l_key[140];
-} SerpentContext;
-
-/* Prototypes */
-u4byte *serpent_set_key(SerpentContext *ctx,
-                       const u4byte in_key[], const u4byte key_len);
-void serpent_encrypt(SerpentContext *ctx,
-                    const u4byte in_blk[4], u4byte out_blk[]);
-void serpent_decrypt(SerpentContext *ctx,
-                    const u4byte in_blk[4], u4byte out_blk[4]);
-
-#endif
index e60a6d022af587b1c5b40421d1da1c4e068c7cf0..f22df0b8b6c4a60e779c376a6953310fa646229b 100644 (file)
@@ -67,13 +67,9 @@ typedef union {
     unsigned long l[16];
 } CHAR64LONG16;
 CHAR64LONG16* block;
-#ifdef SHA1HANDSOFF
 static unsigned char workspace[64];
     block = (CHAR64LONG16*)workspace;
     memcpy(block, buffer, 64);
-#else
-    block = (CHAR64LONG16*)buffer;
-#endif
     /* Copy context->state[] to working vars */
     a = state[0];
     b = state[1];
@@ -174,9 +170,7 @@ unsigned char finalcount[8];
     memset(context->state, 0, 20);
     memset(context->count, 0, 8);
     memset(finalcount, 0, 8);
-#ifdef SHA1HANDSOFF  /* make SHA1Transform overwrite it's own static vars */
     SHA1Transform(context->state, context->buffer);
-#endif
 }
 
 
index 534d300210a913320f905a04ffc7d6830966abfa..6ac0d5b50933709e6098cdd6e36c45989c6aac49 100644 (file)
@@ -20,8 +20,8 @@
 /*
  * $Id$
  * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
- *     Importet from internal CVS/Added Log headers.
+ * Revision 1.1  2000/06/27 11:36:55  priikone
+ * Initial revision
  *
  *
  */
index c3d2087017f1f9bab79f5141b3db6f8c09b27a6b..d98f86d07273461ed0bc7fb74099fd73cbd23e10 100644 (file)
 /*
  * $Id$
  * $Log$
+ * Revision 1.5  2000/10/09 11:37:21  priikone
+ *     bugfixes. Made public/private keys protocol compliant.
+ *
+ * Revision 1.4  2000/10/02 18:31:46  priikone
+ *     Added rijndael (AES) to cipher list.
+ *
+ * Revision 1.3  2000/09/28 11:28:20  priikone
+ *     Changed cipher list order.
+ *
+ * Revision 1.2  2000/07/05 06:08:43  priikone
+ *     Global cosmetic change.
+ *
  * Revision 1.1.1.1  2000/06/27 11:36:54  priikone
- *     Importet from internal CVS/Added Log headers.
+ *     Imported from internal CVS/Added Log headers.
  *
  *
  */
@@ -47,18 +59,21 @@ struct SilcCipherListStruct *silc_cipher_list = NULL;
    support SIM's. */
 SilcCipherObject silc_cipher_builtin_list[] =
 {
-  { "none", 0, 0, silc_none_set_key, silc_none_set_key_with_string,
-    silc_none_encrypt_cbc, silc_none_decrypt_cbc, 
-    silc_none_context_len },
   { "twofish", 16, 16, silc_twofish_set_key, silc_twofish_set_key_with_string,
     silc_twofish_encrypt_cbc, silc_twofish_decrypt_cbc, 
     silc_twofish_context_len },
+  { "aes", 16, 16, silc_rijndael_set_key, 
+    silc_rijndael_set_key_with_string, silc_rijndael_encrypt_cbc,
+    silc_rijndael_decrypt_cbc, silc_rijndael_context_len },
   { "rc6", 16, 16, silc_rc6_set_key, silc_rc6_set_key_with_string,
     silc_rc6_encrypt_cbc, silc_rc6_decrypt_cbc, 
     silc_rc6_context_len },
   { "mars", 16, 16, silc_mars_set_key, silc_mars_set_key_with_string,
     silc_mars_encrypt_cbc, silc_mars_decrypt_cbc, 
     silc_mars_context_len },
+  { "none", 0, 0, silc_none_set_key, silc_none_set_key_with_string,
+    silc_none_encrypt_cbc, silc_none_decrypt_cbc, 
+    silc_none_context_len },
 
   { NULL, 0, 0, NULL, NULL, NULL, NULL, NULL }
 };
@@ -75,18 +90,7 @@ int silc_cipher_register(SilcCipherObject *cipher)
   SILC_LOG_DEBUG(("Registering new cipher"));
 
   new = silc_calloc(1, sizeof(*new));
-  if (!new) {
-    SILC_LOG_ERROR(("Could not allocate new cipher list object: %s",
-                   strerror(errno)));
-    return FALSE;
-  }
-
   new->cipher = silc_calloc(1, sizeof(*new->cipher));
-  if (!new->cipher) {
-    SILC_LOG_ERROR(("Could not allocate new cipher object: %s",
-                   strerror(errno)));
-    return FALSE;
-  }
 
   /* Set the pointers */
   new->cipher->name = strdup(cipher->name);
@@ -180,10 +184,6 @@ int silc_cipher_alloc(const unsigned char *name, SilcCipher *new_cipher)
 
   /* Allocate the new object */
   *new_cipher = silc_calloc(1, sizeof(**new_cipher));
-  if (*new_cipher == NULL) {
-    SILC_LOG_ERROR(("Could not allocate new cipher object"));
-    return FALSE;
-  }
   
   if (silc_cipher_list) {
 
index 6b5f4c42842f887f2a6b9cfad0a7d93ef0a45051..18cf81bc4720f815b21464e1c0a5225a1eb22e29 100644 (file)
 /*
  * $Id$
  * $Log$
+ * Revision 1.3  2000/07/10 05:35:43  priikone
+ *     Added fingerprint functions.
+ *
+ * Revision 1.2  2000/07/05 06:08:43  priikone
+ *     Global cosmetic change.
+ *
  * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
- *     Importet from internal CVS/Added Log headers.
+ *     Imported from internal CVS/Added Log headers.
  *
  *
  */
@@ -63,16 +69,7 @@ int silc_hash_register(SilcHashObject *hash)
   SILC_LOG_DEBUG(("Registering new hash function"));
 
   new = silc_calloc(1, sizeof(*new));
-  if (!new) {
-    SILC_LOG_ERROR(("Could not allocate new hash list object"));
-    return FALSE;
-  }
-
   new->hash = silc_calloc(1, sizeof(*new->hash));
-  if (!new->hash) {
-    SILC_LOG_ERROR(("Could not allocate new hash object"));
-    return FALSE;
-  }
 
   /* Set the pointers */
   new->hash->name = silc_calloc(1, strlen(hash->name));
@@ -163,10 +160,6 @@ int silc_hash_alloc(const unsigned char *name, SilcHash *new_hash)
 
   /* Allocate the new object */
   *new_hash = silc_calloc(1, sizeof(**new_hash));
-  if (*new_hash == NULL) {
-    SILC_LOG_ERROR(("Could not allocate new hash object"));
-    return FALSE;
-  }
 
   if (silc_hash_list) {
     h = silc_hash_list;
@@ -289,3 +282,35 @@ void silc_hash_make(SilcHash hash, const unsigned char *data,
   hash->hash->update(hash->context, (unsigned char *)data, len);
   hash->hash->final(hash->context, return_hash);
 }
+
+/* Creates fingerprint of the data. If `hash' is NULL SHA1 is used as
+   default hash function. The returned fingerprint must be free's by the
+   caller. */
+
+char *silc_hash_fingerprint(SilcHash hash, const unsigned char *data,
+                           unsigned int data_len)
+{
+  char fingerprint[64], *cp;
+  unsigned char h[32];
+  int i;
+
+  if (!hash)
+    silc_hash_alloc("sha1", &hash);
+
+  silc_hash_make(hash, data, data_len, h);
+  
+  memset(fingerprint, 0, sizeof(fingerprint));
+  cp = fingerprint;
+  for (i = 0; i < hash->hash->hash_len; i++) {
+    snprintf(cp, sizeof(fingerprint), "%02X", h[i]);
+    cp += 2;
+    
+    if ((i + 1) % 2 == 0)
+      snprintf(cp++, sizeof(fingerprint), " ");
+
+    if ((i + 1) % 10 == 0)
+      snprintf(cp++, sizeof(fingerprint), " ");
+  }
+  
+  return strdup(fingerprint);
+}
index 98f85ef47d0da1846c6e61f2131b8886858e2aad..751c6e174b94ccca818fde6c0b7b0d20dc9cd09b 100644 (file)
@@ -88,5 +88,7 @@ int silc_hash_is_supported(const unsigned char *name);
 char *silc_hash_get_supported();
 void silc_hash_make(SilcHash hash, const unsigned char *data,
                    unsigned int len, unsigned char *return_hash);
+char *silc_hash_fingerprint(SilcHash hash, const unsigned char *data,
+                           unsigned int data_len);
 
 #endif
index 5be46cf01f100a66f7784f60a398037e6e4b9788..30f36c3f98a8cbc5593f80a9fca2151af9494a0b 100644 (file)
 /*
  * $Id$
  * $Log$
+ * Revision 1.3  2000/07/14 09:12:24  priikone
+ *     Fixed bug in silc_hmac_make.
+ *
+ * Revision 1.2  2000/07/05 06:08:43  priikone
+ *     Global cosmetic change.
+ *
  * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
- *     Importet from internal CVS/Added Log headers.
+ *     Imported from internal CVS/Added Log headers.
  *
  *
  */
@@ -37,11 +43,6 @@ int silc_hmac_alloc(SilcHash hash, SilcHmac *new_hmac)
   SILC_LOG_DEBUG(("Allocating new hmac object"));
 
   *new_hmac = silc_calloc(1, sizeof(**new_hmac));
-  if (*new_hmac == NULL) {
-    SILC_LOG_ERROR(("Could not allocate new hmac object"));
-    return 0;
-  }
-
   (*new_hmac)->hash = hash;
   (*new_hmac)->set_key = silc_hmac_set_key;
   (*new_hmac)->make_hmac = silc_hmac_make;
@@ -154,5 +155,6 @@ void silc_hmac_set_key(SilcHmac hmac, const unsigned char *key,
                       unsigned int key_len)
 {
   hmac->key = silc_calloc(key_len, sizeof(unsigned char));
+  hmac->key_len = key_len;
   memcpy(hmac->key, key, key_len);
 }
index 6b99d59b62f31c0973e45643d67587be2e62dc3a..5398142725d12e224ed2a496c41c390f52224c39 100644 (file)
@@ -17,6 +17,7 @@
   GNU General Public License for more details.
 
 */
+/* $Id$ */
 
 #include "silcincludes.h"
 
@@ -59,10 +60,6 @@ int silc_pkcs_alloc(const unsigned char *name, SilcPKCS *new_pkcs)
     return FALSE;
 
   *new_pkcs = silc_calloc(1, sizeof(**new_pkcs));
-  if (*new_pkcs == NULL) {
-    SILC_LOG_ERROR(("Could not allocate new PKCS object"));
-    return FALSE;
-  }
 
   /* Set the pointers */
   (*new_pkcs)->pkcs = &silc_pkcs_list[i];
@@ -140,104 +137,688 @@ unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, unsigned int *len)
   return pkcs->pkcs->get_private_key(pkcs->context, len);
 }
 
-/* Sets public key */
-/* XXX rewrite */
+/* Sets public key from SilcPublicKey. */
+
+int silc_pkcs_public_key_set(SilcPKCS pkcs, SilcPublicKey public_key)
+{
+  return pkcs->pkcs->set_public_key(pkcs->context, public_key->pk, 
+                                   public_key->pk_len);
+}
+
+/* Sets public key from data. */
 
-int silc_pkcs_set_public_key(SilcPKCS pkcs, unsigned char *pk, 
-                            unsigned int pk_len)
+int silc_pkcs_public_key_data_set(SilcPKCS pkcs, unsigned char *pk,
+                                 unsigned int pk_len)
 {
   return pkcs->pkcs->set_public_key(pkcs->context, pk, pk_len);
 }
 
-/* Sets private key */
+/* Sets private key from SilcPrivateKey. */
 
-int silc_pkcs_set_private_key(SilcPKCS pkcs, unsigned char *prv, 
-                             unsigned int prv_len)
+int silc_pkcs_private_key_set(SilcPKCS pkcs, SilcPrivateKey private_key)
+{
+  return pkcs->pkcs->set_private_key(pkcs->context, private_key->prv, 
+                                    private_key->prv_len);
+}
+
+/* Sets private key from data. */
+
+int silc_pkcs_private_key_data_set(SilcPKCS pkcs, unsigned char *prv,
+                                  unsigned int prv_len)
 {
   return pkcs->pkcs->set_private_key(pkcs->context, prv, prv_len);
 }
 
-/* Saves public key into file */
+/* 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. */
 
-int silc_pkcs_save_public_key(SilcPKCS pkcs, char *filename,
-                             unsigned char *pk, unsigned int pk_len)
+char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
+                                 char *email, char *org, char *country)
 {
   SilcBuffer buf;
-  int ret = TRUE;
+  char *identifier;
+  unsigned int len, tlen = 0;
+
+  if (!username || !host)
+    return NULL;
+
+  len = (username ? strlen(username) : 0) +
+       (host     ? strlen(host)     : 0) +
+       (realname ? strlen(realname) : 0) +
+       (email    ? strlen(email)    : 0) +
+       (org      ? strlen(org)      : 0) +
+       (country  ? strlen(country)  : 0);
+  
+  if (len < 3)
+    return NULL;
+
+  len += 3 + 5 + 5 + 4 + 4 + 4;
+  buf = silc_buffer_alloc(len);
+  silc_buffer_pull_tail(buf, len);
+
+  if (username) {
+    silc_buffer_format(buf,
+                      SILC_STR_UI32_STRING("UN="),
+                      SILC_STR_UI32_STRING(username),
+                      SILC_STR_END);
+    silc_buffer_pull(buf, 3 + strlen(username));
+    tlen = 3 + strlen(username); 
+  }
+    
+  if (host) {
+    silc_buffer_format(buf,
+                      SILC_STR_UI32_STRING(", "),
+                      SILC_STR_UI32_STRING("HN="),
+                      SILC_STR_UI32_STRING(host),
+                      SILC_STR_END);
+    silc_buffer_pull(buf, 5 + strlen(host));
+    tlen += 5 + strlen(host); 
+  }
+
+  if (realname) {
+    silc_buffer_format(buf,
+                      SILC_STR_UI32_STRING(", "),
+                      SILC_STR_UI32_STRING("RN="),
+                      SILC_STR_UI32_STRING(realname),
+                      SILC_STR_END);
+    silc_buffer_pull(buf, 5 + strlen(realname));
+    tlen += 5 + strlen(realname); 
+  }
+
+  if (email) {
+    silc_buffer_format(buf,
+                      SILC_STR_UI32_STRING(", "),
+                      SILC_STR_UI32_STRING("E="),
+                      SILC_STR_UI32_STRING(email),
+                      SILC_STR_END);
+    silc_buffer_pull(buf, 4 + strlen(email));
+    tlen += 4 + strlen(email); 
+  }
+
+  if (org) {
+    silc_buffer_format(buf,
+                      SILC_STR_UI32_STRING(", "),
+                      SILC_STR_UI32_STRING("O="),
+                      SILC_STR_UI32_STRING(org),
+                      SILC_STR_END);
+    silc_buffer_pull(buf, 4 + strlen(org));
+    tlen += 4 + strlen(org); 
+  }
+
+  if (country) {
+    silc_buffer_format(buf,
+                      SILC_STR_UI32_STRING(", "),
+                      SILC_STR_UI32_STRING("C="),
+                      SILC_STR_UI32_STRING(country),
+                      SILC_STR_END);
+    silc_buffer_pull(buf, 4 + strlen(country));
+    tlen += 4 + strlen(country); 
+  }
+
+  silc_buffer_push(buf, buf->data - buf->head);
+  identifier = silc_calloc(tlen, sizeof(*identifier));
+  memcpy(identifier, buf->data, tlen);
+  silc_buffer_free(buf);
 
-  buf = silc_buffer_alloc(strlen(pkcs->pkcs->name) + 2 + pk_len
-                         + strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) 
-                         + strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
+  return identifier;
+}
+
+/* Allocates SILC style public key formed from sent arguments. All data
+   is duplicated. */
+
+SilcPublicKey silc_pkcs_public_key_alloc(char *name, char *identifier,
+                                        unsigned char *pk, 
+                                        unsigned int pk_len)
+{
+  SilcPublicKey public_key;
+
+  public_key = silc_calloc(1, sizeof(*public_key));
+  public_key->len = 4 + 2 + strlen(name) + 2 + strlen(identifier) + pk_len;
+  public_key->name = strdup(name);
+  public_key->identifier = strdup(identifier);
+  public_key->pk_len = pk_len;
+  public_key->pk = silc_calloc(pk_len, sizeof(*public_key->pk));
+  memcpy(public_key->pk, pk, pk_len);
+
+  return public_key;
+}
+
+/* Free's public key */
+
+void silc_pkcs_public_key_free(SilcPublicKey public_key)
+{
+  if (public_key) {
+    silc_free(public_key->name);
+    silc_free(public_key->identifier);
+    silc_free(public_key->pk);
+    silc_free(public_key);
+  }
+}
+
+/* Allocates SILC private key formed from sent arguments. All data is
+   duplicated. */
+
+SilcPrivateKey silc_pkcs_private_key_alloc(char *name, unsigned char *prv,
+                                          unsigned int prv_len)
+{
+  SilcPrivateKey private_key;
+
+  private_key = silc_calloc(1, sizeof(*private_key));
+  private_key->name = strdup(name);
+  private_key->prv_len = prv_len;
+  private_key->prv = silc_calloc(prv_len, sizeof(*private_key->prv));
+  memcpy(private_key->prv, prv, prv_len);
+
+  return private_key;
+}
+
+/* Free's private key */
+
+void silc_pkcs_private_key_free(SilcPrivateKey private_key)
+{
+  if (private_key) {
+    silc_free(private_key->name);
+    silc_free(private_key->prv);
+    silc_free(private_key);
+  }
+}
 
-  silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
+/* Encodes SILC style public key from SilcPublicKey. Returns the encoded
+   data. */
+
+unsigned char *
+silc_pkcs_public_key_encode(SilcPublicKey public_key, unsigned int *len)
+{
+  SilcBuffer buf;
+  unsigned char *ret;
+
+  buf = silc_buffer_alloc(public_key->len);
+  silc_buffer_pull_tail(buf, public_key->len);
 
   silc_buffer_format(buf,
-                    SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
-                    SILC_STR_UI32_STRING(pkcs->pkcs->name),
-                    SILC_STR_UI_SHORT(pk_len),
+                    SILC_STR_UI_INT(public_key->len),
+                    SILC_STR_UI_SHORT(strlen(public_key->name)),
+                    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, 
+                                         public_key->pk_len),
+                    SILC_STR_END);
+  if (len)
+    *len = public_key->len;
+
+  ret = silc_calloc(buf->len, sizeof(*ret));
+  memcpy(ret, buf->data, buf->len);
+  silc_buffer_free(buf);
+
+  return ret;
+}
+
+/* Encodes SILC style public key. Returns the encoded data. */
+
+unsigned char *
+silc_pkcs_public_key_data_encode(unsigned char *pk, unsigned int pk_len,
+                                char *pkcs, char *identifier, 
+                                unsigned int *len)
+{
+  SilcBuffer buf;
+  unsigned char *ret;
+  unsigned int totlen;
+
+  totlen = 4 + 2 + strlen(pkcs) + 2 + strlen(identifier) + pk_len;
+  buf = silc_buffer_alloc(totlen);
+  silc_buffer_pull_tail(buf, totlen);
+
+  silc_buffer_format(buf,
+                    SILC_STR_UI_INT(totlen),
+                    SILC_STR_UI_SHORT(strlen(pkcs)),
+                    SILC_STR_UI32_STRING(pkcs),
+                    SILC_STR_UI_SHORT(strlen(identifier)),
+                    SILC_STR_UI32_STRING(identifier),
                     SILC_STR_UI_XNSTRING(pk, pk_len),
+                    SILC_STR_END);
+  if (len)
+    *len = totlen;
+
+  ret = silc_calloc(buf->len, sizeof(*ret));
+  memcpy(ret, buf->data, buf->len);
+  silc_buffer_free(buf);
+
+  return ret;
+}
+
+/* Decodes SILC style public key. Returns TRUE if the decoding was
+   successful. Allocates new public key as well. */
+
+int silc_pkcs_public_key_decode(unsigned char *data, unsigned int data_len,
+                               SilcPublicKey *public_key)
+{
+  SilcBuffer buf;
+  SilcPKCS alg;
+  unsigned short pkcs_len, identifier_len;
+  unsigned int totlen, key_len;
+  unsigned char *pkcs_name = NULL, *ident = NULL, *key_data = NULL;
+
+  buf = silc_buffer_alloc(data_len);
+  silc_buffer_pull_tail(buf, data_len);
+  silc_buffer_put(buf, data, data_len);
+
+  /* Get length */
+  silc_buffer_unformat(buf,
+                      SILC_STR_UI_INT(&totlen),
+                      SILC_STR_END);
+
+  if (totlen != data_len) {
+    silc_buffer_free(buf);
+    return FALSE;
+  }
+
+  /* Get algorithm name and identifier */
+  silc_buffer_pull(buf, 4);
+  silc_buffer_unformat(buf,
+                      SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
+                      SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len),
+                      SILC_STR_END);
+
+  if (pkcs_len < 1 || identifier_len < 3 || 
+      pkcs_len + identifier_len > totlen)
+    goto err;
+
+  /* See if we support this algorithm */
+  if (!silc_pkcs_is_supported(pkcs_name))
+    goto err;
+
+  /* Protocol says that at least UN and HN must be provided as identifier,
+     check for these. */
+  if (!strstr(ident, "UN=") && !strstr(ident, "HN="))
+    goto err;
+
+  /* Get key data. We assume that rest of the buffer is key data. */
+  silc_buffer_pull(buf, 2 + pkcs_len + 2 + identifier_len);
+  key_len = buf->len;
+  silc_buffer_unformat(buf,
+                      SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
+                      SILC_STR_END);
+
+  /* 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. */
+  silc_pkcs_alloc(pkcs_name, &alg);
+  if (!alg->pkcs->set_public_key(alg->context, key_data, key_len))
+    goto err;
+  silc_pkcs_free(alg);
+  
+  if (public_key) {
+    *public_key = silc_calloc(1, sizeof(**public_key));
+    (*public_key)->len = totlen;
+    (*public_key)->name = pkcs_name;
+    (*public_key)->identifier = ident;
+    (*public_key)->pk = key_data;
+    (*public_key)->pk_len = key_len;
+  }
+
+  silc_buffer_free(buf);
+  return TRUE;
+
+ err:
+  if (pkcs_name)
+    silc_free(pkcs_name);
+  if (ident)
+    silc_free(ident);
+  if (key_data)
+    silc_free(key_data);
+  silc_buffer_free(buf);
+  return FALSE;
+}
+
+/* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
+
+unsigned char *
+silc_pkcs_private_key_encode(SilcPrivateKey private_key, unsigned int *len)
+{
+  SilcBuffer buf;
+  unsigned char *ret;
+  unsigned int totlen;
+
+  totlen = 2 + strlen(private_key->name) + private_key->prv_len;
+  buf = silc_buffer_alloc(totlen);
+  silc_buffer_pull_tail(buf, totlen);
+
+  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, 
+                                         private_key->prv_len),
+                    SILC_STR_END);
+  if (len)
+    *len = totlen;
+
+  ret = silc_calloc(buf->len, sizeof(*ret));
+  memcpy(ret, buf->data, buf->len);
+  silc_buffer_free(buf);
+
+  return ret;
+}
+
+/* Encodes SILC private key. Returns the encoded data. */
+
+unsigned char *
+silc_pkcs_private_key_data_encode(unsigned char *prv, unsigned int prv_len,
+                                 char *pkcs, unsigned int *len)
+{
+  SilcBuffer buf;
+  unsigned char *ret;
+  unsigned int totlen;
+
+  totlen = 2 + strlen(pkcs) + prv_len;
+  buf = silc_buffer_alloc(totlen);
+  silc_buffer_pull_tail(buf, totlen);
+
+  silc_buffer_format(buf,
+                    SILC_STR_UI_SHORT(strlen(pkcs)),
+                    SILC_STR_UI32_STRING(pkcs),
+                    SILC_STR_UI_XNSTRING(prv, prv_len),
+                    SILC_STR_END);
+  if (len)
+    *len = totlen;
+
+  ret = silc_calloc(buf->len, sizeof(*ret));
+  memcpy(ret, buf->data, buf->len);
+  silc_buffer_free(buf);
+
+  return ret;
+}
+
+/* Decodes SILC style public key. Returns TRUE if the decoding was
+   successful. Allocates new private key as well. */
+
+int silc_pkcs_private_key_decode(unsigned char *data, unsigned int data_len,
+                                SilcPrivateKey *private_key)
+{
+  SilcBuffer buf;
+  SilcPKCS alg;
+  unsigned short pkcs_len;
+  unsigned int key_len;
+  unsigned char *pkcs_name = NULL, *key_data = NULL;
+
+  buf = silc_buffer_alloc(data_len);
+  silc_buffer_pull_tail(buf, data_len);
+  silc_buffer_put(buf, data, data_len);
+
+  /* Get algorithm name and identifier */
+  silc_buffer_unformat(buf,
+                      SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len),
+                      SILC_STR_END);
+
+  if (pkcs_len < 1 || pkcs_len > buf->truelen)
+    goto err;
+
+  /* See if we support this algorithm */
+  if (!silc_pkcs_is_supported(pkcs_name))
+    goto err;
+
+  /* Get key data. We assume that rest of the buffer is key data. */
+  silc_buffer_pull(buf, 2 + pkcs_len);
+  key_len = buf->len;
+  silc_buffer_unformat(buf,
+                      SILC_STR_UI_XNSTRING_ALLOC(&key_data, key_len),
+                      SILC_STR_END);
+
+  /* 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. */
+  silc_pkcs_alloc(pkcs_name, &alg);
+  if (!alg->pkcs->set_private_key(alg->context, key_data, key_len))
+    goto err;
+  silc_pkcs_free(alg);
+  
+  if (private_key) {
+    *private_key = silc_calloc(1, sizeof(**private_key));
+    (*private_key)->name = pkcs_name;
+    (*private_key)->prv = key_data;
+    (*private_key)->prv_len = key_len;
+  }
+
+  silc_buffer_free(buf);
+  return TRUE;
+
+ err:
+  if (pkcs_name)
+    silc_free(pkcs_name);
+  if (key_data)
+    silc_free(key_data);
+  silc_buffer_free(buf);
+  return FALSE;
+}
+
+/* Internal routine to save public key */
+
+static int silc_pkcs_save_public_key_internal(char *filename,
+                                             unsigned char *data,
+                                             unsigned int data_len,
+                                             unsigned int encoding)
+{
+  SilcBuffer buf;
+  unsigned int len;
+
+  switch(encoding) {
+  case SILC_PKCS_FILE_BIN:
+    break;
+  case SILC_PKCS_FILE_PEM:
+    data = silc_encode_pem_file(data, data_len);
+    data_len = strlen(data);
+    break;
+  }
+
+  len = data_len + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
+                   strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
+  buf = silc_buffer_alloc(len);
+  silc_buffer_pull_tail(buf, len);
+
+  silc_buffer_format(buf,
+                    SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN),
+                    SILC_STR_UI_XNSTRING(data, data_len),
                     SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END),
                     SILC_STR_END);
 
-  /* Save into file */
+  /* Save into file */
   if (silc_file_write(filename, buf->data, buf->len)) {
-    ret = FALSE;
-    goto out;
+    silc_buffer_free(buf);
+    return FALSE;
   }
 
- out:
   silc_buffer_free(buf);
-  return ret;
+  return TRUE;
 }
 
-/* XXX The buffer should be encrypted */
-/* XXX rewrite */
+/* Saves public key into file */
+
+int silc_pkcs_save_public_key(char *filename, SilcPublicKey public_key,
+                             unsigned int encoding)
+{
+  unsigned char *data;
+  unsigned int data_len;
+
+  data = silc_pkcs_public_key_encode(public_key, &data_len);
+  return silc_pkcs_save_public_key_internal(filename, data, data_len,
+                                           encoding);
+}
+
+/* Saves public key into file */
+
+int silc_pkcs_save_public_key_data(char *filename, unsigned char *data,
+                                  unsigned int data_len,
+                                  unsigned int encoding)
+{
+  return silc_pkcs_save_public_key_internal(filename, data, data_len,
+                                           encoding);
+}
+
+/* Internal routine to save private key. */
 
-int silc_pkcs_save_private_key(SilcPKCS pkcs, char *filename,
-                              unsigned char *prv, unsigned int prv_len,
-                              char *passphrase)
+static int silc_pkcs_save_private_key_internal(char *filename,
+                                              unsigned char *data,
+                                              unsigned int data_len,
+                                              unsigned int encoding)
 {
   SilcBuffer buf;
-  int ret = TRUE;
+  unsigned int len;
+
+  switch(encoding) {
+  case SILC_PKCS_FILE_BIN:
+    break;
+  case SILC_PKCS_FILE_PEM:
+    data = silc_encode_pem_file(data, data_len);
+    data_len = strlen(data);
+    break;
+  }
 
-  buf = silc_buffer_alloc(strlen(pkcs->pkcs->name) + 2 + prv_len
-                         + strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) 
-                         + strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
-  silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
+  len = data_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
+                   strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
+  buf = silc_buffer_alloc(len);
+  silc_buffer_pull_tail(buf, len);
 
   silc_buffer_format(buf,
                     SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN),
-                    SILC_STR_UI32_STRING(pkcs->pkcs->name),
-                    SILC_STR_UI_SHORT(prv_len),
-                    SILC_STR_UI_XNSTRING(prv, prv_len),
+                    SILC_STR_UI_XNSTRING(data, data_len),
                     SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END),
                     SILC_STR_END);
 
   /* Save into a file */
-  if (silc_file_write(filename, buf->data, buf->len)) {
-    ret = FALSE;
-    goto out;
+  if (silc_file_write_mode(filename, buf->data, buf->len, 0600)) {
+    silc_buffer_free(buf);
+    return FALSE;
   }
 
- out:
   silc_buffer_free(buf);
-  return ret;
+  return TRUE;
+}
+
+/* Saves private key into file. */
+/* XXX The buffer should be encrypted if passphrase is provided. */
+
+int silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key, 
+                              unsigned char *passphrase,
+                              unsigned int encoding)
+{
+  unsigned char *data;
+  unsigned int data_len;
+
+  data = silc_pkcs_private_key_encode(private_key, &data_len);
+  return silc_pkcs_save_private_key_internal(filename, data, data_len,
+                                            encoding);
+}
+
+/* Saves private key into file. */
+/* XXX The buffer should be encrypted if passphrase is provided. */
+
+int silc_pkcs_save_private_key_data(char *filename, unsigned char *data, 
+                                   unsigned int data_len,
+                                   unsigned char *passphrase,
+                                   unsigned int encoding)
+{
+  return silc_pkcs_save_private_key_internal(filename, data, data_len,
+                                            encoding);
 }
 
-/* Loads public key from file and allocates new PKCS object and
-   sets the loaded key into it. */
+/* Loads public key from file and allocates new public key. Returns TRUE
+   is loading was successful. */
 
-int silc_pkcs_load_public_key(char *filename, SilcPKCS *ret_pkcs)
+int silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key,
+                             unsigned int encoding)
 {
+  unsigned char *cp, *old, *data, byte;
+  unsigned int i, data_len, len;
+
+  old = data = silc_file_read(filename, &data_len);
+  if (!data)
+    return FALSE;
+
+  /* Check start of file and remove header from the data. */
+  len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN);
+  cp = data;
+  for (i = 0; i < len; i++) {
+    byte = cp[0];
+    cp++;
+    if (byte != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) {
+      memset(old, 0, data_len);
+      silc_free(old);
+    }
+  }
+  data = cp;
+
+  /* Decode public key */
+  if (public_key) {
+    len = data_len - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) +
+                     strlen(SILC_PKCS_PUBLIC_KEYFILE_END));
+
+    switch(encoding) {
+    case SILC_PKCS_FILE_BIN:
+      break;
+    case SILC_PKCS_FILE_PEM:
+      data = silc_decode_pem(data, len, &len);
+      break;
+    }
 
+    if (!data || !silc_pkcs_public_key_decode(data, len, public_key)) {
+      memset(old, 0, data_len);
+      silc_free(old);
+      return FALSE;
+    }
+  }
+
+  memset(old, 0, data_len);
+  silc_free(old);
   return TRUE;
 }
 
-/* Loads private key from file and allocates new PKCS object and
-   sets the loaded key into it. */
+/* Load private key from file and allocates new private key. Returns TRUE
+   if loading was successful. */
+/* XXX Should support encrypted private key files */
 
-int silc_pkcs_load_private_key(char *filename, SilcPKCS *ret_pkcs)
+int silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key,
+                              unsigned int encoding)
 {
+  unsigned char *cp, *old, *data, byte;
+  unsigned int i, data_len, len;
+
+  old = data = silc_file_read(filename, &data_len);
+  if (!data)
+    return FALSE;
+
+  /* Check start of file and remove header from the data. */
+  len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN);
+  cp = data;
+  for (i = 0; i < len; i++) {
+    byte = cp[0];
+    cp++;
+    if (byte != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) {
+      memset(old, 0, data_len);
+      silc_free(old);
+    }
+  }
+  data = cp;
+
+  /* Decode private key */
+  if (private_key) {
+    len = data_len - (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) +
+                     strlen(SILC_PKCS_PRIVATE_KEYFILE_END));
+
+    switch(encoding) {
+    case SILC_PKCS_FILE_BIN:
+      break;
+    case SILC_PKCS_FILE_PEM:
+      data = silc_decode_pem(data, len, &len);
+      break;
+    }
+
+    if (!data || !silc_pkcs_private_key_decode(data, len, private_key)) {
+      memset(old, 0, data_len);
+      silc_free(old);
+      return FALSE;
+    }
+  }
 
+  memset(old, 0, data_len);
+  silc_free(old);
   return TRUE;
 }
index 9d7fd82da58cfd8c2ba3bcec2bcd2cbf3c3d1901..8183b3ac561f161c30cca7477f1a2f0bd988d08b 100644 (file)
@@ -24,7 +24,7 @@
 /* The default SILC PKCS (Public Key Cryptosystem) object to represent
    any PKCS in SILC. */
 typedef struct SilcPKCSObjectStruct {
-  unsigned char *name;
+  char *name;
   void *data_context;
 
   int (*init)(void *, unsigned int, SilcRng);
@@ -59,12 +59,35 @@ typedef struct SilcPKCSStruct {
 /* List of all PKCS in SILC. */
 extern SilcPKCSObject silc_pkcs_list[];
 
+/* SILC style public key object. Public key is read from file to this
+   object. Public keys received from network must be in this format as 
+   well. */
+typedef struct {
+  unsigned int len;
+  char *name;
+  char *identifier;
+  unsigned char *pk;
+  unsigned int pk_len;
+} *SilcPublicKey;
+
+/* SILC style private key object. Private key is read from file to this
+   object. */
+typedef struct {
+  char *name;
+  unsigned char *prv;
+  unsigned int prv_len;
+} *SilcPrivateKey;
+
 /* Public and private key file headers */
 #define SILC_PKCS_PUBLIC_KEYFILE_BEGIN "-----BEGIN SILC PUBLIC KEY-----\n"
 #define SILC_PKCS_PUBLIC_KEYFILE_END "\n-----END SILC PUBLIC KEY-----\n"
 #define SILC_PKCS_PRIVATE_KEYFILE_BEGIN "-----BEGIN SILC PRIVATE KEY-----\n"
 #define SILC_PKCS_PRIVATE_KEYFILE_END "\n-----END SILC PRIVATE KEY-----\n"
 
+/* Public and private key file encoding types */
+#define SILC_PKCS_FILE_BIN 0
+#define SILC_PKCS_FILE_PEM 1
+
 /* Macros */
 
 /* Macros used to implement the SILC PKCS API */
@@ -149,16 +172,51 @@ char *silc_pkcs_get_supported();
 unsigned int silc_pkcs_get_key_len(SilcPKCS self);
 unsigned char *silc_pkcs_get_public_key(SilcPKCS pkcs, unsigned int *len);
 unsigned char *silc_pkcs_get_private_key(SilcPKCS pkcs, unsigned int *len);
-int silc_pkcs_set_public_key(SilcPKCS pkcs, unsigned char *pk, 
-                            unsigned int pk_len);
-int silc_pkcs_set_private_key(SilcPKCS pkcs, unsigned char *prv, 
-                             unsigned int prv_len);
-int silc_pkcs_save_public_key(SilcPKCS pkcs, char *filename,
-                             unsigned char *pk, unsigned int pk_len);
-int silc_pkcs_save_private_key(SilcPKCS pkcs, char *filename,
-                              unsigned char *prv, unsigned int prv_len,
-                              char *passphrase);
-int silc_pkcs_load_public_key(char *filename, SilcPKCS *ret_pkcs);
-int silc_pkcs_load_private_key(char *filename, SilcPKCS *ret_pkcs);
+int silc_pkcs_public_key_set(SilcPKCS pkcs, SilcPublicKey public_key);
+int silc_pkcs_public_key_data_set(SilcPKCS pkcs, unsigned char *pk,
+                                 unsigned int pk_len);
+int silc_pkcs_private_key_set(SilcPKCS pkcs, SilcPrivateKey private_key);
+int silc_pkcs_private_key_data_set(SilcPKCS pkcs, unsigned char *prv,
+                                  unsigned int prv_len);
+char *silc_pkcs_encode_identifier(char *username, char *host, char *realname,
+                                 char *email, char *org, char *country);
+SilcPublicKey silc_pkcs_public_key_alloc(char *name, char *identifier,
+                                        unsigned char *pk, 
+                                        unsigned int pk_len);
+void silc_pkcs_public_key_free(SilcPublicKey public_key);
+SilcPrivateKey silc_pkcs_private_key_alloc(char *name, unsigned char *prv,
+                                          unsigned int prv_len);
+void silc_pkcs_private_key_free(SilcPrivateKey private_key);
+unsigned char *
+silc_pkcs_public_key_encode(SilcPublicKey public_key, unsigned int *len);
+unsigned char *
+silc_pkcs_public_key_data_encode(unsigned char *pk, unsigned int pk_len,
+                                char *pkcs, char *identifier, 
+                                unsigned int *len);
+int silc_pkcs_public_key_decode(unsigned char *data, unsigned int data_len,
+                               SilcPublicKey *public_key);
+unsigned char *
+silc_pkcs_private_key_encode(SilcPrivateKey private_key, unsigned int *len);
+unsigned char *
+silc_pkcs_private_key_data_encode(unsigned char *prv, unsigned int prv_len,
+                                 char *pkcs, unsigned int *len);
+int silc_pkcs_private_key_decode(unsigned char *data, unsigned int data_len,
+                                SilcPrivateKey *private_key);
+int silc_pkcs_save_public_key(char *filename, SilcPublicKey public_key,
+                             unsigned int encoding);
+int silc_pkcs_save_public_key_data(char *filename, unsigned char *data,
+                                  unsigned int data_len,
+                                  unsigned int encoding);
+int silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key, 
+                              unsigned char *passphrase,
+                              unsigned int encoding);
+int silc_pkcs_save_private_key_data(char *filename, unsigned char *data, 
+                                   unsigned int data_len,
+                                   unsigned char *passphrase,
+                                   unsigned int encoding);
+int silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key,
+                             unsigned int encoding);
+int silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key,
+                              unsigned int encoding);
 
 #endif
index c7deb1b482f84a7cfd9d29984afbd883dc7695f7..df7282dc3e1ca72ee0921af9362ace075ba7473e 100644 (file)
 /*
  * $Id$
  * $Log$
+ * Revision 1.3  2000/07/10 05:36:14  priikone
+ *     Added silc_rng_get_rng_data to get variable length binary data.
+ *
+ * Revision 1.2  2000/07/05 06:08:43  priikone
+ *     Global cosmetic change.
+ *
  * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
- *     Importet from internal CVS/Added Log headers.
+ *     Imported from internal CVS/Added Log headers.
  *
  *
  */
@@ -112,10 +118,6 @@ SilcRng silc_rng_alloc()
   SILC_LOG_DEBUG(("Allocating new RNG object"));
 
   new = silc_calloc(1, sizeof(*new));
-  if (!new) {
-    SILC_LOG_ERROR(("Could not allocate new RNG object"));
-    return NULL;
-  }
 
   memset(new->pool, 0, sizeof(new->pool));
   memset(new->key, 0, sizeof(new->key));
@@ -151,13 +153,13 @@ void silc_rng_init(SilcRng rng)
   SILC_LOG_DEBUG(("Initializing RNG object"));
 
   /* Initialize the states for the RNG. */
-  rng->state = silc_malloc(sizeof(*rng->state));
+  rng->state = silc_calloc(1, sizeof(*rng->state));
   rng->state->low = 0;
   rng->state->pos = 8;
   rng->state->next = NULL;
   first = rng->state;
   for (i = SILC_RNG_STATE_NUM - 1; i >= 1; i--) {
-    next = silc_malloc(sizeof(*rng->state));
+    next = silc_calloc(1, sizeof(*rng->state));
     next->low = 
       (i * (sizeof(rng->pool) / SILC_RNG_STATE_NUM));
     next->pos =
@@ -424,11 +426,24 @@ unsigned char *silc_rng_get_rn_string(SilcRng rng, unsigned int len)
   unsigned char *string;
 
   string = silc_calloc((len * 2 + 1), sizeof(unsigned char));
-  if (string == NULL)
-    return NULL;
 
   for (i = 0; i < len; i++)
     sprintf(string + 2 * i, "%02x", silc_rng_get_byte(rng));
 
   return string;
 }
+
+/* Returns random number binary data. */
+
+unsigned char *silc_rng_get_rn_data(SilcRng rng, unsigned int len)
+{
+  int i;
+  unsigned char *data;
+
+  data = silc_calloc(len + 1, sizeof(*data));
+
+  for (i = 0; i < len; i++)
+    data[i] = silc_rng_get_byte(rng);
+
+  return data;
+}
index c35f864974d9a16ca2eba54923204f03df988a33..7dfc2d78982823b293eaa30589509bc8c5f45844 100644 (file)
@@ -47,5 +47,6 @@ unsigned char silc_rng_get_byte(SilcRng rng);
 unsigned short silc_rng_get_rn16(SilcRng rng);
 unsigned int silc_rng_get_rn32(SilcRng rng);
 unsigned char *silc_rng_get_rn_string(SilcRng rng, unsigned int len);
+unsigned char *silc_rng_get_rn_data(SilcRng rng, unsigned int len);
 
 #endif
index 32e35dfecaee570edeb170cf31a489772d5591aa..565bb8e31eb94acc04193b99c9e3e67e431ce9a5 100644 (file)
@@ -20,8 +20,8 @@
 /*
  * $Id$
  * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
- *     Importet from internal CVS/Added Log headers.
+ * Revision 1.1  2000/06/27 11:36:55  priikone
+ * Initial revision
  *
  *
  */
index 436ad72d221e5788591da4ddca6888965b9c63e3..91be08de53f680ed2efdfb799afe3c2f9d3257a2 100644 (file)
 
 AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
 
-SUBDIRS = gmp-3.0.1
+SUBDIRS = gmp
 
 noinst_LIBRARIES = libsilcmath.a
 
 libsilcmath_a_SOURCES = \
        silcprimegen.c \
-       modinv.c
+       modinv.c \
+       mpbin.c
 
 EXTRA_DIST = *.h
 
 INCLUDES = -I. -I.. -I../silccrypt -I../silccore -I../silcske \
-       -I../silcsim -I../.. -I../../includes \
-       -I./gmp-3.0.1
+       -I../silcsim -I../.. -I../silcutil -I../../includes \
+       -I./gmp -I../trq
diff --git a/lib/silcmath/mpbin.c b/lib/silcmath/mpbin.c
new file mode 100644 (file)
index 0000000..1e937eb
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+
+  mpbin.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 2000 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
+  GNU General Public License for more details.
+
+*/
+
+#include "silcincludes.h"
+
+/* Encodes MP integer into binary data. Returns allocated data that
+   must be free'd by the caller. */
+
+unsigned char *silc_mp_mp2bin(SilcInt *val, unsigned int *ret_len)
+{
+  int i;
+  unsigned int size;
+  unsigned char *ret;
+  SilcInt tmp;
+
+  size = (silc_mp_sizeinbase(val, 2) + 7) / 8;
+  ret = silc_calloc(size, sizeof(*ret));
+
+  silc_mp_init_set(&tmp, val);
+
+  for (i = size; i > 0; i--) {
+    ret[i - 1] = (unsigned char)(silc_mp_get_ui(&tmp) & 0xff);
+    silc_mp_fdiv_q_2exp(&tmp, &tmp, 8);
+  }
+
+  silc_mp_clear(&tmp);
+
+  if (ret_len)
+    *ret_len = size;
+
+  return ret;
+}
+
+/* Decodes binary data into MP integer. The integer sent as argument
+   must be initialized. */
+
+void silc_mp_bin2mp(unsigned char *data, unsigned int len, SilcInt *ret)
+{
+  int i;
+
+  silc_mp_set_ui(ret, 0);
+
+  for (i = 0; i < len; i++) {
+    silc_mp_mul_2exp(ret, ret, 8);
+    silc_mp_add_ui(ret, ret, data[i]);
+  }
+}
similarity index 55%
rename from lib/silccrypt/dfc_internal.h
rename to lib/silcmath/mpbin.h
index 5ab4e0abc3450a13687008ae6c82e35cd234204c..41ebf12b711ff1365a991b60f0b605621ccf1252 100644 (file)
@@ -1,10 +1,10 @@
 /*
 
-  dfc_internal.h
-
+  mpbin.h
+  
   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
 
-  Copyright (C) 1997 - 2000 Pekka Riikonen
+  Copyright (C) 2000 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
 
 */
 
-#ifndef DFC_INTERNAL_H
-#define DFC_INTERNAL_H
-
-/* Cipher's context */
-typedef struct {
-  u4byte l_key[32];
-} DfcContext;
+#ifndef MPBIN_H
+#define MPBIN_H
 
-/* Prototypes */
-u4byte *dfc_set_key(DfcContext *ctx,
-                   const u4byte in_key[], const u4byte key_len);
-void dfc_encrypt(DfcContext *ctx,
-                const u4byte in_blk[4], u4byte out_blk[4]);
-void dfc_decrypt(DfcContext *ctx,
-                const u4byte in_blk[4], u4byte out_blk[4]);
+unsigned char *silc_mp_mp2bin(SilcInt *val, unsigned int *ret_len);
+void silc_mp_bin2mp(unsigned char *data, unsigned int len, SilcInt *ret);
 
 #endif
index aaa1fc1169dc03f5b4e70615203c7abccb561125..737a09ad8bcf97eccae4a4982b29c45214dce3c2 100644 (file)
@@ -23,6 +23,9 @@
 /*
  * $Id$
  * $Log$
+ * Revision 1.2  2000/07/05 06:06:52  priikone
+ *     Global cosmetic change.
+ *
  * Revision 1.1.1.1  2000/06/27 11:36:51  priikone
  *     Importet from internal CVS/Added Log headers.
  *
@@ -247,7 +250,7 @@ int silc_math_gen_prime(SilcInt *prime, unsigned int bits, int verbose)
 
   /* Init modulo table with the prime candidate and the primes
      in the primetable. */
-  spmods = silc_malloc(sizeof(primetable) * sizeof(unsigned int));
+  spmods = silc_calloc(1, sizeof(primetable) * sizeof(unsigned int));
   for (i = 0; primetable[i] != 0; i++) {
     silc_mp_mod_ui(&tmp, prime, primetable[i]);
     spmods[i] = silc_mp_get_ui(&tmp);
index dc920e8d78e392088c694abe5c4770f2916108e9..3d761a4d76b8418c7c83573fb2e5bb3a8b132563 100644 (file)
@@ -71,5 +71,5 @@ CLEANFILES = $(SIM_MODULES_DIR)/*.sim.so
 EXTRA_DIST = *.h
 
 INCLUDES = -I. -I.. -I../silccrypt -I../silcmath -I../silcske \
-       -I../silccore -I../.. -I../../includes \
-       -I../silcmath/gmp-3.0.1
+       -I../silccore -I../.. -I../silcutil -I../../includes \
+       -I../silcmath/gmp -I../trq
diff --git a/lib/silcsim/modules/Makefile.in b/lib/silcsim/modules/Makefile.in
deleted file mode 100644 (file)
index 1fa3227..0000000
+++ /dev/null
@@ -1,184 +0,0 @@
-# Makefile.in generated automatically by automake 1.3 from Makefile.am
-
-# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
-# This Makefile.in is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
-# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-# PARTICULAR PURPOSE.
-
-#
-#  Makefile.am
-#
-#  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
-#
-#  Copyright (C) 2000 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
-#  GNU General Public License for more details.
-#
-
-
-SHELL = /bin/sh
-
-srcdir = @srcdir@
-top_srcdir = @top_srcdir@
-VPATH = @srcdir@
-prefix = @prefix@
-exec_prefix = @exec_prefix@
-
-bindir = @bindir@
-sbindir = @sbindir@
-libexecdir = @libexecdir@
-datadir = @datadir@
-sysconfdir = @sysconfdir@
-sharedstatedir = @sharedstatedir@
-localstatedir = @localstatedir@
-libdir = @libdir@
-infodir = @infodir@
-mandir = @mandir@
-includedir = @includedir@
-oldincludedir = /usr/include
-
-DISTDIR =
-
-pkgdatadir = $(datadir)/@PACKAGE@
-pkglibdir = $(libdir)/@PACKAGE@
-pkgincludedir = $(includedir)/@PACKAGE@
-
-top_builddir = ../../..
-
-ACLOCAL = @ACLOCAL@
-AUTOCONF = @AUTOCONF@
-AUTOMAKE = @AUTOMAKE@
-AUTOHEADER = @AUTOHEADER@
-
-INSTALL = @INSTALL@
-INSTALL_PROGRAM = @INSTALL_PROGRAM@
-INSTALL_DATA = @INSTALL_DATA@
-INSTALL_SCRIPT = @INSTALL_SCRIPT@
-transform = @program_transform_name@
-
-NORMAL_INSTALL = :
-PRE_INSTALL = :
-POST_INSTALL = :
-NORMAL_UNINSTALL = :
-PRE_UNINSTALL = :
-POST_UNINSTALL = :
-build_alias = @build_alias@
-build_triplet = @build@
-host_alias = @host_alias@
-host_triplet = @host@
-target_alias = @target_alias@
-target_triplet = @target@
-CC = @CC@
-LN_S = @LN_S@
-MAKEINFO = @MAKEINFO@
-PACKAGE = @PACKAGE@
-RANLIB = @RANLIB@
-VERSION = @VERSION@
-
-AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
-mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
-CONFIG_HEADER = ../../../includes/silcdefs.h
-CONFIG_CLEAN_FILES = 
-DIST_COMMON =  Makefile.am Makefile.in
-
-
-DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
-
-TAR = tar
-GZIP = --best
-all: Makefile
-
-.SUFFIXES:
-$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
-       cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/silcsim/modules/Makefile
-
-Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
-       cd $(top_builddir) \
-         && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
-
-tags: TAGS
-TAGS:
-
-
-distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
-
-subdir = lib/silcsim/modules
-
-distdir: $(DISTFILES)
-       @for file in $(DISTFILES); do \
-         d=$(srcdir); \
-         test -f $(distdir)/$$file \
-         || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
-         || cp -p $$d/$$file $(distdir)/$$file; \
-       done
-info:
-dvi:
-check: all
-       $(MAKE)
-installcheck:
-install-exec: 
-       @$(NORMAL_INSTALL)
-
-install-data: 
-       @$(NORMAL_INSTALL)
-
-install: install-exec install-data all
-       @:
-
-uninstall: 
-
-install-strip:
-       $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install
-installdirs:
-
-
-mostlyclean-generic:
-       -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
-
-clean-generic:
-       -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
-
-distclean-generic:
-       -rm -f Makefile $(DISTCLEANFILES)
-       -rm -f config.cache config.log stamp-h stamp-h[0-9]*
-       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-
-maintainer-clean-generic:
-       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
-       -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
-mostlyclean:  mostlyclean-generic
-
-clean:  clean-generic mostlyclean
-
-distclean:  distclean-generic clean
-       -rm -f config.status
-
-maintainer-clean:  maintainer-clean-generic distclean
-       @echo "This command is intended for maintainers to use;"
-       @echo "it deletes files that may require special tools to rebuild."
-
-.PHONY: tags distdir info dvi installcheck install-exec install-data \
-install uninstall all installdirs mostlyclean-generic distclean-generic \
-clean-generic maintainer-clean-generic clean mostlyclean distclean \
-maintainer-clean
-
-
-all:
-       -cd ..
-
-# Tell versions [3.59,3.63) of GNU make to not export all variables.
-# Otherwise a system limit (for SysV at least) may be exceeded.
-.NOEXPORT:
index 5afc108db31dec3f049f21e96a43ed0b1250643d..ab9b3433615c6923d212c040773869922626aa46 100644 (file)
@@ -108,6 +108,7 @@ int silc_sim_close(SilcSimContext *sim)
 
   /* Close the library */
   dlclose(sim->handle);
+  sim->handle = NULL;
 
   return TRUE;
 }
index dcc56ed7e0eaca0aad3f92fe59cac0df1c13b7d4..c8338ad1f215d52f03807d7f98e887e353a83d45 100644 (file)
@@ -27,6 +27,6 @@ libsilcske_a_SOURCES = \
 
 EXTRA_DIST = *.h
 
-INCLUDES = -I. -I.. -I../silccrypt -I../silccore \
+INCLUDES = -I. -I.. -I../silccrypt -I../silccore -I../silcutil \
        -I../silcsim -I../silcmath -I../.. -I../../includes \
-        -I../silcmath/gmp-3.0.1
+        -I../silcmath/gmp -I../trq
index a37b9db3dbf4c53176d88f612ea7889580ff2cfa..18d70c6c29027f6af6bdd1a4a13f26f4828e25a0 100644 (file)
 /*
  * $Id$
  * $Log$
+ * Revision 1.2  2000/07/05 06:05:15  priikone
+ *     Global cosmetic change.
+ *
  * Revision 1.1.1.1  2000/06/27 11:36:56  priikone
- *     Importet from internal CVS/Added Log headers.
+ *     Imported from internal CVS/Added Log headers.
  *
  *
  */
index 45c9c7cc5c0fb0661cd6345ff09f35c740fd9d22..718e6bc2d94a331ebc586c3ab81c70f3d39c80a1 100644 (file)
 /*
  * $Id$
  * $Log$
+ * Revision 1.6  2000/10/31 19:48:31  priikone
+ *     A LOT updates. Cannot separate. :)
+ *
+ * Revision 1.5  2000/07/19 07:04:37  priikone
+ *     Added version detection support to SKE. Minor bugfixes.
+ *
+ * Revision 1.4  2000/07/10 05:34:22  priikone
+ *     Added mp binary encoding as protocols defines.
+ *
+ * Revision 1.3  2000/07/07 06:46:43  priikone
+ *     Removed ske_verify_public_key function as it is not needed
+ *     anymore. Added support to the public key verification as callback
+ *     function. Other minor changes and bug fixes.
+ *
+ * Revision 1.2  2000/07/05 06:05:15  priikone
+ *     Global cosmetic change.
+ *
  * Revision 1.1.1.1  2000/06/27 11:36:56  priikone
- *     Importet from internal CVS/Added Log headers.
+ *     Imported from internal CVS/Added Log headers.
  *
  *
  */
@@ -50,10 +67,6 @@ SilcSKEStatus silc_ske_payload_start_encode(SilcSKE ske,
 
   /* Allocate channel payload buffer. */
   buf = silc_buffer_alloc(payload->len);
-  if (!buf) {
-    SILC_LOG_ERROR(("Could not allocate encode buffer"));
-    return SILC_SKE_STATUS_ERROR;
-  }
 
   silc_buffer_pull_tail(buf, payload->len);
 
@@ -64,6 +77,9 @@ SilcSKEStatus silc_ske_payload_start_encode(SilcSKE ske,
                     SILC_STR_UI_SHORT(payload->len),
                     SILC_STR_UI_XNSTRING(payload->cookie, 
                                          payload->cookie_len),
+                    SILC_STR_UI_SHORT(payload->version_len),
+                    SILC_STR_UI_XNSTRING(payload->version, 
+                                         payload->version_len),
                     SILC_STR_UI_SHORT(payload->ke_grp_len),
                     SILC_STR_UI_XNSTRING(payload->ke_grp_list,
                                          payload->ke_grp_len),
@@ -115,6 +131,8 @@ silc_ske_payload_start_decode(SilcSKE ske,
                       SILC_STR_UI_CHAR(&payload->flags),
                       SILC_STR_UI_SHORT(&payload->len),
                       SILC_STR_UI_XNSTRING(&buf, SILC_SKE_COOKIE_LEN),
+                      SILC_STR_UI16_NSTRING_ALLOC(&payload->version,
+                                                  &payload->version_len),
                       SILC_STR_UI_SHORT(&payload->ke_grp_len),
                       SILC_STR_END);
 
@@ -136,7 +154,7 @@ silc_ske_payload_start_decode(SilcSKE ske,
     goto err;
   }
 
-  len2 = len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN + 2;
+  len2 = len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN + 2 + payload->version_len + 2;
   silc_buffer_pull(buffer, len);
 
   /* Copy cookie from payload */
@@ -242,6 +260,7 @@ silc_ske_payload_start_decode(SilcSKE ske,
  err:
   silc_ske_payload_start_free(payload);
 
+  ske->status = status;
   return status;
 }
 
@@ -252,6 +271,8 @@ void silc_ske_payload_start_free(SilcSKEStartPayload *payload)
   if (payload) {
     if (payload->cookie)
       silc_free(payload->cookie);
+    if (payload->version)
+      silc_free(payload->version);
     if (payload->ke_grp_list)
       silc_free(payload->ke_grp_list);
     if (payload->pkcs_alg_list)
@@ -275,31 +296,30 @@ SilcSKEStatus silc_ske_payload_one_encode(SilcSKE ske,
 {
   SilcBuffer buf;
   unsigned char *e_str;
-  unsigned short e_len;
+  unsigned int e_len;
 
   SILC_LOG_DEBUG(("Encoding KE 1 Payload"));
 
   if (!payload)
     return SILC_SKE_STATUS_ERROR;
 
-  /* Encode the integer into HEX string */
-  e_len = silc_mp_sizeinbase(&payload->e, 16);
-  e_str = silc_calloc(e_len + 1, sizeof(unsigned char));
-  silc_mp_get_str(e_str, 16, &payload->e);
+  /* Encode the integer into binary data */
+  e_str = silc_mp_mp2bin(&payload->e, &e_len);
+  if (!e_str)
+    return SILC_SKE_STATUS_ERROR;
 
   /* Allocate channel payload buffer. The length of the buffer
      is 2 + e. */
-  buf = silc_buffer_alloc(e_len + 2);
-  if (!buf) {
-    SILC_LOG_ERROR(("Could not allocate encode buffer"));
-    return SILC_SKE_STATUS_ERROR;
-  }
-
-  silc_buffer_pull_tail(buf, e_len + 2);
+  buf = silc_buffer_alloc(e_len + 2 + payload->pk_len + 2 + 2);
+  silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
 
   /* Encode the payload */
   silc_buffer_format(buf, 
-                    SILC_STR_UI_SHORT(e_len + 2),
+                    SILC_STR_UI_SHORT(payload->pk_len),
+                    SILC_STR_UI_SHORT(payload->pk_type),
+                    SILC_STR_UI_XNSTRING(payload->pk_data, 
+                                         payload->pk_len),
+                    SILC_STR_UI_SHORT(e_len),
                     SILC_STR_UI_XNSTRING(e_str, e_len),
                     SILC_STR_END);
 
@@ -321,6 +341,7 @@ SilcSKEStatus silc_ske_payload_one_decode(SilcSKE ske,
 {
   SilcSKEOnePayload *payload;
   SilcSKEStatus status = SILC_SKE_STATUS_ERROR;
+  unsigned char *e;
   unsigned short e_len;
 
   SILC_LOG_DEBUG(("Decoding Key Exchange 1 Payload"));
@@ -329,35 +350,40 @@ SilcSKEStatus silc_ske_payload_one_decode(SilcSKE ske,
 
   payload = silc_calloc(1, sizeof(*payload));
 
-  memset(buf, 0, sizeof(buf));
-
-  /* Parse the payload */
   silc_buffer_unformat(buffer,
-                      SILC_STR_UI_SHORT(&e_len),
+                      SILC_STR_UI_SHORT(&payload->pk_len),
+                      SILC_STR_UI_SHORT(&payload->pk_type),
                       SILC_STR_END);
                       
-  if (e_len < 1) {
-    status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
+  if (payload->pk_len < 5) {
+    status = SILC_SKE_STATUS_BAD_PAYLOAD;
     goto err;
   }
 
-  if (e_len != buffer->len) {
-    status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
+  silc_buffer_pull(buffer, 2 + 2);
+  silc_buffer_unformat(buffer,
+                      SILC_STR_UI_XNSTRING_ALLOC(&payload->pk_data,
+                                                 payload->pk_len),
+                      SILC_STR_UI16_NSTRING_ALLOC(&e, &e_len),
+                      SILC_STR_END);
+
+  if (e_len < 3) {
+    status = SILC_SKE_STATUS_BAD_PAYLOAD;
     goto err;
   }
 
-  /* Length includes the length field length as well. Remove it. */
-  e_len -= 2;
+  silc_buffer_push(buffer, 2 + 2);
 
-  silc_buffer_unformat(buffer,
-                      SILC_STR_UI_SHORT(NULL),
-                      SILC_STR_UI_XNSTRING(&buf, e_len),
-                      SILC_STR_END);
+  if (payload->pk_len + 2 + 2 + 2 + e_len != buffer->len) {
+    status = SILC_SKE_STATUS_BAD_PAYLOAD;
+    goto err;
+  }
 
   /* Decode the HEX string to integer */
   silc_mp_init(&payload->e);
-  silc_mp_set_str(&payload->e, buf, 16);
-  memset(buf, 0, sizeof(buf));
+  silc_mp_bin2mp(e, e_len, &payload->e);
+  memset(e, 0, sizeof(e_len));
+  silc_free(e);
 
   /* Return the payload */
   *return_payload = payload;
@@ -366,7 +392,7 @@ SilcSKEStatus silc_ske_payload_one_decode(SilcSKE ske,
 
  err:
   silc_free(payload);
-
+  ske->status = status;
   return status;
 }
 
@@ -375,7 +401,8 @@ SilcSKEStatus silc_ske_payload_one_decode(SilcSKE ske,
 void silc_ske_payload_one_free(SilcSKEOnePayload *payload)
 {
   if (payload) {
-    silc_mp_clear(&payload->e);
+    if (payload->pk_data)
+      silc_free(payload->pk_data);
     silc_free(payload);
   }
 }
@@ -398,30 +425,24 @@ SilcSKEStatus silc_ske_payload_two_encode(SilcSKE ske,
     return SILC_SKE_STATUS_ERROR;
 
   /* Encode the integer into HEX string */
-  f_len = silc_mp_sizeinbase(&payload->f, 16);
-  f_str = silc_calloc(f_len + 1, sizeof(unsigned char));
-  silc_mp_get_str(f_str, 16, &payload->f);
+  f_str = silc_mp_mp2bin(&payload->f, &f_len);
 
   /* Allocate channel payload buffer. The length of the buffer
      is 2 + 2 + public key + 2 + f + 2 + signature. */
   len = payload->pk_len + 2 + 2 + f_len + 2 + payload->sign_len + 2;
   buf = silc_buffer_alloc(len);
-  if (!buf) {
-    SILC_LOG_ERROR(("Could not allocate encode buffer"));
-    return SILC_SKE_STATUS_ERROR;
-  }
 
   silc_buffer_pull_tail(buf, len);
 
   /* Encode the payload */
   silc_buffer_format(buf, 
-                    SILC_STR_UI_SHORT(payload->pk_len + 4),
+                    SILC_STR_UI_SHORT(payload->pk_len),
                     SILC_STR_UI_SHORT(payload->pk_type),
                     SILC_STR_UI_XNSTRING(payload->pk_data, 
                                          payload->pk_len),
-                    SILC_STR_UI_SHORT(f_len + 2),
+                    SILC_STR_UI_SHORT(f_len),
                     SILC_STR_UI_XNSTRING(f_str, f_len),
-                    SILC_STR_UI_SHORT(payload->sign_len + 2),
+                    SILC_STR_UI_SHORT(payload->sign_len),
                     SILC_STR_UI_XNSTRING(payload->sign_data, 
                                          payload->sign_len),
                     SILC_STR_END);
@@ -444,6 +465,7 @@ SilcSKEStatus silc_ske_payload_two_decode(SilcSKE ske,
 {
   SilcSKEStatus status = SILC_SKE_STATUS_ERROR;
   SilcSKETwoPayload *payload;
+  unsigned char *f;
   unsigned short f_len;
   unsigned int tot_len = 0, len2;
 
@@ -463,65 +485,44 @@ SilcSKEStatus silc_ske_payload_two_decode(SilcSKE ske,
                       SILC_STR_END);
 
   if (payload->pk_len < 5) {
-    status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
+    status = SILC_SKE_STATUS_BAD_PAYLOAD;
     goto err;
   }
 
-  tot_len += payload->pk_len;
+  tot_len += payload->pk_len + 4;
 
-  payload->pk_len -= 4;
   silc_buffer_pull(buffer, 4);
   silc_buffer_unformat(buffer,
-                      SILC_STR_UI_XNSTRING(&buf, payload->pk_len),
-                      SILC_STR_UI_SHORT(&f_len),
+                      SILC_STR_UI_XNSTRING_ALLOC(&payload->pk_data,
+                                                 payload->pk_len),
+                      SILC_STR_UI16_NSTRING_ALLOC(&f, &f_len),
+                      SILC_STR_UI16_NSTRING_ALLOC(&payload->sign_data, 
+                                                  &payload->sign_len),
                       SILC_STR_END);
 
+  tot_len += f_len + 2;
+  tot_len += payload->sign_len + 2;
+
   if (f_len < 3) {
-    status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
+    status = SILC_SKE_STATUS_BAD_PAYLOAD;
     goto err;
   }
 
-  tot_len += f_len;
-
-  payload->pk_data = silc_calloc(payload->pk_len + 1, 
-                                sizeof(unsigned char));
-  memcpy(payload->pk_data, buf, payload->pk_len);
-  memset(buf, 0, sizeof(buf));
-
-  f_len -= 2;
-  silc_buffer_pull(buffer, payload->pk_len + 2);
-  silc_buffer_unformat(buffer,
-                      SILC_STR_UI_XNSTRING(&buf, f_len),
-                      SILC_STR_UI_SHORT(&payload->sign_len),
-                      SILC_STR_END);
-
   if (payload->sign_len < 3) {
-    status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
+    status = SILC_SKE_STATUS_BAD_PAYLOAD;
     goto err;
   }
 
-  tot_len += payload->sign_len;
-
   if (tot_len != len2) {
-    status = SILC_SKE_STATUS_BAD_PAYLOAD_LENGTH;
+    status = SILC_SKE_STATUS_BAD_PAYLOAD;
     goto err;
   }
   
   /* Decode the HEX string to integer */
   silc_mp_init(&payload->f);
-  silc_mp_set_str(&payload->f, buf, 16);
-  memset(buf, 0, sizeof(buf));
-
-  payload->sign_len -= 2;
-  silc_buffer_pull(buffer, f_len + 2);
-  silc_buffer_unformat(buffer,
-                      SILC_STR_UI_XNSTRING(&buf, payload->sign_len),
-                      SILC_STR_END);
-
-  payload->sign_data = silc_calloc(payload->sign_len + 1, 
-                                sizeof(unsigned char));
-  memcpy(payload->sign_data, buf, payload->sign_len);
-  memset(buf, 0, sizeof(buf));
+  silc_mp_bin2mp(f, f_len, &payload->f);
+  memset(f, 0, sizeof(f_len));
+  silc_free(f);
 
   /* Return the payload */
   *return_payload = payload;
@@ -534,7 +535,7 @@ SilcSKEStatus silc_ske_payload_two_decode(SilcSKE ske,
   if (payload->sign_data)
     silc_free(payload->sign_data);
   silc_free(payload);
-
+  ske->status = status;
   return status;
 }
 
@@ -547,7 +548,6 @@ void silc_ske_payload_two_free(SilcSKETwoPayload *payload)
       silc_free(payload->pk_data);
     if (payload->sign_data)
       silc_free(payload->sign_data);
-    silc_mp_clear(&payload->f);
     silc_free(payload);
   }
 }
index f866f46ee3195bf832f0bd0a8c4fa10f8a9fb0f6..c91b3aeedf860de0ba64f4eb9c916dd16cae07eb 100644 (file)
 /* SILC Key Exchange Start Payload */
 typedef struct {
   unsigned char flags;
-  unsigned int len;
+  unsigned short len;
 
   unsigned char *cookie;
   unsigned short cookie_len;
 
+  unsigned char *version;
+  unsigned short version_len;
+
   unsigned short ke_grp_len;
   unsigned char *ke_grp_list;
 
@@ -47,6 +50,10 @@ typedef struct {
 
 /* SILC Key Exchange 1 Payload */
 typedef struct {
+  unsigned short pk_len;
+  unsigned char *pk_data;
+  unsigned short pk_type;
+
   SilcInt e;
 } SilcSKEOnePayload;
 
index 8d36c09653dcc1e5d58e4776bd37786ebc8fdba2..0dac063376bdd3490cf231c9c9faefc128fd3afa 100644 (file)
   GNU General Public License for more details.
 
 */
-/*
- * $Id$
- * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:56  priikone
- *     Importet from internal CVS/Added Log headers.
- *
- *
- */
+/* $Id$ */
 
 #include "silcincludes.h"
 #include "payload_internal.h"
@@ -39,10 +32,7 @@ SilcSKE silc_ske_alloc()
   SILC_LOG_DEBUG(("Allocating new Key Exchange object"));
 
   ske = silc_calloc(1, sizeof(*ske));
-  if (!ske) {
-    SILC_LOG_ERROR(("Could not allocate new SKE object"));
-    return NULL;
-  }
+  ske->status = SILC_SKE_STATUS_OK;
 
   return ske;
 }
@@ -82,8 +72,10 @@ void silc_ske_free(SilcSKE ske)
       silc_buffer_free(ske->start_payload_copy);
     if (ske->pk)
       silc_free(ske->pk);
+    /* XXX
     silc_mp_clear(&ske->x);
     silc_mp_clear(&ske->KEY);
+    */
     if (ske->hash)
       silc_free(ske->hash);
     silc_free(ske);
@@ -209,6 +201,7 @@ SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske,
   if (status == SILC_SKE_STATUS_OK)
     return SILC_SKE_STATUS_ERROR;
 
+  ske->status = status;
   return status;
 }
 
@@ -217,6 +210,7 @@ SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske,
    Key Exchange 1 Payload. */
 
 SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
+                                        SilcPublicKey public_key,
                                         SilcSKESendPacketCb send_packet,
                                         void *context)
 {
@@ -224,6 +218,7 @@ SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
   SilcBuffer payload_buf;
   SilcInt x, e;
   SilcSKEOnePayload *payload;
+  unsigned int pk_len;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -248,6 +243,9 @@ SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
   /* Encode the result to Key Exchange 1 Payload. */
   payload = silc_calloc(1, sizeof(*payload));
   payload->e = e;
+  payload->pk_data = silc_pkcs_public_key_encode(public_key, &pk_len);
+  payload->pk_len = pk_len;
+  payload->pk_type = SILC_SKE_PK_TYPE_SILC;
   status = silc_ske_payload_one_encode(ske, payload, &payload_buf);
   if (status != SILC_SKE_STATUS_OK) {
     silc_mp_clear(&x);
@@ -274,11 +272,14 @@ SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
 
 SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
                                        SilcBuffer ke2_payload,
+                                       SilcSKEVerifyCb verify_key,
+                                       void *verify_context,
                                        SilcSKECb callback,
                                        void *context)
 {
   SilcSKEStatus status = SILC_SKE_STATUS_OK;
   SilcSKETwoPayload *payload;
+  SilcPublicKey public_key = NULL;
   SilcInt KEY;
   unsigned char hash[32];
   unsigned int hash_len;
@@ -300,12 +301,19 @@ SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
 
   SILC_LOG_DEBUG(("Verifying public key"));
 
-  /* Verify the public key */ /* XXX */
-  status = silc_ske_verify_public_key(ske, payload->pk_data, 
-                                     payload->pk_len);
-  if (status != SILC_SKE_STATUS_OK)
+  if (!silc_pkcs_public_key_decode(payload->pk_data, payload->pk_len, 
+                                  &public_key)) {
+    status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
     goto err;
-  
+  }
+
+  if (verify_key) {
+    status = (*verify_key)(ske, payload->pk_data, payload->pk_len,
+                          payload->pk_type, verify_context);
+    if (status != SILC_SKE_STATUS_OK)
+      goto err;
+  }  
+
   SILC_LOG_DEBUG(("Public key is authentic"));
 
   /* Compute the hash value */
@@ -320,7 +328,8 @@ SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
   SILC_LOG_DEBUG(("Verifying signature"));
 
   /* Verify signature */
-  silc_pkcs_set_public_key(ske->prop->pkcs, payload->pk_data, payload->pk_len);
+  silc_pkcs_public_key_data_set(ske->prop->pkcs, public_key->pk, 
+                               public_key->pk_len);
   if (ske->prop->pkcs->pkcs->verify(ske->prop->pkcs->context,
                                    payload->sign_data, payload->sign_len,
                                    hash, hash_len) == FALSE) {
@@ -333,6 +342,7 @@ SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
 
   SILC_LOG_DEBUG(("Signature is Ok"));
 
+  silc_pkcs_public_key_free(public_key);
   memset(hash, 'F', hash_len);
 
   /* Call the callback. */
@@ -342,11 +352,15 @@ SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
   return status;
 
  err:
-  memset(hash, 'F', hash_len);
+  memset(hash, 'F', sizeof(hash));
   silc_ske_payload_two_free(payload);
+  ske->ke2_payload = NULL;
 
   silc_mp_clear(&ske->KEY);
 
+  if (public_key)
+    silc_pkcs_public_key_free(public_key);
+
   if (ske->hash) {
     memset(ske->hash, 'F', hash_len);
     silc_free(ske->hash);
@@ -356,6 +370,7 @@ SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
   if (status == SILC_SKE_STATUS_OK)
     return SILC_SKE_STATUS_ERROR;
 
+  ske->status = status;
   return status;
 }
 
@@ -367,6 +382,7 @@ SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
 
 SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
                                       SilcSocketConnection sock,
+                                      char *version,
                                       SilcBuffer start_payload,
                                       SilcSKECb callback,
                                       void *context)
@@ -390,7 +406,8 @@ SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
 
   /* Parse and select the security properties from the payload */
   payload = silc_calloc(1, sizeof(*payload));
-  status = silc_ske_select_security_properties(ske, payload, remote_payload);
+  status = silc_ske_select_security_properties(ske, version,
+                                              payload, remote_payload);
   if (status != SILC_SKE_STATUS_OK)
     goto err;
 
@@ -411,6 +428,7 @@ SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
   if (status == SILC_SKE_STATUS_OK)
     return SILC_SKE_STATUS_ERROR;
 
+  ske->status = status;
   return status;
 }
 
@@ -485,6 +503,7 @@ SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske,
   if (status == SILC_SKE_STATUS_OK)
     return SILC_SKE_STATUS_ERROR;
 
+  ske->status = status;
   return status;
 }
 
@@ -550,10 +569,8 @@ SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
    encodes Key Exchange 2 Payload and sends it to the other end. */
 
 SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
-                                       unsigned char *pk,
-                                       unsigned int pk_len,
-                                       unsigned char *prv,
-                                       unsigned int prv_len,
+                                       SilcPublicKey public_key,
+                                       SilcPrivateKey private_key,
                                        SilcSKEPKType pk_type,
                                        SilcSKESendPacketCb send_packet,
                                        void *context)
@@ -561,8 +578,8 @@ SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
   SilcSKEStatus status = SILC_SKE_STATUS_OK;
   SilcBuffer payload_buf;
   SilcInt KEY;
-  unsigned char hash[32], sign[256];
-  unsigned int hash_len, sign_len;
+  unsigned char hash[32], sign[256], *pk;
+  unsigned int hash_len, sign_len, pk_len;
 
   SILC_LOG_DEBUG(("Start"));
 
@@ -577,8 +594,8 @@ SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
   SILC_LOG_DEBUG(("Getting public key"));
 
   /* Get the public key */
-  ske->ke2_payload->pk_data = silc_calloc(pk_len, sizeof(unsigned char));
-  memcpy(ske->ke2_payload->pk_data, pk, pk_len);
+  pk = silc_pkcs_public_key_encode(public_key, &pk_len);
+  ske->ke2_payload->pk_data = pk;
   ske->ke2_payload->pk_len = pk_len;
   ske->ke2_payload->pk_type = pk_type;
 
@@ -597,7 +614,8 @@ SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
   SILC_LOG_DEBUG(("Signing HASH value"));
 
   /* Sign the hash value */
-  silc_pkcs_set_private_key(ske->prop->pkcs, prv, prv_len);
+  silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv, 
+                                private_key->prv_len);
   ske->prop->pkcs->pkcs->sign(ske->prop->pkcs->context,
                              hash, hash_len,
                              sign, &sign_len);
@@ -627,6 +645,7 @@ SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
   if (status == SILC_SKE_STATUS_OK)
     return SILC_SKE_STATUS_ERROR;
 
+  ske->status = status;
   return status;
 }
 
@@ -638,18 +657,22 @@ SilcSKEStatus silc_ske_end(SilcSKE ske,
                           SilcSKESendPacketCb send_packet,
                           void *context)
 {
-  SilcSKEStatus status = SILC_SKE_STATUS_OK;
   SilcBuffer packet;
 
   SILC_LOG_DEBUG(("Start"));
 
-  packet = silc_buffer_alloc(1);
-  packet->len = 0;
+  packet = silc_buffer_alloc(4);
+  silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+  silc_buffer_format(packet,
+                    SILC_STR_UI_SHORT(SILC_SKE_STATUS_OK),
+                    SILC_STR_END);
 
   if (send_packet)
     (*send_packet)(ske, packet, SILC_PACKET_SUCCESS, context);
 
-  return status;
+  silc_buffer_free(packet);
+
+  return SILC_SKE_STATUS_OK;
 }
 
 /* Aborts the Key Exchange protocol. This is called if error occurs
@@ -687,23 +710,29 @@ SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status,
 
 SilcSKEStatus 
 silc_ske_assemble_security_properties(SilcSKE ske,
+                                     unsigned char flags,
+                                     char *version,
                                      SilcSKEStartPayload **return_payload)
 {
   SilcSKEStartPayload *rp;
+  int i;
 
   SILC_LOG_DEBUG(("Assembling KE Start Payload"));
 
   rp = silc_calloc(1, sizeof(*rp));
 
-  /* XXX */
   /* Set flags */
-  rp->flags = 0;
+  rp->flags = flags;
 
-  /* XXX */
-  /* Cookie */
-  rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
+  /* Set random cookie */
+  rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(*rp->cookie));
+  for (i = 0; i < SILC_SKE_COOKIE_LEN; i++)
+    rp->cookie[i] = silc_rng_get_byte(ske->rng);
   rp->cookie_len = SILC_SKE_COOKIE_LEN;
-  memcpy(rp->cookie, "1234567890123456", SILC_SKE_COOKIE_LEN);
+
+  /* Put version */
+  rp->version = strdup(version);
+  rp->version_len = strlen(version);
 
   /* Get supported Key Exhange groups */
   rp->ke_grp_list = silc_ske_get_supported_groups();
@@ -727,6 +756,7 @@ silc_ske_assemble_security_properties(SilcSKE ske,
   rp->comp_alg_len = 0;
 
   rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN + 
+    2 + rp->version_len +
     2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len + 
     2 + rp->enc_alg_len + 2 + rp->hash_alg_len + 
     2 + rp->comp_alg_len;
@@ -741,6 +771,7 @@ silc_ske_assemble_security_properties(SilcSKE ske,
 
 SilcSKEStatus 
 silc_ske_select_security_properties(SilcSKE ske,
+                                   char *version,
                                    SilcSKEStartPayload *payload,
                                    SilcSKEStartPayload *remote_payload)
 {
@@ -755,11 +786,18 @@ silc_ske_select_security_properties(SilcSKE ske,
   /* Flags are returned unchanged. */
   payload->flags = rp->flags;
 
-  /* XXX Cookie check?? */
+  /* Take cookie */
   payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
   payload->cookie_len = SILC_SKE_COOKIE_LEN;
   memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
 
+  /* Check version string */
+  silc_ske_check_version(ske, rp->version, rp->version_len);
+
+  /* Put our version to our reply */
+  payload->version = strdup(version);
+  payload->version_len = strlen(version);
+
   /* Get supported Key Exchange groups */
   cp = rp->ke_grp_list;
   if (cp && strchr(cp, ',')) {
@@ -1018,6 +1056,7 @@ silc_ske_select_security_properties(SilcSKE ske,
 #endif
 
   payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN + 
+    2 + payload->version_len + 
     2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len + 
     2 + payload->enc_alg_len + 2 + payload->hash_alg_len + 
     2 + payload->comp_alg_len;
@@ -1038,10 +1077,10 @@ SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcInt n,
   SILC_LOG_DEBUG(("Creating random number"));
 
   /* Get the random number as string */
-  string = silc_rng_get_rn_string(ske->rng, (len / 8));
+  string = silc_rng_get_rn_data(ske->rng, (len / 8));
 
   /* Decode the string into a MP integer */
-  silc_mp_set_str(rnd, string, 16);
+  silc_mp_bin2mp(string, (len / 8), rnd);
   silc_mp_mod_2exp(rnd, rnd, len);
 
   /* Checks */
@@ -1057,17 +1096,6 @@ SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcInt n,
   return status;
 }
 
-/* XXX TODO */
-
-SilcSKEStatus silc_ske_verify_public_key(SilcSKE ske, 
-                                        unsigned char *pubkey,
-                                        unsigned int pubkey_len)
-{
-  SilcSKEStatus status = SILC_SKE_STATUS_OK;
-
-  return status;
-}
-
 /* Creates a hash value HASH as defined in the SKE protocol. */
 
 SilcSKEStatus silc_ske_make_hash(SilcSKE ske, 
@@ -1081,17 +1109,9 @@ SilcSKEStatus silc_ske_make_hash(SilcSKE ske,
 
   SILC_LOG_DEBUG(("Start"));
 
-  e_len = silc_mp_sizeinbase(&ske->ke1_payload->e, 16);
-  e = silc_calloc(e_len + 1, sizeof(unsigned char));
-  silc_mp_get_str(e, 16, &ske->ke1_payload->e);
-
-  f_len = silc_mp_sizeinbase(&ske->ke2_payload->f, 16);
-  f = silc_calloc(f_len + 1, sizeof(unsigned char));
-  silc_mp_get_str(f, 16, &ske->ke2_payload->f);
-
-  KEY_len = silc_mp_sizeinbase(&ske->KEY, 16);
-  KEY = silc_calloc(KEY_len + 1, sizeof(unsigned char));
-  silc_mp_get_str(KEY, 16, &ske->KEY);
+  e = silc_mp_mp2bin(&ske->ke1_payload->e, &e_len);
+  f = silc_mp_mp2bin(&ske->ke2_payload->f, &f_len);
+  KEY = silc_mp_mp2bin(&ske->KEY, &KEY_len);
 
   buf = silc_buffer_alloc(ske->start_payload_copy->len + 
                          ske->pk_len + e_len + f_len + KEY_len);
@@ -1137,9 +1157,8 @@ SilcSKEStatus silc_ske_process_key_material(SilcSKE ske,
                                            unsigned int req_hmac_key_len,
                                            SilcSKEKeyMaterial *key)
 {
-  int i, klen;
+  int klen;
   SilcBuffer buf;
-  SilcInt tmp;
   unsigned char *tmpbuf;
   unsigned char hash[32];
   unsigned int hash_len = ske->prop->hash->hash->hash_len;
@@ -1147,19 +1166,10 @@ SilcSKEStatus silc_ske_process_key_material(SilcSKE ske,
 
   SILC_LOG_DEBUG(("Start"));
 
-  silc_mp_init_set(&tmp, &ske->KEY);
-
-  klen = silc_mp_size(&tmp);
-
-  /* Format the KEY material into binary data */
-  tmpbuf = silc_calloc(klen, sizeof(unsigned char));
-  for (i = klen; i > 0; i--) {
-    tmpbuf[i - 1] = (unsigned char)(silc_mp_get_ui(&tmp) & 0xff);
-    silc_mp_fdiv_q_2exp(&tmp, &tmp, 8);
-  }
+  /* Encode KEY to binary data */
+  tmpbuf = silc_mp_mp2bin(&ske->KEY, &klen);
 
   buf = silc_buffer_alloc(1 + klen + hash_len);
-
   silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf));
   silc_buffer_format(buf,
                     SILC_STR_UI_CHAR(0),
index e429b70f3eaaaebd48f851c40d68c7ca51d20331..55613e4cf3f9fdecf03e2cf886aec541bd3b5172 100644 (file)
@@ -29,6 +29,16 @@ typedef struct SilcSKEStruct *SilcSKE;
 /* Forward declaration for security properties. */
 typedef struct SilcSKESecurityPropertiesStruct *SilcSKESecurityProperties;
 
+/* Supported Public Key Types, defined by the protocol */
+typedef enum {
+  SILC_SKE_PK_TYPE_SILC    = 1,        /* Mandatory type */
+  /* Optional types. These are not implemented currently */
+  SILC_SKE_PK_TYPE_SSH2    = 2,
+  SILC_SKE_PK_TYPE_X509V3  = 3,
+  SILC_SKE_PK_TYPE_OPENPGP = 4,
+  SILC_SKE_PK_TYPE_SPKI    = 5
+} SilcSKEPKType;
+
 /* Packet sending callback. Caller of the SKE routines must provide
    a routine to send packets to negotiation parties. */
 typedef void (*SilcSKESendPacketCb)(SilcSKE ske, SilcBuffer packet, 
@@ -39,16 +49,12 @@ typedef void (*SilcSKESendPacketCb)(SilcSKE ske, SilcBuffer packet,
    callers routine might need (payloads etc). */
 typedef void (*SilcSKECb)(SilcSKE ske, void *context);
 
-/* Supported Public Key Types, defined by the protocol */
-typedef enum {
-  SILC_SKE_PK_TYPE_SILC = 1,   /* Mandatory type */
-  /* Optional types. These are not implemented currently
-  SILC_SKE_PK_TYPE_SSH2 = 2,
-  SILC_SKE_PK_TYPE_X509V3 = 3,
-  SILC_SKE_PK_TYPE_OPENPGP = 4,
-  SILC_SKE_PK_TYPE_SPKI = 5
-  */
-} SilcSKEPKType;
+/* Callback function used to verify the received public key. */
+typedef SilcSKEStatus (*SilcSKEVerifyCb)(SilcSKE ske, 
+                                        unsigned char *pk_data,
+                                        unsigned int pk_len,
+                                        SilcSKEPKType pk_type,
+                                        void *context);
 
 /* Context passed to key material processing function. The function
    returns the processed key material into this structure. */
@@ -63,6 +69,7 @@ typedef struct {
   unsigned int hmac_key_len;
 } SilcSKEKeyMaterial;
 
+/* Length of cookie in Start Payload */
 #define SILC_SKE_COOKIE_LEN 16
 
 #include "groups.h"
@@ -70,9 +77,9 @@ typedef struct {
 
 /* Security Property Flags. */
 typedef enum {
-  SILC_SKE_SP_FLAG_NONE = (1L << 0),
-  SILC_SKE_SP_FLAG_NO_REPLY = (1L << 1),
-  SILC_SKE_SP_FLAG_PFS = (1L << 2),
+  SILC_SKE_SP_FLAG_NONE      = (1L << 0),
+  SILC_SKE_SP_FLAG_NO_REPLY  = (1L << 1),
+  SILC_SKE_SP_FLAG_PFS       = (1L << 2),
 } SilcSKESecurityPropertyFlag;
 
 /* Security Properties negotiated between key exchange parties. This
@@ -128,6 +135,9 @@ struct SilcSKEStruct {
   /* Pointer to the what ever user data. This is set by the caller
      and is not touched by the SKE. The caller must also free this one. */
   void *user_data;
+
+  /* Current status of SKE */
+  SilcSKEStatus status;
 };
 
 /* Prototypes */
@@ -143,14 +153,18 @@ SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske,
                                         SilcSKECb callback,
                                         void *context);
 SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
+                                        SilcPublicKey public_key,
                                         SilcSKESendPacketCb send_packet,
                                         void *context);
 SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
                                        SilcBuffer ke2_payload,
+                                       SilcSKEVerifyCb verify_key,
+                                       void *verify_context,
                                        SilcSKECb callback,
                                        void *context);
 SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
                                       SilcSocketConnection sock,
+                                      char *version,
                                       SilcBuffer start_payload,
                                       SilcSKECb callback,
                                       void *context);
@@ -163,10 +177,8 @@ SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
                                         SilcSKECb callback,
                                         void *context);
 SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
-                                       unsigned char *pk,
-                                       unsigned int pk_len,
-                                       unsigned char *prv,
-                                       unsigned int prv_len,
+                                       SilcPublicKey public_key,
+                                       SilcPrivateKey private_key,
                                        SilcSKEPKType pk_type,
                                        SilcSKESendPacketCb send_packet,
                                        void *context);
@@ -178,17 +190,17 @@ SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status,
                             void *context);
 SilcSKEStatus 
 silc_ske_assemble_security_properties(SilcSKE ske,
+                                     unsigned char flags,
+                                     char *version,
                                      SilcSKEStartPayload **return_payload);
 SilcSKEStatus 
 silc_ske_select_security_properties(SilcSKE ske,
+                                   char *version,
                                    SilcSKEStartPayload *payload,
                                    SilcSKEStartPayload *remote_payload);
 SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcInt n, 
                                  unsigned int len, 
                                  SilcInt *rnd);
-SilcSKEStatus silc_ske_verify_public_key(SilcSKE ske, 
-                                        unsigned char *pubkey,
-                                        unsigned int pubkey_len);
 SilcSKEStatus silc_ske_make_hash(SilcSKE ske, 
                                 unsigned char *return_hash,
                                 unsigned int *return_hash_len);
@@ -197,4 +209,7 @@ SilcSKEStatus silc_ske_process_key_material(SilcSKE ske,
                                            unsigned int req_enc_key_len,
                                            unsigned int req_hmac_key_len,
                                            SilcSKEKeyMaterial *key);
+SilcSKEStatus silc_ske_check_version(SilcSKE ske,
+                                    unsigned char *version,
+                                    unsigned int version_len);
 #endif
index f512354f1179aee5c0a0cdcaa0ba50546a2768cd..d81ed54cd8c586f18f398348f5802260f68344aa 100644 (file)
 /* Status flags returned by all SKE routines */
 typedef enum {
   /* These are defined by the protocol */
-  SILC_SKE_STATUS_OK = 0,
-  SILC_SKE_STATUS_ERROR = 1,
-  SILC_SKE_STATUS_BAD_PAYLOAD = 2,
-  SILC_SKE_STATUS_UNKNOWN_GROUP = 3,
-  SILC_SKE_STATUS_UNKNOWN_CIPHER = 4,
-  SILC_SKE_STATUS_UNKNOWN_PKCS = 5,
-  SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION = 6,
+  SILC_SKE_STATUS_OK                     = 0,
+  SILC_SKE_STATUS_ERROR                  = 1,
+  SILC_SKE_STATUS_BAD_PAYLOAD            = 2,
+  SILC_SKE_STATUS_UNKNOWN_GROUP          = 3,
+  SILC_SKE_STATUS_UNKNOWN_CIPHER         = 4,
+  SILC_SKE_STATUS_UNKNOWN_PKCS           = 5,
+  SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION  = 6,
   SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY = 7,
-  SILC_SKE_STATUS_INCORRECT_SIGNATURE = 8,
+  SILC_SKE_STATUS_INCORRECT_SIGNATURE    = 8,
+  SILC_SKE_STATUS_BAD_VERSION            = 9,
 
   SILC_SKE_STATUS_KEY_EXCHANGE_NOT_ACTIVE,
   SILC_SKE_STATUS_BAD_RESERVED_FIELD,
diff --git a/lib/silcutil/Makefile.am b/lib/silcutil/Makefile.am
new file mode 100644 (file)
index 0000000..302738d
--- /dev/null
@@ -0,0 +1,39 @@
+#
+#  Makefile.am
+#
+#  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+#
+#  Copyright (C) 2000 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
+#  GNU General Public License for more details.
+#
+
+AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
+
+noinst_LIBRARIES = libsilcutil.a
+
+libsilcutil_a_SOURCES = \
+       silcbuffer.c \
+       silcbuffmt.c \
+       silcbufutil.c \
+       silcconfig.c \
+       silclog.c \
+       silcmemory.c \
+       silcnet.c \
+       silcschedule.c \
+       silctask.c \
+       silcutil.c
+
+EXTRA_DIST = *.h
+
+INCLUDES = -I. -I.. -I../silccrypt -I../silcmath -I../silcske \
+       -I../silcsim -I../.. -I../silccore -I../../includes \
+       -I../silcmath/gmp -I../trq
similarity index 79%
rename from lib/silccore/silcbuffer.c
rename to lib/silcutil/silcbuffer.c
index 7559f59f0f95a93d8a604ac1416b6a040cfd1e74..1f9ba2fe53133d968f0405d0e1ab9a82ae2a1c69 100644 (file)
 /*
  * $Id$
  * $Log$
+ * Revision 1.3  2000/11/01 21:43:44  priikone
+ *     removed memset not needed
+ *
+ * Revision 1.2  2000/10/31 19:48:32  priikone
+ *     A LOT updates. Cannot separate. :)
+ *
+ * Revision 1.1  2000/09/13 17:45:15  priikone
+ *     Splitted SILC core library. Core library includes now only
+ *     SILC protocol specific stuff. New utility library includes the
+ *     old stuff from core library that is more generic purpose stuff.
+ *
+ * Revision 1.2  2000/07/05 06:06:35  priikone
+ *     Global cosmetic change.
+ *
  * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
- *     Importet from internal CVS/Added Log headers.
+ *     Imported from internal CVS/Added Log headers.
  *
  *
  */
 #include "silcincludes.h"
 #include "silcbuffer.h"
 
-static unsigned char *silc_buffer_pull_i(SilcBuffer sb, unsigned int len)
-{
-  return silc_buffer_pull(sb, len);
-}
-
-static unsigned char *silc_buffer_push_i(SilcBuffer sb, unsigned int len)
-{
-  return silc_buffer_push(sb, len);
-}
-
-static unsigned char *silc_buffer_pull_tail_i(SilcBuffer sb, unsigned int len)
-{
-  return silc_buffer_pull_tail(sb, len);
-}
-
-static unsigned char *silc_buffer_push_tail_i(SilcBuffer sb, unsigned int len)
-{
-  return silc_buffer_push_tail(sb, len);
-}
-
-static unsigned char *silc_buffer_put_head_i(SilcBuffer sb, 
-                                            unsigned char *data,
-                                            unsigned int len)
-{
-  return silc_buffer_put_head(sb, data, len);
-}
-
-static unsigned char *silc_buffer_put_i(SilcBuffer sb, 
-                                       unsigned char *data,
-                                       unsigned int len)
-{
-  return silc_buffer_put(sb, data, len);
-}
+#ifdef SILC_DEBUG              /* If we are doing debugging we won't
+                                  have the optimized inline buffer functions
+                                  available as optimization is not set
+                                  to compiler. These normal routines are
+                                  used in debugging mode. */
 
-static unsigned char *silc_buffer_put_tail_i(SilcBuffer sb, 
-                                            unsigned char *data,
-                                            unsigned int len)
-{
-  return silc_buffer_put_tail(sb, data, len);
-}
+/* XXX These are currenly obsolete as SILC is compiled always with -O
+   flag thus inline functions maybe used always. So, fix these. */
 
 /* Allocates a new SilcBuffer and returns a pointer to it. The data
    area of the new buffer is set to the real beginning of the buffer. 
@@ -88,14 +70,9 @@ SilcBuffer silc_buffer_alloc(unsigned int len)
 
   /* Allocate new SilcBuffer */
   sb = silc_calloc(1, sizeof(*sb));
-  if (!sb)
-    return NULL;
 
   /* Allocate the actual data area */
-  data = silc_malloc(len);
-  if (!data)
-    return NULL;
-  memset(data, 0, len);
+  data = silc_calloc(len, sizeof(*data));
 
   /* Set pointers to the new buffer */
   sb->truelen = len;
@@ -105,15 +82,6 @@ SilcBuffer silc_buffer_alloc(unsigned int len)
   sb->tail = data;
   sb->end = data + sb->truelen;
 
-  /* Set the function pointers */
-  sb->pull = silc_buffer_pull_i;
-  sb->push = silc_buffer_push_i;
-  sb->pull_tail = silc_buffer_pull_tail_i;
-  sb->push_tail = silc_buffer_push_tail_i;
-  sb->put = silc_buffer_put_i;
-  sb->put_head = silc_buffer_put_head_i;
-  sb->put_tail = silc_buffer_put_tail_i;
-
   return sb;
 }
 
@@ -128,15 +96,6 @@ void silc_buffer_free(SilcBuffer sb)
   }
 }
 
-#ifdef SILC_DEBUG              /* If we are doing debugging we won't
-                                  have the optimized inline buffer functions
-                                  available as optimization is not set
-                                  to compiler. These normal routines are
-                                  used in debugging mode. */
-
-/* XXX These are currenly obsolte as SILC is compiled always with -O
-   flag thus inline functions maybe used. So, fix these. */
-
 /* Pulls current data area towards end. The length of the currently
    valid data area is also decremented. Returns pointer to the data
    area before pulling. 
similarity index 93%
rename from lib/silccore/silcbuffer.h
rename to lib/silcutil/silcbuffer.h
index 179c3d0e0567065917c4d402e077eef0887ad61d..8658e608a4f8c788f65e6888086b856d8d60bef2 100644 (file)
@@ -116,18 +116,6 @@ typedef struct SilcBufferStruct {
   unsigned char *data;
   unsigned char *tail;
   unsigned char *end;
-
-  /* Method functions. */
-  unsigned char *(*pull)(struct SilcBufferStruct *, unsigned int);
-  unsigned char *(*push)(struct SilcBufferStruct *, unsigned int);
-  unsigned char *(*pull_tail)(struct SilcBufferStruct *, unsigned int);
-  unsigned char *(*push_tail)(struct SilcBufferStruct *, unsigned int);
-  unsigned char *(*put)(struct SilcBufferStruct *, unsigned char *, 
-                       unsigned int);
-  unsigned char *(*put_head)(struct SilcBufferStruct *, unsigned char *, 
-                            unsigned int);
-  unsigned char *(*put_tail)(struct SilcBufferStruct *, unsigned char *, 
-                            unsigned int);
 } SilcBufferObject;
 
 typedef SilcBufferObject *SilcBuffer;
@@ -145,6 +133,41 @@ typedef SilcBufferObject *SilcBuffer;
  * functions.
  */
 
+extern inline
+SilcBuffer silc_buffer_alloc(unsigned int len)
+{
+  SilcBuffer sb;
+  unsigned char *data;
+
+  /* Allocate new SilcBuffer */
+  sb = silc_calloc(1, sizeof(*sb));
+
+  /* Allocate the actual data area */
+  data = silc_calloc(len, sizeof(*data));
+
+  /* Set pointers to the new buffer */
+  sb->truelen = len;
+  sb->len = 0;
+  sb->head = data;
+  sb->data = data;
+  sb->tail = data;
+  sb->end = data + sb->truelen;
+
+  return sb;
+}
+
+/* Free's a SilcBuffer */
+
+extern inline
+void silc_buffer_free(SilcBuffer sb)
+{
+  if (sb) {
+    memset(sb->head, 'F', sb->truelen);
+    silc_free(sb->head);
+    silc_free(sb);
+  }
+}
+
 /* Pulls current data area towards end. The length of the currently
    valid data area is also decremented. Returns pointer to the data
    area before pulling. 
@@ -328,9 +351,9 @@ unsigned char *silc_buffer_put_tail(SilcBuffer sb,
 #endif /* !SILC_DEBUG */
 
 /* Prototypes */
+#ifdef SILC_DEBUG
 SilcBuffer silc_buffer_alloc(unsigned int len);
 void silc_buffer_free(SilcBuffer sb);
-#ifdef SILC_DEBUG
 unsigned char *silc_buffer_pull(SilcBuffer sb, unsigned int len);
 unsigned char *silc_buffer_push(SilcBuffer sb, unsigned int len);
 unsigned char *silc_buffer_pull_tail(SilcBuffer sb, unsigned int len);
similarity index 96%
rename from lib/silccore/silcbuffmt.c
rename to lib/silcutil/silcbuffmt.c
index 2e7955c520080f19e16acf4fa56a81c2f1d9a780..54cf0e2c2a37a38c10d53ce223d93df2b9f51b99 100644 (file)
    is too short. Must be fixed. There are some other obvious bugs as
    well. */
 /*
- * $Id$
- * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
- *     Importet from internal CVS/Added Log headers.
- *
- *
- */
+ * $Id$ */
 
 #include "silcincludes.h"
 
@@ -54,14 +48,14 @@ int silc_buffer_format(SilcBuffer dst, ...)
     switch(fmt) {
     case SILC_BUFFER_PARAM_SI8_CHAR:
       {
-       char x = va_arg(ap, char);
+       char x = (char)va_arg(ap, int);
        silc_buffer_put(dst, &x, 1);
        silc_buffer_pull(dst, 1);
        break;
       }
     case SILC_BUFFER_PARAM_UI8_CHAR:
       {
-       unsigned char x = va_arg(ap, unsigned char);
+       unsigned char x = (unsigned char)va_arg(ap, int);
        silc_buffer_put(dst, &x, 1);
        silc_buffer_pull(dst, 1);
        break;
@@ -69,7 +63,7 @@ int silc_buffer_format(SilcBuffer dst, ...)
     case SILC_BUFFER_PARAM_SI16_SHORT:
       {
        unsigned char xf[2];
-       short x = va_arg(ap, short);
+       short x = (short)va_arg(ap, int);
        SILC_PUT16_MSB(x, xf);
        silc_buffer_put(dst, xf, 2);
        silc_buffer_pull(dst, 2);
@@ -78,7 +72,7 @@ int silc_buffer_format(SilcBuffer dst, ...)
     case SILC_BUFFER_PARAM_UI16_SHORT:
       {
        unsigned char xf[2];
-       unsigned short x = va_arg(ap, unsigned short);
+       unsigned short x = (unsigned short)va_arg(ap, int);
        SILC_PUT16_MSB(x, xf);
        silc_buffer_put(dst, xf, 2);
        silc_buffer_pull(dst, 2);
similarity index 99%
rename from lib/silccore/silcbuffmt.h
rename to lib/silcutil/silcbuffmt.h
index 6d9acaeb736327deab7ee84a069cafd441006661..25834505cac375bb383907d7f1f81e8b512c4b79 100644 (file)
@@ -180,7 +180,7 @@ typedef enum {
 #define SILC_STR_UI_XNSTRING_ALLOC(x, l) \
   SILC_BUFFER_PARAM_UI_XNSTRING_ALLOC, (x), (l)
 
-/* Marks end of the argument list. This must the at the end of the
+/* 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
 
similarity index 63%
rename from lib/silccore/silcbufutil.c
rename to lib/silcutil/silcbufutil.c
index f42424840c06df19e2b1b00cfc9325e3c6a40fad..2c89a17cbdaec61ec44d12901f234c9b79bcc888 100644 (file)
 /*
  * $Id$
  * $Log$
+ * Revision 1.1  2000/09/13 17:45:16  priikone
+ *     Splitted SILC core library. Core library includes now only
+ *     SILC protocol specific stuff. New utility library includes the
+ *     old stuff from core library that is more generic purpose stuff.
+ *
+ * Revision 1.3  2000/07/14 06:08:49  priikone
+ *     Added silc_buffer_realloc. Fixed silc_buffer_clone.
+ *
+ * Revision 1.2  2000/07/05 06:06:35  priikone
+ *     Global cosmetic change.
+ *
  * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
- *     Importet from internal CVS/Added Log headers.
+ *     Imported from internal CVS/Added Log headers.
  *
  *
  */
@@ -71,11 +82,31 @@ SilcBuffer silc_buffer_clone(SilcBuffer sb)
   sb_new = silc_buffer_alloc(sb->truelen);
   silc_buffer_pull_tail(sb_new, SILC_BUFFER_END(sb_new));
   silc_buffer_put(sb_new, sb->head, sb->truelen);
-  sb_new->data = sb_new->head + sb->len;
-  sb_new->tail = sb_new->head + (sb->end - sb->tail);
+  sb_new->data = sb_new->head + (sb->data - sb->head);
+  sb_new->tail = sb_new->data + sb->len;
   sb_new->len = sb->len;
 
   return sb_new;
 }
 
+/* Reallocates buffer. Old data is saved into the new buffer. Returns
+   new SilcBuffer pointer. The buffer is exact clone of the old one
+   except that there is now more space at the end of buffer. */
+
+SilcBuffer silc_buffer_realloc(SilcBuffer sb, unsigned int newsize)
+{
+  SilcBuffer sb_new;
+
+  sb_new = silc_buffer_alloc(newsize);
+  silc_buffer_pull_tail(sb_new, SILC_BUFFER_END(sb_new));
+  silc_buffer_put(sb_new, sb->head, sb->truelen);
+  sb_new->data = sb_new->head + (sb->data - sb->head);
+  sb_new->tail = sb_new->data + sb->len;
+  sb_new->len = sb->len;
+
+  silc_buffer_free(sb);
+
+  return sb_new;
+}
+
 #endif /* SILC_DEBUG */
similarity index 72%
rename from lib/silccore/silcbufutil.h
rename to lib/silcutil/silcbufutil.h
index acbbcaf47cc1b5a7b278f2ae88437dd3ec55957f..1525375deb51371c6858258eee9628de74510396 100644 (file)
@@ -64,13 +64,34 @@ SilcBuffer silc_buffer_clone(SilcBuffer sb)
   sb_new = silc_buffer_alloc(sb->truelen);
   silc_buffer_pull_tail(sb_new, SILC_BUFFER_END(sb_new));
   silc_buffer_put(sb_new, sb->head, sb->truelen);
-  sb_new->data = sb_new->head + sb->len;
-  sb_new->tail = sb_new->head + (sb->end - sb->tail);
+  sb_new->data = sb_new->head + (sb->data - sb->head);
+  sb_new->tail = sb_new->data + sb->len;
   sb_new->len = sb->len;
 
   return sb_new;
 }
 
+/* Reallocates buffer. Old data is saved into the new buffer. Returns
+   new SilcBuffer pointer. The buffer is exact clone of the old one
+   except that there is now more space at the end of buffer. */
+
+extern inline
+SilcBuffer silc_buffer_realloc(SilcBuffer sb, unsigned int newsize)
+{
+  SilcBuffer sb_new;
+
+  sb_new = silc_buffer_alloc(newsize);
+  silc_buffer_pull_tail(sb_new, SILC_BUFFER_END(sb_new));
+  silc_buffer_put(sb_new, sb->head, sb->truelen);
+  sb_new->data = sb_new->head + (sb->data - sb->head);
+  sb_new->tail = sb_new->data + sb->len;
+  sb_new->len = sb->len;
+
+  silc_buffer_free(sb);
+
+  return sb_new;
+}
+
 #endif /* !SILC_DEBUG */
 
 /* Prototypes */
@@ -78,6 +99,7 @@ SilcBuffer silc_buffer_clone(SilcBuffer sb)
 void silc_buffer_clear(SilcBuffer sb);
 SilcBuffer silc_buffer_copy(SilcBuffer sb);
 SilcBuffer silc_buffer_clone(SilcBuffer sb);
+SilcBuffer silc_buffer_realloc(SilcBuffer sb, unsigned int newsize);
 #endif
 
 #endif
similarity index 85%
rename from lib/silccore/silcconfig.c
rename to lib/silcutil/silcconfig.c
index 4e0d3d4810fcfe2562c9c88fd8615b4d4f0a1d34..1cb27bf4f78b9045a53b55ce1aa1634bb151b4dd 100644 (file)
 /*
  * $Id$
  * $Log$
+ * Revision 1.1  2000/09/13 17:45:16  priikone
+ *     Splitted SILC core library. Core library includes now only
+ *     SILC protocol specific stuff. New utility library includes the
+ *     old stuff from core library that is more generic purpose stuff.
+ *
+ * Revision 1.2  2000/07/05 06:06:35  priikone
+ *     Global cosmetic change.
+ *
  * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
- *     Importet from internal CVS/Added Log headers.
+ *     Imported from internal CVS/Added Log headers.
  *
  *
  */
similarity index 67%
rename from lib/silccore/silclog.c
rename to lib/silcutil/silclog.c
index aa997d302289da33f286340184ebca9a42bedd7e..243ce20e8792902746ebbb0622c39f59c86a278e 100644 (file)
   GNU General Public License for more details.
 
 */
-/*
- * $Id$
- * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
- *     Importet from internal CVS/Added Log headers.
- *
- *
- */
+/* $Id$ */
 
 #include "silcincludes.h"
 
+/* Set TRUE/FALSE to enable/disable debugging */
+int silc_debug = FALSE;
+
 /* SILC Log name strings. These strings are printed to the log file. */
 const SilcLogTypeName silc_log_types[] =
 {
@@ -48,20 +44,16 @@ unsigned int log_warning_size;
 unsigned int log_error_size;
 unsigned int log_fatal_size;
 
-/* Formats arguments to a string and returns it after allocating memory
-   for it. It must be remembered to free it later. */
-
-char *silc_log_format(char *fmt, ...)
-{
-  va_list args;
-  static char buf[1024];
-
-  va_start(args, fmt);
-  vsprintf(buf, fmt, args);
-  va_end(args);
+/* Log callbacks. If these are set by the application these are used
+   instead of the default functions in this file. */
+static SilcLogCb info_cb = NULL;
+static SilcLogCb warning_cb = NULL;
+static SilcLogCb error_cb = NULL;
+static SilcLogCb fatal_cb = NULL;
 
-  return strdup(buf);
-}
+/* Debug callbacks. If set these are used instead of default ones. */
+static SilcDebugCb debug_cb = NULL;
+static SilcDebugHexdumpCb debug_hexdump_cb = NULL;
 
 /* Outputs the log message to what ever log file selected. */
 
@@ -71,6 +63,38 @@ void silc_log_output(const char *filename, unsigned int maxsize,
   FILE *fp;
   const SilcLogTypeName *np;
 
+  switch(type)
+    {
+    case SILC_LOG_INFO:
+      if (info_cb) {
+       (*info_cb)(string);
+       silc_free(string);
+       return;
+      }
+      break;
+    case SILC_LOG_WARNING:
+      if (warning_cb) {
+       (*warning_cb)(string);
+       silc_free(string);
+       return;
+      }
+      break;
+    case SILC_LOG_ERROR:
+      if (error_cb) {
+       (*error_cb)(string);
+       silc_free(string);
+       return;
+      }
+      break;
+    case SILC_LOG_FATAL:
+      if (fatal_cb) {
+       (*fatal_cb)(string);
+       silc_free(string);
+       return;
+      }
+      break;
+    }
+
   /* Purge the log file if the max size is defined. */
   if (maxsize) {
     fp = fopen(filename, "r");
@@ -81,7 +105,7 @@ void silc_log_output(const char *filename, unsigned int maxsize,
       fseek(fp, (off_t)0L, SEEK_SET);  
       
       /* Purge? */
-      if (maxsize >= filelen)
+      if (filelen >= maxsize)
        unlink(filename);
     }
   }
@@ -111,6 +135,18 @@ void silc_log_output(const char *filename, unsigned int maxsize,
 void silc_log_output_debug(char *file, char *function, 
                           int line, char *string)
 {
+  if (!silc_debug) {
+    silc_free(string);
+    return;
+  }
+
+  if (debug_cb)
+    {
+      (*debug_cb)(file, function, line, string);
+      silc_free(string);
+      return;
+    }
+
   /* fprintf(stderr, "%s:%s:%d: %s\n", file, function, line, string); */
   fprintf(stderr, "%s:%d: %s\n", function, line, string);
   fflush(stderr);
@@ -127,6 +163,18 @@ void silc_log_output_hexdump(char *file, char *function,
   int off, pos, count;
   unsigned char *data = (unsigned char *)data_in;
 
+  if (!silc_debug) {
+    silc_free(string);
+    return;
+  }
+
+  if (debug_hexdump_cb)
+    {
+      (*debug_hexdump_cb)(file, function, line, data_in, len, string);
+      silc_free(string);
+      return;
+    }
+
   /* fprintf(stderr, "%s:%s:%d: %s\n", file, function, line, string); */
   fprintf(stderr, "%s:%d: %s\n", function, line, string);
   silc_free(string);
@@ -205,3 +253,38 @@ void silc_log_set_files(char *info, unsigned int info_size,
   log_error_size = error_size;
   log_fatal_size = fatal_size;
 }
+
+/* Sets log callbacks */
+
+void silc_log_set_callbacks(SilcLogCb info, SilcLogCb warning,
+                           SilcLogCb error, SilcLogCb fatal)
+{
+  info_cb = info;
+  warning_cb = warning;
+  error_cb = error;
+  fatal_cb = fatal;
+}
+
+/* Resets log callbacks */
+
+void silc_log_reset_callbacks()
+{
+  info_cb = warning_cb = error_cb = fatal_cb = NULL;
+}
+
+/* Sets debug callbacks */
+
+void silc_log_set_debug_callbacks(SilcDebugCb debug, 
+                                 SilcDebugHexdumpCb debug_hexdump)
+{
+  debug_cb = debug;
+  debug_hexdump_cb = debug_hexdump;
+}
+
+/* Resets debug callbacks */
+
+void silc_log_reset_debug_callbacks()
+{
+  debug_cb = NULL;
+  debug_hexdump_cb = NULL;
+}
similarity index 76%
rename from lib/silccore/silclog.h
rename to lib/silcutil/silclog.h
index 3cfc499a5f02ce3909bb922dccb881b5be7dd1f4..4d00f05f0d97220745cb78b744c9e95686521957 100644 (file)
@@ -21,6 +21,9 @@
 #ifndef SILCLOG_H
 #define SILCLOG_H
 
+/* Set TRUE/FALSE to enable/disable debugging */
+extern int silc_debug;
+
 /* SILC Log types */
 typedef enum {
   SILC_LOG_INFO,
@@ -35,6 +38,18 @@ typedef struct {
   SilcLogType type;
 } SilcLogTypeName;
 
+/* Log function callback. */
+typedef void (*SilcLogCb)(char *message);
+
+/* Debug function callback. */
+typedef void (*SilcDebugCb)(char *file, char *function, 
+                           int line, char *message);
+
+/* Debug hexdump function callback. */
+typedef void (*SilcDebugHexdumpCb)(char *file, char *function, 
+                                  int line, unsigned char *data,
+                                  unsigned int data_len, char *message);
+
 /* Default log filenames */
 #define SILC_LOG_FILE_INFO "silcd.log"
 #define SILC_LOG_FILE_WARNING "silcd_error.log"
@@ -52,22 +67,22 @@ extern unsigned int log_error_size;
 extern unsigned int log_fatal_size;
 
 /* Log macros. */
-#define SILC_LOG_INFO(fmt) silc_log_output(log_info_file, \
+#define SILC_LOG_INFO(fmt) (silc_log_output(log_info_file, \
                                            log_info_size, \
                                           SILC_LOG_INFO, \
-                                          silc_log_format fmt)) 
+                                          silc_format fmt))
 #define SILC_LOG_WARNING(fmt) (silc_log_output(log_warning_file, \
                                                log_warning_size, \
                                               SILC_LOG_WARNING, \
-                                              silc_log_format fmt))
+                                              silc_format fmt))
 #define SILC_LOG_ERROR(fmt) (silc_log_output(log_error_file, \
                                              log_error_size, \
                                             SILC_LOG_ERROR, \
-                                            silc_log_format fmt))
+                                            silc_format fmt))
 #define SILC_LOG_FATAL(fmt) (silc_log_output(log_fatal_file, \
                                              log_fatal_size, \
                                             SILC_LOG_FATAL, \
-                                            silc_log_format fmt))
+                                            silc_format fmt))
 
 /* Debug macro is a bit different from other logging macros and it
    is compiled in only if debugging is enabled. */
@@ -75,20 +90,19 @@ extern unsigned int log_fatal_size;
 #define SILC_LOG_DEBUG(fmt) (silc_log_output_debug(__FILE__, \
                                                   __FUNCTION__, \
                                                   __LINE__, \
-                                                  silc_log_format fmt))
+                                                  silc_format fmt))
 #define SILC_LOG_HEXDUMP(fmt, data, len) \
   (silc_log_output_hexdump(__FILE__, \
                           __FUNCTION__, \
                           __LINE__, \
                            (data), (len), \
-                          silc_log_format fmt))
+                          silc_format fmt))
 #else
 #define SILC_LOG_DEBUG(fmt)
 #define SILC_LOG_HEXDUMP(fmt, data, len)
 #endif
 
 /* Prototypes */
-char *silc_log_format(char *fmt, ...);
 void silc_log_output_debug(char *file, char *function, 
                            int line, char *string);
 void silc_log_output(const char *filename, unsigned int maxsize,
@@ -100,5 +114,11 @@ void silc_log_set_files(char *info, unsigned int info_size,
                        char *warning, unsigned int warning_size,
                        char *error, unsigned int error_size,
                         char *fatal, unsigned int fatal_size);
+void silc_log_set_callbacks(SilcLogCb info, SilcLogCb warning,
+                           SilcLogCb error, SilcLogCb fatal);
+void silc_log_reset_callbacks();
+void silc_log_set_debug_callbacks(SilcDebugCb debug, 
+                                 SilcDebugHexdumpCb debug_hexdump);
+void silc_log_reset_debug_callbacks();
 
 #endif
similarity index 58%
rename from lib/silccore/silcmemory.c
rename to lib/silcutil/silcmemory.c
index 03d981e27b209b21091267b9c163b95b499ce545..e5ebae567a4d0767611fb80239735f5545a02472 100644 (file)
 /*
  * $Id$
  * $Log$
+ * Revision 1.1  2000/09/13 17:45:16  priikone
+ *     Splitted SILC core library. Core library includes now only
+ *     SILC protocol specific stuff. New utility library includes the
+ *     old stuff from core library that is more generic purpose stuff.
+ *
+ * Revision 1.2  2000/07/05 06:05:56  priikone
+ *     Assert if system is out of memory.
+ *
  * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
- *     Importet from internal CVS/Added Log headers.
+ *     Imported from internal CVS/Added Log headers.
  *
  *
  */
 
 void *silc_malloc(size_t size)
 {
+  void *addr;
 #ifdef HAVE_MLOCK
-  void *addr = malloc(size);
+  addr = malloc(size);
+  assert(addr != NULL);
   mlock(addr, size);
   return addr;
 #else
-  return malloc(size);
+  addr = malloc(size);
+  assert(addr != NULL);
+  return addr;
 #endif
 }
 
 void *silc_calloc(size_t items, size_t size)
 {
+  void *addr;
 #ifdef HAVE_MLOCK
-  void *addr = calloc(items, size);
+  addr = calloc(items, size);
+  assert(addr != NULL);
   mlock(addr, size);
   return addr;
 #else
-  return calloc(items, size);
+  addr = calloc(items, size);
+  assert(addr != NULL);
+  return addr;
 #endif
 }
 
 void *silc_realloc(void *ptr, size_t size)
 {
+  void *addr;
 #ifdef HAVE_MLOCK
-  void *addr = realloc(ptr, size);
+  addr = realloc(ptr, size);
+  assert(addr != NULL);
   mlock(addr, size);
   return addr;
 #else
-  return realloc(ptr, size);
+  addr = realloc(ptr, size);
+  assert(addr != NULL);
+  return addr;
 #endif
 }
 
similarity index 88%
rename from lib/silccore/silcnet.c
rename to lib/silcutil/silcnet.c
index b35c18271511b57ae44c20b028b515ba7fa56281..c4d6d9d7a653a5f00575a4cefcc0daa9541b61f3 100644 (file)
 /*
  * $Id$
  * $Log$
+ * Revision 1.2  2000/10/31 19:48:32  priikone
+ *     A LOT updates. Cannot separate. :)
+ *
+ * Revision 1.1  2000/09/13 17:45:16  priikone
+ *     Splitted SILC core library. Core library includes now only
+ *     SILC protocol specific stuff. New utility library includes the
+ *     old stuff from core library that is more generic purpose stuff.
+ *
+ * Revision 1.3  2000/07/05 06:06:35  priikone
+ *     Global cosmetic change.
+ *
+ * Revision 1.2  2000/06/30 10:49:48  priikone
+ *     Added SOCKS4 and SOCKS5 support for SILC client.
+ *
  * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
- *     Importet from internal CVS/Added Log headers.
+ *     Imported from internal CVS/Added Log headers.
  *
  *
  */
@@ -119,6 +133,7 @@ int silc_net_create_connection(int port, char *host)
   /* Set socket information */
   memset(&desthost, 0, sizeof(desthost));
   desthost.sin_port = htons(port);
+  desthost.sin_family = PF_INET;
   memcpy(&desthost.sin_addr, dest->h_addr_list[0], sizeof(desthost.sin_addr));
 
   /* Create the connection socket */
@@ -137,8 +152,9 @@ int silc_net_create_connection(int port, char *host)
     return -1;
   }
 
-  /* Set appropriate option */
+  /* Set appropriate options */
   silc_net_set_socket_opt(sock, IPPROTO_TCP, TCP_NODELAY, 1);
+  silc_net_set_socket_opt(sock, SOL_SOCKET, SO_KEEPALIVE, 1);
 
   SILC_LOG_DEBUG(("Connection created"));
 
@@ -169,6 +185,7 @@ int silc_net_create_connection_async(int port, char *host)
   /* Set socket information */
   memset(&desthost, 0, sizeof(desthost));
   desthost.sin_port = htons(port);
+  desthost.sin_family = PF_INET;
   memcpy(&desthost.sin_addr, dest->h_addr_list[0], sizeof(desthost.sin_addr));
 
   /* Create the connection socket */
@@ -192,8 +209,9 @@ int silc_net_create_connection_async(int port, char *host)
     }
   }
 
-  /* Set appropriate option */
+  /* Set appropriate options */
   silc_net_set_socket_opt(sock, IPPROTO_TCP, TCP_NODELAY, 1);
+  silc_net_set_socket_opt(sock, SOL_SOCKET, SO_KEEPALIVE, 1);
 
   SILC_LOG_DEBUG(("Connection operation in progress"));
 
@@ -291,3 +309,13 @@ void silc_net_check_host_by_sock(int sock, char **hostname, char **ip)
   memcpy(*ip, host_ip, strlen(host_ip));
   SILC_LOG_DEBUG(("Resolved IP address `%s'", *ip));
 }
+
+/* Return name of localhost. */
+
+char *silc_net_localhost()
+{
+  char hostname[256];
+  if (!gethostname(hostname, sizeof(hostname)))
+    return strdup(hostname);
+  return NULL;
+}
similarity index 97%
rename from lib/silccore/silcnet.h
rename to lib/silcutil/silcnet.h
index d6ef5c07bbd042213f5975eeeb38dff68c735c4c..756f160448cb10760dad1651617263c7eaf25a2d 100644 (file)
@@ -32,5 +32,6 @@ int silc_net_set_socket_nonblock(int sock);
 int silc_net_set_socket_opt(int sock, int level, int option, int on);
 int silc_net_is_ip(const char *addr);
 void silc_net_check_host_by_sock(int sock, char **hostname, char **ip);
+char *silc_net_localhost();
 
 #endif
similarity index 83%
rename from lib/silccore/silcschedule.c
rename to lib/silcutil/silcschedule.c
index a23440b6c6ee0812a8f90e1f46260df9c43d8b6d..5d4a8f612152822ea1596a5dfcd2680edfee0f2d 100644 (file)
   GNU General Public License for more details.
 
 */
-/*
- * $Id$
- * $Log$
- * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
- *     Importet from internal CVS/Added Log headers.
- *
- *
- */
+/* $Id$ */
 
 #include "silcincludes.h"
 
@@ -35,20 +28,32 @@ static SilcSchedule schedule;
    the timeout task queue hook. This must be called before the schedule
    is able to work. */
 
-void silc_schedule_init(SilcTaskQueue fd_queue,
-                       SilcTaskQueue timeout_queue,
-                       SilcTaskQueue generic_queue,
+void silc_schedule_init(SilcTaskQueue *fd_queue,
+                       SilcTaskQueue *timeout_queue,
+                       SilcTaskQueue *generic_queue,
                        int max_fd)
 {
   int i;
 
   SILC_LOG_DEBUG(("Initializing scheduler"));
 
+  /* Register the task queues if they are not registered already. In SILC
+     we have by default three task queues. One task queue for non-timeout
+     tasks which perform different kind of I/O on file descriptors, timeout
+     task queue for timeout tasks, and, generic non-timeout task queue whose
+     tasks apply to all connections. */
+  if (!*fd_queue)
+    silc_task_queue_alloc(fd_queue, TRUE);
+  if (!*timeout_queue)
+    silc_task_queue_alloc(timeout_queue, TRUE);
+  if (!*generic_queue)
+    silc_task_queue_alloc(generic_queue, TRUE);
+
   /* Initialize the schedule */
   memset(&schedule, 0, sizeof(schedule));
-  schedule.fd_queue = fd_queue;
-  schedule.timeout_queue = timeout_queue;
-  schedule.generic_queue = generic_queue;
+  schedule.fd_queue = *fd_queue;
+  schedule.timeout_queue = *timeout_queue;
+  schedule.generic_queue = *generic_queue;
   schedule.fd_list.fd = silc_calloc(max_fd, sizeof(int));
   schedule.fd_list.last_fd = 0;
   schedule.fd_list.max_fd = max_fd;
@@ -141,7 +146,7 @@ void silc_schedule_unset_listen_fd(int fd)
       if (schedule.fd_list.fd[i] != -1)
        break;
 
-    schedule.fd_list.last_fd = i;
+    schedule.fd_list.last_fd = i < 0 ? 0 : i;
   }
 }
 
@@ -415,83 +420,96 @@ do {                                                                           \
   }                                                                         \
 } while(0)
 
-/* The SILC scheduler. This is actually the main routine in SILC programs.
-   When this returns the program is to be ended. Before this function can
-   be called, one must call silc_schedule_init function. */
-
-void silc_schedule()
+int silc_schedule_one(int timeout_usecs)
 {
+  struct timeval timeout;
   int is_run, i;
   SilcTask task;
   SilcTaskQueue queue;
   struct timeval curtime;
 
-  SILC_LOG_DEBUG(("Running scheduler"));
+  SILC_LOG_DEBUG(("In scheduler loop"));
 
-  if (schedule.valid == FALSE) {
-    SILC_LOG_ERROR(("Scheduler is not valid, stopping"));
-    return;
+  /* If the task queues aren't initialized or we aren't valid anymore
+     we will return */
+  if ((!schedule.fd_queue && !schedule.timeout_queue 
+       && !schedule.generic_queue) || schedule.valid == FALSE) {
+    SILC_LOG_DEBUG(("Scheduler not valid anymore, exiting"));
+    return FALSE;
   }
 
-  /* Start the scheduler loop */
-  while(1) {
+  /* Clear everything */
+  FD_ZERO(&schedule.in);
+  FD_ZERO(&schedule.out);
+  schedule.max_fd = -1;
+  is_run = FALSE;
 
-    SILC_LOG_DEBUG(("In scheduler loop"));
+  /* Calculate next timeout for select(). This is the timeout value
+     when at earliest some of the timeout tasks expire. */
+  SILC_SCHEDULE_SELECT_TIMEOUT;
 
-    /* If the task queues aren't initialized or we aren't valid anymore
-       we will return */
-    if ((!schedule.fd_queue && !schedule.timeout_queue 
-        && !schedule.generic_queue) || schedule.valid == FALSE) {
-      SILC_LOG_DEBUG(("Scheduler not valid anymore, exiting"));
-      break;
-    }
+  /* Add the file descriptors to the fd sets. These are the non-timeout
+     tasks. The select() listens to these file descriptors. */
+  SILC_SCHEDULE_SELECT_TASKS;
 
-    /* Clear everything */
-    FD_ZERO(&schedule.in);
-    FD_ZERO(&schedule.out);
-    schedule.max_fd = -1;
-    is_run = FALSE;
+  if (schedule.max_fd == -1) {
+    /*SILC_LOG_ERROR(("Nothing to listen, exiting"));*/
+    return FALSE;
+  }
 
-    /* Calculate next timeout for select(). This is the timeout value
-       when at earliest some of the timeout tasks expire. */
-    SILC_SCHEDULE_SELECT_TIMEOUT;
+  if (schedule.timeout) {
+    SILC_LOG_DEBUG(("timeout: sec=%d, usec=%d", schedule.timeout->tv_sec,
+                   schedule.timeout->tv_usec));
+  }
 
-    /* Add the file descriptors to the fd sets. These are the non-timeout
-       tasks. The select() listens to these file descriptors. */
-    SILC_SCHEDULE_SELECT_TASKS;
+  if (timeout_usecs >= 0) {
+    timeout.tv_sec = 0;
+    timeout.tv_usec = timeout_usecs;
+    schedule.timeout = &timeout;
+  }
 
-    if (schedule.max_fd == -1) {
-      SILC_LOG_ERROR(("Nothing to listen, exiting"));
-      break;
-    }
-
-    if (schedule.timeout)
-      SILC_LOG_DEBUG(("timeout: sec=%d, usec=%d", schedule.timeout->tv_sec,
-                     schedule.timeout->tv_usec));
-
-    /* This is the main select(). The program blocks here until some
-       of the selected file descriptors change status or the selected
-       timeout expires. */
-    SILC_LOG_DEBUG(("Select"));
-    switch(select(schedule.max_fd + 1, &schedule.in, 
-                 &schedule.out, 0, schedule.timeout)) {
-    case -1:
-      /* Error */
-      SILC_LOG_ERROR(("Error in select(): %s", strerror(errno)));
-      break;
-    case 0:
-      /* Timeout */
-      SILC_LOG_DEBUG(("Running timeout tasks"));
-      gettimeofday(&curtime, NULL);
-      SILC_SCHEDULE_RUN_TIMEOUT_TASKS;
+  /* This is the main select(). The program blocks here until some
+     of the selected file descriptors change status or the selected
+     timeout expires. */
+  SILC_LOG_DEBUG(("Select"));
+  switch (select(schedule.max_fd + 1, &schedule.in,
+                &schedule.out, 0, schedule.timeout)) {
+  case -1:
+    /* Error */
+    if (errno == EINTR)
       break;
-    default:
-      /* There is some data available now */
-      SILC_LOG_DEBUG(("Running non-timeout tasks"));
-      SILC_SCHEDULE_RUN_TASKS;
+    SILC_LOG_ERROR(("Error in select(): %s", strerror(errno)));
+    break;
+  case 0:
+    /* Timeout */
+    SILC_LOG_DEBUG(("Running timeout tasks"));
+    gettimeofday(&curtime, NULL);
+    SILC_SCHEDULE_RUN_TIMEOUT_TASKS;
+    break;
+  default:
+    /* There is some data available now */
+    SILC_LOG_DEBUG(("Running non-timeout tasks"));
+    SILC_SCHEDULE_RUN_TASKS;
+
+    SILC_SCHEDULE_RUN_GENERIC_TASKS;
+    break;
+  }
+  return TRUE;
+}
 
-      SILC_SCHEDULE_RUN_GENERIC_TASKS;
-      break;
-    }
+/* The SILC scheduler. This is actually the main routine in SILC programs.
+   When this returns the program is to be ended. Before this function can
+   be called, one must call silc_schedule_init function. */
+
+void silc_schedule()
+{
+  SILC_LOG_DEBUG(("Running scheduler"));
+
+  if (schedule.valid == FALSE) {
+    SILC_LOG_ERROR(("Scheduler is not valid, stopping"));
+    return;
   }
+
+  /* Start the scheduler loop */
+  while (silc_schedule_one(-1)) ;
 }
similarity index 96%
rename from lib/silccore/silcschedule.h
rename to lib/silcutil/silcschedule.h
index 87af2d1e377876ef674f2ef259632aed10246375..ce9070cf9f3ebf3ef56f928cfc4e51bae47a8dd6 100644 (file)
@@ -110,14 +110,15 @@ typedef struct {
 typedef SilcScheduleObject SilcSchedule;
 
 /* Prototypes */
-void silc_schedule_init(SilcTaskQueue fd_queue,
-                       SilcTaskQueue timeout_queue,
-                       SilcTaskQueue generic_queue,
+void silc_schedule_init(SilcTaskQueue *fd_queue,
+                       SilcTaskQueue *timeout_queue,
+                       SilcTaskQueue *generic_queue,
                        int max_fd);
 int silc_schedule_uninit();
 void silc_schedule_stop();
 void silc_schedule_set_listen_fd(int fd, unsigned int iomask);
 void silc_schedule_unset_listen_fd(int fd);
 void silc_schedule();
+int silc_schedule_one(int block);
 
 #endif
similarity index 97%
rename from lib/silccore/silctask.c
rename to lib/silcutil/silctask.c
index f9e09ebf1e8a27418e6681a8c48a0d56c3863630..1bf8388f9ffb45ef4f26127f8dc5725adff8603c 100644 (file)
 /*
  * $Id$
  * $Log$
+ * Revision 1.1  2000/09/13 17:45:16  priikone
+ *     Splitted SILC core library. Core library includes now only
+ *     SILC protocol specific stuff. New utility library includes the
+ *     old stuff from core library that is more generic purpose stuff.
+ *
+ * Revision 1.2  2000/07/05 06:06:35  priikone
+ *     Global cosmetic change.
+ *
  * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
- *     Importet from internal CVS/Added Log headers.
+ *     Imported from internal CVS/Added Log headers.
  *
  *
  */
@@ -38,11 +46,6 @@ void silc_task_queue_alloc(SilcTaskQueue *new, int valid)
   SILC_LOG_DEBUG(("Allocating new task queue"));
 
   *new = silc_calloc(1, sizeof(**new));
-  if (*new == NULL) {
-    SILC_LOG_ERROR(("Could not allocate new task queue object: %s", 
-                   strerror(errno)));
-    return;
-  }
 
   /* Set the pointers */
   (*new)->valid = valid;
@@ -371,11 +374,6 @@ SilcTask silc_task_register(SilcTaskQueue queue, int fd,
   }
 
   new = silc_calloc(1, sizeof(*new));
-  if (!new) {
-    SILC_LOG_ERROR(("Could not allocate new task object"));
-    return NULL;
-  }
-
   new->fd = fd;
   new->context = context;
   new->callback = cb;
diff --git a/lib/silcutil/silcutil.c b/lib/silcutil/silcutil.c
new file mode 100644 (file)
index 0000000..81b5afe
--- /dev/null
@@ -0,0 +1,546 @@
+/*
+
+  silcutil.c
+
+  Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+  Copyright (C) 1997 - 2000 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
+  GNU General Public License for more details.
+
+*/
+/*
+ * These are general utility functions that doesn't belong to any specific
+ * group of routines.
+ */
+/* $Id$ */
+
+#include "silcincludes.h"
+
+/* Reads a file to a buffer. The allocated buffer is returned. Length of
+   the file read is returned to the return_len argument. */
+
+char *silc_file_read(const char *filename, int *return_len)
+{
+  int fd;
+  char *buffer;
+  int filelen;
+
+  fd = open(filename, O_RDONLY);
+  if (fd < 0) {
+    SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno)));
+    return NULL;
+  }
+
+  filelen = lseek(fd, (off_t)0L, SEEK_END);
+  if (filelen < 0)
+    return NULL;
+  if (lseek(fd, (off_t)0L, SEEK_SET) < 0)
+    return NULL;
+
+  if (filelen < 0) {
+    SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno)));
+    return NULL;
+  }
+  
+  buffer = silc_calloc(filelen + 1, sizeof(char));
+  
+  if ((read(fd, buffer, filelen)) == -1) {
+    memset(buffer, 0, sizeof(buffer));
+    close(fd);
+    SILC_LOG_ERROR(("Cannot read from file %s: %s", filename,
+                    strerror(errno)));
+    return NULL;
+  }
+
+  close(fd);
+  buffer[filelen] = EOF;
+
+  if (return_len)
+    *return_len = filelen;
+
+  return buffer;
+}
+
+/* Writes a buffer to the file. */
+
+int silc_file_write(const char *filename, const char *buffer, int len)
+{
+  int fd;
+        
+  if ((fd = creat(filename, 0644)) == -1) {
+    SILC_LOG_ERROR(("Cannot open file %s for writing: %s", strerror(errno)));
+    return -1;
+  }
+  
+  if ((write(fd, buffer, len)) == -1) {
+    SILC_LOG_ERROR(("Cannot write to file %s: %s", strerror(errno)));
+    return -1;
+  }
+
+  close(fd);
+  
+  return 0;
+}
+
+/* Writes a buffer to the file.  If the file is created specific mode is
+   set to the file. */
+
+int silc_file_write_mode(const char *filename, const char *buffer, 
+                        int len, int mode)
+{
+  int fd;
+        
+  if ((fd = creat(filename, mode)) == -1) {
+    SILC_LOG_ERROR(("Cannot open file %s for writing: %s", strerror(errno)));
+    return -1;
+  }
+  
+  if ((write(fd, buffer, len)) == -1) {
+    SILC_LOG_ERROR(("Cannot write to file %s: %s", strerror(errno)));
+    return -1;
+  }
+
+  close(fd);
+  
+  return 0;
+}
+
+/* Gets line from a buffer. Stops reading when a newline or EOF occurs.
+   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)
+{
+  static int start = 0;
+  int i;
+  
+  memset(dest, 0, destlen);
+  
+  if (begin != start)
+    start = 0;
+  
+  i = 0;
+  for ( ; start <= srclen; i++, start++) {
+    if (i > destlen)
+      return -1;
+    
+    dest[i] = src[start];
+    
+    if (dest[i] == EOF) 
+      return EOF;
+    
+    if (dest[i] == '\n') 
+      break;
+  }
+  start++;
+  
+  return start;
+}
+
+/* Checks line for illegal characters. Return -1 when illegal character
+   were found. This is used to check for bad lines when reading data from
+   for example a configuration file. */
+
+int silc_check_line(char *buf) 
+{
+  /* Illegal characters in line */
+  if (strchr(buf, '#')) return -1;
+  if (strchr(buf, '\'')) return -1;
+  if (strchr(buf, '\\')) return -1;
+  if (strchr(buf, '\r')) return -1;
+  if (strchr(buf, '\a')) return -1;
+  if (strchr(buf, '\b')) return -1;
+  if (strchr(buf, '\f')) return -1;
+  
+  /* Empty line */
+  if (buf[0] == '\n')
+    return -1;
+  
+  return 0;
+}
+
+/* Returns current time as string. */
+
+char *silc_get_time()
+{
+  time_t curtime;
+  char *return_time;
+
+  curtime = time(NULL);
+  return_time = ctime(&curtime);
+  return_time[strlen(return_time) - 1] = '\0';
+
+  return return_time;
+}
+
+/* Converts string to capital characters */
+
+char *silc_to_upper(char *string)
+{
+  int i;
+  char *ret = silc_calloc(strlen(string) + 1, sizeof(char));
+
+  for (i = 0; i < strlen(string); i++)
+    ret[i] = toupper(string[i]);
+
+  return ret;
+}
+
+/* Compares two strings. Strings may include wildcards * and ?.
+   Returns TRUE if strings match. */
+
+int silc_string_compare(char *string1, char *string2)
+{
+  int i;
+  int slen1 = strlen(string1);
+  int slen2 = strlen(string2);
+  char *tmpstr1, *tmpstr2;
+
+  if (!string1 || !string2)
+    return FALSE;
+
+  /* See if they are same already */
+  if (!strncmp(string1, string2, strlen(string2)))
+    return TRUE;
+
+  if (slen2 < slen1)
+    if (!strchr(string1, '*'))
+      return FALSE;
+  
+  /* Take copies of the original strings as we will change them */
+  tmpstr1 = silc_calloc(slen1 + 1, sizeof(char));
+  memcpy(tmpstr1, string1, slen1);
+  tmpstr2 = silc_calloc(slen2 + 1, sizeof(char));
+  memcpy(tmpstr2, string2, slen2);
+  
+  for (i = 0; i < slen2; i++) {
+    
+    /* * wildcard. Only one * wildcard is possible. */
+    if (tmpstr1[i] == '*')
+      if (!strncmp(tmpstr1, tmpstr2, i)) {
+       memset(tmpstr2, 0, slen2);
+       strncpy(tmpstr2, tmpstr1, i);
+       break;
+      }
+    
+    /* ? wildcard */
+    if (tmpstr1[i] == '?') {
+      if (!strncmp(tmpstr1, tmpstr2, i)) {
+       if (!(slen1 < i + 1))
+         if (tmpstr1[i + 1] != '?' &&
+             tmpstr1[i + 1] != tmpstr2[i + 1])
+           continue;
+       
+       if (!(slen1 < slen2))
+         tmpstr2[i] = '?';
+      }
+#if 0
+    } else {
+      if (strncmp(tmpstr1, tmpstr2, i))
+       strncpy(tmpstr2, string2, slen2);
+#endif
+    }
+  }
+  
+  /* if using *, remove it */
+  if (strchr(tmpstr1, '*'))
+    *strchr(tmpstr1, '*') = 0;
+  
+  if (!strcmp(tmpstr1, tmpstr2)) {
+    memset(tmpstr1, 0, slen1);
+    memset(tmpstr2, 0, slen2);
+    silc_free(tmpstr1);
+    silc_free(tmpstr2);
+    return TRUE;
+  }
+  
+  memset(tmpstr1, 0, slen1);
+  memset(tmpstr2, 0, slen2);
+  silc_free(tmpstr1);
+  silc_free(tmpstr2);
+  return FALSE;
+}
+
+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. */
+
+char *silc_encode_pem(unsigned char *data, unsigned int len)
+{
+  int i, j;
+  unsigned int bits, c, char_count;
+  char *pem;
+
+  char_count = 0;
+  bits = 0;
+  j = 0;
+
+  pem = silc_calloc(((len * 8 + 5) / 6) + 5, sizeof(*pem));
+
+  for (i = 0; i < len; i++) {
+    c = data[i];
+    bits += c;
+    char_count++;
+
+    if (char_count == 3) {
+      pem[j++] = pem_enc[bits  >> 18];
+      pem[j++] = pem_enc[(bits >> 12) & 0x3f];
+      pem[j++] = pem_enc[(bits >> 6)  & 0x3f];
+      pem[j++] = pem_enc[bits & 0x3f];
+      bits = 0;
+      char_count = 0;
+    } else {
+      bits <<= 8;
+    }
+  }
+
+  if (char_count != 0) {
+    bits <<= 16 - (8 * char_count);
+    pem[j++] = pem_enc[bits >> 18];
+    pem[j++] = pem_enc[(bits >> 12) & 0x3f];
+
+    if (char_count == 1) {
+      pem[j++] = '=';
+      pem[j] = '=';
+    } else {
+      pem[j++] = pem_enc[(bits >> 6) & 0x3f];
+      pem[j] = '=';
+    }
+  }
+
+  return pem;
+}
+
+/* Same as above but puts newline ('\n') every 72 characters. */
+
+char *silc_encode_pem_file(unsigned char *data, unsigned int data_len)
+{
+  int i, j;
+  unsigned int len, cols;
+  char *pem, *pem2;
+
+  pem = silc_encode_pem(data, data_len);
+  len = strlen(pem);
+
+  pem2 = silc_calloc(len + (len / 72) + 1, sizeof(*pem2));
+
+  for (i = 0, j = 0, cols = 1; i < len; i++, cols++) {
+    if (cols == 72) {
+      pem2[i] = '\n';
+      cols = 0;
+      len++;
+      continue;
+    }
+
+    pem2[i] = pem[j++];
+  }
+
+  return pem2;
+}
+
+/* Decodes PEM into data. Returns the decoded data. Note: This is
+   originally public domain code and is still PD. */
+
+unsigned char *silc_decode_pem(unsigned char *pem, unsigned int pem_len,
+                              unsigned int *ret_len)
+{
+  int i, j;
+  unsigned int len, c, char_count, bits;
+  unsigned char *data;
+  static char ialpha[256], decoder[256];
+
+  for (i = 64 - 1; i >= 0; i--) {
+    ialpha[pem_enc[i]] = 1;
+    decoder[pem_enc[i]] = i;
+  }
+
+  char_count = 0;
+  bits = 0;
+  j = 0;
+
+  if (!pem_len)
+    len = strlen(pem);
+  else
+    len = pem_len;
+
+  data = silc_calloc(((len * 6) / 8), sizeof(*data));
+
+  for (i = 0; i < len; i++) {
+    c = pem[i];
+
+    if (c == '=')
+      break;
+
+    if (c > 127 || !ialpha[c])
+      continue;
+
+    bits += decoder[c];
+    char_count++;
+
+    if (char_count == 4) {
+      data[j++] = bits >> 16;
+      data[j++] = (bits >> 8) & 0xff;
+      data[j++] = bits & 0xff;
+      bits = 0;
+      char_count = 0;
+    } else {
+      bits <<= 6;
+    }
+  }
+
+  switch(char_count) {
+  case 1:
+    silc_free(data);
+    return NULL;
+    break;
+  case 2:
+    data[j++] = bits >> 10;
+    break;
+  case 3:
+    data[j++] = bits >> 16;
+    data[j++] = (bits >> 8) & 0xff;
+    break;
+  }
+
+  if (ret_len)
+    *ret_len = j;
+
+  return data;
+}
+
+/* Parse nickname string. The format may be <num>!<nickname>@<server> to
+   support multiple same nicknames. The <num> is the final unifier if same
+   nickname is on same server. Note, this is only local format and server
+   does not know anything about these. */
+
+int silc_parse_nickname(char *string, char **nickname, char **server,
+                       unsigned int *num)
+{
+  unsigned int tlen;
+  char tmp[256];
+
+  if (!string)
+    return FALSE;
+
+  if (strchr(string, '!')) {
+    tlen = strcspn(string, "!");
+    memset(tmp, 0, sizeof(tmp));
+    memcpy(tmp, string, tlen);
+
+    if (num)
+      *num = atoi(tmp);
+
+    if (tlen >= strlen(string))
+      return FALSE;
+
+    string += tlen + 1;
+  }
+
+  if (strchr(string, '@')) {
+    tlen = strcspn(string, "@");
+    
+    if (nickname) {
+      *nickname = silc_calloc(tlen + 1, sizeof(char));
+      memcpy(*nickname, string, tlen);
+    }
+    
+    if (server) {
+      *server = silc_calloc(strlen(string) - tlen, sizeof(char));
+      memcpy(*server, string + tlen + 1, strlen(string) - tlen - 1);
+    }
+  } else {
+    if (nickname)
+      *nickname = strdup(string);
+  }
+
+  return TRUE;
+}
+
+/* Parses command line. At most `max_args' is taken. Rest of the line
+   will be allocated as the last argument if there are more than `max_args'
+   arguments in the line. Note that the command name is counted as one
+   argument and is saved. */
+
+void silc_parse_command_line(unsigned char *buffer, 
+                            unsigned char ***parsed,
+                            unsigned int **parsed_lens,
+                            unsigned int **parsed_types,
+                            unsigned int *parsed_num,
+                            unsigned int max_args)
+{
+  int i, len = 0;
+  int argc = 0;
+  const char *cp = buffer;
+
+  *parsed = silc_calloc(1, sizeof(**parsed));
+  *parsed_lens = silc_calloc(1, sizeof(**parsed_lens));
+
+  /* Get the command first */
+  len = strcspn(cp, " ");
+  (*parsed)[0] = silc_to_upper((char *)cp);
+  (*parsed_lens)[0] = len;
+  cp += len + 1;
+  argc++;
+
+  /* Parse arguments */
+  if (strchr(cp, ' ') || strlen(cp) != 0) {
+    for (i = 1; i < max_args; i++) {
+
+      if (i != max_args - 1)
+       len = strcspn(cp, " ");
+      else
+       len = strlen(cp);
+      
+      *parsed = silc_realloc(*parsed, sizeof(**parsed) * (argc + 1));
+      *parsed_lens = silc_realloc(*parsed_lens, 
+                                 sizeof(**parsed_lens) * (argc + 1));
+      (*parsed)[argc] = silc_calloc(len + 1, sizeof(char));
+      memcpy((*parsed)[argc], cp, len);
+      (*parsed_lens)[argc] = len;
+      argc++;
+
+      cp += len;
+      if (strlen(cp) == 0)
+       break;
+      else
+       cp++;
+    }
+  }
+
+  /* Save argument types. Protocol defines all argument types but
+     this implementation makes sure that they are always in correct
+     order hence this simple code. */
+  *parsed_types = silc_calloc(argc, sizeof(**parsed_types));
+  for (i = 0; i < argc; i++)
+    (*parsed_types)[i] = i;
+
+  *parsed_num = argc;
+}
+
+/* Formats arguments to a string and returns it after allocating memory
+   for it. It must be remembered to free it later. */
+
+char *silc_format(char *fmt, ...)
+{
+  va_list args;
+  static char buf[8192];
+
+  memset(buf, 0, sizeof(buf));
+  va_start(args, fmt);
+  vsnprintf(buf, sizeof(buf) - 1, fmt, args);
+  va_end(args);
+
+  return strdup(buf);
+}
similarity index 60%
rename from lib/silccore/silcutil.h
rename to lib/silcutil/silcutil.h
index dc57eeb27826df3ac0d5a6dc8fa52839572ce9aa..1c6f764e1f4df3ccb595d6ccc8e9a3b24d6be295 100644 (file)
 /* Prototypes */
 char *silc_file_read(const char *filename, int *return_len);
 int silc_file_write(const char *filename, const char *buffer, int len);
+int silc_file_write_mode(const char *filename, const char *buffer, 
+                        int len, int mode);
 int silc_gets(char *dest, int destlen, const char *src, int srclen, int begin);
 int silc_check_line(char *buf);
 char *silc_get_time();
 char *silc_to_upper(char *string);
 int silc_string_compare(char *string1, char *string2);
+char *silc_encode_pem(unsigned char *data, unsigned int len);
+char *silc_encode_pem_file(unsigned char *data, unsigned int data_len);
+unsigned char *silc_decode_pem(unsigned char *pem, unsigned int pem_len,
+                              unsigned int *ret_len);
+int silc_parse_nickname(char *string, char **nickname, char **server,
+                       unsigned int *num);
+void silc_parse_command_line(unsigned char *buffer, 
+                            unsigned char ***parsed,
+                            unsigned int **parsed_lens,
+                            unsigned int **parsed_types,
+                            unsigned int *parsed_num,
+                            unsigned int max_args);
+char *silc_format(char *fmt, ...);
 
 #endif
diff --git a/prepare b/prepare
index 7ac2ad60fdd53be41bcddc29f57a197b9d250689..e052592dc8cf0d8297458459d6513c9406c077df 100755 (executable)
--- a/prepare
+++ b/prepare
@@ -30,4 +30,11 @@ aclocal
 autoconf
 autoheader
 automake
+
+version=`date +%Y%m%d`
+file=includes/version_internal.h
+echo "/* Automatically generated by ./prepare */" >$file
+echo "#define SILC_VERSION_STRING \"$version\"" >>$file
+echo "#define SILC_PROTOCOL_VERSION_STRING \"SILC-1.0-$version\"" >>$file
+
 echo "Done, now run ./configure and make."
index 3c8754b71c45345cbed423c840ef995e86fb32cc..3994ea8523899de404c2da36e1c1730d0cc03864 100755 (executable)
 
 echo "Cleaning entire SILC source tree..."
 echo "All errors and warnings may be safely ignored."
-make distclean
+make clean -k
+make distclean -k
 rm -f includes/stamp-*
 rm -f includes/silcconfig.*
+rm -f includes/version_internal.h
+rm -f includes/silcdefs.h.in
 rm -f Makefile.in
-rm -f doc/draft-riikonen*.txt
+rm -f doc/draft-*.txt
+rm -f doc/Makefile.in
+rm -f includes/Makefile.in
 rm -f lib/Makefile.in
+rm -f lib/contrib/Makefile.in
+rm -f lib/silcclient/Makefile.in
 rm -f lib/silccore/Makefile.in
+rm -f lib/silcutil/Makefile.in
 rm -f lib/silccrypt/Makefile.in
 rm -f lib/silcmath/Makefile.in
 rm -f lib/silcsim/Makefile.in
+rm -f lib/silcsim/modules/Makefile.in
 rm -f lib/silcske/Makefile.in
+rm -f lib/trq/tests/Makefile
+rm -f lib/trq/trq_test/Makefile
+rm -rf lib/silcmath/gmp/.deps
 rm -f silcd/Makefile.in silcd/log* silcd/*.log
 rm -f silc/Makefile.in silc/log* silc/*.log
 rm -f aclocal.m4
+rm -f config.status
 rm -f configure
 echo "Done."
index 2d6ee33ab95035c6cfdcf2031c14d02a59d9da4b..1f8e1351bc903accf1a2cc7229f11b3af05500c1 100644 (file)
@@ -1,4 +1,5 @@
 <html>
+<style TYPE="text/css"><!-- A:link {text-decoration: none}A:visited{text-decoration:none}A:active{text-decoration:none}--></style>
 <body bgcolor="#ffffff">
 <p><br>
 <a href="index.html"><img src="silc2.jpg" border=0></a>
@@ -12,13 +13,58 @@ align=center>
 <p>
 SILC (Secure Internet Live Conferencing) is a protocol which provides
 secure conferencing services in the Internet over insecure channel.
-SILC is IRC like softwarre although internally they are very different.
+SILC is IRC like software although internally they are very different.
 Biggest similiarity between SILC and IRC is that they both provide
 conferencing services and that SILC has almost same commands as IRC.  Other
 than that they are nothing alike.  Biggest differences are that SILC is 
 secure what IRC is not in any way.  The network model is also entirely
 different compared to IRC.
 
+<p>
+SILC provides security services that any other conferencing protocol
+does not offer today.  The most popular conferencing service, IRC,
+is entirely insecure.  If you need secure place to talk to some people
+or to group of people over the Internet, IRC or any other conferencing
+service, for that matter, cannot be used.  Anyone can see the messages
+and their contents in the IRC network.  And the most worse case, some
+people is able to change the contents of the messages.  Also, all the
+authentication data, such as, passwords are sent plaintext.
+
+<p>
+SILC is a lot more than just about `encrypting the traffic'.  That is
+easy enough to do with IRC, SSL and some ad hoc scripts, and even then
+the entire network cannot be secured, only part of it.  SILC provides
+security services, such as, sending private messages entirely secure; no
+one can see the message except you and the real receiver of the message.
+SILC also provides same functionality for channels; no one except those
+clients joined to the channel may see the messages destined to the
+channel.  Communication between client and server is also secured with
+session keys, and all commands, authentication data (such as passwords etc.)
+and other traffic is entirely secured.  The entire network, and all parts
+of it, is secured.  This is something that cannot be done currently with
+any other conferencing protocol, even when using the ad hoc scripts. :)
+
+<p>
+SILC has secure key exchange protocol that is used to create the session
+keys for each connection.  SILC also provides strong authentication based
+on either passwords or public key authentication.  All authentication
+data is always encrypted in the SILC network.  All connections has their
+own session keys, all channels has channel specific keys, and all private
+messages can be secured with private message specific keys.
+
+<p>
+SILC is an open source (or freeware) project and it has been released
+under the GNU General Public Licence.  The SILC is free to use and everyone
+is free to distribute and change the SILC under the terms of the GNU GPL.
+While there is no guarantee for the product SILC has been tried make
+as secure as possible.  The fact that the software and the protocol is
+open for public analysis is a good thing for end user.
+
+<p>
+Protocol specification of SILC protocol is available for
+anyone to look at. There exists three Internet Drafts that has been
+submitted to <a href="http://www.ietf.org">IETF</a>. 
+See <a href="docs.html">documentation page</a> for more information.
 <p>
 <h1>Contact</h1>
 <p>
@@ -38,4 +84,3 @@ priikone@poseidon.pspt.fi
 </table>
 </body>
 </html>
-
diff --git a/public_html/contribute.html b/public_html/contribute.html
new file mode 100644 (file)
index 0000000..4d8bdc3
--- /dev/null
@@ -0,0 +1,38 @@
+<html>
+<style TYPE="text/css"><!-- A:link {text-decoration: none}A:visited{text-decoration:none}A:active{text-decoration:none}--></style>
+<body bgcolor="#ffffff">
+<p><br>
+<a href="index.html"><img src="silc2.jpg" border=0></a>
+<table width="70%" border="0" cellspacing="0" cellpadding="1"
+align=center>
+<tr>
+<td>
+<p>
+<font size=4>
+<h1>Contributing</h1>
+<p>
+Developers are needed in SILC project.  Everyone who has the time and
+ability is welcome to come and join the project.  We need C coders,
+technical writers (to write documentation) and web administrator to take
+over these web pages.  Feel free to start narrowing down the TODO
+list.
+<p>
+Interested people are also welcome to give new ideas to the SILC protocol
+that is still in its draft phase.  You should probably go and read the
+SILC protocol specification Internet Drafts to get the idea about what
+SILC actually is.  The current software version might not give the
+whole picture of the SILC.  The Internet Drafts are available in
+<a href="docs.html">documentation page.</a>
+<p>
+Who wants to send code to the project should read the <a 
+href="docs/CodingStyle">CodingStyle</a>
+documentation.  New code must comply with the coding style conventions
+described in that document.
+<p>
+There will be anonymous CVS access as soon as I get around to set it up.
+It will be available any day now.
+</td>
+</tr>
+</table>
+</body>
+</html>
index 1fc18fedc855c2557b8dfe87672e231da33f6aaa..9838065199e29797dcb00236af794789c2c0acb6 100644 (file)
@@ -1,4 +1,5 @@
 <html>
+<style TYPE="text/css"><!-- A:link {text-decoration: none}A:visited{text-decoration:none}A:active{text-decoration:none}--></style>
 <body bgcolor="#ffffff">
 <p><br>
 <a href="index.html"><img src="silc2.jpg" border=0></a>
diff --git a/public_html/docs.html b/public_html/docs.html
new file mode 100644 (file)
index 0000000..72a042d
--- /dev/null
@@ -0,0 +1,91 @@
+<html>
+<style TYPE="text/css"><!-- A:link {text-decoration: none}A:visited{text-decoration:none}A:active{text-decoration:none}--></style>
+<body bgcolor="#ffffff">
+<p><br>
+<a href="index.html"><img src="silc2.jpg" border=0></a>
+<table width="70%" border="0" cellspacing="0" cellpadding="1"
+align=center>
+<tr>
+<td>
+<p>
+<font size=4>
+<h1>SILC Documentation</h1>
+<p>
+Currently the SILC documentation is under work and the software does not
+have that much of a documentation.
+<p>
+README file from the software: <a href="docs/README">README</a>
+<br>
+Coding Style in SILC source tree: <a href="docs/CodingStyle">CodingStyle</a>
+<p>
+[Coming later: Software manual, SILC Library Reference manual]
+
+<p><br>
+<h1>SILC Protocol Internet Drafts</h1>
+<p>
+SILC Protocol is documented and three Internet Drafts exists. These 
+Internet Drafts are also available from 
+<a href="http://www.ietf.org">IETF</a>.
+<p>
+<li>Secure Internet Live Conferencing (SILC), Protocol Specification
+<p>
+Abstract
+<p>
+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
+methods are used to protect SILC packets inside SILC network.  Two
+other Internet Drafts relates very closely to this memo;  SILC Packet
+Protocol [SILC2] and SILC Key Exchange and Authentication Protocols
+[SILC3].
+<p>
+<a href="docs/draft-riikonen-silc-spec-00.txt">
+draft-riikonen-silc-spec-00.txt</a>
+<p><br>
+
+<li>SILC Packet Protocol
+<p>
+Abstract
+<p>
+This memo describes a Packet Protocol used in the Secure Internet Live
+Conferencing (SILC) protocol specified in the Secure Internet Live
+Conferencing, Protocol Specification Internet Draft [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.
+<p>
+<a href="docs/draft-riikonen-silc-pp-00.txt">
+draft-riikonen-silc-pp-00.txt</a>
+<p><br>
+
+<li>SILC Key Exchange and Authentication Protocols
+<p>
+Abstract
+<p>
+This memo describes two protocols used in the Secure Internet Live
+Conferencing (SILC) protocol specified in the Secure Internet Live
+Conferencing, Protocol Specification internet-draft [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.  SKE uses best parts
+of the SSH2 Key Exchange protocol, Station-To-Station (STS) protocol
+and the OAKLEY Key Determination protocol [OAKLEY].
+<p>
+The 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 user with, for example, passphrase
+(pre-shared- secret) or public key (and certificate).
+<p>
+<a href="docs/draft-riikonen-silc-ke-auth-00.txt">
+draft-riikonen-silc-ke-auth-00.txt</a>
+<p><br>
+
+</td>
+</tr>
+</table>
+</body>
+</html>
diff --git a/public_html/docs/CodingStyle b/public_html/docs/CodingStyle
new file mode 100644 (file)
index 0000000..e603353
--- /dev/null
@@ -0,0 +1,575 @@
+Coding Style in SILC source tree
+================================
+
+This documents describes the coding style and coding conventions used
+in the SILC source tree.  The purpose of the document is to describe the
+common way to program for SILC and thus should be learned when programming
+new code.  The document describes various conventions regarding variable
+naming, function naming, indentation, overall appearance of a piece of
+code and how some of the technical issues has been done in the SILC and
+should be done in the future.
+
+
+Naming
+======
+
+Generic naming
+
+All identifiers, whether they defines, functions or something else, with
+execption of variables, has a common naming convention.  Usually all 
+identifiers use `silc' prefix to indicate that the identifier is part of
+SILC distribution.  For example, silc_server_init(), SILC_PACKET_TYPE_ERROR, 
+etc.  As mentioned however, variables, local or global, does not use this
+naming convention.
+
+Lower lever routines, usually some library routines, may use their
+own naming convention if generic API is defined over them.  The API uses
+the common naming convention while the lower level routines uses what
+ever they want.  For example, ciphers are implemented currently in this
+way.  They define common SILC Cipher API but the actual implementation
+of algorithms uses their own naming convention.  Another example is
+the GMP math library that uses its own function naming but we have our
+own SILC MP API over it that has been defined using common SILC naming
+convention.
+
+
+Variables
+
+Variable names are always in lowercase and any mixed-case or totally
+uppercase variable names should be avoided.  Variable names may include
+underscore if it is necessary.  For example, `unsigned char *id_string;'.
+
+The same name convention is used in structure field names.  All fields
+in structures should be in lowercase.  Global variables should have some
+sort of prefix to indicate that the variable is global.  Although, global
+variables should be avoided if possible.
+
+Local variable names should be as short as possible without losing
+meaning of the name.  For example there is no reason to call loop
+counter as `loop_counter' when `i' is commonly used instead.  Using
+variable name `tmp' is also ok and should be used when some temporary
+value is used.
+
+
+#define's and Macros
+
+All #define's should always be in uppercase to indicate that it is
+a define, for example, `#define SILC_PACKET_TYPE_NONE 0'.  As mentioned
+previously #define's and macros always use the `SILC' prefix.  The
+names also uses always underscores.
+
+Names of #define's and macros should be self explanatory.  This may
+lead to long names but it is better than having some `#define SILC_KE1_SX'
+which does not tell you anything.
+
+
+Type definitions
+
+Type definitions (typedefs) uses some what different naming convention
+from variables and macros.  Typedefs has mixed-case names and they
+never use underscores.  For example, `SilcSomeStruct', `SilcServerObject'.
+Like in any other case the names should be self explanatory which may
+lead to long names but that is not a problem.
+
+The names should tell what the typedef is about.  If it is a typedef
+of a structure it should tell what the structure is for in the first
+place.  For example `SilcClientStruct', `SilcCipherObject', 
+`SilcConfigSection´, etc.
+
+
+Structures
+
+Same naming convention used in typedefs applies to names of structures as
+well.  Same as with typedef, structure names should be self explanatory
+and should tell what the structure is made for.
+
+Structures are used a lot in SILC.  They are used as simple structures
+and as objects as well.  When normal structures are needed they are
+defined as follows,
+
+       struct SilcDummyStruct {
+         unsigned char *dummy;
+       };
+
+And used as `struct SilcDummyStruct *dummy'.  However, this is quite
+rarely used in the SILC, instead structures are typedef'd as following
+later.  When structure is used as object they are defined as follows,
+
+       typedef struct SilcDummyStruct {
+         unsigned char *dummy;
+         unsigned int flags;
+         void (*callback)(void *, unsigned int);
+       } SilcDummyObject;
+
+If the SilcDummyStruct is not needed it may be omitted (which is very
+common in SILC code), leaving,
+
+       typedef struct {
+         unsigned char *dummy;
+         unsigned int flags;
+         void (*callback)(void *, unsigned int);
+       } SilcDummyObject;
+
+Finally, it is common that structures are typedef'd pointers as they
+are very flexible to use,
+
+       typedef SilcDummyObject *SilcDummy;
+
+It is common in SILC to typedef structures instead of defining name
+for the structure.  In this case the structure may be used without
+defining `struct' to the code, For example,
+
+       SilcDummyObject dummy_obj;
+       SilcDummyObject *dummy;
+
+If the structure has a pointer typedef then they are defined as normal
+variables but for real they are pointers, For example,
+
+       SilcDummy dummy;
+       dummy = silc_calloc(1, sizeof(*dummy));
+       dummy->flags = 0;
+
+This convention is very common in SILC code and has been used consistently
+throughout the code.  The pattern here is that all structures are named
+as `SilcXxxStruct', all objects are named as `SilcXxxObject' and when
+they are typedef'd pointers they are named as `SilcXxx'.
+
+
+Functions
+
+Function naming uses the common naming convention used in the SILC.  All
+functions are always lowercase and they use underscores.  The name of
+the function always starts with prefix `silc_'.  The name of the function
+should be self explanatory which may lead to long names.  The name of
+a function is constructed from following parts,
+
+       silc_<application>_<module>_<function>
+
+The <application> is for example <client> or <server>, however, it is
+always omitted (and must be omitted) when programming library code.
+
+The <module> is the module you are programming currently.  You should
+have a pretty good idea what you are programming and what the module
+does.  For example, <cipher>, <config>, <command>, <packet>, etc.
+
+The <function> is the describtion of the functionality of the function
+you are writing.  Naturally it should be self explanatory and weird
+short names should be avoided.  It is better to have long function
+names than some odd name that does not tell what it is about.  Function
+naming could be for example, <read>, <new_id>, <register>, <find_by_name>,
+etc.
+
+So, it is common in SILC to have function names, such as,
+
+       silc_server_packet_send
+       silc_server_packet_send_to_channel
+       silc_client_packet_process
+       silc_idcache_del_by_id
+       silc_task_unregister_by_fd
+       silc_protocol_excute_final
+       silc_buffer_alloc
+
+When function registers something the name of the function should
+generally be `silc_function_register' and unregistering should happen
+with `silc_function_unregister'.  When function allocates something it
+should be called `silc_function_alloc' and when freeing it should be
+called `silc_function_free'.  Respectively, with init/uninit functions.
+
+When this naming convention is used consistently it is easy to remember
+what the name of the function is.  For example, if you need buffer it
+is easy to figure out that the routines are most likely called 
+`silc_buffer_*',  and if you need to allocate buffer it is most likely 
+called `silc_buffer_alloc'.  This sort of naming makes the programming,
+in the long run, much cleaner, simpler and faster.
+
+
+Inline functions
+
+SILC uses quite a bit inline functions to optimize the code.  The
+naming of inline functions must follow same convention as any normal
+function.  All inline functions in SILC are defined and written into
+header files.  Inline functions must be defined in following manner
+in the header file,
+
+extern inline void silc_dummy_inline(unsigned int flags)
+{
+  doing_little_dummy_things;
+}
+
+Because the function is defined as extern they can be included into
+public header files.  Do not forget to define inline function as extern.
+There are no any explicit prototype definitions for inline functions.
+
+
+Indentation
+===========
+
+SILC has been coded with Emacs so standard indentation of Emacs is used
+in the SILC code.  The indentation is always 2 characters, not a 
+tabulator.  If you use Emacs then this should not be a problem.  So,
+if you code for SILC be sure to format the code to the standard way
+used in the SILC before submitting the code.
+
+A tip for those who think that these long function names etc are just
+too long to type, consider using dynamic abbreviation found in Emacs.
+With this cool feature you only have type some part of the string and
+then use the dabbrev to find the rest of the string.  I guess, by 
+default it is M-/ in Emacs but I have binded it into Shift-TAB so it
+is fast to use when typing.
+
+
+Placing Braces
+==============
+
+The common fight about how the braces should be placed in the C code
+is probably going on in the SILC code as well.  However, SILC code
+is consistent about this.  The placing uses K&R style thus the opening
+of the brace is put to the last on the line and the closing brace is
+on first on its own line,
+
+       if (condition) {
+         silc_something();
+         silc_something_more();
+       }
+
+The function's braces are as follows,
+
+       int silc_client_function()
+       {
+         return 0;
+       }
+
+More examples,
+
+       if (condition) {
+         something;
+         silc_something_more();
+       } else {
+         something_else;
+       }
+
+       if (condition) {
+         something;
+         silc_something_more();
+       } else if (other_condition) {
+         something;
+         silc_something_more();
+       } else {
+         something_else;
+       }
+
+
+Commenting
+==========
+
+SILC code is usually pretty well commented and this should be the way
+in the future as well.  However, the comments should not tell how the
+code works, it should be apparent by looking at the code.  Instead the
+commenting should tell what the function does.  All functions should
+be commented.  If nothing more a line of comment telling what the function
+is about helps a lot when you go back to it after six months.  Static
+functions should be commented as well.
+
+The commenting of functions in SILC has been made into the source files,
+and not in the header files where the function prototypes reside.  Header
+files usually includes structure comments, macro comments and perhaps
+some other relevant commenting but usually not function comments.
+It is also Ok to comment the code inside function when it is needed.
+
+Comments should use normal C-language comments /* */ and not C++ comments.
+
+
+General Appearance
+==================
+
+The code should be clean and good to eye, although the function of it
+must always supersede the appearance.  However, it is nice to read code
+that looks good.  Here are some issues on general appearance.
+
+       o Use empty lines when appropriate but not too much.  There
+         should not be excess empty lines at the end of file.  However,
+          using some empty lines in the code makes the code better 
+          looking.
+
+       o The line is 79 characters long and not one character longer.
+         Longer lines must be cut in two, or three, or ...
+
+       o Use spaces very much.  Do not write things like `if(!k)',
+         instead write `if (!k)'.  Same with `for', `while', etc.
+         Spaces should be put around all binary operators like `*', 
+         `==', `+', etc.  Also, when setting a value to variable be
+         sure to set spaces around `='.  When writing argument list 
+         to a function, space should follow each of the comma in the
+         list.  However, do not use spaces with parenthesis, for 
+         example, `if ( !k )' is not accepted.
+
+       o If you are not sure about how something should be done or
+         the code you've done is not finished, it should be commented
+         with XXX plus explanation what is going on.
+
+
+Source Files
+
+All source files starts with header that includes the name of the author,
+copyright notice and the copyright policy, usually part of GNU GPL licence.
+Now, this really isn't that important but some sort of header should be in
+all source files.
+
+In the start of the source files should include the #include's that are
+needed.  All library source files must include `silcincludes.h', this is
+a must.  Client source file must include at least `clientincludes.h' and
+server source file must include `serverincludes.h'.  Additional include's
+may be added as well, however, system specific includes should not be
+added directly (unless it is really a special case).  Go see any source
+file as an example.
+
+
+Header Files
+
+As with source files, header files should include same file header at
+the start of the file.
+
+Header files are usually divided in three parts in SILC.  At the start
+of header files should include all definitions, typedefs, structure
+definitions etc.  After definitions should include macros and inline
+functions if any of those exist.  After macros should include the
+public prototypes of the functions.  Go see any header file as an example.
+
+
+Debug Messages
+==============
+
+When writing new code it is recommended that the code produces some sort
+of debug messages.  SILC has own debug logging system that must be used
+in the generic SILC code.  Few macros exist,
+
+       SILC_LOG_DEBUG
+       SILC_LOG_HEXDUMP
+       SILC_LOG_INFO
+       SILC_LOG_WARNING
+       SILC_LOG_ERROR
+       SILC_LOG_FATAL
+
+When doing debugging the most used macros are SILC_LOG_DEBUG and 
+SILC_LOG_HEXDUMP.  With first macro you can print out any sort of debug
+messages with variable argument list, for example,
+
+       SILC_LOG_DEBUG(("Start"));
+       SILC_LOG_DEBUG(("Packet length %d", packet_len));
+
+Note the extra parenthesis that are required for the macro so that the
+variable argument list formatting would work correctly.
+
+When you need to dump some data into screen you should use SILC_LOG_HEXDUMP
+macro.  For example,
+
+       SILC_LOG_HEXDUMP(("Packet"), packet->data, packet->len);
+       SILC_LOG_HEXDUMP(("Packet, size %d", size), packet->data, packet->len);
+
+In SILC_LOG_HEXDUMP the data to be dumped are set between the second last
+and last parenthesis in order that the data is first and the length of the
+data is next.  If arguments are used they are used the same way as in
+SILC_LOG_DEBUG and the data to be dumped are set after the argument list
+is closed with the parenthesis.
+
+
+Memory Allocation
+=================
+
+Naturally, memory allocation is a big part of SILC.  However, there are
+few things that must be noted on the issue.  SILC has defined its own
+memory allocation functions that must be used.  System specific functions
+must not be used directly.  There are functions like,
+
+       silc_malloc
+       silc_calloc
+       silc_realloc
+       silc_free
+
+You should always use silc_calloc instead of silc_malloc because
+silc_calloc automatically zeroes the allocated memory area.  This is
+important especially with structures because generally we want that all
+fields, by default, are zero.
+
+So, instead of doing
+
+       SilcStruct *ptr;
+
+       ptr = silc_malloc(sizeof(*ptr));
+
+You should do
+
+       SilcStruct *ptr
+
+       ptr = silc_calloc(1, sizeof(*ptr));
+
+
+When freeing memory it should be zero'ed when appropriate.  All memory
+allocations that handle sensitive data such as keys should be zero'ed
+by memset() before freeing the memory.  Common way to do is,
+
+       memset(ptr, 'F', sizeof(*ptr));
+       silc_free(ptr);
+
+Where 'F' indicates free'd memory if you ever check it with debugger.
+Other choice is to use 0 instead of 'F'.  The pointer after freeing 
+should be set to NULL if appropriate, ptr = NULL.
+
+Note that some functions in the SILC library handles the zeroing of
+the memory area automatically, like for example, silc_buffer_free.
+
+
+Callback Programming
+====================
+
+SILC uses pretty much programming convention called callback programming.
+This is a programming style that extensively uses function pointers
+which are usually called inside some other function.
+
+Typical scenario is this;  You are performing some task that most likely
+is asynchronous.  You need to be able get some structure context when
+the operation finishes.  Most common way in this case is to pass the
+structure context to the operation function with a callback function
+that is called when the operation has finished.  Following code explains
+probaly better.
+
+
+/* Prototypes */
+static silc_callback(void *context);
+void silc_start();
+void silc_async_operation_register(int fd, SilcAsyncCb callback, 
+                                   void *context);
+void silc_async_operation(int fd, SilcAsyncCb callback, void *context);
+
+/* Type definition of the callback function */
+typedef (*SilcAsyncCb)(void *context);
+
+/* Registers async operation and passes callback function and context
+   to it as arguments. */
+
+void silc_start()
+{
+  SilcDummyStruct *ctx;
+
+  ctx = silc_calloc(1, sizeof(*ctx));
+  ctx->fd = 30;
+
+  silc_async_operation_register(30, silc_callback, (void *)ctx);
+}
+
+/* The callblack function that is called from the operation function */
+
+static void silc_callback(void *context)
+{
+  SilcDummyStruct *ctx = (SilcDummyStruct *)context;
+
+  ctx->fd = 10;
+}
+
+/* Register async operation */
+
+void silc_async_operation_register(int fd, SilcAsyncCb callback, 
+                                   void *context)
+{
+  /* Register and return immediately */
+  silc_register_async_operation_internal(fd, callback, context);
+}
+
+/* Operation function that will call the callback function after it
+   has finished. */
+
+void silc_async_operation(int fd, SilcAsyncCb callback, void *context)
+{
+  here_this_function_does_what_ever_it_wants;
+
+  here_something_more;
+
+  /* We are finished, call the callback */
+  if (callback)
+    (*callback)(context);
+}
+       
+
+Now, after the registeration of the async operation in this dumb example
+the silc_start returns immediately.  Lets say, 10 seconds later the
+async operation is executed (it would have been better to call it just
+timeout) by calling silc_async_operation which on the other hand will
+call the callback function after it has finished.  The context that
+was passed to the registeration function is now passed back to the
+callback function.  Thus, you will get the context you wanted.  This is
+the typical scenario where callback functions come in very handy.  This 
+is also the best way to pass context's that are needed later without
+making them global context's.  And as long as the context's are defined
+as void * they can be what ever contexts making the functions, that
+takes in the context, generic.  Like in above example, you could pass
+what ever context to the registeration function if you'd want to.
+
+Callback programming is also used when making generic API's of some
+operation.  For example, if you want generic hooks to the API so that
+something could be done while doing the operation (maybe to collect
+statistics or something else) just get the functions accept a callback
+function and context and call them when appropriate, then continue
+as normally.
+
+Callback functions has been used a lot in SILC code.  The scheduler
+and task system implemented in core library uses extensively callback
+functions.  Timeout's uses callbacks as well.  SILC Key Exchange protocol
+uses callback functions too.  The callback function in SKE provides
+packet sending without defining into the SKE code how the packets
+should be sent thus making it generic for both client and server 
+(and actually to any application for that matter).
+
+There are some technical issues on callback programming that are
+common in SILC code.
+
+       o Callback functions are usually defined as void functions
+         as the routine that calls them usually don't care about
+         what the callback function does.  Many times it doesn't
+         actually know what it does nor would it be interested to
+         know that.  It doesn't care about return values.
+
+       o Many times the callback functions are static functions
+         because they are not wanted to be called in anyway else
+         than as callback functions.
+
+       o Callback function names usually have the `_cb' or `_callback'
+         at the end of function name, eg. silc_client_cb.
+
+       o Type of callback functions should be typedef'd instead of
+         defining them directly to the function.  See above example.
+         This makes the code much cleaner.
+
+       o Callback function types has usually the suffix `Cb' or
+         Â´Callback' in the type name, eg. SilcAsyncCallback.
+
+       o You must explicitly cast the void * context's to correct
+         type in the callback function.  Of course you must be careful
+         to cast them to the correct type as they are void * they 
+         could be anything.  Many times this causes problems when you
+         forget what was the type you passed to it.  Callback 
+         programming may get very complex.
+
+       o You cannot use inline functions as callback functions,
+         naturally.
+
+Callback programming may be hard to understand from first standing if
+you haven't done these before, and debugging them may be pain in the
+ass sometimes.  But after the grand idea behind callback functions 
+becomes clear they are a wonderful tool.
+
+
+Copyrights of the Code
+======================
+
+The original code in SILC is GPL licensed.  GMP is GPL licensed as well
+and zlib is with free license as well.  New code will be accepted to
+the official SILC source tree if it is coded in GPL or similiar free
+license as GPL is, and of course if it is public domain.  Code with
+restricting licenses will not be accepted to the SILC source tree.
+SILC is free software, open source, what ever, project and will remain
+as such.
+
+Also, about authoring; If you write code to SILC don't forget to add
+yourself as author at the start of the file.  The reason for this is
+of course that everybody should get the credits they deserve but also 
+if problems occur we know who to blame. :)
diff --git a/public_html/download.html b/public_html/download.html
new file mode 100644 (file)
index 0000000..d12012d
--- /dev/null
@@ -0,0 +1,33 @@
+<html>
+<style TYPE="text/css"><!-- A:link {text-decoration: none}A:visited{text-decoration:none}A:active{text-decoration:none}--></style>
+<body bgcolor="#ffffff">
+<p><br>
+<a href="index.html"><img src="silc2.jpg" border=0></a>
+<table width="70%" border="0" cellspacing="0" cellpadding="1"
+align=center>
+<tr>
+<td>
+<p>
+<font size=4>
+<h1>Download SILC</h1>
+<p>
+Currently only available version is 06072000 Development Version that is
+meant for testing only. Please, read the README and INSTALL files after
+downloading for instructions how to install and use SILC.
+<p>
+HTTP: <a href="http://silc.pspt.fi/silc-06072000.tar.gz">
+silc-06072000.tar.gz (1.1 MB)</a>
+<br>
+FTP: <a href="ftp://silc.pspt.fi/pub/silc/snapshots/silc-06072000.tar.gz">
+silc-06072000.tar.gz (1.1 MB)</a>
+<p>
+SILC has been coded and tested under Linux. It has not been tested on
+any other Unix platform just yet.
+<p>
+Daily snapshots will be available a bit later (after the anonymous CVS
+repository has been set up).
+</td>
+</tr>
+</table>
+</body>
+</html>
diff --git a/public_html/faq.html b/public_html/faq.html
new file mode 100644 (file)
index 0000000..39eb90b
--- /dev/null
@@ -0,0 +1,153 @@
+<html>
+<style TYPE="text/css"><!-- A:link {text-decoration: none}A:visited{text-decoration:none}A:active{text-decoration:none}--></style>
+<body bgcolor="#ffffff">
+<p><br>
+<a href="index.html"><img src="silc2.jpg" border=0></a>
+<table width="70%" border="0" cellspacing="0" cellpadding="1"
+align=center>
+<tr>
+<td>
+<p>
+<font size=4>
+<h1>Frequently Asked Questions</h1>
+<p>
+<i>Q: What is SILC?</i><br>
+A: SILC (Secure Internet Live Conferencing) is a protocol which provides
+   secure conferencing services in the Internet over insecure channel.
+   SILC is IRC like although internally they are very different.  Biggest
+   similiarity between SILC and IRC is that they both provide conferencing
+   services and that SILC has almost same commands as IRC.  Other than
+   that they are nothing alike.
+<p>
+   Biggest differences are that SILC is secure what IRC is not in any
+   way.  The network model is also entirely different compared to IRC.
+<p><br>
+
+<i>Q: Why SILC in the first place?</i></br>
+A: Simply for fun, nothing more.  An actually for need back then when
+   it was started.  SILC has been very interesting and educational
+   project.
+<p><br>
+
+<i>Q: When will SILC be completed?</i><br>
+A: SILC still has a lot things to do.  The time of completion is much
+   related to how many interested people is willing to join the effort.
+   It will be ready when it is ready.  The reason for release of the
+   current development version is just to get it out and people aware
+   that something like this exist.  SILC is not ready for production
+   use so it is not expected that there is that much of a hype around
+   SILC.  I don't have to hurry... :)
+<p><br>
+
+<i>Q: Why use SILC? Why not IRC with SSL?</i><br>
+A: Sure, that is possible, although, does that secure the entire IRC
+   network? And does that increase or decrease the lags and splits in
+   the IRC network?  Does that provide user based security where some
+   specific private message are secured? Does that provide security
+   where some specific channel messages are secured?  Security is not
+   just about applying encryption to traffic and SILC is not just about
+   `encrypting the traffic`.  You cannot make insecure protocol suddenly
+   secure just by encrypting the traffic.  SILC is not meant to be IRC
+   replacement.  IRC is good for some things, SILC is good for same and
+   some other things.
+<p><br>
+
+<i>Q: Can I use SILC with IRC client?  What about can I use IRC with SILC
+   client?</i><br>
+A: Answer for both question is no.  IRC client is in no way compatible
+   with SILC server.  SILC client cannot currently use IRC but this may
+   change in the future if IRC support is added to the SILC client.  
+   After that one could use both SILC and IRC with the same client.
+   Although, even then one cannot talk from SILC network to IRC network.
+   That just is not possible.
+<p><br>
+
+<i>Q: Why client/server protocol is based on IRC? Would it be more
+   interesting to implement something extensible and more powerful?</i><br>
+A: They are not, none the least.  Have you read the protocol specification?
+   The client superficially resembles IRC client but everything that
+   happens under the hood is nothing alike IRC.  SILC could *never*
+   support IRC because the entire network toppology is different
+   (hopefully more scalable and powerful).  So no, SILC protocol (client  
+   or server) is not based on IRC.  Instead, I've taken good things from
+   IRC and leaved all the bad things behind and not even tried to burden
+   myself with the IRC caveats that will burden IRC and future IRC
+   projects til the end.  SILC client resembles IRC client because it is  
+   easier for new users to start using SILC when they already know all the
+   commands.
+<p><br>
+
+
+<i>Q: Why SILC? Why not IRC3?</i><br>
+A: Question that is justified no doubt of that.  I didn't start doing SILC
+   to be replacement for IRC.  SILC was something that didn't exist in
+   1996 or even today except that SILC is now released.  However, I did
+   check out the IRC3 project in 1997 when I started coding and planning
+   the SILC protocol.
+<p>
+   But, IRC3 is problematic. Why? Because it still doesn't exist.  The
+   project is at the same spot where it was in 1997 when I checked it out.
+   And it was old project back then as well.  Couple of months ago I 
+   checked it again and nothing were happening.  That's the problem of IRC3
+   project.  The same almost happened to SILC as well as I wasn't making
+   real progress over the years.  I talked to the original author of IRC,
+   Jarkko Oikarinen, in 1997 and he directed me to the IRC3 project, 
+   although he said that IRC3 is a lot of talking and not that much of 
+   anything else.  I am not trying to put down the IRC3 project but its
+   problem is that no one in the project is able to make a decision what
+   is the best way to go about making the IRC3 and I wasn't going to be
+   part of that.  The fact is that if I would've gone to IRC3 project,
+   nor IRC3 or SILC would exist today.  I think IRC3 could be something
+   really great if they just would get their act together and start
+   coding the thing.
+<p><br>
+
+<i>Q: How secure SILC really is?</i><br>
+A: A good question which I don't have a answer.  SILC has been tried to
+   make as secure as possible.  However, there is no security protocol
+   or security software that has not been vulnerable to some sort of
+   attacks.  SILC is in no means different from this.  So, it is suspected 
+   that there are security holes in the SILC.  These holes just needs to 
+   be found so that they can be fixed.
+<p>
+   But to give you some parameters of security SILC uses the most secure
+   crytographic algorithms such as Blowfish, RC5, Twofish, etc.  SILC
+   does not have DES or 3DES as DES is insecure and 3DES is just too
+   slow.  SILC also uses cryptographically strong random number generator
+   when it needs random numbers.  Public key cryptography uses RSA
+   and Diffie Hellman algorithms.  Key lengths for ciphers are initially
+   set to 128 bits but many algorithm supports longer keys.  For public
+   key algorithms the starting key length is 1024 bits.
+<p>
+   But the best answer for this question is that SILC is as secure as
+   its weakest link.  SILC is open and the protocol is open and in public
+   thus open for security analyzes.
+<p>
+   To give a list of attacks that are ineffective against SILC:
+<p>
+      <li> Man-in-the-middle attacks are ineffective if proper public key
+        infrastructure is used.  SILC is vulnerable to this attack if
+        the public keys used in the SILC are not verified to be trusted.
+
+      <li> IP spoofing is ineffective (because of encryption and trusted 
+        keys).
+
+      <li> Attacks that change the contents of the data or add extra
+        data to the packets are ineffective (because of encryption and
+        integrity checks).
+
+      <li> Passive attacks (listenning network traffic) are ineffective
+        (because of encryption).  Everything is encrypted including
+        authentication data such as passwords when they are needed.
+
+      <li> Any sort of cryptanalytic attacks are tried to make ineffective
+        by using the best cryptographic algorithms out there.
+<p><br>
+<i>More to come later...</i>
+<p><br>
+
+</td>
+</tr>
+</table>
+</body>
+</html>
index 426901f38a98d4191ef3bb7b6decdae59e628915..91417cb270c6eb8e56e88a795ca27bfad705eea2 100644 (file)
@@ -1,4 +1,5 @@
 <html>
+<style TYPE="text/css"><!-- A:link {text-decoration: none}A:visited{text-decoration:none}A:active{text-decoration:none}--></style>
 <body bgcolor="#ffffff">
 <p><br>
 <a href="index.html"><img src="silc2.jpg" border=0></a>
index ccfe31beeabaa73401f26f82537ea626ec2e542e..2a43ec14e1403c3c2edbbf39e039c92140db64a8 100644 (file)
@@ -1,4 +1,5 @@
 <html>
+<style TYPE="text/css"><!-- A:link {text-decoration: none}A:visited{text-decoration:none}A:active{text-decoration:none}--></style>
 <body bgcolor="#ffffff">
 <p><br>
 <a href="index.html"><img src="silc2.jpg" border=0></a>
index 4ce90b3d8a253fc2f6ac90f0d15ba36227058a49..d156db11a6a9be98b95b87e7e86c12cb813b5f82 100644 (file)
@@ -17,7 +17,7 @@
   <li><a href="about.html">About the SILC</a>
   <li><a href="history.html">History</a>
   <li><a href="faq.html">The SILC FAQ</a>
-  <li><a href="doc.html">SILC Documentation</a>
+  <li><a href="docs.html">SILC Documentation</a>
   <li><a href="features.html">SILC Features</a>
 </ul>
 </td>
 <tr><td bgcolor="#EEEEFF">&nbsp;<tr><td>&nbsp;</td></tr>
 <tr><td>
 <div style="margin-left: 20px">
-<center><h1>SILC XXXX2000 Development Version Available</h1></center>
+<center><h1>SILC 06072000 Development Version Available</h1></center>
 <center>
 <font size=4>
-No, it's not available just yet.
+The Developer's version 06072000 of SILC is available for testing. Note
+that developer's versions are preliminary versions of the software and
+they may not compile or work. However, these releases are tested and
+they have compiled and worked. Read the README and INSTALL files after
+downloading on instructions how to compile and use SILC.
+<p>
+Download: <a href="download.html">SILC 06072000 Development Version</a>
+<br>
+Changes: <a href="changes.txt">SILC 06072000 Changes</a>
+<p>
 </center>
 <p><br>
+</div>
+</td></tr>
 
+<tr><td bgcolor="#EEEEFF">&nbsp;<tr><td>&nbsp;</td></tr>
+<tr><td>
+<div style="margin-left: 20px">
+<center><h1>Official Port For SILC Has Been Assigned</h1></center>
+<center>
+<font size=4>
+<p>
+<a href="http://www.iana.org">IANA</a> has assigned on 06.07.2000 official
+port for SILC protocol. The port is TCP 706 and the latest release already
+supports this port.
+<p>
+</center>
+<p><br>
+</div>
+</td></tr>
+
+<tr><td bgcolor="#EEEEFF">&nbsp;<tr><td>&nbsp;</td></tr>
+<tr><td>
+<div style="margin-left: 20px">
+<center><h1>SILC Server Available For Testing</h1></center>
+<center>
+<font size=4>
+<p>
+There is SILC server up and running that can be tested. Just give command
+/server silc.pspt.fi to connect to the server. There may be some action
+on channel #silc so you might want to give command /join #silc. To get
+into action just say hello.
+<p>
+Note the old server on port 334 is not running anymore. The new server
+is running on port 706, please update your SILC client.
+<p>
+</center>
+<p><br>
 </div>
 </td></tr>
+
 <tr><td bgcolor="#EEEEFF">&nbsp;<tr><td>&nbsp;</td></tr>
 <tr><td>
 <div style="margin-left: 20px">
 <center><h1>Developers Wanted For SILC Project</h1></center>
 <center>
 <font size=4>
-XXX
+SILC Project needs developers who would like to contribute their time,
+skills and ideas to the project.  SILC still has a long road ahead before
+the first official stable release.  We need C coders,  technical writers
+(to write documentation) and web administrator to take over these web pages.
+Feel free to start narrowing down the TODO list.
+<p>
+If You would like to contribute to SILC project please contact me at:
+<a href="mailto:priikone@poseidon.pspt.fi">priikone@poseidon.pspt.fi</a>
 </center>
 <p><br>
 </div>
 </td></tr>
+
+<tr><td bgcolor="#EEEEFF">&nbsp;<tr><td>&nbsp;</td></tr>
+<tr><td>
+<div style="margin-left: 20px">
+<center><h1>SILC Project Started</h1></center>
+<center>
+<font size=4>
+The Press release:
+<p>
+New Open Source project called Secure Internet Live Conferencing (SILC)
+has been started.  Initial development version of the software is
+available for testing.
+<p>
+SILC (Secure Internet Live Conferencing) is a protocol which provides
+secure conferencing services in the Internet over insecure channel.
+SILC is IRC like software although internally they are very different.
+Biggest similiarity between SILC and IRC is that they both provide
+conferencing services and that SILC has almost same commands as IRC.
+Other
+than that they are nothing alike.  Biggest differences are that SILC is
+secure what IRC is not in any way.  The network model is also entirely
+different compared to IRC.
+<p>
+SILC is an open source (or freeware) project and it has been released
+under the GNU General Public Licence.  The SILC is free to use and
+everyone
+is free to distribute and change the SILC under the terms of the GNU GPL.
+While there is no guarantee for the product SILC has been tried make
+as secure as possible.  Developers are needed and everyone is free to
+contribute their time, skills and ideas for the project.
+<p>
+Official SILC Project home page: 
+<a href="http://silc.pspt.fi">http://silc.pspt.fi</a>
+<p>
+SILC Development Version is available for download from following addresses:
+<p>
+HTTP: <a href="http://silc.pspt.fi/silc-28062000.tar.gz">
+silc-28062000.tar.gz (1.1 MB)</a>
+<br>
+FTP: <a href="ftp://silc.pspt.fi/pub/silc/snapshots/silc-28062000.tar.gz">
+silc-28062000.tar.gz (1.1 MB)</a>
+<p>
+The SILC protocol specification is available from following addresses:
+<p>
+HTTP: <a href="http://silc.pspt.fi/docs.html">
+http://silc.pspt.fi/docs.html</a>
+<br>
+FTP: <a href="ftp://silc.pspt.fi/pub/silc/">
+ftp://silc.pspt.fi/pub/silc/</a>
+<p>
+Author's contact information:
+<p>
+Pekka Riikonen <a href="mailto:priikone@poseidon.pspt.fi">
+priikone@poseidon.pspt.fi</a>
+<br>
+Home page: <a href="http://poseidon.pspt.fi/~priikone/english/">
+http://poseidon.pspt.fi/~priikone/english/</a>
+<p>
+</center>
+<p><br>
+</div>
+</td></tr>
+
 </table>
 
 <p>
@@ -69,7 +184,8 @@ Webpage by Pekka Riikonen <a href="mailto:priikone@poseidon.pspt.fi">
 priikone@poseidon.pspt.fi</a><br>
 Logos automagically generated with GIMP<br>
 [ <!--#exec cgi="/cgi-bin/textcounter/counter.cgi"--> ] hits since June 12 2000<br>
-Last updated: Mon Jun 12 10:44:06 EEST 2000
+Last updated:
+Thu Jul  6 12:51:08 EEST 2000
 </center>
 </font>
 </body>
diff --git a/public_html/press.html b/public_html/press.html
new file mode 100644 (file)
index 0000000..89957e4
--- /dev/null
@@ -0,0 +1,72 @@
+<html>
+<style TYPE="text/css"><!-- A:link {text-decoration: none}A:visited{text-decoration:none}A:active{text-decoration:none}--></style>
+<body bgcolor="#ffffff">
+<p><br>
+<a href="index.html"><img src="silc2.jpg" border=0></a>
+<table width="70%" border="0" cellspacing="0" cellpadding="1"
+align=center>
+<tr>
+<td>
+<p>
+<font size=4>
+<h1>XXX</h1>
+<p>
+New Open Source project called Secure Internet Live Conferencing (SILC)
+has been started.  Initial development version of the software is
+available for testing.
+<p>
+SILC (Secure Internet Live Conferencing) is a protocol which provides
+secure conferencing services in the Internet over insecure channel.
+SILC is IRC like software although internally they are very different.
+Biggest similiarity between SILC and IRC is that they both provide
+conferencing services and that SILC has almost same commands as IRC.
+Other
+than that they are nothing alike.  Biggest differences are that SILC is
+secure what IRC is not in any way.  The network model is also entirely
+different compared to IRC.
+<p>
+SILC is an open source (or freeware) project and it has been released
+under the GNU General Public Licence.  The SILC is free to use and
+everyone  
+is free to distribute and change the SILC under the terms of the GNU GPL.
+While there is no guarantee for the product SILC has been tried make
+as secure as possible.  Developers are needed and everyone is free to
+contribute their time, skills and ideas for the project.
+<p>
+Official SILC Project home page:
+<a href="http://silc.pspt.fi">http://silc.pspt.fi</a>
+<p>
+SILC Development Version is available for download from following
+addresses:
+<p>
+HTTP: <a href="http://silc.pspt.fi/silc-28062000.tar.gz">
+silc-28062000.tar.gz (1.1 MB)</a>
+<br>
+FTP: <a href="ftp://silc.pspt.fi/pub/silc/snapshots/silc-28062000.tar.gz">
+silc-28062000.tar.gz (1.1 MB)</a>
+<p>
+The SILC protocol specification is available from following addresses:
+<p>
+HTTP: <a href="http://silc.pspt.fi/docs.html">
+http://silc.pspt.fi/docs.html</a>
+<br>
+FTP: <a href="ftp://silc.pspt.fi/pub/silc/">
+ftp://silc.pspt.fi/pub/silc/</a>
+<p>
+Author's contact information:
+<p>
+Pekka Riikonen <a href="mailto:priikone@poseidon.pspt.fi">
+priikone@poseidon.pspt.fi</a>
+<br>
+Home page: <a href="http://poseidon.pspt.fi/~priikone/english/">
+http://poseidon.pspt.fi/~priikone/english/</a>
+<p>
+
+
+<p>
+
+</td>
+</tr>
+</table>
+</body>
+</html>
diff --git a/public_html/todo.html b/public_html/todo.html
new file mode 100644 (file)
index 0000000..97ba3e0
--- /dev/null
@@ -0,0 +1,380 @@
+<html>
+<style TYPE="text/css"><!-- A:link {text-decoration: none}A:visited{text-decoration:none}A:active{text-decoration:none}--></style>
+<body bgcolor="#ffffff">
+<p><br>
+<a href="index.html"><img src="silc2.jpg" border=0></a>
+<table width="70%" border="0" cellspacing="0" cellpadding="1"
+align=center>
+<tr>
+<td>
+<p>
+<font size=4>
+<h1>TODO</h1>
+<p>
+<pre>
+TODO
+====
+
+This is more or less complete list of tasks that has to be done before
+SILC 1.0 could ever be released.  It is clear that the list does not
+include all the bugs that exists.  At the end of list are tasks that 
+needs to be done but are probably post 1.0.
+
+Feel free to contribute if you have the ability and free time - all the
+help is really appreciated - and needed.
+
+                                                       - Pekka
+
+
+New features TODO
+=================
+
+ o Extended SIM (SILC Module) support.  Currently only SILC Cipher API
+   and SILC Hash API may be used as SIM's.  What I have in mind is to
+   have extended support for SIM's so that basically any SILC API could
+   be used as SIM's.  This would open tremendous possiblities but
+   opens also issues on security that needs to be dealt with.
+
+   Some sort of SIM compilation environment should be defined so that
+   the SIM's could use SILC specific symbols from the modules (which they
+   cannot do currently).  In the future modules could add new features
+   to SILC easily with this support.  I'm more thinking this from client's
+   perspective to add new features to client (such as IRC support as SIM)
+   but server should have the support as well.  Anyhow, this is an 
+   interesting feature...
+
+   This maybe post 1.0 task - dunno.
+
+ o SIM support for other platforms than just for Linux.  Apache has
+   example code (code that we could use directly pretty easily) for
+   other platforms.
+
+ o We should replace all short, int, long, unsigned short, unsigned int,
+   unsigned long with some pre-defined datatypes that really are what
+   we want on all platforms.  int16, uint16, int32, uint32 etc. are
+   what we could use or maybe SilcInt16, SilcUInt16 etc.  Also, boolean
+   datatype should be defined.
+
+ o More platform supports should be added.  The code is pretty much
+   generic but there are some parts that require porting (SIM).  Also, 
+   some support for different platforms is needed into configure.in.
+
+ o SILC requires currently GCC to work because we use GCC specific 
+   compilation options.  Generally any compiler that supports inline
+   functions and can build shared libraries (for SIMs) should work.  
+   These cases should be included into configure.in.
+
+
+TODO In SILC Client
+===================
+
+ o Implement all commands.  A lot of commands are still yet to be
+   implemented.  Most of them are trivial but some will require some
+   planning.  Go see the command.c for unimplemented commands.
+
+ o Non-blocking connection on the background must be stopped if some
+   other connection on same window has established.  Now it is possible
+   that some non-blocking connection timeouts on the background when
+   we already have a working connection to some other place; things
+   goes bad.
+
+ o Finish WHOIS, finish JOIN and other commands that are partly
+   implemented.
+
+ o Input line on UI is buggy.  Cursor movement etc bugs.  Too lazy to
+   fix it.
+
+ o Logic for handling multiple same nicknames for example in private
+   message sending.  I guess the logic is done in server side but is
+   missing from client.
+
+ o Private message key setting is missing and must be implemented.
+   Currently private messages are encrypted with session keys.  This
+   is required by the protocol.
+
+ o Channel private key setting is missing and must be implemented.
+   Currently there cannot be private keys for channels.  Normal channel
+   keys (generated by server) are used.  This is required by the protocol.
+
+ o Public and private key generation is now done everytime the program
+   is run.  Now, this is only for testing period as I've been lazy to
+   do it any better for now.  This must be fixed.
+
+ o I guess, public key authentication (when connecting to a server)
+   is not working currently.  It is just matter of loading the keys
+   from file and using them (see corresponding code in server, it should
+   support public key authentication already).
+
+ o Multiple windows support.  Basic support for multiple windows already
+   exists but a lot is still missing to get it working.  Also, some
+   of the existing stuff probably needs to be tweaked a bit before the
+   multiple windows support could be done.  And of course the actual
+   commands that control the windows needs to be written (/WINDDOW).
+
+ o Implement /KEYMAP (or similiar) command to remap control and function
+   keys.
+
+ o Implement /ALIAS command to make command aliases.
+
+ o Implement /set/if/do/while etc as in IRC2.  Maybe post 1.0 task.
+   Some scripting would be good.
+
+ o Connection Authentication request resolving is missing and must be
+   done.  This is required by the protocol.
+
+ o Key Exchange protocol's responder side is missing from client.  
+   Generally it is possible for the client to be responder so it should
+   be implemented (See corresponding code from server).  Error handling
+   in the KE protocol is also in pretty bad shape in client.
+
+ o Configuration file loading from global and from local dirs.  This
+   is currently missing and I guess the global is only used.  Old SILC
+   version (in 1997) had ~./silc directory that I guess should be done
+   now as well.  The code for handling those exists but not in current
+   source tree.
+
+ o Configuration file format - could be better.
+
+ o Write help files for commands.  Nice format for the help files should
+   be selected.  I'm open for ideas.
+
+ o All allocations and freeing needs to be checked for memory leaks.
+
+
+TODO In SILC Server
+===================
+
+ o Implement all commands on server side.  A lot of commands are still yet
+   to be implemented.  Most of them are trivial but some will require some
+   planning.  Go see the command.c for unimplemented commands.
+
+ o DNS/IP lookup blocks the server.  This must be fixed.  Check the
+   resolver stuff (resolver(3), resolver(5)).  Either we have to do the
+   own resolver stuff (through scheduler, if possible without writing
+   too much own stuff) or use threads.
+
+ o Lenght of the packet processing timeouts needs to be checked whether
+   they are too short or too long.  I haven't really tested whether they
+   are suitable.  They should be tested on high load which I haven't done
+   at all yet.
+
+ o INVITE command must set the channel's invite list if channel is 
+   invite-only channel.
+
+ o Public and private key generation is now done everytime the program
+   is run.  Now, this is only for testing period as I've been lazy to
+   do it any better for now.  This must be fixed.
+
+ o Server says that it is able to listen on multiple ports but currently
+   that is bogus.  It can, but internals are for single server.
+
+ o Command lagging must implemented.  Those commands (all currently) that
+   has the LAG flag set they must not be allowed to be executed more than
+   once, say, in 2 seconds.
+
+ o Command flag usage in general is not implemented yet.
+
+ o Client history must be implemented.  Protocol says that server must
+   keep history information about clients for some period of time.
+
+ o Channel flags and user modes on channels are not implemented yet as
+   /MODE command is not implemented yet in client and server.
+
+ o Protocol execution timeouts are hard coded, should be configurable.
+
+ o Channel message sending routines uses a lot of common code.  Should
+   create a common function for those instead of writing the same code
+   again everytime, as done now.
+
+ o serverutil.c I guess should be created for util-like functions that
+   now resides in server.c, which is getting too big.
+
+ o serverconfig.c and the function naming in it is inconsistent.  It is 
+   not silc_config_server* it should be silc_server_config*.  As should
+   all the SilcConfigServer* types be SilcServerConfig*.
+
+ o Implement DENY_CONNECTION section in serverconfig.c and in server.
+
+ o Implement REDIRECT_CLIENT section in serverconfig.c and in server.
+
+ o Configuration file format - could be better.
+
+ o IP address fields in configuration file should accept mask format
+   as well, IP/MASK, and not just plain IP.
+
+ o Connection classes should be actually implemented in serverconfig.c.
+   They can be defined but they are totally ignored currently.
+
+ o Acceptance of incoming connections (client and server connections)
+   should be checked before key exchange protocol.  Currently it is
+   checked at the authentication phase after KE, that is ok, but it should
+   be checked before starting KE, as well.
+
+ o Statistics are totally missing from the server.  It would be nice
+   to gather some statistics.
+
+ o All allocations and freeing needs to be checked for memory leaks.
+
+
+TODO In SILC Libraries
+======================
+
+ o Public key verification in SKE (SILC Key Exchange) protocol is missing,
+   thus currently we trust on all public keys.  This probably doesn't cause
+   bad problems but the mechanism of verifying it from local database
+   (from files) needs to be done (it can open man-in-the-middle-attacks).
+
+ o Implement PFS (Perfect Forward Secrecy) flag in SKE (and in client and
+   server, actually).  If PFS is set, re-key must cause new key exchange.
+   This is required by the SILC protocol.
+
+ o Re-key in general is actually missing (from everywhere) and must be done.
+
+ o SKE does not send correct status types.  Types are defined but not
+   sent.
+
+ o Connection authentication protocol does not send correct status types.
+   These types are not defined currently at all.
+
+ o PKCS#1 style RSA public key encryption/decryption/sign/verify is 
+   missing, and should be added for interoperability reasons.  The thing 
+   I've done now is bad and should be removed as soon as possible (or 
+   the protocol should then state the method of how they should be done).
+
+ o SILC public key file type is bad.  I'd like to see PEM encoded files.
+   I have public domain code for base64 encoding but it needs to be 
+   rewritten.
+
+ o Slow ciphers should be removed.  I think we don't need more than
+   the AES finalists plus blowfish and RC5.
+
+ o These slow ciphers actually don't work currently as I've tested
+   only the ones that are worth testing.  The CBC mode on these slow
+   ciphers probably don't work.  No need to worry, these ciphers should
+   be removed.
+
+ o Scheduler needs to be analyzed on high load as it might be unfair
+   towards select() because it may run timeout tasks before select() and
+   after select().  If it is found to be unfair the timeout task running
+   before select() should probably be removed.
+
+ o On select() issue; maybe we should use poll() instead if it is
+   available? poll() doesn't have max fd limit...
+
+ o SIM support for SILC PKCS API needs to made so that they could be
+   used as SIM's.  At the same time some work is required on prime
+   generation as the way it is done now sucks.  Read from code for
+   more (silcpkcs.h).
+
+ o Compression routines are missing.  The protocol supports packet
+   compression thus it must be implemented.  SILC Comp API must be
+   defined.  zlib package is already included into the lib dir (in CVS,
+   not in distribution), but it is not used yet, and it requires some
+   tweaking on the Makefiles (we want static lib not shared).
+
+ o Cipher API needs to be made more consistent.  Some parts of the
+   code generated with current Cipher API looks really bad.  Same
+   is with PKCS API, even worse actually.  They need to be made
+   cleaner.  Introducing silc_cipher_encrypt/decrypt/set_key etc.
+   functions (I actually don't understand why have I left these un-done).
+
+ o Scheduler should automatically allocate task queues if NULL pointers 
+   are passed to the silc_schedule_init.  Would make initialization 
+   cleaner.
+
+ o Packet processing routines in client and server are actually pretty
+   much generic and should be moved from the client/server to the library
+   as generic routines (silc_<client/server>_packet_decrypt_rest* etc).
+   This requires heavy changes to the client and server.
+
+ o Random Number Generator needs some tweaking.  Reading /dev/random may
+   block resulting slow initialization of RNG.  Some other things in the
+   RNG may block as well.  Also, I have some pending changes to the RNG 
+   that needs to be commited (from Schneier's Yarrow-160 paper).  They 
+   should make the RNG even better.
+
+ o Logging should be made more generic in a way that application can
+   set to where the logging is destined to.  Now, it is always destined
+   to stdout (or stderr) which is a bad thing for client.  Ie. some
+   sort of logging registration functions or similiar should be done
+   (silclog.[ch] in core).  The actual output of logs should be done
+   by callback function in the application not in lib.
+
+ o I don't like the ID cache system currenly implemented.  Ugly and
+   not so good.  Must be rewritten very soon.
+
+ o All allocations and freeing needs to be checked for memory leaks.
+
+ o silc_buffer_[un]format() needs to be made more stable as it may
+   crash the SILC if malformed data is sent as argument.  There are a
+   lot of places in client and server where we trust directly data coming
+   from network and try to unformat it.  The unformatting routine needs
+   to be able handle situations where data sent is malformed, by mistake
+   or intentionally.  This is important as it is easy to crash the SILC
+   now by just sending malformed data.  Also, in client and server we
+   must start checking the return value from silc_buffer_[un]format.
+
+
+Other Things TODO
+=================
+
+ o Write manuals for server.
+
+ o Write manuals for client.
+
+ o Write SILC Library Reference manual.  This would include all the SILC
+   API's with simple examples how the functions are to be used.  This is
+   pretty easy to create by taking all the functions plus their comments
+   from source/header files.  However, same sort of reference manual 
+   should be written for client and server as well.
+
+
+TODO After 1.0
+==============
+
+ o Pthreads support.  A lot of problems are solved with server (and with
+   client as well) if we add pthread support.  We can forget things such
+   as non-blocking connecting etc, and we can do things such as DNS/IP
+   lookups async.  The server itself also benefits great deal from 
+   threads, especially from performance point of view.
+
+   But, this is not a small task and almost entire SILC Library has to
+   be made re-entrant.  Own API is probably added for the threads support
+   to make changes in the future as painless as possible.  So the API 
+   would have things like silc_mutex_lock, silc_mutex_unlock and 
+   friends...
+
+ o X.509 certificate support.  SILC protocol supports certificates and
+   it would be great to have support for them.  This is a big task as
+   support has to be made for ASN.1 as well.  I've looked into OpenSSL 
+   package as it has X.509 certificate support (and ASN.1 as well).  
+   The code does not look very good to my eye but it has some potentials.
+   This should be looked at more closely.
+
+   Naturally own SILC Certificate API has to be defined regardles what
+   the actual X.509 library is (OpenSSL X.509 or something else).  Other
+   choice is to write own X.509 library but I'm not going to do it - 
+   I can help to migrate the OpenSSL X.509 into SILC and I can help if 
+   someone would like to write the X.509 library - but I'm not going 
+   to start writing one myself.  Anyhow, the OpenSSL X.509 lib should
+   be checked.
+
+ o SSH2 public keys support.  Maybe - not really needed but could be
+   nice as SSH is widely used all over the place.  SILC Protocol 
+   supports SSH2 public keys.
+
+ o IRC support for SILC client.  This would be nice to have on client
+   as it could be used to connect to SILC and IRC.  People wouldn't
+   have to have two different clients when same would work on both.
+   I'd like to see this done as SIM, after the extended SIM support
+   has been added to SILC.
+
+ o Cipher optimizations (asm, that this) at least for i386 would be nice.
+</pre>
+<p>
+
+</td>
+</tr>
+</table>
+</body>
+</html>