Created SILC Client Libary by moving stuff from silc/ directory.
authorPekka Riikonen <priikone@silcnet.org>
Wed, 13 Sep 2000 17:47:53 +0000 (17:47 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Wed, 13 Sep 2000 17:47:53 +0000 (17:47 +0000)
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.

170 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/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
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-pp-00.nroff
doc/draft-riikonen-silc-spec-00.nroff
doc/example_silc.conf
doc/example_silcd.conf
includes/Makefile.in [deleted file]
includes/clientincludes.h
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 61% similarity]
lib/silcclient/command.c [new file with mode: 0644]
lib/silcclient/command.h [moved from apps/silc/command.h with 95% similarity]
lib/silcclient/command_reply.c [moved from apps/silc/command_reply.c with 50% similarity]
lib/silcclient/command_reply.h [moved from apps/silc/command_reply.h with 96% similarity]
lib/silcclient/idlist.c [new file with mode: 0644]
lib/silcclient/idlist.h [moved from apps/silc/idlist.h with 82% similarity]
lib/silcclient/ops.h [new file with mode: 0644]
lib/silcclient/protocol.c [moved from apps/silc/protocol.c with 75% similarity]
lib/silcclient/protocol.h [moved from apps/silc/protocol.h with 72% similarity]
lib/silccore/Makefile.am
lib/silccore/id.c
lib/silccore/idcache.c
lib/silccore/idcache.h
lib/silccore/silcchannel.c
lib/silccore/silccommand.c
lib/silccore/silccommand.h
lib/silccore/silcpacket.c
lib/silccore/silcpacket.h
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/crypton.h
lib/silccrypt/dfc.h
lib/silccrypt/e2.h
lib/silccrypt/loki.h
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.h
lib/silccrypt/rsa.c
lib/silccrypt/safer.h
lib/silccrypt/serpent.h
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 [new file with mode: 0644]
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/silcutil/Makefile.am [new file with mode: 0644]
lib/silcutil/silcbuffer.c [moved from lib/silccore/silcbuffer.c with 94% similarity]
lib/silcutil/silcbuffer.h [moved from lib/silccore/silcbuffer.h with 100% 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 100% 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 80% 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 93% similarity]
lib/silcutil/silcnet.h [moved from lib/silccore/silcnet.h with 100% similarity]
lib/silcutil/silcschedule.c [moved from lib/silccore/silcschedule.c with 92% similarity]
lib/silcutil/silcschedule.h [moved from lib/silccore/silcschedule.h with 97% 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 61% similarity]
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..3cbade9
--- /dev/null
+++ b/CHANGES
@@ -0,0 +1,251 @@
+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..a6933329f2e3044f5a8760e6dd43bb2c04fbb612 100644 (file)
--- a/README
+++ b/README
@@ -17,13 +17,102 @@ 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.
+
+       /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 +144,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
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..464e8704a248929347140396de87683572ef48c1 100644 (file)
--- a/TODO
+++ b/TODO
@@ -11,10 +11,6 @@ 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
 =================
@@ -86,10 +82,6 @@ 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
@@ -117,20 +109,12 @@ TODO In SILC Client
    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
@@ -145,22 +129,17 @@ TODO In SILC Server
    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
@@ -171,10 +150,6 @@ TODO In SILC 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.
 
@@ -203,18 +178,11 @@ TODO In SILC Server
    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.
@@ -232,10 +200,6 @@ TODO In SILC Libraries
    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.
 
@@ -291,17 +255,8 @@ TODO In SILC Libraries
    (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
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..91cab5844579e0120f1abb837e6b664553508304 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
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..3a08a79
--- /dev/null
@@ -0,0 +1,411 @@
+/*
+
+  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);
+}
+
+/* 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, ...)
+{
+  SilcClientInternal app = (SilcClientInternal)client->application;
+  va_list vp;
+
+  if (!success)
+    return;
+
+  va_start(vp, command);
+
+  switch(command)
+    {
+
+    case SILC_COMMAND_JOIN:
+      app->screen->bottom_line->channel = va_arg(vp, char *);
+      silc_screen_print_bottom_line(app->screen, 0);
+      break;
+
+    case SILC_COMMAND_NICK:
+      app->screen->bottom_line->nickname = va_arg(vp, char *);
+      silc_screen_print_bottom_line(app->screen, 0);
+      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;
+}
+
+/* SILC client operations */
+SilcClientOperations ops = {
+  say:                  silc_say,
+  channel_message:      silc_channel_message,
+  private_message:      silc_private_message,
+  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,
+};
diff --git a/apps/silc/client_ops.h b/apps/silc/client_ops.h
new file mode 100644 (file)
index 0000000..70b6f0f
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+
+  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_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, ...);
+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);
+
+#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/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..3cbae77e3592e8dc777afd9e90572cb43590dd70 100644 (file)
 /*
  * $Id$
  * $Log$
+ * Revision 1.5  2000/07/19 09:19:05  priikone
+ *     Enhancements to AWAY command.
+ *
+ * Revision 1.4  2000/07/10 05:38:08  priikone
+ *     Fixed screen refresh.
+ *
+ * Revision 1.3  2000/07/07 06:52:10  priikone
+ *     Fixed screen refresh routine.
+ *
+ * Revision 1.2  2000/07/05 06:12:05  priikone
+ *     Global cosmetic 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.
  *
  *
  */
@@ -38,16 +50,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 +71,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 +114,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 +138,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 +226,9 @@ void silc_screen_print_bottom_line(SilcScreen screen, int win_index)
            SILC_SCREEN_MAX_CHANNEL_LEN : len);
   }
 
+  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 +248,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 +318,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 +422,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..a1fe8ce32522b326703790a9ef2b092412f8cb89 100644 (file)
@@ -26,6 +26,7 @@ typedef struct {
   char *nickname;
   char *connection;
   char *channel;
+  int away;
 } *SilcScreenBottomLine;
 
 typedef struct {
@@ -53,8 +54,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 +104,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..ce9f7ee028dd58d84490abbb52132efcb99cef88 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,97 @@ 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->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 +331,326 @@ 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:
+  case KEY_BEG:
+    /* Beginning, Home */
+    silc_screen_input_cursor_home(app->screen);
+    break;
+  case CTRL('e'):
+  case KEY_END:
+    /* End */
+    silc_screen_input_cursor_end(app->screen);
+    break;
+  case KEY_LL:
+    /* End */
+    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:
+  case KEY_UNDO:
+  case KEY_EXIT:
+  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..9310116e8636285a418ac202f6259224d8942769 100644 (file)
@@ -39,4 +39,4 @@ 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../lib/silcmath/gmp
index b9a0cc63b90f069216bf6bc42f1a58079f75f260..0c52c4e251509ce9dfe2eecbf2ec04c5711643d9 100644 (file)
 /*
  * $Id$
  * $Log$
+ * Revision 1.13  2000/08/21 14:21:21  priikone
+ *     Fixed channel joining and channel message sending inside a
+ *     SILC cell. Added silc_server_send_remove_channel_user and
+ *     silc_server_remove_channel_user functions.
+ *
+ * Revision 1.12  2000/07/26 07:05:11  priikone
+ *     Fixed the server to server (server to router actually) connections
+ *     and made the private message work inside a cell. Added functin
+ *     silc_server_replace_id.
+ *
+ * Revision 1.11  2000/07/19 07:08:09  priikone
+ *     Added version detection support to SKE.
+ *
+ * Revision 1.10  2000/07/17 11:47:30  priikone
+ *     Added command lagging support. Added idle counting support.
+ *
+ * Revision 1.9  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.8  2000/07/10 05:42:59  priikone
+ *     Removed command packet processing from server.c and added it to
+ *     command.c.
+ *     Implemented INFO command. Added support for testing that
+ *     connections are registered before executing commands.
+ *
+ * Revision 1.7  2000/07/07 06:55:24  priikone
+ *     Do not allow client to join twice on same channel.
+ *
+ * Revision 1.6  2000/07/06 10:20:59  priikone
+ *     Cipher name in joining is not mandatory, removed check.
+ *
+ * Revision 1.5  2000/07/06 07:16:43  priikone
+ *     Fixed a wrong way of sending command replies. The fixed way
+ *     does comply with the protocol.
+ *
+ * Revision 1.4  2000/07/05 06:13:38  priikone
+ *     Added PING, INVITE and NAMES command.
+ *
+ * Revision 1.3  2000/07/03 05:52:22  priikone
+ *     Implemented LEAVE command.
+ *
+ * Revision 1.2  2000/06/28 05:06:38  priikone
+ *     Shorter timeout for channel joining notify.
+ *
  * 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"
 
+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[] =
 {
@@ -67,6 +131,108 @@ 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;
+
+  /* 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;
+  }
+  
+  /* 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(packet->buffer);
+  if (!ctx->payload) {
+    SILC_LOG_ERROR(("Bad command payload, packet dropped"));
+    silc_buffer_free(packet->buffer);
+    silc_free(ctx);
+    return;
+  }
+  
+  /* 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 +298,48 @@ static void silc_server_command_free(SilcServerCommandContext cmd)
   }
 }
 
-/* Sends command status message as command reply packet. */
+#define SILC_COMMAND_STATUS_DATA(x) \
+  (
+
+/* 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_encode_reply_payload_va(command, status, 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_encode_reply_payload_va(command, status, 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,10 +348,11 @@ silc_server_command_send_status_reply(SilcServerCommandContext cmd,
 SILC_SERVER_CMD_FUNC(whois)
 {
   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;
+  SilcClientEntry entry;
+  SilcBuffer packet;
   unsigned char *id_string;
 
   SILC_LOG_DEBUG(("Start"));
@@ -209,8 +376,8 @@ SILC_SERVER_CMD_FUNC(whois)
       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);
+      server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
+      memcpy(server_name, tmp + len + 1, strlen(tmp) - len - 1);
     } else {
       nick = strdup(tmp);
     }
@@ -228,42 +395,42 @@ SILC_SERVER_CMD_FUNC(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);
+  entry = silc_idlist_find_client_by_nickname(server->local_list, 
+                                             nick, server_name);
   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) {
+    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;
   }
 
@@ -272,12 +439,12 @@ SILC_SERVER_CMD_FUNC(whois)
 
   /* 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);
+  tmp = silc_command_get_first_arg(cmd->payload, NULL);
 
   /* XXX */
   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
     char nh[256], uh[256];
+    unsigned char idle[4];
     SilcSocketConnection hsock;
 
     memset(uh, 0, sizeof(uh));
@@ -286,9 +453,9 @@ SILC_SERVER_CMD_FUNC(whois)
     strncat(nh, entry->nickname, strlen(entry->nickname));
     strncat(nh, "@", 1);
     len = entry->router ? strlen(entry->router->server_name) :
-      strlen(cmd->server->server_name);
+      strlen(server->server_name);
     strncat(nh, entry->router ? entry->router->server_name :
-           cmd->server->server_name, len);
+           server->server_name, len);
 
     strncat(uh, entry->username, strlen(entry->username));
     strncat(uh, "@", 1);
@@ -296,39 +463,43 @@ SILC_SERVER_CMD_FUNC(whois)
     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_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));
+        silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS,
+                                            SILC_STATUS_OK, 5, 
+                                            2, id_string, SILC_ID_CLIENT_LEN,
+                                            3, nh, strlen(nh),
+                                            4, uh, strlen(uh),
+                                            5, entry->userinfo, 
+                                            strlen(entry->userinfo),
+                                            7, idle, 4);
     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));
+        silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS,
+                                            SILC_STATUS_OK, 4, 
+                                            2, id_string, SILC_ID_CLIENT_LEN,
+                                            3, nh, strlen(nh),
+                                            4, uh, strlen(uh),
+                                            7, idle, 4);
 
   } 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 */
+      silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS, 
+                                          SILC_STATUS_OK, 3, 
+                                          2, id_string, SILC_ID_CLIENT_LEN,
+                                          3, entry->nickname, 
+                                          strlen(entry->nickname),
+                                          4, tmp, strlen(tmp)); /* XXX */
   }
-  silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
+  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);
 
  out:
   silc_server_command_free(cmd);
@@ -341,10 +512,11 @@ 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;
+  SilcClientEntry entry;
+  SilcBuffer packet;
   unsigned char *id_string;
 
   SILC_LOG_DEBUG(("Start"));
@@ -368,8 +540,8 @@ SILC_SERVER_CMD_FUNC(identify)
       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);
+      server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
+      memcpy(server_name, tmp + len + 1, strlen(tmp) - len - 1);
     } else {
       nick = strdup(tmp);
     }
@@ -390,75 +562,73 @@ 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;
-
-      /* 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;
-    }
+  /* Find client */
+  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);
+
+  /* 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;
+  }
+
+  /* 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);
 
-    silc_server_command_send_status_msg(cmd, SILC_COMMAND_IDENTIFY,
-                                       SILC_STATUS_ERR_NO_SUCH_NICK,
-                                       tmp, strlen(tmp));
+  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));
+  packet = silc_command_encode_reply_payload_va(SILC_COMMAND_IDENTIFY,
+                                               SILC_STATUS_OK, 2,
+                                               2, id_string, 
+                                               SILC_ID_CLIENT_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);
 
  out:
   if (nick)
     silc_free(nick);
-  if (server)
-    silc_free(server);
+  if (server_name)
+    silc_free(server_name);
   silc_server_command_free(cmd);
 }
 
@@ -485,18 +655,15 @@ 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 id_entry = (SilcClientEntry)cmd->sock->user_data;
   SilcServer server = cmd->server;
-  SilcBuffer packet, sp_buf;
+  SilcBuffer packet;
   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) {
     silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
@@ -534,9 +701,8 @@ SILC_SERVER_CMD_FUNC(nick)
                                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, 
+                        id_entry->id); 
   
   /* Free old ID */
   if (id_entry->id) {
@@ -552,27 +718,23 @@ SILC_SERVER_CMD_FUNC(nick)
   id_entry->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, id_entry->nickname, 
+                  SILC_ID_CLIENT, id_entry->id, (void *)id_entry, TRUE);
 
   /* 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_encode_reply_payload_va(SILC_COMMAND_NICK, 
+                                               SILC_STATUS_OK, 1
+                                               2, id_string, 
+                                               SILC_ID_CLIENT_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);
 
  out:
   silc_server_command_free(cmd);
-#undef LCC
-#undef LCCC
 }
 
 SILC_SERVER_CMD_FUNC(list)
@@ -583,8 +745,100 @@ SILC_SERVER_CMD_FUNC(topic)
 {
 }
 
+/* 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;
+  unsigned int argc, len;
+  unsigned char *id_string;
+
+  /* Check number of arguments */
+  argc = silc_command_get_arg_num(cmd->payload);
+  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 */
+  id_string = silc_command_get_arg_type(cmd->payload, 1, &len);
+  if (!id_string) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+                                         SILC_STATUS_ERR_NO_CLIENT_ID);
+    goto out;
+  }
+  dest_id = silc_id_str2id(id_string, SILC_ID_CLIENT);
+
+  /* Get Channel ID */
+  id_string = silc_command_get_arg_type(cmd->payload, 2, &len);
+  if (!id_string) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+                                         SILC_STATUS_ERR_NO_CHANNEL_ID);
+    goto out;
+  }
+  channel_id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
+
+  /* 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. */
+  /* XXX */
+
+  /* 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;
+  }
+
+  /* Send notify to the client that is invited to the channel */
+  silc_server_send_notify_dest(server, dest_sock, dest_id, SILC_ID_CLIENT,
+                              "%s invites you to channel %s",
+                              sender->nickname, channel->channel_name);
+
+  /* Send command reply */
+  silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+                                       SILC_STATUS_OK);
+
+ out:
+  silc_server_command_free(cmd);
 }
 
 /* Quits connection to client. This gets called if client won't
@@ -625,16 +879,127 @@ 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;
+  unsigned int argc;
+  unsigned char *id_string;
+  char info_string[256], *dest_server;
+
+  argc = silc_command_get_arg_num(cmd->payload);
+  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_command_get_arg_type(cmd->payload, 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);
+
+    id_string = silc_id_id2str(server->id, SILC_ID_SERVER);
+
+    packet = 
+      silc_command_encode_reply_payload_va(SILC_COMMAND_INFO,
+                                          SILC_STATUS_OK, 2,
+                                          2, id_string, SILC_ID_SERVER_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_free(id_string);
+    silc_buffer_free(packet);
+  } 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)
 {
 }
 
+/* Server side of command PING. This just replies to the ping. */
+
 SILC_SERVER_CMD_FUNC(ping)
 {
+  SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+  SilcServer server = cmd->server;
+  SilcServerID *id;
+  unsigned int argc;
+  unsigned char *id_string;
+
+  argc = silc_command_get_arg_num(cmd->payload);
+  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 */
+  id_string = silc_command_get_arg_type(cmd->payload, 1, NULL);
+  if (!id_string) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
+                                         SILC_STATUS_ERR_NO_SERVER_ID);
+    goto out;
+  }
+  id = silc_id_str2id(id_string, SILC_ID_SERVER);
+
+  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)
@@ -646,7 +1011,7 @@ typedef struct {
   char *nickname;
   char *username;
   char *hostname;
-  SilcChannelList *channel;
+  SilcChannelEntry channel;
   SilcServer server;
 } JoinInternalContext;
 
@@ -667,6 +1032,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;
+  unsigned char *id_string;
+
+  id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+  buffer = silc_command_encode_payload_va(SILC_COMMAND_NAMES, 1,
+                                         1, id_string, SILC_ID_CHANNEL_LEN);
+
+  cmd = silc_calloc(1, sizeof(*cmd));
+  cmd->payload = silc_command_parse_payload(buffer);
+  cmd->server = server;
+  cmd->sock = sock;
+  cmd->pending = FALSE;
+
+  silc_server_command_names((void *)cmd);
+  silc_free(id_string);
+  silc_free(buffer);
+}
+
 /* Server side of command JOIN. Joins client into requested channel. If 
    the channel does not exist it will be created. */
 
@@ -678,18 +1070,14 @@ SILC_SERVER_CMD_FUNC(join)
   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;
+  unsigned char *passphrase, mode[4];
+  SilcChannelEntry channel;
   SilcServerID *router_id;
-  SilcIDCache *id_cache;
-  SilcBuffer packet, sp_buf;
-  SilcClientList *client;
+  SilcBuffer packet;
+  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);
   if (argc < 1) {
@@ -704,13 +1092,15 @@ SILC_SERVER_CMD_FUNC(join)
   }
 
   /* Get channel name */
-  tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
+  tmp = silc_command_get_arg_type(cmd->payload, 1, &tmp_len);
+  channel_name = silc_calloc(tmp_len + 1, sizeof(*channel_name));
+  memcpy(channel_name, tmp, tmp_len);
   if (silc_server_command_bad_chars(tmp) == 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);
@@ -723,10 +1113,10 @@ SILC_SERVER_CMD_FUNC(join)
   cipher = silc_command_get_arg_type(cmd->payload, 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. */
@@ -734,6 +1124,9 @@ SILC_SERVER_CMD_FUNC(join)
       router_id = server->id;
       channel = silc_server_new_channel(server, router_id, 
                                        cipher, channel_name);
+      if (!channel)
+       goto out;
+
       goto join_channel;
     }
 
@@ -743,12 +1136,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 +1153,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,32 +1166,40 @@ SILC_SERVER_CMD_FUNC(join)
 
   }
 
-  channel = (SilcChannelList *)id_cache->context;
-
  join_channel:
 
-  /* XXX must check whether the client already is on the channel */
-
-  /* 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;
-
   /* 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);
   }
+
+  /* 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);
+    silc_free(channel_name);
+    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;
+  channel->user_list[i].client = client;
   channel->user_list_count++;
 
+  /* Add the channel to client's channel list */
   i = client->channel_count;
   client->channel = silc_realloc(client->channel, 
                                 sizeof(*client->channel) * (i + 1));
@@ -813,24 +1213,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);
+    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_encode_reply_payload_va(SILC_COMMAND_JOIN,
+                                            SILC_STATUS_OK, 3,
+                                            2, channel_name, 
+                                            strlen(channel_name),
+                                            3, id_string, SILC_ID_CHANNEL_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_encode_reply_payload_va(SILC_COMMAND_JOIN,
+                                            SILC_STATUS_OK, 4, 
+                                            2, channel_name, 
+                                            strlen(channel_name),
+                                            3, id_string, SILC_ID_CHANNEL_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);
@@ -844,7 +1250,6 @@ SILC_SERVER_CMD_FUNC(join)
                              packet->data, packet->len, FALSE);
     
     silc_buffer_free(packet);
-    silc_free(sp_buf);
   }
 
   /* Send channel key to the client. Client cannot start transmitting
@@ -855,7 +1260,7 @@ SILC_SERVER_CMD_FUNC(join)
       silc_channel_key_encode_payload(SILC_ID_CHANNEL_LEN, 
                                      id_string, tmp_len, 
                                      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);
@@ -886,14 +1291,16 @@ SILC_SERVER_CMD_FUNC(join)
       ctx->server = server;
       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
@@ -934,10 +1341,240 @@ 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;
+  unsigned char *tmp, channel_key[32];
+
+  SILC_LOG_DEBUG(("Start"));
+
+  argc = silc_command_get_arg_num(cmd->payload);
+  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_command_get_arg_type(cmd->payload, 1, NULL);
+  if (!tmp) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
+                                         SILC_STATUS_ERR_NO_CHANNEL_ID);
+    goto out;
+  }
+  id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
+
+  /* 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_encode_payload(SILC_ID_CHANNEL_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;
+  SilcChannelID *id;
+  SilcBuffer packet;
+  unsigned int i, len, len2, argc;
+  unsigned char *tmp;
+  char *name_list = NULL, *n;
+  SilcBuffer client_id_list;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  argc = silc_command_get_arg_num(cmd->payload);
+  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_command_get_arg_type(cmd->payload, 1, NULL);
+  if (!tmp) {
+    silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
+                                         SILC_STATUS_ERR_NO_CHANNEL_ID);
+    goto out;
+  }
+  id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
+
+  /* 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;
+  for (i = 0; i < channel->user_list_count; i++) {
+    if (!channel->user_list[i].client)
+      continue;
+
+    n = channel->user_list[i].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 == channel->user_list_count - 1)
+       break;
+      memcpy(name_list + len, ",", 1);
+      len++;
+    }
+  }
+  if (!name_list)
+    name_list = "";
+
+  /* Assemble the Client ID list now */
+  client_id_list = silc_buffer_alloc(SILC_ID_CLIENT_LEN * 
+                                    channel->user_list_count);
+  silc_buffer_pull_tail(client_id_list, (SILC_ID_CLIENT_LEN *
+                                        channel->user_list_count));
+  for (i = 0; i < channel->user_list_count; i++) {
+    unsigned char *id_string;
+
+    if (!channel->user_list[i].client)
+      continue;
+
+    id_string = silc_id_id2str(channel->user_list[i].client->id,
+                              SILC_ID_CLIENT);
+    silc_buffer_format(client_id_list,
+                      SILC_STR_UI_XNSTRING(id_string, SILC_ID_CLIENT_LEN),
+                      SILC_STR_END);
+    silc_buffer_pull(client_id_list, SILC_ID_CLIENT_LEN);
+    silc_free(id_string);
+  }
+  silc_buffer_push(client_id_list, 
+                  client_id_list->data - client_id_list->head);
+
+  /* Send reply */
+  packet = silc_command_encode_reply_payload_va(SILC_COMMAND_NAMES,
+                                               SILC_STATUS_OK, 3,
+                                               2, tmp, SILC_ID_CHANNEL_LEN,
+                                               3, name_list, 
+                                               strlen(name_list),
+                                               4, client_id_list->data,
+                                               client_id_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_free(id);
+
+ out:
+  silc_server_command_free(cmd);
 }
index d7ed494402f85815512825d49220991aab85bb6e..d5c96e9b28c7df3c211a62765547108333a0e605 100644 (file)
@@ -82,24 +82,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 +110,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);
index 815a858509f92ab281d2b9c21b5bcccc25938d62..08cee1c7baee3b23ce95479d325a082defd80c3f 100644 (file)
 /*
  * $Id$
  * $Log$
+ * Revision 1.5  2000/07/26 07:05:11  priikone
+ *     Fixed the server to server (server to router actually) connections
+ *     and made the private message work inside a cell. Added functin
+ *     silc_server_replace_id.
+ *
+ * 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/03 05:52:22  priikone
+ *     Implemented LEAVE command.
+ *
  * 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 "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 },
 };
@@ -91,14 +108,10 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
   SilcServer server = cmd->server;
   SilcCommandStatus status;
   SilcChannelID *id;
-  SilcChannelList *entry;
-  unsigned int argc;
+  SilcChannelEntry entry;
   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);
@@ -120,13 +133,12 @@ SILC_SERVER_CMD_REPLY_FUNC(join)
 
   /* 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);
+  entry = silc_idlist_add_channel(server->local_list, channel_name, 
+                                 SILC_CHANNEL_MODE_NONE, id, 
+                                 server->id_entry->router, NULL);
+  if (!entry)
+    goto out;
+
   entry->global_users = TRUE;
 
   /* Execute pending JOIN command so that the client who originally
@@ -135,6 +147,62 @@ 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;
+  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)
+    goto out;
+
+  /* Process one identify reply */
+  if (status == SILC_STATUS_OK) {
+    SilcClientID *client_id;
+    unsigned char *id_data;
+    char *nickname, *username;
+
+    id_data = silc_command_get_arg_type(cmd->payload, 2, NULL);
+    nickname = silc_command_get_arg_type(cmd->payload, 3, NULL);
+    if (!id_data || !nickname)
+      goto out;
+
+    username = silc_command_get_arg_type(cmd->payload, 4, NULL);
+
+    client_id = silc_id_str2id(id_data, SILC_ID_CLIENT);
+
+    /* 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..28d95c5b7c4fa026e3c36a0c4f9a40eef03e0205 100644 (file)
@@ -73,5 +73,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..97ee88544126bf3897a45cca39874ae45a0b6880 100644 (file)
 /*
  * $Id$
  * $Log$
+ * Revision 1.7  2000/07/26 07:04:01  priikone
+ *     Added server_find_by_id, replace_[server/client]_id.
+ *
+ * Revision 1.6  2000/07/17 11:47:30  priikone
+ *     Added command lagging support. Added idle counting support.
+ *
+ * Revision 1.5  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.4  2000/07/06 07:16:13  priikone
+ *     Added SilcPublicKey's
+ *
+ * Revision 1.3  2000/07/05 06:14:01  priikone
+ *     Global costemic changes.
+ *
+ * Revision 1.2  2000/07/03 05:52:11  priikone
+ *     Fixed typo and a bug.
+ *
  * 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 "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 */
 
-  if (new_idlist)
-    *new_idlist = idlist;
+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;
+
+  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;
 
-  /* Add it to the list */
-  last = (*list)->prev;
-  last->next = idlist;
-  (*list)->prev = idlist;
-  idlist->next = *list;
-  idlist->prev = last;
+  server = (SilcServerEntry)id_cache->context;
+  silc_free(server->id);
+  server->id = new_id;
+  id_cache->id = (void *)new_id;
 
-  if (new_idlist)
-    *new_idlist = idlist;
+  return server;
 }
 
-/* Free client entry.  This free's everything. */
+/******************************************************************************
 
-void silc_idlist_del_client(SilcClientList **list, SilcClientList *entry)
+                          Client entry functions
+
+******************************************************************************/
+
+/* 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. */
+
+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 and removes the entry
+   from ID cache. */
+
+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 +210,191 @@ 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;
-    }
-
-    /* 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;
-    }
-
-    /* Remove from list */
-    entry->prev->next = entry->next;
-    entry->next->prev = entry->prev;
-    silc_free(entry);
-    return;
   }
 }
 
-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;
+
+      if (!strcmp(server, XXX, strlen(server)))
+       break;
 
-  while(entry != first) {
-    if (!strcmp(entry->nickname, nickname)) {
-      SILC_LOG_DEBUG(("Found"));
-      return entry;
+      client = NULL;
     }
+#endif
 
-    entry = entry->next;
+   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;
+
+    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;
+
+    id_cache = NULL;
+    client = NULL;
 
-    entry = entry->next;
+    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;
+
+  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) {
+    /* 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 +404,61 @@ 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));
 
     if (entry->user_list_count)
       silc_free(entry->user_list);
+  }
+}
 
-    /* Last one in list? */
-    if (*list == entry && entry->next == entry) {
-      *list = NULL;
-      silc_free(entry);
-      return;
-    }
+/* Finds channel by channel name. Channel names are unique and they
+   are not case-sensitive. */
 
-    /* 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;
-    }
+SilcChannelEntry
+silc_idlist_find_channel_by_name(SilcIDList id_list, char *name)
+{
+  SilcIDCacheList list = NULL;
+  SilcIDCacheEntry id_cache = NULL;
+  SilcChannelEntry channel;
 
-    /* Remove from list */
-    entry->prev->next = entry->next;
-    entry->next->prev = entry->prev;
-    silc_free(entry);
-    return;
+  SILC_LOG_DEBUG(("Finding channel by name"));
+
+  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..e1f39ec1b7878f7351f9153a749969fea2732552 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,43 +215,46 @@ 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;
+  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.
 
@@ -238,19 +263,19 @@ struct SilcClientListStruct {
        Client's current mode on the channel.
 
 */
-typedef struct SilcChannelClientListStruct {
-  SilcClientList *client;
+typedef struct SilcChannelClientEntryStruct {
+  SilcClientEntry client;
   int mode;
-} SilcChannelClientList;
+} *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
    =======================================================================
@@ -288,19 +313,28 @@ typedef struct SilcChannelClientListStruct {
 
        Current topic of the channel.
 
-   SilcServerList *router
+   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;
   SilcChannelID *id;
@@ -308,20 +342,17 @@ struct SilcChannelListStruct {
   char *topic;
 
   /* List of users on channel */
-  SilcChannelClientList *user_list;
+  SilcChannelClientEntry user_list;
   unsigned int user_list_count;
 
   /* 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 +360,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 +383,84 @@ 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_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..fe6139302b87d832c230b68eead6880de19a6c9a 100644 (file)
 /*
  * $Id$
  * $Log$
+ * Revision 1.9  2000/07/20 10:17:25  priikone
+ *     Added dynamic protocol registering/unregistering support.  The
+ *     patch was provided by cras.
+ *
+ * Revision 1.8  2000/07/19 07:08:09  priikone
+ *     Added version detection support to SKE.
+ *
+ * Revision 1.7  2000/07/14 06:14:20  priikone
+ *     Put the HMAC keys into the HMAC object instead of having them
+ *     saved elsewhere; now we can use silc_hmac_make insteaad of
+ *     silc_hmac_make_with_key.
+ *
+ * Revision 1.6  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.5  2000/07/10 05:42:14  priikone
+ *     Support for public key encoding functions added.
+ *
+ * Revision 1.4  2000/07/07 06:55:59  priikone
+ *     Added SILC style public key support and made server to use
+ *     it at all time.
+ *
+ * Revision 1.3  2000/07/06 07:15:31  priikone
+ *     Cleaner code fro password and public key authentication.
+ *     Deprecated old `channel_auth' protocol.
+ *
+ * Revision 1.2  2000/07/05 06:13:04  priikone
+ *     Support for SILC style public keys added.
+ *
  * 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 "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 +101,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 +139,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,10 +147,7 @@ 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;
 }
@@ -169,12 +187,14 @@ SILC_TASK_CALLBACK(silc_server_protocol_key_exchange)
        /* 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_version_string,
+                                             &start_payload);
 
        /* Start the key exchange by sending our security properties
           to the remote end. */
@@ -258,6 +278,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 +306,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) {
@@ -397,6 +404,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 +499,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 +576,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 +598,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 +655,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 +677,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 +734,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 +756,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"));
@@ -897,6 +918,22 @@ SILC_TASK_CALLBACK(silc_server_protocol_connection_auth)
   }
 }
 
-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..e652099db0e49938bd042146594b8e630d364fe6 100644 (file)
 /*
  * $Id$
  * $Log$
+ * Revision 1.13  2000/08/21 14:21:21  priikone
+ *     Fixed channel joining and channel message sending inside a
+ *     SILC cell. Added silc_server_send_remove_channel_user and
+ *     silc_server_remove_channel_user functions.
+ *
+ * Revision 1.12  2000/07/26 07:05:11  priikone
+ *     Fixed the server to server (server to router actually) connections
+ *     and made the private message work inside a cell. Added functin
+ *     silc_server_replace_id.
+ *
+ * Revision 1.11  2000/07/20 10:17:25  priikone
+ *     Added dynamic protocol registering/unregistering support.  The
+ *     patch was provided by cras.
+ *
+ * Revision 1.10  2000/07/17 11:47:30  priikone
+ *     Added command lagging support. Added idle counting support.
+ *
+ * Revision 1.9  2000/07/14 06:15:47  priikone
+ *     Moved all the generic packet sending, encryption, reception,
+ *     decryption and processing functions to library as they were
+ *     duplicated code. Now server uses the generic routine which is
+ *     a lot cleaner. Channel message sending uses now also generic
+ *     routines instead of duplicating the packet sending for every
+ *     channel message sending function. Same was done for private
+ *     message sending as well.
+ *
+ * Revision 1.8  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.7  2000/07/10 05:43:00  priikone
+ *     Removed command packet processing from server.c and added it to
+ *     command.c.
+ *     Implemented INFO command. Added support for testing that
+ *     connections are registered before executing commands.
+ *
+ * Revision 1.6  2000/07/07 06:55:59  priikone
+ *     Added SILC style public key support and made server to use
+ *     it at all time.
+ *
+ * Revision 1.5  2000/07/06 13:18:07  priikone
+ *     Check for NULL in client_on_channel.
+ *
+ * Revision 1.4  2000/07/05 06:14:01  priikone
+ *     Global costemic changes.
+ *
+ * Revision 1.3  2000/07/04 08:13:53  priikone
+ *     Changed message route discovery to use silc_server_get_route.
+ *     Added silc_server_client_on_channel function.
+ *
  * 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.
  *
  *
  */
@@ -42,24 +94,9 @@ 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[];
 
 /* Allocates a new SILC server object. This has to be done before the server
@@ -69,27 +106,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 +148,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 +182,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 +247,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 +289,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,6 +332,9 @@ 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, 
@@ -326,6 +387,8 @@ void silc_server_stop(SilcServer server)
   silc_schedule_stop();
   silc_schedule_uninit();
 
+  silc_server_protocols_unregister();
+
   SILC_LOG_DEBUG(("Server stopped"));
 }
 
@@ -398,13 +461,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 +533,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 +682,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 +744,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 +821,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 +841,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 +887,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 +954,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 +965,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 +1059,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 +1103,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 +1117,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 +1139,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 +1172,126 @@ 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);
+
+       cipher = srvr->receive_key;
+       hmac = srvr->hmac;
+       break;
       }
+    case SILC_SOCKET_TYPE_UNKNOWN:
+      {
+       SilcUnknownEntry conn_data = (SilcUnknownEntry)sock->user_data;
+       if (!conn_data)
+         break;
 
+       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. */
+    if (!silc_packet_receive_process(sock, cipher, hmac,
+                                    silc_server_packet_parse, server)) {
       silc_buffer_clear(sock->inbuf);
-
-      /* 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);
       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. */
+/* 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);
+  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
@@ -1628,38 +1359,12 @@ 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);
-    }
-    break;
+    /*
+     * 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 +1519,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 +1584,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 +1630,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 +1639,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 +1680,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 +1698,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 +1728,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 +1735,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 +1753,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 +1763,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 +1774,54 @@ 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. */
+
+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 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);
+  silc_packet_encrypt(cipher, hmac, sock->outbuf, SILC_PACKET_HEADER_LEN + 
+                     packet->src_id_len + packet->dst_id_len +
+                     packet->padlen);
+    
+  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,
                                        unsigned char *data,
                                        unsigned int data_len,
                                        int force_send)
@@ -2185,13 +1829,9 @@ 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;
   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;
@@ -2205,8 +1845,10 @@ void silc_server_packet_send_to_channel(SilcServer server,
   /* Encode the channel payload */
   payload = silc_channel_encode_payload(0, "", data_len, data, 
                                        16, channel->iv, server->rng);
-  if (!payload)
+  if (!payload) {
+    SILC_LOG_ERROR(("Could not encode channel payload, message not sent"));
     return;
+  }
   
   /* Encrypt payload of the packet. This is encrypted with the 
      channel key. */
@@ -2233,58 +1875,19 @@ void silc_server_packet_send_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;
 
     /* 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, payload->data,
+                                           payload->len, force_send);
   }
 
   /* Send the message to clients on the channel's client list. */
@@ -2305,49 +1908,11 @@ void silc_server_packet_send_to_channel(SilcServer server,
       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, payload->data,
+                                             payload->len, 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 +1933,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, payload->data,
+                                             payload->len, force_send);
     }
   }
 
@@ -2432,7 +1959,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,13 +1969,9 @@ 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;
   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;
 
@@ -2474,7 +1997,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,51 +2008,12 @@ 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, force_send);
     }
   }
 
@@ -2546,8 +2030,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;
 
@@ -2567,49 +2050,11 @@ void silc_server_packet_relay_to_channel(SilcServer server,
        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, 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 +2065,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, force_send);
     }
   }
 
@@ -2681,6 +2087,41 @@ 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. */
+
+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;
+  SilcSocketConnection sock = NULL;
+
+  SILC_LOG_DEBUG(("Start"));
+
+  /* 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;
+
+    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 +2133,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 +2154,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 +2232,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 +2240,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 +2262,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 +2291,10 @@ 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;
-
-#define LCC(x) server->local_list->channel_cache[(x) - 32]
-#define LCCC(x) server->local_list->channel_cache_count[(x) - 32]
+  SilcChannelEntry channel;
 
   /* Remove the client from all channels. The client is removed from
      the channels' user list. */
@@ -2902,23 +2310,32 @@ void silc_server_remove_from_channels(SilcServer server,
        /* 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);
+
+         /* 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,
+                                              "Signoff: %s@%s",
+                                              client->nickname,
+                                              sock->hostname ?
+                                              sock->hostname : sock->ip);
+
+         silc_idlist_del_channel(server->local_list, channel);
          break;
        }
 
        channel->user_list[k].client = NULL;
        channel->user_list[k].mode = SILC_CHANNEL_UMODE_NONE;
 
-       /* 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",
+                                          "Signoff: %s@%s",
                                           client->nickname,
-                                          channel->channel_name);
+                                          sock->hostname ?
+                                          sock->hostname : sock->ip);
       }
     }
   }
@@ -2926,8 +2343,91 @@ void silc_server_remove_from_channels(SilcServer server,
   if (client->channel_count)
     silc_free(client->channel);
   client->channel = NULL;
-#undef LCC
-#undef LCCC
+}
+
+/* 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;
+
+  /* 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;
+
+    /* XXX */
+    client->channel[i] = NULL;
+
+    /* Remove from channel */
+    for (k = 0; k < channel->user_list_count; k++) {
+      if (channel->user_list[k].client == client) {
+       
+       /* If this client is last one on the channel the channel
+          is removed all together. */
+       if (channel->user_list_count == 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,
+                                              "%s@%s has left channel %s",
+                                              client->nickname, 
+                                              sock->hostname ?
+                                              sock->hostname : sock->ip,
+                                              channel->channel_name);
+
+         silc_idlist_del_channel(server->local_list, channel);
+         return FALSE;
+       }
+       
+       channel->user_list[k].client = NULL;
+       channel->user_list[k].mode = SILC_CHANNEL_UMODE_NONE;
+
+       /* Send notify to channel about client leaving the channel */
+       if (notify)
+         silc_server_send_notify_to_channel(server, channel,
+                                            "%s@%s has left channel %s",
+                                            client->nickname, sock->hostname ?
+                                            sock->hostname : sock->ip,
+                                            channel->channel_name);
+      }
+    }
+  }
+
+  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'. */
+/* XXX This really is utility function and should be in eg. serverutil.c */
+
+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 +2445,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 +2493,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 +2521,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 +2545,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);
+    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 +2578,21 @@ 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;
+  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 +2601,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) {
+    for (i = 0; i < channel->user_list_count; i++) {
+      client = channel->user_list[i].client;
+      if (client && !SILC_ID_CLIENT_COMPARE(client->id, sender))
+       break;
+    }
+    if (i >= channel->user_list_count)
+      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,16 +2652,13 @@ void silc_server_channel_key(SilcServer server,
   SilcBuffer buffer = packet->buffer;
   SilcChannelKeyPayload payload = NULL;
   SilcChannelID *id = NULL;
-  SilcChannelList *channel;
-  SilcClientList *client;
+  SilcChannelEntry channel;
+  SilcClientEntry client;
   unsigned char *key;
   unsigned int key_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;
@@ -3244,7 +2667,7 @@ void silc_server_channel_key(SilcServer server,
   payload = silc_channel_key_parse_payload(buffer);
   if (!payload) {
     SILC_LOG_ERROR(("Bad channel key payload, dropped"));
-    SILC_LOG_DEBUG(("Bad channel key payload, dropped"));
+    goto out;
   }
 
   /* Get channel ID */
@@ -3253,10 +2676,9 @@ void silc_server_channel_key(SilcServer server,
     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;
   }
 
@@ -3267,7 +2689,7 @@ void silc_server_channel_key(SilcServer server,
   cipher = silc_channel_key_get_cipher(payload, NULL);;
   if (!cipher)
     goto out;
-  channel->key_len = key_len;
+  channel->key_len = key_len * 8;
   channel->key = silc_calloc(key_len, sizeof(unsigned char));
   memcpy(channel->key, key, key_len);
   silc_cipher_alloc(cipher, &channel->channel_key);
@@ -3330,11 +2752,35 @@ void silc_server_send_notify(SilcServer server,
                          buf, strlen(buf), FALSE);
 }
 
+/* Sends notify message destined to specific entity. */
+
+void silc_server_send_notify_dest(SilcServer server,
+                                 SilcSocketConnection sock,
+                                 void *dest_id,
+                                 SilcIdType dest_id_type,
+                                 const char *fmt, ...)
+{
+  va_list ap;
+  unsigned char buf[4096];
+
+  memset(buf, 0, sizeof(buf));
+  va_start(ap, fmt);
+  vsprintf(buf, fmt, ap);
+  va_end(ap);
+
+  silc_server_packet_send_dest(server, sock, SILC_PACKET_NOTIFY, 0, 
+                              dest_id, dest_id_type,
+                              buf, strlen(buf), FALSE);
+}
+
 /* Sends notify message to a channel. The notify message sent is 
-   distributed to all clients on the channel. */
+   distributed to all clients on the channel. Actually this is not real
+   notify message, instead it is message to channel sent by server. But
+   as server is sending it it will appear as notify type message on the
+   client side. */
 
 void silc_server_send_notify_to_channel(SilcServer server,
-                                       SilcChannelList *channel,
+                                       SilcChannelEntry channel,
                                        const char *fmt, ...)
 {
   va_list ap;
@@ -3430,24 +2876,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 +3013,25 @@ 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);
 
   /* 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)
+    return NULL;
+
+  /* Add to cache */
+  silc_idcache_add(server->local_list->channels, channel_name,
+                  SILC_ID_CHANNEL, channel_id, (void *)entry, TRUE);
+
+  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 +3059,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,
@@ -3575,17 +3148,15 @@ SilcClientList *silc_server_new_client(SilcServer server,
   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);
+                         client->send_key->cipher->name,
+                         client->send_key->cipher->key_len);
   silc_server_send_notify(server, sock, 
                          "Your current nickname is %s",
-                         id_entry->nickname);
+                         client->nickname);
 
   /* XXX Send motd */
 
-#undef LCC
-#undef LCCC
-  return id_entry;
+  return client;
 }
 
 /* Create new server. This processes incoming NEW_SERVER packet and
@@ -3593,15 +3164,17 @@ 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;
 
   SILC_LOG_DEBUG(("Creating new server"));
@@ -3610,39 +3183,46 @@ 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_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);
+  /* Get Server ID */
+  server_id = silc_id_str2id(id_string, SILC_ID_SERVER);
+  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,14 +3233,18 @@ void silc_server_new_id(SilcServer server, SilcSocketConnection sock,
                        SilcPacketContext *packet)
 {
   SilcBuffer buffer = packet->buffer;
+  SilcIDList id_list;
+  SilcServerEntry tmpserver, router;
+  SilcSocketConnection router_sock;
   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,
@@ -3676,44 +3260,54 @@ void silc_server_new_id(SilcServer server, SilcSocketConnection sock,
   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:
@@ -3724,3 +3318,63 @@ void silc_server_new_id(SilcServer server, SilcSocketConnection sock,
  out:
   silc_free(id_string);
 }
+
+/* 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..74ee74ae38921b123923b9da5681c528c726cc06 100644 (file)
@@ -39,6 +39,10 @@ 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 +64,25 @@ 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,
                                        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 +92,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, ...);
@@ -100,8 +118,13 @@ void silc_server_send_error(SilcServer server,
 void silc_server_send_notify(SilcServer server,
                             SilcSocketConnection sock,
                             const char *fmt, ...);
+void silc_server_send_notify_dest(SilcServer server,
+                                 SilcSocketConnection sock,
+                                 void *dest_id,
+                                 SilcIdType dest_id_type,
+                                 const char *fmt, ...);
 void silc_server_send_notify_to_channel(SilcServer server,
-                                       SilcChannelList *channel,
+                                       SilcChannelEntry channel,
                                        const char *fmt, ...);
 void silc_server_send_new_id(SilcServer server,
                             SilcSocketConnection sock,
@@ -115,16 +138,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..d648e8a69f2dd9bc80bfafa716d5dc556b4008ec 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"
 
-const char server_version[] = "27062000";
+const char server_version[] = "26072000";
index 2f617c2621c8676c31b8513a41c081c924461391..b6d44d6bed07d7e5ab9a22ce6a55dff8c66454f9 100644 (file)
 /*
  * $Id$
  * $Log$
+ * 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.
  *
  *
  */
@@ -305,7 +311,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 +582,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)
index 56ed10eb129e107081e2aad1f7fa0e4863798832..af017597958a826b3e3d01d5dee1570d4598fe72 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;
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..ca2e5b88ac65dcf10bea045a0739d54028931fd5 100644 (file)
 /*
  * $Id$
  * $Log$
+ * 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.
  *
  *
  */
index e5417e2105bf4cf290260b1a2050ba42ea1ab4df..c04a7aa81a15d54964f590338f3928d490bfc463 100644 (file)
@@ -32,7 +32,6 @@ errorlogfile:silcd2_error.log:10000
 2:200:300:400
 
 [ClientConnection]
-10.2.1.199:passwd:priikone:333:1
 :::1333:1
 
 [AdminConnection]
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..b983c1eb64c9e57cf344bd81d6f613fc761d8aa7 100644 (file)
@@ -33,7 +33,7 @@ case "$target" in
     ;;
 esac
 
-AM_INIT_AUTOMAKE(silc, 28062000)
+AM_INIT_AUTOMAKE(silc, 26072000)
 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,111 @@ 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,15 +226,19 @@ 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_OUTPUT( \
 Makefile
 doc/Makefile
 includes/Makefile
 lib/Makefile
+lib/contrib/Makefile
 lib/silccore/Makefile
 lib/silccrypt/Makefile
 lib/silcmath/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..ac405ee09704e4d3307b6c789cf62686ec915984 100644 (file)
@@ -26,6 +26,9 @@ all:
 
 dist-hook:
        -rm -f draft-riikonen*.txt
+       touch draft-riikonen-silc-spec-00.txt
+       touch draft-riikonen-silc-pp-00.txt
+       touch draft-riikonen-silc-ke-auth-00.txt
        ./makerfc draft-riikonen-silc-spec-00.nroff \
                draft-riikonen-silc-spec-00.txt
        ./makerfc draft-riikonen-silc-pp-00.nroff \
@@ -35,6 +38,7 @@ dist-hook:
 
 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..9dc849eddc30db3755e213c7604f30ad22b61b6b 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 28 June 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                        28 June 2000
+Expires: 28 Jan 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 28 Jan 2001 
+
index 7f907438a7c05785d7ac793be51376c7cfd65963..10516d0a71d3eac9829063dd08e14a4c6825808d 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 28 June 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                             28 June 2000
+Expires: 28 Jan 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,10 +931,6 @@ 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
@@ -981,7 +1003,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 +1012,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 +1287,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 +1323,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 +1333,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 +1344,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 +1357,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 +1428,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 +1714,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 +1950,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 +2231,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 +2267,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 +2299,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 +2433,5 @@ Kasarmikatu 11 A4
 Finland
 
 EMail: priikone@poseidon.pspt.fi
+
+This Internet-Draft expires 28 Jan 2001
index a37c0a5181e7fe681a09f20867b8d3ec5fbb9d5a..9c1128a94c7fc8efee7b8a670bd88525a0fed3ce 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 28 June 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                           28 June 2000
+Expires: 28 Jan 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 28 Jan 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..238416635ef0db6f6576a90c0fd1a20fbb63c8b6 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"
 
 /* SILC Client includes */
-#include "idlist.h"
 #include "screen.h"
 #include "clientconfig.h"
 #include "client.h"
-#include "clientutil.h"
-#include "protocol.h"
 #include "command.h"
 #include "command_reply.h"
+#include "idlist.h"
+#include "clientutil.h"
+#include "protocol.h"
 #include "silc.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..0358befd4ff2bfea8b4f9b459f87c15e1b674649 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
 /* Math library includes */
 #include "silcmp.h"
 #include "modinv.h"
+#include "mpbin.h"
 #include "silcprimegen.h"
 
 /* Crypto library includes */
 #include "silcconfig.h"
 #include "id.h"
 #include "idcache.h"
-#include "silcpacket.h"
 #include "silctask.h"
 #include "silcschedule.h"
 #include "silcprotocol.h"
+#include "silcsockconn.h"
 #include "silccommand.h"
 #include "silcchannel.h"
-#include "silcsockconn.h"
+#include "silcpacket.h"
 
 #ifdef SILC_SIM
 /* SILC Module library includes */
index e225709c4b79eef7b12b33f1980789411b19209a..d724ec3293e89867ce1c2e4b57e1364fe2ba7990 100644 (file)
@@ -33,7 +33,8 @@ typedef unsigned char SilcVersion;
 #define SILC_VERSION_1 '\1'
 
 /* SILC version string */
-const char *silc_version = "27062000";
+const char *silc_version = "26072000";
+const char *silc_version_string = "SILC-1.0-26072000";
 const char *silc_name = "SILC";
 const char *silc_fullname = "Secure Internet Live Conferencing";
 
index 66c6682a79b4e42dcdce880775223b23cd5310c5..e67620e39d58e018296d9cc6e292a75c60edd695 100644 (file)
@@ -19,6 +19,7 @@
 AUTOMAKE_OPTIONS = 1.0 no-dependencies foreign
 
 SUBDIRS = \
+       contrib \
        silccore \
        silccrypt \
        silcsim \
@@ -29,7 +30,7 @@ SUBDIRS = \
 CLEANFILES = libsilc.a
 DISTCLEANFILES = libsilc.a
 
-all:   libsilc.a
+all:  libsilc.a
 
 libsilc.a:
        find . -type f -name *.o | xargs $(AR) cru libsilc.a
diff --git a/lib/contrib/Makefile.am b/lib/contrib/Makefile.am
new file mode 100644 (file)
index 0000000..343a02e
--- /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../silcmath/gmp
diff --git a/lib/contrib/getopt.c b/lib/contrib/getopt.c
new file mode 100644 (file)
index 0000000..7a4673b
--- /dev/null
@@ -0,0 +1,757 @@
+/* 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
+#ifdef HAVE_CONFIG_H
+#if defined (emacs) || defined (CONFIG_BROKETS)
+/* We use <config.h> instead of "config.h" so that a compilation
+   using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
+   (which it would do because it found this file in $srcdir).  */
+#include <config.h>
+#else
+#include "config.h"
+#endif
+#endif
+
+#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..f784b57
--- /dev/null
@@ -0,0 +1,187 @@
+/* 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
+#ifdef HAVE_CONFIG_H
+#if defined (emacs) || defined (CONFIG_BROKETS)
+/* We use <config.h> instead of "config.h" so that a compilation
+   using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
+   (which it would do because it found this file in $srcdir).  */
+#include <config.h>
+#else
+#include "config.h"
+#endif
+#endif
+
+#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..8f914cf
--- /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
diff --git a/lib/silcclient/README b/lib/silcclient/README
new file mode 100644 (file)
index 0000000..26eb385
--- /dev/null
@@ -0,0 +1,114 @@
+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,
+  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->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).
diff --git a/lib/silcclient/client.c b/lib/silcclient/client.c
new file mode 100644 (file)
index 0000000..d2b4aa6
--- /dev/null
@@ -0,0 +1,1499 @@
+/*
+
+  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,
+                                               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->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;
+
+  SILC_LOG_DEBUG(("Connecting to port %d of server %s",
+                 port, host));
+
+  conn = silc_client_add_connection(client, context);
+  conn->remote_host = strdup(host);
+  conn->remote_port = port;
+
+  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 */
+  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;
+  SilcClientConnection conn = ctx->conn;
+  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 */
+      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);
+    }
+    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 *)conn, &conn->sock);
+  if (conn->sock == NULL) {
+    client->ops->say(client, conn, 
+                    "Error: Could not allocate connection socket");
+    silc_net_close_connection(fd);
+    client->ops->connect(client, conn, FALSE);
+    return;
+  }
+
+  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");
+    client->ops->connect(client, conn, FALSE);
+    return;
+  }
+  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);
+}
+
+/* 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;
+    silc_free(ctx);
+
+    /* Notify application of failure */
+    client->ops->connect(client, ctx->sock->user_data, FALSE);
+    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);
+    silc_free(ctx);
+    conn->sock->protocol = NULL;
+
+    /* Notify application of failure */
+    client->ops->connect(client, ctx->sock->user_data, FALSE);
+    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;
+
+  client->ops->say(client, conn, "Connected to port %d of host %s",
+                  conn->remote_port, conn->remote_host);
+
+  /* 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)) {
+       silc_client_close_connection(client, sock);
+       client->ops->disconnect(client, conn);
+       return;
+      }
+      
+      client->ops->say(client, conn, "Connection closed: premature EOF");
+      SILC_LOG_DEBUG(("Premature EOF from connection %d", sock->sock));
+      silc_client_close_connection(client, sock);
+      client->ops->disconnect(client, conn);
+      return;
+    }
+
+    /* Process the packet. This will call the parser that will then
+       decrypt and parse the packet. */
+    if (!silc_packet_receive_process(sock, conn->receive_key, conn->hmac,
+                                    silc_client_packet_parse, client)) {
+      silc_buffer_clear(sock->inbuf);
+      return;
+    }
+  }
+}
+
+/* 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);
+  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_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
+     */
+    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.
+       */
+      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;
+  }
+}
+
+/* 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_encode_payload(strlen(conn->nickname), conn->nickname,
+                                       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;
+  }
+
+  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);
+}
+
+/* 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);
+  client->ops->say(client, sock->user_data, 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)
+{
+  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);
+  conn->local_id = silc_id_str2id(id_string, SILC_ID_CLIENT);
+  if (conn->local_id_data)
+    silc_free(conn->local_id_data);
+  conn->local_id_data = 
+    silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
+  memcpy(conn->local_id_data, id_string, SILC_ID_CLIENT_LEN);
+  conn->local_id_data_len = SILC_ID_CLIENT_LEN;
+  if (!conn->local_entry)
+    conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
+  conn->local_entry->nickname = conn->nickname;
+  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,
+                               unsigned char *id_string)
+{
+  SilcClientConnection conn = (SilcClientConnection)sock->user_data;
+  SilcChannelID *id;
+  SilcChannelEntry channel;
+
+  SILC_LOG_DEBUG(("New channel ID"));
+
+  id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
+  channel = silc_calloc(1, sizeof(*channel));
+  channel->channel_name = channel_name;
+  channel->id = id;
+  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 *)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 key_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_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. */
+  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, &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) {
+    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, key_len);
+
+  /* Client is now joined to the channel */
+  channel->on_channel = TRUE;
+
+ out:
+  silc_free(id);
+  silc_channel_key_free_payload(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;
+
+  /* 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 */
+  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_parse_payload(buffer);
+  if (!payload)
+    goto out;
+
+  /* Pass the message to application */
+  if (packet->src_id_type == SILC_ID_CLIENT) {
+    client->ops->channel_message(client, conn, 
+                                silc_channel_get_nickname(payload, NULL),
+                                channel->channel_name,
+                                silc_channel_get_data(payload, NULL));
+  } else {
+    /* Message from server */
+    /* XXX maybe this should be passed to app... */
+    client->ops->say(client, conn, "%s", silc_channel_get_data(payload, NULL));
+  }
+
+ out:
+  if (id)
+    silc_free(id);
+  if (payload)
+    silc_channel_free_payload(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 (!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;
+       remote_client->nickname = strdup(nickname);
+
+       /* 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);
+}
similarity index 61%
rename from apps/silc/client.h
rename to lib/silcclient/client.h
index 661bd83a481604aad891dc11bc2d0263043af5ca..8caffe812c574e61d749268d4635165b25b3ef25 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,73 @@ 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 thourh 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 and realname. */
   char *username;
   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 connections in client. All the connection data is saved here. */
+  SilcClientConnection *conns;
+  unsigned int conns_count;
 
-  /* Table of windows in client. All the data, including connection
-     specific data, is saved in here. */
-  SilcClientWindow *windows;
-  unsigned int windows_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 +206,26 @@ 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,
+                                               void *context);
 int silc_client_connect_to_server(SilcClient client, int port,
-                                 char *host);
+                                 char *host, void *context);
 void silc_client_packet_send(SilcClient client, 
                             SilcSocketConnection sock,
                             SilcPacketType type, 
@@ -239,6 +265,7 @@ void silc_client_receive_new_id(SilcClient client,
 void silc_client_new_channel_id(SilcClient client,
                                SilcSocketConnection sock,
                                char *channel_name,
+                               unsigned int mode,
                                unsigned char *id_string);
 void silc_client_receive_channel_key(SilcClient client,
                                     SilcSocketConnection sock,
@@ -246,4 +273,7 @@ void silc_client_receive_channel_key(SilcClient client,
 void silc_client_channel_message(SilcClient client, 
                                 SilcSocketConnection sock, 
                                 SilcPacketContext *packet);
+void silc_client_private_message(SilcClient client, 
+                                SilcSocketConnection sock, 
+                                SilcPacketContext *packet);
 #endif
diff --git a/lib/silcclient/command.c b/lib/silcclient/command.c
new file mode 100644 (file)
index 0000000..1784d4e
--- /dev/null
@@ -0,0 +1,757 @@
+/*
+
+  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, 2),
+  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, 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),
+
+  { 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;
+
+/* 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_encode_payload(SILC_COMMAND_WHOIS,
+                                      cmd->argc - 1, ++cmd->argv,
+                                      ++cmd->argv_lens, ++cmd->argv_types);
+  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_encode_payload(SILC_COMMAND_IDENTIFY,
+                                      cmd->argc - 1, ++cmd->argv,
+                                      ++cmd->argv_lens, ++cmd->argv_types);
+  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;
+  }
+
+  /* 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_encode_payload(SILC_COMMAND_NICK,
+                                      cmd->argc - 1, ++cmd->argv,
+                                      ++cmd->argv_lens, ++cmd->argv_types);
+  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)
+{
+}
+
+SILC_CLIENT_CMD_FUNC(topic)
+{
+}
+
+/* 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;
+  unsigned int num = 0;
+  char *nickname = NULL, *server = NULL;
+  unsigned char *client_id, *channel_id;
+
+  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) {
+    /* 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;
+  }
+  
+  client_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
+
+  /* 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");
+    silc_free(client_id);
+    COMMAND_ERROR;
+    goto out;
+  }
+
+  channel_id = silc_id_id2str(channel_entry->id, SILC_ID_CHANNEL);
+
+  buffer = silc_command_encode_payload_va(SILC_COMMAND_INVITE, 2,
+                                         1, client_id, SILC_ID_CLIENT_LEN,
+                                         2, channel_id, SILC_ID_CHANNEL_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);
+
+  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_encode_payload(SILC_COMMAND_QUIT, cmd->argc - 1, 
+                                      ++cmd->argv, ++cmd->argv_lens,
+                                      ++cmd->argv_types);
+  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_encode_payload_va(SILC_COMMAND_INFO, 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);
+
+  id = silc_id_str2id(conn->remote_id_data, SILC_ID_SERVER);
+
+  /* Send the command */
+  buffer = silc_command_encode_payload_va(SILC_COMMAND_PING, 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);
+
+  /* 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 */
+  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, 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(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)
+{
+}
+
+/* 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;
+  unsigned char *id_string;
+  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 chanenl");
+      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 */
+  id_string = silc_id_id2str(id_cache->id, SILC_ID_CHANNEL);
+  buffer = silc_command_encode_payload_va(SILC_COMMAND_LEAVE, 1, 
+                                         1, id_string, SILC_ID_CHANNEL_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);
+
+  /* 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);
+  silc_free(id_string);
+
+  /* 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;
+  char *name;
+  unsigned char *id_string;
+
+  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 */
+  id_string = silc_id_id2str(id_cache->id, SILC_ID_CHANNEL);
+  buffer = silc_command_encode_payload_va(SILC_COMMAND_NAMES, 1, 
+                                         1, id_string, SILC_ID_CHANNEL_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_free(id_string);
+
+  /* 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
+     execute. */
+  /* 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 95%
rename from apps/silc/command.h
rename to lib/silcclient/command.h
index 19db809b936484e47199e6a98002ca3dbce81cfb..edb714505f12fec5e244134fa14487939455a3c7 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,8 @@ do {                                                        \
 } while(0)
 
 /* Prototypes */
+void silc_client_command_free(SilcClientCommandContext cmd);
+SilcClientCommand *silc_client_command_find(const char *name);
 void silc_client_command_pending(SilcCommand reply_cmd,
                                 SilcClientCommandCallback callback,
                                 void *context);
@@ -134,7 +137,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);
@@ -155,10 +157,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
similarity index 50%
rename from apps/silc/command_reply.c
rename to lib/silcclient/command_reply.c
index 491808ec8e8bfee1fb062ab945e5cd3d5302a46d..604389376afaa09e6ac221de992ab4d4e297ddff 100644 (file)
  * 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.
- *
- *
- */
+/* $Id$ */
 
-#include "clientincludes.h"
+#include "clientlibincludes.h"
 
 /* Client command reply list. */
 SilcClientCommandReply silc_command_reply_list[] =
@@ -45,7 +38,6 @@ SilcClientCommandReply silc_command_reply_list[] =
   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),
@@ -59,7 +51,7 @@ SilcClientCommandReply silc_command_reply_list[] =
   SILC_CLIENT_CMD_REPLY(die, DIE),
   SILC_CLIENT_CMD_REPLY(silcoper, SILCOPER),
   SILC_CLIENT_CMD_REPLY(leave, LEAVE),
-  SILC_CLIENT_CMD_REPLY(names, LEAVE),
+  SILC_CLIENT_CMD_REPLY(names, NAMES),
 
   { NULL, 0 },
 };
@@ -83,6 +75,7 @@ const SilcCommandStatusMessage silc_command_status_messages[] = {
   { 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" },
@@ -111,12 +104,23 @@ const SilcCommandStatusMessage silc_command_status_messages[] = {
   { 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)
+
+/* 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))
+
 /* Process received command reply. */
 
 void silc_client_command_reply_process(SilcClient client,
                                       SilcSocketConnection sock,
-                                      SilcBuffer buffer)
+                                      SilcPacketContext *packet)
 {
+  SilcBuffer buffer = packet->buffer;
   SilcClientCommandReplyContext ctx;
   SilcCommandPayload payload;
 
@@ -134,6 +138,7 @@ void silc_client_command_reply_process(SilcClient client,
   ctx->client = client;
   ctx->sock = sock;
   ctx->payload = payload;
+  ctx->packet = packet;
       
   /* Check for pending commands and mark to be exeucted */
   SILC_CLIENT_COMMAND_CHECK_PENDING(ctx);
@@ -172,11 +177,12 @@ void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
 
 /* Received reply for WHOIS command. This maybe called several times
    for one WHOIS command as server may reply with list of results. */
+/* Sends to application: (no arguments) */
 
 SILC_CLIENT_CMD_REPLY_FUNC(whois)
 {
   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
-  SilcClient client = cmd->client;
+  SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
   SilcCommandStatus status;
   unsigned char *tmp;
 
@@ -186,12 +192,20 @@ SILC_CLIENT_CMD_REPLY_FUNC(whois)
   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));
+      /* Take nickname which may be provided */
+      tmp = silc_command_get_arg_type(cmd->payload, 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 {
-      silc_say(cmd->client, "%s", silc_client_command_status_message(status));
+      cmd->client->ops->say(cmd->client, conn,
+              "%s", silc_client_command_status_message(status));
+      COMMAND_REPLY_ERROR;
       goto out;
     }
   }
@@ -203,7 +217,6 @@ SILC_CLIENT_CMD_REPLY_FUNC(whois)
     unsigned char *id_data;
     char *nickname = NULL, *username = NULL;
     char *realname = NULL;
-    void *id;
 
     memset(buf, 0, sizeof(buf));
 
@@ -232,16 +245,19 @@ SILC_CLIENT_CMD_REPLY_FUNC(whois)
     /* 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->current_conn->client_id_cache_count[(int)nickname[0] - 32] =
+    silc_idcache_add(&client->current_conn->
                     client_id_cache[(int)nickname[0] - 32],
-                    client->current_win->
+                    client->current_conn->
                     client_id_cache_count[(int)nickname[0] - 32],
                     strdup(nickname), SILC_ID_CLIENT, id, NULL);
 #endif
 
-    silc_say(cmd->client, "%s", buf);
-   }
+    cmd->client->ops->say(cmd->client, conn, "%s", buf);
+
+    /* Notify application */
+    COMMAND_REPLY((ARGS));
+  }
 
   if (status == SILC_STATUS_LIST_START) {
 
@@ -268,26 +284,31 @@ SILC_CLIENT_CMD_REPLY_FUNC(whowas)
 SILC_CLIENT_CMD_REPLY_FUNC(identify)
 {
   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
-  SilcClientWindow win = (SilcClientWindow)cmd->sock->user_data;
+  SilcClientConnection conn = (SilcClientConnection)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));
+      /* Take nickname which may be provided */
+      tmp = silc_command_get_arg_type(cmd->payload, 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 {
-      silc_say(cmd->client, "%s", silc_client_command_status_message(status));
+      cmd->client->ops->say(cmd->client, conn,
+              "%s", silc_client_command_status_message(status));
+      COMMAND_REPLY_ERROR;
       goto out;
     }
   }
@@ -306,10 +327,8 @@ SILC_CLIENT_CMD_REPLY_FUNC(identify)
     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);
+    silc_idcache_add(conn->client_cache, client_entry->nickname,
+                    SILC_ID_CLIENT, client_entry->id, client_entry, TRUE);
   }
 
   if (status == SILC_STATUS_LIST_START) {
@@ -324,17 +343,16 @@ SILC_CLIENT_CMD_REPLY_FUNC(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. */
+/* Sends to application: char * (nickname). */
 
 SILC_CLIENT_CMD_REPLY_FUNC(nick)
 {
   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
-  SilcClientWindow win = (SilcClientWindow)cmd->sock->user_data;
+  SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
   SilcCommandStatus status;
   unsigned char *tmp, *id_string;
   int argc;
@@ -344,14 +362,17 @@ SILC_CLIENT_CMD_REPLY_FUNC(nick)
   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", 
+    cmd->client->ops->say(cmd->client, conn, "Cannot set nickname: %s", 
             silc_client_command_status_message(status));
+    COMMAND_REPLY_ERROR;
     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");
+    cmd->client->ops->say(cmd->client, conn, 
+                         "Cannot set nickname: bad reply to command");
+    COMMAND_REPLY_ERROR;
     goto out;
   }
 
@@ -359,9 +380,8 @@ SILC_CLIENT_CMD_REPLY_FUNC(nick)
   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);
+  /* Notify application */
+  COMMAND_REPLY((ARGS, conn->nickname));
 
  out:
   silc_client_command_reply_free(cmd);
@@ -375,8 +395,30 @@ SILC_CLIENT_CMD_REPLY_FUNC(topic)
 {
 }
 
+/* Received reply to invite command. */
+/* Sends to application: (no arguments) */
+
 SILC_CLIENT_CMD_REPLY_FUNC(invite)
 {
+  SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+  SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+  SilcCommandStatus status;
+  unsigned char *tmp;
+
+  tmp = silc_command_get_arg_type(cmd->payload, 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));
+    silc_client_command_reply_free(cmd);
+    COMMAND_REPLY_ERROR;
+    return;
+  }
+
+  /* Notify application */
+  COMMAND_REPLY((ARGS));
+
+  silc_client_command_reply_free(cmd);
 }
  
 SILC_CLIENT_CMD_REPLY_FUNC(quit)
@@ -387,20 +429,100 @@ SILC_CLIENT_CMD_REPLY_FUNC(kill)
 {
 }
 
+/* Received reply to INFO command. We receive the server ID and some
+   information about the server user requested. */
+/* Sends to application: char * (server information) */
+
 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;
 
-SILC_CLIENT_CMD_REPLY_FUNC(away)
-{
+  tmp = silc_command_get_arg_type(cmd->payload, 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));
+    silc_client_command_reply_free(cmd);
+    COMMAND_REPLY_ERROR;
+    return;
+  }
+
+  /* Get server ID */
+  tmp = silc_command_get_arg_type(cmd->payload, 2, NULL);
+  if (!tmp)
+    goto out;
+
+  /* XXX save server id */
+
+  /* Get server info */
+  tmp = silc_command_get_arg_type(cmd->payload, 3, NULL);
+  if (!tmp)
+    goto out;
+
+  client->ops->say(cmd->client, conn, "Info: %s", tmp);
+
+  /* Notify application */
+  COMMAND_REPLY((ARGS, (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. */
+/* Sends to application: (no arguments) */
+
 SILC_CLIENT_CMD_REPLY_FUNC(ping)
 {
+  SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+  SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+  SilcCommandStatus status;
+  void *id;
+  char *tmp;
+  int i;
+  time_t diff, curtime;
+
+  tmp = silc_command_get_arg_type(cmd->payload, 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;
+  }
+
+  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));
+      goto out;
+    }
+  }
+
+ out:
+  silc_client_command_reply_free(cmd);
 }
 
 SILC_CLIENT_CMD_REPLY_FUNC(oper)
@@ -412,9 +534,10 @@ SILC_CLIENT_CMD_REPLY_FUNC(oper)
 SILC_CLIENT_CMD_REPLY_FUNC(join)
 {
   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+  SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
   SilcClient client = cmd->client;
   SilcCommandStatus status;
-  unsigned int argc;
+  unsigned int argc, mode;
   unsigned char *id_string;
   char *topic, *tmp, *channel_name;
 
@@ -423,35 +546,59 @@ SILC_CLIENT_CMD_REPLY_FUNC(join)
   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));
+    cmd->client->ops->say(cmd->client, conn,
+            "%s", silc_client_command_status_message(status));
+    COMMAND_REPLY_ERROR;
     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");
+    cmd->client->ops->say(cmd->client, conn,
+            "Cannot join channel: Bad reply packet");
+    COMMAND_REPLY_ERROR;
     goto out;
   }
 
   /* Get channel name */
   tmp = silc_command_get_arg_type(cmd->payload, 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 */
+  /* Get Channel ID */
   id_string = silc_command_get_arg_type(cmd->payload, 3, NULL);
+  if (!id_string) {
+    cmd->client->ops->say(cmd->client, conn, 
+                         "Cannot join channel: Bad reply packet");
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+
+  /* Get channel mode */
+  tmp = silc_command_get_arg_type(cmd->payload, 4, NULL);
+  if (tmp)
+    SILC_GET32_MSB(mode, tmp);
+  else
+    mode = 0;
 
   /* Get topic */
-  topic = silc_command_get_arg_type(cmd->payload, 4, NULL);
+  topic = silc_command_get_arg_type(cmd->payload, 5, 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);
+  silc_client_new_channel_id(cmd->client, cmd->sock, channel_name, 
+                            mode, id_string);
 
   if (topic)
-    silc_say(client, "Topic for %s: %s", channel_name, topic);
+    client->ops->say(cmd->client, conn, 
+                    "Topic for %s: %s", channel_name, topic);
+
+  /* Notify application */
+  COMMAND_REPLY((ARGS, channel_name, topic));
 
  out:
   silc_client_command_reply_free(cmd);
@@ -489,63 +636,152 @@ SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
 {
 }
 
+/* Reply to LEAVE command. */
+/* Sends to application: (no arguments) */
+
 SILC_CLIENT_CMD_REPLY_FUNC(leave)
 {
-}
+  SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+  SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+  SilcCommandStatus status;
+  unsigned char *tmp;
 
-SILC_CLIENT_CMD_REPLY_FUNC(names)
-{
+  tmp = silc_command_get_arg_type(cmd->payload, 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);
 }
 
-/* Private message received. This processes the private message and
-   finally displays it on the screen. */
+/* Reply to NAMES command. Received list of client names on the channel 
+   we requested. */
 
-SILC_CLIENT_CMD_REPLY_FUNC(msg)
+SILC_CLIENT_CMD_REPLY_FUNC(names)
 {
   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;
+  SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+  SilcCommandStatus status;
+  SilcIDCacheEntry id_cache = NULL;
+  SilcChannelEntry channel;
+  SilcChannelID *channel_id = NULL;
+  SilcBuffer client_id_list;
+  unsigned char *tmp;
+  char *name_list;
+  int i, len1, len2, list_count = 0;
 
-  /* Get nickname */
-  silc_buffer_unformat(buffer, 
-                      SILC_STR_UI16_NSTRING_ALLOC(&nickname, &nick_len),
-                      SILC_STR_END);
-  silc_buffer_pull(buffer, 2 + nick_len);
+  SILC_LOG_DEBUG(("Start"));
 
-#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);
+  tmp = silc_command_get_arg_type(cmd->payload, 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;
+  }
 
-  /* 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) {
+  /* Get channel ID */
+  tmp = silc_command_get_arg_type(cmd->payload, 2, NULL);
+  if (!tmp) {
+    cmd->client->ops->say(cmd->client, conn, 
+                         "Cannot get user list: Bad reply packet");
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
+  channel_id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
+
+  /* Get the name list of the channel */
+  name_list = silc_command_get_arg_type(cmd->payload, 3, &len1);
+  if (!name_list) {
+    cmd->client->ops->say(cmd->client, conn, 
+                         "Cannot get user list: Bad reply packet");
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
 
-    SilcClientCommandContext ctx;
-    char whois[255];
+  /* Get Client ID list */
+  tmp = silc_command_get_arg_type(cmd->payload, 4, &len2);
+  if (!tmp) {
+    cmd->client->ops->say(cmd->client, conn, 
+                         "Cannot get user list: Bad reply packet");
+    COMMAND_REPLY_ERROR;
+    goto out;
+  }
 
-    /* Private message from unknown source, try to resolve it. */
+  client_id_list = silc_buffer_alloc(len2);
+  silc_buffer_pull_tail(client_id_list, len2);
+  silc_buffer_put(client_id_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;
 
-    return;
+  /* 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++;
+      }
+
+    cmd->client->ops->say(cmd->client, conn,
+                         "Users on %s: %s", channel->channel_name, name_list);
   }
-#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);
+
+  /* Cache the received name list and client ID's. This cache expires
+     whenever server sends notify message to channel. It means two things;
+     some user has joined or leaved the channel. */
+  for (i = 0; i < list_count; i++) {
+    int nick_len = strcspn(name_list, " ");
+    char *nickname = silc_calloc(nick_len, sizeof(*nickname));
+    SilcClientID *client_id;
+    SilcClientEntry client;
+
+    memcpy(nickname, name_list, nick_len);
+    client_id = silc_id_str2id(client_id_list->data, SILC_ID_CLIENT);
+    silc_buffer_pull(client_id_list, SILC_ID_CLIENT_LEN);
+
+    client = silc_calloc(1, sizeof(*client));
+    client->id = client_id;
+    client->nickname = nickname;
+
+    silc_idcache_add(conn->client_cache, nickname, SILC_ID_CLIENT,
+                    client_id, (void *)client, TRUE);
+    name_list = name_list + nick_len + 1;
+  }
+
+  silc_buffer_free(client_id_list);
+
+ out:
+  if (channel_id)
+    silc_free(channel_id);
+  silc_client_command_reply_free(cmd);
 }
similarity index 96%
rename from apps/silc/command_reply.h
rename to lib/silcclient/command_reply.h
index 36b312860733035d2df58f02f963c30bc38c93ad..1a7e057867405232e565b21640e793ee77230a52 100644 (file)
@@ -35,6 +35,7 @@ typedef struct {
   SilcClient client;
   SilcSocketConnection sock;
   SilcCommandPayload payload;
+  SilcPacketContext *packet;
 
   /* If defined this executes the pending command. */
   void *context;
@@ -71,7 +72,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 +86,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);
@@ -101,6 +101,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..7f632e9
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+
+  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 */
+    while (silc_idcache_list_next(list, &id_cache)) {
+      entry = (SilcClientEntry)id_cache->context;
+
+      if (server && entry->server && 
+         strncasecmp(server, entry->server, strlen(server))) {
+       entry = NULL;
+       continue;
+      }
+      
+      if (num && entry->num != num) {
+       entry = NULL;
+       continue;
+      }
+
+      break;
+    }
+
+    /* If match weren't found, request it */
+    if (!entry)
+      goto identify;
+  }
+
+  if (list)
+    silc_idcache_list_free(list);
+
+  return entry;
+}
+
+/* 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 82%
rename from apps/silc/idlist.h
rename to lib/silcclient/idlist.h
index 9c769e9839578215407f626e2222903e590dcf30..8a7b82815fc8528284bd0beda6e9bd8e582f92bc 100644 (file)
@@ -27,6 +27,8 @@
    they are used. */
 typedef struct SilcClientEntryStruct {
   char *nickname;
+  char *server;
+  unsigned int num;
   SilcClientID *id;
 
   /* Keys, these are defined if private message key has been defined 
@@ -44,6 +46,7 @@ typedef SilcClientEntryObject *SilcClientEntry;
 typedef struct SilcChannelEntryStruct {
   char *channel_name;
   SilcChannelID *id;
+  unsigned int mode;
   int on_channel;
 
   /* Channel keys */
@@ -55,4 +58,15 @@ typedef struct SilcChannelEntryStruct {
 
 typedef SilcChannelEntryObject *SilcChannelEntry;
 
+/* Prototypes */
+
+SilcClientEntry silc_idlist_get_client(SilcClient client,
+                                      SilcClientConnection conn,
+                                      char *nickname,
+                                      char *server,
+                                      unsigned int num);
+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..49d3b8c
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+
+  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 (*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, ...);
+  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);
+} 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 (*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,
+                        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. `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. 
+
+*/
+
+#endif
similarity index 75%
rename from apps/silc/protocol.c
rename to lib/silcclient/protocol.c
index ba89d9dcf80a4fb47ddd4d9b24a98aeee608d0f3..d0b8064c1093adc736e96f4cd8dbd5f3bd179f79 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;
-
-  SILC_LOG_DEBUG(("Start"));
-
-}
+/* Callback that is called when we have received KE2 payload from
+   responder. We try to verify the public key now. */
 
-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,38 @@ 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);
 }
 
 /* Performs key exchange protocol. This is used for both initiator
@@ -148,6 +128,7 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
   SilcClientKEInternalContext *ctx = 
     (SilcClientKEInternalContext *)protocol->context;
   SilcClient client = (SilcClient)ctx->client;
+  SilcClientConnection conn = ctx->sock->user_data;
   SilcSKEStatus status;
 
   SILC_LOG_DEBUG(("Start"));
@@ -183,7 +164,8 @@ 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_version_string,
+                                             &start_payload);
 
        /* Start the key exchange by sending our security properties
           to the remote end. */
@@ -223,11 +205,7 @@ 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) {
@@ -259,6 +237,7 @@ 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);
       }
@@ -278,6 +257,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 +268,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
@@ -335,7 +324,10 @@ SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
   case SILC_PROTOCOL_STATE_ERROR:
     
     /* 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 +344,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 +376,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;
       }
 
@@ -459,6 +451,22 @@ SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
   }
 }
 
-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..62ed6aef58e61f66004a7694391efc23cc1d17d4 100644 (file)
@@ -23,24 +23,14 @@ 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
+       silcsockconn.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
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 6f9c13077a472d62e0b180e6133e650c4c4b651b..8955fff940d2884c1222e37a544a70f4306f3163 100644 (file)
   GNU General Public License for more details.
 
 */
-/* XXX: This ID cache system sucks and must be rewritten! */
 /*
  * $Id$
  * $Log$
+ * Revision 1.6  2000/07/26 07:03:20  priikone
+ *     Use ID check as well in silc_idcache_add.
+ *
+ * Revision 1.5  2000/07/18 06:51:48  priikone
+ *     Use length of data found from cache instead of length of searched
+ *     data in comparison.
+ *
+ * Revision 1.4  2000/07/17 11:46:36  priikone
+ *     Added debug logging
+ *
+ * Revision 1.3  2000/07/12 05:54:01  priikone
+ *     Major rewrite of whole ID Cache system.
+ *
+ * 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 "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;
 
-  if (cache == NULL)
+  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 (!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_id(SilcIDCache *cache, unsigned int cache_count, 
-                           void *id, SilcIdType type, SilcIDCache **ret)
+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, 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[i]);
+       *ret = &(cache->cache[i]);
       return TRUE;
     }
 
   return FALSE;
 }
 
-/* Add new entry to the cache. Returns number of allocated cache
-   entries in the cache. */
+/* Finds cache entry by context. */
 
-int silc_idcache_add(SilcIDCache **cache, unsigned int cache_count,
-                    char *data, SilcIdType id_type, void *id, 
-                    void *context)
+int silc_idcache_find_by_context(SilcIDCache cache, void *context, 
+                                SilcIDCacheEntry *ret)
 {
-  SilcIDCache *c;
   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->cache[i]);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+/* 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, char *data, SilcIdType id_type,
+                    void *id, void *context, int sort)
+{
+  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 +431,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;
 
-  return cache_count;
+  if (sort)
+    silc_idcache_sort_by_data(cache);
+
+  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 +466,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 +474,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 +497,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 +512,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..4cfe30022fb45114732eb0c5c943ca6ce94cfa92 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.
  *
  *
  */
@@ -60,10 +63,6 @@ SilcChannelPayload silc_channel_parse_payload(SilcBuffer buffer)
   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. */
@@ -119,8 +118,6 @@ SilcBuffer silc_channel_encode_payload(unsigned short nick_len,
   /* 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++)
@@ -198,10 +195,6 @@ SilcChannelKeyPayload silc_channel_key_parse_payload(SilcBuffer buffer)
   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,
@@ -252,8 +245,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));
 
index cab272faf32ea705d514bc445da92930758832fc..cfdf18a05e91c08da97116d66bad4bbaaf18da06 100644 (file)
 /*
  * $Id$
  * $Log$
+ * Revision 1.3  2000/07/06 07:11:06  priikone
+ *     Removed status paylaod encoding functions -> not needed anymore.
+ *     Added encode_reply_payload_va to encode reply packets only.
+ *     Normal encode_payload_va accepts now argument type as variable
+ *     argument as well.
+ *
+ * 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.
  *
  *
  */
@@ -58,10 +67,6 @@ SilcCommandPayload silc_command_parse_payload(SilcBuffer buffer)
   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, 
@@ -197,11 +202,12 @@ SilcBuffer silc_command_encode_payload(SilcCommand cmd,
 }
 
 /* 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. */
+   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(SilcCommand cmd, 
                                          unsigned int argc, ...)
@@ -211,6 +217,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,13 +228,70 @@ 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] = x_type;
+  }
+
+  buffer = silc_command_encode_payload(cmd, 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;
+}
+
+/* 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. */
+
+SilcBuffer 
+silc_command_encode_reply_payload_va(SilcCommand cmd, 
+                                    SilcCommandStatus status,
+                                    unsigned int 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;
+
+  va_start(ap, argc);
+
+  argc++;
+  argv = silc_calloc(argc, sizeof(unsigned char *));
+  argv_lens = silc_calloc(argc, sizeof(unsigned int));
+  argv_types = silc_calloc(argc, sizeof(unsigned int));
+
+  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;
+
+  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);
 
     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, 
@@ -318,23 +382,3 @@ unsigned char *silc_command_get_arg_type(SilcCommandPayload payload,
 
   return payload->argv[i];
 }
-
-/* 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. */
-
-SilcBuffer silc_command_encode_status_payload(SilcCommandStatus status,
-                                             unsigned char *data,
-                                             unsigned int len)
-{
-  SilcBuffer sp;
-
-  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);
-
-  return sp;
-}
index 80c7ece9f804ac91f6baf51cadd5c93e696ce2a9..709115563c3b31d2064a327ae1405eddc24ed394 100644 (file)
@@ -55,40 +55,30 @@ typedef enum {
 /* 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_KICK              19
-#define        SILC_COMMAND_RESTART            20
-#define        SILC_COMMAND_CLOSE              21
-#define        SILC_COMMAND_DIE                22
-#define SILC_COMMAND_SILCOPER          23
-#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
+#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_KICK              18
+#define        SILC_COMMAND_RESTART            19
+#define        SILC_COMMAND_CLOSE              20
+#define        SILC_COMMAND_DIE                21
+#define SILC_COMMAND_SILCOPER          22
+#define SILC_COMMAND_LEAVE             23
+#define SILC_COMMAND_NAMES             24
 
 /* Reserved */
 #define SILC_COMMAND_RESERVED           255
@@ -109,30 +99,31 @@ 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_ON_CHANNEL     26
+#define SILC_STATUS_ERR_NOT_REGISTERED      27
+#define SILC_STATUS_ERR_NOT_ENOUGH_PARAMS   28
+#define SILC_STATUS_ERR_TOO_MANY_PARAMS     29
+#define SILC_STATUS_ERR_PERM_DENIED         30
+#define SILC_STATUS_ERR_BANNED_FROM_SERVER  31
+#define SILC_STATUS_ERR_BAD_PASSWORD        32
+#define SILC_STATUS_ERR_CHANNEL_IS_FULL     33
+#define SILC_STATUS_ERR_NOT_INVITED         34
+#define SILC_STATUS_ERR_BANNED_FROM_CHANNEL 35
+#define SILC_STATUS_ERR_UNKNOWN_MODE        36
+#define SILC_STATUS_ERR_NOT_YOU             37
+#define SILC_STATUS_ERR_NO_CHANNEL_PRIV     38
+#define SILC_STATUS_ERR_NO_SERVER_PRIV      39
+#define SILC_STATUS_ERR_NO_ROUTER_PRIV      40
+#define SILC_STATUS_ERR_BAD_NICKNAME        41
+#define SILC_STATUS_ERR_BAD_CHANNEL         42
+#define SILC_STATUS_ERR_AUTH_FAILED         43
 
 /* Prototypes */
 SilcCommandPayload silc_command_parse_payload(SilcBuffer buffer);
@@ -143,6 +134,10 @@ SilcBuffer silc_command_encode_payload(SilcCommand cmd,
                                       unsigned int *argv_types);
 SilcBuffer silc_command_encode_payload_va(SilcCommand cmd, 
                                          unsigned int argc, ...);
+SilcBuffer 
+silc_command_encode_reply_payload_va(SilcCommand cmd, 
+                                    SilcCommandStatus status,
+                                    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);
@@ -153,8 +148,5 @@ unsigned char *silc_command_get_next_arg(SilcCommandPayload payload,
 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);
 
 #endif
index 26c7cbefa9e686236e9b7075af09a087928f0a3b..8cb2799552e401223dacd42547815fb18708b6be 100644 (file)
 /*
  * $Id$
  * $Log$
+ * Revision 1.4  2000/07/18 06:51:58  priikone
+ *     Debug version bug fixes.
+ *
+ * Revision 1.3  2000/07/14 06:10:15  priikone
+ *     Moved all the generic packet sending, enryption, reception,
+ *     decryption and processing function from client and server to
+ *     here as they were duplicated code in the applications. Now they
+ *     are generic code over generic API. Some functions were rewritter;
+ *     packet reception and HMAC computation and checking is now more
+ *     optimized.
+ *
+ * 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"
 
+/******************************************************************************
+
+                          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 +82,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
@@ -98,8 +340,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 +374,285 @@ 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. Returns TRUE on success and FALSE on error. */
+
+int silc_packet_receive_process(SilcSocketConnection sock, 
+                               SilcCipher cipher, SilcHmac hmac,
+                               SilcPacketParserCallback parser, 
+                               void *context)
+{
+  SilcPacketParserContext *parse_ctx;
+  int packetlen, paddedlen, mac_len = 0;
+
+  /* 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 FALSE;
+  }
+
+  /* Parse the packets from the data */
+  if (sock->inbuf->len - 2 > (paddedlen + mac_len)) {
+    /* Received possibly many packets at once */
+
+    if (hmac)
+      mac_len = hmac->hash->hash->hash_len;
 
-void silc_packet_encrypt(SilcCipher cipher, SilcBuffer buffer,
-                        unsigned int len)
+    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 FALSE;
+      }
+
+      paddedlen += 2;
+      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);
+    }
+
+    /* All packets are processed, return successfully. */
+    silc_buffer_clear(sock->inbuf);
+    return TRUE;
+
+  } else {
+    /* Received one packet */
+    
+    SILC_LOG_HEXDUMP(("An incoming packet, len %d", sock->inbuf->len),
+                    sock->inbuf->data, sock->inbuf->len);
+
+    parse_ctx = silc_calloc(1, sizeof(*parse_ctx));
+    parse_ctx->packet = silc_calloc(1, sizeof(*parse_ctx->packet));
+    parse_ctx->packet->buffer = silc_buffer_copy(sock->inbuf);
+    parse_ctx->sock = sock;
+    parse_ctx->cipher = cipher;
+    parse_ctx->hmac = hmac;
+    parse_ctx->context = context;
+    silc_buffer_clear(sock->inbuf);
+
+    /* Call the parser */
+    if (parser)
+      (*parser)(parse_ctx);
+
+    /* Return successfully */
+    return TRUE;
+  }
+}
+
+/* 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. */
+
+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 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). */
+
+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. */
+/* 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. */
 
-void silc_packet_decrypt(SilcCipher cipher, SilcBuffer buffer, 
-                        unsigned int len)
+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) {
+
+    /* 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);
 
-  /* 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);
+    /* 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
@@ -285,104 +779,3 @@ 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.
-
-   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"));
-}
index a26447900093483f8190fc9ee56c3a1399b18497..d48035135b9302e90420f917de7085cfb50dc0d1 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
@@ -126,6 +126,55 @@ typedef struct {
   SilcRng rng;
 } 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 +204,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 +225,23 @@ 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);
+int 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);
 
 #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..620ca85b7027ce4fe253f259e7a72e2350f19434 100644 (file)
@@ -39,6 +39,9 @@ typedef unsigned char SilcProtocolState;
 #define SILC_PROTOCOL_CONN_AUTH_PASSWORD 1
 #define SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY 2
 
+/* Type definition for above auth methods */
+typedef unsigned char SilcProtocolAuthMeth;
+
 /* 
    SILC Protocol Object.
 
@@ -91,15 +94,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 +115,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..6e7514e37dceaa6bc6d7748fb0b565c5cd1569ce 100644 (file)
@@ -41,4 +41,4 @@ EXTRA_DIST = *.h
 
 INCLUDES = -I. -I.. -I../silccore -I../silcmath -I../silcske \
        -I../silcsim -I../.. -I../../includes \
-       -I../silcmath/gmp-3.0.1
+       -I../silcmath/gmp
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 22c79b9d25902b153aefd04489cee62bedcc2bbb..dc5a402c052be55d77cbd73ab14eb868df72f18a 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 15be620dfd2e6b9d7d91d65d0005600ea25cfe2d..97c25d52581ec37b938b44dc6c589c966ba29623 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 600fafe01d6d1120ac0a44289d8f5de3b1335545..173af143e27d1831cc23c0bf400450bfbb427d34 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 0f3bc51aac205cc8d5081590c262f7896998527b..a93b2ce10708c1d30968cc9cc9db01bd169f2d11 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 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 d53a11d174279f697be1ac11e194933e9bd593ab..6307a5e245d52182a17878fb32da83e82313143f 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 c185adb97f799f0c5057e0ff2ee1888d6add7f51..730ec263df19246e3a11ef1aa5bad324ac4af3e0 100644 (file)
@@ -113,12 +113,8 @@ SILC_PKCS_API_GET_PUBLIC_KEY(rsa)
   unsigned int e_len, n_len;
   unsigned char tmp[2];
 
-  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 = silc_calloc(*ret_len, sizeof(unsigned char));
@@ -158,15 +154,9 @@ SILC_PKCS_API_GET_PRIVATE_KEY(rsa)
   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);
+  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 + 2 + n_len + 2 + d_len + 2;
   ret = silc_calloc(*ret_len, sizeof(unsigned char));
@@ -210,30 +200,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 int e_len, n_len;
+  unsigned char tmp[2];
+  unsigned short 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]);
+  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 + 2, e_len, &key->e);
   
   memcpy(tmp, key_data + 2 + e_len, 2);
   n_len = ((unsigned int)tmp[0] << 8) | ((unsigned int)tmp[1]);
+  if (e_len + n_len > key_len) {
+    silc_mp_clear(&key->e);
+    silc_mp_clear(&key->n);
+    return FALSE;
+  }
 
-  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);
-
-  memset(e, 0, e_len);
-  memset(n, 0, n_len);
-  silc_free(e);
-  silc_free(n);
+  silc_mp_bin2mp(key_data + 2 + e_len + 2, n_len, &key->n);
 
   return TRUE;
 }
@@ -245,8 +236,8 @@ 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 int e_len, n_len, d_len;
+  unsigned char tmp[2];
+  unsigned short e_len, n_len, d_len;
 
   silc_mp_init(&key->e);
   silc_mp_init(&key->n);
@@ -254,31 +245,33 @@ SILC_PKCS_API_SET_PRIVATE_KEY(rsa)
 
   memcpy(tmp, key_data, 2);
   e_len = ((unsigned int)tmp[0] << 8) | ((unsigned int)tmp[1]);
+  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 + 2, e_len, &key->e);
   
   memcpy(tmp, key_data + 2 + e_len, 2);
   n_len = ((unsigned int)tmp[0] << 8) | ((unsigned int)tmp[1]);
+  if (e_len + n_len > key_len) {
+    silc_mp_clear(&key->e);
+    silc_mp_clear(&key->n);
+    return FALSE;
+  }
 
-  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);
+  silc_mp_bin2mp(key_data + 2 + e_len + 2, n_len, &key->n);
 
   memcpy(tmp, key_data + 2 + e_len + 2 + n_len, 2);
   d_len = ((unsigned int)tmp[0] << 8) | ((unsigned int)tmp[1]);
+  if (e_len + n_len + d_len > key_len) {
+    silc_mp_clear(&key->e);
+    silc_mp_clear(&key->n);
+    return FALSE;
+  }
 
-  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);
-
-  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 + 2 + e_len + 2 + n_len + 2, d_len, &key->d);
 
   return TRUE;
 }
index 106b4eaf3e4791568c0e0d04afbced1e91261804..063be801eda0cba2c243b84ccd58c5dc6570639e 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 f00798dc11233946ba56b9f5e46072209d3e5b2d..cadff85f449323814d49dd90cd90c67feb78072b 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 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..6bef0f15a5f005a02cb925fba4ab0ac16eda96d3 100644 (file)
 /*
  * $Id$
  * $Log$
+ * 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.
  *
  *
  */
@@ -75,18 +78,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 +172,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..e501d2742aed5672d91e738fb2ce12037fb72fd1 100644 (file)
@@ -59,10 +59,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 +136,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 (!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 (!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..c9aaf66bdf5924bc461224b6fb19ed71c8171c57 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./gmp
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]);
+  }
+}
diff --git a/lib/silcmath/mpbin.h b/lib/silcmath/mpbin.h
new file mode 100644 (file)
index 0000000..41ebf12
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+
+  mpbin.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 MPBIN_H
+#define MPBIN_H
+
+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..64dfa8629aa622160601ede958dcaa78a5da10e5 100644 (file)
@@ -72,4 +72,4 @@ EXTRA_DIST = *.h
 
 INCLUDES = -I. -I.. -I../silccrypt -I../silcmath -I../silcske \
        -I../silccore -I../.. -I../../includes \
-       -I../silcmath/gmp-3.0.1
+       -I../silcmath/gmp
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..c2ac3a96c4e193aa35701d7c65934e549ca9ae3e 100644 (file)
@@ -29,4 +29,4 @@ EXTRA_DIST = *.h
 
 INCLUDES = -I. -I.. -I../silccrypt -I../silccore \
        -I../silcsim -I../silcmath -I../.. -I../../includes \
-        -I../silcmath/gmp-3.0.1
+        -I../silcmath/gmp
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..c5163358d17b37fb556e9319f2d33973afb9aac2 100644 (file)
 /*
  * $Id$
  * $Log$
+ * 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 +64,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 +74,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 +128,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 +151,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 */
@@ -252,6 +267,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 +292,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 +337,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 +346,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 +388,6 @@ SilcSKEStatus silc_ske_payload_one_decode(SilcSKE ske,
 
  err:
   silc_free(payload);
-
   return status;
 }
 
@@ -375,7 +396,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 +420,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 +460,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 +480,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 +530,6 @@ SilcSKEStatus silc_ske_payload_two_decode(SilcSKE ske,
   if (payload->sign_data)
     silc_free(payload->sign_data);
   silc_free(payload);
-
   return status;
 }
 
@@ -547,7 +542,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..62de501168903b12f7e4b04adafdddae6a36ba42 100644 (file)
@@ -29,6 +29,9 @@ typedef struct {
   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..2ee18f78f51bc2beb4e78c30adb20b368e117c76 100644 (file)
 /*
  * $Id$
  * $Log$
+ * Revision 1.6  2000/07/19 07:04:37  priikone
+ *     Added version detection support to SKE. Minor bugfixes.
+ *
+ * Revision 1.5  2000/07/10 05:34:22  priikone
+ *     Added mp binary encoding as protocols defines.
+ *
+ * Revision 1.4  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.3  2000/07/06 07:12:39  priikone
+ *     Support for SILC style public keys added.
+ *
+ * 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.
  *
  *
  */
@@ -39,10 +56,6 @@ 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;
-  }
 
   return ske;
 }
@@ -82,8 +95,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);
@@ -217,6 +232,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 +240,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 +265,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 +294,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 +323,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 +350,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 +364,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 +374,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);
@@ -367,6 +403,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 +427,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;
 
@@ -550,10 +588,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 +597,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 +613,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 +633,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);
@@ -687,6 +724,7 @@ SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status,
 
 SilcSKEStatus 
 silc_ske_assemble_security_properties(SilcSKE ske,
+                                     char *version,
                                      SilcSKEStartPayload **return_payload)
 {
   SilcSKEStartPayload *rp;
@@ -705,6 +743,10 @@ silc_ske_assemble_security_properties(SilcSKE ske,
   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();
   rp->ke_grp_len = strlen(rp->ke_grp_list);
@@ -727,6 +769,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 +784,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 +799,17 @@ 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);
 
+  /* XXX Do version check */
+
+  /* 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 +1068,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 +1089,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 +1108,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 +1121,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 +1169,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 +1178,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..c80bf6a7b6eacb923781e962b5642b8598552dd8 100644 (file)
@@ -29,16 +29,6 @@ typedef struct SilcSKEStruct *SilcSKE;
 /* Forward declaration for security properties. */
 typedef struct SilcSKESecurityPropertiesStruct *SilcSKESecurityProperties;
 
-/* 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, 
-                                   SilcPacketType type, void *context);
-
-/* Generic SKE callback function. This is called in various SKE
-   routines. The SilcSKE object sent as argument provides all the data
-   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 */
@@ -50,6 +40,23 @@ typedef enum {
   */
 } 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, 
+                                   SilcPacketType type, void *context);
+
+/* Generic SKE callback function. This is called in various SKE
+   routines. The SilcSKE object sent as argument provides all the data
+   callers routine might need (payloads etc). */
+typedef void (*SilcSKECb)(SilcSKE ske, void *context);
+
+/* 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. */
 typedef struct {
@@ -143,14 +150,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 +174,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 +187,16 @@ SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status,
                             void *context);
 SilcSKEStatus 
 silc_ske_assemble_security_properties(SilcSKE ske,
+                                     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);
diff --git a/lib/silcutil/Makefile.am b/lib/silcutil/Makefile.am
new file mode 100644 (file)
index 0000000..fc02b27
--- /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
similarity index 94%
rename from lib/silccore/silcbuffer.c
rename to lib/silcutil/silcbuffer.c
index 7559f59f0f95a93d8a604ac1416b6a040cfd1e74..ccaf1f572e7abb704b86d60d29aafc6d72e065d5 100644 (file)
 /*
  * $Id$
  * $Log$
+ * 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.
  *
  *
  */
@@ -88,13 +96,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;
+  data = silc_calloc(len, sizeof(*data));
   memset(data, 0, len);
 
   /* Set pointers to the new buffer */
similarity index 96%
rename from lib/silccore/silcbuffmt.c
rename to lib/silcutil/silcbuffmt.c
index 2e7955c520080f19e16acf4fa56a81c2f1d9a780..3399ccb14f4828ad77dba7ac34c3b37d4020694d 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 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..24f3ddcee748dabba4de0fbc190fdcd09de08bd5 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;
+
 /* SILC Log name strings. These strings are printed to the log file. */
 const SilcLogTypeName silc_log_types[] =
 {
@@ -48,16 +44,28 @@ unsigned int log_warning_size;
 unsigned int log_error_size;
 unsigned int log_fatal_size;
 
+/* 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;
+
+/* Debug callbacks. If set these are used instead of default ones. */
+static SilcDebugCb debug_cb = NULL;
+static SilcDebugHexdumpCb debug_hexdump_cb = NULL;
+
 /* 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];
+  static char buf[8192];
 
+  memset(buf, 0, sizeof(buf));
   va_start(args, fmt);
-  vsprintf(buf, fmt, args);
+  vsnprintf(buf, sizeof(buf) - 1, fmt, args);
   va_end(args);
 
   return strdup(buf);
@@ -71,6 +79,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 +121,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 +151,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 +179,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 +269,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 80%
rename from lib/silccore/silclog.h
rename to lib/silcutil/silclog.h
index 3cfc499a5f02ce3909bb922dccb881b5be7dd1f4..cd34639f3d1fc994cd0c45ad54b3e11ec7361b5a 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,10 +67,10 @@ 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_log_format fmt))
 #define SILC_LOG_WARNING(fmt) (silc_log_output(log_warning_file, \
                                                log_warning_size, \
                                               SILC_LOG_WARNING, \
@@ -100,5 +115,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 93%
rename from lib/silccore/silcnet.c
rename to lib/silcutil/silcnet.c
index b35c18271511b57ae44c20b028b515ba7fa56281..68a820f6316ec79b5fdb6dc95dc31a817f849b5f 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/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 +130,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 */
@@ -169,6 +181,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 */
similarity index 92%
rename from lib/silccore/silcschedule.c
rename to lib/silcutil/silcschedule.c
index a23440b6c6ee0812a8f90e1f46260df9c43d8b6d..0cbf333e21ae98267f2a58f6f32ea94fe479af9b 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/18 06:51:58  priikone
+ *     Debug version bug fixes.
+ *
+ * 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.
  *
  *
  */
@@ -35,20 +46,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;
@@ -465,9 +488,10 @@ void silc_schedule()
       break;
     }
 
-    if (schedule.timeout)
+    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
similarity index 97%
rename from lib/silccore/silcschedule.h
rename to lib/silcutil/silcschedule.h
index 87af2d1e377876ef674f2ef259632aed10246375..19c384684e35f8c52b0f53f210b9a33794e98a5f 100644 (file)
@@ -110,9 +110,9 @@ 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();
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..39b9ab1
--- /dev/null
@@ -0,0 +1,549 @@
+/*
+
+  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  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.4  2000/07/19 07:04:04  priikone
+ *     Minor bug fix in silc_encode_pem
+ *
+ * Revision 1.3  2000/07/10 05:34:40  priikone
+ *     Added PEM encoding/decoding functions.
+ *
+ * Revision 1.2  2000/07/05 06:06:12  priikone
+ *     Added file saving with specific mode.
+ *
+ * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
+ *     Imported 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);
+  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;
+  
+  *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;
+}
similarity index 61%
rename from lib/silccore/silcutil.h
rename to lib/silcutil/silcutil.h
index dc57eeb27826df3ac0d5a6dc8fa52839572ce9aa..e9c011b3f0f2429039d3da59ebfa987d2c54bc68 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);
 
 #endif
index 3c8754b71c45345cbed423c840ef995e86fb32cc..b7a92bb639eb36adcf0a9d74e338f7e26304ff8f 100755 (executable)
@@ -29,13 +29,18 @@ make distclean
 rm -f includes/stamp-*
 rm -f includes/silcconfig.*
 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/silccore/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/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
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>